feat:新增投顾工作台相关接口

This commit is contained in:
2026-09-12 20:42:33 +08:00
parent b95fb5d4f7
commit 639a10e10a
50 changed files with 3434 additions and 14 deletions
+37
View File
@@ -0,0 +1,37 @@
"""advisor_report 建议报告表 ORM(工作台本地镜像:sent 状态 + 编辑/发送留痕)。
send_status 流转:draft(草稿快照,随 save 镜像)→ sent(投顾手动发送)/ discarded(废弃归档)。
sent 是工作台本地状态,不回写投顾Agent。
"""
from __future__ import annotations
from datetime import datetime
from typing import Any
from sqlalchemy import BigInteger, DateTime, JSON, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class AdvisorReport(Base):
__tablename__ = "advisor_report"
__table_args__ = {"comment": "建议报告表(工作台本地镜像,承载 sent 状态与发送/编辑留痕)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
report_id: Mapped[str] = mapped_column(String(64), unique=True)
draft_id: Mapped[str] = mapped_column(String(64))
customer_id: Mapped[int] = mapped_column(BigInteger)
advisor_id: Mapped[int] = mapped_column(BigInteger)
intent: Mapped[str] = mapped_column(String(32))
title: Mapped[str | None] = mapped_column(String(128))
content: Mapped[str | None] = mapped_column(Text)
edit_history: Mapped[list[Any] | None] = mapped_column(JSON)
send_status: Mapped[str] = mapped_column(String(16), server_default="draft")
send_time: Mapped[datetime | None] = mapped_column(DateTime)
send_by: Mapped[int | None] = mapped_column(BigInteger)
msg_id: Mapped[int | None] = mapped_column(BigInteger)
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
update_time: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now(), onupdate=func.now()
)
+30
View File
@@ -0,0 +1,30 @@
"""advisor_todo 投顾待办表 ORM(事件/定时/计算三类来源统一承载)。
幂等唯一键 uk_todo(todo_type, customer_id, biz_id) 由 DDL 维护;应用层在写入前
以相同三元组查询去重,避免重复建待办。
"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, String, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class AdvisorTodo(Base):
__tablename__ = "advisor_todo"
__table_args__ = {"comment": "投顾待办表(事件/定时/计算三类来源统一承载)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
todo_type: Mapped[str] = mapped_column(String(32))
customer_id: Mapped[int | None] = mapped_column(BigInteger)
advisor_id: Mapped[int] = mapped_column(BigInteger)
source: Mapped[str] = mapped_column(String(32))
biz_id: Mapped[str | None] = mapped_column(String(64))
priority: Mapped[str] = mapped_column(String(8), server_default="普通")
status: Mapped[str] = mapped_column(String(16), server_default="待处理")
due_at: Mapped[datetime | None] = mapped_column(DateTime)
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
handle_time: Mapped[datetime | None] = mapped_column(DateTime)
+23
View File
@@ -0,0 +1,23 @@
"""advisor_visit_record 投顾回访记录表 ORM(人工留痕,不触发 Agent 记忆抽取)。"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class AdvisorVisitRecord(Base):
__tablename__ = "advisor_visit_record"
__table_args__ = {"comment": "投顾回访记录表(人工留痕归档,不触发Agent记忆抽取)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
customer_id: Mapped[int] = mapped_column(BigInteger)
advisor_id: Mapped[int] = mapped_column(BigInteger)
visit_type: Mapped[str] = mapped_column(String(32))
visit_time: Mapped[datetime] = mapped_column(DateTime)
summary: Mapped[str | None] = mapped_column(Text)
audio_url: Mapped[str | None] = mapped_column(String(512))
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
+26
View File
@@ -0,0 +1,26 @@
"""audit_log 操作审计日志表 ORM(企业级合规留痕,工作台台账只读)。"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class AuditLog(Base):
__tablename__ = "audit_log"
__table_args__ = {"comment": "操作审计日志表(企业级合规留痕)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
user_id: Mapped[int | None] = mapped_column(BigInteger)
username: Mapped[str | None] = mapped_column(String(64))
module: Mapped[str] = mapped_column(String(32))
action: Mapped[str] = mapped_column(String(64))
target: Mapped[str | None] = mapped_column(String(128))
detail: Mapped[str | None] = mapped_column(Text)
ip: Mapped[str | None] = mapped_column(String(64))
trace_id: Mapped[str | None] = mapped_column(String(32))
status: Mapped[str] = mapped_column(String(8), server_default="成功")
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
+14 -8
View File
@@ -1,27 +1,33 @@
"""customer_relation 客户-投顾关系表 ORM 模型。"""
"""customer_relation 客户-投顾关系表 ORM 模型。
同时服务于:
- 投顾工作台(advisor):签约状态 unsigned/signed/closed,工作台为唯一写入方;
- 记忆/client_agent 模块:读取客户与投顾的当前或历史关系。
"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, String
from sqlalchemy import BigInteger, DateTime, String, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class CustomerRelation(Base):
"""客户与投顾的当前或历史关系。"""
__tablename__ = "customer_relation"
__table_args__ = {"comment": "客户-投顾关系表"}
__table_args__ = {"comment": "客户-投顾关系表(状态驱动:签约后投顾Agent方案正式触达客户)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
customer_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
advisor_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
assign_time: Mapped[datetime] = mapped_column(DateTime, nullable=False)
assign_time: Mapped[datetime] = mapped_column(
DateTime, nullable=False, server_default=func.now()
)
signed_time: Mapped[datetime | None] = mapped_column(DateTime)
end_time: Mapped[datetime | None] = mapped_column(DateTime)
status: Mapped[str] = mapped_column(String(16), nullable=False)
status: Mapped[str] = mapped_column(
String(16), nullable=False, server_default="unsigned"
)
reason: Mapped[str | None] = mapped_column(String(128))
+24
View File
@@ -0,0 +1,24 @@
"""event_log 事件日志表 ORM(事件双写落库,Pub/Sub 仅作实时通知,消费以 event_id 幂等)。"""
from __future__ import annotations
from datetime import datetime
from typing import Any
from sqlalchemy import BigInteger, DateTime, JSON, String, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class EventLog(Base):
__tablename__ = "event_log"
__table_args__ = {"comment": "事件日志表(事件双写落库,Pub/Sub 仅作实时通知,消费幂等)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
event_id: Mapped[str] = mapped_column(String(64), unique=True)
event_name: Mapped[str] = mapped_column(String(64))
payload: Mapped[dict[str, Any] | None] = mapped_column(JSON)
trace_id: Mapped[str | None] = mapped_column(String(64))
status: Mapped[str] = mapped_column(String(16), server_default="待消费")
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
consume_time: Mapped[datetime | None] = mapped_column(DateTime)
+26
View File
@@ -0,0 +1,26 @@
"""portfolio_benchmark 组合基准配置表 ORM(投顾Agent 再平衡参照,运营可调整;工作台只读展示)。"""
from __future__ import annotations
from datetime import datetime
from decimal import Decimal
from typing import Any
from sqlalchemy import BigInteger, DateTime, JSON, Numeric, String, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class PortfolioBenchmark(Base):
__tablename__ = "portfolio_benchmark"
__table_args__ = {"comment": "组合基准配置表(投顾Agent 再平衡参照,运营可调整)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
risk_level: Mapped[str] = mapped_column(String(16))
target_allocation: Mapped[dict[str, Any] | None] = mapped_column(JSON)
drift_threshold: Mapped[Decimal] = mapped_column(Numeric(5, 2), server_default="5.00")
status: Mapped[str] = mapped_column(String(8), server_default="启用")
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
update_time: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now(), onupdate=func.now()
)
+23
View File
@@ -0,0 +1,23 @@
"""sensitive_word 敏感词库表 ORM(工作台与 Agent 同源,合规拦截唯一来源)。"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, String, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class SensitiveWord(Base):
__tablename__ = "sensitive_word"
__table_args__ = {"comment": "敏感词库表(工作台与Agent同源,合规拦截唯一来源)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
word: Mapped[str] = mapped_column(String(128), unique=True)
category: Mapped[str] = mapped_column(String(32))
level: Mapped[str] = mapped_column(String(8), server_default="高")
status: Mapped[str] = mapped_column(String(8), server_default="启用")
update_time: Mapped[datetime] = mapped_column(
DateTime, server_default=func.now(), onupdate=func.now()
)
+23
View File
@@ -0,0 +1,23 @@
"""sys_message 站内信/消息中心表 ORM(投顾触达客户通道,发送报告时写入)。"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import BigInteger, DateTime, Integer, String, func
from sqlalchemy.orm import Mapped, mapped_column
from model.base import Base
class SysMessage(Base):
__tablename__ = "sys_message"
__table_args__ = {"comment": "站内信/消息中心表(投顾触达客户通道)"}
id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(BigInteger)
msg_type: Mapped[str] = mapped_column(String(32))
title: Mapped[str] = mapped_column(String(128))
content: Mapped[str | None] = mapped_column(String(512))
biz_id: Mapped[str | None] = mapped_column(String(64))
is_read: Mapped[int] = mapped_column(Integer, server_default="0")
create_time: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())