feat: chat integration, tenant admin spec, backend chat service, miniprogram updates, DEMO moved to tmp, XCX-TEST removed, migrations & docs

This commit is contained in:
Neo
2026-03-20 09:02:10 +08:00
parent 3d2e5f8165
commit beb88d5bea
388 changed files with 6436 additions and 25458 deletions

View File

@@ -1,8 +1,13 @@
# AI_CHANGELOG
# - 2026-03-20 | Prompt: H2 FDW→直连ETL统一改造 | get_task_list() 中 2 处、get_task_list_v2() 中 1 处、
# get_task_detail() 中 1 处 fdw_etl.v_dim_member / v_dws_member_assistant_relation_index
# 改为直连 ETL 库查询 app.v_* RLS 视图。使用 fdw_queries._fdw_context()。
"""
任务管理服务
负责任务 CRUD、置顶、放弃、取消放弃等操作。
通过 FDW 读取客户信息和 RS 指数,计算爱心 icon 档位。
直连 ETL 库查询 app.v_* RLS 视图获取客户信息和 RS 指数,计算爱心 icon 档位。
RNS1.1 扩展get_task_list_v2TASK-1、get_task_detailTASK-2
"""
@@ -169,17 +174,18 @@ async def get_task_list(user_id: int, site_id: int) -> list[dict]:
member_info_map: dict[int, dict] = {}
rs_map: dict[int, Decimal] = {}
with conn.cursor() as cur:
cur.execute("BEGIN")
cur.execute(
"SET LOCAL app.current_site_id = %s", (str(site_id),)
)
# CHANGE 2026-03-20 | H2 FDW→直连ETL | fdw_etl.v_dim_member + v_dws_member_assistant_relation_index
# → 直连 ETL 库查 app.v_* RLS 视图
# intent: 修复 RLS 门店隔离失效postgres_fdw 不传递 GUC 参数)
from app.services.fdw_queries import _fdw_context
with _fdw_context(conn, site_id) as cur:
# 读取客户基本信息
# 列名映射: FDW 外部表 member_name/member_phone → RLS 视图 nickname/mobile
cur.execute(
"""
SELECT member_id, member_name, member_phone
FROM fdw_etl.v_dim_member
SELECT member_id, nickname, mobile
FROM app.v_dim_member
WHERE member_id = ANY(%s)
""",
(member_ids,),
@@ -194,7 +200,7 @@ async def get_task_list(user_id: int, site_id: int) -> list[dict]:
cur.execute(
"""
SELECT member_id, COALESCE(rs_display, 0)
FROM fdw_etl.v_dws_member_assistant_relation_index
FROM app.v_dws_member_assistant_relation_index
WHERE assistant_id = %s
AND member_id = ANY(%s)
""",
@@ -203,8 +209,6 @@ async def get_task_list(user_id: int, site_id: int) -> list[dict]:
for row in cur.fetchall():
rs_map[row[0]] = Decimal(str(row[1]))
conn.commit()
# 组装结果
result = []
for task_row in tasks:
@@ -598,26 +602,24 @@ async def get_task_list_v2(
logger.warning("FDW 查询 lastVisitDays 失败", exc_info=True)
# ── 5. RS 指数(用于 heart_score ──
# CHANGE 2026-03-20 | H2 FDW→直连ETL | fdw_etl → app直连 ETL 库)
rs_map: dict[int, Decimal] = {}
try:
with conn.cursor() as cur:
cur.execute("BEGIN")
cur.execute(
"SET LOCAL app.current_site_id = %s", (str(site_id),)
)
from app.services.fdw_queries import _fdw_context
with _fdw_context(conn, site_id) as cur:
cur.execute(
"""
SELECT member_id, COALESCE(rs_display, 0)
FROM fdw_etl.v_dws_member_assistant_relation_index
FROM app.v_dws_member_assistant_relation_index
WHERE assistant_id = %s AND member_id = ANY(%s)
""",
(assistant_id, member_ids),
)
for row in cur.fetchall():
rs_map[row[0]] = Decimal(str(row[1]))
conn.commit()
except Exception:
logger.warning("FDW 查询 RS 指数失败", exc_info=True)
logger.warning("ETL 查询 RS 指数失败", exc_info=True)
try:
conn.rollback()
except Exception:
@@ -831,17 +833,16 @@ async def get_task_detail(
customer_name = info.get("nickname") or "未知客户"
# RS 指数
# CHANGE 2026-03-20 | H2 FDW→直连ETL | fdw_etl → app直连 ETL 库)
rs_score = Decimal("0")
try:
with conn.cursor() as cur:
cur.execute("BEGIN")
cur.execute(
"SET LOCAL app.current_site_id = %s", (str(site_id),)
)
from app.services.fdw_queries import _fdw_context
with _fdw_context(conn, site_id) as cur:
cur.execute(
"""
SELECT COALESCE(rs_display, 0)
FROM fdw_etl.v_dws_member_assistant_relation_index
FROM app.v_dws_member_assistant_relation_index
WHERE assistant_id = %s AND member_id = %s
""",
(assistant_id, member_id),
@@ -849,13 +850,8 @@ async def get_task_detail(
rs_row = cur.fetchone()
if rs_row:
rs_score = Decimal(str(rs_row[0]))
conn.commit()
except Exception:
logger.warning("FDW 查询 RS 指数失败", exc_info=True)
try:
conn.rollback()
except Exception:
pass
logger.warning("ETL 查询 RS 指数失败", exc_info=True)
# ── 3. 查询维客线索 ──
retention_clues = []