Добавлена логика для отображения стрелок и раскраски | Изменена ширина первого столбца таблицы
This commit is contained in:
@@ -23,3 +23,4 @@
|
||||
@use "main";
|
||||
@use "header";
|
||||
@use "nav";
|
||||
@use "organisation";
|
||||
@@ -81,6 +81,10 @@ a.link:hover {
|
||||
border: 3px solid black;
|
||||
}
|
||||
|
||||
.information-table tr :is(td, th):first-child {
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
.type_doc_header#tabs {
|
||||
width: 75%;
|
||||
margin: 0 auto;
|
||||
|
||||
@@ -1,2 +1,117 @@
|
||||
module OrganisationsHelper
|
||||
# Функции для раскраски
|
||||
def group_key(code)
|
||||
return nil if code.nil? || code.size < 2
|
||||
prefix = code[0, 2]
|
||||
case prefix
|
||||
when '21', '22', '23', '24'
|
||||
'21-24'
|
||||
else
|
||||
prefix
|
||||
end
|
||||
end
|
||||
|
||||
def keep_code?(code, type_data: 'min_max')
|
||||
return false if code.nil? || code.size < 2
|
||||
prefix = code[0, 2]
|
||||
return false unless prefix.match?(/\A\d{2}\z/)
|
||||
if type_data == 'min_max'
|
||||
return false if %w[16 17].include?(prefix)
|
||||
return true if %w[21 22 23 24 25 29].include?(prefix)
|
||||
return !code.end_with?('00')
|
||||
elsif type_data == 'comparsion'
|
||||
return code.end_with?('00')
|
||||
end
|
||||
end
|
||||
|
||||
def parse_number(value)
|
||||
return 0 if value.empty? || ['-', '(-)', 'X'].include?(value)
|
||||
negative = value.start_with?('(') && value.end_with?(')')
|
||||
value = value.tr('()', '') if negative
|
||||
value = value.delete(' ')
|
||||
return 0 unless value.match?(/\A\d+\z/)
|
||||
number = value.to_i
|
||||
negative ? -number : number
|
||||
end
|
||||
|
||||
def prepare_data(data, type_data: 'min_max')
|
||||
return {} if data.nil?
|
||||
filtered_data = data.reject do |(_, _), values|
|
||||
values.all? { |value| ['-', '(-)', 'X'].include?(value) }
|
||||
end
|
||||
if type_data == 'min_max'
|
||||
prepared_data = filtered_data.each_with_object({}) do |((_, code), values), result|
|
||||
next if code.nil? || !keep_code?(code)
|
||||
group = group_key(code)
|
||||
result[group] ||= Hash.new { |h, k| h[k] = [] }
|
||||
values.each_with_index do |value, index|
|
||||
result[group][index + 1] << parse_number(value)
|
||||
end
|
||||
end
|
||||
min_max_data = prepared_data.transform_values do |columns|
|
||||
columns.transform_values do |values|
|
||||
sorted = values.sort
|
||||
size = sorted.size
|
||||
p50 = size.odd? ? sorted[size / 2] : (sorted[size / 2 - 1] + sorted[size / 2]) / 2.0
|
||||
{ min: sorted.first, p50: p50, max: sorted.last }
|
||||
end
|
||||
end
|
||||
elsif type_data == 'comparsion'
|
||||
prepared_data = filtered_data.each_with_object({}) do |((_, code), values), result|
|
||||
next if code.nil? || !keep_code?(code, type_data: 'comparsion')
|
||||
result[code] ||= []
|
||||
(0...values.size - 1).each do |index|
|
||||
if parse_number(values[index]) == parse_number(values[index + 1])
|
||||
result[code] << nil
|
||||
elsif
|
||||
result[code] << (parse_number(values[index]) > parse_number(values[index + 1]))
|
||||
end
|
||||
end
|
||||
result[code] << nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_color_for_cell(value, min:, median:, max:)
|
||||
value = parse_number(value)
|
||||
return rgb_to_hex(WHITE) if value.nil? || min.nil? || max.nil? || median.nil?
|
||||
return rgb_to_hex(GREEN) if min == max
|
||||
|
||||
if value <= median
|
||||
ratio = median == min ? 0.0 : (value - min).to_f / (median - min)
|
||||
rgb = interpolate_color(RED, YELLOW, clamp(ratio))
|
||||
else
|
||||
ratio = max == median ? 0.0 : (value - median).to_f / (max - median)
|
||||
rgb = interpolate_color(YELLOW, GREEN, clamp(ratio))
|
||||
end
|
||||
|
||||
rgb_to_hex(rgb)
|
||||
end
|
||||
|
||||
def get_arrow_for_cell(value, condition)
|
||||
return content_tag(:td, value) if condition.nil?
|
||||
css_class = condition ? 'up': 'down'
|
||||
content_tag(:td, value, class: css_class)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def interpolate_color(from, to, ratio)
|
||||
from.zip(to).map { |a, b| (a + (b - a) * ratio).round }
|
||||
end
|
||||
|
||||
def rgb_to_hex(rgb)
|
||||
format("#%02X%02X%02X", *rgb)
|
||||
end
|
||||
|
||||
def clamp(value)
|
||||
[[value, 0.0].max, 1.0].min
|
||||
end
|
||||
|
||||
RED = [248, 105, 107].freeze
|
||||
YELLOW = [255, 235, 132].freeze
|
||||
GREEN = [99, 190, 123].freeze
|
||||
WHITE = [255, 255, 255].freeze
|
||||
|
||||
end
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
- unless @info_about_organisation.any?
|
||||
= 'У данной организации пока не загружена отчетность'
|
||||
- else
|
||||
- min_max_data = prepare_data(@current_doc_info1)
|
||||
- comparsion_data = prepare_data(@current_doc_info1, type_data: 'comparsion')
|
||||
.informations-data
|
||||
h2
|
||||
= "Сведения об организации"
|
||||
@@ -27,10 +29,18 @@
|
||||
tr
|
||||
td = key[0]
|
||||
td = key[1]
|
||||
- @current_doc_info1[key].each do |value|
|
||||
td = value
|
||||
|
||||
- @current_doc_info1[key].each_with_index do |value, index|
|
||||
- key_group = key[1].nil? ? nil : group_key(key[1])
|
||||
- if min_max_data.has_key?(key_group) && keep_code?(key[1])
|
||||
- min_value = min_max_data[key_group][index + 1][:min]
|
||||
- max_value = min_max_data[key_group][index + 1][:max]
|
||||
- p50 = min_max_data[key_group][index + 1][:p50]
|
||||
- color = get_color_for_cell(value, min: min_value, median: p50, max: max_value)
|
||||
td style="background-color: #{color}" = value
|
||||
- elsif comparsion_data.has_key?(key[1]) && keep_code?(key[1], type_data: 'comparsion')
|
||||
- condition = comparsion_data[key[1]][index]
|
||||
= get_arrow_for_cell(value, condition)
|
||||
- else
|
||||
td = value
|
||||
- else
|
||||
h3
|
||||
= "Нет данных"
|
||||
|
||||
h3 = "Нет данных"
|
||||
Reference in New Issue
Block a user