123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- # -*- coding: utf-8 -*-
- from . import util
- # 得到多组列表
- # 用法举例:
- # helper = MultiColTableHelper(6,2,3) # 一页6行、一页2组(指2大列)、每组3列
- # helper.add_a_style_class('cell_sum', '''
- # .cell_sum{
- # font-size:18px;
- # }''')#add_a_style_class必须在add_group_data方法前面。可以有多个
- # helper.add_a_style_class('cell_content', '''
- # .cell_content{
- # font_size:16px;
- # border-right: 1px solid gray;
- # border-collapse:collapse;
- # border-spacing:0;
- # }''')#add_a_style_class必须在add_group_data方法前面。可以有多个
- # 只有一个数据,表示合计行;如果是一个也没有,则表示空行。==合计行的数据,格式需要自己处理==
- # helper.add_group_data([u'<td colspan="3" class="cell_sum">合计 21</td>']) # 合计行
- # helper.add_group_data(['a', 'b', 'c'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data(['1', '2', '3'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data(['4', '5', '6'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data(['7', '8', '9'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data(['11', '12', '13'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data(['14', '15', '16'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data([u'<td colspan="3" class="cell_sum">合计 22 其他 33</td>']) # 合计行
- # helper.add_group_data(['a', 'b', 'c'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.add_group_data(['21', '22', '23'], ['cell_content', 'cell_content', 'cell_content'])
- # helper.set_between_table()
- # helper.get() # 结果参见后面的“多组列表”
- # ======多组列表======
- # 若数据为:
- # |合计 21 |14 |15 |16 |
- # |a |b |c |合计 22 其他 33 |
- # |1 |2 |3 |a |b |c |
- # |4 |5 |6 |21 |22 |23 |
- # |7 |8 |9 | |
- # |11 |12 |13 | |
- # 则:表示2组,每组有3列
- class MultiColTableHelper(object):
- default_title_attr = u'style="font-size:20px;" align="center"'
- def __init__(self, row_count, group_count, col_count_in_group):
- if group_count < 1:
- group_count = 1
- if row_count < 0:
- row_count = 0
- self._class_dic = {}
- self._row_count = row_count
- self._group_count = group_count
- self._col_count_in_group = col_count_in_group
- self._data = []
- self._string_between_table = u''
- self._title = u''
- self._title_attr = u''
- def add_a_style_class(self, class_name, class_content):
- self._class_dic[class_name] = class_content
- return
- def set_title(self, title, title_attr=''):
- self._title = title
- if title_attr:
- self._title_attr = title_attr
- else:
- self._title_attr = self.default_title_attr
- return
- def add_group_data(self, group_row, style_or_class=[]):
- data = []
- if not group_row:
- self._data.append(data) # 空行
- return
- if len(group_row) == 1:
- data.append(Cell(group_row[0], need_add_td=False)) # 一行只有一个数据。用于合计行。合计行需要包含格式
- else:
- if not style_or_class:
- for c in group_row:
- data.append(Cell(c))
- else:
- _len = len(style_or_class)
- if _len < len(group_row):
- tail = group_row[_len:] # 没有格式的
- self._add_cell(data, group_row, _len, style_or_class)
- for c in tail:
- data.append(Cell(c))
- else:
- self._add_cell(data, group_row, len(group_row), style_or_class)
- self._data.append(data)
- return
- def _add_cell(self, data, group_row, length, style_class):
- for i in range(length):
- if style_class[i] in self._class_dic:
- data.append(Cell(group_row[i], style_class_name=style_class[i]))
- else:
- data.append(Cell(group_row[i], style=style_class[i]))
- return
- def set_between_table(self, string_between_table='''<div style="padding-bottom:20px;"></div>'''):
- self._string_between_table = string_between_table
- def get(self):
- if not self._data:
- return u''
- if not self._row_count:
- return self._get_one_table_page()
- group_arr = util.list_split(self._data, self._row_count)
- page_arr = util.list_split(group_arr, self._group_count)
- table_data_list = []
- for group_columns in page_arr:
- row_list = MultiColTableHelper._get_row_list(group_columns, self._row_count, self._col_count_in_group)
- table_data_list.append(row_list)
- return self._get_table(table_data_list)
- def _get_one_table_page(self):
- remain = len(self._data) % self._group_count
- row_count = len(self._data) / self._group_count
- if remain > 0:
- row_count += 1
- group_arr = util.list_split(self._data, row_count)
- row_list = MultiColTableHelper._get_row_list(group_arr, row_count, self._col_count_in_group)
- return self._get_table([row_list])
- # 参数group_arr:
- # 为一个list,每一项表示一个组(多个列;每组的多个列一一对应)
- # 每个组,为一个list,每一项,表示这一组中的一行
- # 组中的一行,为一个list,每一项表示一个单元格的信息,即一个Cell对象
- # 参数row_count:
- # table的行数。也是group_arr中,每个组的最大行数(要么所有组为row_count行;要么前几组为row_count行,最后一组为小于row_count行)
- # 参数col_count_in_group:
- # 每个组里面的列的个数
- @staticmethod
- def _get_row_list(group_arr, row_count, col_count_in_group):
- result = []
- if not group_arr:
- return result
- need_add_empty = True
- for i in range(row_count):
- row = []
- empty_count = 0 # 最后一组中,为空的行数
- for group in group_arr:
- if len(group) > i:
- for cell in group[i]:
- row.append(cell)
- else:
- empty_count = row_count - i
- if need_add_empty and empty_count > 0:
- need_add_empty = False
- if empty_count == 1:
- cell = Cell(u'', attr=u'''colspan="%s"''' % col_count_in_group)
- else:
- cell = Cell(u'', attr=u'''colspan="%s" rowspan="%s"''' % (col_count_in_group, empty_count))
- row.append(cell)
- result.append(row)
- return result
- # 参数row_list_arr:
- # 为一个list,每一项,为一个table的数据;
- # 每个table的数据,为一个list,每一项表示一行数据;
- # 每一行数据,为一个list,每一项为一个Cell对象
- def _get_table(self, row_list_arr):
- result = []
- title = self._get_title()
- for table_row_list in row_list_arr:
- if title:
- result.append(title)
- table = Table()
- table.set_class(self._class_dic)
- table.add_rows(table_row_list)
- result.append(table.get())
- return self._string_between_table.join(result)
- def _get_title(self):
- if self._title:
- attr = self._title_attr if self._title_attr else self.default_title_attr
- return u'<div%s>%s</div>' % (u' ' + attr, self._title)
- return u''
- class Cell(object):
- def __init__(self, data, style_class_name=u'', style=u'', need_add_td=True, attr=u''):
- self._data = data
- self._style_class_name = style_class_name
- self._style = style
- self._need_add_td = need_add_td
- self._attr = attr
- def add_class(self, style_class):
- if self._style_class_name:
- self._style_class_name += ' ' + style_class
- else:
- self._style_class_name = style_class
- def get(self):
- if self._need_add_td:
- c = u''' class="%s"''' % self._style_class_name if self._style_class_name else u''
- s = u''' style="%s"''' % self._style if self._style else u''
- a = u' ' + self._attr if self._attr else u''
- return u'''<td%s%s%s>%s</td>''' % (c, s, a, self._data)
- return self._data
- class Table(object):
- table_start = u'''<table style="width:100%;border: 1px solid gray;font-size:15px;">
- '''
- table_end = u'''
- </table>
- '''
- line_start = u'''
- <tr>'''
- line_end = u'''
- </tr>'''
- style_format = u'''
- <style>
- table {
- border-collapse:collapse; /* 关键属性:合并表格内外边框(其实表格边框有2px,外面1px,里面还有1px哦) */
- border:solid #FFF; /* 设置边框属性:样式(solid=实线)、颜色(#FFF=黑) */
- border-width:1px 0 0 1px; /* 设置边框状粗细:上 右 下 左 = 对应:1px 0 0 1px */
- }
- table caption {font-size:14px;font-weight:bolder;}
- table th, table td {border:solid #999;border-width:0 1px 1px 0;padding:2px;} /* 设置表格每个td的边框, 只设置下侧和右侧的边框 */
- tfoot td {text-align:center;}
- %s
- </style>
- '''
- def __init__(self):
- self._rows = []
- self._class_dic = {}
- pass
- def set_class(self, class_dic):
- self._class_dic = class_dic
- def add_row(self, row):
- self._rows.append(row)
- return
- def add_rows(self, rows):
- self._rows += rows
- def get(self):
- result = self.table_start + self._get_style()
- for row in self._rows:
- result += self.line_start
- for cell in row:
- result += cell.get()
- result += self.line_end
- result += self.table_end
- return result
- def _get_style(self):
- if self._class_dic:
- v = '''
- '''.join(self._class_dic.values())
- else:
- v = ''
- return self.style_format % v
|