From dea365977e1ea386a877108291a19c3103aeb05f Mon Sep 17 00:00:00 2001 From: xiaji Date: Mon, 12 Jan 2026 16:47:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8A=A5=E8=A1=A8=E5=AF=BC=E5=87=BA):=20?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=88=86=E6=94=AF=E6=9C=BA=E6=9E=84=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在Excel和PDF导出中增加省份分组显示,并添加统计信息 - 按省份分组显示分支机构数据 - 添加省份标题行和统计信息 - 优化表格样式和布局 - 在HTML模板中显示分支机构数量 --- .../huodong/__pycache__/views.cpython-311.pyc | Bin 32278 -> 38033 bytes fzjgact/huodong/templates/branch_info.html | 2 +- fzjgact/huodong/views.py | 138 ++++++++++++++++-- 3 files changed, 126 insertions(+), 14 deletions(-) diff --git a/fzjgact/huodong/__pycache__/views.cpython-311.pyc b/fzjgact/huodong/__pycache__/views.cpython-311.pyc index 661d527c3bd3409189ed1072f7cd43c17b6d92c9..ce78a92ba997b37606cfc8937cf9e532d2e8fe75 100644 GIT binary patch delta 6570 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 FzX892*gOCL delta 2350 zcmZXU4Nz276oB7-`}XaFh2^JZVFg7%(KQ3n6eSZ-Q1E9NSTI72U3n`%A&Ykx#oA2> zMoA@Lj+M+wZ_Yh`@4S1@ zy}bwcm;WM$H^Re1IW|0R$aQDy4jXQzCpHUgo_llmb_)qe)eeud#zi-&%7skX3^6m# z#VE{$<|5uf97VhfKh2m*29)@WT0wstH75`s!HcuA$Z6%{*~KJEWEu^7f4)LE?iJ2M zz_Hl~*_qShWM0i;1#^ugIf3?bNO_iIL1Yk#r-_T^|LoP z^0?L6m2BqI`6M`;WscIxf>){^P0P~k&9W5fWRYprf5*6k+WoAqeymL$gxithiM==D zI9Yd4+Rtk4XK!%$LgWx{h#WefO}zx}#+qPHVRWK5#Ku|l){$tYzS+5DXy>7!*9L}m zcicF>cc|^q2y|zg$O!Duo+)f*9uSsWPr_kiZk}m1o6;kQM23Lic5HB3LSga3d2s<9 zb#1I_Y+k1>c|f90cay8p?F3RA1J}x;B3c^U^eT&*z^ZfW2+UiQB1KN}PoC#DWPx+h zii*~P5s^!n+*khQ`it=ym*O*qIbNGjf_x#OQ`cj+gqFNZQl4LZV9%05eFXcqx~+X0rMK=w0*4E;OukS#MmE*(HN>a)hO%u* z@r8Ny;8+^FIjkNd)Zq=QkGv<>@MD*lZNel^$~`MvX8l;ZFWfWvzEzHu<7BfZ^}eRw zcu!s{$m8x??Ll>Y%me0lIRPEK0&^WNPhiOs<%wgGnI7;?K&$GT#G)q3(PKPgp{g-n zYw(8m#X;NL7-E1ns|8w?MzJpLGouQo7Mo&{t$#!~nwlEw*deQPHKsSoYw3Bg6{nF; z;rZf#{tWvdJ&QO8y(Keq4hR8l?()JVR{9H59^h#g+7JP8QNFb_za$_nF0z(db64au zUsbjhR^+Sh^j8ju&8)*vl#^`6us<ng&Pp(*eot^w>O`8c@+(*C1OWXelPWf*3@wc(H8ul+RG^VF(Da!{Z1x zuh!#OgQ0HB;Knw9N;*Dn4RthD*E-!*xCpVVjUU5S&gGR}Y9tW-#Ek6Lf?<&}B>Ph` z{b6(c`gyH+m!roGb42^7icaye6xOZZrtev~b5&pJzI4BF=0$1NC25vleZW_q0k-CD zMPBtRAzPHMD|rnGz);mBq5-{qAvpEJMikcoz3}dy>M{u6T zoM;+K>4*%(1n6&CRGxt12%7(EFed$m)87$)BmO}U^b-)+d{oOMOOkryQ4zI+sMVqL z4N4MJtWSo$HXs*vV%UMA#uu$=GS>Xfk0==Oi}>H zT2jdgxZYC6x?%37b<<8@!OJjqIbsDvK&W=fPO6@+LR6|9u@o+Bnx!pa^BhI@%#(t? zoQW>B^6rZqM0Jc;I-eUPWF^$MrbL!v6rv67tIqRc!#ImXm0Nvg17Yv}wX~b0o-U_r3r2+&V9*SE*anUF)SMW#i z$0*iLu@qWMz@B1^UgwgV8=MR1My6vA=k_Z{dxrUBGcgWxqsS^CIDddEdH4j*{0nPQ BWO4ui diff --git a/fzjgact/huodong/templates/branch_info.html b/fzjgact/huodong/templates/branch_info.html index cee8103..32e6080 100644 --- a/fzjgact/huodong/templates/branch_info.html +++ b/fzjgact/huodong/templates/branch_info.html @@ -25,7 +25,7 @@ {% if forloop.first %} - {{ province }} + {{ province }}({{ branches|length }}) {% endif %} diff --git a/fzjgact/huodong/views.py b/fzjgact/huodong/views.py index 7a33c71..8f159ee 100644 --- a/fzjgact/huodong/views.py +++ b/fzjgact/huodong/views.py @@ -290,17 +290,74 @@ def export_branches_xls(request): worksheet.title = "分支机构信息" # 添加表头 - headers = ['分支机构名称', '信息系统类别'] + headers = ['所在省份', '分支机构名称', '信息系统类别'] for col_num, header in enumerate(headers, 1): worksheet.cell(row=1, column=col_num, value=header) - # 获取所有分支机构数据 - branches = Branch.objects.all() + # 获取所有分支机构数据并按省份分组 + branches = Branch.objects.all().order_by('location', 'name') + from collections import defaultdict + branches_by_province = defaultdict(list) + for branch in branches: + branches_by_province[branch.location].append(branch) + branches_by_province = dict(sorted(branches_by_province.items())) # 填充数据 - for row_num, branch in enumerate(branches, 2): - worksheet.cell(row=row_num, column=1, value=branch.name) - worksheet.cell(row=row_num, column=2, value=branch.category) + row_num = 2 + for province, province_branches in branches_by_province.items(): + # 添加省份标题行 + worksheet.cell(row=row_num, column=1, value=f"{province}({len(province_branches)})") + worksheet.cell(row=row_num, column=2, value="") + worksheet.cell(row=row_num, column=3, value="") + + # 设置省份标题行样式 + province_row = worksheet[row_num] + for cell in province_row: + cell.font = Font(bold=True) + cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid") + + row_num += 1 + + # 填充该省份的分支机构数据 + for branch in province_branches: + worksheet.cell(row=row_num, column=1, value=branch.location) + worksheet.cell(row=row_num, column=2, value=branch.name) + worksheet.cell(row=row_num, column=3, value=branch.category) + row_num += 1 + + row_num += 1 # 空行分隔 + + # 添加统计信息 + row_num += 1 + worksheet.cell(row=row_num, column=1, value="省份统计") + worksheet.cell(row=row_num, column=2, value=f"总计 {len(branches)} 个分支机构,分布在 {len(branches_by_province)} 个省份") + worksheet.cell(row=row_num, column=3, value="") + + # 设置统计行样式 + stats_row = worksheet[row_num] + for cell in stats_row: + cell.font = Font(bold=True) + cell.fill = PatternFill(start_color="FFD700", end_color="FFD700", fill_type="solid") + + # 添加类别统计 + row_num += 1 + type_a_count = branches.filter(category='A型').count() + type_b_count = branches.filter(category='B型').count() + type_c_count = branches.filter(category='C型').count() + worksheet.cell(row=row_num, column=1, value="类别统计") + worksheet.cell(row=row_num, column=2, value=f"A型: {type_a_count}家 | B型: {type_b_count}家 | C型: {type_c_count}家") + worksheet.cell(row=row_num, column=3, value="") + + # 设置类别统计行样式 + category_row = worksheet[row_num] + for cell in category_row: + cell.font = Font(bold=True) + cell.fill = PatternFill(start_color="FFD700", end_color="FFD700", fill_type="solid") + + # 设置列宽 + worksheet.column_dimensions['A'].width = 25 + worksheet.column_dimensions['B'].width = 40 + worksheet.column_dimensions['C'].width = 15 # 设置响应 response = HttpResponse(content_type='application/vnd.ms-excel') @@ -353,13 +410,28 @@ def export_branches_pdf(request): title = Paragraph("分支机构信息", title_style) elements.append(title) - # 获取所有分支机构数据 - branches = Branch.objects.all() + # 获取所有分支机构数据并按省份分组 + branches = Branch.objects.all().order_by('location', 'name') + from collections import defaultdict + branches_by_province = defaultdict(list) + for branch in branches: + branches_by_province[branch.location].append(branch) + branches_by_province = dict(sorted(branches_by_province.items())) # 准备表格数据 - data = [['分支机构名称', '信息系统类别']] # 表头 - for branch in branches: - data.append([branch.name, branch.category]) + data = [['所在省份', '分支机构名称', '信息系统类别']] # 表头 + + # 按省份填充数据 + for province, province_branches in branches_by_province.items(): + # 添加省份标题行 + data.append([f"{province}({len(province_branches)})", '', '']) + + # 填充该省份的分支机构数据 + for branch in province_branches: + data.append([branch.location, branch.name, branch.category]) + + # 添加空行分隔 + data.append(['', '', '']) # 创建表格 table = Table(data) @@ -368,19 +440,59 @@ def export_branches_pdf(request): style = TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.grey), ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), - ('ALIGN', (0, 0), (-1, -1), 'CENTER'), + ('ALIGN', (0, 0), (-1, -1), 'LEFT'), ('FONTNAME', (0, 0), (-1, 0), chinese_font), # 使用中文字体 ('FONTSIZE', (0, 0), (-1, 0), 14), ('BOTTOMPADDING', (0, 0), (-1, 0), 12), - ('BACKGROUND', (0, 1), (-1, -1), colors.beige), ('FONTNAME', (0, 1), (-1, -1), chinese_font), # 使用中文字体 ('GRID', (0, 0), (-1, -1), 1, colors.black) ]) + + # 设置省份标题行的样式 + current_row = 1 + for province, province_branches in branches_by_province.items(): + # 省份标题行 + style.add('BACKGROUND', (0, current_row), (-1, current_row), colors.lightgrey) + style.add('FONTNAME', (0, current_row), (-1, current_row), chinese_font) + style.add('FONTSIZE', (0, current_row), (-1, current_row), 12) + style.add('TEXTCOLOR', (0, current_row), (-1, current_row), colors.black) + + current_row += 1 + + # 分支机构数据行 + for _ in province_branches: + style.add('BACKGROUND', (0, current_row), (-1, current_row), colors.beige) + current_row += 1 + + # 空行 + current_row += 1 + table.setStyle(style) # 添加表格到文档 elements.append(table) + # 添加统计信息 + elements.append(Spacer(1, 20)) + + # 省份统计 + stats_style = ParagraphStyle( + 'Stats', + parent=styles['Normal'], + fontName=chinese_font, + fontSize=12, + spaceAfter=10 + ) + stats_text = f"省份统计:总计 {len(branches)} 个分支机构,分布在 {len(branches_by_province)} 个省份" + elements.append(Paragraph(stats_text, stats_style)) + + # 类别统计 + type_a_count = branches.filter(category='A型').count() + type_b_count = branches.filter(category='B型').count() + type_c_count = branches.filter(category='C型').count() + category_text = f"类别统计:A型: {type_a_count}家 | B型: {type_b_count}家 | C型: {type_c_count}家" + elements.append(Paragraph(category_text, stats_style)) + # 构建PDF doc.build(elements)