feat: 操作日志系统 + 日期修复 + 协同去重 + 主题持久化 + 计划自动完成
本次累积提交包含以下功能: 1. 修复:el-date-picker 缺失 value-format 导致日期保存偏移(8处) 2. 新增:协同拜访 visit_group_id 去重机制(完整副本 + 周报合并 + 亮灯去重) 3. 新增:计划自动完成(创建计划检测已有拜访 / 编辑拜访触发) 4. 新增:拜访表单选择客户后自动预填过期计划内容 5. 新增:移动端主题切换按钮 + 后端持久化 6. 新增:操作日志系统 (audit_logs),全覆盖 8 个模块 CRUD 7. 新增:PC端「我的数据」支局长/领导视角客户经理列 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,8 @@ async def get_dashboard_stats(db: AsyncSession, reference_date: date | None = No
|
||||
today = date.today()
|
||||
|
||||
visits_count = (await db.execute(
|
||||
select(func.count(Visit.id)).where(Visit.visit_date >= monday, Visit.visit_date <= sunday)
|
||||
select(func.count(func.distinct(func.coalesce(Visit.visit_group_id, Visit.id))))
|
||||
.where(Visit.visit_date >= monday, Visit.visit_date <= sunday)
|
||||
)).scalar() or 0
|
||||
|
||||
plans_count = (await db.execute(
|
||||
@@ -171,31 +172,52 @@ async def get_weekly_report(
|
||||
visits_result = await db.execute(visit_query)
|
||||
visits = visits_result.scalars().all()
|
||||
|
||||
visits_data = []
|
||||
# Group visits by visit_group_id (or id for solo visits)
|
||||
groups: dict[str, list] = {}
|
||||
for v in visits:
|
||||
# Resolve companion names: system users → names, external → direct
|
||||
companion_names_resolved = [user_map.get(c, str(c)) for c in (v.companions or [])]
|
||||
companion_names_resolved.extend(v.companion_names or [])
|
||||
visits_data.append({
|
||||
"id": str(v.id),
|
||||
"customer_id": str(v.customer_id),
|
||||
"customer_name": customer_map.get(v.customer_id, ""),
|
||||
"visit_date": str(v.visit_date),
|
||||
"visit_method": v.visit_method,
|
||||
"time_range": v.time_range,
|
||||
"visitor_name": v.visitor_name or "",
|
||||
"visitor_phone": v.visitor_phone or "",
|
||||
"communication_content": v.communication_content,
|
||||
"customer_demand": v.customer_demand,
|
||||
"companions": [str(c) for c in (v.companions or [])],
|
||||
"companion_names": v.companion_names or [],
|
||||
gid = str(v.visit_group_id) if v.visit_group_id else str(v.id)
|
||||
groups.setdefault(gid, []).append(v)
|
||||
|
||||
visits_data = []
|
||||
for gid, gvisits in groups.items():
|
||||
# Determine the "primary" — first record in group (the creator's)
|
||||
primary = gvisits[0]
|
||||
companion_names_resolved = [user_map.get(c, str(c)) for c in (primary.companions or [])]
|
||||
companion_names_resolved.extend(primary.companion_names or [])
|
||||
|
||||
merged = {
|
||||
"id": str(primary.id),
|
||||
"customer_id": str(primary.customer_id),
|
||||
"customer_name": customer_map.get(primary.customer_id, ""),
|
||||
"visit_date": str(primary.visit_date),
|
||||
"visit_method": primary.visit_method,
|
||||
"time_range": primary.time_range,
|
||||
"visitor_name": primary.visitor_name or "",
|
||||
"visitor_phone": primary.visitor_phone or "",
|
||||
"visit_group_id": gid if len(gvisits) > 1 else None,
|
||||
"companions": [str(c) for c in (primary.companions or [])],
|
||||
"companion_names": primary.companion_names or [],
|
||||
"companion_names_resolved": companion_names_resolved,
|
||||
"photos": v.photos or [],
|
||||
"manager_id": str(v.manager_id),
|
||||
"manager_name": user_map.get(v.manager_id, ""),
|
||||
"edit_log": v.edit_log or [],
|
||||
"created_at": str(v.created_at),
|
||||
})
|
||||
"communication_content": primary.communication_content,
|
||||
"customer_demand": primary.customer_demand,
|
||||
"photos": primary.photos or [],
|
||||
"manager_id": str(primary.manager_id),
|
||||
"manager_name": user_map.get(primary.manager_id, ""),
|
||||
"edit_log": primary.edit_log or [],
|
||||
"created_at": str(primary.created_at),
|
||||
"participants": [
|
||||
{
|
||||
"manager_id": str(v.manager_id),
|
||||
"manager_name": user_map.get(v.manager_id, ""),
|
||||
"role": "primary" if v is primary else "companion",
|
||||
"communication_content": v.communication_content,
|
||||
"customer_demand": v.customer_demand,
|
||||
"photos": v.photos or [],
|
||||
}
|
||||
for v in gvisits
|
||||
],
|
||||
}
|
||||
visits_data.append(merged)
|
||||
|
||||
# ── Work Plans ──
|
||||
wp_query = select(WorkPlan)
|
||||
|
||||
Reference in New Issue
Block a user