Files
Neo-ZQYY/docs/miniprogram-dev/API-contract.md

83 KiB
Raw Blame History

小程序接口契约文档

创建时间2026-03-18 状态:联调前草案,后端开发时以此为契约基准 基础路径:/api/xcx


〇、约定

  • 所有接口需认证(Authorization: Bearer <token>),除 login/dev-login 外
  • 响应统一 JSON成功 { code: 0, data: ... },失败 { code: number, message: string }
  • 分页统一 { items: T[], total: number, page: number, pageSize: number }
  • 金额单位number保留 2 位小数)
  • 时间格式ISO 86012026-03-18T10:30:00
  • 排序参数:sort=field:asc|desc

一、认证模块(已实现

AUTH-1: 微信登录

POST /api/xcx/login
Body: { code: string }
Response: { access_token, refresh_token, user: { user_id, status, nickname } }

AUTH-2: 开发模式登录

POST /api/xcx/dev-login
Body: { openid: string }
Response: 同 AUTH-1
⚠️ 生产环境必须禁用此接口REQ-3

AUTH-3: 查询当前用户

GET /api/xcx/me
Response: {
  user_id: number,
  status: 'new' | 'pending' | 'approved' | 'rejected' | 'disabled',
  nickname: string,
  role: string,           // 新增REQ-4
  store_name: string,     // 新增REQ-4
  coach_level?: string,   // 新增REQ-4仅助教角色
  avatar?: string         // 新增REQ-4
}

AUTH-4: 刷新 Token

POST /api/xcx/refresh
Body: { refresh_token: string }
Response: { access_token, refresh_token }

AUTH-5: 提交入驻申请

POST /api/xcx/apply
Body: { name: string, phone: string, store_id: string }
Response: { user_id: number, status: 'pending' }

二、任务模块

TASK-1: 任务列表

数据源:zqyy_app.coach_tasks(任务)、etl_feiqiu.dws.*绩效聚合via FDW 金额口径:收入金额使用 items_sumDWD-DOC 强制规则 1

GET /api/xcx/tasks?status={pending|completed|abandoned}&page=1&pageSize=20

响应结构

interface TaskListResponse {
  items: TaskItem[]
  total: number
  page: number
  pageSize: number

  // 绩效概览(附带在任务列表响应中,避免额外请求)
  performance: PerformanceSummary
}

子类型定义

/** 任务项 */
interface TaskItem {
  id: string
  customerName: string
  customerAvatar: string
  taskType: 'callback' | 'priority_recall' | 'relationship' | 'high_priority'
  taskTypeLabel: string
  deadline: string                 // ISO 8601
  heartScore: number               // 0-10
  hobbies: string[]
  isPinned: boolean
  hasNote: boolean
  status: 'pending' | 'completed' | 'abandoned'

  // ── 可选扩展字段(需求 5.7.2 ──
  lastVisitDays?: number           // 距上次到店天数
  balance?: number                 // 客户余额(元)
  aiSuggestion?: string            // AI 建议摘要
}

/** 绩效概览(扩展版,需求 5.7.1
 *  从原 4 字段扩展为 15+ 字段,供任务列表页 Banner 进度条组件使用 */
interface PerformanceSummary {
  // ── 原有字段 ──
  totalHours: number               // 本月总工时(折算后)
  totalIncome: number              // 本月总收入
  totalCustomers: number           // 本月服务客户数
  monthLabel: string               // 月份标签,如 '3月'

  // ── 扩展字段 ──
  tierNodes: number[]              // 档位节点数组,如 [0, 100, 130, 160, 190, 220]
  basicHours: number               // 基础课时
  bonusHours: number               // 激励课时
  currentTier: number              // 当前档位索引0-based对应 tierNodes
  nextTierHours: number            // 下一档位工时阈值
  tierCompleted: boolean           // 是否已达最高档
  bonusMoney: number               // 升档奖金(元)
  incomeTrend: string              // 收入趋势描述,如 '↓368'
  incomeTrendDir: 'up' | 'down'    // 趋势方向
  prevMonth: string                // 上月标签,如 '1月'
  currentTierLabel: string         // 当前档位名称,如 '初级'
}

字段说明

字段 类型 说明
performance.tierNodes number[] 档位节点数组,前端用于绘制进度条刻度
performance.basicHours number 基础课工时
performance.bonusHours number 激励课工时
performance.currentTier number 当前所在档位索引0=未入档1=初级...
performance.nextTierHours number 下一档位的工时阈值
performance.tierCompleted boolean 是否已达最高档位
performance.bonusMoney number 达到下一档位可获得的奖金
performance.incomeTrend string 与上月对比的收入变化,含方向符号
performance.incomeTrendDir string 'up''down',前端用于控制颜色
performance.prevMonth string 上月标签,用于对比展示
items[].lastVisitDays number? 距上次到店天数,可选
items[].balance number? 客户余额,可选
items[].aiSuggestion string? AI 建议摘要,可选

TASK-2: 任务详情

GET /api/xcx/tasks/{taskId}
Response: {
  // 基础信息(同 TASK-1 item
  id, customer_name, customer_avatar, task_type, task_type_label,
  deadline, heart_score, hobbies, is_pinned, has_note, status,
  // 扩展信息
  last_visit_date?: string,
  last_spend_amount?: number,
  days_absent?: number,
  spend_trend?: 'up' | 'down' | 'flat',
  churn_risk?: 'high' | 'medium' | 'low',
  callback_reason?: string,
  preferences?: string[],
  consumption_habits?: string,
  social_preference?: string,
  // 维客线索
  retention_clues: Array<{
    tag: string,
    tag_color: 'primary' | 'success' | 'purple' | 'error',
    emoji: string,
    text: string,
    source: string,
    desc?: string
  }>,
  // 话术参考
  talking_points: string[],
  // 近期服务记录摘要
  service_summary: { total_hours: number, total_income: number, avg_income: number },
  service_records: Array<{
    table: string,
    type: string,
    type_class: 'basic' | 'vip' | 'tip' | 'recharge' | 'incentive',
    record_type?: 'course' | 'recharge',
    duration: number,
    duration_raw?: number,
    income: number,
    is_estimate?: boolean,
    drinks: string,
    date: string
  }>,
  // AI 分析
  ai_analysis: { summary: string, suggestions: string[] },
  // 备注(最近 N 条)
  notes: Array<{
    id: string,
    content: string,
    tag_type: 'customer' | 'coach' | 'system',
    tag_label: string,
    created_at: string,
    ai_score?: number,
    manual_score?: number
  }>
}

TASK-3: 放弃任务

POST /api/xcx/tasks/{taskId}/abandon
Body: { reason: string }
Response: { status: 'abandoned' }

TASK-4: 取消放弃

POST /api/xcx/tasks/{taskId}/restore
Response: { status: 'pending' }

三、备注模块

NOTE-1: 备注列表

GET /api/xcx/notes?page=1&pageSize=20
Response: {
  items: Array<{
    id: string,
    content: string,
    tag_type: 'customer' | 'coach' | 'system',
    tag_label: string,
    created_at: string,
    ai_score?: number,
    manual_score?: number
  }>,
  total, page, pageSize
}

NOTE-2: 新增备注

POST /api/xcx/notes
Body: { content: string, task_id?: string, customer_id?: string }
Response: { id: string, created_at: string }

NOTE-3: 删除备注

DELETE /api/xcx/notes/{noteId}
Response: { success: true }

四、绩效模块

PERF-1: 绩效概览

数据源:etl_feiqiu.dws.*(绩效/收入聚合via FDWzqyy_app.coaches(助教信息) 金额口径:所有收入金额使用 items_sumDWD-DOC 强制规则 1助教费用使用 assistant_pd_money + assistant_cx_money 拆分DWD-DOC 强制规则 2

GET /api/xcx/performance?year={year}&month={month}

响应结构

interface PerformanceOverviewResponse {
  // ── Banner 数据 ──
  coachName: string                // 助教姓名
  coachRole: string                // 角色,如 '助教'
  storeName: string                // 门店名
  monthlyIncome: string            // 本月收入(格式化),如 '¥6,206'
  lastMonthIncome: string          // 上月收入(格式化),如 '¥16,880'

  // ── 收入档位 ──
  currentTier: {
    basicRate: number              // 当前档基础课时费率(元/h
    incentiveRate: number          // 当前档激励课时费率(元/h
  }
  nextTier: {
    basicRate: number              // 下一档基础课时费率
    incentiveRate: number          // 下一档激励课时费率
  }
  upgradeHoursNeeded: number       // 距升档所需工时
  upgradeBonus: number             // 升档奖金(元)

  // ── 本月业绩明细incomeItems ──
  incomeItems: IncomeItem[]
  monthlyTotal: string             // 本月收入合计(格式化),如 '¥6,950.5'

  // ── 本月服务记录thisMonthRecords ──
  // 按日期分组的 DateGroup 结构
  thisMonthRecords: DateGroup[]

  // ── 新客列表newCustomers ──
  newCustomers: Array<{
    name: string
    avatarChar: string             // 姓氏首字
    avatarColor: string            // 头像渐变色
    lastService: string            // 最后服务日期,如 '2月7日'
    count: number                  // 服务次数
  }>

  // ── 常客列表regularCustomers ──
  regularCustomers: Array<{
    name: string
    avatarChar: string
    avatarColor: string
    hours: number                  // 总工时
    income: string                 // 总收入(格式化),如 '¥960'
    count: number                  // 服务次数
  }>
}

子类型定义

/** 业绩明细项 */
interface IncomeItem {
  icon: string                     // emoji 图标,如 '🎱'、'⭐'、'💰'、'🏆'
  label: string                    // 标签,如 '基础课'、'激励课'、'充值激励'、'TOP3 销冠奖'
  desc: string                     // 费率×工时描述,如 '80元/h × 75h'
  value: string                    // 金额(格式化),如 '¥6,000';或文字如 '继续努力'
}

/** 按日期分组的服务记录 */
interface DateGroup {
  date: string                     // 日期标签,如 '2月7日'
  totalHours: string               // 当日总工时,如 '4.0h'
  totalIncome: string              // 当日总收入,如 '¥350'
  records: Array<{
    customerName: string
    avatarChar: string             // 姓氏首字
    avatarColor: string            // 头像渐变色
    timeRange: string              // 时间段,如 '20:00-22:00'
    hours: string                  // 工时,如 '2.0h'
    courseType: string             // 课程类型,如 '基础课'、'包厢课'
    courseTypeClass: string        // 样式类tag-basic / tag-vip / tag-tip
    location: string               // 台桌/包厢,如 '3号台'、'VIP1号房'
    income: string                 // 收入(格式化),如 '¥160'
  }>
}

字段说明

字段 类型 说明
lastMonthIncome string 上月收入,用于 Banner 对比展示
currentTier / nextTier object 当前/下一档位的基础课和激励课费率
upgradeHoursNeeded number 距升档还需多少工时
upgradeBonus number 升档后可获得的奖金
incomeItems[].desc string 费率×工时的拆分描述,如 "80元/h × 75h"
newCustomers[].lastService string 最后服务日期
newCustomers[].count number 服务次数
regularCustomers[].hours number 总工时
regularCustomers[].income string 总收入(items_sum 口径)

PERF-2: 绩效明细(按月)

GET /api/xcx/performance/records?year={year}&month={month}&page=1&pageSize=20
Response: {
  // 月度汇总
  summary: {
    total_count: number,
    total_hours: number,
    total_hours_raw: number,
    total_income: number
  },
  // 按日期分组
  date_groups: Array<{
    date: string,           // "3月18日"
    total_hours: number,
    total_income: number,
    records: Array<{
      id: string,
      customer_name: string,
      time_range: string,   // "20:00-22:00"
      hours: number,
      hours_raw?: number,
      course_type: string,
      course_type_class: string,
      location: string,
      income: number
    }>
  }>,
  has_more: boolean
}

五、客户模块(已实现

CUST-1: 客户详情

客户详情页完整数据,包含 Banner 概览、AI 洞察、关联助教任务、最亲密助教、消费记录(嵌套结构)和备注列表。 数据源:biz.members(会员基础信息)、fdw_etl.dwd.dim_member(手机号/昵称DQ-6fdw_etl.dwd.dim_member_card_account会员卡DQ-7fdw_etl.dwd.dwd_settlement_head(消费记录)、fdw_etl.dws.*(聚合指标)、biz.ai_cacheAI 洞察)、biz.tasks(助教任务)、biz.customer_notes(备注) DWD-DOC 强制规则:金额字段使用 items_sum 口径(规则 1助教费用使用 assistant_pd_money + assistant_cx_money 拆分(规则 2会员信息通过 member_id JOIN dim_member 获取(规则 DQ-6禁止直接使用 settlement_head.member_phone;会员卡信息通过 member_id JOIN dim_member_card_account 获取(规则 DQ-7

GET /api/xcx/customers/{customerId}

请求参数

参数 类型 必填 说明
customerId string (path) 客户唯一 ID

响应结构TypeScript 类型定义)

/** 顶层响应 */
interface CustomerDetailResponse {
  // ─── 基础信息 ───

  /** 客户唯一 ID */
  id: string
  /** 客户姓名(⚠️ 通过 member_id JOIN dim_member.nickname 获取DQ-6 */
  name: string
  /** 脱敏手机号,如 "139****5678"(⚠️ 通过 member_id JOIN dim_member.mobile 获取DQ-6 */
  phone: string
  /** 完整手机号(点击查看时用)(⚠️ 同上DQ-6 */
  phoneFull: string
  /** 头像 URL */
  avatar: string
  /** 会员等级(⚠️ 通过 member_id JOIN dim_member_card_account 获取DQ-7 */
  memberLevel: string
  /** 关系指数,如 "0.85" */
  relationIndex: string
  /** 客户标签列表 */
  tags: string[]

  // ─── Banner 概览字段 ───

  /** 客户余额(元),⚠️ 使用 `items_sum` 口径 */
  balance: number
  /** 近 60 天消费金额(元),⚠️ 使用 `items_sum` 口径 */
  consumption60d: number
  /** 理想到店间隔(天) */
  idealInterval: number
  /** 距上次到店天数 */
  daysSinceVisit: number

  // ─── AI 洞察模块 ───

  /** AI 分析洞察数据源biz.ai_cachecache_type=app4_analysis */
  aiInsight: AiInsight

  // ─── 关联助教任务列表 ───

  /** 关联助教任务 */
  coachTasks: CoachTask[]

  // ─── 最亲密助教 ───

  /** 最亲密助教列表 */
  favoriteCoaches: FavoriteCoach[]

  // ─── 维客线索 ───

  /** 维客线索列表(同 TASK-2 格式) */
  retentionClues: RetentionClue[]

  // ─── 消费记录(嵌套结构) ───

  /** 消费记录列表,⚠️ 所有金额使用 `items_sum` 口径 */
  consumptionRecords: ConsumptionRecord[]

  // ─── 备注列表 ───

  /** 客户备注 */
  notes: CustomerNote[]
}

// ─── AI 洞察 ───

interface AiInsight {
  /** AI 分析摘要文本 */
  summary: string
  /** 策略建议列表 */
  strategies: Array<{
    /** 标签颜色CSS 类或色值) */
    color: string
    /** 策略建议文本 */
    text: string
  }>
}

// ─── 关联助教任务 ───

interface CoachTask {
  /** 助教姓名 */
  name: string
  /** 助教等级star / senior / middle / junior */
  level: string
  /** 等级对应颜色(前端样式用) */
  levelColor: string
  /** 任务类型,如 "回访"、"召回" */
  taskType: string
  /** 任务类型对应颜色 */
  taskColor: string
  /** 背景样式类 */
  bgClass: string
  /** 任务状态,如 "进行中"、"已完成" */
  status: string
  /** 最后服务日期,如 "2026-03-01" */
  lastService: string
  /**
   * 指标列表(近 60 天统计)
   * 含近60天次数 / 总时长 / 次均时长
   */
  metrics: MetricItem[]
}

// ─── 最亲密助教 ───

interface FavoriteCoach {
  /** 亲密度 emoji如 "💖"、"🧡"、"💛"、"💙" */
  emoji: string
  /** 助教姓名 */
  name: string
  /** 关系指数,如 "0.92" */
  relationIndex: string
  /** 关系指数对应颜色 */
  indexColor: string
  /** 背景样式类 */
  bgClass: string
  /**
   * 统计指标列表
   * 含基础课时assistant_pd_money 对应)/ 激励课时assistant_cx_money 对应)/ 上课次数 / 充值金额
   * ⚠️ 课时费用使用 assistant_pd_money + assistant_cx_money 拆分DWD-DOC 规则 2
   */
  stats: MetricItem[]
}

// ─── 通用指标项 ───

interface MetricItem {
  /** 指标标签,如 "近60天次数"、"基础课时" */
  label: string
  /** 指标值,如 "12次"、"45.5h"、"¥3,200" */
  value: string
  /** 可选颜色标记(高亮/警告等) */
  color?: string
}

// ─── 维客线索(同 TASK-2 格式) ───

interface RetentionClue {
  /** 线索类型 */
  type: string
  /** 线索描述 */
  text: string
}

// ─── 消费记录(嵌套结构) ───

interface ConsumptionRecord {
  /** 记录唯一 ID */
  id: string
  /** 消费类型table台桌消费/ shop酒水/商品消费)/ recharge充值 */
  type: 'table' | 'shop' | 'recharge'
  /** 消费日期,如 "2026-03-01" */
  date: string
  /** 台桌名称type=table 时有值) */
  tableName?: string
  /** 开始时间,如 "14:00"type=table 时有值) */
  startTime?: string
  /** 结束时间,如 "16:30"type=table 时有值) */
  endTime?: string
  /** 时长分钟type=table 时有值) */
  duration?: number
  /**
   * 台费金额(元),⚠️ 使用 `items_sum` 口径中的 `table_charge_money`
   * type=table 时有值
   */
  tableFee?: number
  /** 台费原价优惠前type=table 时有值 */
  tableOrigPrice?: number
  /**
   * 助教服务列表
   * ⚠️ fee 使用 assistant_pd_money基础/陪打)+ assistant_cx_money激励/超休拆分DWD-DOC 规则 2
   */
  coaches: CoachServiceItem[]
  /** 酒水/商品金额(元),⚠️ 使用 `items_sum` 口径中的 `goods_money` */
  foodAmount?: number
  /** 酒水/商品原价(元,优惠前) */
  foodOrigPrice?: number
  /**
   * 消费总金额(元)
   * ⚠️ 使用 `items_sum` 口径 = table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money
   */
  totalAmount: number
  /** 消费总原价(元,优惠前) */
  totalOrigPrice: number
  /** 支付方式,如 "储值卡"、"微信支付"、"现金" */
  payMethod: string
  /** 充值金额type=recharge 时有值 */
  rechargeAmount?: number
}

/** 助教服务明细(嵌套在消费记录中) */
interface CoachServiceItem {
  /** 助教姓名 */
  name: string
  /** 助教等级star / senior / middle / junior */
  level: string
  /** 等级对应颜色 */
  levelColor: string
  /** 课程类型,如 "基础课"、"激励课" */
  courseType: string
  /** 服务时长(小时) */
  hours: number
  /**
   * 折算工时(小时),可选
   * 激励课按系数折算后的工时
   */
  perfHours?: number
  /**
   * 服务费用(元)
   * ⚠️ 基础课 = assistant_pd_money激励课 = assistant_cx_moneyDWD-DOC 规则 2
   */
  fee: number
}

// ─── 客户备注 ───

interface CustomerNote {
  /** 备注唯一 ID */
  id: string
  /** 标签文本,如 "跟进"、"重要" */
  tagLabel: string
  /** 创建时间ISO 8601 格式 */
  createdAt: string
  /** 备注内容 */
  content: string
}

字段说明表

基础信息字段8 个)
字段 类型 说明 数据源
id string 客户唯一 ID biz.members.id
name string 客户姓名 ⚠️ member_id JOIN fdw_etl.dwd.dim_member.nicknamescd2_is_current=1DQ-6
phone string 脱敏手机号,如 "139****5678" ⚠️ member_id JOIN fdw_etl.dwd.dim_member.mobilescd2_is_current=1DQ-6后端脱敏
phoneFull string 完整手机号(点击查看时用) 同上,不脱敏
avatar string 头像 URL biz.members.avatar
memberLevel string 会员等级 ⚠️ member_id JOIN fdw_etl.dwd.dim_member_card_accounttenant_member_id=member_idscd2_is_current=1DQ-7
relationIndex string 关系指数,如 "0.85" 后端根据服务频率/消费金额/亲密度综合计算
tags string[] 客户标签列表 biz.customer_tags
Banner 概览字段4 个)
字段 类型 说明 数据源
balance number 客户余额(元),⚠️ items_sum 口径 fdw_etl.dws.* 聚合,储值卡余额
consumption60d number 近 60 天消费金额(元),⚠️ items_sum 口径 fdw_etl.dwd.dwd_settlement_head,按 settle_time 过滤近 60 天,SUM(items_sum)
idealInterval number 理想到店间隔(天) 后端根据历史到店频率计算
daysSinceVisit number 距上次到店天数 fdw_etl.dwd.dwd_settlement_headMAX(settle_time) 与当前日期差值
aiInsight 模块2 个字段)
字段 类型 说明 数据源
summary string AI 分析摘要文本 biz.ai_cachecache_type='app4_analysis'target_id=customerId
strategies Array<{ color, text }> 策略建议列表,color 为标签颜色,text 为建议文本 同上JSON 解析 cache_value
coachTasks 模块(每项 9 个字段)
字段 类型 说明 数据源
name string 助教姓名 biz.users.nickname
level string 助教等级:star/senior/middle/junior fdw_etl.v_dws_assistant_salary_calc.coach_level
levelColor string 等级对应颜色 后端根据 level 映射
taskType string 任务类型,如 "回访""召回" biz.tasks.task_type
taskColor string 任务类型对应颜色 后端根据 taskType 映射
bgClass string 背景样式类 后端根据 level 映射
status string 任务状态,如 "进行中""已完成" biz.tasks.status
lastService string 最后服务日期 fdw_etl.dwd.dwd_settlement_head,该助教对该客户的 MAX(settle_time)
metrics MetricItem[] 近 60 天指标:次数/总时长/次均时长 fdw_etl.dwd.dwd_settlement_head + dwd_assistant_service_log_ex,按助教+客户聚合近 60 天
favoriteCoaches 模块(每项 6 个字段)
字段 类型 说明 数据源
emoji string 亲密度 emoji💖(>8.5) / 🧡(>7) / 💛(>5) / 💙(≤5),后端 compute_heart_icon() 根据 rs_display 映射) 后端根据 relationIndex 映射
name string 助教姓名 biz.users.nickname
relationIndex string 关系指数,如 "0.92" 后端根据服务频率/消费金额综合计算
indexColor string 关系指数对应颜色 后端根据 relationIndex 阈值映射
bgClass string 背景样式类 后端根据排名映射
stats MetricItem[] 统计指标:基础课时(assistant_pd_money/ 激励课时(assistant_cx_money/ 上课次数 / 充值金额 fdw_etl.dwd.dwd_settlement_head + dwd_assistant_service_log_ex⚠️ 课时费用使用 assistant_pd_money + assistant_cx_money 拆分DWD-DOC 规则 2
consumptionRecords 模块(每项 16 个字段)
字段 类型 说明 数据源
id string 记录唯一 ID fdw_etl.dwd.dwd_settlement_head.id
type enum 消费类型:table/shop/recharge 后端根据 settle_type 映射(IN (1,3) 为正向交易)
date string 消费日期 dwd_settlement_head.settle_time,格式化为日期
tableName string? 台桌名称 dwd_settlement_head.table_name
startTime string? 开始时间 dwd_settlement_head.start_time,格式化为 "HH:mm"
endTime string? 结束时间 dwd_settlement_head.end_time,格式化为 "HH:mm"
duration number? 时长(分钟) 后端根据 startTime/endTime 计算
tableFee number? 台费金额(元),⚠️ table_charge_money dwd_settlement_head.table_charge_money
tableOrigPrice number? 台费原价(元,优惠前) dwd_settlement_head.table_charge_money + 对应折扣
coaches CoachServiceItem[] 助教服务列表 fdw_etl.dwd.dwd_assistant_service_log_ex,关联 settlement_id
foodAmount number? 酒水/商品金额(元),⚠️ goods_money dwd_settlement_head.goods_money
foodOrigPrice number? 酒水/商品原价(元,优惠前) dwd_settlement_head.goods_money + 对应折扣
totalAmount number 消费总金额(元),⚠️ items_sum 口径 dwd_settlement_head.items_sum
totalOrigPrice number 消费总原价(元,优惠前) items_sum + adjust_amount
payMethod string 支付方式 后端根据 pay_type / balance_amount 等字段映射
rechargeAmount number? 充值金额(元),type=recharge 时有值 biz.recharge_records.amount
coaches 子数组CoachServiceItem每项 7 个字段)
字段 类型 说明 数据源
name string 助教姓名 biz.users.nickname
level string 助教等级 fdw_etl.v_dws_assistant_salary_calc.coach_level
levelColor string 等级对应颜色 后端根据 level 映射
courseType string 课程类型:"基础课" / "激励课" 后端根据 dwd_assistant_service_log_ex 服务类型映射
hours number 服务时长(小时) dwd_assistant_service_log_ex.service_hours
perfHours number? 折算工时(小时),激励课按系数折算 dwd_assistant_service_log_ex,后端按激励系数计算
fee number 服务费用(元),⚠️ 基础课 = assistant_pd_money,激励课 = assistant_cx_moneyDWD-DOC 规则 2 dwd_settlement_head.assistant_pd_money / assistant_cx_money
notes 模块(每项 4 个字段)
字段 类型 说明 数据源
id string 备注唯一 ID biz.customer_notes.id
tagLabel string 标签文本,如 "跟进""重要" biz.customer_notes.tag
createdAt string 创建时间ISO 8601 格式 biz.customer_notes.created_at
content string 备注内容 biz.customer_notes.content

业务规则

规则 说明
items_sum 口径DWD-DOC 规则 1 所有金额字段(balance/consumption60d/tableFee/foodAmount/totalAmount 等)使用 items_sum = table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money,禁止使用 consume_money
助教费用拆分DWD-DOC 规则 2 coaches[].fee 中基础课 = assistant_pd_money(陪打),激励课 = assistant_cx_money(超休);favoriteCoaches[].stats 中基础课时/激励课时同理。禁止使用 service_fee
会员信息 JOINDWD-DOC 规则 DQ-6 name/phone/phoneFull 必须通过 member_id LEFT JOIN dwd.dim_member(取 scd2_is_current=1)获取,禁止直接使用 settlement_head.member_phone/member_name(自 2025-12 起全为 NULL
会员卡 JOINDWD-DOC 规则 DQ-7 memberLevel 必须通过 member_id LEFT JOIN dwd.dim_member_card_accounttenant_member_id=member_idscd2_is_current=1)获取,禁止直接使用 member_card_type_name(自 2025-07-21 起全为 NULL
settle_type 过滤 消费记录取正向交易 settle_type IN (1, 3),本表无 is_delete 字段
废单排除 使用 dwd_assistant_service_log_ex.is_trash 排除废单,dwd_assistant_trash_event 已废弃
type 枚举映射 table(台桌消费)/ shop(酒水/商品消费)/ recharge(充值),后端根据 settle_type 和业务逻辑映射
亲密度 emoji 💖(>8.5) / 🧡(>7) / 💛(>5) / 💙(≤5)

数据源映射表

模块 主数据源 辅助数据源
基础信息 biz.members fdw_etl.dwd.dim_memberDQ-6fdw_etl.dwd.dim_member_card_accountDQ-7
Banner 概览 fdw_etl.dwd.dwd_settlement_head fdw_etl.dws.*(余额聚合)
AI 洞察 biz.ai_cachecache_type='app4_analysis'
关联助教任务 biz.tasks biz.usersfdw_etl.dwd.dwd_settlement_headdwd_assistant_service_log_ex
最亲密助教 fdw_etl.dwd.dwd_assistant_service_log_ex biz.usersfdw_etl.dwd.dwd_settlement_head
消费记录 fdw_etl.dwd.dwd_settlement_head fdw_etl.dwd.dwd_assistant_service_log_exbiz.recharge_records
备注 biz.customer_notes

CUST-2: 客户服务记录

GET /api/xcx/customers/{customerId}/records?year={year}&month={month}&table={tableId}
Response: {
  customer_name: string,
  customer_phone: string,
  relation_index: string,
  tables: Array<{ id: string, name: string }>,
  records: Array<{
    id: string,
    date: string,
    time_range: string,
    table: string,
    type: string,
    type_class: string,
    duration: number,
    duration_raw?: number,
    income: number,
    drinks: string
  }>,
  has_more: boolean
}

客户模块错误码CUST-1 / CUST-2 共用)

HTTP 状态码 场景 响应示例
403 用户未通过审核(require_approved() 拦截) { "code": 403, "message": "用户未通过审核,无法访问此资源" }
404 客户不存在(customerId 无对应记录) { "code": 404, "message": "客户不存在" }
422 请求参数校验失败year/month/page/pageSize 不合法) Pydantic HTTPValidationError

CUST-1 扩展模块aiInsight/coachTasks/favoriteCoaches/consumptionRecords查询失败时不返回错误码而是对该模块返回空默认值空数组或空对象整体响应仍为 HTTP 200。


六、看板模块

BOARD-1: 助教看板

助教排行看板支持排序×技能×时间三重筛选4 种维度卡片(定档业绩/工资/客源储值/任务)。 数据源:fdw_etl.v_dws_assistant_salary_calc(工资/定档)、fdw_etl.v_dws_recharge_summary(储值)、biz.tasks(任务) DWD-DOC 强制规则:金额字段使用 items_sum 口径(规则 1助教费用使用 assistant_pd_money + assistant_cx_money 拆分(规则 2

GET /api/xcx/board/coaches?sort={sort}&skill={skill}&time={time}

请求参数

参数 类型 必填 说明
sort enum 排序维度6 种枚举:perf_desc(定档业绩最高)/ perf_asc(定档业绩最低)/ salary_desc(工资最高)/ salary_asc(工资最低)/ sv_desc(客源储值最高)/ task_desc(任务完成最多)
skill enum 技能筛选5 种枚举:all(不限)/ chinese🎱 中式/追分)/ snooker(斯诺克)/ mahjong🀄 麻将/棋牌)/ karaoke🎤 团建/K歌
time enum 时间范围6 种枚举:month(本月)/ quarter(本季度)/ last_month(上月)/ last_3m前3个月不含本月/ last_quarter(上季度)/ last_6m最近6个月不含本月

交叉约束

约束 说明
time=last_6m + sort=sv_desc 不兼容,后端返回 HTTP 400 { code: 400, message: "最近6个月不支持客源储值排序" }

原因:储值数据跨 6 个月聚合开销过大,且业务意义有限。前端 TIME_OPTIONS 中已在 last_6m 选项文案标注"不支持客源储值最高"。

响应结构TypeScript 类型定义)

/** 顶层响应 */
interface BoardCoachesResponse {
  items: CoachBoardItem[]
}

/** 助教卡片 — 基础字段 + 4 维度专属字段 */
interface CoachBoardItem {
  // ─── 基础字段(所有维度共享) ───

  /** 助教 ID */
  id: string
  /** 助教姓名 */
  name: string
  /** 姓名首字(用于头像占位符) */
  initial: string
  /** 头像渐变色标识blue/green/pink/amber/violet/cyan 等) */
  avatarGradient: string
  /** 等级英文 keystar / senior / middle / junior */
  level: string
  /**
   * 技能标签列表
   * - text: 技能 emoji 或文字(如 '🎱'、'斯'、'🀄'、'🎤'
   * - cls: 前端样式类(如 'skill--chinese'、'skill--snooker'
   */
  skills: Array<{ text: string; cls: string }>
  /**
   * Top 客户列表(含亲密度 emoji 前缀)
   * 示例:['💖 王先生', '🧡 李女士', '💛 赵总', '💙 新客户']
   * 💖(>8.5) / 🧡(>7) / 💛(>5) / 💙(≤5)
   */
  topCustomers: string[]

  // ─── perf 维度专属sort=perf_desc / perf_asc 时展示) ───

  /** 当期定档工时(小时) */
  perfHours: number
  /** 上期定档工时(小时),无上期数据时不返回 */
  perfHoursBefore?: number
  /** 距升档差距描述,如 '距升档 13.8h';已达标时不返回 */
  perfGap?: string
  /** 是否已达标当前档位 */
  perfReached: boolean

  // ─── salary 维度专属sort=salary_desc / salary_asc 时展示) ───

  /** 预估工资总额(元) */
  salary: number
  /** 工资维度-定档工时(小时) */
  salaryPerfHours: number
  /** 工资维度-上期定档工时(小时),无上期数据时不返回 */
  salaryPerfBefore?: number

  // ─── sv 维度专属sort=sv_desc 时展示) ───

  /** 客源储值总额(元) */
  svAmount: number
  /** 储值客户数 */
  svCustomerCount: number
  /** 储值消耗额(元) */
  svConsume: number

  // ─── task 维度专属sort=task_desc 时展示) ───

  /** 召回任务完成数 */
  taskRecall: number
  /** 回访任务完成数 */
  taskCallback: number
}

字段说明表

基础字段7 个,所有维度共享)
字段 类型 说明 数据源
id string 助教唯一 ID biz.users.id
name string 助教姓名 biz.users.nickname
initial string 姓名首字,用于头像占位符渲染 后端从 name 提取
avatarGradient string 头像渐变色标识(blue/green/pink/amber/violet/cyan 后端根据 ID 哈希分配
level string 等级英文 keystar/senior/middle/junior fdw_etl.v_dws_assistant_salary_calc.coach_level
skills Array<{ text: string, cls: string }> 技能标签,text 为 emoji 或文字,cls 为前端样式类 biz.coach_skills 或配置表
topCustomers string[] Top 客户列表,含亲密度 emoji 前缀(💖/🧡/💛/💙 后端按亲密度排序取 Top 3拼接 emoji + 姓名
perf 维度专属字段4 个)
字段 类型 说明 数据源
perfHours number 当期定档工时(小时) fdw_etl.v_dws_assistant_salary_calc,按 time 参数聚合
perfHoursBefore number? 上期定档工时(小时),无上期数据时不返回 同上,取上一周期
perfGap string? 距升档差距描述,如 '距升档 13.8h';已达标时不返回 后端根据档位阈值计算
perfReached boolean 是否已达标当前档位 后端根据档位阈值判断
salary 维度专属字段3 个)
字段 类型 说明 数据源
salary number 预估工资总额(元),⚠️ 使用 items_sum 口径 fdw_etl.v_dws_assistant_salary_calc
salaryPerfHours number 工资维度-定档工时(小时) 同上
salaryPerfBefore number? 工资维度-上期定档工时(小时),无上期数据时不返回 同上,取上一周期
sv 维度专属字段3 个)
字段 类型 说明 数据源
svAmount number 客源储值总额(元) fdw_etl.v_dws_recharge_summary,按助教关联客户聚合
svCustomerCount number 储值客户数 同上,COUNT(DISTINCT customer_id)
svConsume number 储值消耗额(元) 同上,消耗金额聚合
task 维度专属字段2 个)
字段 类型 说明 数据源
taskRecall number 召回任务完成数 biz.taskstask_type='priority_recall' AND status='completed'
taskCallback number 回访任务完成数 biz.taskstask_type='callback' AND status='completed'

维度与排序的关系

前端根据 sort 参数决定展示哪组维度字段(卡片模板切换):

sort 值 维度类型 展示字段
perf_desc / perf_asc perf perfHours / perfHoursBefore / perfGap / perfReached
salary_desc / salary_asc salary salary / salaryPerfHours / salaryPerfBefore
sv_desc sv svAmount / svCustomerCount / svConsume
task_desc task taskRecall / taskCallback

后端始终返回所有维度字段(避免多次请求),前端根据 sort 选择性渲染对应卡片模板。

业务规则

规则 说明
time=last_6m + sort=sv_desc → HTTP 400 储值数据跨 6 个月聚合开销过大,后端拒绝此组合
items_sum 口径DWD-DOC 规则 1 salary 等金额字段使用 items_sum 口径,禁止使用 consume_money
助教费用拆分DWD-DOC 规则 2 工资计算中基础课 = assistant_pd_money,激励课 = assistant_cx_money
levelClass 前端计算 后端仅返回 level(英文 key前端通过 LEVEL_CLASS 映射生成样式类
perfGap 后端计算 后端根据档位阈值计算差距描述字符串,已达标时不返回该字段
topCustomers emoji 规则 💖(>8.5) / 🧡(>7) / 💛(>5) / 💙(≤5),基于 rs_display 值域 0-10

BOARD-2: 客户看板

客户排行看板,支持 8 个维度查看前 100 名客户,每个维度展示不同的专属字段卡片。 数据源:fdw_etl.v_dws_customer_* 系列视图(召回/潜力/余额/充值/到店/消费/频率/专一度)、biz.tasks(任务关联)、fdw_etl.dwd.dim_member(会员信息) DWD-DOC 强制规则:金额字段使用 items_sum 口径(规则 1会员信息通过 member_id JOIN dim_member 获取(规则 DQ-6/DQ-7

GET /api/xcx/board/customers?dimension={dim}&project={proj}&page=1&pageSize=20

请求参数

参数 类型 必填 说明
dimension enum 维度8 种枚举:recall(最应召回)/ potential(最大消费潜力)/ balance(最高余额)/ recharge(最近充值)/ recent(最近到店)/ spend60最高消费近60天/ freq60最频繁近60天/ loyal最专一近60天
project enum 项目筛选5 种枚举:all(全部)/ chinese🎱 中式/追分)/ snooker(斯诺克)/ mahjong🀄 麻将/棋牌)/ karaoke🎤 团建/K歌
page number 页码,默认 1
pageSize number 每页条数,默认 20

响应结构TypeScript 类型定义)

/** 顶层响应 */
interface BoardCustomersResponse {
  items: CustomerBoardItem[]
  total: number
  page: number
  pageSize: number
}

// ─── 助教信息(嵌套在客户卡片中) ───

interface AssistantInfo {
  /** 助教姓名 */
  name: string
  /**
   * 前端样式类
   * - 'assistant--assignee':当前跟进助教
   * - 'assistant--abandoned':已放弃的助教
   * - 'assistant--normal':普通关联助教
   */
  cls: string
  /** 亲密度分数 0-10供 heart-icon 组件渲染 */
  heartScore: number
  /** 角标文字,如 '跟'(跟进中)/ '弃'(已放弃) */
  badge?: string
  /** 角标样式类,如 'assistant-badge--follow' / 'assistant-badge--drop' */
  badgeCls?: string
}

/** 客户卡片 — 基础字段 + 8 维度专属字段 */
interface CustomerBoardItem {
  // ─── 基础字段所有维度共享5 个) ───

  /** 客户唯一 ID */
  id: string
  /** 客户姓名 */
  name: string
  /** 姓名首字(用于头像占位符) */
  initial: string
  /** 头像样式类avatar--amber / avatar--pink / avatar--blue 等) */
  avatarCls: string
  /**
   * 关联助教列表
   * 按亲密度降序排列,含跟进状态角标
   */
  assistants: AssistantInfo[]

  // ─── recall 维度专属dimension=recall 时展示) ───

  /** 理想到店间隔(天) */
  idealDays?: number
  /** 已过天数(距上次到店) */
  elapsedDays?: number
  /** 超期天数elapsedDays - idealDays> 0 表示超期) */
  overdueDays?: number
  /** 近 30 天到店次数 */
  visits30d?: number
  /** 客户余额(格式化字符串,如 '¥2,680' */
  balance?: string
  /** 召回指数0-10 评分,如 '9.2' */
  recallIndex?: string

  // ─── potential 维度专属dimension=potential 时展示) ───

  /**
   * 潜力标签列表
   * - text: 标签文字(如 '高频'、'高客单'、'高余额'、'低频'
   * - theme: 标签主题色('primary' / 'warning' / 'success' / 'gray'
   */
  potentialTags?: Array<{ text: string; theme: string }>
  /** 近 30 天消费(格式化字符串,如 '¥4,200' */
  spend30d?: string
  /** 平均到店频率(如 '6.2次' */
  avgVisits?: string
  /** 平均客单价(格式化字符串,如 '¥680' */
  avgSpend?: string

  // ─── balance 维度专属dimension=balance 时展示) ───

  // balance 字段复用上方 recall 维度的 balance格式化字符串
  /** 最后到店时间(如 '3天前'、'12天前' */
  lastVisit?: string
  /** 月均消费(格式化字符串,如 '¥3,500' */
  monthlyConsume?: string
  /** 可用月数(如 '约0.8个月'、'约4.6个月' */
  availableMonths?: string

  // ─── recharge 维度专属dimension=recharge 时展示) ───

  /** 最近充值日期(如 '2月15日' */
  lastRecharge?: string
  /** 充值金额(格式化字符串,如 '¥5,000' */
  rechargeAmount?: string
  /** 近 60 天充值次数(如 '2次' */
  recharges60d?: string
  /** 当前余额(格式化字符串,如 '¥2,680' */
  currentBalance?: string

  // ─── recent 维度专属dimension=recent 时展示) ───

  /** 距上次到店天数 */
  daysAgo?: number
  /** 到店频率(如 '6.2次/月' */
  visitFreq?: string
  // idealDays 复用 recall 维度字段
  // visits30d 复用 recall 维度字段
  // avgSpend 复用 potential 维度字段

  // ─── spend60 维度专属dimension=spend60 时展示) ───

  /** 近 60 天消费(格式化字符串,如 '¥8,400' */
  spend60d?: string
  /** 近 60 天到店次数(如 '12' */
  visits60d?: string
  /** 是否高消费标记true 时前端显示高消费标签) */
  highSpendTag?: boolean
  // avgSpend 复用 potential 维度字段

  // ─── freq60 维度专属dimension=freq60 时展示) ───

  // visits60d 复用 spend60 维度字段
  /** 平均到店间隔(天,如 '5.0天' */
  avgInterval?: string
  /**
   * 最近 8 周到店柱状图数据
   * - val: 该周到店次数
   * - pct: 百分比高度0-100相对于最大值
   * 数组长度固定为 8从最早一周到最近一周排列
   */
  weeklyVisits?: Array<{ val: number; pct: number }>
  // spend60d 复用 spend60 维度字段

  // ─── loyal 维度专属dimension=loyal 时展示) ───

  /** 专一度指数0-100如 '92' */
  intimacy?: string
  /** Top 1 助教姓名 */
  topCoachName?: string
  /** Top 1 助教亲密度heart-icon 分数0-10 */
  topCoachHeart?: number
  /** Top 1 助教关系指数(如 '9.2' */
  topCoachScore?: string
  /** 主助教姓名(占比最高的助教) */
  coachName?: string
  /** 主助教服务占比(如 '78%' */
  coachRatio?: string
  /**
   * 助教明细列表(按服务占比降序)
   * 展示每位助教的服务统计和关系指数
   */
  coachDetails?: Array<{
    /** 助教姓名 */
    name: string
    /** 前端样式类(同 AssistantInfo.cls */
    cls: string
    /** 亲密度分数 0-10 */
    heartScore: number
    /** 角标文字('跟' / '弃'),无角标时不返回 */
    badge?: string
    /** 平均服务时长(如 '2.3h' */
    avgDuration: string
    /** 服务次数(如 '14' */
    serviceCount: string
    /** 该助教关联消费金额(格式化字符串,如 '¥4,200' */
    coachSpend: string
    /** 关系指数0-10 */
    relationIdx: number
  }>
}

字段说明表

基础字段5 个,所有维度共享)
字段 类型 说明 数据源
id string 客户唯一 ID fdw_etl.dwd.dim_member.member_id
name string 客户姓名 fdw_etl.dwd.dim_member.nickname(通过 member_id JOINDQ-6
initial string 姓名首字,用于头像占位符渲染 后端从 name 提取
avatarCls string 头像样式类(avatar--amber/avatar--pink/avatar--blue 等) 后端根据 ID 哈希分配
assistants AssistantInfo[] 关联助教列表,含亲密度和跟进状态 biz.tasks + fdw_etl.dws 亲密度计算
recall 维度专属字段6 个)
字段 类型 说明 数据源
idealDays number 理想到店间隔(天),基于历史到店频率计算 fdw_etl.v_dws_customer_recall
elapsedDays number 距上次到店已过天数 同上,CURRENT_DATE - last_visit_date
overdueDays number 超期天数(elapsedDays - idealDays 后端计算
visits30d number 近 30 天到店次数 fdw_etl.v_dws_customer_recall
balance string 客户余额(格式化),⚠️ 使用 items_sum 口径 fdw_etl.dwd.dim_member_card_account
recallIndex string 召回指数0-10综合超期天数、余额、频率加权 后端算法计算
potential 维度专属字段4 个)
字段 类型 说明 数据源
potentialTags Array<{ text, theme }> 潜力标签(高频/高客单/高余额/低频等),theme 取值 primary/warning/success/gray 后端根据消费特征生成
spend30d string 近 30 天消费(格式化),⚠️ 使用 items_sum 口径 fdw_etl.v_dws_customer_potential
avgVisits string 平均到店频率(如 '6.2次' 同上
avgSpend string 平均客单价(格式化),⚠️ 使用 items_sum 口径 同上,spend / visits
balance 维度专属字段4 个)
字段 类型 说明 数据源
balance string 客户余额(格式化),与 recall 维度共用字段 fdw_etl.dwd.dim_member_card_account
lastVisit string 最后到店时间描述(如 '3天前' fdw_etl.v_dws_customer_balance
monthlyConsume string 月均消费(格式化),⚠️ 使用 items_sum 口径 同上
availableMonths string 可用月数(balance / monthlyConsume,如 '约0.8个月' 后端计算
recharge 维度专属字段4 个)
字段 类型 说明 数据源
lastRecharge string 最近充值日期(如 '2月15日' fdw_etl.v_dws_customer_recharge
rechargeAmount string 最近充值金额(格式化) 同上
recharges60d string 近 60 天充值次数(如 '2次' 同上
currentBalance string 当前余额(格式化) fdw_etl.dwd.dim_member_card_account
recent 维度专属字段5 个)
字段 类型 说明 数据源
daysAgo number 距上次到店天数 fdw_etl.v_dws_customer_recent
visitFreq string 到店频率(如 '6.2次/月' 同上
idealDays number 理想到店间隔(天),与 recall 维度共用字段 fdw_etl.v_dws_customer_recall
visits30d number 近 30 天到店次数,与 recall 维度共用字段 同上
avgSpend string 平均客单价,与 potential 维度共用字段 fdw_etl.v_dws_customer_potential
spend60 维度专属字段4 个)
字段 类型 说明 数据源
spend60d string 近 60 天消费(格式化),⚠️ 使用 items_sum 口径 fdw_etl.v_dws_customer_spend60
visits60d string 近 60 天到店次数 同上
highSpendTag boolean 是否高消费标记(true 时前端显示高消费标签) 后端根据阈值判断
avgSpend string 平均客单价,与 potential 维度共用字段 fdw_etl.v_dws_customer_potential
freq60 维度专属字段4 个)
字段 类型 说明 数据源
visits60d string 近 60 天到店次数,与 spend60 维度共用字段 fdw_etl.v_dws_customer_spend60
avgInterval string 平均到店间隔(如 '5.0天' fdw_etl.v_dws_customer_freq60
weeklyVisits Array<{ val, pct }> 最近 8 周到店柱状图,val 为次数,pct 为百分比高度0-100 同上,按周聚合
spend60d string 近 60 天消费,与 spend60 维度共用字段 fdw_etl.v_dws_customer_spend60
loyal 维度专属字段7 个)
字段 类型 说明 数据源
intimacy string 专一度指数0-100 fdw_etl.v_dws_customer_loyal
topCoachName string Top 1 助教姓名 同上,按服务占比排序取第一
topCoachHeart number Top 1 助教亲密度0-10heart-icon 用) 同上
topCoachScore string Top 1 助教关系指数(如 '9.2' 同上
coachName string 主助教姓名(占比最高) 同上
coachRatio string 主助教服务占比(如 '78%' 同上
coachDetails Array<{ name, cls, heartScore, badge?, avgDuration, serviceCount, coachSpend, relationIdx }> 助教明细列表,按服务占比降序 同上,逐助教聚合

维度与展示字段的关系

前端根据 dimension 参数决定展示哪组维度字段(卡片模板切换):

dimension 值 维度类型 展示字段
recall 召回 idealDays / elapsedDays / overdueDays / visits30d / balance / recallIndex
potential 潜力 potentialTags / spend30d / avgVisits / avgSpend
balance 余额 balance / lastVisit / monthlyConsume / availableMonths
recharge 充值 lastRecharge / rechargeAmount / recharges60d / currentBalance
recent 到店 daysAgo / visitFreq / idealDays / visits30d / avgSpend
spend60 消费60天 spend60d / visits60d / highSpendTag / avgSpend
freq60 频率60天 visits60d / avgInterval / weeklyVisits / spend60d
loyal 专一度 intimacy / topCoachName / topCoachHeart / topCoachScore / coachName / coachRatio / coachDetails

后端按 dimension 参数仅返回对应维度的专属字段(减少传输量),前端根据 dimension 选择性渲染对应卡片模板。

业务规则

规则 说明
items_sum 口径DWD-DOC 规则 1 balancespend30davgSpendmonthlyConsumespend60dcoachSpend 等金额字段使用 items_sum 口径,禁止使用 consume_money
会员信息 JOINDWD-DOC 规则 DQ-6 客户姓名通过 member_id JOIN dim_membernicknamescd2_is_current=1),禁止直接使用 member_phone/member_name
会员卡余额 JOINDWD-DOC 规则 DQ-7 余额通过 member_id JOIN dim_member_card_accountscd2_is_current=1),禁止直接使用 member_card_type_name
assistants 排序规则 按亲密度(heartScore)降序排列;当前跟进助教(cls='assistant--assignee')置顶
weeklyVisits 固定 8 周 数组长度固定为 8从最早一周到最近一周排列pct 为相对于 8 周最大值的百分比
coachDetails 排序规则 按服务占比降序排列;badge 仅在跟进('跟')或放弃('弃')状态时返回
分页上限 单次最多返回 100 条(pageSize 上限 100超出截断

数据源映射

维度 FDW 视图 说明
recall fdw_etl.v_dws_customer_recall 召回指数、理想间隔、超期天数
potential fdw_etl.v_dws_customer_potential 潜力标签、消费频率、客单价
balance fdw_etl.v_dws_customer_balance 余额、月均消费、可用月数
recharge fdw_etl.v_dws_customer_recharge 充值记录、充值频率
recent fdw_etl.v_dws_customer_recent 到店天数、到店频率
spend60 fdw_etl.v_dws_customer_spend60 60 天消费、到店次数
freq60 fdw_etl.v_dws_customer_freq60 到店间隔、周柱状图
loyal fdw_etl.v_dws_customer_loyal 专一度、助教明细
会员基础 fdw_etl.dwd.dim_member 姓名、手机号DQ-6
会员卡 fdw_etl.dwd.dim_member_card_account 余额DQ-7
助教关联 biz.tasks + biz.users 跟进状态、角标

BOARD-3: 财务看板

⚠️ 全项目最复杂的单个接口6 个独立板块嵌套结构。 数据源:fdw_etl.v_dws_finance_* 系列视图 + fdw_etl.v_dws_assistant_salary_calc DWD-DOC 强制规则:所有金额字段使用 items_sum 口径(规则 1助教费用使用 assistant_pd_money + assistant_cx_money 拆分(规则 2

GET /api/xcx/board/finance?time={time}&area={area}&compare={0|1}

请求参数

参数 类型 必填 说明
time enum 时间范围8 种枚举:month(本月)/ lastMonth(上月)/ week(本周)/ lastWeek(上周)/ quarter3前3个月不含本月/ quarter(本季度)/ lastQuarter(上季度)/ half6最近6个月不含本月
area enum 区域筛选7 种枚举:all(全部区域)/ hall(大厅)/ hallAA区/ hallBB区/ hallCC区/ mahjong(麻将房)/ teamBuilding(团建房)
compare 0 | 1 是否返回环比数据,默认 0compare=0 时所有 xxxCompare / isDown / isFlat 字段不返回(减少查询开销)

响应结构TypeScript 类型定义)

/** 顶层响应 */
interface BoardFinanceResponse {
  overview: OverviewSection
  recharge: RechargeSection | null  // area ≠ all 时为 null储值卡数据不按区域拆分
  revenue: RevenueSection
  cashflow: CashflowSection
  expense: ExpenseSection
  coachAnalysis: CoachAnalysisSection
}

// ─── 环比字段通用模式 ───
// 每个核心指标附带 3 个环比字段:
//   xxxCompare: string    — 环比百分比,如 "12.5%"、"持平"
//   isDown: boolean       — 是否下降true = 负向变化)
//   isFlat: boolean       — 是否持平true 时 compare 显示 "持平"
// compare=0 时这 3 个字段不返回

// ─── 1. 经营一览 overview ───

interface OverviewSection {
  /** 发生额/正价 — 所有消费项目按标价计算的总金额 */
  occurrence: string                    // 格式化金额,如 "¥823,456"
  occurrenceCompare?: string
  occurrenceDown?: boolean
  occurrenceFlat?: boolean

  /** 总优惠 — 会员折扣 + 赠送卡抵扣 + 团购差价等 */
  discount: string                      // 负值,如 "-¥113,336"
  discountCompare?: string
  discountDown?: boolean
  discountFlat?: boolean

  /** 折扣率 — discount / occurrence */
  discountRate: string                  // 百分比,如 "13.8%"
  discountRateCompare?: string
  discountRateDown?: boolean
  discountRateFlat?: boolean

  /** 成交/确认收入 — occurrence - discount */
  confirmedRevenue: string
  confirmedCompare?: string
  confirmedDown?: boolean
  confirmedFlat?: boolean

  /** 实收/现金流入 — 实际到账现金(消费直接支付 + 储值充值) */
  cashIn: string
  cashInCompare?: string
  cashInDown?: boolean
  cashInFlat?: boolean

  /** 现金支出 — 人工 + 房租 + 水电 + 进货等 */
  cashOut: string
  cashOutCompare?: string
  cashOutDown?: boolean
  cashOutFlat?: boolean

  /** 现金结余 — cashIn - cashOut */
  cashBalance: string
  cashBalanceCompare?: string
  cashBalanceDown?: boolean
  cashBalanceFlat?: boolean

  /** 结余率 — cashBalance / cashIn */
  balanceRate: string                   // 百分比,如 "32.4%"
  balanceRateCompare?: string
  balanceRateDown?: boolean
  balanceRateFlat?: boolean
}

// ─── 2. 预收资产 recharge ───
// ⚠️ area ≠ all 时整个板块返回 null储值卡数据不按区域拆分

interface RechargeSection {
  /** 储值卡充值实收 */
  actualIncome: string
  actualCompare?: string
  actualDown?: boolean
  actualFlat?: boolean

  /** 首充 */
  firstCharge: string
  firstChargeCompare?: string
  firstChargeDown?: boolean
  firstChargeFlat?: boolean

  /** 续费 */
  renewCharge: string
  renewChargeCompare?: string
  renewChargeDown?: boolean
  renewChargeFlat?: boolean

  /** 消耗 — 会员使用储值卡消费的金额 */
  consumed: string
  consumedCompare?: string
  consumedDown?: boolean
  consumedFlat?: boolean

  /** 储值卡总余额 */
  cardBalance: string
  cardBalanceCompare?: string
  cardBalanceDown?: boolean
  cardBalanceFlat?: boolean

  /**
   * 赠送卡 3×4 矩阵
   * 行:新增 / 消费 / 余额
   * 列:合计 / 酒水卡 / 台费卡 / 抵用券
   * 每个单元格含值和环比字段
   */
  giftRows: GiftRow[]

  /** 全类别会员卡余额合计 — 储值卡 + 赠送卡(酒水卡 + 台费卡 + 抵用券) */
  allCardBalance: string
  allCardBalanceCompare?: string
  allCardBalanceDown?: boolean
  allCardBalanceFlat?: boolean
}

interface GiftRow {
  label: string               // "新增" | "消费" | "余额"
  total: string               // 合计金额
  totalCompare?: string
  wine: string                // 酒水卡
  wineCompare?: string
  table: string               // 台费卡
  tableCompare?: string
  coupon: string              // 抵用券
  couponCompare?: string
}

// ─── 3. 应计收入确认 revenue ───

interface RevenueSection {
  /**
   * 收入结构表 — 9 行含子行标记
   * 主行:开台与包厢 / 助教(基础课) / 助教(激励课) / 食品酒水
   * 子行isSub=trueA区 / B区 / C区 / 团建区 / 麻将区(属于"开台与包厢"的子行)
   *
   * ⚠️ DWD-DOC 规则 2助教行金额来自 assistant_pd_money基础课/陪打)和 assistant_cx_money激励课/超休)
   */
  structureRows: RevenueStructureRow[]

  /** 正价明细 — 4 项 */
  priceItems: RevenueDetailItem[]

  /** 发生额合计 */
  totalOccurrence: string
  totalOccurrenceCompare?: string

  /** 优惠明细 — 4 项 */
  discountItems: RevenueDetailItem[]

  /** 确认收入合计 — occurrence - discount */
  confirmedTotal: string
  confirmedTotalCompare?: string
  confirmedTotalDown?: boolean
  confirmedTotalFlat?: boolean

  /** 渠道明细 — 3 项(储值卡结算冲销 / 现金线上支付 / 团购核销确认收入) */
  channelItems: RevenueDetailItem[]
}

interface RevenueStructureRow {
  id: string                  // 行标识,如 "table" / "area-a" / "coach-basic" / "food"
  name: string                // 行名称,如 "开台与包厢" / "A区" / "助教" / "食品酒水"
  desc?: string               // 行描述,如 "基础课" / "激励课"
  amount: string              // 发生额
  discount: string            // 优惠金额(无优惠时为 "-"
  booked: string              // 入账金额
  bookedCompare?: string      // 入账环比
  isSub?: boolean             // 是否为子行(缩进展示)
}

interface RevenueDetailItem {
  name: string                // 项目名称
  desc?: string               // 补充说明,如 "台桌卡+酒水卡+抵用券"
  value: string               // 金额
  compare?: string            // 环比
}

// ─── 4. 现金流入 cashflow ───

interface CashflowSection {
  /** 消费收款 — 3 项(纸币现金 / 线上收款 / 团购平台) */
  consumeItems: CashflowItem[]

  /** 充值收款 — 1 项(会员充值到账) */
  rechargeItems: CashflowItem[]

  /** 合计 */
  total: string
  totalCompare?: string
  totalDown?: boolean
  totalFlat?: boolean
}

interface CashflowItem {
  name: string                // 项目名称
  desc: string                // 补充说明,如 "柜台现金收款"
  value: string               // 金额
  compare?: string            // 环比
  isDown?: boolean            // 是否下降
}

// ─── 5. 现金流出 expense ───

interface ExpenseSection {
  /** 经营支出 — 3 项(食品饮料 / 耗材 / 报销) */
  operationItems: ExpenseItem[]

  /** 固定支出 — 4 项(房租 / 水电 / 物业 / 人员工资) */
  fixedItems: ExpenseItem[]

  /**
   * 助教分成 — 4 项(基础课分成 / 激励课分成 / 充值提成 / 额外奖金)
   * ⚠️ DWD-DOC 规则 2基础课分成来自 assistant_pd_money激励课分成来自 assistant_cx_money
   */
  coachItems: ExpenseItem[]

  /** 平台服务费 — 3 项(汇来米 / 美团 / 抖音) */
  platformItems: ExpenseItem[]

  /** 合计 */
  total: string
  totalCompare?: string
  totalDown?: boolean
  totalFlat?: boolean
}

interface ExpenseItem {
  name: string                // 项目名称
  value: string               // 金额
  compare?: string            // 环比,如 "4.5%" 或 "持平"
  isDown?: boolean            // 是否下降
  isFlat?: boolean            // 是否持平
}

// ─── 6. 助教分析 coachAnalysis ───

interface CoachAnalysisSection {
  /** 基础课(陪打)— assistant_pd_money */
  basic: CoachAnalysisTable

  /** 激励课(超休)— assistant_cx_money */
  incentive: CoachAnalysisTable
}

interface CoachAnalysisTable {
  /** 汇总行 */
  totalPay: string                    // 总课时费
  totalPayCompare?: string
  totalPayDown?: boolean
  totalShare: string                  // 总分成
  totalShareCompare?: string
  totalShareDown?: boolean
  avgHourly: string                   // 平均时薪,如 "¥25/h"
  avgHourlyCompare?: string
  avgHourlyFlat?: boolean

  /** 按等级分行 — 初级 / 中级 / 高级 / 星级 */
  rows: CoachAnalysisRow[]
}

interface CoachAnalysisRow {
  level: string               // "初级" | "中级" | "高级" | "星级"
  pay: string                 // 课时费
  payCompare?: string
  payDown?: boolean
  share: string               // 分成
  shareCompare?: string
  shareDown?: boolean
  hourly: string              // 时薪,如 "¥20/h"
  hourlyCompare?: string      // 如 "持平"
  hourlyFlat?: boolean        // 是否持平
}

业务规则

规则 说明
area ≠ allrecharge = null 储值卡数据不按区域拆分,非全部区域时预收资产板块不返回
items_sum 口径DWD-DOC 规则 1 所有金额字段使用 items_sum = table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money,禁止使用 consume_money
助教费用拆分DWD-DOC 规则 2 基础课 = assistant_pd_money(陪打),激励课 = assistant_cx_money(超休),禁止使用 service_fee
支付渠道恒等式DWD-DOC 规则 3 balance_amount = recharge_card_amount + gift_card_amount,三者不可重复计算
折扣互斥DWD-DOC 规则 6 discount_manual(大客户优惠)与 discount_other 互斥,两者之和 = adjust_amount
现金流互斥DWD-DOC 规则 7 platform_settlement_amountgroupbuy_pay_amount 互斥
环比计算 后端根据 time 参数计算当期和上期日期范围,分别查询后计算百分比;compare=0 时不计算

数据源映射

板块 FDW 视图 说明
overview fdw_etl.v_dws_finance_overview 8 指标 + 8 环比
recharge fdw_etl.v_dws_finance_recharge 储值卡 + 赠送卡矩阵
revenue fdw_etl.v_dws_finance_revenue 收入结构表 + 明细
cashflow fdw_etl.v_dws_finance_cashflow 消费收款 + 充值收款
expense fdw_etl.v_dws_finance_expense 4 子分组
coachAnalysis fdw_etl.v_dws_assistant_salary_calc 按等级分行聚合

字段说明表

overview 经营一览8 指标)
字段 类型 说明 环比字段
occurrence string 发生额/正价 occurrenceCompare + occurrenceDown + occurrenceFlat
discount string 总优惠(负值) discountCompare + discountDown + discountFlat
discountRate string 折扣率(百分比) discountRateCompare + discountRateDown + discountRateFlat
confirmedRevenue string 成交/确认收入 confirmedCompare + confirmedDown + confirmedFlat
cashIn string 实收/现金流入 cashInCompare + cashInDown + cashInFlat
cashOut string 现金支出 cashOutCompare + cashOutDown + cashOutFlat
cashBalance string 现金结余 cashBalanceCompare + cashBalanceDown + cashBalanceFlat
balanceRate string 结余率(百分比) balanceRateCompare + balanceRateDown + balanceRateFlat
recharge 预收资产
字段 类型 说明
actualIncome string 储值卡充值实收
firstCharge string 首充
renewCharge string 续费
consumed string 消耗
cardBalance string 储值卡总余额
giftRows GiftRow[] 赠送卡 3×4 矩阵(新增/消费/余额 × 合计/酒水卡/台费卡/抵用券)
allCardBalance string 全类别会员卡余额合计
revenue 应计收入确认
字段 类型 说明
structureRows RevenueStructureRow[] 收入结构表9 行含子行)
priceItems RevenueDetailItem[] 正价明细4 项:开台消费/酒水商品/包厢费用/助教服务)
totalOccurrence string 发生额合计
discountItems RevenueDetailItem[] 优惠明细4 项:团购优惠/手动调整+大客户优惠/赠送卡抵扣/其他优惠)
confirmedTotal string 确认收入合计
channelItems RevenueDetailItem[] 渠道明细3 项:储值卡结算冲销/现金线上支付/团购核销确认收入)
coachAnalysis 助教分析
子表 数据源字段 说明
basic assistant_pd_money 基础课(陪打)按初级/中级/高级/星级分行
incentive assistant_cx_money 激励课(超休)按初级/中级/高级/星级分行

七、助教模块(已实现

COACH-1: 助教详情

数据源:zqyy_app.coaches(基本信息)、etl_feiqiu.dws.*(绩效/收入via FDWzqyy_app.coach_tasks(任务)、zqyy_app.coach_notes(备注) 金额口径:所有消费金额使用 items_sumDWD-DOC 强制规则 1助教费用使用 assistant_pd_money + assistant_cx_money 拆分DWD-DOC 强制规则 2 会员信息:通过 member_id JOIN dim_member 获取DWD-DOC 强制规则 DQ-6禁止直接使用 member_phone

GET /api/xcx/coaches/{coachId}

响应结构

interface CoachDetailResponse {
  // ── 基本信息 ──
  id: string
  name: string
  avatar: string
  level: string                    // 初级/中级/高级/星级
  skills: string[]                 // 技能标签,如 ['中🎱', '🎯斯诺克']
  workYears: number                // 工龄(年)
  customerCount: number            // 客户数
  hireDate: string                 // 入职日期,如 '2023-03-15'

  // ── 绩效指标performance ──
  performance: {
    monthlyHours: number           // 本月定档工时
    monthlySalary: number          // 本月工资(预估)
    customerBalance: number        // 客源储值余额合计
    tasksCompleted: number         // 本月任务完成数
    perfCurrent: number            // 当前绩效值
    perfTarget: number             // 绩效目标值
  }

  // ── 收入明细income ──
  // thisMonth / lastMonth 各含 4 项收入分类
  income: {
    thisMonth: IncomeItem[]
    lastMonth: IncomeItem[]
  }

  // ── 档位节点tierNodes ──
  // 供前端绩效进度条组件使用,如 [0, 100, 130, 160, 190, 220]
  tierNodes: number[]

  // ── 任务分组 ──
  visibleTasks: TaskItem[]         // 可见任务
  hiddenTasks: TaskItem[]          // 隐藏任务
  abandonedTasks: AbandonedTask[]  // 已放弃任务

  // ── Top 客户topCustomers ──
  topCustomers: TopCustomer[]

  // ── 近期服务记录serviceRecords ──
  serviceRecords: ServiceRecord[]

  // ── 历史月份统计historyMonths ──
  // 最近 5+ 个月的汇总数据
  historyMonths: HistoryMonth[]

  // ── 备注notes ──
  notes: NoteItem[]
}

子类型定义

/** 收入分项 */
interface IncomeItem {
  label: string                    // 如 '基础课时费'、'激励课时费'、'充值提成'、'酒水提成'
  amount: string                   // 格式化金额,如 '¥3,500'
  color: string                    // 主题色primary / success / warning / purple
}

/** 任务项visibleTasks / hiddenTasks */
interface TaskItem {
  typeLabel: string                // 任务类型标签,如 '高优先召回'、'客户回访'
  typeClass: string                // 样式类high-priority / priority / callback / relationship
  customerName: string             // 客户姓名
  customerId?: string              // 客户 ID用于跳转 customer-detail
  noteCount: number                // 备注数量
  pinned: boolean                  // 是否置顶
  notes?: Array<{                  // 备注列表(可选)
    pinned?: boolean               // 是否置顶备注
    text: string                   // 备注内容
    date: string                   // 日期,如 '2026-02-06'
  }>
}

/** 已放弃任务 */
interface AbandonedTask {
  customerName: string
  reason: string                   // 放弃原因,如 '客户拒绝'、'超时未响应'
}

/** Top 客户(扩展版,含关系指数和余额) */
interface TopCustomer {
  id: string
  name: string
  initial: string                  // 姓氏首字,如 '王'
  avatarGradient: string           // 头像渐变色pink / amber / green / blue / violet / teal
  heartEmoji: string               // 关系 emojiP6 AC3 四级映射):💖 / 🧡 / 💛 / 💙
  relationScore: string            // 关系指数0-10如 '9.5'
  scoreColor: string               // 分数颜色:#FF6B6B / #FF8C00 / #FFA726 / #5B9BD5
  serviceCount: number             // 服务次数
  balance: string                  // 余额(格式化),如 '¥8,600'
  consume: string                  // 消费总额格式化items_sum 口径),如 '¥12,800'
}

/** 近期服务记录 */
interface ServiceRecord {
  customerId?: string              // 客户 ID用于跳转 customer-detail
  customerName: string
  initial: string
  avatarGradient: string
  type: string                     // 课程类型:'基础课' / '激励课'
  typeClass: string                // 样式类basic / incentive
  table: string                    // 台桌名,如 'A12号台'
  duration: string                 // 时长,如 '2.5h'
  income: string                   // 收入(格式化),如 '¥200'
  date: string                     // 日期时间,如 '2026-02-07 21:30'
  perfHours?: string               // 折算工时(可选),如 '2h'
}

/** 历史月份统计 */
interface HistoryMonth {
  month: string                    // 月份标签:'本月' / '上月' / '4月' 等
  estimated: boolean               // 是否为预估数据
  customers: string                // 客户数(格式化),如 '22人'
  hours: string                    // 工时(格式化),如 '87.5h'
  salary: string                   // 工资(格式化),如 '¥6,950'
  callbackDone: number             // 回访任务完成数
  recallDone: number               // 召回任务完成数
}

/** 备注项 */
interface NoteItem {
  id: string
  content: string                  // 备注内容
  timestamp: string                // ISO 时间戳,用于排序
  aiScore?: number                 // AI 应用 6 评分1-10展示用星数 = aiScore ÷ 2
  manualScore?: number             // 用户手动评分1-5 星,输入用)
  customerName: string             // 关联客户/操作人
  tagLabel: string                 // 标签
  createdAt: string                // 格式化时间,如 '2026-03-05 14:30'
}

字段说明

字段 类型 说明
performance.monthlyHours number 本月定档工时(折算后)
performance.monthlySalary number 本月工资预估(含基础+激励+提成)
performance.customerBalance number 该助教所有客户的储值余额合计
performance.tasksCompleted number 本月已完成任务数
performance.perfCurrent number 当前绩效进度值
performance.perfTarget number 绩效目标值
tierNodes number[] 档位节点数组,如 [0, 100, 130, 160, 190, 220],前端用于绘制进度条刻度
income.thisMonth / lastMonth IncomeItem[] 各含 4 项:基础课时费 / 激励课时费 / 充值提成 / 酒水提成
topCustomers[].consume string 消费总额,使用 items_sum 口径
serviceRecords[].perfHours string? 折算工时,仅激励课有值
serviceRecords[].customerId string? 客户 ID用于从服务记录跳转到客户详情
visibleTasks[].customerId string? 客户 ID用于从任务项跳转到客户详情
historyMonths HistoryMonth[] 最近 5+ 个月,第一条为本月(estimated: true

助教模块错误码COACH-1

HTTP 状态码 场景 响应示例
403 用户未通过审核(require_approved() 拦截) { "code": 403, "message": "用户未通过审核,无法访问此资源" }
404 助教不存在(coachId 无对应记录) { "code": 404, "message": "助教不存在" }
422 请求参数校验失败coachId 类型不合法) Pydantic HTTPValidationError

COACH-1 扩展模块income/topCustomers/serviceRecords/historyMonths/notes查询失败时不返回错误码而是对该模块返回空默认值整体响应仍为 HTTP 200。


八、对话模块(已实现 — RNS1.4

路由前缀:/api/xcx/chatRNS1.4 从 /api/ai/* 迁移,旧路径已移除) 数据源:zqyy_app.biz.ai_conversations(对话会话)、zqyy_app.biz.ai_messages(消息) 时间字段统一使用 createdAtcamelCase替代前端 timestamp 和旧契约 created_at 所有端点需 JWTapproved 状态),使用 require_approved() 权限检查

CHAT-1: 对话历史列表

GET /api/xcx/chat/history?page=1&pageSize=20

请求参数

参数 类型 必填 说明
page number (query) 页码,默认 1
pageSize number (query) 每页条数,默认 20最大 100

响应结构

interface ChatHistoryResponse {
  items: Array<{
    id: number                     // 对话 ID即 chatId
    title: string                  // 对话标题(自定义 > 客户姓名 > 首条消息前20字
    customerName?: string          // 关联客户姓名(仅 contextType=customer 时有值)
    lastMessage?: string           // 最后一条消息摘要
    timestamp: string              // 最后消息时间ISO 8601
    unreadCount: number            // 未读消息数
  }>
  total: number
  page: number
  pageSize: number
}

排序规则

last_message_at 倒序(最新对话在前)。

CHAT-2a: 通过 chatId 查询消息

GET /api/xcx/chat/{chatId}/messages?page=1&pageSize=50

请求参数

参数 类型 必填 说明
chatId number (path) 对话 ID
page number (query) 页码,默认 1
pageSize number (query) 每页条数,默认 50最大 100

CHAT-2b: 通过上下文查询消息

后端根据 contextType + contextId 自动查找或创建对话,返回对应的 chatId 和消息列表。 对话复用规则:task 入口同一 taskId 始终复用(无时限);customer/coach 入口 ≤ 3 天复用、> 3 天新建;general 入口始终新建。

GET /api/xcx/chat/messages?contextType={type}&contextId={id}&page=1&pageSize=50

请求参数

参数 类型 必填 说明
contextType string (query) 上下文类型:task / customer / coach / general
contextId string (query) 上下文 IDtaskId / customerId / coachIdgeneral 时为空)
page number (query) 页码,默认 1
pageSize number (query) 每页条数,默认 50最大 100

响应结构CHAT-2a / CHAT-2b 共用)

interface ChatMessagesResponse {
  chatId: number                   // 对话 ID上下文入口时由后端返回供后续发送消息使用
  items: Array<{
    id: number
    role: 'user' | 'assistant'
    content: string
    createdAt: string              // 统一时间字段名ISO 8601

    // 引用卡片可选AI 回复涉及特定客户时附带)
    referenceCard?: ReferenceCard
  }>
  total: number
  page: number
  pageSize: number
}

排序规则

消息按 created_at 正序(最早的消息在前)。

referenceCard 结构定义

interface ReferenceCard {
  type: 'customer' | 'record'      // 引用类型
  title: string                    // 卡片标题,如 '张伟 — 消费概览'
  summary: string                  // 摘要文字,如 '余额 ¥5,200近30天消费 ¥2,380'
  data: Record<string, string>     // 键值对详情
}

示例:

{
  "type": "customer",
  "title": "张伟 — 消费概览",
  "summary": "余额 ¥5,200近30天消费 ¥2,380",
  "data": {
    "余额": "¥5,200",
    "近30天消费": "¥2,380",
    "到店次数": "8次",
    "最近到店": "3天前"
  }
}

referenceCard 中金额使用 items_sum 口径DWD-DOC 强制规则 1会员信息通过 member_id JOIN dim_member 获取DWD-DOC 规则 DQ-6

CHAT-3: 发送消息(同步回复)

POST /api/xcx/chat/{chatId}/messages
Content-Type: application/json
Body: { content: string }

请求参数

参数 类型 必填 说明
chatId number (path) 对话 ID归属验证不属于当前用户返回 403
content string (body) 消息内容(不能为空)

响应结构

interface SendMessageResponse {
  userMessage: {
    id: number
    content: string
    createdAt: string              // ISO 8601
  }
  aiReply: {
    id: number
    content: string
    createdAt: string              // ISO 8601
  }
}

AI 失败降级

AI 服务调用失败时,用户消息仍保存,aiReply.content 返回错误提示消息(如 "抱歉AI 助手暂时无法回复,请稍后重试"HTTP 状态码保持 200。

CHAT-4: SSE 流式端点

用于 AI 流式回复,前端通过 SSE 接收逐 token 输出。 chatId 归属验证在 SSE 流开始前完成,失败时返回普通 HTTP 403非 SSE

POST /api/xcx/chat/stream
Content-Type: application/json
Body: { chatId: number, content: string }
Response: text/event-stream

SSE 事件类型定义

三种事件类型:message(逐 tokendone(完成)、error(错误)。

event: message
data: {"token": "根据"}

event: message
data: {"token": "数据分析"}

event: done
data: {"messageId": 123, "createdAt": "2026-03-20T14:30:00+08:00"}

event: error
data: {"message": "AI 服务暂时不可用"}
事件类型 data 结构 说明
message { "token": string } 逐 token 输出,token 为文本片段
done { "messageId": number, "createdAt": string } 流结束,返回完整消息 ID 和创建时间
error { "message": string } 错误,返回错误描述

注意SSE 端点的响应不经过 ResponseWrapperMiddleware 包装(text/event-stream 自动跳过RNS1.0 已实现)。

对话模块错误码

HTTP 状态码 场景 响应示例
403 用户未通过审核 { "code": 403, "message": "用户未通过审核,无法访问此资源" }
403 chatId 不属于当前用户 { "code": 403, "message": "无权访问此对话" }
404 对话不存在 { "code": 404, "message": "对话不存在" }
422 消息内容为空 { "code": 422, "message": "消息内容不能为空" }

字段说明

字段 类型 说明
CHAT-1.items[].title string 对话标题(自定义 > 客户姓名 > 首条消息前20字
CHAT-1.items[].timestamp string 最后消息时间ISO 8601
CHAT-2.items[].createdAt string 统一时间字段名,替代 created_attimestamp
CHAT-2.items[].referenceCard ReferenceCard? 引用卡片AI 回复涉及客户时附带结构化上下文数据
CHAT-2b contextType 参数 query 上下文类型:task / customer / coach / general
CHAT-2b contextId 参数 query 上下文 IDtaskId / customerId / coachId
CHAT-4 SSE text/event-stream 三种事件:messagetoken/ done(完成)/ error(错误)

九、配置模块

CONFIG-1: 技能类型列表REQ-1

GET /api/xcx/config/skill-types
Response: {
  skills: Array<{ value: string, text: string, icon?: string }>
}

附:接口与页面映射

页面 依赖接口 优先级
login AUTH-1, AUTH-2 已实现
app.ts AUTH-3, AUTH-4 已实现
apply AUTH-5 已实现
reviewing AUTH-3 已实现
no-permission AUTH-3 已实现
task-list TASK-1 P0
task-detail TASK-2, TASK-3, TASK-4, NOTE-2, NOTE-3 P0
notes NOTE-1, NOTE-3 P1
performance PERF-1 P1
performance-records PERF-2 P1
customer-detail CUST-1 后端已实现
customer-service-records CUST-2 后端已实现
coach-detail COACH-1 后端已实现
board-coach BOARD-1, CONFIG-1 P2
board-customer BOARD-2 P2
board-finance BOARD-3 P2
chat-history CHAT-1 后端已实现
chat CHAT-2a, CHAT-2b, CHAT-3, CHAT-4 后端已实现
my-profile AUTH-3 已实现(读 globalData