Files
qiji/backend/app/services/excel_export.py
T
v6ole a1886074dd 企迹(qiji) 政企周报管理系统 — v0.1
后端: FastAPI + SQLAlchemy 2.0 (async) + Alembic + MinIO + Casdoor + 企微
前端: Vue 3 + Vite + TypeScript + Element Plus + Pinia

功能清单:
- 8 张数据表自动建表 / Casdoor OIDC 登录 / 企微静默登录
- 双布局: 移动端(填报) + PC端(汇总管理)
- 拜访记录 CRUD + MinIO 照片直传 + 缩略图预览 + 同访人草稿
- 今日纪要 (6 分类) / 工作计划 / 小微商机 / 要客拜访 CRUD
- 客户档案: 备注/收支费用/联系人/归属分配/批量转移
- 客户导入导出 + 模板下载 + 搜索/分页/筛选
- 仪表盘: 四卡统计 + 填报进度 (拜访+纪要双维度)
- 周报详情: 五 Tab + 按人/客户筛选 + 时间轴
- 用户管理 / 客户经理 PC 端工作台
- 企微: 催办/公告/定时提醒 / 时区修正
- Docker 部署配置

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 08:30:12 +08:00

138 lines
5.1 KiB
Python

import io
from datetime import date, timedelta
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, Border, Side
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.models.visit import Visit
from app.models.work_plan import WorkPlan
from app.models.mini_business import MiniBusiness
from app.models.key_visit import KeyVisit
from app.models.customer import Customer
from app.models.user import User
def get_week_range(reference_date: date | None = None):
"""Get the Monday and Sunday of the week containing reference_date (defaults to today)."""
today = reference_date or date.today()
monday = today - timedelta(days=today.weekday())
sunday = monday + timedelta(days=6)
return monday, sunday
async def export_weekly_report(db: AsyncSession, reference_date: date | None = None) -> io.BytesIO:
"""Generate a 4-sheet xlsx matching the existing weekly report template."""
monday, sunday = get_week_range(reference_date)
wb = Workbook()
# Pre-fetch lookups
customers_result = await db.execute(select(Customer.id, Customer.name))
customer_map = {str(c.id): c.name for c in customers_result.all()}
users_result = await db.execute(select(User.id, User.name))
user_map = {str(u.id): u.name for u in users_result.all()}
thin_border = Border(
left=Side(style='thin'), right=Side(style='thin'),
top=Side(style='thin'), bottom=Side(style='thin')
)
header_font = Font(bold=True)
# ── Sheet 1: 每日拜访记录 ──
ws1 = wb.active
ws1.title = "每日拜访记录"
headers1 = ["客户单位", "拜访日期", "拜访方式", "时间范围", "沟通内容", "客户需求", "同访人员", "客户经理"]
ws1.append(headers1)
for col in range(1, len(headers1) + 1):
cell = ws1.cell(row=1, column=col)
cell.font = header_font
cell.border = thin_border
visits_result = await db.execute(
select(Visit).where(Visit.visit_date >= monday, Visit.visit_date <= sunday)
)
for v in visits_result.scalars():
companions_names = [user_map.get(str(cid), str(cid)) for cid in (v.companions or [])]
ws1.append([
customer_map.get(str(v.customer_id), ""),
str(v.visit_date),
v.visit_method,
v.time_range,
v.communication_content,
v.customer_demand,
", ".join(companions_names),
user_map.get(str(v.manager_id), ""),
])
# ── Sheet 2: 下周工作计划 ──
ws2 = wb.create_sheet("下周工作计划")
headers2 = ["客户单位", "工作计划", "计划拜访时间", "客户经理", "状态"]
ws2.append(headers2)
for col in range(1, len(headers2) + 1):
cell = ws2.cell(row=1, column=col)
cell.font = header_font
cell.border = thin_border
plans_result = await db.execute(select(WorkPlan))
for p in plans_result.scalars():
ws2.append([
customer_map.get(str(p.customer_id), ""),
p.plan_content,
str(p.plan_date),
user_map.get(str(p.manager_id), ""),
p.status,
])
# ── Sheet 3: 小微业务商机 ──
ws3 = wb.create_sheet("小微业务商机")
headers3 = ["客户单位", "产品类型", "金额", "跟进内容具体情况", "跟进状态", "客户经理", "预计列收时间"]
ws3.append(headers3)
for col in range(1, len(headers3) + 1):
cell = ws3.cell(row=1, column=col)
cell.font = header_font
cell.border = thin_border
mb_result = await db.execute(select(MiniBusiness))
for m in mb_result.scalars():
ws3.append([
customer_map.get(str(m.customer_id), ""),
m.product_type,
m.amount,
m.follow_up_detail,
m.status,
user_map.get(str(m.manager_id), ""),
m.expected_revenue_date,
])
# ── Sheet 4: 要客拜访计划 ──
ws4 = wb.create_sheet("要客拜访计划")
headers4 = ["客户单位", "紧急重要度", "内容描述", "进展状态", "计划拜访时间", "计划拜访人", "拜访对象", "客户经理"]
ws4.append(headers4)
for col in range(1, len(headers4) + 1):
cell = ws4.cell(row=1, column=col)
cell.font = header_font
cell.border = thin_border
kv_result = await db.execute(select(KeyVisit))
for k in kv_result.scalars():
ws4.append([
customer_map.get(str(k.customer_id), ""),
k.urgency_level,
k.description,
k.progress_status,
k.planned_date,
k.planned_visitor,
k.visit_target,
user_map.get(str(k.manager_id), ""),
])
# Adjust column widths
for ws in [ws1, ws2, ws3, ws4]:
for col_cells in ws.columns:
max_length = max((len(str(cell.value or "")) for cell in col_cells), default=10)
ws.column_dimensions[col_cells[0].column_letter].width = min(max_length + 4, 50)
output = io.BytesIO()
wb.save(output)
output.seek(0)
return output