Merge branch 'main' into develop
# Conflicts: # backend/app/api/key_visits.py # backend/app/api/mini_business.py # backend/app/api/visits.py # backend/app/api/work_plans.py # backend/app/main.py # backend/app/models/__init__.py # backend/app/schemas/key_visit.py # backend/app/schemas/mini_business.py # backend/app/schemas/work_plan.py # backend/app/services/light_board.py # frontend/src/components/DesktopLayout.vue # frontend/src/stores/theme.ts # frontend/src/views/desktop/ManagerWorkspace.vue # frontend/src/views/desktop/WorkPlans.vue # frontend/src/views/mobile/KeyVisitForm.vue # frontend/src/views/mobile/LeaveForm.vue # frontend/src/views/mobile/PlansList.vue # frontend/src/views/mobile/VisitForm.vue # frontend/src/views/mobile/WorkPlanForm.vue
This commit is contained in:
+53
-12
@@ -3,7 +3,7 @@ from datetime import date, datetime
|
||||
from typing import Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy import select, func, or_
|
||||
from app.database import get_db
|
||||
from app.middleware.auth import get_current_user, require_any_role
|
||||
from app.models.visit import Visit
|
||||
@@ -74,6 +74,8 @@ async def list_visits(
|
||||
date_from: Optional[str] = Query(None),
|
||||
date_to: Optional[str] = Query(None),
|
||||
customer_id: Optional[str] = Query(None),
|
||||
customer_type: Optional[str] = Query(None),
|
||||
search: Optional[str] = Query(None),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
@@ -89,6 +91,12 @@ async def list_visits(
|
||||
query = query.where(Visit.visit_date <= parse_date(date_to))
|
||||
if customer_id:
|
||||
query = query.where(Visit.customer_id == uuid.UUID(customer_id))
|
||||
if customer_type:
|
||||
query = query.join(Customer, Visit.customer_id == Customer.id).where(Customer.customer_type == customer_type)
|
||||
if search:
|
||||
query = query.outerjoin(Customer, Visit.customer_id == Customer.id).where(
|
||||
or_(Visit.communication_content.ilike(f"%{search}%"), Visit.customer_demand.ilike(f"%{search}%"), Visit.visitor_name.ilike(f"%{search}%"), Customer.name.ilike(f"%{search}%"))
|
||||
)
|
||||
|
||||
query = query.order_by(Visit.visit_date.desc(), Visit.created_at.desc()).limit(200)
|
||||
result = await db.execute(query)
|
||||
@@ -161,7 +169,7 @@ async def create_visit(
|
||||
companions=data.companions,
|
||||
companion_names=data.companion_names,
|
||||
photos=data.photos,
|
||||
manager_id=uuid.UUID(current_user["user_id"]),
|
||||
manager_id=data.manager_id if (current_user["role"] in ("director", "leader") and data.manager_id) else uuid.UUID(current_user["user_id"]),
|
||||
visit_group_id=group_id,
|
||||
)
|
||||
init_entry(visit, current_user["name"])
|
||||
@@ -176,18 +184,22 @@ async def create_visit(
|
||||
db.add(customer)
|
||||
|
||||
# Auto-complete matching work plans for this customer
|
||||
from app.models.work_plan import WorkPlan
|
||||
plans_result = await db.execute(
|
||||
select(WorkPlan).where(
|
||||
WorkPlan.customer_id == data.customer_id,
|
||||
WorkPlan.status == "计划中",
|
||||
WorkPlan.plan_date <= parse_date(data.visit_date),
|
||||
from app.services.visits import auto_complete_work_plans
|
||||
await auto_complete_work_plans(
|
||||
db, data.customer_id, parse_date(data.visit_date),
|
||||
current_user["name"], "拜访自动完成",
|
||||
)
|
||||
|
||||
# Auto-create follow-up logs for active mini business opportunities
|
||||
from app.models.mini_business import MiniBusiness
|
||||
from app.models.mini_business_log import MiniBusinessLog
|
||||
method_map = {"上门": "上门", "电话": "电话", "微信": "微信", "出差": "其他"}
|
||||
active_biz = await db.execute(
|
||||
select(MiniBusiness).where(
|
||||
MiniBusiness.customer_id == data.customer_id,
|
||||
MiniBusiness.status == "跟进中",
|
||||
)
|
||||
)
|
||||
for plan in plans_result.scalars().all():
|
||||
plan.status = "已完成"
|
||||
append_entry(plan, current_user["name"], [{"field": "status", "from": "计划中", "to": "已完成", "reason": "拜访自动完成"}])
|
||||
|
||||
# Create full copies for companions (not blank drafts)
|
||||
creator_name = current_user["name"]
|
||||
for companion_id in data.companions:
|
||||
@@ -215,6 +227,24 @@ async def create_visit(
|
||||
init_entry(draft, current_user["name"])
|
||||
db.add(draft)
|
||||
|
||||
# Auto-create follow-up logs for active mini business opportunities
|
||||
for biz in active_biz.scalars().all():
|
||||
parts = []
|
||||
if data.communication_content and data.communication_content.strip():
|
||||
parts.append(f"沟通内容:{data.communication_content.strip()}")
|
||||
if data.customer_demand and data.customer_demand.strip():
|
||||
parts.append(f"客户需求:{data.customer_demand.strip()}")
|
||||
log_content = "\n".join(parts) if parts else "拜访跟进"
|
||||
follow_method = method_map.get(data.visit_method, "其他")
|
||||
log = MiniBusinessLog(
|
||||
business_id=biz.id,
|
||||
log_date=parse_date(data.visit_date),
|
||||
method=follow_method,
|
||||
content=log_content,
|
||||
created_by=uuid.UUID(current_user["user_id"]),
|
||||
)
|
||||
db.add(log)
|
||||
|
||||
# Audit log (before commit — part of same transaction)
|
||||
cust = await db.execute(select(Customer.name).where(Customer.id == visit.customer_id))
|
||||
await log_audit(db, "visit", visit.id, f"{cust.scalar_one_or_none() or ''} ({data.visit_date})", "create", current_user["user_id"], current_user["name"])
|
||||
@@ -251,6 +281,8 @@ async def update_visit(
|
||||
}
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
if current_user["role"] not in ("director", "leader"):
|
||||
update_data.pop("manager_id", None)
|
||||
if "visit_date" in update_data and update_data["visit_date"]:
|
||||
update_data["visit_date"] = parse_date(update_data["visit_date"])
|
||||
if "manager_id" in update_data and update_data["manager_id"]:
|
||||
@@ -289,6 +321,15 @@ async def update_visit(
|
||||
await log_audit(db, "visit", visit.id, f"{cust.scalar_one_or_none() or ''} ({visit.visit_date})", "update", current_user["user_id"], current_user["name"], ", ".join(changes.keys()) if changes else "")
|
||||
await db.commit()
|
||||
await db.refresh(visit)
|
||||
|
||||
# Auto-complete matching work plans after visit update
|
||||
from app.services.visits import auto_complete_work_plans
|
||||
await auto_complete_work_plans(
|
||||
db, visit.customer_id, visit.visit_date,
|
||||
current_user["name"], "拜访更新自动完成",
|
||||
)
|
||||
await db.commit()
|
||||
|
||||
return await _enrich_visit(visit, db)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user