import io import uuid from fastapi import APIRouter, Depends, File, UploadFile, HTTPException from fastapi.responses import StreamingResponse from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.middleware.auth import get_current_user, require_director from app.services.excel_import import import_from_excel router = APIRouter(prefix="/import", tags=["Import"]) @router.get("/template") async def download_weekly_report_template(): """Download a 4-sheet weekly report import template.""" from openpyxl import Workbook from openpyxl.styles import Font wb = Workbook() header_font = Font(bold=True) # Sheet 1: 每日拜访记录 ws1 = wb.active ws1.title = "每日拜访记录" ws1.append(["客户单位", "拜访日期", "拜访方式", "时间范围", "拜访人姓名", "拜访人电话", "沟通内容", "客户需求", "同访人员", "客户经理"]) for c in ws1[1]: c.font = header_font ws1.append(["XX科技有限公司", "2026-06-23", "上门", "9:00-10:00", "韦柳柏", "13800000000", "沟通了解云桌面需求", "希望扩容", "", "韦矍森"]) ws1.column_dimensions['A'].width = 20; ws1.column_dimensions['E'].width = 30; ws1.column_dimensions['F'].width = 20 # Sheet 2: 下周工作计划 ws2 = wb.create_sheet("下周工作计划") ws2.append(["客户单位", "工作计划", "计划拜访时间", "客户经理", "状态"]) for c in ws2[1]: c.font = header_font ws2.append(["XX科技有限公司", "跟进云桌面扩容方案", "2026-06-30", "韦柳柏", "计划中"]) ws2.column_dimensions['A'].width = 20; ws2.column_dimensions['B'].width = 35 # Sheet 3: 小微业务商机 ws3 = wb.create_sheet("小微业务商机") ws3.append(["客户单位", "产品类型", "金额", "跟进内容具体情况", "跟进状态", "客户经理", "预计列收时间"]) for c in ws3[1]: c.font = header_font ws3.append(["XX科技有限公司", "云桌面", "5000元/月", "确认技术方案中", "跟进中", "韦柳柏", "2026Q3"]) ws3.column_dimensions['A'].width = 20; ws3.column_dimensions['D'].width = 30 # Sheet 4: 要客拜访计划 ws4 = wb.create_sheet("要客拜访计划") ws4.append(["客户单位", "紧急重要度", "内容描述", "进展状态", "计划拜访时间", "计划拜访人", "拜访对象", "客户经理"]) for c in ws4[1]: c.font = header_font ws4.append(["XX科技有限公司", "重要", "拜访技术负责人确认方案", "未开始", "2026-07-01", "韦柳柏", "王局长", "韦矍森"]) ws4.column_dimensions['A'].width = 20; ws4.column_dimensions['C'].width = 30 output = io.BytesIO() wb.save(output) output.seek(0) return StreamingResponse( output, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", headers={"Content-Disposition": "attachment; filename=weekly_report_template.xlsx"}, ) @router.post("/weekly-report") async def import_weekly_report( file: UploadFile = File(...), current_user: dict = Depends(require_director), db: AsyncSession = Depends(get_db), ): """Upload old weekly report Excel and import data. Only director can do this.""" if not file.filename or not file.filename.endswith(('.xlsx', '.xls')): raise HTTPException(status_code=400, detail="Only .xlsx and .xls files are supported") content = await file.read() try: import openpyxl wb = openpyxl.load_workbook(io.BytesIO(content), data_only=True) preview = {} for sheet_name in wb.sheetnames: ws = wb[sheet_name] headers = [str(cell.value) for cell in ws[1]] row_count = ws.max_row - 1 preview[sheet_name] = {"headers": headers, "row_count": row_count} except Exception as e: raise HTTPException(status_code=400, detail=f"Failed to parse Excel: {str(e)}") stats = await import_from_excel(db, content, uuid.UUID(current_user["user_id"])) stats["preview"] = preview return stats