feat: 支局长/分管领导可为任意客户经理代填记录
后端: - 5个模块的 Create/Update schema 新增可选 manager_id 字段 - POST 端点: director/leader 可指定 manager_id,manager 角色自动用自身 - PUT 端点: director/leader 可修改 manager_id,manager 角色禁止修改 前端(移动端+桌面端共10个页面): - 支局长/领导可见「客户经理」下拉选择框 - 创建和编辑时均可指定记录归属的客户经理 - 涵盖今日拜访、今日纪要、工作计划、商机跟单、要客拜访五个模块 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,7 @@ async def create_note(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
note = DailyNote(
|
||||
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"]),
|
||||
note_date=parse_date(data.note_date),
|
||||
category=data.category,
|
||||
content=data.content,
|
||||
@@ -108,6 +108,8 @@ async def update_note(
|
||||
|
||||
old_snapshot = {"note_date": str(note.note_date), "category": note.category, "content": note.content, "time_range": note.time_range}
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
if current_user["role"] not in ("director", "leader"):
|
||||
update_data.pop("manager_id", None)
|
||||
if "note_date" in update_data and update_data["note_date"]:
|
||||
update_data["note_date"] = parse_date(update_data["note_date"])
|
||||
for k, v in update_data.items():
|
||||
|
||||
@@ -63,7 +63,7 @@ async def create_key_visit(
|
||||
planned_date=data.planned_date,
|
||||
planned_visitor=data.planned_visitor,
|
||||
visit_target=data.visit_target,
|
||||
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"]),
|
||||
)
|
||||
init_entry(k, current_user["name"])
|
||||
db.add(k)
|
||||
@@ -87,6 +87,8 @@ async def update_key_visit(
|
||||
|
||||
old_snapshot = {"customer_id": str(k.customer_id), "urgency_level": k.urgency_level, "description": k.description, "progress_status": k.progress_status, "planned_date": k.planned_date, "planned_visitor": k.planned_visitor, "visit_target": k.visit_target}
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
if current_user["role"] not in ("director", "leader"):
|
||||
update_data.pop("manager_id", None)
|
||||
for key, v in update_data.items():
|
||||
setattr(k, key, v)
|
||||
new_snapshot = {"customer_id": str(k.customer_id), "urgency_level": k.urgency_level, "description": k.description, "progress_status": k.progress_status, "planned_date": k.planned_date, "planned_visitor": k.planned_visitor, "visit_target": k.visit_target}
|
||||
|
||||
@@ -60,7 +60,7 @@ async def create_mini_business(
|
||||
amount=data.amount,
|
||||
follow_up_detail=data.follow_up_detail,
|
||||
status=data.status,
|
||||
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"]),
|
||||
expected_revenue_date=data.expected_revenue_date,
|
||||
)
|
||||
init_entry(m, current_user["name"])
|
||||
@@ -85,6 +85,8 @@ async def update_mini_business(
|
||||
|
||||
old_snapshot = {"customer_id": str(m.customer_id), "product_type": m.product_type, "amount": m.amount, "follow_up_detail": m.follow_up_detail, "status": m.status, "expected_revenue_date": m.expected_revenue_date}
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
if current_user["role"] not in ("director", "leader"):
|
||||
update_data.pop("manager_id", None)
|
||||
for k, v in update_data.items():
|
||||
setattr(m, k, v)
|
||||
new_snapshot = {"customer_id": str(m.customer_id), "product_type": m.product_type, "amount": m.amount, "follow_up_detail": m.follow_up_detail, "status": m.status, "expected_revenue_date": m.expected_revenue_date}
|
||||
|
||||
@@ -147,7 +147,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"]),
|
||||
)
|
||||
init_entry(visit, current_user["name"])
|
||||
db.add(visit)
|
||||
@@ -212,6 +212,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"])
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ async def create_work_plan(
|
||||
customer_id=data.customer_id,
|
||||
plan_content=data.plan_content,
|
||||
plan_date=parse_date(data.plan_date),
|
||||
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"]),
|
||||
status=data.status,
|
||||
)
|
||||
init_entry(wp, current_user["name"])
|
||||
@@ -83,6 +83,8 @@ async def update_work_plan(
|
||||
|
||||
old_snapshot = {"customer_id": str(wp.customer_id), "plan_content": wp.plan_content, "plan_date": str(wp.plan_date), "status": wp.status}
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
if current_user["role"] not in ("director", "leader"):
|
||||
update_data.pop("manager_id", None)
|
||||
if "plan_date" in update_data and update_data["plan_date"]:
|
||||
update_data["plan_date"] = parse_date(update_data["plan_date"])
|
||||
for k, v in update_data.items():
|
||||
|
||||
@@ -9,6 +9,7 @@ class DailyNoteCreate(BaseModel):
|
||||
category: str = "其他"
|
||||
content: str = ""
|
||||
time_range: str = ""
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class DailyNoteUpdate(BaseModel):
|
||||
@@ -16,6 +17,7 @@ class DailyNoteUpdate(BaseModel):
|
||||
category: Optional[str] = None
|
||||
content: Optional[str] = None
|
||||
time_range: Optional[str] = None
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class DailyNoteOut(BaseModel):
|
||||
|
||||
@@ -11,6 +11,7 @@ class KeyVisitCreate(BaseModel):
|
||||
planned_date: str = ""
|
||||
planned_visitor: str = ""
|
||||
visit_target: str = ""
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class KeyVisitUpdate(BaseModel):
|
||||
@@ -21,6 +22,7 @@ class KeyVisitUpdate(BaseModel):
|
||||
planned_date: Optional[str] = None
|
||||
planned_visitor: Optional[str] = None
|
||||
visit_target: Optional[str] = None
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class KeyVisitOut(BaseModel):
|
||||
|
||||
@@ -10,6 +10,7 @@ class MiniBusinessCreate(BaseModel):
|
||||
follow_up_detail: str = ""
|
||||
status: str = "跟进中"
|
||||
expected_revenue_date: str = ""
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class MiniBusinessUpdate(BaseModel):
|
||||
@@ -19,6 +20,7 @@ class MiniBusinessUpdate(BaseModel):
|
||||
follow_up_detail: Optional[str] = None
|
||||
status: Optional[str] = None
|
||||
expected_revenue_date: Optional[str] = None
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class MiniBusinessOut(BaseModel):
|
||||
|
||||
@@ -16,6 +16,7 @@ class VisitCreate(BaseModel):
|
||||
companions: list[uuid.UUID] = []
|
||||
companion_names: list[str] = []
|
||||
photos: list[str] = []
|
||||
manager_id: Optional[uuid.UUID] = None # director/leader can specify
|
||||
|
||||
|
||||
class VisitUpdate(BaseModel):
|
||||
@@ -28,6 +29,7 @@ class VisitUpdate(BaseModel):
|
||||
communication_content: Optional[str] = None
|
||||
customer_demand: Optional[str] = None
|
||||
companions: Optional[list[uuid.UUID]] = None
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
companion_names: Optional[list[str]] = None
|
||||
photos: Optional[list[str]] = None
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ class WorkPlanCreate(BaseModel):
|
||||
plan_content: str = ""
|
||||
plan_date: str # "YYYY-MM-DD"
|
||||
status: str = "计划中"
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class WorkPlanUpdate(BaseModel):
|
||||
@@ -16,6 +17,7 @@ class WorkPlanUpdate(BaseModel):
|
||||
plan_content: Optional[str] = None
|
||||
plan_date: Optional[str] = None
|
||||
status: Optional[str] = None
|
||||
manager_id: Optional[uuid.UUID] = None
|
||||
|
||||
|
||||
class WorkPlanOut(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user