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:
@@ -1,4 +1,9 @@
|
||||
# AI_CHANGELOG
|
||||
# - 2026-03-20 | Prompt: R3 项目类型筛选接口重建 | get_skill_types() 从虚构的 v_cfg_skill_type
|
||||
# 改为查询 app.v_cfg_area_category(真实 RLS 视图),头部插入"不限"选项;
|
||||
# get_all_assistants() 移除 _skill_to_category/_category_to_skill 映射字典,
|
||||
# 改为 _valid_categories set 直接比较;_project_filter_clause() 移除 _project_to_category
|
||||
# 映射字典,直接用 category_code。
|
||||
# - 2026-03-20 | Prompt: RNS1.3 FDW 列名修正 | 修正 17 处列名映射(design.md 理想名 → 实际视图列名),
|
||||
# gift_rows 每个 cell 改为 GiftCell dict 避免 Pydantic 校验失败,
|
||||
# v_dws_member_spending_power_index 降级为空列表,skill_filter 暂不生效
|
||||
@@ -525,15 +530,22 @@ def get_relation_index(
|
||||
return records
|
||||
|
||||
|
||||
# AI_CHANGELOG
|
||||
# - 2026-03-20: R1 修复 — 5 列(table_charge_money, goods_money, assistant_pd_money,
|
||||
# assistant_cx_money, settle_type)从 sl(service_log) 改为 sh(settlement_head),
|
||||
# 添加 LEFT JOIN v_dwd_settlement_head,WHERE settle_type 引用也改为 sh。
|
||||
# 原因:这些字段属于结算单头表,不在助教服务日志视图中。
|
||||
# 验证:MCP 端到端查询通过。
|
||||
def get_consumption_records(
|
||||
conn: Any, site_id: int, member_id: int, limit: int, offset: int
|
||||
) -> list[dict]:
|
||||
"""
|
||||
查询客户消费记录(CUST-1 consumptionRecords 用)。
|
||||
|
||||
来源: app.v_dwd_assistant_service_log + v_dim_assistant。
|
||||
⚠️ DWD-DOC 规则 1: totalAmount 使用 ledger_amount。
|
||||
⚠️ DWD-DOC 规则 2: coaches fee 使用 assistant_pd_money / assistant_cx_money。
|
||||
来源: app.v_dwd_assistant_service_log + v_dwd_settlement_head + v_dim_assistant。
|
||||
⚠️ DWD-DOC 规则 1: totalAmount 使用 ledger_amount(来自 service_log)。
|
||||
⚠️ DWD-DOC 规则 2: coaches fee 使用 assistant_pd_money / assistant_cx_money(来自 settlement_head)。
|
||||
⚠️ 费用拆分字段(table_charge_money, goods_money, settle_type)来自 settlement_head。
|
||||
⚠️ 废单排除: is_delete = 0。
|
||||
⚠️ 正向交易: settle_type IN (1, 3)。
|
||||
⚠️ DQ-6: 助教姓名通过 v_dim_assistant 获取。
|
||||
@@ -553,18 +565,25 @@ def get_consumption_records(
|
||||
sl.site_assistant_id AS assistant_id,
|
||||
COALESCE(da.real_name, da.nickname, '') AS assistant_name,
|
||||
da.level AS assistant_level,
|
||||
sl.table_charge_money,
|
||||
sl.goods_money,
|
||||
sl.assistant_pd_money,
|
||||
sl.assistant_cx_money,
|
||||
sl.settle_type
|
||||
sh.table_charge_money,
|
||||
sh.goods_money,
|
||||
sh.assistant_pd_money,
|
||||
sh.assistant_cx_money,
|
||||
sh.settle_type
|
||||
FROM app.v_dwd_assistant_service_log sl
|
||||
LEFT JOIN app.v_dim_assistant da
|
||||
ON sl.site_assistant_id = da.assistant_id
|
||||
AND da.scd2_is_current = 1
|
||||
LEFT JOIN app.v_dwd_settlement_head sh
|
||||
ON sl.order_settle_id = sh.order_settle_id
|
||||
-- CHANGE 2026-03-20 | R1 修复: 费用拆分字段来自 settlement_head 而非 service_log
|
||||
-- intent: table_charge_money/goods_money/assistant_pd_money/assistant_cx_money/settle_type
|
||||
-- 属于结算单头表(dwd_settlement_head),通过 order_settle_id 关联
|
||||
-- assumption: 每条 service_log 对应一条 settlement_head(1:1 或 1:0)
|
||||
-- verify: SELECT count(*) FROM v_dwd_assistant_service_log WHERE order_settle_id IS NULL
|
||||
WHERE sl.tenant_member_id = %s
|
||||
AND sl.is_delete = 0
|
||||
AND sl.settle_type IN (1, 3)
|
||||
AND sh.settle_type IN (1, 3)
|
||||
ORDER BY sl.create_time DESC
|
||||
LIMIT %s OFFSET %s
|
||||
""",
|
||||
@@ -963,23 +982,17 @@ def get_coach_service_records(
|
||||
|
||||
|
||||
def get_all_assistants(
|
||||
conn: Any, site_id: int, skill_filter: str = "all"
|
||||
conn: Any, site_id: int, skill_filter: str = "ALL"
|
||||
) -> list[dict]:
|
||||
"""
|
||||
查询门店全部助教列表(BOARD-1 用)。
|
||||
|
||||
CHANGE 2026-03-19 | P1 修复:通过 LEFT JOIN v_dws_assistant_project_tag 获取技能标签,
|
||||
支持 skill_filter 筛选(chinese/snooker/mahjong/karaoke/all)。
|
||||
category_code 映射:BILLIARD→chinese, SNOOKER→snooker, MAHJONG→mahjong, KTV→karaoke。
|
||||
CHANGE 2026-03-20 | R3 修复:skill_filter 直接接收 category_code
|
||||
(BILLIARD/SNOOKER/MAHJONG/KTV/ALL),去掉 chinese→BILLIARD 映射层。
|
||||
"""
|
||||
# CHANGE 2026-03-19 | feiqiu-data-rules 规则 6: 等级名称从配置表动态读取
|
||||
_skill_to_category = {
|
||||
"chinese": "BILLIARD",
|
||||
"snooker": "SNOOKER",
|
||||
"mahjong": "MAHJONG",
|
||||
"karaoke": "KTV",
|
||||
}
|
||||
_category_to_skill = {v: k for k, v in _skill_to_category.items()}
|
||||
# CHANGE 2026-03-20 | R3 修复:去掉 _skill_to_category 映射,直接用 category_code
|
||||
_valid_categories = {"BILLIARD", "SNOOKER", "MAHJONG", "KTV"}
|
||||
|
||||
level_map = get_level_map(conn, site_id)
|
||||
records: list[dict] = []
|
||||
@@ -987,7 +1000,7 @@ def get_all_assistants(
|
||||
# 筛选条件:如果指定了技能,只返回被标记的助教
|
||||
filter_clause = ""
|
||||
params: tuple = ()
|
||||
if skill_filter != "all" and skill_filter in _skill_to_category:
|
||||
if skill_filter != "ALL" and skill_filter in _valid_categories:
|
||||
filter_clause = """
|
||||
AND da.assistant_id IN (
|
||||
SELECT apt.assistant_id
|
||||
@@ -995,7 +1008,7 @@ def get_all_assistants(
|
||||
WHERE apt.category_code = %s AND apt.is_tagged = true
|
||||
)
|
||||
"""
|
||||
params = (_skill_to_category[skill_filter],)
|
||||
params = (skill_filter,)
|
||||
|
||||
cur.execute(
|
||||
f"""
|
||||
@@ -1015,11 +1028,11 @@ def get_all_assistants(
|
||||
)
|
||||
for row in cur.fetchall():
|
||||
skill_codes = row[3] if row[3] else []
|
||||
skill_labels = [_category_to_skill.get(c, c) for c in skill_codes if c]
|
||||
# CHANGE 2026-03-20 | R3 修复:直接返回 category_code,不再反向映射为旧值
|
||||
records.append({
|
||||
"assistant_id": row[0],
|
||||
"name": row[1] or "",
|
||||
"skill": ",".join(skill_labels) if skill_labels else "",
|
||||
"skill": ",".join(c for c in skill_codes if c) if skill_codes else "",
|
||||
"level": level_map.get(row[2], "") if row[2] else "",
|
||||
})
|
||||
return records
|
||||
@@ -1190,19 +1203,13 @@ def _project_filter_clause(project: str) -> tuple[str, tuple]:
|
||||
"""
|
||||
生成项目筛选 SQL 片段(用于 BOARD-2 会员维度查询)。
|
||||
|
||||
CHANGE 2026-03-19 | P1 修复:通过 v_dws_member_project_tag 子查询实现项目筛选。
|
||||
project 参数映射:chinese→BILLIARD, snooker→SNOOKER, mahjong→MAHJONG, karaoke→KTV。
|
||||
CHANGE 2026-03-20 | R3 修复:project 参数直接接收 category_code
|
||||
(BILLIARD/SNOOKER/MAHJONG/KTV/ALL),去掉 chinese→BILLIARD 映射层。
|
||||
返回 (sql_fragment, params),sql_fragment 以 AND 开头,可直接拼入 WHERE 子句。
|
||||
"""
|
||||
_project_to_category = {
|
||||
"chinese": "BILLIARD",
|
||||
"snooker": "SNOOKER",
|
||||
"mahjong": "MAHJONG",
|
||||
"karaoke": "KTV",
|
||||
}
|
||||
if project == "all" or project not in _project_to_category:
|
||||
_valid_categories = {"BILLIARD", "SNOOKER", "MAHJONG", "KTV"}
|
||||
if project == "ALL" or project not in _valid_categories:
|
||||
return "", ()
|
||||
category_code = _project_to_category[project]
|
||||
clause = """
|
||||
AND vd.member_id IN (
|
||||
SELECT mpt.member_id
|
||||
@@ -1210,7 +1217,7 @@ def _project_filter_clause(project: str) -> tuple[str, tuple]:
|
||||
WHERE mpt.category_code = %s AND mpt.is_tagged = true
|
||||
)
|
||||
"""
|
||||
return clause, (category_code,)
|
||||
return clause, (project,)
|
||||
|
||||
|
||||
def get_customer_board_recall(
|
||||
@@ -2314,25 +2321,31 @@ def get_finance_coach_analysis(
|
||||
|
||||
def get_skill_types(conn: Any, site_id: int) -> list[dict]:
|
||||
"""
|
||||
CONFIG-1: 查询技能类型配置。
|
||||
CONFIG-1: 查询项目类型筛选器配置。
|
||||
|
||||
来源: ETL cfg 表(app.v_cfg_skill_type 或类似配置视图)。
|
||||
来源: app.v_cfg_area_category(基于 dws.cfg_area_category 去重,
|
||||
排除 SPECIAL/OTHER)。返回列表头部插入"不限"选项。
|
||||
查询失败时由调用方降级返回空数组。
|
||||
"""
|
||||
# CHANGE 2026-03-20 | R3 修复:原查询虚构的 v_cfg_skill_type 视图不存在,
|
||||
# 改为查询 v_cfg_area_category(项目类型配置),value 直接用 category_code
|
||||
# (BILLIARD/SNOOKER/MAHJONG/KTV),前端枚举同步修改。
|
||||
# 假设:cfg_area_category 的 category_code 是稳定的业务标识,不会频繁变动。
|
||||
with _fdw_context(conn, site_id) as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT skill_key, skill_label, emoji, css_cls
|
||||
FROM app.v_cfg_skill_type
|
||||
SELECT category_code, display_name, short_name
|
||||
FROM app.v_cfg_area_category
|
||||
ORDER BY sort_order
|
||||
"""
|
||||
)
|
||||
items = []
|
||||
# 头部插入"不限"选项(后端生成,不存数据库)
|
||||
items: list[dict] = [{"key": "ALL", "label": "不限", "emoji": "", "cls": ""}]
|
||||
for row in cur.fetchall():
|
||||
items.append({
|
||||
"key": row[0] or "",
|
||||
"label": row[1] or "",
|
||||
"emoji": row[2] or "",
|
||||
"cls": row[3] or "",
|
||||
"cls": "",
|
||||
})
|
||||
return items
|
||||
|
||||
Reference in New Issue
Block a user