e7af0e15ab
新增: - 今日纪要 (6分类+彩色标签+时间选择器) - 客户经理PC端工作台 (我的数据,5模块CRUD) - 用户管理页 (支局长修改角色) - 客户备注/收支费用(金额+单位)/联系人管理 - 拜访人姓名+电话字段 - 客户导入导出/旧周报导入模板下载 - 序号列+分页(25/50/100) 修复/优化: - Hash路由→HTML5 History, Casdoor回调正常 - 时区统一为Asia/Shanghai (today_cst) - 数据库懒加载→selectinload预加载 - 日期解析兼容ISO datetime字符串 - 文件上传定位修复 (position:relative) - 表单button type='button'防止误提交 - 分管领导权限(只读客户档案,不可编辑) - 侧边栏折叠+SVG图标 - 拜访方式/紧急度统一chip风格 - 时间范围统一为el-time-picker(is-range) - 全局CSS设计变量+box-sizing修复滚动条 Co-Authored-By: Claude <noreply@anthropic.com>
80 lines
3.2 KiB
Python
80 lines
3.2 KiB
Python
import uuid
|
|
from datetime import datetime, date
|
|
from typing import Any
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
import openpyxl
|
|
from app.models.customer import Customer
|
|
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.user import User
|
|
|
|
|
|
async def import_from_excel(db: AsyncSession, file_bytes: bytes, manager_id: uuid.UUID) -> dict:
|
|
"""Parse old weekly report Excel and import data. Returns summary stats."""
|
|
wb = openpyxl.load_workbook(io.BytesIO(file_bytes), data_only=True)
|
|
stats = {"visits": 0, "work_plans": 0, "mini_business": 0, "key_visits": 0, "skipped": 0}
|
|
|
|
# Resolve customer name -> id cache
|
|
customers_result = await db.execute(select(Customer.id, Customer.name))
|
|
customer_map = {c.name: c.id for c in customers_result.all()}
|
|
|
|
# ── Parse Sheet 1: 每日拜访记录 ──
|
|
if "每日拜访记录" in wb.sheetnames:
|
|
ws = wb["每日拜访记录"]
|
|
for row in ws.iter_rows(min_row=2, values_only=True):
|
|
if not row[0]:
|
|
continue
|
|
try:
|
|
cust_name, visit_date_str, visit_method, time_range, visitor_name, visitor_phone, content, demand, companions_str, mgr_str = \
|
|
row[0], str(row[1]) if row[1] else str(date.today()), \
|
|
str(row[2]) if row[2] else "上门", str(row[3]) if row[3] else "", \
|
|
str(row[4]) if row[4] else "", str(row[5]) if row[5] else "", \
|
|
str(row[6]) if row[6] else "", str(row[7]) if row[7] else "", \
|
|
str(row[8]) if row[8] else "", str(row[9]) if row[9] else ""
|
|
|
|
customer_id = customer_map.get(cust_name)
|
|
if not customer_id:
|
|
stats["skipped"] += 1
|
|
continue
|
|
|
|
try:
|
|
visit_date = datetime.strptime(visit_date_str[:10], "%Y-%m-%d").date()
|
|
except ValueError:
|
|
visit_date = date.today()
|
|
|
|
existing = await db.execute(
|
|
select(Visit).where(
|
|
Visit.visit_date == visit_date,
|
|
Visit.manager_id == manager_id,
|
|
Visit.customer_id == customer_id,
|
|
)
|
|
)
|
|
if existing.scalar_one_or_none():
|
|
stats["skipped"] += 1
|
|
continue
|
|
|
|
visit = Visit(
|
|
customer_id=customer_id,
|
|
visit_date=visit_date,
|
|
visit_method=visit_method if visit_method in ["上门", "电话", "微信", "出差"] else "上门",
|
|
time_range=time_range,
|
|
visitor_name=visitor_name,
|
|
visitor_phone=visitor_phone,
|
|
communication_content=content,
|
|
customer_demand=demand,
|
|
manager_id=manager_id,
|
|
)
|
|
db.add(visit)
|
|
stats["visits"] += 1
|
|
except Exception:
|
|
stats["skipped"] += 1
|
|
|
|
await db.commit()
|
|
return stats
|
|
|
|
|
|
import io
|