# AI_CHANGELOG # - 2026-03-20 | Prompt: R3 项目类型筛选接口重建 | SkillFilterEnum 和 ProjectFilterEnum # 枚举值从 all/chinese/snooker/mahjong/karaoke 改为 ALL/BILLIARD/SNOOKER/MAHJONG/KTV, # 与 dws.cfg_area_category.category_code 一致,消除前后端映射层。 """三看板接口 Pydantic Schema(BOARD-1/2/3 请求参数枚举 + 响应模型)。""" from __future__ import annotations from enum import Enum from app.schemas.base import CamelModel # --------------------------------------------------------------------------- # 请求参数枚举(Task 2.1) # --------------------------------------------------------------------------- class CoachSortEnum(str, Enum): """BOARD-1 排序维度。""" perf_desc = "perf_desc" perf_asc = "perf_asc" salary_desc = "salary_desc" salary_asc = "salary_asc" sv_desc = "sv_desc" task_desc = "task_desc" class SkillFilterEnum(str, Enum): """BOARD-1 技能筛选(值与 dws.cfg_area_category.category_code 一致)。""" # CHANGE 2026-03-20 | R3 修复:枚举值从 chinese/snooker 等前端自定义值 # 改为数据库 category_code(BILLIARD/SNOOKER/MAHJONG/KTV),消除映射层。 ALL = "ALL" BILLIARD = "BILLIARD" SNOOKER = "SNOOKER" MAHJONG = "MAHJONG" KTV = "KTV" class BoardTimeEnum(str, Enum): """BOARD-1 时间范围。""" month = "month" quarter = "quarter" last_month = "last_month" last_3m = "last_3m" last_quarter = "last_quarter" last_6m = "last_6m" class CustomerDimensionEnum(str, Enum): """BOARD-2 客户维度。""" recall = "recall" potential = "potential" balance = "balance" recharge = "recharge" recent = "recent" spend60 = "spend60" freq60 = "freq60" loyal = "loyal" class ProjectFilterEnum(str, Enum): """BOARD-2 项目筛选(值与 dws.cfg_area_category.category_code 一致)。""" # CHANGE 2026-03-20 | R3 修复:枚举值从 chinese/snooker 等前端自定义值 # 改为数据库 category_code(BILLIARD/SNOOKER/MAHJONG/KTV),消除映射层。 ALL = "ALL" BILLIARD = "BILLIARD" SNOOKER = "SNOOKER" MAHJONG = "MAHJONG" KTV = "KTV" class FinanceTimeEnum(str, Enum): """BOARD-3 时间范围。""" month = "month" lastMonth = "lastMonth" week = "week" lastWeek = "lastWeek" quarter3 = "quarter3" quarter = "quarter" lastQuarter = "lastQuarter" half6 = "half6" class AreaFilterEnum(str, Enum): """BOARD-3 区域筛选。""" all = "all" hall = "hall" hallA = "hallA" hallB = "hallB" hallC = "hallC" mahjong = "mahjong" teamBuilding = "teamBuilding" # --------------------------------------------------------------------------- # BOARD-1 响应 Schema(Task 2.2) # --------------------------------------------------------------------------- class CoachSkillItem(CamelModel): text: str cls: str class CoachBoardItem(CamelModel): """助教看板单条记录(扁平结构,包含所有维度字段)。""" # 基础字段(所有维度共享) id: int name: str initial: str avatar_gradient: str level: str # star/senior/middle/junior skills: list[CoachSkillItem] top_customers: list[str] # ["💖 王先生", "💛 李女士"] # perf 维度 perf_hours: float = 0.0 perf_hours_before: float | None = None perf_gap: str | None = None # "距升档 13.8h" 或 None perf_reached: bool = False # salary 维度 salary: float = 0.0 salary_perf_hours: float = 0.0 salary_perf_before: float | None = None # sv 维度 sv_amount: float = 0.0 sv_customer_count: int = 0 sv_consume: float = 0.0 # task 维度 task_recall: int = 0 task_callback: int = 0 class CoachBoardResponse(CamelModel): items: list[CoachBoardItem] dim_type: str # perf/salary/sv/task # --------------------------------------------------------------------------- # BOARD-2 响应 Schema(Task 2.3) # --------------------------------------------------------------------------- class CustomerAssistant(CamelModel): name: str cls: str heart_score: float badge: str | None = None badge_cls: str | None = None class CustomerBoardItemBase(CamelModel): """客户看板基础字段(所有维度共享)。""" id: int name: str initial: str avatar_cls: str assistants: list[CustomerAssistant] class RecallItem(CustomerBoardItemBase): ideal_days: int elapsed_days: int overdue_days: int visits_30d: int balance: str recall_index: float class PotentialTag(CamelModel): text: str theme: str class PotentialItem(CustomerBoardItemBase): potential_tags: list[PotentialTag] spend_30d: float avg_visits: float avg_spend: float class BalanceItem(CustomerBoardItemBase): balance: str last_visit: str # "3天前" monthly_consume: float available_months: str # "约0.8个月" class RechargeItem(CustomerBoardItemBase): last_recharge: str recharge_amount: float recharges_60d: int current_balance: str class RecentItem(CustomerBoardItemBase): days_ago: int visit_freq: str # "6.2次/月" ideal_days: int visits_30d: int avg_spend: float class Spend60Item(CustomerBoardItemBase): spend_60d: float visits_60d: int high_spend_tag: bool avg_spend: float class WeeklyVisit(CamelModel): val: int pct: int # 0-100 class Freq60Item(CustomerBoardItemBase): visits_60d: int avg_interval: str # "5.0天" weekly_visits: list[WeeklyVisit] # 固定长度 8 spend_60d: float class CoachDetail(CamelModel): name: str cls: str heart_score: float badge: str | None = None avg_duration: str service_count: int coach_spend: float relation_idx: float class LoyalItem(CustomerBoardItemBase): intimacy: float top_coach_name: str top_coach_heart: float top_coach_score: float coach_name: str coach_ratio: str # "78%" coach_details: list[CoachDetail] class CustomerBoardResponse(CamelModel): items: list[dict] # 实际类型取决于 dimension total: int page: int page_size: int # --------------------------------------------------------------------------- # BOARD-3 响应 Schema(Task 2.4) # --------------------------------------------------------------------------- class OverviewPanel(CamelModel): """经营一览:8 项核心指标 + 各 3 个环比字段(Optional,compare=0 时为 None)。""" occurrence: float discount: float # 负值 discount_rate: float confirmed_revenue: float cash_in: float cash_out: float cash_balance: float balance_rate: float # occurrence 环比 occurrence_compare: str | None = None occurrence_down: bool | None = None occurrence_flat: bool | None = None # discount 环比 discount_compare: str | None = None discount_down: bool | None = None discount_flat: bool | None = None # discount_rate 环比 discount_rate_compare: str | None = None discount_rate_down: bool | None = None discount_rate_flat: bool | None = None # confirmed_revenue 环比 confirmed_revenue_compare: str | None = None confirmed_revenue_down: bool | None = None confirmed_revenue_flat: bool | None = None # cash_in 环比 cash_in_compare: str | None = None cash_in_down: bool | None = None cash_in_flat: bool | None = None # cash_out 环比 cash_out_compare: str | None = None cash_out_down: bool | None = None cash_out_flat: bool | None = None # cash_balance 环比 cash_balance_compare: str | None = None cash_balance_down: bool | None = None cash_balance_flat: bool | None = None # balance_rate 环比 balance_rate_compare: str | None = None balance_rate_down: bool | None = None balance_rate_flat: bool | None = None class GiftCell(CamelModel): value: float compare: str | None = None down: bool | None = None flat: bool | None = None class GiftRow(CamelModel): """赠送卡矩阵一行:合计 / 酒水卡 / 台费卡 / 抵用券。""" label: str # "新增" / "消费" / "余额" total: GiftCell liquor: GiftCell table_fee: GiftCell voucher: GiftCell class RechargePanel(CamelModel): """预收资产板块:储值卡 5 指标 + 赠送卡 3×4 矩阵 + 全卡余额。""" actual_income: float first_charge: float renew_charge: float consumed: float card_balance: float gift_rows: list[GiftRow] # 3 行 all_card_balance: float # 储值卡各项环比字段 actual_income_compare: str | None = None actual_income_down: bool | None = None actual_income_flat: bool | None = None first_charge_compare: str | None = None first_charge_down: bool | None = None first_charge_flat: bool | None = None renew_charge_compare: str | None = None renew_charge_down: bool | None = None renew_charge_flat: bool | None = None consumed_compare: str | None = None consumed_down: bool | None = None consumed_flat: bool | None = None card_balance_compare: str | None = None card_balance_down: bool | None = None card_balance_flat: bool | None = None class RevenueStructureRow(CamelModel): id: str name: str desc: str | None = None is_sub: bool = False amount: float discount: float booked: float booked_compare: str | None = None class RevenueItem(CamelModel): label: str amount: float class ChannelItem(CamelModel): label: str amount: float class RevenuePanel(CamelModel): structure_rows: list[RevenueStructureRow] price_items: list[RevenueItem] # 4 项 total_occurrence: float discount_items: list[RevenueItem] # 4 项 confirmed_total: float channel_items: list[ChannelItem] # 3 项 class CashflowItem(CamelModel): label: str amount: float class CashflowPanel(CamelModel): consume_items: list[CashflowItem] # 3 项 recharge_items: list[CashflowItem] # 1 项 total: float class ExpenseItem(CamelModel): label: str amount: float compare: str | None = None down: bool | None = None flat: bool | None = None class ExpensePanel(CamelModel): operation_items: list[ExpenseItem] # 3 项 fixed_items: list[ExpenseItem] # 4 项 coach_items: list[ExpenseItem] # 4 项 platform_items: list[ExpenseItem] # 3 项 total: float total_compare: str | None = None total_down: bool | None = None total_flat: bool | None = None class CoachAnalysisRow(CamelModel): level: str pay: float share: float hourly: float pay_compare: str | None = None pay_down: bool | None = None share_compare: str | None = None share_down: bool | None = None hourly_compare: str | None = None hourly_flat: bool | None = None class CoachAnalysisTable(CamelModel): total_pay: float total_share: float avg_hourly: float total_pay_compare: str | None = None total_pay_down: bool | None = None total_share_compare: str | None = None total_share_down: bool | None = None avg_hourly_compare: str | None = None avg_hourly_flat: bool | None = None rows: list[CoachAnalysisRow] # 4 行:初级/中级/高级/星级 class CoachAnalysisPanel(CamelModel): basic: CoachAnalysisTable # 基础课/陪打 incentive: CoachAnalysisTable # 激励课/超休 class FinanceBoardResponse(CamelModel): overview: OverviewPanel recharge: RechargePanel | None # area≠all 时为 null revenue: RevenuePanel cashflow: CashflowPanel expense: ExpensePanel coach_analysis: CoachAnalysisPanel