Class: TalltyImportExport::Export

Inherits:
Object
  • Object
show all
Defined in:
lib/tallty_import_export/export.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass) ⇒ Export

Returns a new instance of Export.



5
6
7
# File 'lib/tallty_import_export/export.rb', line 5

def initialize klass
  @klass = klass
end

Instance Attribute Details

#klassObject (readonly)

Returns the value of attribute klass.



3
4
5
# File 'lib/tallty_import_export/export.rb', line 3

def klass
  @klass
end

Instance Method Details

#export_headers(**args) ⇒ Object



143
144
145
# File 'lib/tallty_import_export/export.rb', line 143

def export_headers **args
  @headers || klass.try(:headers) || klass.try(:model_headers)
end

#export_headers_resultObject



139
140
141
# File 'lib/tallty_import_export/export.rb', line 139

def export_headers_result
  @headers || export_headers
end

#export_workbook(workbook, records) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/tallty_import_export/export.rb', line 66

def export_workbook workbook, records
  # excel导出样式
  alignment = { vertical: :center, horizontal: :center }
  border    = { color: '969696', style: :thin }
  title1 = workbook.styles.add_style(alignment: alignment, border: border, sz: 12, b: true)
  title2 = workbook.styles.add_style(alignment: alignment, border: border, bg_color: "2a5caa",  sz: 12, fg_color: "fffffb")
  title3 = workbook.styles.add_style(alignment: alignment.merge(wrap_text: true), border: border, sz: 10)
  headers = export_headers_result

  _sheet_name = respond_to?(:sheet_name) ? self.sheet_name : nil

  workbook.add_worksheet(name: _sheet_name) do |sheet|
    if respond_to?(:first_header)
      row_index = Axlsx.col_ref(headers.size - 1)
      sheet.merge_cells("A1:#{row_index}1")
      sheet.add_row [first_header], style: title1, height: 40
    end

    sheet.add_row headers.map{|header| header[:name]}, style: title2, height: 39

    last_row = nil
    merge_column_hash = {}
    first_content_row_index = respond_to?(:first_header) ? 2 : 1

    each_method = records.is_a?(Array) ? :each : :each
    records.send(each_method).with_index do |record, index|
      row = []
      headers.each_with_index do |header, col_index|
        _data = handle_data(record, header, index)
        if header[:merge].present? && last_row.present? && _data == last_row[col_index]
          # 这里使用二维数组,每个数组里都是列内容相同的各行
          merge_column_hash[col_index] ||= []
          if merge_column_hash[col_index].last&.last == index + first_content_row_index - 1
            # 说明内容和上面的是延续的,继续加入之前的数组
            merge_column_hash[col_index].last << index + first_content_row_index
          else
            merge_column_hash[col_index] << [index + first_content_row_index - 1, index + first_content_row_index]
          end
        end
        row.push(_data)
      end
      sheet.add_row row, style: title3, height: @row_height, types: headers.map{|header| header[:format]&.to_sym}
      last_row = row
    end
    # 需要根据column进行多行的内容合并
    if merge_column_hash.present?
      merge_column_hash.each do |col_index, row_arr|
        row_arr.each do |arr|
          sheet.merge_cells(
            Axlsx::cell_r(col_index, arr.first) + ':' + Axlsx::cell_r(col_index, arr.last)
          )
        end
      end
    end
    sheet.column_widths(*headers.map{|header| (header[:width] || @width).to_f})
  end
end

#export_xlsx(records, **options) ⇒ Object

[

{ key: 'entry_user_name', name: '被考核人', chain: [:entry, :user_name] },
{ key: 'entry_user_code', name: '被考核人工号' },
{ key: 'entry_user_department_name', name: '被考核人部门' },
{ key: 'dimension_name', name: '考核维度' },
{ key: 'user_name', name: '考核人' },
{ key: 'user_code', name: '考核人工号' },
{ key: 'user_department_name', name: '考核人部门' },
{ key: 'state', name: '考核状态', method: :state_zh },
{ key: 'score', name: '考核分' },

] export_headers_result / headers key: 属性的英文名,可以支持user.name这样的方式name: 属性的中文名attr_type: 属性的类型format: excel是否需要特定的格式,目前主要是类似于身份证号,可以用string method: 导出时本地调用的方法chain: 导出时对象属性通过链式调用index: 数组方式,需要嵌套拿到里面的merge: true/false,默认false,某一列,如果上下行的内容相同,则直接合并单元格json: model_payload,代表存储在某一个列中



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/tallty_import_export/export.rb', line 31

def export_xlsx records, **options
  records = with_scope records
  process_options(options)

  options = options.with_indifferent_access

  Axlsx::Package.new do |pack|
    workbook = pack.workbook

    if @group_by.present?
      @header = nil # 因为group_by的,基本上都是export_header动态变化的,因此去掉选择
      if records.is_a?(Array)
        records.group_by { |record| record.send(@group_by)}.each do |key, group_records|
          @group_key = key
          export_workbook workbook, group_records
        end
      else
        records.group(@group_by).count.keys.each do |key|
          @group_key = key
          export_workbook workbook, records.ransack("#{@group_where}" => key).result
        end
      end
    else
      export_workbook workbook, records
    end

    file_path = File.join(Rails.root, 'public', 'export')
    FileUtils.mkdir_p(file_path) unless Dir.exist?(file_path)
    file_name = "#{Time.now.strftime('%Y%m%d%H%M%S')}#{@filename}.xlsx"
    file_path_with_name = File.join(file_path, file_name)
    pack.serialize(file_path_with_name)
    return file_path_with_name
  end
end

#handle_data(record, header, index = 0) ⇒ Object

处理一个记录的数据



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/tallty_import_export/export.rb', line 148

def handle_data record, header, index=0
  data =
    if header[:key] == '_index'
      index + 1
    elsif header[:method].present?
      send(header[:method], record, header)
    elsif header[:chain].present?
      try_chain(record, header[:chain])
    elsif header[:json]
      record.send(header[:json])[header[:key]]
    else
      try_method(record, header[:key])
    end
    handle_format(data, header)
rescue
  ''
end

#handle_format(data, header) ⇒ Object

根据数据类型 attr_type 进行数据的格式化



176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/tallty_import_export/export.rb', line 176

def handle_format data, header
  case header[:attr_type].to_s
  when 'string'
    data.to_s
  when 'datetime'
    data ? data.strftime('%F %H:%M') : nil
  when 'date'
    data ? data.strftime('%F') : nil
  else
    data
  end
end

#process_options(options = {}) ⇒ Object



124
125
126
127
128
129
130
131
132
133
# File 'lib/tallty_import_export/export.rb', line 124

def process_options options = {}
  options = options.with_indifferent_access

  @row_height ||= options.delete(:row_height) || 35
  @width ||= (options.delete(:width) || 20).to_f
  @filename ||= options.delete(:filename)
  @group_by ||= options.delete(:group_by)
  @group_where = "#{@group_by}_eq" if @group_by.present?
  @headers ||= options.delete(:headers)
end

#try_chain(record, arr) ⇒ Object



166
167
168
# File 'lib/tallty_import_export/export.rb', line 166

def try_chain record, arr
  arr.inject(record, :try)
end

#try_method(record, method) ⇒ Object



170
171
172
173
# File 'lib/tallty_import_export/export.rb', line 170

def try_method record, method
  arr = method.to_s.split(/\./)
  try_chain record, arr
end

#with_scope(records) ⇒ Object



135
136
137
# File 'lib/tallty_import_export/export.rb', line 135

def with_scope records
  records
end