1
@@ -24,38 +24,25 @@
|
||||
|
||||
### 2.2 数据库变更手册 `docs/database/`
|
||||
|
||||
每个 `BD_Manual_*.md` 是一次数据库结构变更的完整审计文档,包含:变更说明、字段定义、影响分析、回滚策略、验证 SQL。
|
||||
业务库(zqyy_app)相关的 BD 手册。ETL 专属表级文档已迁移至 `apps/etl/connectors/feiqiu/docs/database/`(见 3.2 节)。
|
||||
|
||||
| 文件 | 记录内容 |
|
||||
|------|----------|
|
||||
| `BD_Manual_auth_tables.md` | auth Schema 8 张认证表(users、roles、permissions、user_applications 等) |
|
||||
| `BD_Manual_biz_tables.md` | biz Schema 4 张核心业务表(coach_tasks、coach_task_history、notes、trigger_jobs) |
|
||||
| `BD_Manual_biz_tables.md` | biz Schema 核心业务表(coach_tasks、coach_task_history、notes、trigger_jobs、AI 表等) |
|
||||
| `BD_Manual_auth_biz_schemas.md` | auth + biz Schema 创建 |
|
||||
| `BD_Manual_fdw_etl_setup.md` | FDW 跨库访问配置(zqyy_app → etl_feiqiu) |
|
||||
| `BD_Manual_app_schema_rls_views.md` | app Schema RLS 视图 |
|
||||
| `BD_Manual_dws_assistant_order_contribution.md` | DWS 助教订单贡献表 |
|
||||
| `BD_Manual_dws_goods_stock_summary.md` | DWS 商品库存汇总表 |
|
||||
| `BD_Manual_dws_member_spending_power_index.md` | DWS 会员消费力指数表 |
|
||||
| `BD_Manual_member_balance_changes.md` | 会员余额变动表 |
|
||||
| `BD_Manual_recharge_settlements.md` | 充值结算表 |
|
||||
| `BD_Manual_goods_stock_movements.md` | 商品库存流水表 |
|
||||
| `BD_Manual_goods_stock_summary.md` | 商品库存汇总表 |
|
||||
| `BD_Manual_goods_stock_warning_info.md` | 商品库存预警表 |
|
||||
| `BD_Manual_store_goods_master.md` | 门店商品主表 |
|
||||
| `BD_Manual_store_goods_sales_records.md` | 门店商品销售记录 |
|
||||
| `BD_Manual_tenant_goods_master.md` | 租户商品主表 |
|
||||
| `BD_Manual_assistant_accounts_master.md` | 助教账户主表 |
|
||||
| `BD_Manual_assistant_service_records.md` | 助教服务记录表 |
|
||||
| `BD_Manual_site_tables_master.md` | 门店台桌主表 |
|
||||
| `BD_Manual_20260301_cleanup_and_fixes.md` | 已删除表残留清理 + ODS 商品销售窗口修复 + dim_staff_ex 列名修复 |
|
||||
| `BD_Manual_ai_tables.md` | AI 相关表(ai_chat_sessions、ai_chat_messages 等) |
|
||||
| `BD_Manual_member_retention_clue.md` | 会员留存线索表 |
|
||||
| `README.md` | 数据库文档目录说明 |
|
||||
|
||||
子目录:
|
||||
|
||||
| 目录 | 内容 |
|
||||
|------|------|
|
||||
| `ddl/` | 10 个 DDL 基线文件,覆盖 etl_feiqiu 六层 Schema(meta/ods/dwd/core/dws/app)+ zqyy_app 三个 Schema(auth/biz/public)+ FDW |
|
||||
| `_archived/` | 10 个已归档的历史变更文档(已废弃的表、已回滚的变更等) |
|
||||
| `ddl/` | 10 个 DDL 基线文件(含种子数据),覆盖 etl_feiqiu 六层 Schema(meta/ods/dwd/core/dws/app)+ zqyy_app 三个 Schema(auth/biz/public)+ FDW |
|
||||
| `_archived/` | 已归档的历史变更文档(已废弃的表、已回滚的变更、已合并入 DDL 基线的迁移记录) |
|
||||
|
||||
### 2.3 审计记录 `docs/audit/`
|
||||
|
||||
@@ -66,7 +53,7 @@
|
||||
| `audit_dashboard.md` | 审计仪表盘,汇总所有变更审计记录 |
|
||||
| `README.md` | 审计目录说明 |
|
||||
| `SESSION-LOG-GUIDE.md` | Session 日志使用指南:索引字段说明、查询方法、典型场景、与其他审计产物的关系 |
|
||||
| `changes/` | 38 份变更审计文档(`YYYY-MM-DD__<slug>.md` 格式),每份包含:变更原因、影响范围、回滚策略、验证 SQL |
|
||||
| `changes/` | 39 份变更审计文档(`YYYY-MM-DD__<slug>.md` 格式),每份包含:变更原因、影响范围、回滚策略、验证 SQL |
|
||||
| `prompt_logs/` | ~500 份 Prompt 日志(`prompt_log_YYYYMMDD_HHMMSS.md`),记录每次 AI 交互的输入输出 |
|
||||
| `session_logs/` | 全量会话记录(按 `YYYY-MM/DD/` 分层),含双索引(`_session_index.json` / `_session_index_full.json`)、每轮 execution 的完整 Markdown 记录、LLM 生成的操作摘要 |
|
||||
|
||||
@@ -109,14 +96,39 @@ H5 静态原型页面,用于小程序 UI 设计参考。
|
||||
| `js/` | 8 个交互脚本 |
|
||||
| `img/` | 图片资源 |
|
||||
|
||||
### 2.8 参考资料 `docs/reference/`
|
||||
### 2.8 小程序前端开发指南 `docs/miniprogram-dev/`
|
||||
|
||||
微信小程序前端页面开发与 H5 原型迁移的统一文档中心。覆盖批量自动迁移、用户指定半自动开发、新页面从零开发三种模式。
|
||||
|
||||
| 路径 | 内容 |
|
||||
|------|------|
|
||||
| `README.md` | 入口索引:快速导航、目录结构、Power 依赖、关联资源 |
|
||||
| `01-orchestration/batch-auto-playbook.md` | 批量自动模式:89 单元编排 + 4 代理流水线 |
|
||||
| `01-orchestration/user-guided-playbook.md` | 半自动模式:对话触发 + 按需执行 |
|
||||
| `01-orchestration/new-page-playbook.md` | 新页面开发:有原型 / 无原型两条路径 |
|
||||
| `02-action/screenshot-agent.md` | 截图代理:H5/MP 双端截图执行手册 |
|
||||
| `02-action/audit-agent.md` | 审计代理:结构化审计执行手册 |
|
||||
| `02-action/fix-agent.md` | 修正代理:P0-P7 分级修正执行手册 |
|
||||
| `02-action/verify-agent.md` | 验证代理:回归校验执行手册 |
|
||||
| `02-action/page-dev-agent.md` | 页面开发代理:新页面完整开发执行手册 |
|
||||
| `03-reference/wxss-rules.md` | WXSS 规范 + rpx 换算 + 颜色/字号/圆角标准值 |
|
||||
| `03-reference/page-structure-map.md` | 各页面特殊结构速查 |
|
||||
| `03-reference/css-risk-features.md` | CSS 风险特性 + 替代方案 |
|
||||
| `03-reference/power-integration.md` | Power 集成指南(4 个 Power 的调用方式) |
|
||||
| `03-reference/benchmark-history.md` | 基准测试历史记录 |
|
||||
| `04-audit/PROGRESS.md` | 89 单元进度跟踪(实时更新) |
|
||||
| `04-audit/CHANGELOG.md` | 文档体系版本变更记录 |
|
||||
| `05-lessons/pitfalls.md` | 踩坑速查 + 页面迁移经验 |
|
||||
| `05-lessons/convergence-patterns.md` | 收敛模式 + 不可消除差异白名单 |
|
||||
|
||||
### 2.9 参考资料 `docs/reference/`
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `bailian-agent-guide.md` | 百炼 Agent 集成参考指南(由 v1 + v2 合并) |
|
||||
| `bailian-dashscope-api.md` | 百炼 DashScope API 参考 |
|
||||
|
||||
### 2.9 数据分析报告 `docs/reports/`
|
||||
### 2.10 数据分析报告 `docs/reports/`
|
||||
|
||||
一次性数据分析、调研产出的报告文档。与 `prd/specs/` 的区别:specs 是需求规格,reports 是基于数据的分析结论。
|
||||
|
||||
@@ -125,13 +137,13 @@ H5 静态原型页面,用于小程序 UI 设计参考。
|
||||
| `complex-orders-analysis.md` | 复杂订单结构分析(ODS 全量扫描,关联键与复杂度定义) |
|
||||
| `dwd-amount-duration-calibration.md` | DWD 层金额·绩效·时长字段口径全景(置信度与存疑项标注) |
|
||||
|
||||
### 2.10 架构文档 `docs/architecture/`
|
||||
### 2.11 架构文档 `docs/architecture/`
|
||||
|
||||
| 文件 | 内容 |
|
||||
|------|------|
|
||||
| `etl-feiqiu-architecture.md` | ETL Connector 整体架构说明(数据流、DWS/INDEX 任务、调度编排、CLI) |
|
||||
|
||||
### 2.11 其他项目级文档目录
|
||||
### 2.12 其他项目级文档目录
|
||||
|
||||
| 路径 | 内容 |
|
||||
|------|------|
|
||||
@@ -166,7 +178,7 @@ H5 静态原型页面,用于小程序 UI 设计参考。
|
||||
| `docs/api-reference/` | 上游飞球 API 接口文档(字段映射、请求参数、响应结构) |
|
||||
| `docs/architecture/` | 架构设计文档(数据流、分层设计、SCD 策略) |
|
||||
| `docs/business-rules/` | 业务规则文档(金额精度、时区处理、去重逻辑) |
|
||||
| `docs/database/` | ETL 数据库文档(Schema 设计、表结构、索引策略) |
|
||||
| `docs/database/` | ETL 数据库文档:按 Schema 层分目录(ODS/DWD/DWS/ETL_Admin),含表结构、索引策略、跨层映射(cross_layer)、变更记录 |
|
||||
| `docs/etl_tasks/` | ETL 任务文档(每个任务的输入输出、依赖、调度配置) |
|
||||
| `docs/operations/` | 运维文档(监控、告警、故障排查) |
|
||||
| `docs/requirements/` | 需求文档(功能需求、非功能需求) |
|
||||
@@ -204,10 +216,10 @@ H5 静态原型页面,用于小程序 UI 设计参考。
|
||||
|------|------|
|
||||
| `README.md` | 数据库目录总览、四库架构说明 |
|
||||
| `zqyy_app/README.md` | 业务库文档:auth Schema 8 张表字段说明、迁移顺序、FDW 跨库访问 |
|
||||
| `zqyy_app/migrations/` | 业务库迁移脚本(日期前缀命名) |
|
||||
| `zqyy_app/migrations/` | 业务库迁移脚本(已合并入 DDL 基线,目录保留 .gitkeep) |
|
||||
| `etl_feiqiu/README.md` | ETL 库文档:六层 Schema 说明、表清单 |
|
||||
| `etl_feiqiu/migrations/` | ETL 库迁移脚本(日期前缀命名) |
|
||||
| `fdw/` | FDW(Foreign Data Wrapper)跨库访问配置脚本 |
|
||||
| `etl_feiqiu/migrations/` | ETL 库迁移脚本(已合并入 DDL 基线,目录保留 .gitkeep) |
|
||||
| `fdw/` | FDW(Foreign Data Wrapper)跨库访问配置脚本(4 个,运行时资产) |
|
||||
| `scripts/` | 数据库运维脚本 |
|
||||
| `_archived/` | 已归档的历史数据库文件 |
|
||||
|
||||
@@ -277,6 +289,7 @@ H5 静态原型页面,用于小程序 UI 设计参考。
|
||||
| 迁移记录 | `migrate/` | 仓库迁移总结、配置迁移记录 |
|
||||
| MCP 相关 | `mcp/` | AI 工具集成文档 |
|
||||
| UI 原型 | `h5_ui/` | H5 静态原型页面 |
|
||||
| 小程序前端开发指南 | `miniprogram-dev/` | 页面开发流程、代理手册、规范参考、进度审计、经验教训 |
|
||||
| 运维手册 | `ops/` | 故障排查、日常运维流程 |
|
||||
| 权限矩阵 | `permission_matrix/` | 角色-资源权限映射 |
|
||||
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
# 审计一览表
|
||||
|
||||
> 自动生成于 2026-03-08 03:05:13,请勿手动编辑。
|
||||
> 自动生成于 2026-03-15 10:14:07,请勿手动编辑。
|
||||
|
||||
## 时间线视图
|
||||
|
||||
| 日期 | 项目 | 需求摘要 | 变更类型 | 影响模块 | 风险 | 详情 |
|
||||
|------|------|----------|----------|----------|------|------|
|
||||
| 2026-03-15 | 项目级 | 变更审计记录:DDL 基线统一整理 + BD 手册重组 + 小程序副本清理 | bugfix | 其他 | 低 | [链接](changes/2026-03-15__ddl-baseline-consolidation-bd-manual-reorg.md) |
|
||||
| 2026-03-13 | ETL-feiqiu, 小程序 | 审计记录:board-finance line-height 全量补齐 | bugfix | 其他, 文档 | 低 | [链接](changes/2026-03-13__board-finance-line-height-audit.md) |
|
||||
| 2026-03-13 | 项目级 | 审计记录:board-finance.wxss rpx 换算公式修正 | 功能 | 其他 | 未知 | [链接](changes/2026-03-13__board-finance-rpx-formula-correction.md) |
|
||||
| 2026-03-13 | 项目级 | 变更审计记录:task-list 页面 H5 原型 1:1 重写 | bugfix | 其他 | 未知 | [链接](changes/2026-03-13__task-list-h5-rewrite.md) |
|
||||
| 2026-03-12 | 项目级 | 变更审计记录:board-finance WXSS 视觉校对(四轮) | bugfix | 其他 | 未知 | [链接](changes/2026-03-12__board-finance-overview-wxss-calibration.md) |
|
||||
| 2026-03-12 | 项目级 | 变更审计记录:小程序前端开发文档体系收尾(步骤 1-4) | 文档 | 其他 | 低 | [链接](changes/2026-03-12__miniprogram-dev-docs-finalize.md) |
|
||||
| 2026-03-12 | 项目级 | 变更审计记录:多模块累积变更 — AI 对话系统 + 任务防御 + 小程序 UI 重构 + ETL DWS | bugfix | 其他 | 未知 | [链接](changes/2026-03-12__multi-module-ai-taskdefense-miniprogram-etl.md) |
|
||||
| 2026-03-12 | 项目级 | 变更审计记录:pixel-audit 结构化审计方法论替换像素对比 | 文档 | 其他 | 未知 | [链接](changes/2026-03-12__pixel-audit-structured-methodology.md) |
|
||||
| 2026-03-10 | 项目级 | 变更审计记录:多模块累积变更 — AI 应用骨架 + 任务队列防卡死 + 小程序页面迁移 | bugfix | 其他 | 未知 | [链接](changes/2026-03-10__multi-module-ai-apps-task-defense-miniprogram.md) |
|
||||
| 2026-03-08 | ETL-feiqiu, 后端 | 变更审计记录:P5 AI 集成需求审视 — 7 项歧义修补 + category 枚举对齐 | 文档 | 其他, 文档, 脚本工具 | 未知 | [链接](changes/2026-03-08__p5-ai-spec-review-category-enum-align.md) |
|
||||
| 2026-03-07 | 项目级 | 变更审计记录:TASK 3 项目标签计算逻辑 — 文档与配置同步 | 文档 | 其他 | 低 | [链接](changes/2026-03-07__task3-project-tag-docs-sync.md) |
|
||||
| 2026-03-06 | 项目级 | 变更审计记录:修复 RecordingAPIClient 缺少 post 方法 | bugfix | 其他 | 极低 | [链接](changes/2026-03-06__fix-api-client-post-method.md) |
|
||||
@@ -60,6 +69,7 @@
|
||||
|
||||
| 日期 | 需求摘要 | 变更类型 | 影响模块 | 风险 | 详情 |
|
||||
|------|----------|----------|----------|------|------|
|
||||
| 2026-03-13 | 审计记录:board-finance line-height 全量补齐 | bugfix | 其他, 文档 | 低 | [链接](changes/2026-03-13__board-finance-line-height-audit.md) |
|
||||
| 2026-03-08 | 变更审计记录:P5 AI 集成需求审视 — 7 项歧义修补 + category 枚举对齐 | 文档 | 其他, 文档, 脚本工具 | 未知 | [链接](changes/2026-03-08__p5-ai-spec-review-category-enum-align.md) |
|
||||
| 2026-03-02 | 变更审计:合并 ETL Hook 为统一分析入口 | 文档 | 其他, 脚本工具 | 未知 | [链接](changes/2026-03-02__etl-unified-analysis-hook-merge.md) |
|
||||
| 2026-02-28 | 变更审计记录:多模块累积变更(营业日/核心业务/认证/ETL DWS 重构/参考文档合并) | 重构 | 其他 | 未知 | [链接](changes/2026-02-28__multi-module-accumulated-changes.md) |
|
||||
@@ -104,6 +114,12 @@
|
||||
|------|----------|----------|----------|------|------|
|
||||
| 2026-02-28 | 变更审计记录:多模块累积变更(营业日/核心业务/认证/ETL DWS 重构/参考文档合并) | 重构 | 其他 | 未知 | [链接](changes/2026-02-28__multi-module-accumulated-changes.md) |
|
||||
|
||||
### 小程序
|
||||
|
||||
| 日期 | 需求摘要 | 变更类型 | 影响模块 | 风险 | 详情 |
|
||||
|------|----------|----------|----------|------|------|
|
||||
| 2026-03-13 | 审计记录:board-finance line-height 全量补齐 | bugfix | 其他, 文档 | 低 | [链接](changes/2026-03-13__board-finance-line-height-audit.md) |
|
||||
|
||||
### 桌面GUI
|
||||
|
||||
| 日期 | 需求摘要 | 变更类型 | 影响模块 | 风险 | 详情 |
|
||||
@@ -126,6 +142,14 @@
|
||||
|
||||
| 日期 | 需求摘要 | 变更类型 | 影响模块 | 风险 | 详情 |
|
||||
|------|----------|----------|----------|------|------|
|
||||
| 2026-03-15 | 变更审计记录:DDL 基线统一整理 + BD 手册重组 + 小程序副本清理 | bugfix | 其他 | 低 | [链接](changes/2026-03-15__ddl-baseline-consolidation-bd-manual-reorg.md) |
|
||||
| 2026-03-13 | 审计记录:board-finance.wxss rpx 换算公式修正 | 功能 | 其他 | 未知 | [链接](changes/2026-03-13__board-finance-rpx-formula-correction.md) |
|
||||
| 2026-03-13 | 变更审计记录:task-list 页面 H5 原型 1:1 重写 | bugfix | 其他 | 未知 | [链接](changes/2026-03-13__task-list-h5-rewrite.md) |
|
||||
| 2026-03-12 | 变更审计记录:board-finance WXSS 视觉校对(四轮) | bugfix | 其他 | 未知 | [链接](changes/2026-03-12__board-finance-overview-wxss-calibration.md) |
|
||||
| 2026-03-12 | 变更审计记录:小程序前端开发文档体系收尾(步骤 1-4) | 文档 | 其他 | 低 | [链接](changes/2026-03-12__miniprogram-dev-docs-finalize.md) |
|
||||
| 2026-03-12 | 变更审计记录:多模块累积变更 — AI 对话系统 + 任务防御 + 小程序 UI 重构 + ETL DWS | bugfix | 其他 | 未知 | [链接](changes/2026-03-12__multi-module-ai-taskdefense-miniprogram-etl.md) |
|
||||
| 2026-03-12 | 变更审计记录:pixel-audit 结构化审计方法论替换像素对比 | 文档 | 其他 | 未知 | [链接](changes/2026-03-12__pixel-audit-structured-methodology.md) |
|
||||
| 2026-03-10 | 变更审计记录:多模块累积变更 — AI 应用骨架 + 任务队列防卡死 + 小程序页面迁移 | bugfix | 其他 | 未知 | [链接](changes/2026-03-10__multi-module-ai-apps-task-defense-miniprogram.md) |
|
||||
| 2026-03-07 | 变更审计记录:TASK 3 项目标签计算逻辑 — 文档与配置同步 | 文档 | 其他 | 低 | [链接](changes/2026-03-07__task3-project-tag-docs-sync.md) |
|
||||
| 2026-03-06 | 变更审计记录:修复 RecordingAPIClient 缺少 post 方法 | bugfix | 其他 | 极低 | [链接](changes/2026-03-06__fix-api-client-post-method.md) |
|
||||
| 2026-03-06 | 变更审计记录:修复 DatabaseOperations 缺少 _dsn 属性导致 DWD 并行装载全部失败 | bugfix | 其他 | 极低 | [链接](changes/2026-03-06__fix-db-operations-dsn-proxy.md) |
|
||||
@@ -191,6 +215,15 @@
|
||||
|
||||
| 日期 | 需求摘要 | 变更类型 | 风险 | 详情 |
|
||||
|------|----------|----------|------|------|
|
||||
| 2026-03-15 | 变更审计记录:DDL 基线统一整理 + BD 手册重组 + 小程序副本清理 | bugfix | 低 | [链接](changes/2026-03-15__ddl-baseline-consolidation-bd-manual-reorg.md) |
|
||||
| 2026-03-13 | 审计记录:board-finance line-height 全量补齐 | bugfix | 低 | [链接](changes/2026-03-13__board-finance-line-height-audit.md) |
|
||||
| 2026-03-13 | 审计记录:board-finance.wxss rpx 换算公式修正 | 功能 | 未知 | [链接](changes/2026-03-13__board-finance-rpx-formula-correction.md) |
|
||||
| 2026-03-13 | 变更审计记录:task-list 页面 H5 原型 1:1 重写 | bugfix | 未知 | [链接](changes/2026-03-13__task-list-h5-rewrite.md) |
|
||||
| 2026-03-12 | 变更审计记录:board-finance WXSS 视觉校对(四轮) | bugfix | 未知 | [链接](changes/2026-03-12__board-finance-overview-wxss-calibration.md) |
|
||||
| 2026-03-12 | 变更审计记录:小程序前端开发文档体系收尾(步骤 1-4) | 文档 | 低 | [链接](changes/2026-03-12__miniprogram-dev-docs-finalize.md) |
|
||||
| 2026-03-12 | 变更审计记录:多模块累积变更 — AI 对话系统 + 任务防御 + 小程序 UI 重构 + ETL DWS | bugfix | 未知 | [链接](changes/2026-03-12__multi-module-ai-taskdefense-miniprogram-etl.md) |
|
||||
| 2026-03-12 | 变更审计记录:pixel-audit 结构化审计方法论替换像素对比 | 文档 | 未知 | [链接](changes/2026-03-12__pixel-audit-structured-methodology.md) |
|
||||
| 2026-03-10 | 变更审计记录:多模块累积变更 — AI 应用骨架 + 任务队列防卡死 + 小程序页面迁移 | bugfix | 未知 | [链接](changes/2026-03-10__multi-module-ai-apps-task-defense-miniprogram.md) |
|
||||
| 2026-03-08 | 变更审计记录:P5 AI 集成需求审视 — 7 项歧义修补 + category 枚举对齐 | 文档 | 未知 | [链接](changes/2026-03-08__p5-ai-spec-review-category-enum-align.md) |
|
||||
| 2026-03-07 | 变更审计记录:TASK 3 项目标签计算逻辑 — 文档与配置同步 | 文档 | 低 | [链接](changes/2026-03-07__task3-project-tag-docs-sync.md) |
|
||||
| 2026-03-06 | 变更审计记录:修复 RecordingAPIClient 缺少 post 方法 | bugfix | 极低 | [链接](changes/2026-03-06__fix-api-client-post-method.md) |
|
||||
@@ -239,6 +272,7 @@
|
||||
|
||||
| 日期 | 需求摘要 | 变更类型 | 风险 | 详情 |
|
||||
|------|----------|----------|------|------|
|
||||
| 2026-03-13 | 审计记录:board-finance line-height 全量补齐 | bugfix | 低 | [链接](changes/2026-03-13__board-finance-line-height-audit.md) |
|
||||
| 2026-03-08 | 变更审计记录:P5 AI 集成需求审视 — 7 项歧义修补 + category 枚举对齐 | 文档 | 未知 | [链接](changes/2026-03-08__p5-ai-spec-review-category-enum-align.md) |
|
||||
| 2026-02-15 | 变更审计记录(Change Audit Record) | 文档 | 极低 | [链接](changes/2026-02-15__audit-consolidation-doc-reorg.md) |
|
||||
| 2026-02-15 | 审计记录:docs/bd_manual + docs/dictionary → docs/database 合并 | 清理 | 极低 | [链接](changes/2026-02-15__docs-database-merge.md) |
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
# BD_Manual:assistant_accounts_master(助教账号档案)
|
||||
|
||||
> ODS 表:`ods.assistant_accounts_master`
|
||||
> DWD 表:`dwd.dim_assistant`(主表)、`dwd.dim_assistant_ex`(扩展表)
|
||||
> API 接口:助教账号列表
|
||||
> JSON 路径:`assistant_accounts_master.json → data.assistantInfos`
|
||||
> 装载方式:SCD2 维度合并(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dim_assistant(主表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `assistant_id` | BIGINT | `id` | FACT_MAPPINGS | 助教唯一标识(PK 之一) | 飞球系统雪花 ID,如 `2947562271297029` |
|
||||
| `user_id` | BIGINT | `user_id` | FACT_MAPPINGS | 关联的系统用户 ID,0 表示未绑定用户账号 | `0` 或飞球用户 ID |
|
||||
| `assistant_no` | TEXT | `assistant_no` | 自动映射 | 助教编号(门店内序号),用于排班和展示 | 如 `31`、`1` |
|
||||
| `real_name` | TEXT | `real_name` | 自动映射 | 助教真实姓名 | 如 `张静然` |
|
||||
| `nickname` | TEXT | `nickname` | 自动映射 | 助教昵称,用于小程序端展示 | 如 `小然` |
|
||||
| `mobile` | TEXT | `mobile` | 自动映射 | 助教手机号 | 11 位手机号 |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 所属租户 ID | 飞球租户 ID |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 所属门店 ID | 飞球门店 ID |
|
||||
| `team_id` | BIGINT | `team_id` | 自动映射 | 所属团队 ID,0 表示未分组 | `0` 或团队 ID |
|
||||
| `team_name` | TEXT | `team_name` | 自动映射 | 团队名称 | 如 `1组`,NULL 表示未分组 |
|
||||
| `level` | INTEGER | `level` | 自动映射 | 助教等级(技能等级编号) | 如 `20`(对应"高级"等) |
|
||||
| `entry_time` | TIMESTAMPTZ | `entry_time` | 自动映射 | 入职时间 | ISO 时间戳 |
|
||||
| `resign_time` | TIMESTAMPTZ | `resign_time` | 自动映射 | 离职时间,NULL 表示在职 | ISO 时间戳或 NULL |
|
||||
| `leave_status` | INTEGER | `leave_status` | 自动映射 | 在职状态:0=在职,1=已离职 | `0` / `1` |
|
||||
| `assistant_status` | INTEGER | `assistant_status` | 自动映射 | 助教状态:1=正常,2=停用 | `1` / `2` |
|
||||
| `scd2_start_time` | TIMESTAMPTZ | — | DWD 元数据 | SCD2 版本生效起点 | — |
|
||||
| `scd2_end_time` | TIMESTAMPTZ | — | DWD 元数据 | SCD2 版本失效时间,`9999-12-31` 表示当前版本 | — |
|
||||
| `scd2_is_current` | INT | — | DWD 元数据 | 当前版本标记:1=当前,0=历史 | `0` / `1` |
|
||||
| `scd2_version` | INT | — | DWD 元数据 | SCD2 版本号(自增) | — |
|
||||
|
||||
---
|
||||
|
||||
## 2. dim_assistant_ex(扩展表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `assistant_id` | BIGINT | `id` | FACT_MAPPINGS | 助教唯一标识(PK 之一) | 同主表 |
|
||||
| `gender` | INTEGER | `gender` | 自动映射 | 性别:0=未设置 | `0` |
|
||||
| `birth_date` | TIMESTAMPTZ | `birth_date` | 自动映射 | 出生日期 | `0001-01-01` 表示未设置 |
|
||||
| `avatar` | TEXT | `avatar` | 自动映射 | 头像 URL | HTTPS 链接 |
|
||||
| `introduce` | TEXT | `introduce` | FACT_MAPPINGS | 个人简介文本 | 自由文本或 NULL |
|
||||
| `video_introduction_url` | TEXT | `video_introduction_url` | 自动映射 | 视频介绍 URL | HTTPS 链接或 NULL |
|
||||
| `height` | NUMERIC(5,2) | `height` | 自动映射 | 身高(cm),0 表示未填写 | `0.00` 或实际身高 |
|
||||
| `weight` | NUMERIC(5,2) | `weight` | 自动映射 | 体重(kg),0 表示未填写 | `0.00` 或实际体重 |
|
||||
| `shop_name` | TEXT | `shop_name` | 自动映射 | 所属门店名称快照 | 如 `朗朗桌球` |
|
||||
| `group_id` | BIGINT | `group_id` | 自动映射 | 分组 ID,0 表示未分组 | `0` 或分组 ID |
|
||||
| `group_name` | TEXT | `group_name` | FACT_MAPPINGS | 分组名称 | NULL 或分组名 |
|
||||
| `person_org_id` | BIGINT | `person_org_id` | 自动映射 | 人事组织 ID | 飞球组织 ID |
|
||||
| `staff_id` | BIGINT | `staff_id` | 自动映射 | 员工 ID,0 表示未绑定员工档案 | `0` 或员工 ID |
|
||||
| `staff_profile_id` | BIGINT | `staff_profile_id` | 自动映射 | 员工档案 ID,0 表示无档案 | `0` 或档案 ID |
|
||||
| `assistant_grade` | DOUBLE PRECISION | `assistant_grade` | 自动映射 | 助教评分(客户评价均分) | `0.0` ~ `5.0` |
|
||||
| `sum_grade` | DOUBLE PRECISION | `sum_grade` | 自动映射 | 累计评分总和 | `0.0` 或累计值 |
|
||||
| `get_grade_times` | INTEGER | `get_grade_times` | 自动映射 | 被评价次数 | `0` 或正整数 |
|
||||
| `charge_way` | INTEGER | `charge_way` | 自动映射 | 计费方式:2=按时长计费(当前门店全部为 2) | `2` |
|
||||
| `allow_cx` | INTEGER | `allow_cx` | 自动映射 | 是否允许促销服务:1=允许(当前全部为 1) | `1` |
|
||||
| `is_guaranteed` | INTEGER | `is_guaranteed` | 自动映射 | 是否保底:0=不保底,1=保底 | `0` / `1` |
|
||||
| `salary_grant_enabled` | INTEGER | `salary_grant_enabled` | 自动映射 | 工资发放开关:2=启用 | `2` |
|
||||
| `entry_type` | INTEGER | `entry_type` | 自动映射 | 入职类型:1=正常入职 | `1` |
|
||||
| `entry_sign_status` | INTEGER | `entry_sign_status` | 自动映射 | 入职签到状态:0=未签到 | `0` |
|
||||
| `resign_sign_status` | INTEGER | `resign_sign_status` | 自动映射 | 离职签到状态:0=未签到 | `0` |
|
||||
| `work_status` | INTEGER | `work_status` | 自动映射 | 工作状态:1=在岗,2=离岗 | `1` / `2` |
|
||||
| `show_status` | INTEGER | `show_status` | 自动映射 | 展示状态:1=展示 | `1` |
|
||||
| `show_sort` | INTEGER | `show_sort` | 自动映射 | 展示排序序号 | 正整数 |
|
||||
| `online_status` | INTEGER | `online_status` | 自动映射 | 在线状态:1=在线 | `1` |
|
||||
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 软删除标记:0=正常,1=已删除 | `0` / `1` |
|
||||
| `criticism_status` | INTEGER | `criticism_status` | 自动映射 | 差评处理状态:1=正常 | `1` |
|
||||
| `create_time` | TIMESTAMPTZ | `create_time` | 自动映射 | 助教记录创建时间 | ISO 时间戳 |
|
||||
| `update_time` | TIMESTAMPTZ | `update_time` | 自动映射 | 助教记录最后更新时间 | ISO 时间戳 |
|
||||
| `start_time` | TIMESTAMPTZ | `start_time` | 自动映射 | 合同/排班开始时间 | ISO 时间戳 |
|
||||
| `end_time` | TIMESTAMPTZ | `end_time` | 自动映射 | 合同/排班结束时间 | ISO 时间戳 |
|
||||
| `last_table_id` | BIGINT | `last_table_id` | 自动映射 | 最近服务的台桌 ID,0 表示无 | `0` 或台桌 ID |
|
||||
| `last_table_name` | TEXT | `last_table_name` | 自动映射 | 最近服务的台桌名称 | 如 `TV`、`1号台` |
|
||||
| `last_update_name` | TEXT | `last_update_name` | 自动映射 | 最后操作人姓名(带职位前缀) | 如 `管理员:郑丽珊` |
|
||||
| `order_trade_no` | BIGINT | `order_trade_no` | 自动映射 | 当前关联的订单交易号,0 表示空闲 | `0` 或订单号 |
|
||||
| `ding_talk_synced` | INTEGER | `ding_talk_synced` | 自动映射 | 钉钉同步状态:1=已同步 | `1` |
|
||||
| `site_light_cfg_id` | BIGINT | `site_light_cfg_id` | 自动映射 | 门店灯控配置 ID,0 表示未配置 | `0` 或配置 ID |
|
||||
| `light_equipment_id` | TEXT | `light_equipment_id` | FACT_MAPPINGS | 灯控设备 ID | NULL 或设备编号 |
|
||||
| `light_status` | INTEGER | `light_status` | 自动映射 | 台灯状态:2=已开灯 | `1` / `2` |
|
||||
| `is_team_leader` | INTEGER | `is_team_leader` | 自动映射 | 是否组长:0=否,1=是 | `0` / `1` |
|
||||
| `serial_number` | BIGINT | `serial_number` | 自动映射 | 序列号,0 表示未分配 | `0` 或序列号 |
|
||||
| `system_role_id` | BIGINT | `system_role_id` | FACT_MAPPINGS | 系统角色 ID,标识助教在系统中的角色类型。当前门店全部为 10 | `10` |
|
||||
| `job_num` | TEXT | `job_num` | FACT_MAPPINGS | 工号,助教的内部编号标识。当前门店未启用,全部为 NULL | NULL |
|
||||
| `cx_unit_price` | NUMERIC(18,2) | `cx_unit_price` | FACT_MAPPINGS | 促销单价(元),助教提供促销服务时的计费单价。当前门店未在账号表层面设置,全部为 0.00 | `0.00` |
|
||||
| `pd_unit_price` | NUMERIC(18,2) | `pd_unit_price` | FACT_MAPPINGS | 陪打单价(元),助教提供陪打服务时的计费单价。当前门店未在账号表层面设置,全部为 0.00 | `0.00` |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段(同主表) | — |
|
||||
|
||||
---
|
||||
|
||||
## 3. 跳过字段说明
|
||||
|
||||
| ODS 字段 | 跳过原因 |
|
||||
|---------|---------|
|
||||
| `siteprofile` | JSONB 嵌套列,已由 `dim_site` / `dim_site_ex` 通过 JSONB 提取映射 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dim_assistant"]` / `FACT_MAPPINGS["dwd.dim_assistant_ex"]`
|
||||
- TABLE_MAP:`"dwd.dim_assistant" → "ods.assistant_accounts_master"`
|
||||
- DWS 下游:`dws_assistant_daily_task.py`(助教日业绩汇总)、`dws_salary_task.py`(工资计算)
|
||||
@@ -1,114 +0,0 @@
|
||||
# BD_Manual:assistant_service_records(助教服务流水)
|
||||
|
||||
> ODS 表:`ods.assistant_service_records`
|
||||
> DWD 表:`dwd.dwd_assistant_service_log`(主表)、`dwd.dwd_assistant_service_log_ex`(扩展表)
|
||||
> API 接口:助教服务记录列表
|
||||
> JSON 路径:`assistant_service_records.json → data.orderAssistantLedgers`
|
||||
> 装载方式:事实表增量插入(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dwd_assistant_service_log(主表,33 列)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `assistant_service_id` | BIGINT | `id` | FACT_MAPPINGS | 助教服务记录唯一标识(PK) | 飞球雪花 ID |
|
||||
| `order_trade_no` | BIGINT | `order_trade_no` | 自动映射 | 关联的订单交易号 | 飞球订单号 |
|
||||
| `order_settle_id` | BIGINT | `order_settle_id` | 自动映射 | 关联的结算单 ID | 飞球结算单 ID |
|
||||
| `order_pay_id` | BIGINT | `order_pay_id` | 自动映射 | 关联的支付单 ID | 飞球支付单 ID |
|
||||
| `order_assistant_id` | BIGINT | `order_assistant_id` | 自动映射 | 订单级助教明细 ID,标识本次服务在订单中的唯一记录 | 飞球雪花 ID |
|
||||
| `order_assistant_type` | INTEGER | `order_assistant_type` | 自动映射 | 助教服务类型:1=陪打,2=促销 | `1` / `2` |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID | 飞球租户 ID |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID | 飞球门店 ID |
|
||||
| `site_table_id` | BIGINT | `site_table_id` | 自动映射 | 服务台桌 ID,关联 `dim_table.table_id` | 飞球台桌 ID |
|
||||
| `tenant_member_id` | BIGINT | `tenant_member_id` | 自动映射 | 租户维度会员 ID | 飞球会员 ID 或 0 |
|
||||
| `system_member_id` | BIGINT | `system_member_id` | 自动映射 | 系统维度会员 ID(跨租户唯一) | 飞球会员 ID 或 0 |
|
||||
| `assistant_no` | VARCHAR(64) | `assistantno` | FACT_MAPPINGS | 助教编号(门店内序号) | 如 `31` |
|
||||
| `nickname` | VARCHAR(64) | `nickname` | 自动映射 | 助教昵称 | 如 `小张` |
|
||||
| `site_assistant_id` | BIGINT | `site_assistant_id` | FACT_MAPPINGS | 门店维度助教档案 ID,关联 `dim_assistant.assistant_id`。⚠️ 已于 2026-02-20 修正映射源(原错误映射自 `order_assistant_id`) | 飞球助教 ID |
|
||||
| `user_id` | BIGINT | `user_id` | 自动映射 | 助教用户 ID | 飞球用户 ID |
|
||||
| `assistant_team_id` | BIGINT | `assistant_team_id` | 自动映射 | 助教团队 ID | 飞球团队 ID |
|
||||
| `person_org_id` | BIGINT | `person_org_id` | 自动映射 | 人员组织 ID | 飞球组织 ID |
|
||||
| `assistant_level` | INTEGER | `assistant_level` | 自动映射 | 助教等级编码 | 枚举值 |
|
||||
| `level_name` | VARCHAR(64) | `levelname` | FACT_MAPPINGS | 助教等级名称 | 如 `高级`、`中级` |
|
||||
| `skill_id` | BIGINT | `skill_id` | 自动映射 | 服务技能 ID | 飞球技能 ID |
|
||||
| `skill_name` | VARCHAR(64) | `skillname` | FACT_MAPPINGS | 服务技能名称 | 如 `陪打`、`促销` |
|
||||
| `ledger_unit_price` | NUMERIC(10,2) | `ledger_unit_price` | 自动映射 | 分账单价(元/小时) | 金额值 |
|
||||
| `ledger_amount` | NUMERIC(10,2) | `ledger_amount` | 自动映射 | 分账总金额(元) | 金额值 |
|
||||
| `projected_income` | NUMERIC(10,2) | `projected_income` | 自动映射 | 预计收入(元) | 金额值 |
|
||||
| `coupon_deduct_money` | NUMERIC(10,2) | `coupon_deduct_money` | 自动映射 | 优惠券抵扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `income_seconds` | INTEGER | `income_seconds` | 自动映射 | 计费时长(秒) | 正整数 |
|
||||
| `real_use_seconds` | INTEGER | `real_use_seconds` | 自动映射 | 实际使用时长(秒) | 正整数 |
|
||||
| `add_clock` | INTEGER | `add_clock` | 自动映射 | 加钟次数 | `0` ~ 正整数 |
|
||||
| `create_time` | TIMESTAMPTZ | `create_time` | 自动映射 | 记录创建时间 | ISO 时间戳 |
|
||||
| `start_use_time` | TIMESTAMPTZ | `start_use_time` | 自动映射 | 服务开始时间 | ISO 时间戳 |
|
||||
| `last_use_time` | TIMESTAMPTZ | `last_use_time` | 自动映射 | 最后使用时间(服务结束时间) | ISO 时间戳 |
|
||||
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 是否已删除:0=正常,1=已删除 | `0` / `1` |
|
||||
| `real_service_money` | NUMERIC(18,2) | `real_service_money` | FACT_MAPPINGS | 实际服务金额(元),扣除折扣后的实收 | `0.00` ~ 金额值 |
|
||||
|
||||
---
|
||||
|
||||
## 2. dwd_assistant_service_log_ex(扩展表,33 列)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `assistant_service_id` | BIGINT | `id` | FACT_MAPPINGS | 助教服务记录唯一标识(PK) | 同主表 |
|
||||
| `table_name` | VARCHAR(64) | `tablename` | FACT_MAPPINGS | 台桌名称快照 | 如 `1号台` |
|
||||
| `assistant_name` | VARCHAR(64) | `assistantname` | FACT_MAPPINGS | 助教姓名快照 | 如 `张静然` |
|
||||
| `ledger_name` | VARCHAR(128) | `ledger_name` | 自动映射 | 分账项名称 | 如 `陪打费` |
|
||||
| `ledger_group_name` | VARCHAR(128) | `ledger_group_name` | FACT_MAPPINGS | 分账组名称 | 分账组名或 NULL |
|
||||
| `ledger_count` | INTEGER | `ledger_count` | 自动映射 | 分账数量 | 正整数 |
|
||||
| `member_discount_amount` | NUMERIC(10,2) | `member_discount_amount` | 自动映射 | 会员折扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `manual_discount_amount` | NUMERIC(10,2) | `manual_discount_amount` | 自动映射 | 手动折扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `service_money` | NUMERIC(10,2) | `service_money` | 自动映射 | 服务原价金额(元) | 金额值 |
|
||||
| `returns_clock` | INTEGER | `returns_clock` | 自动映射 | 退钟次数 | `0` ~ 正整数 |
|
||||
| `ledger_start_time` | TIMESTAMPTZ | `ledger_start_time` | 自动映射 | 分账开始时间 | ISO 时间戳 |
|
||||
| `ledger_end_time` | TIMESTAMPTZ | `ledger_end_time` | 自动映射 | 分账结束时间 | ISO 时间戳 |
|
||||
| `ledger_status` | INTEGER | `ledger_status` | 自动映射 | 分账状态 | 枚举值 |
|
||||
| `is_confirm` | INTEGER | `is_confirm` | 自动映射 | 是否已确认:0=未确认,1=已确认 | `0` / `1` |
|
||||
| `is_single_order` | INTEGER | `is_single_order` | 自动映射 | 是否单独订单 | `0` / `1` |
|
||||
| `is_not_responding` | INTEGER | `is_not_responding` | 自动映射 | 是否未响应 | `0` / `1` |
|
||||
| `is_trash` | INTEGER | `is_trash` | 自动映射 | 是否已废除:0=正常,1=已废除 | `0` / `1` |
|
||||
| `trash_applicant_id` | BIGINT | `trash_applicant_id` | 自动映射 | 废除申请人 ID | 员工 ID 或 NULL |
|
||||
| `trash_applicant_name` | VARCHAR(64) | `trash_applicant_name` | FACT_MAPPINGS | 废除申请人姓名 | 姓名或 NULL |
|
||||
| `trash_reason` | VARCHAR(255) | `trash_reason` | FACT_MAPPINGS | 废除原因 | 自由文本或 NULL |
|
||||
| `salesman_user_id` | BIGINT | `salesman_user_id` | 自动映射 | 销售员用户 ID | 用户 ID 或 NULL |
|
||||
| `salesman_name` | VARCHAR(64) | `salesman_name` | FACT_MAPPINGS | 销售员姓名 | 姓名或 NULL |
|
||||
| `salesman_org_id` | BIGINT | `salesman_org_id` | 自动映射 | 销售员组织 ID | 组织 ID 或 NULL |
|
||||
| `skill_grade` | INTEGER | `skill_grade` | 自动映射 | 技能评分 | 评分值 |
|
||||
| `service_grade` | INTEGER | `service_grade` | 自动映射 | 服务评分 | 评分值 |
|
||||
| `composite_grade` | NUMERIC(5,2) | `composite_grade` | 自动映射 | 综合评分 | 如 `4.50` |
|
||||
| `sum_grade` | NUMERIC(10,2) | `sum_grade` | 自动映射 | 累计评分 | 累计值 |
|
||||
| `get_grade_times` | INTEGER | `get_grade_times` | 自动映射 | 获评次数 | 正整数 |
|
||||
| `grade_status` | INTEGER | `grade_status` | 自动映射 | 评分状态 | 枚举值 |
|
||||
| `composite_grade_time` | TIMESTAMPTZ | `composite_grade_time` | 自动映射 | 综合评分时间 | ISO 时间戳 |
|
||||
| `assistant_team_name` | TEXT | `assistantteamname` | FACT_MAPPINGS | 助教团队名称快照 | 如 `1组` |
|
||||
| `operator_id` | BIGINT | `operator_id` | FACT_MAPPINGS | 操作员 ID,录入/结算这条助教服务的员工。0 表示系统自动 | `0` 或员工 ID |
|
||||
| `operator_name` | TEXT | `operator_name` | FACT_MAPPINGS | 操作员姓名(带职位前缀),便于直接阅读 | 如 `收银员:郑丽珊`,NULL 表示系统自动 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 映射修正记录
|
||||
|
||||
| 日期 | 字段 | 修正内容 |
|
||||
|------|------|---------|
|
||||
| 2026-02-20 | `site_assistant_id` | ODS 源从 `order_assistant_id`(订单级 ID)修正为 `site_assistant_id`(助教档案 ID) |
|
||||
| 2026-02-26 | (下游)`table_area_name` | DWS 任务 `_extract_service_records()` 原错误引用 `asl.table_area_name`(本表无此列),改为 JOIN `dwd.dim_table` 取 `site_table_area_name`。详见 `BD_Manual_fix_dws_assistant_daily_table_area.md` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 跳过字段说明
|
||||
|
||||
| ODS 字段 | 跳过原因 |
|
||||
|---------|---------|
|
||||
| `siteprofile` | JSONB 嵌套列,已由 `dim_site` / `dim_site_ex` 通过 JSONB 提取映射 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_assistant_service_log"]` / `FACT_MAPPINGS["dwd.dwd_assistant_service_log_ex"]`
|
||||
- TABLE_MAP:`"dwd.dwd_assistant_service_log" → "ods.assistant_service_records"`
|
||||
- DWS 下游:`dws_assistant_daily_task.py`(助教日业绩汇总)
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__fix_assistant_service_site_assistant_id.sql`(已归档)、`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__add_assistant_service_log_ex_fields.sql`(已归档)
|
||||
@@ -1,88 +0,0 @@
|
||||
# BD_Manual:dim_groupbuy_package_ex 新增团购详情字段
|
||||
|
||||
> 日期:2026-03-05
|
||||
> 涉及库:`etl_feiqiu` / `test_etl_feiqiu`
|
||||
> 迁移脚本:`db/etl_feiqiu/migrations/2026-03-05__add_detail_fields_to_dim_groupbuy_package_ex.sql`
|
||||
> 直接原因:整合团购详情接口(QueryPackageCouponInfo),需在 DWD 扩展表中存储可用台区、助教服务、关联门店等维度信息
|
||||
> Prompt 摘要:etl-coupon-detail spec — 需求 4 验收标准 1
|
||||
|
||||
---
|
||||
|
||||
## 1. 变更说明
|
||||
|
||||
### 变更内容
|
||||
|
||||
在 `dwd.dim_groupbuy_package_ex` 表新增 4 个 JSONB 列,用于存储从团购详情接口提取的维度数据。
|
||||
|
||||
| Schema | 表 | 新增列 | 类型 | 说明 |
|
||||
|--------|-----|--------|------|------|
|
||||
| dwd | dim_groupbuy_package_ex | table_area_ids | JSONB | 可用台区 ID 列表(来自详情接口 tableAreaId) |
|
||||
| dwd | dim_groupbuy_package_ex | table_area_names | JSONB | 可用台区名称列表(来自详情接口 tableAreaNameList) |
|
||||
| dwd | dim_groupbuy_package_ex | assistant_services | JSONB | 助教服务关联(来自详情接口 packageCouponAssistants) |
|
||||
| dwd | dim_groupbuy_package_ex | groupon_site_infos | JSONB | 关联门店信息(来自详情接口 grouponSiteInfos) |
|
||||
|
||||
所有列均为 NULLABLE,使用 `ADD COLUMN IF NOT EXISTS` 确保幂等性。
|
||||
|
||||
### 数据来源
|
||||
|
||||
ODS 层 `ods.group_buy_package_details` 表(由 `ODS_GROUP_PACKAGE` 任务的详情拉取子流程写入),通过 `coupon_id = groupbuy_package_id` 关联后在 DWD 加载时合并。
|
||||
|
||||
---
|
||||
|
||||
## 2. 兼容性影响
|
||||
|
||||
| 组件 | 影响 | 说明 |
|
||||
|------|------|------|
|
||||
| ETL DWD 加载 | 需配合修改 | `dwd_load_task.py` 需新增 LEFT JOIN 逻辑从 ODS 详情表读取并映射到这 4 个字段(Task 4.2/4.3) |
|
||||
| ETL SCD2 | 自动兼容 | 新增 JSONB 字段自动纳入 `_is_row_changed` 变更检测 |
|
||||
| 后端 API | 无影响 | 当前无接口直接查询 dim_groupbuy_package_ex 的详情字段 |
|
||||
| 小程序 | 无影响 | 不直接使用 DWD 层表 |
|
||||
| RLS 视图 | 无影响 | dim_groupbuy_package_ex 无 RLS 视图 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 回滚策略
|
||||
|
||||
```sql
|
||||
ALTER TABLE dwd.dim_groupbuy_package_ex
|
||||
DROP COLUMN IF EXISTS table_area_ids,
|
||||
DROP COLUMN IF EXISTS table_area_names,
|
||||
DROP COLUMN IF EXISTS assistant_services,
|
||||
DROP COLUMN IF EXISTS groupon_site_infos;
|
||||
```
|
||||
|
||||
回滚后需同步撤销 `dwd_load_task.py` 中对应的 LEFT JOIN 和字段映射逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 4. 验证 SQL
|
||||
|
||||
```sql
|
||||
-- 1. 确认 4 个新列存在且类型正确
|
||||
SELECT column_name, data_type, is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'dwd'
|
||||
AND table_name = 'dim_groupbuy_package_ex'
|
||||
AND column_name IN ('table_area_ids', 'table_area_names', 'assistant_services', 'groupon_site_infos')
|
||||
ORDER BY ordinal_position;
|
||||
-- 预期:4 行,data_type 均为 'jsonb',is_nullable 均为 'YES'
|
||||
|
||||
-- 2. 确认列 COMMENT 已写入
|
||||
SELECT a.attname AS column_name, d.description AS comment
|
||||
FROM pg_catalog.pg_attribute a
|
||||
JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
|
||||
JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
|
||||
LEFT JOIN pg_catalog.pg_description d ON d.objoid = c.oid AND d.objsubid = a.attnum
|
||||
WHERE n.nspname = 'dwd'
|
||||
AND c.relname = 'dim_groupbuy_package_ex'
|
||||
AND a.attname IN ('table_area_ids', 'table_area_names', 'assistant_services', 'groupon_site_infos')
|
||||
ORDER BY a.attnum;
|
||||
-- 预期:4 行,每行 comment 非 NULL
|
||||
|
||||
-- 3. 确认表主键和索引未受影响
|
||||
SELECT indexname, indexdef
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = 'dwd'
|
||||
AND tablename = 'dim_groupbuy_package_ex';
|
||||
-- 预期:原有 4 个索引不变(pkey + 3 个辅助索引)
|
||||
```
|
||||
@@ -1,266 +0,0 @@
|
||||
# BD_Manual:dws_assistant_order_contribution(助教订单流水四项统计)
|
||||
|
||||
> DWS 表:`dws.dws_assistant_order_contribution`
|
||||
> DWD 数据源:`dwd.dwd_settlement_head`(结算主表)、`dwd.dwd_table_fee_log`(台费明细)、`dwd.dwd_assistant_service_log`(助教服务记录)
|
||||
> 任务代码:`DWS_ASSISTANT_ORDER_CONTRIBUTION`
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dws/assistant_order_contribution_task.py`
|
||||
> DDL 位置:`docs/database/ddl/etl_feiqiu__dws.sql`
|
||||
> 迁移脚本:`db/etl_feiqiu/migrations/2025-02-24__create_dws_assistant_order_contribution.sql`
|
||||
> RLS 视图:`db/etl_feiqiu/migrations/2025-02-24__create_rls_view_assistant_order_contribution.sql`
|
||||
> FDW 映射:`db/zqyy_app/migrations/2025-02-24__add_fdw_dws_extensions.sql`
|
||||
|
||||
---
|
||||
|
||||
## 1. 表结构
|
||||
|
||||
| 列名 | 类型 | 默认值 | 业务含义 | 取值范围/示例 |
|
||||
|------|------|--------|---------|-------------|
|
||||
| `contribution_id` | BIGINT (SERIAL) | nextval 序列 | 自增主键(PK) | 自增 |
|
||||
| `site_id` | BIGINT NOT NULL | — | 门店 ID | 飞球门店 ID |
|
||||
| `tenant_id` | BIGINT NOT NULL | — | 租户 ID | 飞球租户 ID |
|
||||
| `assistant_id` | BIGINT NOT NULL | — | 助教 ID | 飞球助教 ID |
|
||||
| `assistant_nickname` | VARCHAR(100) | NULL | 助教昵称 | 中文昵称 |
|
||||
| `stat_date` | DATE NOT NULL | — | 统计日期 | `2025-01-15` |
|
||||
| `order_gross_revenue` | NUMERIC(14,2) | 0 | 订单总流水 = 台费 + 酒水食品 + 所有助教服务费 | `0.00` ~ 金额值 |
|
||||
| `order_net_revenue` | NUMERIC(14,2) | 0 | 订单净流水 = 订单总流水 - 所有助教服务分成 | `0.00` ~ 金额值 |
|
||||
| `time_weighted_revenue` | NUMERIC(14,2) | 0 | 时效贡献流水 = 台费按时长分摊 + 个人服务费 + 酒水食品按时长比例 | `0.00` ~ 金额值 |
|
||||
| `time_weighted_net_revenue` | NUMERIC(14,2) | 0 | 时效净贡献 = 时效贡献流水 - 个人服务分成 | `0.00` ~ 金额值 |
|
||||
| `order_count` | INTEGER | 0 | 当日参与订单数 | `0` ~ 正整数 |
|
||||
| `total_service_seconds` | INTEGER | 0 | 当日总服务时长(秒) | `0` ~ 正整数 |
|
||||
| `created_at` | TIMESTAMPTZ | NOW() | 记录创建时间 | ISO 时间戳 |
|
||||
| `updated_at` | TIMESTAMPTZ | NOW() | 记录最后更新时间 | ISO 时间戳 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 主键与索引
|
||||
|
||||
| 名称 | 类型 | 列 | 说明 |
|
||||
|------|------|----|------|
|
||||
| `dws_assistant_order_contribution_pkey` | PRIMARY KEY | `contribution_id` | 物理主键(自增序列) |
|
||||
| `idx_aoc_site_assistant_date` | UNIQUE INDEX | `(site_id, assistant_id, stat_date)` | 业务主键:每个门店每个助教每天唯一一条记录 |
|
||||
| `idx_aoc_stat_date` | INDEX | `(site_id, stat_date)` | 按门店+日期查询,支持日度报表 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据写入策略
|
||||
|
||||
- **delete-before-insert**:每次执行按 `site_id` + 日期窗口全量刷新
|
||||
1. `DELETE FROM dws.dws_assistant_order_contribution WHERE site_id = %s AND stat_date BETWEEN %s AND %s`
|
||||
2. 批量 `INSERT` 新计算结果
|
||||
- 继承 `BaseDwsTask` 默认 load 实现,幂等可重跑
|
||||
|
||||
---
|
||||
|
||||
## 4. 算法概要
|
||||
|
||||
### 4.1 数据来源
|
||||
|
||||
| 来源表 | 筛选条件 | 提取内容 |
|
||||
|--------|---------|---------|
|
||||
| `dwd.dwd_settlement_head` | 日期窗口内,`settle_type IN (1, 3)` | 结算单信息、酒水食品金额 |
|
||||
| `dwd.dwd_table_fee_log` | 关联结算单 | 台桌使用时长、台费金额、区域 |
|
||||
| `dwd.dwd_assistant_service_log` | 关联结算单 | 助教服务时长、服务流水、分成、课程类型 |
|
||||
|
||||
### 4.2 四项统计公式
|
||||
|
||||
**订单总流水(order_gross_revenue)**
|
||||
```
|
||||
order_gross_revenue = total_table_fee + total_goods_amount + SUM(所有助教 ledger_amount)
|
||||
```
|
||||
每个参与助教获得相同值。
|
||||
|
||||
**订单净流水(order_net_revenue)**
|
||||
```
|
||||
order_net_revenue = order_gross_revenue - SUM(所有助教 commission)
|
||||
```
|
||||
每个参与助教获得相同值。
|
||||
|
||||
**时效贡献流水(time_weighted_revenue)**
|
||||
```
|
||||
对于台桌 t:
|
||||
billable_seconds = MAX(SUM(助教服务时长), 台桌使用时长)
|
||||
台费分摊_a = table_fee_t × (service_seconds_a / billable_seconds)
|
||||
|
||||
酒水食品分摊_a = total_goods_amount × (助教 a 总服务时长 / 所有助教总服务时长)
|
||||
|
||||
time_weighted_revenue_a = SUM(各台桌台费分摊_a) + ledger_amount_a + 酒水食品分摊_a
|
||||
```
|
||||
|
||||
**时效净贡献(time_weighted_net_revenue)**
|
||||
```
|
||||
time_weighted_net_revenue_a = time_weighted_revenue_a - commission_a
|
||||
```
|
||||
|
||||
### 4.3 超休/打赏课特殊处理
|
||||
|
||||
当 `course_type = BONUS` 时,四项统计均等于个人服务流水和分成,不参与订单级分摊。
|
||||
|
||||
---
|
||||
|
||||
## 5. 前置依赖
|
||||
|
||||
- 任务依赖:`DWD_LOAD_FROM_ODS`(需先完成 DWD 层数据加载)
|
||||
- 数据源表:`dwd.dwd_settlement_head`、`dwd.dwd_table_fee_log`、`dwd.dwd_assistant_service_log` 必须已有数据
|
||||
|
||||
---
|
||||
|
||||
## 6. 验证 SQL
|
||||
|
||||
### 6.1 检查表是否存在且有数据
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
COUNT(*) AS total_rows,
|
||||
COUNT(DISTINCT site_id) AS site_count,
|
||||
COUNT(DISTINCT assistant_id) AS assistant_count,
|
||||
MIN(stat_date) AS earliest_date,
|
||||
MAX(stat_date) AS latest_date
|
||||
FROM dws.dws_assistant_order_contribution;
|
||||
```
|
||||
|
||||
### 6.2 检查业务主键唯一性(不应有重复)
|
||||
|
||||
```sql
|
||||
SELECT site_id, assistant_id, stat_date, COUNT(*) AS cnt
|
||||
FROM dws.dws_assistant_order_contribution
|
||||
GROUP BY site_id, assistant_id, stat_date
|
||||
HAVING COUNT(*) > 1;
|
||||
-- 预期:无结果返回
|
||||
```
|
||||
|
||||
### 6.3 检查四项统计数值合理性(非负)
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE order_gross_revenue < 0) AS neg_gross,
|
||||
COUNT(*) FILTER (WHERE order_net_revenue < 0) AS neg_net,
|
||||
COUNT(*) FILTER (WHERE time_weighted_revenue < 0) AS neg_twr,
|
||||
COUNT(*) FILTER (WHERE time_weighted_net_revenue < 0) AS neg_twnr
|
||||
FROM dws.dws_assistant_order_contribution;
|
||||
-- 预期:所有列均为 0
|
||||
```
|
||||
|
||||
### 6.4 按门店查看统计概况
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
site_id,
|
||||
COUNT(*) AS record_count,
|
||||
SUM(order_count) AS total_orders,
|
||||
ROUND(AVG(order_gross_revenue), 2) AS avg_gross,
|
||||
ROUND(AVG(order_net_revenue), 2) AS avg_net,
|
||||
ROUND(AVG(time_weighted_revenue), 2) AS avg_twr,
|
||||
ROUND(AVG(time_weighted_net_revenue), 2) AS avg_twnr
|
||||
FROM dws.dws_assistant_order_contribution
|
||||
GROUP BY site_id
|
||||
ORDER BY site_id;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. RLS 视图与 FDW 映射
|
||||
|
||||
### 7.1 RLS 视图(ETL 库 app schema)
|
||||
|
||||
```sql
|
||||
-- 视图名:app.v_dws_assistant_order_contribution
|
||||
CREATE OR REPLACE VIEW app.v_dws_assistant_order_contribution AS
|
||||
SELECT * FROM dws.dws_assistant_order_contribution
|
||||
WHERE site_id = current_setting('app.current_site_id')::bigint;
|
||||
```
|
||||
|
||||
### 7.2 FDW 外部表(业务库 fdw_etl schema)
|
||||
|
||||
```sql
|
||||
-- 外部表名:fdw_etl.v_dws_assistant_order_contribution
|
||||
-- 通过 app schema RLS 视图访问,非直接访问 dws schema
|
||||
CREATE FOREIGN TABLE fdw_etl.v_dws_assistant_order_contribution (...)
|
||||
SERVER etl_server
|
||||
OPTIONS (schema_name 'app', table_name 'v_dws_assistant_order_contribution');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 兼容性说明
|
||||
|
||||
| 影响范围 | 说明 |
|
||||
|---------|------|
|
||||
| ETL 任务 | 新增任务 `DWS_ASSISTANT_ORDER_CONTRIBUTION`,依赖 `DWD_LOAD_FROM_ODS`。不影响现有 DWS 任务 |
|
||||
| 后端 API | 当前无 API 直接读取此表。后续小程序助教看板需新增接口 |
|
||||
| 管理后台 | 当前无前端页面展示。后续可在助教详情页新增流水统计展示 |
|
||||
| 小程序 | 小程序助教端将通过后端 API 读取此表数据展示四项统计 |
|
||||
| 其他 DWS 表 | 独立于现有 `dws_assistant_daily_detail`,不修改任何已有表或任务逻辑 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 回滚策略
|
||||
|
||||
### 9.1 删除数据(保留表结构)
|
||||
|
||||
```sql
|
||||
DELETE FROM dws.dws_assistant_order_contribution;
|
||||
```
|
||||
|
||||
### 9.2 完整回滚(删除表 + 视图 + FDW)
|
||||
|
||||
```sql
|
||||
-- 1. 删除 FDW 外部表(业务库)
|
||||
DROP FOREIGN TABLE IF EXISTS fdw_etl.v_dws_assistant_order_contribution;
|
||||
|
||||
-- 2. 删除 RLS 视图(ETL 库)
|
||||
DROP VIEW IF EXISTS app.v_dws_assistant_order_contribution;
|
||||
|
||||
-- 3. 删除表和索引(ETL 库)
|
||||
DROP INDEX IF EXISTS dws.idx_aoc_stat_date;
|
||||
DROP INDEX IF EXISTS dws.idx_aoc_site_assistant_date;
|
||||
DROP TABLE IF EXISTS dws.dws_assistant_order_contribution;
|
||||
```
|
||||
|
||||
### 9.3 回滚任务注册
|
||||
|
||||
从 `orchestration/task_registry.py` 中移除 `DWS_ASSISTANT_ORDER_CONTRIBUTION` 注册行,并从 `tasks/dws/__init__.py` 中移除 `AssistantOrderContributionTask` 导出。
|
||||
|
||||
---
|
||||
|
||||
## 10. 代码引用
|
||||
|
||||
- 任务类:`tasks/dws/assistant_order_contribution_task.py` → `AssistantOrderContributionTask`
|
||||
- 数据结构:`TableUsage`、`AssistantService`、`OrderData`(同文件)
|
||||
- 继承:`BaseDwsTask`
|
||||
- 任务注册:`orchestration/task_registry.py` → `DWS_ASSISTANT_ORDER_CONTRIBUTION`
|
||||
- 属性测试:`tests/test_dws_contribution_properties.py`
|
||||
- 迁移脚本:`db/etl_feiqiu/migrations/2025-02-24__create_dws_assistant_order_contribution.sql`
|
||||
- RLS 视图:`db/etl_feiqiu/migrations/2025-02-24__create_rls_view_assistant_order_contribution.sql`
|
||||
- FDW 映射:`db/zqyy_app/migrations/2025-02-24__add_fdw_dws_extensions.sql`
|
||||
- 验证脚本:`apps/etl/connectors/feiqiu/scripts/verify_dws_extensions.py`
|
||||
|
||||
---
|
||||
|
||||
## 11. 关联扩展字段说明
|
||||
|
||||
本次 Spec(02-etl-dws-miniapp-extensions)同时扩展了两张已有表的字段,简要说明如下:
|
||||
|
||||
### 11.1 dws_member_consumption_summary 新增字段
|
||||
|
||||
| 列名 | 类型 | 默认值 | 业务含义 |
|
||||
|------|------|--------|---------|
|
||||
| `recharge_count_30d` | INTEGER | 0 | 近 30 天充值次数 |
|
||||
| `recharge_count_60d` | INTEGER | 0 | 近 60 天充值次数 |
|
||||
| `recharge_count_90d` | INTEGER | 0 | 近 90 天充值次数 |
|
||||
| `recharge_amount_30d` | NUMERIC(14,2) | 0 | 近 30 天充值金额 |
|
||||
| `recharge_amount_60d` | NUMERIC(14,2) | 0 | 近 60 天充值金额 |
|
||||
| `recharge_amount_90d` | NUMERIC(14,2) | 0 | 近 90 天充值金额 |
|
||||
| `avg_ticket_amount` | NUMERIC(14,2) | 0 | 次均消费 = total_consume_amount / MAX(total_visit_count, 1) |
|
||||
|
||||
迁移脚本:`db/etl_feiqiu/migrations/2025-02-24__alter_member_consumption_add_recharge_fields.sql`
|
||||
|
||||
### 11.2 dws_assistant_daily_detail 新增字段
|
||||
|
||||
| 列名 | 类型 | 默认值 | 业务含义 |
|
||||
|------|------|--------|---------|
|
||||
| `penalty_minutes` | NUMERIC(10,2) | 0 | 定档折算惩罚分钟数,无惩罚时为 0 |
|
||||
| `penalty_reason` | TEXT | NULL | 惩罚原因描述,无惩罚时为 NULL |
|
||||
| `is_exempt` | BOOLEAN | FALSE | 是否豁免惩罚 |
|
||||
| `per_hour_contribution` | NUMERIC(14,2) | NULL | 单人每小时贡献流水 = 台费每小时单价 / 助教人数 |
|
||||
|
||||
迁移脚本:`db/etl_feiqiu/migrations/2025-02-24__alter_assistant_daily_add_penalty_fields.sql`
|
||||
@@ -1,80 +0,0 @@
|
||||
# BD_Manual:DWS 库存汇总(日/周/月)
|
||||
|
||||
> DWS 表:`dws.dws_goods_stock_daily_summary`、`dws.dws_goods_stock_weekly_summary`、`dws.dws_goods_stock_monthly_summary`
|
||||
> DWD 数据源:`dwd.dwd_goods_stock_summary`
|
||||
> 任务代码:`DWS_GOODS_STOCK_DAILY`、`DWS_GOODS_STOCK_WEEKLY`、`DWS_GOODS_STOCK_MONTHLY`
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dws/goods_stock_daily_task.py`、`goods_stock_weekly_task.py`、`goods_stock_monthly_task.py`
|
||||
> DDL 位置:`docs/database/ddl/etl_feiqiu__dws.sql`
|
||||
> 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__create_dws_goods_stock_summary.sql`(已归档)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表结构(三张表结构相同)
|
||||
|
||||
| DWS 列名 | 类型 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|-------------|
|
||||
| `site_id` | BIGINT | 门店 ID(PK 之一) | 飞球门店 ID |
|
||||
| `tenant_id` | BIGINT | 租户 ID | 飞球租户 ID |
|
||||
| `stat_date` | DATE | 统计日期(PK 之一)。日度=当天日期,周度=ISO 周一日期,月度=月首日期 | 如 `2026-01-15`、`2026-01-13`(周一)、`2026-01-01`(月首) |
|
||||
| `site_goods_id` | BIGINT | 门店商品 ID(PK 之一),关联 `dim_store_goods.site_goods_id` | 飞球商品 ID |
|
||||
| `goods_name` | TEXT | 商品名称 | 如 `百威啤酒` |
|
||||
| `goods_unit` | TEXT | 计量单位 | 如 `瓶`、`包` |
|
||||
| `goods_category_id` | BIGINT | 一级商品分类 ID | 飞球分类 ID |
|
||||
| `goods_category_second_id` | BIGINT | 二级商品分类 ID | 飞球分类 ID |
|
||||
| `category_name` | TEXT | 一级分类名称 | 如 `酒水` |
|
||||
| `range_start_stock` | NUMERIC | 期初库存(统计周期起点的库存量) | 数值 |
|
||||
| `range_end_stock` | NUMERIC | 期末库存(统计周期终点的库存量) | 数值 |
|
||||
| `range_in` | NUMERIC | 入库数量(统计周期内的采购/调拨入库总量) | 数值 |
|
||||
| `range_out` | NUMERIC | 出库数量(统计周期内的调拨出库/报损总量) | 数值 |
|
||||
| `range_sale` | NUMERIC | 销售数量(统计周期内的销售出库总量) | 数值 |
|
||||
| `range_sale_money` | NUMERIC(12,2) | 销售金额(元),统计周期内的销售总金额 | 金额值 |
|
||||
| `range_inventory` | NUMERIC | 盘点调整量(统计周期内的盘盈/盘亏净量) | 正/负数值 |
|
||||
| `current_stock` | NUMERIC | 当前库存(统计周期末的实时库存量) | 数值 |
|
||||
| `stat_period` | TEXT | 汇总粒度标识 | `'daily'` / `'weekly'` / `'monthly'` |
|
||||
| `created_at` | TIMESTAMPTZ | 记录创建时间 | 自动填充 `now()` |
|
||||
| `updated_at` | TIMESTAMPTZ | 记录最后更新时间 | 自动填充 `now()` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 主键
|
||||
|
||||
`(site_id, stat_date, site_goods_id)` — 按门店、日期、商品维度唯一。
|
||||
|
||||
---
|
||||
|
||||
## 3. 粒度说明
|
||||
|
||||
| 表名 | 粒度 | stat_date 规则 | stat_period |
|
||||
|------|------|---------------|-------------|
|
||||
| `dws_goods_stock_daily_summary` | 日 | 当天日期 | `'daily'` |
|
||||
| `dws_goods_stock_weekly_summary` | 周 | ISO 周一日期 | `'weekly'` |
|
||||
| `dws_goods_stock_monthly_summary` | 月 | 月首日期(如 `2026-01-01`) | `'monthly'` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 聚合逻辑
|
||||
|
||||
- extract:从 `dwd.dwd_goods_stock_summary` 按时间范围查询
|
||||
- transform:按粒度对 `fetched_at` 进行分组聚合
|
||||
- `range_start_stock`:取周期内最早记录的 `range_start_stock`
|
||||
- `range_end_stock`:取周期内最晚记录的 `range_end_stock`
|
||||
- `range_in` / `range_out` / `range_sale` / `range_inventory`:SUM 汇总
|
||||
- `range_sale_money`:SUM 汇总
|
||||
- `current_stock`:取周期内最晚记录的 `current_stock`
|
||||
- `goods_name` / `goods_unit` / `category_name`:取最晚记录的值
|
||||
- load:upsert 写入目标表,主键冲突时更新
|
||||
|
||||
---
|
||||
|
||||
## 5. 前置依赖
|
||||
|
||||
- `dwd.dwd_goods_stock_summary` 表必须已创建并有数据
|
||||
- ODS 任务配置 `requires_window=True` 必须已生效并重新采集
|
||||
|
||||
---
|
||||
|
||||
## 6. 代码引用
|
||||
|
||||
- 任务代码:`tasks/dws/goods_stock_daily_task.py`、`goods_stock_weekly_task.py`、`goods_stock_monthly_task.py`
|
||||
- 继承:`BaseDwsTask`(`tasks/dws/base_dws_task.py`)
|
||||
- 任务注册:`DWS_GOODS_STOCK_DAILY`、`DWS_GOODS_STOCK_WEEKLY`、`DWS_GOODS_STOCK_MONTHLY`
|
||||
@@ -1,251 +0,0 @@
|
||||
# BD_Manual:dws_member_spending_power_index(SPI 消费力指数)
|
||||
|
||||
> DWS 表:`dws.dws_member_spending_power_index`
|
||||
> DWD 数据源:`dwd.dwd_settlement_head`(消费订单)、`dwd.dwd_recharge_order`(充值订单)
|
||||
> 配置表:`dws.cfg_index_parameters`(`index_type='SPI'`)
|
||||
> 任务代码:`DWS_SPENDING_POWER_INDEX`
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dws/index/spending_power_index_task.py`
|
||||
> DDL 位置:`docs/database/ddl/etl_feiqiu__dws.sql`
|
||||
> 迁移脚本:`db/etl_feiqiu/migrations/2026-02-23_create_dws_member_spending_power_index.sql`
|
||||
> 种子数据:`db/etl_feiqiu/seeds/seed_index_parameters.sql`(`index_type='SPI'` 部分)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表结构
|
||||
|
||||
| 列名 | 类型 | 默认值 | 业务含义 | 取值范围/示例 |
|
||||
|------|------|--------|---------|-------------|
|
||||
| `spi_id` | BIGINT (SERIAL) | nextval 序列 | 自增主键(PK) | 自增 |
|
||||
| `site_id` | INTEGER NOT NULL | — | 门店 ID | 飞球门店 ID |
|
||||
| `member_id` | BIGINT NOT NULL | — | 会员 ID | 飞球会员 ID |
|
||||
| `spend_30` | NUMERIC(14,2) | 0 | 近 30 天消费总额(元) | `0.00` ~ 金额值 |
|
||||
| `spend_90` | NUMERIC(14,2) | 0 | 近 90 天消费总额(元) | `0.00` ~ 金额值 |
|
||||
| `recharge_90` | NUMERIC(14,2) | 0 | 近 90 天充值总额(元) | `0.00` ~ 金额值 |
|
||||
| `orders_30` | INTEGER | 0 | 近 30 天消费笔数 | `0` ~ 正整数 |
|
||||
| `orders_90` | INTEGER | 0 | 近 90 天消费笔数 | `0` ~ 正整数 |
|
||||
| `visit_days_30` | INTEGER | 0 | 近 30 天消费日数(按天去重) | `0` ~ `30` |
|
||||
| `visit_days_90` | INTEGER | 0 | 近 90 天消费日数(按天去重) | `0` ~ `90` |
|
||||
| `avg_ticket_90` | NUMERIC(14,2) | 0 | 90 天客单价(= spend_90 / max(orders_90, 1)) | `0.00` ~ 金额值 |
|
||||
| `active_weeks_90` | INTEGER | 0 | 近 90 天有消费的自然周数 | `0` ~ `13` |
|
||||
| `daily_spend_ewma_90` | NUMERIC(14,2) | 0 | 日消费 EWMA(指数加权移动平均) | `0.00` ~ 金额值 |
|
||||
| `score_level_raw` | NUMERIC(10,4) | 0 | Level 子分原始分(消费水平) | ≥ 0 |
|
||||
| `score_speed_raw` | NUMERIC(10,4) | 0 | Speed 子分原始分(消费速度) | ≥ 0 |
|
||||
| `score_stability_raw` | NUMERIC(10,4) | 0 | Stability 子分原始分(消费稳定性) | `0.0000` ~ `1.0000` |
|
||||
| `score_level_display` | NUMERIC(5,2) | 0 | Level 子分展示分 | `0.00` ~ `10.00` |
|
||||
| `score_speed_display` | NUMERIC(5,2) | 0 | Speed 子分展示分 | `0.00` ~ `10.00` |
|
||||
| `score_stability_display` | NUMERIC(5,2) | 0 | Stability 子分展示分 | `0.00` ~ `10.00` |
|
||||
| `raw_score` | NUMERIC(10,4) | 0 | SPI 总分原始分(加权合成) | ≥ 0 |
|
||||
| `display_score` | NUMERIC(5,2) | 0 | SPI 总分展示分 | `0.00` ~ `10.00` |
|
||||
| `calc_time` | TIMESTAMPTZ | NOW() | 本次计算时间 | ISO 时间戳 |
|
||||
| `created_at` | TIMESTAMPTZ | NOW() | 记录创建时间 | ISO 时间戳 |
|
||||
| `updated_at` | TIMESTAMPTZ | NOW() | 记录最后更新时间 | ISO 时间戳 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 主键与索引
|
||||
|
||||
| 名称 | 类型 | 列 | 说明 |
|
||||
|------|------|----|------|
|
||||
| `dws_member_spending_power_index_pkey` | PRIMARY KEY | `spi_id` | 物理主键(自增序列) |
|
||||
| `idx_spi_site_member` | UNIQUE INDEX | `(site_id, member_id)` | 业务主键:每个门店每个会员唯一一条记录 |
|
||||
| `idx_spi_display_score` | INDEX | `(site_id, display_score DESC)` | 按门店查询展示分排名,支持 TOP-N 查询 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据写入策略
|
||||
|
||||
- **delete-before-insert**:每次执行按 `site_id` 全量刷新
|
||||
1. `DELETE FROM dws.dws_member_spending_power_index WHERE site_id = %s`
|
||||
2. 批量 `INSERT` 新计算结果
|
||||
- 无数据时跳过(不删除、不插入),返回 `{'status': 'skipped', 'reason': 'no_data'}`
|
||||
|
||||
---
|
||||
|
||||
## 4. 算法概要
|
||||
|
||||
### 4.1 数据来源
|
||||
|
||||
| 来源表 | 筛选条件 | 提取内容 |
|
||||
|--------|---------|---------|
|
||||
| `dwd.dwd_settlement_head` | 近 90 天,`settle_type IN (1, 3)` | 消费金额、笔数、消费日数、周覆盖、日消费序列 |
|
||||
| `dwd.dwd_recharge_order` | 近 90 天,`settle_type = 5` | 充值总额 |
|
||||
|
||||
### 4.2 子分公式
|
||||
|
||||
- **Level**(消费水平,权重 0.60):
|
||||
`L = w_s30 × ln(1 + spend_30/M30) + w_s90 × ln(1 + spend_90/M90) + w_ticket × ln(1 + avg_ticket_90/T0) + w_r90 × ln(1 + recharge_90/R90)`
|
||||
|
||||
- **Speed**(消费速度,权重 0.30):
|
||||
`S = w_abs × V_abs + w_rel × max(0, V_rel) + w_ewma × V_ewma`
|
||||
- `V_abs = ln(1 + spend_30 / (max(visit_days_30, 1) × V0))`
|
||||
- `V_rel = ln((v_30 + ε) / (v_90 + ε))`,仅加速加分
|
||||
- `V_ewma = ln(1 + daily_spend_ewma_90 / E0)`
|
||||
|
||||
- **Stability**(消费稳定性,权重 0.10):
|
||||
`P = active_weeks_90 / 13`,取值 [0, 1]
|
||||
|
||||
### 4.3 总分合成
|
||||
|
||||
`SPI_raw = w_L × L + w_S × S + w_P × P`(默认 0.60 / 0.30 / 0.10)
|
||||
|
||||
### 4.4 展示分映射
|
||||
|
||||
Raw → Winsorize(P5, P95) → 可选压缩(log1p/asinh) → MinMax [0, 10] → 可选 EWMA 平滑
|
||||
|
||||
子分(Level/Speed/Stability)各自独立映射,使用 `SPI_LEVEL` / `SPI_SPEED` / `SPI_STABILITY` 隔离分位历史。
|
||||
|
||||
---
|
||||
|
||||
## 5. 配置参数
|
||||
|
||||
所有参数存储在 `dws.cfg_index_parameters`(`index_type='SPI'`),缺失时回退到代码中 `DEFAULT_PARAMS`。
|
||||
|
||||
| 参数名 | 默认值 | 说明 |
|
||||
|--------|--------|------|
|
||||
| `spend_window_short_days` | 30 | 短窗口天数 |
|
||||
| `spend_window_long_days` | 90 | 长窗口天数 |
|
||||
| `ewma_alpha_daily_spend` | 0.3 | 日消费 EWMA 平滑系数 |
|
||||
| `amount_base_spend_30` | 500.0 | 30 天消费金额压缩基数 |
|
||||
| `amount_base_spend_90` | 1500.0 | 90 天消费金额压缩基数 |
|
||||
| `amount_base_ticket_90` | 200.0 | 客单价压缩基数 |
|
||||
| `amount_base_recharge_90` | 1000.0 | 充值金额压缩基数 |
|
||||
| `amount_base_speed_abs` | 100.0 | 绝对速度压缩基数 |
|
||||
| `amount_base_ewma_90` | 50.0 | EWMA 速度压缩基数 |
|
||||
| `w_level_spend_30` | 0.30 | Level 子分中 spend_30 权重 |
|
||||
| `w_level_spend_90` | 0.35 | Level 子分中 spend_90 权重 |
|
||||
| `w_level_ticket_90` | 0.20 | Level 子分中 avg_ticket_90 权重 |
|
||||
| `w_level_recharge_90` | 0.15 | Level 子分中 recharge_90 权重 |
|
||||
| `w_speed_abs` | 0.50 | Speed 子分中绝对速度权重 |
|
||||
| `w_speed_rel` | 0.30 | Speed 子分中相对速度权重 |
|
||||
| `w_speed_ewma` | 0.20 | Speed 子分中 EWMA 速度权重 |
|
||||
| `weight_level` | 0.60 | 总分中 Level 权重 |
|
||||
| `weight_speed` | 0.30 | 总分中 Speed 权重 |
|
||||
| `weight_stability` | 0.10 | 总分中 Stability 权重 |
|
||||
| `stability_window_days` | 90 | 稳定性计算窗口 |
|
||||
| `use_stability` | 1 | 是否启用稳定性子分(0=禁用) |
|
||||
| `percentile_lower` | 5 | Winsorize 下分位 |
|
||||
| `percentile_upper` | 95 | Winsorize 上分位 |
|
||||
| `compression_mode` | 1 | 压缩模式:0=无,1=log1p,2=asinh |
|
||||
| `use_smoothing` | 1 | 是否启用 EWMA 分位平滑 |
|
||||
| `ewma_alpha` | 0.2 | 分位平滑 EWMA 系数 |
|
||||
| `speed_epsilon` | 1e-6 | 速度计算防除零小量 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 前置依赖
|
||||
|
||||
- 任务依赖:`DWS_MEMBER_CONSUMPTION`(需先完成会员消费汇总)
|
||||
- 数据源表:`dwd.dwd_settlement_head`、`dwd.dwd_recharge_order` 必须已有数据
|
||||
- 配置表:`dws.cfg_index_parameters` 中 `index_type='SPI'` 种子数据已插入(缺失时使用默认值)
|
||||
- 分位历史表:`dws.dws_index_percentile_history`(首次执行时无历史,不平滑)
|
||||
|
||||
---
|
||||
|
||||
## 7. 验证 SQL
|
||||
|
||||
### 7.1 检查表是否存在且有数据
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
COUNT(*) AS total_rows,
|
||||
COUNT(DISTINCT site_id) AS site_count,
|
||||
MIN(calc_time) AS earliest_calc,
|
||||
MAX(calc_time) AS latest_calc
|
||||
FROM dws.dws_member_spending_power_index;
|
||||
```
|
||||
|
||||
### 7.2 检查展示分范围是否合规(应全部在 [0, 10])
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE display_score < 0 OR display_score > 10) AS spi_out_of_range,
|
||||
COUNT(*) FILTER (WHERE score_level_display < 0 OR score_level_display > 10) AS level_out_of_range,
|
||||
COUNT(*) FILTER (WHERE score_speed_display < 0 OR score_speed_display > 10) AS speed_out_of_range,
|
||||
COUNT(*) FILTER (WHERE score_stability_display < 0 OR score_stability_display > 10) AS stability_out_of_range
|
||||
FROM dws.dws_member_spending_power_index;
|
||||
-- 预期:所有列均为 0
|
||||
```
|
||||
|
||||
### 7.3 检查业务主键唯一性(不应有重复)
|
||||
|
||||
```sql
|
||||
SELECT site_id, member_id, COUNT(*) AS cnt
|
||||
FROM dws.dws_member_spending_power_index
|
||||
GROUP BY site_id, member_id
|
||||
HAVING COUNT(*) > 1;
|
||||
-- 预期:无结果返回
|
||||
```
|
||||
|
||||
### 7.4 按门店查看 SPI 分布概况
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
site_id,
|
||||
COUNT(*) AS member_count,
|
||||
ROUND(AVG(display_score), 2) AS avg_spi,
|
||||
ROUND(MIN(display_score), 2) AS min_spi,
|
||||
ROUND(MAX(display_score), 2) AS max_spi,
|
||||
ROUND(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY display_score), 2) AS median_spi
|
||||
FROM dws.dws_member_spending_power_index
|
||||
GROUP BY site_id
|
||||
ORDER BY site_id;
|
||||
```
|
||||
|
||||
### 7.5 检查 Stability 子分原始分范围(应在 [0, 1])
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) AS out_of_range
|
||||
FROM dws.dws_member_spending_power_index
|
||||
WHERE score_stability_raw < 0 OR score_stability_raw > 1;
|
||||
-- 预期:0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 兼容性说明
|
||||
|
||||
| 影响范围 | 说明 |
|
||||
|---------|------|
|
||||
| ETL 任务 | 新增任务 `DWS_SPENDING_POWER_INDEX`,依赖 `DWS_MEMBER_CONSUMPTION`。不影响现有 WBI/NCI/RS/OS/MS/ML 指数任务 |
|
||||
| 后端 API | 当前无 API 直接读取此表。后续如需暴露 SPI 数据,需新增接口 |
|
||||
| 管理后台 | 当前无前端页面展示 SPI。后续可在会员详情页新增 SPI 展示 |
|
||||
| 小程序 | 无影响 |
|
||||
| 其他指数 | SPI 独立于现有指数体系,不修改任何已有表或任务逻辑 |
|
||||
| 分位历史 | SPI 会向 `dws.dws_index_percentile_history` 写入 `index_type='SPI'`/`SPI_LEVEL`/`SPI_SPEED`/`SPI_STABILITY` 的分位记录 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 回滚策略
|
||||
|
||||
### 9.1 删除数据(保留表结构)
|
||||
|
||||
```sql
|
||||
DELETE FROM dws.dws_member_spending_power_index;
|
||||
DELETE FROM dws.dws_index_percentile_history WHERE index_type LIKE 'SPI%';
|
||||
DELETE FROM dws.cfg_index_parameters WHERE index_type = 'SPI';
|
||||
```
|
||||
|
||||
### 9.2 完整回滚(删除表)
|
||||
|
||||
```sql
|
||||
DROP INDEX IF EXISTS dws.idx_spi_display_score;
|
||||
DROP INDEX IF EXISTS dws.idx_spi_site_member;
|
||||
DROP TABLE IF EXISTS dws.dws_member_spending_power_index;
|
||||
DROP SEQUENCE IF EXISTS dws.dws_member_spending_power_index_spi_id_seq;
|
||||
```
|
||||
|
||||
### 9.3 回滚任务注册
|
||||
|
||||
从 `orchestration/task_registry.py` 中移除 `DWS_SPENDING_POWER_INDEX` 注册行,并从 `tasks/dws/index/__init__.py` 和 `tasks/dws/__init__.py` 中移除 `SpendingPowerIndexTask` 导出。
|
||||
|
||||
---
|
||||
|
||||
## 10. 代码引用
|
||||
|
||||
- 任务类:`tasks/dws/index/spending_power_index_task.py` → `SpendingPowerIndexTask`
|
||||
- 继承:`BaseIndexTask`(`tasks/dws/index/base_index_task.py`)
|
||||
- 任务注册:`orchestration/task_registry.py` → `DWS_SPENDING_POWER_INDEX`
|
||||
- 属性测试:`tests/test_spi_properties.py`
|
||||
- 单元测试:`apps/etl/connectors/feiqiu/tests/unit/test_spi_task.py`
|
||||
- 迁移脚本:`db/etl_feiqiu/migrations/2026-02-23_create_dws_member_spending_power_index.sql`
|
||||
- 种子数据:`db/etl_feiqiu/seeds/seed_index_parameters.sql`
|
||||
@@ -1,62 +0,0 @@
|
||||
# BD_Manual:goods_stock_movements(库存变动流水)
|
||||
|
||||
> ODS 表:`ods.goods_stock_movements`
|
||||
> DWD 表:`dwd.dwd_goods_stock_movement`(事实表,无 ex 扩展表)
|
||||
> API 接口:库存变动记录列表
|
||||
> JSON 路径:`goods_stock_movements.json → data.goodsStockList`
|
||||
> 装载方式:事实表按 `create_time` 增量加载(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dwd_goods_stock_movement
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `site_goods_stock_id` | BIGINT | `sitegoodsstockid`(ODS 驼峰 → PG 小写) | FACT_MAPPINGS (cast bigint) | 库存变动记录唯一标识(PK) | 飞球雪花 ID |
|
||||
| `tenant_id` | BIGINT | `tenantid` | FACT_MAPPINGS (cast bigint) | 租户 ID | 飞球租户 ID |
|
||||
| `site_id` | BIGINT | `siteid` | FACT_MAPPINGS (cast bigint) | 门店 ID | 飞球门店 ID |
|
||||
| `site_goods_id` | BIGINT | `sitegoodsid` | FACT_MAPPINGS (cast bigint) | 门店商品 ID,关联 `dim_store_goods.site_goods_id` | 飞球商品 ID |
|
||||
| `goods_name` | TEXT | `goodsname` | FACT_MAPPINGS | 商品名称 | 如 `百威啤酒` |
|
||||
| `goods_category_id` | BIGINT | `goodscategoryid` | FACT_MAPPINGS (cast bigint) | 一级商品分类 ID | 飞球分类 ID |
|
||||
| `goods_second_category_id` | BIGINT | `goodssecondcategoryid` | FACT_MAPPINGS (cast bigint) | 二级商品分类 ID | 飞球分类 ID |
|
||||
| `unit` | TEXT | `unit` | FACT_MAPPINGS | 计量单位 | 如 `瓶`、`包`、`张` |
|
||||
| `price` | NUMERIC(18,4) | `price` | FACT_MAPPINGS (cast numeric) | 商品单价(元) | 金额值 |
|
||||
| `stock_type` | INTEGER | `stocktype` | FACT_MAPPINGS (cast integer) | 库存变动类型枚举(详见下方枚举表) | `1`/`2`/`4`/`7`/`8`/`9` |
|
||||
| `change_num` | NUMERIC(18,4) | `changenum` | FACT_MAPPINGS (cast numeric) | 变动数量(正数为增加,负数为减少) | 正/负数值 |
|
||||
| `start_num` | NUMERIC(18,4) | `startnum` | FACT_MAPPINGS (cast numeric) | 变动前库存量 | `0.0000` ~ 正数 |
|
||||
| `end_num` | NUMERIC(18,4) | `endnum` | FACT_MAPPINGS (cast numeric) | 变动后库存量 | `0.0000` ~ 正数 |
|
||||
| `change_num_a` | NUMERIC(18,4) | `changenuma` | FACT_MAPPINGS (cast numeric) | 辅助单位变动量(用于双单位商品,如"箱→瓶"换算) | 数值或 0 |
|
||||
| `start_num_a` | NUMERIC(18,4) | `startnuma` | FACT_MAPPINGS (cast numeric) | 辅助单位变动前库存 | 数值或 0 |
|
||||
| `end_num_a` | NUMERIC(18,4) | `endnuma` | FACT_MAPPINGS (cast numeric) | 辅助单位变动后库存 | 数值或 0 |
|
||||
| `remark` | TEXT | `remark` | FACT_MAPPINGS | 备注说明 | 如 `结账退货`、`采购退货`、`系统自动领用`,或 NULL |
|
||||
| `operator_name` | TEXT | `operatorname` | FACT_MAPPINGS | 操作人姓名 | 姓名或 NULL |
|
||||
| `create_time` | TIMESTAMPTZ | `createtime` | FACT_MAPPINGS (cast timestamptz) | 变动发生时间 | ISO 时间戳 |
|
||||
| `fetched_at` | TIMESTAMPTZ | `fetched_at` | 自动映射 | ETL 采集时间戳 | ISO 时间戳 |
|
||||
|
||||
---
|
||||
|
||||
## 2. stock_type 枚举值详解
|
||||
|
||||
| stock_type | 含义 | 典型 remark | 数据量 |
|
||||
|-----------|------|------------|--------|
|
||||
| 1 | 销售出库 | NULL(系统自动扣减) | 29,573 条 |
|
||||
| 2 | 采购入库 | NULL | 1,033 条 |
|
||||
| 4 | 退货入库 | `结账退货` | 3,300 条 |
|
||||
| 7 | 采购退货(出库) | `采购退货` | 33 条 |
|
||||
| 8 | 领用出库 | `系统自动领用` | 1,033 条 |
|
||||
| 9 | 领用退回(入库) | `系统自动领用退回` | 33 条 |
|
||||
|
||||
---
|
||||
|
||||
## 3. ODS 列名映射说明
|
||||
|
||||
ODS DDL 中列名使用驼峰式(如 `siteGoodsStockId`),PostgreSQL 在无引号时自动小写化。FACT_MAPPINGS 中使用带引号的 ODS 列名以正确引用。部分列(`unit`、`price`、`remark`)在 ODS 中已是小写,无需引号。
|
||||
|
||||
---
|
||||
|
||||
## 4. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_goods_stock_movement"]`
|
||||
- TABLE_MAP:`"dwd.dwd_goods_stock_movement" → "ods.goods_stock_movements"`
|
||||
- DWS 下游:暂无直接 DWS 汇总(库存汇总基于 `dwd_goods_stock_summary`)
|
||||
@@ -1,62 +0,0 @@
|
||||
# BD_Manual:goods_stock_summary(库存汇总)
|
||||
|
||||
> ODS 表:`ods.goods_stock_summary`
|
||||
> DWD 表:`dwd.dwd_goods_stock_summary`(事实表,无 ex 扩展表)
|
||||
> API 接口:库存汇总查询(支持 `startTime`/`endTime` 时间窗口参数)
|
||||
> JSON 路径:`goods_stock_summary.json → data.goodsStockSummaryList`
|
||||
> 装载方式:事实表按时间窗口增量加载(`DwdLoadTask`)
|
||||
> ODS 配置:`requires_window=True`,`time_fields=("startTime", "endTime")`
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dwd_goods_stock_summary
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `site_goods_id` | BIGINT | `sitegoodsid`(ODS DDL 驼峰 → PG 小写) | FACT_MAPPINGS (cast bigint) | 门店商品 ID(PK 之一),关联 `dim_store_goods.site_goods_id` | 飞球商品 ID,如 `3028609051954117` |
|
||||
| `goods_name` | TEXT | `goodsname` | FACT_MAPPINGS | 商品名称 | 如 `酱香爆珠槟榔`、`百威啤酒` |
|
||||
| `goods_unit` | TEXT | `goodsunit` | FACT_MAPPINGS | 计量单位 | 如 `包`、`瓶`、`张`、`罐` |
|
||||
| `goods_category_id` | BIGINT | `goodscategoryid` | FACT_MAPPINGS (cast bigint) | 一级商品分类 ID | 飞球分类 ID |
|
||||
| `goods_category_second_id` | BIGINT | `goodscategorysecondid` | FACT_MAPPINGS (cast bigint) | 二级商品分类 ID | 飞球分类 ID |
|
||||
| `category_name` | TEXT | `categoryname` | FACT_MAPPINGS | 一级分类名称 | 如 `槟榔`、`酒水`、`其他` |
|
||||
| `range_start_stock` | NUMERIC(18,4) | `rangestartstock` | FACT_MAPPINGS (cast numeric) | 期初库存(查询时间窗口起点的库存量) | 如 `100.0000`、`0.0000` |
|
||||
| `range_end_stock` | NUMERIC(18,4) | `rangeendstock` | FACT_MAPPINGS (cast numeric) | 期末库存(查询时间窗口终点的库存量) | 如 `100.0000`、`0.0000` |
|
||||
| `range_in` | NUMERIC(18,4) | `rangein` | FACT_MAPPINGS (cast numeric) | 入库数量(时间窗口内的采购/调拨入库总量) | `0.0000` ~ 正数 |
|
||||
| `range_out` | NUMERIC(18,4) | `rangeout` | FACT_MAPPINGS (cast numeric) | 出库数量(时间窗口内的调拨出库/报损总量) | `0.0000` ~ 正数 |
|
||||
| `range_sale` | NUMERIC(18,4) | `rangesale` | FACT_MAPPINGS (cast numeric) | 销售数量(时间窗口内的销售出库总量) | `0.0000` ~ 正数 |
|
||||
| `range_sale_money` | NUMERIC(18,2) | `rangesalemoney` | FACT_MAPPINGS (cast numeric) | 销售金额(元),时间窗口内的销售总金额 | `0.00` ~ 金额值 |
|
||||
| `range_inventory` | NUMERIC(18,4) | `rangeinventory` | FACT_MAPPINGS (cast numeric) | 盘点调整量(时间窗口内的盘盈/盘亏净量) | 正数(盘盈)或负数(盘亏) |
|
||||
| `current_stock` | NUMERIC(18,4) | `currentstock` | FACT_MAPPINGS (cast numeric) | 当前库存(API 返回时的实时库存量) | `0.0000` ~ 正数 |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID(ETL 注入) | 飞球门店 ID |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID(ETL 注入) | 飞球租户 ID |
|
||||
| `fetched_at` | TIMESTAMPTZ | `fetched_at` | 自动映射 | ETL 采集时间戳(PK 之一),标识本次快照的采集时间 | ISO 时间戳 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 主键说明
|
||||
|
||||
主键为 `(site_goods_id, fetched_at)` 复合键。同一商品在不同采集时间窗口会产生多条记录,每条记录代表该时间窗口内的库存汇总快照。
|
||||
|
||||
---
|
||||
|
||||
## 3. ODS 列名映射说明
|
||||
|
||||
ODS DDL 中列名使用驼峰式(如 `siteGoodsId`),但 PostgreSQL 在无引号时自动小写化为 `sitegoodsid`。FACT_MAPPINGS 中使用带引号的 ODS 列名(如 `"siteGoodsId"`)以正确引用。
|
||||
|
||||
---
|
||||
|
||||
## 4. DWS 下游
|
||||
|
||||
- `dws.dws_goods_stock_daily_summary`:日度库存汇总
|
||||
- `dws.dws_goods_stock_weekly_summary`:周度库存汇总(ISO 周)
|
||||
- `dws.dws_goods_stock_monthly_summary`:月度库存汇总
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_goods_stock_summary"]`
|
||||
- TABLE_MAP:`"dwd.dwd_goods_stock_summary" → "ods.goods_stock_summary"`
|
||||
- ODS 任务配置:`tasks/ods/ods_tasks.py` → `OdsTaskSpec("ODS_GOODS_STOCK_SUMMARY", requires_window=True, time_fields=("startTime", "endTime"))`
|
||||
- DWS 任务:`tasks/dws/goods_stock_daily_task.py`、`goods_stock_weekly_task.py`、`goods_stock_monthly_task.py`
|
||||
@@ -1,102 +0,0 @@
|
||||
# BD Manual: goodsStockWarningInfo(库存预警信息)
|
||||
|
||||
## 变更概述
|
||||
|
||||
- 日期:2026-02-24
|
||||
- 触发:一致性检查报告发现 API 独有嵌套字段 `goodsStockWarningInfo` 未映射到 ODS/DWD
|
||||
- 迁移脚本:`db/etl_feiqiu/migrations/2026-02-24__add_goods_stock_warning_info.sql`
|
||||
|
||||
## 字段来源
|
||||
|
||||
API 端点 `/TenantGoods/GetGoodsInventoryList` 返回的 `store_goods_master` 记录中包含嵌套对象:
|
||||
|
||||
```json
|
||||
{
|
||||
"goodsStockWarningInfo": {
|
||||
"tenant_goods_id": 0, // 冗余,已有同名顶层字段
|
||||
"site_goods_id": 0, // 冗余,对应顶层 id
|
||||
"sales_day": 0.0, // → warning_sales_day
|
||||
"warning_day_max": 0, // → warning_day_max
|
||||
"warning_day_min": 0 // → warning_day_min
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
仅提取 3 个有效字段,冗余 ID 不重复收录。
|
||||
|
||||
## 新增字段
|
||||
|
||||
| 层 | 表 | 列名 | 类型 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| ODS | `ods.store_goods_master` | `warning_sales_day` | NUMERIC(18,2) | 库存预警参考的日均销量 |
|
||||
| ODS | `ods.store_goods_master` | `warning_day_max` | INTEGER | 预警天数上限 |
|
||||
| ODS | `ods.store_goods_master` | `warning_day_min` | INTEGER | 预警天数下限 |
|
||||
| DWD | `dwd.dim_store_goods_ex` | `warning_sales_day` | NUMERIC(18,2) | 同 ODS,直接映射 |
|
||||
| DWD | `dwd.dim_store_goods_ex` | `warning_day_max` | INTEGER | 同 ODS,直接映射 |
|
||||
| DWD | `dwd.dim_store_goods_ex` | `warning_day_min` | INTEGER | 同 ODS,直接映射 |
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
API goodsStockWarningInfo (嵌套 JSON)
|
||||
↓ _merge_record_layers 扁平化(_STOCK_WARNING_FIELD_MAP)
|
||||
ODS ods.store_goods_master (warning_sales_day / warning_day_max / warning_day_min)
|
||||
↓ DWD FACT_MAPPINGS 直接映射
|
||||
DWD dwd.dim_store_goods_ex (同名列)
|
||||
```
|
||||
|
||||
## 代码变更
|
||||
|
||||
| 文件 | 变更 |
|
||||
|---|---|
|
||||
| `apps/etl/connectors/feiqiu/tasks/ods/ods_tasks.py` | `_merge_record_layers` 增加 `goodsStockWarningInfo` 扁平化逻辑 |
|
||||
| `apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py` | `FACT_MAPPINGS["dwd.dim_store_goods_ex"]` 增加 3 个映射 |
|
||||
| `db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/schemas/ods.sql` | baseline 同步 |
|
||||
| `db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/schemas/dwd.sql` | baseline 同步 |
|
||||
|
||||
## 兼容性
|
||||
|
||||
- 后端 API:无影响(后端不直接读取 ODS/DWD 层这些字段)
|
||||
- 小程序:无影响
|
||||
- ETL:ODS schema-aware 插入自动识别新列;DWD 通过 FACT_MAPPINGS 映射
|
||||
- 管理后台:如需展示库存预警信息,可从 `dwd.dim_store_goods_ex` 读取
|
||||
|
||||
## 回滚策略
|
||||
|
||||
```sql
|
||||
ALTER TABLE ods.store_goods_master
|
||||
DROP COLUMN IF EXISTS warning_sales_day,
|
||||
DROP COLUMN IF EXISTS warning_day_max,
|
||||
DROP COLUMN IF EXISTS warning_day_min;
|
||||
ALTER TABLE dwd.dim_store_goods_ex
|
||||
DROP COLUMN IF EXISTS warning_sales_day,
|
||||
DROP COLUMN IF EXISTS warning_day_max,
|
||||
DROP COLUMN IF EXISTS warning_day_min;
|
||||
```
|
||||
|
||||
## 验证 SQL
|
||||
|
||||
```sql
|
||||
-- 1. 确认 ODS 新列存在
|
||||
SELECT column_name, data_type FROM information_schema.columns
|
||||
WHERE table_schema = 'ods' AND table_name = 'store_goods_master'
|
||||
AND column_name IN ('warning_sales_day', 'warning_day_max', 'warning_day_min')
|
||||
ORDER BY column_name;
|
||||
-- 预期:3 行
|
||||
|
||||
-- 2. 确认 DWD 新列存在
|
||||
SELECT column_name, data_type FROM information_schema.columns
|
||||
WHERE table_schema = 'dwd' AND table_name = 'dim_store_goods_ex'
|
||||
AND column_name IN ('warning_sales_day', 'warning_day_max', 'warning_day_min')
|
||||
ORDER BY column_name;
|
||||
-- 预期:3 行
|
||||
|
||||
-- 3. 确认注释已设置
|
||||
SELECT c.column_name, pgd.description
|
||||
FROM information_schema.columns c
|
||||
JOIN pg_catalog.pg_statio_all_tables st ON st.schemaname = c.table_schema AND st.relname = c.table_name
|
||||
JOIN pg_catalog.pg_description pgd ON pgd.objoid = st.relid AND pgd.objsubid = c.ordinal_position
|
||||
WHERE c.table_schema = 'ods' AND c.table_name = 'store_goods_master'
|
||||
AND c.column_name LIKE 'warning_%';
|
||||
-- 预期:3 行,description 非空
|
||||
```
|
||||
@@ -1,92 +0,0 @@
|
||||
# BD_Manual:ods.group_buy_package_details 团购套餐详情表
|
||||
|
||||
> 日期:2026-03-05
|
||||
> 涉及库:`etl_feiqiu` / `test_etl_feiqiu`
|
||||
> DDL 路径:`db/etl_feiqiu/ods/group_buy_package_details.sql`
|
||||
> 直接原因:整合团购详情接口(QueryPackageCouponInfo),新建 ODS 详情表存储每个团购套餐的详情数据
|
||||
> Prompt 摘要:etl-coupon-detail spec — 需求 3 验收标准 1-4
|
||||
|
||||
---
|
||||
|
||||
## 1. 变更说明
|
||||
|
||||
### 变更内容
|
||||
|
||||
新建 `ods.group_buy_package_details` 表,用于存储 `QueryPackageCouponInfo` 详情接口的原始数据。
|
||||
|
||||
| Schema | 表 | 操作 | 说明 |
|
||||
|--------|-----|------|------|
|
||||
| ods | group_buy_package_details | 新建 | 团购套餐详情,主键 `coupon_id`,含 12 个结构化字段 + 6 个 JSONB 数组字段 + 3 个 ETL 元数据字段 |
|
||||
|
||||
### 数据获取方式
|
||||
|
||||
通过 `ODS_GROUP_PACKAGE` 任务的 `detail_endpoint` 二级详情拉取子流程:
|
||||
- 主流程拉取团购列表 → `ods.group_buy_packages`
|
||||
- 子流程遍历每个 `id`,串行调用 `QueryPackageCouponInfo` → 本表
|
||||
- 全量快照模式,UPSERT on `coupon_id`
|
||||
|
||||
### 关键字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `coupon_id` | BIGINT PK | 团购套餐 ID(= group_buy_packages.id) |
|
||||
| `table_area_ids` | JSONB | 可用台区 ID 列表 |
|
||||
| `table_area_names` | JSONB | 可用台区名称列表 |
|
||||
| `assistant_services` | JSONB | 助教服务关联数组 |
|
||||
| `groupon_site_infos` | JSONB | 关联门店信息数组 |
|
||||
| `package_services` | JSONB | 套餐服务数组(待调研) |
|
||||
| `coupon_details_list` | JSONB | 券明细数组(待调研) |
|
||||
| `content_hash` | TEXT | 内容哈希,用于变更检测 |
|
||||
| `payload` | JSONB | 完整原始 JSON 响应 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 兼容性影响
|
||||
|
||||
| 组件 | 影响 | 说明 |
|
||||
|------|------|------|
|
||||
| ETL ODS 层 | 新增表 | `ODS_GROUP_PACKAGE` 任务通过 `detail_endpoint` 配置自动写入 |
|
||||
| ETL DWD 层 | 需配合修改 | `dwd_load_task.py` 需 LEFT JOIN 本表将 4 个 JSONB 字段合并到 `dim_groupbuy_package_ex` |
|
||||
| 后端 API | 无影响 | 当前无接口直接查询本表 |
|
||||
| 小程序 | 无影响 | 不直接使用 ODS 层表 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 回滚策略
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS ods.group_buy_package_details;
|
||||
```
|
||||
|
||||
回滚后需同步移除 `ODS_GROUP_PACKAGE` 任务中的 `detail_endpoint` 相关配置。
|
||||
|
||||
---
|
||||
|
||||
## 4. 验证 SQL
|
||||
|
||||
```sql
|
||||
-- 1. 确认表存在且主键正确
|
||||
SELECT column_name, data_type, is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'ods'
|
||||
AND table_name = 'group_buy_package_details'
|
||||
ORDER BY ordinal_position;
|
||||
-- 预期:22 列,coupon_id 为 BIGINT NOT NULL
|
||||
|
||||
-- 2. 确认主键约束
|
||||
SELECT constraint_name, constraint_type
|
||||
FROM information_schema.table_constraints
|
||||
WHERE table_schema = 'ods'
|
||||
AND table_name = 'group_buy_package_details'
|
||||
AND constraint_type = 'PRIMARY KEY';
|
||||
-- 预期:1 行,pk_group_buy_package_details
|
||||
|
||||
-- 3. 确认 JSONB 列存在
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'ods'
|
||||
AND table_name = 'group_buy_package_details'
|
||||
AND data_type = 'jsonb'
|
||||
ORDER BY ordinal_position;
|
||||
-- 预期:8 行(table_area_ids, table_area_names, assistant_services, groupon_site_infos, package_services, coupon_details_list, payload)
|
||||
```
|
||||
@@ -1,74 +0,0 @@
|
||||
# BD_Manual:member_balance_changes(会员余额变动)
|
||||
|
||||
> ODS 表:`ods.member_balance_changes`
|
||||
> DWD 表:`dwd.dwd_member_balance_change`(主表)、`dwd.dwd_member_balance_change_ex`(扩展表)
|
||||
> API 接口:会员余额变动记录列表
|
||||
> JSON 路径:`member_balance_changes.json → data.memberAccountChanges`
|
||||
> 装载方式:事实表增量插入(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dwd_member_balance_change(主表,22 列)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `balance_change_id` | BIGINT | `id` | FACT_MAPPINGS | 余额变动记录唯一标识(PK) | 飞球雪花 ID |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID | 飞球租户 ID |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID | 飞球门店 ID |
|
||||
| `register_site_id` | BIGINT | `register_site_id` | 自动映射 | 会员注册门店 ID | 飞球门店 ID |
|
||||
| `tenant_member_id` | BIGINT | `tenant_member_id` | 自动映射 | 租户维度会员 ID | 飞球会员 ID |
|
||||
| `system_member_id` | BIGINT | `system_member_id` | 自动映射 | 系统维度会员 ID(跨租户唯一) | 飞球会员 ID |
|
||||
| `tenant_member_card_id` | BIGINT | `tenant_member_card_id` | 自动映射 | 会员卡 ID | 飞球会员卡 ID |
|
||||
| `card_type_id` | BIGINT | `card_type_id` | 自动映射 | 会员卡类型 ID | 飞球卡类型 ID |
|
||||
| `card_type_name` | VARCHAR(32) | `membercardtypename` | FACT_MAPPINGS | 会员卡类型名称快照 | 如 `普通会员卡` |
|
||||
| `member_name` | VARCHAR(64) | `membername` | FACT_MAPPINGS | 会员姓名快照 | 姓名 |
|
||||
| `member_mobile` | VARCHAR(20) | `membermobile` | FACT_MAPPINGS | 会员手机号快照 | 11 位手机号 |
|
||||
| `balance_before` | NUMERIC(18,2) | `before` | FACT_MAPPINGS | 变动前余额(元) | 金额值 |
|
||||
| `change_amount` | NUMERIC(18,2) | `account_data` | FACT_MAPPINGS | 变动金额(元),正数为充入,负数为扣减 | 正/负金额 |
|
||||
| `balance_after` | NUMERIC(18,2) | `after` | FACT_MAPPINGS | 变动后余额(元) | 金额值 |
|
||||
| `from_type` | INTEGER | `from_type` | 自动映射 | 变动来源类型:1=结算扣款,2=充值,3=退款返还,4=系统调整,7=转账,9=其他 | `1`/`2`/`3`/`4`/`7`/`9` |
|
||||
| `payment_method` | INTEGER | `payment_method` | 自动映射 | 支付方式 | 枚举值 |
|
||||
| `change_time` | TIMESTAMPTZ | `create_time` | FACT_MAPPINGS | 变动发生时间 | ISO 时间戳 |
|
||||
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 是否已删除:0=正常,1=已删除 | `0` / `1` |
|
||||
| `remark` | VARCHAR(255) | `remark` | 自动映射 | 备注说明 | 自由文本或 NULL |
|
||||
| `principal_before` | NUMERIC(18,2) | `principal_before` | FACT_MAPPINGS | 变动前本金余额(元),不含赠送金 | 金额值 |
|
||||
| `principal_after` | NUMERIC(18,2) | `principal_after` | FACT_MAPPINGS | 变动后本金余额(元) | 金额值 |
|
||||
| `principal_change_amount` | NUMERIC(18,2) | *计算列* | FACT_MAPPINGS | 本金变动金额(元),= `principal_after - principal_before` | 正/负金额 |
|
||||
|
||||
---
|
||||
|
||||
## 2. dwd_member_balance_change_ex(扩展表,8 列)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `balance_change_id` | BIGINT | `id` | FACT_MAPPINGS | 余额变动记录唯一标识(PK) | 同主表 |
|
||||
| `pay_site_name` | VARCHAR(64) | `paysitename` | FACT_MAPPINGS | 支付门店名称快照 | 如 `朗朗桌球` |
|
||||
| `register_site_name` | VARCHAR(64) | `registersitename` | FACT_MAPPINGS | 注册门店名称快照 | 如 `朗朗桌球` |
|
||||
| `refund_amount` | NUMERIC(18,2) | `refund_amount` | 自动映射 | 退款金额(元) | `0.00` ~ 金额值 |
|
||||
| `operator_id` | BIGINT | `operator_id` | 自动映射 | 操作员 ID,执行本次余额变动的员工。0 表示系统自动 | `0` 或员工 ID |
|
||||
| `operator_name` | VARCHAR(64) | `operator_name` | 自动映射 | 操作员姓名 | 姓名或 NULL |
|
||||
| `principal_data` | TEXT | `principal_data` | FACT_MAPPINGS | 本金变动金额(元),正数为充入本金,负数为扣减本金 | 正/负金额 |
|
||||
| `relate_id` | BIGINT | `relate_id` | FACT_MAPPINGS | 关联业务单据 ID,指向触发本次余额变动的业务记录。按 `from_type` 不同指向不同表:1→结算单 ID,2→充值单 ID,3→退款单 ID,7→转账单 ID。`from_type=4`(系统调整)和 `9`(其他)时为 0 | `0` 或业务单据 ID |
|
||||
|
||||
---
|
||||
|
||||
## 3. from_type 枚举值详解
|
||||
|
||||
| from_type | 含义 | relate_id 指向 | 数据量 |
|
||||
|-----------|------|---------------|--------|
|
||||
| 1 | 结算扣款(消费) | 结算单 ID(`dwd_settlement_head.order_settle_id`) | 5637 条 |
|
||||
| 2 | 充值 | 充值单 ID(`dwd_recharge_order.recharge_order_id`) | 110 条 |
|
||||
| 3 | 退款返还 | 退款单 ID(`dwd_refund.refund_id`) | 650 条 |
|
||||
| 4 | 系统调整 | 0(无关联单据) | 775 条 |
|
||||
| 7 | 转账 | 转账单 ID | 15 条 |
|
||||
| 9 | 其他 | 0(无关联单据) | 179 条 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_member_balance_change"]` / `FACT_MAPPINGS["dwd.dwd_member_balance_change_ex"]`
|
||||
- TABLE_MAP:`"dwd.dwd_member_balance_change" → "ods.member_balance_changes"`
|
||||
- DWS 下游:`dws_member_analysis_task.py`(会员消费分析)
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__add_member_balance_change_ex_relate_id.sql`(已归档)
|
||||
@@ -1,103 +0,0 @@
|
||||
# BD_Manual:recharge_settlements(充值结算)
|
||||
|
||||
> ODS 表:`ods.recharge_settlements`
|
||||
> DWD 表:`dwd.dwd_recharge_order`(主表)、`dwd.dwd_recharge_order_ex`(扩展表)
|
||||
> API 接口:充值结算记录列表
|
||||
> JSON 路径:`recharge_settlements.json → data.orderSettles`
|
||||
> 装载方式:事实表增量插入(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dwd_recharge_order(主表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `recharge_order_id` | BIGINT | `id` | FACT_MAPPINGS | 充值结算记录唯一标识(PK) | 飞球雪花 ID |
|
||||
| `tenant_id` | BIGINT | `tenantid` | FACT_MAPPINGS | 租户 ID | 飞球租户 ID |
|
||||
| `site_id` | BIGINT | `siteid` | FACT_MAPPINGS | 门店 ID | 飞球门店 ID |
|
||||
| `member_id` | BIGINT | `memberid` | FACT_MAPPINGS | 会员 ID | 飞球会员 ID |
|
||||
| `member_name_snapshot` | TEXT | `membername` | FACT_MAPPINGS | 会员姓名快照 | 姓名 |
|
||||
| `member_phone_snapshot` | TEXT | `memberphone` | FACT_MAPPINGS | 会员手机号快照 | 11 位手机号 |
|
||||
| `tenant_member_card_id` | BIGINT | `tenantmembercardid` | FACT_MAPPINGS | 会员卡 ID | 飞球会员卡 ID |
|
||||
| `member_card_type_name` | TEXT | `membercardtypename` | FACT_MAPPINGS | 会员卡类型名称 | 如 `普通会员卡` |
|
||||
| `settle_relate_id` | BIGINT | `settlerelateid` | FACT_MAPPINGS | 关联结算单 ID | 飞球结算 ID |
|
||||
| `settle_type` | INTEGER | `settletype` | FACT_MAPPINGS | 结算类型枚举 | 枚举值 |
|
||||
| `settle_name` | TEXT | `settlename` | FACT_MAPPINGS | 结算类型名称 | 如 `充值` |
|
||||
| `is_first` | INTEGER | `isfirst` | FACT_MAPPINGS | 是否首次充值:0=否,1=是 | `0` / `1` |
|
||||
| `pay_amount` | NUMERIC | `payamount` | FACT_MAPPINGS | 实付金额(元) | 金额值 |
|
||||
| `refund_amount` | NUMERIC | `refundamount` | FACT_MAPPINGS | 退款金额(元) | `0.00` ~ 金额值 |
|
||||
| `point_amount` | NUMERIC | `pointamount` | FACT_MAPPINGS | 积分抵扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `cash_amount` | NUMERIC | `cashamount` | FACT_MAPPINGS | 现金支付金额(元) | `0.00` ~ 金额值 |
|
||||
| `payment_method` | TEXT | `paymentmethod` | FACT_MAPPINGS | 支付方式 | 如 `微信`、`支付宝` |
|
||||
| `create_time` | TIMESTAMPTZ | `createtime` | FACT_MAPPINGS | 充值记录创建时间 | ISO 时间戳 |
|
||||
| `pay_time` | TIMESTAMPTZ | `paytime` | FACT_MAPPINGS | 支付完成时间 | ISO 时间戳 |
|
||||
| `pl_coupon_sale_amount` | NUMERIC | `plcouponsaleamount` | FACT_MAPPINGS | 平台券销售金额(元)。当前门店业务未启用,全部为 0 | `0.00` |
|
||||
| `mervou_sales_amount` | NUMERIC | `mervousalesamount` | FACT_MAPPINGS | 储值券销售金额(元)。当前门店业务未启用,全部为 0 | `0.00` |
|
||||
| `electricity_money` | NUMERIC | `electricitymoney` | FACT_MAPPINGS | 电费金额(元)。当前门店业务未启用,全部为 0 | `0.00` |
|
||||
| `real_electricity_money` | NUMERIC | `realelectricitymoney` | FACT_MAPPINGS | 实际电费金额(元),扣除调整后的电费。当前门店业务未启用,全部为 0 | `0.00` |
|
||||
| `electricity_adjust_money` | NUMERIC | `electricityadjustmoney` | FACT_MAPPINGS | 电费调整金额(元),电费手动调整的差额。当前门店业务未启用,全部为 0 | `0.00` |
|
||||
|
||||
---
|
||||
|
||||
## 2. dwd_recharge_order_ex(扩展表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `recharge_order_id` | BIGINT | `id` | FACT_MAPPINGS | 充值结算记录唯一标识(PK) | 同主表 |
|
||||
| `site_name_snapshot` | TEXT | `sitename` | FACT_MAPPINGS | 门店名称快照 | 如 `朗朗桌球` |
|
||||
| `settle_status` | INTEGER | `settlestatus` | FACT_MAPPINGS | 结算状态枚举 | 枚举值 |
|
||||
| `is_bind_member` | BOOLEAN | `isbindmember` | FACT_MAPPINGS (cast boolean) | 是否绑定会员 | `true` / `false` |
|
||||
| `is_activity` | BOOLEAN | `isactivity` | FACT_MAPPINGS (cast boolean) | 是否参与活动 | `true` / `false` |
|
||||
| `is_use_coupon` | BOOLEAN | `isusecoupon` | FACT_MAPPINGS (cast boolean) | 是否使用优惠券 | `true` / `false` |
|
||||
| `is_use_discount` | BOOLEAN | `isusediscount` | FACT_MAPPINGS (cast boolean) | 是否使用折扣 | `true` / `false` |
|
||||
| `can_be_revoked` | BOOLEAN | `canberevoked` | FACT_MAPPINGS (cast boolean) | 是否可撤销 | `true` / `false` |
|
||||
| `online_amount` | NUMERIC | `onlineamount` | FACT_MAPPINGS | 线上支付金额(元) | 金额值 |
|
||||
| `balance_amount` | NUMERIC | `balanceamount` | FACT_MAPPINGS | 余额支付金额(元) | 金额值 |
|
||||
| `card_amount` | NUMERIC | `cardamount` | FACT_MAPPINGS | 银行卡支付金额(元) | 金额值 |
|
||||
| `coupon_amount` | NUMERIC | `couponamount` | FACT_MAPPINGS | 优惠券抵扣金额(元) | 金额值 |
|
||||
| `recharge_card_amount` | NUMERIC | `rechargecardamount` | FACT_MAPPINGS | 充值卡支付金额(元) | 金额值 |
|
||||
| `gift_card_amount` | NUMERIC | `giftcardamount` | FACT_MAPPINGS | 赠送卡支付金额(元) | 金额值 |
|
||||
| `prepay_money` | NUMERIC | `prepaymoney` | FACT_MAPPINGS | 预付金额(元) | 金额值 |
|
||||
| `consume_money` | NUMERIC | `consumemoney` | FACT_MAPPINGS | 消费总金额(元) | 金额值 |
|
||||
| `goods_money` | NUMERIC | `goodsmoney` | FACT_MAPPINGS | 商品金额(元) | 金额值 |
|
||||
| `real_goods_money` | NUMERIC | `realgoodsmoney` | FACT_MAPPINGS | 实收商品金额(元) | 金额值 |
|
||||
| `table_charge_money` | NUMERIC | `tablechargemoney` | FACT_MAPPINGS | 台费金额(元) | 金额值 |
|
||||
| `service_money` | NUMERIC | `servicemoney` | FACT_MAPPINGS | 服务费金额(元) | 金额值 |
|
||||
| `activity_discount` | NUMERIC | `activitydiscount` | FACT_MAPPINGS | 活动折扣金额(元) | 金额值 |
|
||||
| `all_coupon_discount` | NUMERIC | `allcoupondiscount` | FACT_MAPPINGS | 全部优惠券折扣金额(元) | 金额值 |
|
||||
| `goods_promotion_money` | NUMERIC | `goodspromotionmoney` | FACT_MAPPINGS | 商品促销金额(元) | 金额值 |
|
||||
| `assistant_promotion_money` | NUMERIC | `assistantpromotionmoney` | FACT_MAPPINGS | 助教促销金额(元) | 金额值 |
|
||||
| `assistant_pd_money` | NUMERIC | `assistantpdmoney` | FACT_MAPPINGS | 助教陪打金额(元) | 金额值 |
|
||||
| `assistant_cx_money` | NUMERIC | `assistantcxmoney` | FACT_MAPPINGS | 助教促销服务金额(元) | 金额值 |
|
||||
| `assistant_manual_discount` | NUMERIC | `assistantmanualdiscount` | FACT_MAPPINGS | 助教手动折扣金额(元) | 金额值 |
|
||||
| `coupon_sale_amount` | NUMERIC | `couponsaleamount` | FACT_MAPPINGS | 券销售金额(元) | 金额值 |
|
||||
| `member_discount_amount` | NUMERIC | `memberdiscountamount` | FACT_MAPPINGS | 会员折扣金额(元) | 金额值 |
|
||||
| `point_discount_price` | NUMERIC | `pointdiscountprice` | FACT_MAPPINGS | 积分折扣价格(元) | 金额值 |
|
||||
| `point_discount_cost` | NUMERIC | `pointdiscountcost` | FACT_MAPPINGS | 积分折扣成本(元) | 金额值 |
|
||||
| `adjust_amount` | NUMERIC | `adjustamount` | FACT_MAPPINGS | 调整金额(元) | 金额值 |
|
||||
| `rounding_amount` | NUMERIC | `roundingamount` | FACT_MAPPINGS | 抹零金额(元) | 金额值 |
|
||||
| `operator_id` | BIGINT | `operatorid` | FACT_MAPPINGS | 操作员 ID | 员工 ID |
|
||||
| `operator_name_snapshot` | TEXT | `operatorname` | FACT_MAPPINGS | 操作员姓名快照 | 如 `郑丽珊` |
|
||||
| `salesman_user_id` | BIGINT | `salesmanuserid` | FACT_MAPPINGS | 销售员用户 ID | 用户 ID |
|
||||
| `salesman_name` | TEXT | `salesmanname` | FACT_MAPPINGS | 销售员姓名 | 姓名或 NULL |
|
||||
| `order_remark` | TEXT | `orderremark` | FACT_MAPPINGS | 订单备注 | 自由文本或 NULL |
|
||||
| `table_id` | BIGINT | `tableid` | FACT_MAPPINGS | 台桌 ID | 飞球台桌 ID |
|
||||
| `serial_number` | INTEGER | `serialnumber` | FACT_MAPPINGS | 流水号 | 正整数 |
|
||||
| `revoke_order_id` | BIGINT | `revokeorderid` | FACT_MAPPINGS | 撤销关联的订单 ID | 订单 ID 或 0 |
|
||||
| `revoke_order_name` | TEXT | `revokeordername` | FACT_MAPPINGS | 撤销关联的订单名称 | 名称或 NULL |
|
||||
| `revoke_time` | TIMESTAMPTZ | `revoketime` | FACT_MAPPINGS | 撤销时间 | ISO 时间戳或 NULL |
|
||||
|
||||
---
|
||||
|
||||
## 3. B 类表说明
|
||||
|
||||
本表属于 B 类(仅补 FACT_MAPPINGS),5 个电费/券字段的 DWD 列在 DDL 中已存在,但之前缺少 FACT_MAPPINGS 条目导致数据未从 ODS 流入 DWD。2026-02-20 补充映射后,这 5 个字段的数据可正常流转。当前门店这 5 个字段的 ODS/DWD 数据全部为 0(业务未启用电费和券销售功能)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_recharge_order"]` / `FACT_MAPPINGS["dwd.dwd_recharge_order_ex"]`
|
||||
- TABLE_MAP:`"dwd.dwd_recharge_order" → "ods.recharge_settlements"`
|
||||
- DWS 下游:`dws_finance_daily_task.py`(财务日报,充值汇总)
|
||||
@@ -1,61 +0,0 @@
|
||||
# BD_Manual:site_tables_master(台桌维表)
|
||||
|
||||
> ODS 表:`ods.site_tables_master`
|
||||
> DWD 表:`dwd.dim_table`(主表)、`dwd.dim_table_ex`(扩展表)
|
||||
> API 接口:门店台桌列表
|
||||
> JSON 路径:`site_tables_master.json → data.siteTables`
|
||||
> 装载方式:SCD2 维度合并(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dim_table(主表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `table_id` | BIGINT | `id` | FACT_MAPPINGS | 台桌唯一标识(PK 之一) | 飞球雪花 ID |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID | 飞球门店 ID |
|
||||
| `table_name` | TEXT | `table_name` | 自动映射 | 台桌名称 | 如 `1号台`、`VIP1` |
|
||||
| `site_table_area_id` | BIGINT | `site_table_area_id` | 自动映射 | 门店台桌区域 ID | 飞球区域 ID |
|
||||
| `site_table_area_name` | TEXT | `areaname` | FACT_MAPPINGS | 台桌区域名称 | 如 `大厅`、`VIP区` |
|
||||
| `tenant_table_area_id` | BIGINT | `site_table_area_id` | FACT_MAPPINGS | 租户级台桌区域 ID | 飞球区域 ID |
|
||||
| `table_price` | NUMERIC | `table_price` | 自动映射 | 台费单价(元/小时) | 金额值 |
|
||||
| `order_id` | BIGINT | `order_id` | FACT_MAPPINGS | 当前关联的订单 ID,0 表示空闲 | `0` 或订单 ID |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |
|
||||
|
||||
---
|
||||
|
||||
## 2. dim_table_ex(扩展表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `table_id` | BIGINT | `id` | FACT_MAPPINGS | 台桌唯一标识(PK 之一) | 同主表 |
|
||||
| `show_status` | INTEGER | `show_status` | 自动映射 | 展示状态 | 枚举值 |
|
||||
| `is_online_reservation` | INTEGER | `is_online_reservation` | 自动映射 | 是否支持在线预约:0=否,1=是 | `0` / `1` |
|
||||
| `table_cloth_use_time` | INTEGER | `table_cloth_use_time` | FACT_MAPPINGS | 台布使用时间(累计使用次数或时长) | 整数 |
|
||||
| `table_cloth_use_cycle` | INTEGER | `table_cloth_use_cycle` | 自动映射 | 台布更换周期 | 整数 |
|
||||
| `table_status` | INTEGER | `table_status` | 自动映射 | 台桌状态枚举 | 枚举值 |
|
||||
| `create_time` | TIMESTAMPTZ | `create_time` | FACT_MAPPINGS | 台桌配置的创建时间或最近一次创建/复制时间 | ISO 时间戳 |
|
||||
| `light_status` | INTEGER | `light_status` | FACT_MAPPINGS | 台灯状态:1=已关灯,2=已开灯 | `1` / `2` |
|
||||
| `tablestatusname` | TEXT | `tablestatusname` | FACT_MAPPINGS | 台桌状态中文名称(如"空闲中""使用中"),仅展示用途。ODS 列 `tableStatusName` 在 PG 中小写化 | 如 `空闲中`、`使用中` |
|
||||
| `sitename` | TEXT | `sitename` | FACT_MAPPINGS | 门店名称快照,冗余字段。ODS 列 `siteName` 在 PG 中小写化 | 如 `朗朗桌球` |
|
||||
| `applet_qr_code_url` | TEXT | `"appletQrCodeUrl"` | FACT_MAPPINGS | 小程序二维码 URL,用于扫码开台等场景。ODS 列用双引号保留驼峰大小写 | HTTPS 链接或 NULL |
|
||||
| `audit_status` | INTEGER | `audit_status` | FACT_MAPPINGS | 审核状态:2=已审核通过(当前全部为 2) | `2` |
|
||||
| `charge_free` | INTEGER | `charge_free` | FACT_MAPPINGS | 是否免费台:0=收费,1=免费(当前全部为 0) | `0` / `1` |
|
||||
| `delay_lights_time` | INTEGER | `delay_lights_time` | FACT_MAPPINGS | 台灯熄灭延迟时间(秒),结账后延时关灯的秒数 | 正整数 |
|
||||
| `is_rest_area` | INTEGER | `is_rest_area` | FACT_MAPPINGS | 是否休息区台桌:0=否,1=是(当前全部为 0) | `0` / `1` |
|
||||
| `only_allow_groupon` | INTEGER | `only_allow_groupon` | FACT_MAPPINGS | 是否仅允许团购开台:0=不限制,1=仅团购,2=不限制(当前全部为 2) | `0` / `1` / `2` |
|
||||
| `order_delay_time` | INTEGER | `order_delay_time` | FACT_MAPPINGS | 订单自动延时时长(秒),超时未结账自动延长的时间 | 正整数 |
|
||||
| `self_table` | INTEGER | `self_table` | FACT_MAPPINGS | 是否自有台桌:1=自有(当前全部为 1) | `1` |
|
||||
| `temporary_light_second` | INTEGER | `temporary_light_second` | FACT_MAPPINGS | 临时开灯秒数,临时开灯持续的时间 | 正整数 |
|
||||
| `virtual_table` | INTEGER | `virtual_table` | FACT_MAPPINGS | 是否虚拟台桌:0=实体台,1=虚拟台(当前全部为 0) | `0` / `1` |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |
|
||||
|
||||
---
|
||||
|
||||
## 3. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dim_table"]` / `FACT_MAPPINGS["dwd.dim_table_ex"]`
|
||||
- TABLE_MAP:`"dwd.dim_table" → "ods.site_tables_master"`
|
||||
- DWS 下游:`dws_finance_daily_task.py`(财务日报,台费汇总按区域分组)
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__add_dim_table_ex_fields.sql`(已归档)
|
||||
@@ -1,103 +0,0 @@
|
||||
# BD_Manual:store_goods_master(门店商品档案)
|
||||
|
||||
> ODS 表:`ods.store_goods_master`
|
||||
> DWD 表:`dwd.dim_store_goods`(主表)、`dwd.dim_store_goods_ex`(扩展表)
|
||||
> API 接口:门店商品列表
|
||||
> JSON 路径:`store_goods_master.json → data.orderGoodsList`
|
||||
> 装载方式:SCD2 维度合并(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dim_store_goods(主表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `site_goods_id` | BIGINT | `id` | FACT_MAPPINGS | 门店商品唯一标识(PK 之一) | 飞球雪花 ID |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID | 飞球租户 ID |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID | 飞球门店 ID |
|
||||
| `tenant_goods_id` | BIGINT | `tenant_goods_id` | 自动映射 | 租户商品 ID,关联 `dim_tenant_goods` | 飞球商品 ID |
|
||||
| `goods_name` | TEXT | `goods_name` | 自动映射 | 商品名称 | 如 `百威啤酒` |
|
||||
| `goods_category_id` | BIGINT | `goods_category_id` | 自动映射 | 一级分类 ID | 飞球分类 ID |
|
||||
| `goods_second_category_id` | BIGINT | `goods_second_category_id` | 自动映射 | 二级分类 ID | 飞球分类 ID |
|
||||
| `category_level1_name` | TEXT | `onecategoryname` | FACT_MAPPINGS | 一级分类名称 | 如 `酒水` |
|
||||
| `category_level2_name` | TEXT | `twocategoryname` | FACT_MAPPINGS | 二级分类名称 | 如 `啤酒` |
|
||||
| `batch_stock_qty` | INTEGER | `batch_stock_quantity` | FACT_MAPPINGS | 批次库存数量(按批次管理的库存)。⚠️ 2026-02-20 修正映射源(原错误映射自 `stock`,即当前库存) | 数值 |
|
||||
| `sale_qty` | INTEGER | `sale_num` | FACT_MAPPINGS | 累计销售数量 | 数值 |
|
||||
| `total_sales_qty` | INTEGER | `total_sales` | FACT_MAPPINGS | 累计销售总额 | 数值 |
|
||||
| `sale_price` | NUMERIC(18,2) | `sale_price` | 自动映射 | 商品售价(元) | 金额值 |
|
||||
| `created_at` | TIMESTAMPTZ | `create_time` | FACT_MAPPINGS | 商品创建时间 | ISO 时间戳 |
|
||||
| `updated_at` | TIMESTAMPTZ | `update_time` | FACT_MAPPINGS | 商品最后更新时间 | ISO 时间戳 |
|
||||
| `avg_monthly_sales` | NUMERIC(18,4) | `average_monthly_sales` | FACT_MAPPINGS | 月均销量 | 数值 |
|
||||
| `goods_state` | INTEGER | `goods_state` | 自动映射 | 商品状态 | 枚举值 |
|
||||
| `enable_status` | INTEGER | `enable_status` | 自动映射 | 启用状态 | 枚举值 |
|
||||
| `send_state` | INTEGER | `send_state` | 自动映射 | 配送状态 | 枚举值 |
|
||||
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 是否已删除:0=正常,1=已删除 | `0` / `1` |
|
||||
| `commodity_code` | TEXT | `commodity_code` | FACT_MAPPINGS | 商品编码 | 编码字符串 |
|
||||
| `not_sale` | INTEGER | `not_sale` | FACT_MAPPINGS | 是否停售:0=在售,1=停售 | `0` / `1` |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |
|
||||
|
||||
---
|
||||
|
||||
## 2. dim_store_goods_ex(扩展表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `site_goods_id` | BIGINT | `id` | FACT_MAPPINGS | 门店商品唯一标识(PK 之一) | 同主表 |
|
||||
| `site_name` | TEXT | `sitename` | FACT_MAPPINGS | 门店名称快照 | 如 `朗朗桌球` |
|
||||
| `unit` | TEXT | `unit` | 自动映射 | 计量单位 | 如 `瓶`、`包` |
|
||||
| `goods_barcode` | TEXT | `goods_bar_code` | FACT_MAPPINGS | 商品条码 | 条码字符串或 NULL |
|
||||
| `goods_cover_url` | TEXT | `goods_cover` | FACT_MAPPINGS | 商品封面图 URL | HTTPS 链接或 NULL |
|
||||
| `pinyin_initial` | TEXT | `pinyin_initial` | 自动映射 | 拼音首字母(用于搜索) | 如 `BWPJ` |
|
||||
| `stock_qty` | INTEGER | `stock` | FACT_MAPPINGS | 当前库存数量(实时库存) | 数值 |
|
||||
| `stock_secondary_qty` | INTEGER | `stock_a` | FACT_MAPPINGS | 辅助单位库存数量(双单位商品) | 数值 |
|
||||
| `safety_stock_qty` | INTEGER | `safe_stock` | FACT_MAPPINGS | 安全库存数量(低于此值触发预警) | 数值 |
|
||||
| `cost_price` | NUMERIC(18,4) | `cost_price` | 自动映射 | 成本价(元) | 金额值 |
|
||||
| `cost_price_type` | INTEGER | `cost_price_type` | 自动映射 | 成本价类型 | 枚举值 |
|
||||
| `provisional_total_cost` | NUMERIC(18,2) | `provisional_total_cost` | FACT_MAPPINGS | 暂估总成本(元),按暂估价计算的库存成本。⚠️ 2026-02-20 修正映射源(原错误映射自 `total_purchase_cost`,即实际采购成本) | 金额值 |
|
||||
| `total_purchase_cost` | NUMERIC(18,2) | `total_purchase_cost` | 自动映射 | 实际采购总成本(元) | 金额值 |
|
||||
| `min_discount_price` | NUMERIC(18,2) | `min_discount_price` | 自动映射 | 最低折扣价(元) | 金额值 |
|
||||
| `is_discountable` | INTEGER | `able_discount` | FACT_MAPPINGS | 是否可打折:0=不可,1=可 | `0` / `1` |
|
||||
| `days_on_shelf` | INTEGER | `days_available` | FACT_MAPPINGS | 上架天数 | 正整数 |
|
||||
| `audit_status` | INTEGER | `audit_status` | 自动映射 | 审核状态 | 枚举值 |
|
||||
| `sale_channel` | INTEGER | `sale_channel` | 自动映射 | 销售渠道 | 枚举值 |
|
||||
| `is_warehousing` | INTEGER | `is_warehousing` | 自动映射 | 是否入库管理:0=否,1=是 | `0` / `1` |
|
||||
| `freeze_status` | INTEGER | `freeze` | FACT_MAPPINGS | 冻结状态:0=正常,1=冻结 | `0` / `1` |
|
||||
| `forbid_sell_status` | INTEGER | `forbid_sell_status` | 自动映射 | 禁售状态 | 枚举值 |
|
||||
| `able_site_transfer` | INTEGER | `able_site_transfer` | 自动映射 | 是否允许门店间调拨:0=否,1=是 | `0` / `1` |
|
||||
| `custom_label_type` | INTEGER | `custom_label_type` | 自动映射 | 自定义标签类型 | 枚举值 |
|
||||
| `option_required` | INTEGER | `option_required` | 自动映射 | 是否必选规格:0=否,1=是 | `0` / `1` |
|
||||
| `remark` | TEXT | `remark` | FACT_MAPPINGS | 商品备注 | 自由文本或 NULL |
|
||||
| `sort_order` | INTEGER | `sort` | FACT_MAPPINGS | 排序序号 | 正整数 |
|
||||
| `batch_stock_quantity` | NUMERIC | `batch_stock_quantity` | 自动映射 | 批次库存数量(冗余,与主表 `batch_stock_qty` 同源) | 数值 |
|
||||
| `time_slot_sale` | INTEGER | `time_slot_sale` | FACT_MAPPINGS | 分时段销售标记(当前观测全部为 2)。2026-02-21 新增 | `2` |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |
|
||||
|
||||
---
|
||||
|
||||
## 3. 映射修正记录
|
||||
|
||||
| 日期 | 字段 | 修正内容 |
|
||||
|------|------|---------|
|
||||
| 2026-02-20 | `batch_stock_qty` | ODS 源从 `stock`(当前库存)修正为 `batch_stock_quantity`(批次库存)。验证:仅 7.3% 行两列值相等 |
|
||||
| 2026-02-20 | `provisional_total_cost` | ODS 源从 `total_purchase_cost`(实际采购成本)修正为 `provisional_total_cost`(暂估成本)。验证:93.5% 行相等但 113 行不同 |
|
||||
| 2026-02-21 | `time_slot_sale` | 新增字段。ODS `ods.store_goods_master` + DWD `dwd.dim_store_goods_ex` 同步新增 `time_slot_sale INTEGER`。API 返回值当前全部为 `2` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 跳过字段说明
|
||||
|
||||
| ODS 字段 | 跳过原因 |
|
||||
|---------|---------|
|
||||
| ~~`time_slot_sale`~~ | ~~ODS 列不存在~~ → 2026-02-21 已新增,见映射修正记录 |
|
||||
| `goodsStockWarningInfo` | JSONB 嵌套对象,展开不在本次范围内 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dim_store_goods"]` / `FACT_MAPPINGS["dwd.dim_store_goods_ex"]`
|
||||
- TABLE_MAP:`"dwd.dim_store_goods" → "ods.store_goods_master"`
|
||||
- DWS 下游:`dws_finance_daily_task.py`(财务日报,商品维度关联)
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__fix_store_goods_master_mapping.sql`(已归档)
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-21__add_time_slot_sale_merge_commodity_code.sql`(已归档)
|
||||
@@ -1,93 +0,0 @@
|
||||
# BD_Manual:store_goods_sales_records(门店商品销售流水)
|
||||
|
||||
> ODS 表:`ods.store_goods_sales_records`
|
||||
> DWD 表:`dwd.dwd_store_goods_sale`(主表)、`dwd.dwd_store_goods_sale_ex`(扩展表)
|
||||
> API 接口:门店商品销售记录列表
|
||||
> JSON 路径:`store_goods_sales_records.json → data.orderGoodsLedgers`
|
||||
> 装载方式:事实表增量插入(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dwd_store_goods_sale(主表,25 列)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `store_goods_sale_id` | BIGINT | `id` | FACT_MAPPINGS | 销售记录唯一标识(PK) | 飞球雪花 ID |
|
||||
| `order_trade_no` | BIGINT | `order_trade_no` | 自动映射 | 关联的订单交易号 | 飞球订单号 |
|
||||
| `order_settle_id` | BIGINT | `order_settle_id` | 自动映射 | 关联的结算单 ID | 飞球结算单 ID |
|
||||
| `order_pay_id` | BIGINT | `order_pay_id` | 自动映射 | 关联的支付单 ID | 飞球支付单 ID |
|
||||
| `order_goods_id` | BIGINT | `order_goods_id` | 自动映射 | 订单商品明细 ID | 飞球雪花 ID |
|
||||
| `site_id` | BIGINT | `site_id` | 自动映射 | 门店 ID | 飞球门店 ID |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID | 飞球租户 ID |
|
||||
| `site_goods_id` | BIGINT | `site_goods_id` | 自动映射 | 门店商品 ID,关联 `dim_store_goods` | 飞球商品 ID |
|
||||
| `tenant_goods_id` | BIGINT | `tenant_goods_id` | 自动映射 | 租户商品 ID,关联 `dim_tenant_goods` | 飞球商品 ID |
|
||||
| `tenant_goods_category_id` | BIGINT | `tenant_goods_category_id` | 自动映射 | 商品分类 ID | 飞球分类 ID |
|
||||
| `tenant_goods_business_id` | BIGINT | `tenant_goods_business_id` | 自动映射 | 商品业务类型 ID | 飞球业务 ID |
|
||||
| `site_table_id` | BIGINT | `site_table_id` | 自动映射 | 消费台桌 ID,关联 `dim_table.table_id` | 飞球台桌 ID |
|
||||
| `ledger_name` | VARCHAR(200) | `ledger_name` | 自动映射 | 分账项名称(商品名称快照) | 如 `百威啤酒` |
|
||||
| `ledger_group_name` | VARCHAR(100) | `ledger_group_name` | 自动映射 | 分账组名称 | 分账组名或 NULL |
|
||||
| `ledger_unit_price` | NUMERIC(18,2) | `ledger_unit_price` | 自动映射 | 分账单价(元/单位) | 金额值 |
|
||||
| `ledger_count` | INTEGER | `ledger_count` | 自动映射 | 分账数量(销售数量) | 正整数 |
|
||||
| `ledger_amount` | NUMERIC(18,2) | `ledger_amount` | 自动映射 | 分账总金额(元),= 单价 × 数量 | 金额值 |
|
||||
| `discount_money` | NUMERIC(18,2) | `discount_money` | FACT_MAPPINGS | 折扣金额(元),会员折扣减免的金额。⚠️ 2026-02-20 由原 `discount_price` 重命名而来,修正列名误导 | `0.00` ~ 金额值 |
|
||||
| `real_goods_money` | NUMERIC(18,2) | `real_goods_money` | 自动映射 | 实收商品金额(元),扣除折扣后 | 金额值 |
|
||||
| `cost_money` | NUMERIC(18,2) | `cost_money` | 自动映射 | 成本金额(元) | 金额值 |
|
||||
| `ledger_status` | INTEGER | `ledger_status` | 自动映射 | 分账状态 | 枚举值 |
|
||||
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 是否已删除:0=正常,1=已删除 | `0` / `1` |
|
||||
| `create_time` | TIMESTAMPTZ | `create_time` | 自动映射 | 销售记录创建时间 | ISO 时间戳 |
|
||||
| `coupon_share_money` | NUMERIC(18,2) | `coupon_share_money` | FACT_MAPPINGS | 优惠券分摊金额(元),该商品分摊的优惠券减免 | `0.00` ~ 金额值 |
|
||||
| `discount_price` | NUMERIC(18,2) | `discount_price` | FACT_MAPPINGS | 折后单价(元),会员折扣后的商品单价。⚠️ 2026-02-20 新增,映射自 ODS 真正的 `discount_price` | `0.00` ~ 金额值 |
|
||||
|
||||
---
|
||||
|
||||
## 2. dwd_store_goods_sale_ex(扩展表,28 列)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `store_goods_sale_id` | BIGINT | `id` | FACT_MAPPINGS | 销售记录唯一标识(PK) | 同主表 |
|
||||
| `legacy_order_goods_id` | BIGINT | `ordergoodsid` | FACT_MAPPINGS | 旧版订单商品 ID(兼容字段) | 飞球 ID |
|
||||
| `site_name` | TEXT | `sitename` | FACT_MAPPINGS | 门店名称快照 | 如 `朗朗桌球` |
|
||||
| `legacy_site_id` | BIGINT | `siteid` | FACT_MAPPINGS | 旧版门店 ID(兼容字段) | 飞球门店 ID |
|
||||
| `goods_remark` | TEXT | `goods_remark` | 自动映射 | 商品备注 | 自由文本或 NULL |
|
||||
| `option_value_name` | TEXT | `option_value_name` | FACT_MAPPINGS | 商品规格选项名称 | 如 `大杯`、NULL |
|
||||
| `operator_name` | TEXT | `operator_name` | 自动映射 | 操作员姓名 | 姓名或 NULL |
|
||||
| `open_salesman_flag` | INTEGER | `opensalesman` | FACT_MAPPINGS (cast integer) | 是否开启销售员提成:0=否,1=是 | `0` / `1` |
|
||||
| `salesman_user_id` | BIGINT | `salesman_user_id` | 自动映射 | 销售员用户 ID | 用户 ID 或 NULL |
|
||||
| `salesman_name` | TEXT | `salesman_name` | FACT_MAPPINGS | 销售员姓名 | 姓名或 NULL |
|
||||
| `salesman_role_id` | BIGINT | `salesman_role_id` | 自动映射 | 销售员角色 ID | 角色 ID 或 NULL |
|
||||
| `salesman_org_id` | BIGINT | `sales_man_org_id` | FACT_MAPPINGS | 销售员组织 ID | 组织 ID 或 NULL |
|
||||
| `discount_money` | NUMERIC(18,2) | `discount_money` | 自动映射 | 折扣金额(元),扩展表中的折扣明细 | `0.00` ~ 金额值 |
|
||||
| `returns_number` | INTEGER | `returns_number` | 自动映射 | 退货数量 | `0` ~ 正整数 |
|
||||
| `coupon_deduct_money` | NUMERIC(18,2) | `coupon_deduct_money` | 自动映射 | 优惠券抵扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `member_discount_amount` | NUMERIC(18,2) | `member_discount_amount` | 自动映射 | 会员折扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `point_discount_money` | NUMERIC(18,2) | `point_discount_money` | 自动映射 | 积分抵扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `point_discount_money_cost` | NUMERIC(18,2) | `point_discount_money_cost` | 自动映射 | 积分抵扣成本(元) | `0.00` ~ 金额值 |
|
||||
| `package_coupon_id` | BIGINT | `package_coupon_id` | 自动映射 | 套餐券 ID | 券 ID 或 NULL |
|
||||
| `order_coupon_id` | BIGINT | `order_coupon_id` | 自动映射 | 订单券 ID | 券 ID 或 NULL |
|
||||
| `member_coupon_id` | BIGINT | `member_coupon_id` | 自动映射 | 会员券 ID | 券 ID 或 NULL |
|
||||
| `option_price` | NUMERIC(18,2) | `option_price` | 自动映射 | 规格选项加价(元) | `0.00` ~ 金额值 |
|
||||
| `option_member_discount_money` | NUMERIC(18,2) | `option_member_discount_money` | 自动映射 | 规格选项会员折扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `option_coupon_deduct_money` | NUMERIC(18,2) | `option_coupon_deduct_money` | 自动映射 | 规格选项优惠券抵扣金额(元) | `0.00` ~ 金额值 |
|
||||
| `push_money` | NUMERIC(18,2) | `push_money` | 自动映射 | 推销提成金额(元) | `0.00` ~ 金额值 |
|
||||
| `is_single_order` | INTEGER | `is_single_order` | 自动映射 | 是否单独订单 | `0` / `1` |
|
||||
| `sales_type` | INTEGER | `sales_type` | 自动映射 | 销售类型 | 枚举值 |
|
||||
| `operator_id` | BIGINT | `operator_id` | 自动映射 | 操作员 ID | 员工 ID 或 NULL |
|
||||
|
||||
---
|
||||
|
||||
## 3. 映射修正记录
|
||||
|
||||
| 日期 | 字段 | 修正内容 |
|
||||
|------|------|---------|
|
||||
| 2026-02-20 | `discount_price` → `discount_money` | 原 DWD `discount_price` 实际映射自 ODS `discount_money`(折扣金额),列名与语义不符,重命名为 `discount_money` |
|
||||
| 2026-02-20 | `discount_price`(新增) | 新增 DWD 列,映射自 ODS 真正的 `discount_price`(折后单价) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dwd_store_goods_sale"]` / `FACT_MAPPINGS["dwd.dwd_store_goods_sale_ex"]`
|
||||
- TABLE_MAP:`"dwd.dwd_store_goods_sale" → "ods.store_goods_sales_records"`
|
||||
- DWS 下游:`dws_finance_daily_task.py`(财务日报,商品销售汇总)
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-20__fix_store_goods_sale_discount_price.sql`(已归档)
|
||||
@@ -1,80 +0,0 @@
|
||||
# BD_Manual:tenant_goods_master(租户商品档案)
|
||||
|
||||
> ODS 表:`ods.tenant_goods_master`
|
||||
> DWD 表:`dwd.dim_tenant_goods`(主表)、`dwd.dim_tenant_goods_ex`(扩展表)
|
||||
> API 接口:租户商品列表
|
||||
> JSON 路径:`tenant_goods_master.json → data.tenantGoodsList`
|
||||
> 装载方式:SCD2 维度合并(`DwdLoadTask`)
|
||||
> 代码位置:`apps/etl/connectors/feiqiu/tasks/dwd/dwd_load_task.py`
|
||||
|
||||
---
|
||||
|
||||
## 1. dim_tenant_goods(主表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `tenant_goods_id` | BIGINT | `id` | FACT_MAPPINGS | 租户商品唯一标识(PK 之一) | 飞球雪花 ID |
|
||||
| `tenant_id` | BIGINT | `tenant_id` | 自动映射 | 租户 ID | 飞球租户 ID |
|
||||
| `supplier_id` | BIGINT | `supplier_id` | 自动映射 | 供应商 ID | 飞球供应商 ID 或 0 |
|
||||
| `category_name` | VARCHAR | `categoryname` | FACT_MAPPINGS | 一级分类名称 | 如 `酒水` |
|
||||
| `goods_category_id` | BIGINT | `goods_category_id` | 自动映射 | 一级分类 ID | 飞球分类 ID |
|
||||
| `goods_second_category_id` | BIGINT | `goods_second_category_id` | 自动映射 | 二级分类 ID | 飞球分类 ID |
|
||||
| `goods_name` | VARCHAR | `goods_name` | 自动映射 | 商品名称 | 如 `百威啤酒` |
|
||||
| `goods_number` | VARCHAR | `goods_number` | 自动映射 | 商品编号 | 编号字符串 |
|
||||
| `unit` | VARCHAR | `unit` | 自动映射 | 计量单位 | 如 `瓶`、`包` |
|
||||
| `market_price` | NUMERIC | `market_price` | 自动映射 | 市场价/建议售价(元) | 金额值 |
|
||||
| `goods_state` | INTEGER | `goods_state` | 自动映射 | 商品状态 | 整数枚举 |
|
||||
| `create_time` | TIMESTAMPTZ | `create_time` | 自动映射 | 商品创建时间 | ISO 时间戳 |
|
||||
| `update_time` | TIMESTAMPTZ | `update_time` | 自动映射 | 商品最后更新时间 | ISO 时间戳 |
|
||||
| `is_delete` | INTEGER | `is_delete` | 自动映射 | 软删除标记:0=正常,1=已删除 | `0` / `1` |
|
||||
| `not_sale` | INTEGER | `not_sale` | FACT_MAPPINGS | 是否停售:0=在售,1=停售 | `0` / `1` |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |
|
||||
|
||||
---
|
||||
|
||||
## 2. dim_tenant_goods_ex(扩展表)
|
||||
|
||||
| DWD 列名 | 类型 | ODS 源列 | 映射方式 | 业务含义 | 取值范围/示例 |
|
||||
|----------|------|---------|---------|---------|-------------|
|
||||
| `tenant_goods_id` | BIGINT | `id` | FACT_MAPPINGS | 租户商品唯一标识(PK 之一) | 同主表 |
|
||||
| `remark_name` | VARCHAR(128) | `remark_name` | FACT_MAPPINGS | 商品备注名称 | 自由文本或 NULL |
|
||||
| `pinyin_initial` | VARCHAR | `pinyin_initial` | 自动映射 | 商品名称拼音首字母,用于快速检索 | 如 `BWPJ` |
|
||||
| `goods_cover` | VARCHAR | `goods_cover` | 自动映射 | 商品封面图 URL | HTTPS 链接或 NULL |
|
||||
| `goods_bar_code` | VARCHAR | `goods_bar_code` | FACT_MAPPINGS | 商品条码 | 条码字符串或 NULL |
|
||||
| `commodity_code` | VARCHAR | `commodity_code` | 自动映射 | 商品编码(单值,旧字段) | 编码字符串或 NULL |
|
||||
| `commodity_code_list` | TEXT[] | `commoditycode` | FACT_MAPPINGS (cast TEXT[]) | 商品编码数组。ODS `commoditycode` 存储 PG 数组格式 `{CODE1}`,CAST 为 `TEXT[]`。2026-02-21 从 VARCHAR(256) 改为 TEXT[] | `['1234571']` |
|
||||
| `min_discount_price` | NUMERIC | `min_discount_price` | 自动映射 | 最低折扣价(元) | 金额值 |
|
||||
| `cost_price` | NUMERIC | `cost_price` | 自动映射 | 成本价(元) | 金额值 |
|
||||
| `cost_price_type` | INTEGER | `cost_price_type` | 自动映射 | 成本价类型 | 整数枚举 |
|
||||
| `able_discount` | INTEGER | `able_discount` | 自动映射 | 是否允许折扣:0=不允许,1=允许 | `0` / `1` |
|
||||
| `sale_channel` | INTEGER | `sale_channel` | 自动映射 | 销售渠道 | 整数枚举 |
|
||||
| `is_warehousing` | INTEGER | `is_warehousing` | 自动映射 | 是否入库管理:0=否,1=是 | `0` / `1` |
|
||||
| `is_in_site` | BOOLEAN | `isinsite` | FACT_MAPPINGS (cast boolean) | 是否已分配到门店 | `true` / `false` |
|
||||
| `able_site_transfer` | INTEGER | `able_site_transfer` | 自动映射 | 是否允许门店间调拨 | `0` / `1` |
|
||||
| `common_sale_royalty` | INTEGER | `common_sale_royalty` | 自动映射 | 普通销售提成(分) | 整数 |
|
||||
| `point_sale_royalty` | INTEGER | `point_sale_royalty` | 自动映射 | 积分销售提成(分) | 整数 |
|
||||
| `out_goods_id` | BIGINT | `out_goods_id` | 自动映射 | 外部商品 ID(第三方系统关联) | 外部 ID 或 0 |
|
||||
| `scd2_*` | — | — | DWD 元数据 | SCD2 慢变维度追踪字段 | — |
|
||||
|
||||
## 3. 映射修正记录
|
||||
|
||||
| 日期 | 字段 | 修正内容 |
|
||||
|------|------|---------|
|
||||
| 2026-02-21 | `commodity_code_list` | 类型从 `VARCHAR(256)` 改为 `TEXT[]`。映射源从 `commodity_code`(单值)改为 `commoditycode`(PG 数组格式 `{xxx}`),通过 `::TEXT[]` CAST。现有数据通过 `ARRAY[commodity_code_list]` 迁移 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 跳过字段说明
|
||||
|
||||
所有 ODS 业务字段均已映射到 DWD 主表或扩展表,无跳过字段。
|
||||
|
||||
> `commoditycode`(ODS 列)已作为 `commodity_code_list` 的映射源(`commoditycode::TEXT[]`),同时 `commodity_code`(单值旧字段)也保留在扩展表中。
|
||||
|
||||
---
|
||||
|
||||
## 5. 代码引用
|
||||
|
||||
- FACT_MAPPINGS:`dwd_load_task.py` → `FACT_MAPPINGS["dwd.dim_tenant_goods"]` / `FACT_MAPPINGS["dwd.dim_tenant_goods_ex"]`
|
||||
- TABLE_MAP:`"dwd.dim_tenant_goods" → "ods.tenant_goods_master"`
|
||||
- DWS 下游:无直接 DWS 汇总引用
|
||||
- 迁移脚本:`db/_archived/ddl_baseline_2026-02-22/db/etl_feiqiu/migrations/2026-02-21__add_time_slot_sale_merge_commodity_code.sql`(已归档)
|
||||
@@ -8,50 +8,46 @@
|
||||
|------|--------|--------|------|
|
||||
| `etl_feiqiu__meta.sql` | etl_feiqiu | meta | 调度元数据(3 表) |
|
||||
| `etl_feiqiu__ods.sql` | etl_feiqiu | ods | 原始数据层(23 表) |
|
||||
| `etl_feiqiu__dwd.sql` | etl_feiqiu | dwd | 明细数据层(44 表) |
|
||||
| `etl_feiqiu__dwd.sql` | etl_feiqiu | dwd | 明细数据层(42 表) |
|
||||
| `etl_feiqiu__core.sql` | etl_feiqiu | core | 跨门店标准化(7 表) |
|
||||
| `etl_feiqiu__dws.sql` | etl_feiqiu | dws | 汇总数据层(34 表 + 1 视图 + 8 物化视图) |
|
||||
| `etl_feiqiu__app.sql` | etl_feiqiu | app | RLS 视图层(43 视图,无表) |
|
||||
| `etl_feiqiu__dws.sql` | etl_feiqiu | dws | 汇总数据层(36 表 + 物化视图) |
|
||||
| `etl_feiqiu__app.sql` | etl_feiqiu | app | RLS 视图层(仅视图,无表) |
|
||||
| `zqyy_app__public.sql` | zqyy_app | public | 小程序业务表(12 表) |
|
||||
| `zqyy_app__auth.sql` | zqyy_app | auth | 用户认证与权限(8 表) |
|
||||
| `zqyy_app__biz.sql` | zqyy_app | biz | 核心业务表(任务/备注/触发器,4 表) |
|
||||
| `zqyy_app__biz.sql` | zqyy_app | biz | 核心业务表(任务/备注/触发器/AI,7 表) |
|
||||
| `fdw.sql` | — | — | FDW 正向跨库映射配置(etl→app) |
|
||||
|
||||
## 数据字典(BD_Manual — ODS→DWD 字段映射)
|
||||
## 业务库文档(BD_Manual — zqyy_app / 跨模块)
|
||||
|
||||
记录每个 ODS 表到 DWD 表的字段映射、装载方式、业务含义。
|
||||
本目录仅保留业务库(zqyy_app)和跨模块的 BD_Manual。ETL 专属文档(ODS→DWD 映射、DWS 表文档)已迁移至 `apps/etl/connectors/feiqiu/docs/database/`。
|
||||
|
||||
| 文件 | ODS 表 | DWD 表 |
|
||||
|------|--------|--------|
|
||||
| `BD_Manual_assistant_accounts_master.md` | ods.assistant_accounts_master | dwd.dim_assistant / dim_assistant_ex |
|
||||
| `BD_Manual_assistant_service_records.md` | ods.assistant_service_records | dwd.dwd_assistant_service_log* |
|
||||
| `BD_Manual_dws_goods_stock_summary.md` | — | dws.dws_goods_stock_*_summary |
|
||||
| `BD_Manual_goods_stock_movements.md` | ods.goods_stock_movements | dwd.dwd_goods_stock_movement |
|
||||
| `BD_Manual_goods_stock_summary.md` | ods.goods_stock_summary | dwd.dwd_goods_stock_summary |
|
||||
| `BD_Manual_member_balance_changes.md` | ods.member_balance_changes | dwd.dwd_member_balance_change* |
|
||||
| `BD_Manual_recharge_settlements.md` | ods.recharge_settlements | dwd.dwd_recharge_order* |
|
||||
| `BD_Manual_site_tables_master.md` | ods.site_tables_master | dwd.dim_table* |
|
||||
| `BD_Manual_store_goods_master.md` | ods.store_goods_master | dwd.dim_store_goods* |
|
||||
| `BD_Manual_store_goods_sales_records.md` | ods.store_goods_sales_records | dwd.dwd_store_goods_sale* |
|
||||
| `BD_Manual_tenant_goods_master.md` | ods.tenant_goods_master | dwd.dim_tenant_goods* |
|
||||
| `BD_Manual_staff_info_master.md` | ods.staff_info_master | dwd.dim_staff / dim_staff_ex |
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `BD_Manual_auth_tables.md` | zqyy_app auth schema 表结构 |
|
||||
| `BD_Manual_biz_tables.md` | zqyy_app biz schema 表结构 |
|
||||
| `BD_Manual_ai_tables.md` | zqyy_app AI 相关表 |
|
||||
| `BD_Manual_auth_biz_schemas.md` | auth + biz schema 建库说明 |
|
||||
| `BD_Manual_app_schema_rls_views.md` | app schema RLS 视图 |
|
||||
| `BD_Manual_fdw_etl_setup.md` | FDW 跨库映射配置 |
|
||||
| `BD_Manual_member_retention_clue.md` | zqyy_app 维客线索表 |
|
||||
|
||||
## 归档(`_archived/` 子目录)
|
||||
|
||||
已吸收进 DDL 基线的迁移变更记录,仅供历史参考:
|
||||
- 迁移变更类 BD_Manual(加列、改约束、删表、FDW 变更等)
|
||||
- 迁移变更类 BD_Manual(加列、改约束、删表、FDW 变更、tenant_id 类型变更等)
|
||||
- `etl_feiqiu_schema_migration.md`(旧迁移汇总)
|
||||
- `zqyy_app_admin_web_tables.md`(建表记录)
|
||||
|
||||
## 注意事项
|
||||
|
||||
- `fdw.sql` 仅包含正向映射(etl_feiqiu → zqyy_app),反向映射(zqyy_app → etl_feiqiu)的可执行脚本在 `db/fdw/setup_fdw_reverse*.sql`
|
||||
- DDL 基线中的统计数字以文件实际内容为准,本 README 的表格数字可能滞后于最新导出
|
||||
- DDL 基线最近一次从测试库导出日期:2026-03-15(合并了 2026-02-27 至 2026-03-09 的全部迁移)
|
||||
- ETL 专属文档(ODS→DWD 映射、DWS 表文档):`apps/etl/connectors/feiqiu/docs/database/`
|
||||
|
||||
## 相关资源
|
||||
|
||||
- 种子数据:`db/etl_feiqiu/seeds/`、`db/zqyy_app/seeds/`
|
||||
- 种子数据:已合并进各 DDL 文件末尾(不再单独维护)
|
||||
- FDW 配置(可执行):`db/fdw/`(含正向 + 反向 + 测试环境版本)
|
||||
- DDL 生成脚本:`scripts/ops/gen_consolidated_ddl.py`
|
||||
- 迁移脚本(活跃):`db/etl_feiqiu/migrations/`、`db/zqyy_app/migrations/`
|
||||
- 迁移脚本(活跃):`db/etl_feiqiu/migrations/`、`db/zqyy_app/migrations/`(当前已清空,1.0 基线已统一)
|
||||
- 迁移脚本归档:`db/_archived/ddl_baseline_2026-02-22/`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- etl_feiqiu / app(RLS 视图层)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -322,9 +322,6 @@ SELECT recharge_order_id,
|
||||
WHERE (site_id = (current_setting('app.current_site_id'::text))::bigint);
|
||||
;
|
||||
|
||||
-- ⚠️ consume_money 透传自 DWD 层,存在三种历史口径(A/B/C),API 消费端不应直接展示或参与计算。
|
||||
-- 应使用 items_sum = table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money
|
||||
-- settle_type 枚举:1=台桌结账, 3=商城订单, 6=退货订单, 7=退款订单(本表无 is_delete 字段)
|
||||
CREATE OR REPLACE VIEW app.v_dwd_settlement_head AS
|
||||
SELECT order_settle_id,
|
||||
tenant_id,
|
||||
@@ -686,7 +683,7 @@ SELECT id,
|
||||
platform_fee_amount,
|
||||
recharge_cash_inflow,
|
||||
card_consume_total,
|
||||
recharge_card_consume,
|
||||
recharge_card_consume AS cash_card_consume,
|
||||
gift_card_consume,
|
||||
cash_outflow_total,
|
||||
cash_balance_change,
|
||||
@@ -995,8 +992,7 @@ SELECT id,
|
||||
total_discount,
|
||||
actual_pay,
|
||||
cash_pay,
|
||||
balance_pay,
|
||||
recharge_card_pay,
|
||||
balance_pay AS cash_card_pay,
|
||||
gift_card_pay,
|
||||
groupbuy_pay,
|
||||
table_duration_min,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- etl_feiqiu / core(跨门店标准化维度/事实)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- etl_feiqiu / dwd(明细数据层)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -153,7 +153,11 @@ CREATE TABLE dwd.dim_groupbuy_package_ex (
|
||||
scd2_start_time timestamp with time zone NOT NULL,
|
||||
scd2_end_time timestamp with time zone,
|
||||
scd2_is_current integer,
|
||||
scd2_version integer
|
||||
scd2_version integer,
|
||||
table_area_ids jsonb,
|
||||
table_area_names jsonb,
|
||||
assistant_services jsonb,
|
||||
groupon_site_infos jsonb
|
||||
);
|
||||
|
||||
CREATE TABLE dwd.dim_member (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- etl_feiqiu / dws(汇总数据层)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -18,6 +18,7 @@ CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_daily_detail_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_finance_analysis_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_monthly_summary_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_order_contribution_contribution_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_project_tag_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_recharge_commission_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_salary_calc_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_finance_daily_summary_id_seq AS bigint;
|
||||
@@ -30,6 +31,7 @@ CREATE SEQUENCE IF NOT EXISTS dws.dws_member_assistant_intimacy_intimacy_id_seq
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_assistant_relation_index_relation_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_consumption_summary_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_newconv_index_newconv_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_project_tag_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_recall_index_recall_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_spending_power_index_spi_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_visit_detail_id_seq AS bigint;
|
||||
@@ -42,21 +44,18 @@ CREATE SEQUENCE IF NOT EXISTS dws.dws_platform_settlement_id_seq AS bigint;
|
||||
CREATE TABLE dws.cfg_area_category (
|
||||
category_id integer DEFAULT nextval('dws.cfg_area_category_category_id_seq'::regclass) NOT NULL,
|
||||
source_area_name character varying(100) NOT NULL,
|
||||
source_table_name character varying(100) DEFAULT NULL,
|
||||
category_code character varying(20) NOT NULL,
|
||||
category_name character varying(50) NOT NULL,
|
||||
display_name character varying(50) DEFAULT NULL,
|
||||
short_name character varying(20) DEFAULT NULL,
|
||||
match_type character varying(10) DEFAULT 'EXACT'::character varying NOT NULL,
|
||||
match_priority integer DEFAULT 100 NOT NULL,
|
||||
is_active boolean DEFAULT true NOT NULL,
|
||||
description text,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
source_table_name character varying(100) DEFAULT NULL::character varying,
|
||||
display_name character varying(50) DEFAULT NULL::character varying,
|
||||
short_name character varying(20) DEFAULT NULL::character varying
|
||||
);
|
||||
-- 唯一约束:(source_area_name, source_table_name) 支持同一台区下按台桌细分
|
||||
CREATE UNIQUE INDEX uk_cfg_area_category
|
||||
ON dws.cfg_area_category (source_area_name, COALESCE(source_table_name, ''));
|
||||
|
||||
CREATE TABLE dws.cfg_assistant_level_price (
|
||||
price_id integer DEFAULT nextval('dws.cfg_assistant_level_price_price_id_seq'::regclass) NOT NULL,
|
||||
@@ -286,6 +285,24 @@ CREATE TABLE dws.dws_assistant_order_contribution (
|
||||
updated_at timestamp with time zone DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE dws.dws_assistant_project_tag (
|
||||
id bigint DEFAULT nextval('dws.dws_assistant_project_tag_id_seq'::regclass) NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
tenant_id bigint NOT NULL,
|
||||
assistant_id bigint NOT NULL,
|
||||
time_window character varying(40) NOT NULL,
|
||||
category_code character varying(30) NOT NULL,
|
||||
category_name character varying(50) NOT NULL,
|
||||
short_name character varying(10) NOT NULL,
|
||||
duration_seconds bigint DEFAULT 0 NOT NULL,
|
||||
total_seconds bigint DEFAULT 0 NOT NULL,
|
||||
percentage numeric(5,4) DEFAULT 0 NOT NULL,
|
||||
is_tagged boolean DEFAULT false NOT NULL,
|
||||
computed_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE dws.dws_assistant_recharge_commission (
|
||||
id bigint DEFAULT nextval('dws.dws_assistant_recharge_commission_id_seq'::regclass) NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
@@ -700,6 +717,24 @@ CREATE TABLE dws.dws_member_newconv_index (
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE dws.dws_member_project_tag (
|
||||
id bigint DEFAULT nextval('dws.dws_member_project_tag_id_seq'::regclass) NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
tenant_id bigint NOT NULL,
|
||||
member_id bigint NOT NULL,
|
||||
time_window character varying(40) NOT NULL,
|
||||
category_code character varying(30) NOT NULL,
|
||||
category_name character varying(50) NOT NULL,
|
||||
short_name character varying(10) NOT NULL,
|
||||
duration_seconds bigint DEFAULT 0 NOT NULL,
|
||||
total_seconds bigint DEFAULT 0 NOT NULL,
|
||||
percentage numeric(5,4) DEFAULT 0 NOT NULL,
|
||||
is_tagged boolean DEFAULT false NOT NULL,
|
||||
computed_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE dws.dws_member_recall_index (
|
||||
recall_id bigint DEFAULT nextval('dws.dws_member_recall_index_recall_id_seq'::regclass) NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
@@ -774,14 +809,14 @@ CREATE TABLE dws.dws_member_visit_detail (
|
||||
actual_pay numeric(12,2) DEFAULT 0 NOT NULL,
|
||||
cash_pay numeric(12,2) DEFAULT 0 NOT NULL,
|
||||
balance_pay numeric(12,2) DEFAULT 0 NOT NULL,
|
||||
recharge_card_pay numeric(12,2) DEFAULT 0 NOT NULL,
|
||||
gift_card_pay numeric(12,2) DEFAULT 0 NOT NULL,
|
||||
groupbuy_pay numeric(12,2) DEFAULT 0 NOT NULL,
|
||||
table_duration_min integer DEFAULT 0 NOT NULL,
|
||||
assistant_duration_min integer DEFAULT 0 NOT NULL,
|
||||
assistant_services jsonb,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
recharge_card_pay numeric(12,2) DEFAULT 0 NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE dws.dws_member_winback_index (
|
||||
@@ -935,7 +970,6 @@ CREATE TABLE dws.dws_platform_settlement (
|
||||
|
||||
-- 约束(主键 / 唯一 / 外键)
|
||||
ALTER TABLE dws.cfg_area_category ADD CONSTRAINT cfg_area_category_pkey PRIMARY KEY (category_id);
|
||||
ALTER TABLE dws.cfg_area_category ADD CONSTRAINT uk_cfg_area_category UNIQUE (source_area_name);
|
||||
ALTER TABLE dws.cfg_assistant_level_price ADD CONSTRAINT cfg_assistant_level_price_pkey PRIMARY KEY (price_id);
|
||||
ALTER TABLE dws.cfg_assistant_level_price ADD CONSTRAINT uk_cfg_assistant_level_price UNIQUE (level_code, effective_from);
|
||||
ALTER TABLE dws.cfg_bonus_rules ADD CONSTRAINT cfg_bonus_rules_pkey PRIMARY KEY (rule_id);
|
||||
@@ -955,6 +989,8 @@ ALTER TABLE dws.dws_assistant_finance_analysis ADD CONSTRAINT uk_dws_assistant_f
|
||||
ALTER TABLE dws.dws_assistant_monthly_summary ADD CONSTRAINT dws_assistant_monthly_summary_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE dws.dws_assistant_monthly_summary ADD CONSTRAINT uk_dws_assistant_monthly UNIQUE (site_id, assistant_id, stat_month, assistant_level_code);
|
||||
ALTER TABLE dws.dws_assistant_order_contribution ADD CONSTRAINT dws_assistant_order_contribution_pkey PRIMARY KEY (contribution_id);
|
||||
ALTER TABLE dws.dws_assistant_project_tag ADD CONSTRAINT pk_dws_assistant_project_tag PRIMARY KEY (id);
|
||||
ALTER TABLE dws.dws_assistant_project_tag ADD CONSTRAINT uk_dws_assistant_project_tag UNIQUE (site_id, assistant_id, time_window, category_code);
|
||||
ALTER TABLE dws.dws_assistant_recharge_commission ADD CONSTRAINT dws_assistant_recharge_commission_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE dws.dws_assistant_salary_calc ADD CONSTRAINT dws_assistant_salary_calc_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE dws.dws_assistant_salary_calc ADD CONSTRAINT uk_dws_assistant_salary UNIQUE (site_id, assistant_id, salary_month, assistant_level_code);
|
||||
@@ -981,6 +1017,8 @@ ALTER TABLE dws.dws_member_consumption_summary ADD CONSTRAINT dws_member_consump
|
||||
ALTER TABLE dws.dws_member_consumption_summary ADD CONSTRAINT uk_dws_member_consumption UNIQUE (site_id, member_id, stat_date);
|
||||
ALTER TABLE dws.dws_member_newconv_index ADD CONSTRAINT dws_member_newconv_index_pkey PRIMARY KEY (newconv_id);
|
||||
ALTER TABLE dws.dws_member_newconv_index ADD CONSTRAINT uk_dws_member_newconv UNIQUE (site_id, member_id);
|
||||
ALTER TABLE dws.dws_member_project_tag ADD CONSTRAINT pk_dws_member_project_tag PRIMARY KEY (id);
|
||||
ALTER TABLE dws.dws_member_project_tag ADD CONSTRAINT uk_dws_member_project_tag UNIQUE (site_id, member_id, time_window, category_code);
|
||||
ALTER TABLE dws.dws_member_recall_index ADD CONSTRAINT dws_member_recall_index_pkey PRIMARY KEY (recall_id);
|
||||
ALTER TABLE dws.dws_member_recall_index ADD CONSTRAINT uk_dws_member_recall UNIQUE (site_id, member_id);
|
||||
ALTER TABLE dws.dws_member_spending_power_index ADD CONSTRAINT dws_member_spending_power_index_pkey PRIMARY KEY (spi_id);
|
||||
@@ -997,6 +1035,7 @@ ALTER TABLE dws.dws_platform_settlement ADD CONSTRAINT dws_platform_settlement_p
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_cfg_area_category_code ON dws.cfg_area_category USING btree (category_code);
|
||||
CREATE UNIQUE INDEX uk_cfg_area_category ON dws.cfg_area_category USING btree (source_area_name, COALESCE(source_table_name, ''::character varying));
|
||||
CREATE INDEX idx_cfg_assistant_level_price_effective ON dws.cfg_assistant_level_price USING btree (effective_from, effective_to);
|
||||
CREATE INDEX idx_cfg_bonus_rules_effective ON dws.cfg_bonus_rules USING btree (effective_from, effective_to);
|
||||
CREATE INDEX idx_cfg_bonus_rules_type ON dws.cfg_bonus_rules USING btree (rule_type);
|
||||
@@ -1017,6 +1056,7 @@ CREATE INDEX idx_dws_assistant_monthly_month ON dws.dws_assistant_monthly_summar
|
||||
CREATE INDEX idx_dws_assistant_monthly_tier ON dws.dws_assistant_monthly_summary USING btree (tier_code);
|
||||
CREATE UNIQUE INDEX idx_aoc_site_assistant_date ON dws.dws_assistant_order_contribution USING btree (site_id, assistant_id, stat_date);
|
||||
CREATE INDEX idx_aoc_stat_date ON dws.dws_assistant_order_contribution USING btree (site_id, stat_date);
|
||||
CREATE INDEX idx_apt_site_window_tagged ON dws.dws_assistant_project_tag USING btree (site_id, time_window) WHERE (is_tagged = true);
|
||||
CREATE INDEX idx_dws_assistant_commission_asst ON dws.dws_assistant_recharge_commission USING btree (assistant_id, commission_month);
|
||||
CREATE INDEX idx_dws_assistant_commission_batch ON dws.dws_assistant_recharge_commission USING btree (import_batch_no);
|
||||
CREATE INDEX idx_dws_assistant_commission_month ON dws.dws_assistant_recharge_commission USING btree (commission_month);
|
||||
@@ -1051,6 +1091,7 @@ CREATE INDEX idx_dws_member_consumption_date ON dws.dws_member_consumption_summa
|
||||
CREATE INDEX idx_dws_member_consumption_member ON dws.dws_member_consumption_summary USING btree (member_id, stat_date);
|
||||
CREATE INDEX idx_dws_member_consumption_tier ON dws.dws_member_consumption_summary USING btree (customer_tier);
|
||||
CREATE INDEX idx_dws_newconv_display ON dws.dws_member_newconv_index USING btree (site_id, display_score DESC);
|
||||
CREATE INDEX idx_mpt_site_window_tagged ON dws.dws_member_project_tag USING btree (site_id, time_window) WHERE (is_tagged = true);
|
||||
CREATE INDEX idx_dws_recall_display ON dws.dws_member_recall_index USING btree (site_id, display_score DESC);
|
||||
CREATE INDEX idx_spi_display_score ON dws.dws_member_spending_power_index USING btree (site_id, display_score DESC);
|
||||
CREATE UNIQUE INDEX idx_spi_site_member ON dws.dws_member_spending_power_index USING btree (site_id, member_id);
|
||||
@@ -1317,7 +1358,7 @@ SELECT id,
|
||||
platform_fee_amount,
|
||||
recharge_cash_inflow,
|
||||
card_consume_total,
|
||||
recharge_card_consume,
|
||||
recharge_card_consume AS cash_card_consume,
|
||||
gift_card_consume,
|
||||
cash_outflow_total,
|
||||
cash_balance_change,
|
||||
@@ -1364,7 +1405,7 @@ SELECT id,
|
||||
platform_fee_amount,
|
||||
recharge_cash_inflow,
|
||||
card_consume_total,
|
||||
recharge_card_consume,
|
||||
recharge_card_consume AS cash_card_consume,
|
||||
gift_card_consume,
|
||||
cash_outflow_total,
|
||||
cash_balance_change,
|
||||
@@ -1411,7 +1452,7 @@ SELECT id,
|
||||
platform_fee_amount,
|
||||
recharge_cash_inflow,
|
||||
card_consume_total,
|
||||
recharge_card_consume,
|
||||
recharge_card_consume AS cash_card_consume,
|
||||
gift_card_consume,
|
||||
cash_outflow_total,
|
||||
cash_balance_change,
|
||||
@@ -1458,7 +1499,7 @@ SELECT id,
|
||||
platform_fee_amount,
|
||||
recharge_cash_inflow,
|
||||
card_consume_total,
|
||||
recharge_card_consume,
|
||||
recharge_card_consume AS cash_card_consume,
|
||||
gift_card_consume,
|
||||
cash_outflow_total,
|
||||
cash_balance_change,
|
||||
@@ -1491,68 +1532,624 @@ CREATE INDEX idx_mv_finance_daily_l3 ON dws.mv_dws_finance_daily_summary_l3 USIN
|
||||
CREATE INDEX idx_mv_finance_daily_l4 ON dws.mv_dws_finance_daily_summary_l4 USING btree (site_id, stat_date);
|
||||
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 项目标签表(2026-03-07 新增)
|
||||
-- 种子数据:DWS 配置表初始数据(绩效档位、等级定价、奖金规则、区域分类、技能映射)
|
||||
-- =============================================================================
|
||||
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_assistant_project_tag_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS dws.dws_member_project_tag_id_seq AS bigint;
|
||||
-- =============================================================================
|
||||
-- DWS 配置表初始数据
|
||||
-- 版本: v4.0
|
||||
-- 创建日期: 2026-02-01
|
||||
-- 更新日期: 2026-02-21
|
||||
-- AI_CHANGELOG [2026-02-21] 取消全文注释,数据已写入 test_etl_feiqiu;
|
||||
-- 新增 2025-01-01~2026-02-28 统一提成档位(基础课18元/小时,打赏课40%);
|
||||
-- 新增 GUARANTEE 保底奖金规则(按等级:初级12000/中级16000/高级18000/星级23000);
|
||||
-- 历史分档口径截止日期调整为 2024-12-31
|
||||
-- 描述: 初始化配置表数据,包含绩效档位、等级定价、奖金规则、区域分类、技能映射
|
||||
-- =============================================================================
|
||||
|
||||
CREATE TABLE dws.dws_assistant_project_tag (
|
||||
id BIGSERIAL NOT NULL,
|
||||
site_id BIGINT NOT NULL,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
assistant_id BIGINT NOT NULL,
|
||||
time_window VARCHAR(40) NOT NULL,
|
||||
category_code VARCHAR(30) NOT NULL,
|
||||
category_name VARCHAR(50) NOT NULL,
|
||||
short_name VARCHAR(10) NOT NULL,
|
||||
duration_seconds BIGINT NOT NULL DEFAULT 0,
|
||||
total_seconds BIGINT NOT NULL DEFAULT 0,
|
||||
percentage NUMERIC(5,4) NOT NULL DEFAULT 0,
|
||||
is_tagged BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT pk_dws_assistant_project_tag PRIMARY KEY (id),
|
||||
CONSTRAINT uk_dws_assistant_project_tag
|
||||
UNIQUE (site_id, assistant_id, time_window, category_code)
|
||||
);
|
||||
-- =============================================================================
|
||||
-- 1. cfg_performance_tier - 绩效档位配置(含历史口径)
|
||||
-- 数据来源:DWS 数据库处理需求.md
|
||||
-- 三段时间线:
|
||||
-- 2000-01-01 ~ 2024-12-31: 旧方案(6档阶梯抽成)
|
||||
-- 2025-01-01 ~ 2026-02-28: 统一提成(不分档,基础课18元/小时,打赏课40%)
|
||||
-- 2026-03-01 ~ 9999-12-31: 新方案(5档阶梯抽成)
|
||||
-- =============================================================================
|
||||
TRUNCATE TABLE dws.cfg_performance_tier RESTART IDENTITY CASCADE;
|
||||
|
||||
COMMENT ON TABLE dws.dws_assistant_project_tag IS '助教项目标签:按时间窗口计算各项目时长占比,≥25%分配标签';
|
||||
COMMENT ON COLUMN dws.dws_assistant_project_tag.time_window IS '时间窗口:THIS_MONTH/THIS_QUARTER/LAST_MONTH/LAST_3_MONTHS_EXCL_CURRENT/LAST_QUARTER/LAST_6_MONTHS';
|
||||
COMMENT ON COLUMN dws.dws_assistant_project_tag.is_tagged IS '占比≥0.25时为TRUE,表示该助教拥有此项目标签';
|
||||
INSERT INTO dws.cfg_performance_tier (
|
||||
tier_code, tier_name, tier_level,
|
||||
min_hours, max_hours,
|
||||
base_deduction, bonus_deduction_ratio, vacation_days, vacation_unlimited,
|
||||
is_new_hire_tier, effective_from, effective_to, description
|
||||
) VALUES
|
||||
-- 旧方案(至2024-12-31)
|
||||
('T0', '0档-淘汰压力', 0,
|
||||
0, 100,
|
||||
28.00, 0.50, 3, FALSE,
|
||||
FALSE, '2000-01-01', '2024-12-31',
|
||||
'旧方案:H<100,专业课抽成28元/小时,打赏课抽成50%,休假3天'),
|
||||
('T1', '1档-及格档', 1,
|
||||
100, 130,
|
||||
18.00, 0.40, 4, FALSE,
|
||||
FALSE, '2000-01-01', '2024-12-31',
|
||||
'旧方案:100≤H<130,专业课抽成18元/小时,打赏课抽成40%,休假4天'),
|
||||
('T2', '2档-良好档', 2,
|
||||
130, 160,
|
||||
15.00, 0.38, 4, FALSE,
|
||||
FALSE, '2000-01-01', '2024-12-31',
|
||||
'旧方案:130≤H<160,专业课抽成15元/小时,打赏课抽成38%,休假4天'),
|
||||
('T3', '3档-优秀档', 3,
|
||||
160, 190,
|
||||
13.00, 0.35, 5, FALSE,
|
||||
FALSE, '2000-01-01', '2024-12-31',
|
||||
'旧方案:160≤H<190,专业课抽成13元/小时,打赏课抽成35%,休假5天'),
|
||||
('T4', '4档-卓越加速档', 4,
|
||||
190, 220,
|
||||
10.00, 0.33, 6, FALSE,
|
||||
FALSE, '2000-01-01', '2024-12-31',
|
||||
'旧方案:190≤H<220,专业课抽成10元/小时,打赏课抽成33%,休假6天'),
|
||||
('T5', '5档-冠军加速档', 5,
|
||||
220, NULL,
|
||||
8.00, 0.30, 0, TRUE,
|
||||
FALSE, '2000-01-01', '2024-12-31',
|
||||
'旧方案:H≥220,专业课抽成8元/小时,打赏课抽成30%,休假自由'),
|
||||
|
||||
CREATE TABLE dws.dws_member_project_tag (
|
||||
id BIGSERIAL NOT NULL,
|
||||
site_id BIGINT NOT NULL,
|
||||
tenant_id BIGINT NOT NULL,
|
||||
member_id BIGINT NOT NULL,
|
||||
time_window VARCHAR(40) NOT NULL,
|
||||
category_code VARCHAR(30) NOT NULL,
|
||||
category_name VARCHAR(50) NOT NULL,
|
||||
short_name VARCHAR(10) NOT NULL,
|
||||
duration_seconds BIGINT NOT NULL DEFAULT 0,
|
||||
total_seconds BIGINT NOT NULL DEFAULT 0,
|
||||
percentage NUMERIC(5,4) NOT NULL DEFAULT 0,
|
||||
is_tagged BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
computed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT pk_dws_member_project_tag PRIMARY KEY (id),
|
||||
CONSTRAINT uk_dws_member_project_tag
|
||||
UNIQUE (site_id, member_id, time_window, category_code)
|
||||
);
|
||||
-- 2025-01-01 ~ 2026-02-28: 统一提成(不分档,所有助教统一规则)
|
||||
-- CHANGE 2026-02-21 | 新增统一提成档位,基础课球房提成18元/小时,打赏课球房提成40%
|
||||
('T0', '统一档', 0,
|
||||
0, NULL,
|
||||
18.00, 0.40, 0, FALSE,
|
||||
FALSE, '2025-01-01', '2026-02-28',
|
||||
'2025-01-01~2026-02-28统一规则:基础课球房提成18元/小时,打赏课球房提成40%,不分档位'),
|
||||
|
||||
COMMENT ON TABLE dws.dws_member_project_tag IS '客户项目标签:按时间窗口计算各项目消费时长占比,≥25%分配标签';
|
||||
COMMENT ON COLUMN dws.dws_member_project_tag.time_window IS '时间窗口:LAST_30_DAYS/LAST_60_DAYS';
|
||||
COMMENT ON COLUMN dws.dws_member_project_tag.is_tagged IS '占比≥0.25时为TRUE,表示该客户拥有此项目标签';
|
||||
-- 新方案(2026-03-01起)
|
||||
('T0', '0档-淘汰压力', 0,
|
||||
0, 120,
|
||||
28.00, 0.50, 3, FALSE,
|
||||
FALSE, '2026-03-01', '9999-12-31',
|
||||
'新方案:H<120,专业课抽成28元/小时,打赏课抽成50%,休假3天'),
|
||||
('T1', '1档-及格档', 1,
|
||||
120, 150,
|
||||
18.00, 0.40, 4, FALSE,
|
||||
FALSE, '2026-03-01', '9999-12-31',
|
||||
'新方案:120≤H<150,专业课抽成18元/小时,打赏课抽成40%,休假4天'),
|
||||
('T2', '2档-良好档', 2,
|
||||
150, 180,
|
||||
13.00, 0.35, 5, FALSE,
|
||||
FALSE, '2026-03-01', '9999-12-31',
|
||||
'新方案:150≤H<180,专业课抽成13元/小时,打赏课抽成35%,休假5天'),
|
||||
('T3', '3档-优秀档', 3,
|
||||
180, 210,
|
||||
10.00, 0.30, 6, FALSE,
|
||||
FALSE, '2026-03-01', '9999-12-31',
|
||||
'新方案:180≤H<210,专业课抽成10元/小时,打赏课抽成30%,休假6天'),
|
||||
('T4', '4档-销冠竞争', 4,
|
||||
210, NULL,
|
||||
8.00, 0.25, 0, TRUE,
|
||||
FALSE, '2026-03-01', '9999-12-31',
|
||||
'新方案:H≥210,专业课抽成8元/小时,打赏课抽成25%,休假自由');
|
||||
|
||||
-- 部分索引(加速看板查询)
|
||||
CREATE INDEX idx_apt_site_window_tagged
|
||||
ON dws.dws_assistant_project_tag (site_id, time_window)
|
||||
WHERE is_tagged = TRUE;
|
||||
|
||||
CREATE INDEX idx_mpt_site_window_tagged
|
||||
ON dws.dws_member_project_tag (site_id, time_window)
|
||||
WHERE is_tagged = TRUE;
|
||||
-- =============================================================================
|
||||
-- 2. cfg_assistant_level_price - 助教等级定价
|
||||
-- 说明:
|
||||
-- - level_code 来自 dim_assistant.assistant_level
|
||||
-- - 8=助教管理, 10=初级, 20=中级, 30=高级, 40=星级
|
||||
-- - 价格为客户支付价格(对外价格),助教收入=客户支付-档位抽成
|
||||
-- - 包厢课基础课统一138元/小时(不随等级变化)
|
||||
-- =============================================================================
|
||||
TRUNCATE TABLE dws.cfg_assistant_level_price RESTART IDENTITY CASCADE;
|
||||
|
||||
INSERT INTO dws.cfg_assistant_level_price (
|
||||
level_code, level_name,
|
||||
base_course_price, bonus_course_price,
|
||||
effective_from, effective_to, description
|
||||
) VALUES
|
||||
(10, '初级',
|
||||
98.00, 190.00,
|
||||
'2000-01-01', '9999-12-31',
|
||||
'初级助教:基础课98元/时,附加课190元/时(客户支付价格)'),
|
||||
(20, '中级',
|
||||
108.00, 190.00,
|
||||
'2000-01-01', '9999-12-31',
|
||||
'中级助教:基础课108元/时,附加课190元/时(客户支付价格)'),
|
||||
(30, '高级',
|
||||
118.00, 190.00,
|
||||
'2000-01-01', '9999-12-31',
|
||||
'高级助教:基础课118元/时,附加课190元/时(客户支付价格)'),
|
||||
(40, '星级',
|
||||
138.00, 190.00,
|
||||
'2000-01-01', '9999-12-31',
|
||||
'星级助教:基础课138元/时,附加课190元/时(客户支付价格)'),
|
||||
(8, '助教管理',
|
||||
98.00, 190.00,
|
||||
'2000-01-01', '9999-12-31',
|
||||
'助教管理:不参与客户服务计费,默认按初级价格');
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 3. cfg_bonus_rules - 奖金规则配置
|
||||
-- 说明:
|
||||
-- - SPRINT: 冲刺奖金(历史口径,至2024-12-31)
|
||||
-- - GUARANTEE: 保底月薪线(2025-01-01~2026-02-28,按等级区分)
|
||||
-- * 保底规则:总课时达标 + 打赏课≥10小时 → 触发保底月薪线
|
||||
-- * 保底含义:实发 = MAX(课时收入+奖金, 保底金额),非额外奖金
|
||||
-- * rule_code 中 LV10/LV20/LV30/LV40 对应 level_code
|
||||
-- - TOP_RANK: Top3排名奖金(2026-03-01起)
|
||||
-- CHANGE 2026-02-21 | 新增 GUARANTEE 保底奖金规则
|
||||
-- =============================================================================
|
||||
TRUNCATE TABLE dws.cfg_bonus_rules RESTART IDENTITY CASCADE;
|
||||
|
||||
INSERT INTO dws.cfg_bonus_rules (
|
||||
rule_type, rule_code, rule_name,
|
||||
threshold_hours, rank_position, bonus_amount,
|
||||
is_cumulative, priority,
|
||||
effective_from, effective_to, description
|
||||
) VALUES
|
||||
-- 冲刺奖金(历史口径,至2024-12-31)
|
||||
('SPRINT', 'SPRINT_190', '冲刺奖金190',
|
||||
190.00, NULL, 300.00,
|
||||
FALSE, 1,
|
||||
'2000-01-01', '2024-12-31',
|
||||
'历史口径:业绩≥190小时,获得300元冲刺奖金(不累计)'),
|
||||
('SPRINT', 'SPRINT_220', '冲刺奖金220',
|
||||
220.00, NULL, 800.00,
|
||||
FALSE, 2,
|
||||
'2000-01-01', '2024-12-31',
|
||||
'历史口径:业绩≥220小时,获得800元冲刺奖金(覆盖190档)'),
|
||||
|
||||
-- 保底奖金(2025-01-01 ~ 2026-02-28)
|
||||
-- 按助教等级区分,需同时满足总课时和打赏课最低时数(≥10小时)
|
||||
('GUARANTEE', 'GUAR_LV10', '初级保底奖金',
|
||||
130.00, NULL, 12000.00,
|
||||
FALSE, 10,
|
||||
'2025-01-01', '2026-02-28',
|
||||
'初级保底:完成130小时课程(含≥10小时打赏课),保底月薪线12000元(实发=MAX(课时收入+奖金, 12000))'),
|
||||
('GUARANTEE', 'GUAR_LV20', '中级保底奖金',
|
||||
150.00, NULL, 16000.00,
|
||||
FALSE, 20,
|
||||
'2025-01-01', '2026-02-28',
|
||||
'中级保底:完成150小时课程(含≥10小时打赏课),保底月薪线16000元(实发=MAX(课时收入+奖金, 16000))'),
|
||||
('GUARANTEE', 'GUAR_LV30', '高级保底奖金',
|
||||
160.00, NULL, 18000.00,
|
||||
FALSE, 30,
|
||||
'2025-01-01', '2026-02-28',
|
||||
'高级保底:完成160小时课程(含≥10小时打赏课),保底月薪线18000元(实发=MAX(课时收入+奖金, 18000))'),
|
||||
('GUARANTEE', 'GUAR_LV40', '星级保底奖金',
|
||||
170.00, NULL, 23000.00,
|
||||
FALSE, 40,
|
||||
'2025-01-01', '2026-02-28',
|
||||
'星级保底:完成170小时课程(含≥10小时打赏课),保底月薪线23000元(实发=MAX(课时收入+奖金, 23000))'),
|
||||
|
||||
-- Top排名奖金(2026-03-01起)
|
||||
('TOP_RANK', 'TOP_1', 'Top1排名奖金',
|
||||
NULL, 1, 1000.00,
|
||||
FALSE, 0,
|
||||
'2026-03-01', '9999-12-31',
|
||||
'月度排名第一,获得1000元(并列都算)'),
|
||||
('TOP_RANK', 'TOP_2', 'Top2排名奖金',
|
||||
NULL, 2, 600.00,
|
||||
FALSE, 0,
|
||||
'2026-03-01', '9999-12-31',
|
||||
'月度排名第二,获得600元(并列都算)'),
|
||||
('TOP_RANK', 'TOP_3', 'Top3排名奖金',
|
||||
NULL, 3, 400.00,
|
||||
FALSE, 0,
|
||||
'2026-03-01', '9999-12-31',
|
||||
'月度排名第三,获得400元(并列都算)');
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 4. cfg_area_category - 台区分类映射(纯台桌级精确映射)
|
||||
-- 说明:
|
||||
-- - 每台桌一行精确映射,source_area_name=区域, source_table_name=台桌名
|
||||
-- - 不使用 LIKE 模糊匹配,仅 EXACT + DEFAULT 兜底
|
||||
-- - 数据来源: 用户提供的完整台桌清单(2026-03-09)
|
||||
-- =============================================================================
|
||||
TRUNCATE TABLE dws.cfg_area_category RESTART IDENTITY CASCADE;
|
||||
|
||||
INSERT INTO dws.cfg_area_category (
|
||||
source_area_name, source_table_name, category_code, category_name,
|
||||
display_name, short_name,
|
||||
match_type, match_priority, is_active, description
|
||||
) VALUES
|
||||
-- ============ BILLIARD 🎱 中式/追分 ============
|
||||
-- A区(18台)
|
||||
('A区', 'A1', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A1'),
|
||||
('A区', 'A2', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A2'),
|
||||
('A区', 'A3', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A3'),
|
||||
('A区', 'A4', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A4'),
|
||||
('A区', 'A5', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A5'),
|
||||
('A区', 'A6', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A6'),
|
||||
('A区', 'A7', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A7'),
|
||||
('A区', 'A8', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A8'),
|
||||
('A区', 'A9', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A9'),
|
||||
('A区', 'A10', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A10'),
|
||||
('A区', 'A11', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A11'),
|
||||
('A区', 'A12', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A12'),
|
||||
('A区', 'A13', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A13'),
|
||||
('A区', 'A14', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A14'),
|
||||
('A区', 'A15', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A15'),
|
||||
('A区', 'A16', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A16'),
|
||||
('A区', 'A17', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A17'),
|
||||
('A区', 'A18', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'A区-A18'),
|
||||
-- B区(15台)
|
||||
('B区', 'B1', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B1'),
|
||||
('B区', 'B2', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B2'),
|
||||
('B区', 'B3', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B3'),
|
||||
('B区', 'B4', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B4'),
|
||||
('B区', 'B5', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B5'),
|
||||
('B区', 'B6', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B6'),
|
||||
('B区', 'B7', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B7'),
|
||||
('B区', 'B8', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B8'),
|
||||
('B区', 'B9', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B9'),
|
||||
('B区', 'B10', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B10'),
|
||||
('B区', 'B11', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B11'),
|
||||
('B区', 'B12', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B12'),
|
||||
('B区', 'B13', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B13'),
|
||||
('B区', 'B14', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B14'),
|
||||
('B区', 'B15', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'B区-B15'),
|
||||
-- C区(6台)
|
||||
('C区', 'C1', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'C区-C1'),
|
||||
('C区', 'C2', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'C区-C2'),
|
||||
('C区', 'C3', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'C区-C3'),
|
||||
('C区', 'C4', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'C区-C4'),
|
||||
('C区', 'C5', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'C区-C5'),
|
||||
('C区', 'C6', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'C区-C6'),
|
||||
-- VIP包厢 BILLIARD(3台)
|
||||
('VIP包厢', 'VIP1', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'VIP包厢-VIP1'),
|
||||
('VIP包厢', 'VIP2', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'VIP包厢-VIP2'),
|
||||
('VIP包厢', 'VIP3', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'VIP包厢-VIP3'),
|
||||
-- TV台(1台)
|
||||
('TV台', 'TV', 'BILLIARD', '🎱 中式/追分', '🎱 中式/追分', '🎱', 'EXACT', 10, TRUE, 'TV台-TV'),
|
||||
-- ============ SNOOKER 斯诺克 ============
|
||||
('VIP包厢', 'VIP5', 'SNOOKER', '斯诺克', '斯诺克', '斯', 'EXACT', 10, TRUE, 'VIP包厢-VIP5→斯诺克'),
|
||||
('斯诺克区', 'S1', 'SNOOKER', '斯诺克', '斯诺克', '斯', 'EXACT', 10, TRUE, '斯诺克区-S1'),
|
||||
('斯诺克区', 'S2', 'SNOOKER', '斯诺克', '斯诺克', '斯', 'EXACT', 10, TRUE, '斯诺克区-S2'),
|
||||
('斯诺克区', 'S3', 'SNOOKER', '斯诺克', '斯诺克', '斯', 'EXACT', 10, TRUE, '斯诺克区-S3'),
|
||||
('斯诺克区', 'S4', 'SNOOKER', '斯诺克', '斯诺克', '斯', 'EXACT', 10, TRUE, '斯诺克区-S4'),
|
||||
-- ============ MAHJONG 🀄 麻将/棋牌 ============
|
||||
('666', '董事办', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '666-董事办'),
|
||||
('666', '666', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '666-666'),
|
||||
('麻将房', 'M1', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '麻将房-M1'),
|
||||
('麻将房', 'M2', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '麻将房-M2'),
|
||||
('麻将房', 'M3', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '麻将房-M3'),
|
||||
('麻将房', 'M4', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '麻将房-M4'),
|
||||
('麻将房', 'M5', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '麻将房-M5'),
|
||||
('M7', 'M7', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, 'M7-M7'),
|
||||
('M7', '大包麻将房', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, 'M7-大包麻将房'),
|
||||
('M8', 'M8', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, 'M8-M8'),
|
||||
('发财', '发财', 'MAHJONG', '🀄 麻将/棋牌', '🀄 麻将/棋牌', '🀄', 'EXACT', 10, TRUE, '发财-发财'),
|
||||
-- ============ KTV 🎤 团建/K歌 ============
|
||||
('K包', '常乐', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, 'K包-常乐'),
|
||||
('K包', '幸会(纯k)', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, 'K包-幸会(纯k)'),
|
||||
('K包', '虚拟188', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, 'K包-虚拟188'),
|
||||
('K包', '888', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, 'K包-888'),
|
||||
('k包活动区', '大包', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, 'k包活动区-大包'),
|
||||
('k包活动区', '小包', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, 'k包活动区-小包'),
|
||||
('幸会158', '纯k', 'KTV', '🎤 团建/K歌', '🎤 团建/K歌', '🎤', 'EXACT', 10, TRUE, '幸会158-纯k'),
|
||||
-- ============ SPECIAL 补时长/虚拟台 ============
|
||||
('补时长', '补时长', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长'),
|
||||
('补时长', '补时长2', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长2'),
|
||||
('补时长', '补时长3', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长3'),
|
||||
('补时长', '补时长4', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长4'),
|
||||
('补时长', '补时长5', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长5'),
|
||||
('补时长', '补时长6', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长6'),
|
||||
('补时长', '补时长7', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '补时长-补时长7'),
|
||||
('虚拟台', '虚拟台1号', 'SPECIAL', '补时长', '补时长', '补', 'EXACT', 10, TRUE, '虚拟台-虚拟台1号'),
|
||||
-- ============ OTHER 兜底 ============
|
||||
('DEFAULT', NULL, 'OTHER', '其他', '其他', '他', 'DEFAULT', 999, TRUE, '兜底规则:无法匹配的归入其他');
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 5. cfg_skill_type - 技能→课程类型映射
|
||||
-- 说明:
|
||||
-- - 将 skill_id 映射到课程类型
|
||||
-- - 基础课/陪打: skill_id = 2791903611396869
|
||||
-- - 附加课/超休: skill_id = 2807440316432197
|
||||
-- - 避免依赖 skill_name 文本匹配
|
||||
-- =============================================================================
|
||||
TRUNCATE TABLE dws.cfg_skill_type RESTART IDENTITY CASCADE;
|
||||
|
||||
INSERT INTO dws.cfg_skill_type (
|
||||
skill_id, skill_name,
|
||||
course_type_code, course_type_name,
|
||||
is_active, description
|
||||
) VALUES
|
||||
(2791903611396869, '台球基础陪打',
|
||||
'BASE', '基础课',
|
||||
TRUE, '基础课:陪打服务,按助教等级计价'),
|
||||
(2807440316432197, '台球超休服务',
|
||||
'BONUS', '附加课',
|
||||
TRUE, '附加课:超休/激励课,固定190元/小时'),
|
||||
(2807440316432198, '包厢服务',
|
||||
'BASE', '基础课',
|
||||
TRUE, '包厢服务:归入基础课统计,统一按138元/小时计价');
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 6~8. 优惠类型/支出类型/平台类型 — 作为代码常量使用,不单独建表
|
||||
-- =============================================================================
|
||||
-- 优惠类型: GROUPBUY/VIP/GIFT_CARD/MANUAL/ROUNDING/BIG_CUSTOMER/OTHER
|
||||
-- 支出类型: RENT/UTILITY/PROPERTY/SALARY/REIMBURSE/PLATFORM_FEE/OTHER
|
||||
-- 平台类型: MEITUAN/DOUYIN/DIANPING/OTHER
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证数据插入
|
||||
-- =============================================================================
|
||||
DO $
|
||||
DECLARE
|
||||
v_tier_count INTEGER;
|
||||
v_price_count INTEGER;
|
||||
v_bonus_count INTEGER;
|
||||
v_area_count INTEGER;
|
||||
v_skill_count INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO v_tier_count FROM dws.cfg_performance_tier;
|
||||
SELECT COUNT(*) INTO v_price_count FROM dws.cfg_assistant_level_price;
|
||||
SELECT COUNT(*) INTO v_bonus_count FROM dws.cfg_bonus_rules;
|
||||
SELECT COUNT(*) INTO v_area_count FROM dws.cfg_area_category;
|
||||
SELECT COUNT(*) INTO v_skill_count FROM dws.cfg_skill_type;
|
||||
|
||||
RAISE NOTICE '配置数据初始化完成:';
|
||||
RAISE NOTICE ' - cfg_performance_tier: % 条', v_tier_count;
|
||||
RAISE NOTICE ' - cfg_assistant_level_price: % 条', v_price_count;
|
||||
RAISE NOTICE ' - cfg_bonus_rules: % 条', v_bonus_count;
|
||||
RAISE NOTICE ' - cfg_area_category: % 条', v_area_count;
|
||||
RAISE NOTICE ' - cfg_skill_type: % 条', v_skill_count;
|
||||
END;
|
||||
$;
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:指数算法参数(NCI/WBI/RS/OS/MS/ML/SPI)
|
||||
-- =============================================================================
|
||||
|
||||
-- =============================================================================
|
||||
-- 指数算法参数初始化脚本
|
||||
-- 版本: v3.0
|
||||
-- 创建日期: 2026-02-13
|
||||
-- 描述: 仅保留 RS / OS / MS / ML / NCI / WBI 指数参数(已移除 RECALL / INTIMACY)
|
||||
-- AI_CHANGELOG [2026-02-13] 移除 RECALL/INTIMACY 参数及 ML 废弃参数(source_mode/recharge_attribute_hours)
|
||||
-- =============================================================================
|
||||
|
||||
-- 清理旧版指数参数
|
||||
DELETE FROM dws.cfg_index_parameters WHERE index_type IN ('RECALL', 'INTIMACY');
|
||||
-- 清理 ML 已废弃参数
|
||||
DELETE FROM dws.cfg_index_parameters WHERE index_type = 'ML' AND param_name IN ('source_mode', 'recharge_attribute_hours');
|
||||
|
||||
INSERT INTO dws.cfg_index_parameters
|
||||
(index_type, param_name, param_value, description, effective_from)
|
||||
VALUES
|
||||
('NCI', 'active_new_penalty', 0.200000, 'active-new suppression multiplier', DATE '2026-02-06'),
|
||||
('NCI', 'active_new_recency_days', 7.000000, 'active-new recency window (days)', DATE '2026-02-06'),
|
||||
('NCI', 'active_new_visit_threshold_14d', 2.000000, 'active-new threshold in 14d visits', DATE '2026-02-06'),
|
||||
('NCI', 'amount_base_M0', 300.000000, 'spend log base M0', DATE '2026-02-06'),
|
||||
('NCI', 'balance_base_B0', 500.000000, 'balance log base B0', DATE '2026-02-06'),
|
||||
('NCI', 'compression_mode', 0.000000, 'compression mode', DATE '2026-02-06'),
|
||||
('NCI', 'enable_stop_high_balance_exception', 0.000000, 'enable high-balance STOP exception', DATE '2026-02-06'),
|
||||
('NCI', 'ewma_alpha', 0.200000, 'EWMA alpha', DATE '2026-02-06'),
|
||||
('NCI', 'h_recharge', 7.000000, 'recharge decay half-life (days)', DATE '2026-02-06'),
|
||||
('NCI', 'high_balance_threshold', 1000.000000, 'high-balance threshold', DATE '2026-02-06'),
|
||||
('NCI', 'lookback_days_recency', 60.000000, 'recency lookback window (days)', DATE '2026-02-06'),
|
||||
('NCI', 'new_days_threshold', 30.000000, 'new member days threshold', DATE '2026-02-06'),
|
||||
('NCI', 'new_recharge_max_visits', 10.000000, 'max visits for new-recharge grouping', DATE '2026-02-06'),
|
||||
('NCI', 'new_visit_threshold', 2.000000, 'new member visit threshold', DATE '2026-02-06'),
|
||||
('NCI', 'no_touch_days_new', 3.000000, 'no-touch threshold (days)', DATE '2026-02-06'),
|
||||
('NCI', 'percentile_lower', 5.000000, 'lower percentile', DATE '2026-02-06'),
|
||||
('NCI', 'percentile_upper', 95.000000, 'upper percentile', DATE '2026-02-06'),
|
||||
('NCI', 'recharge_recent_days', 14.000000, 'recent recharge window (days)', DATE '2026-02-06'),
|
||||
('NCI', 'salvage_end', 60.000000, 'salvage decay end day', DATE '2026-02-06'),
|
||||
('NCI', 'salvage_start', 30.000000, 'salvage decay start day', DATE '2026-02-06'),
|
||||
('NCI', 't2_target_days', 7.000000, 'second-visit target window (days)', DATE '2026-02-06'),
|
||||
('NCI', 'use_smoothing', 1.000000, 'enable smoothing', DATE '2026-02-06'),
|
||||
('NCI', 'value_w_bal', 0.800000, 'value weight for balance', DATE '2026-02-06'),
|
||||
('NCI', 'value_w_spend', 1.000000, 'value weight for spend', DATE '2026-02-06'),
|
||||
('NCI', 'visit_lookback_days', 180.000000, 'visit history lookback (days)', DATE '2026-02-06'),
|
||||
('NCI', 'w_need', 1.600000, 'need weight', DATE '2026-02-06'),
|
||||
('NCI', 'w_re', 0.800000, 'recharge pressure weight', DATE '2026-02-06'),
|
||||
('NCI', 'w_value', 1.000000, 'value weight', DATE '2026-02-06'),
|
||||
('NCI', 'w_welcome', 1.000000, 'welcome-stage weight', DATE '2026-02-06'),
|
||||
('NCI', 'welcome_window_days', 3.000000, 'welcome outreach window for first touch (days)', DATE '2026-02-06'),
|
||||
('WBI', 'amount_base_M0', 300.000000, 'spend log base M0', DATE '2026-02-06'),
|
||||
('WBI', 'balance_base_B0', 500.000000, 'balance log base B0', DATE '2026-02-06'),
|
||||
('WBI', 'compression_mode', 0.000000, 'compression mode', DATE '2026-02-06'),
|
||||
('WBI', 'enable_stop_high_balance_exception', 0.000000, 'enable high-balance STOP exception', DATE '2026-02-06'),
|
||||
('WBI', 'ewma_alpha', 0.200000, 'EWMA alpha', DATE '2026-02-06'),
|
||||
('WBI', 'h_recharge', 7.000000, 'recharge decay half-life (days)', DATE '2026-02-06'),
|
||||
('WBI', 'high_balance_threshold', 1000.000000, 'high-balance threshold', DATE '2026-02-06'),
|
||||
('WBI', 'lookback_days_recency', 60.000000, 'recency lookback window (days)', DATE '2026-02-06'),
|
||||
('WBI', 'new_days_threshold', 30.000000, 'new member days threshold', DATE '2026-02-06'),
|
||||
('WBI', 'new_recharge_max_visits', 10.000000, 'max visits for new-recharge grouping', DATE '2026-02-06'),
|
||||
('WBI', 'new_visit_threshold', 2.000000, 'new member visit threshold', DATE '2026-02-06'),
|
||||
('WBI', 'overdue_alpha', 2.000000, 'overdue fallback alpha', DATE '2026-02-06'),
|
||||
('WBI', 'overdue_weight_blend_min_samples', 8.000000, 'minimum samples to fully trust weighted overdue CDF', DATE '2026-02-07'),
|
||||
('WBI', 'overdue_weight_halflife_days', 30.000000, 'overdue weighted-CDF interval half-life (days)', DATE '2026-02-07'),
|
||||
('WBI', 'percentile_lower', 5.000000, 'lower percentile', DATE '2026-02-06'),
|
||||
('WBI', 'percentile_upper', 95.000000, 'upper percentile', DATE '2026-02-06'),
|
||||
('WBI', 'recency_gate_days', 14.000000, 'recency suppression gate center (days)', DATE '2026-02-06'),
|
||||
('WBI', 'recency_gate_slope_days', 3.000000, 'recency suppression slope (days)', DATE '2026-02-06'),
|
||||
('WBI', 'recency_hard_floor_days', 14.000000, 'hard floor for winback recency (days)', DATE '2026-02-06'),
|
||||
('WBI', 'recharge_recent_days', 14.000000, 'recent recharge window (days)', DATE '2026-02-06'),
|
||||
('WBI', 'use_smoothing', 1.000000, 'enable smoothing', DATE '2026-02-06'),
|
||||
('WBI', 'value_w_bal', 1.000000, 'value weight for balance', DATE '2026-02-06'),
|
||||
('WBI', 'value_w_spend', 1.000000, 'value weight for spend', DATE '2026-02-06'),
|
||||
('WBI', 'visit_lookback_days', 180.000000, 'visit history lookback (days)', DATE '2026-02-06'),
|
||||
('WBI', 'w_drop', 1.000000, 'drop weight', DATE '2026-02-06'),
|
||||
('WBI', 'w_over', 2.000000, 'overdue weight', DATE '2026-02-06'),
|
||||
('WBI', 'w_re', 0.400000, 'recharge pressure weight', DATE '2026-02-06'),
|
||||
('WBI', 'w_value', 1.200000, 'value weight', DATE '2026-02-06')
|
||||
ON CONFLICT (index_type, param_name, effective_from) DO UPDATE SET
|
||||
param_value = EXCLUDED.param_value,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = NOW();
|
||||
|
||||
-- =============================================================================
|
||||
-- 关系指数(RS/OS/MS/ML)参数
|
||||
-- 生效时间:北京时间 2026-01-01(按数据库日期管理)
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO dws.cfg_index_parameters
|
||||
(index_type, param_name, param_value, description, effective_from)
|
||||
VALUES
|
||||
-- RS(关系强度)
|
||||
('RS', 'lookback_days', 60.000000, '服务行为回溯窗口(天)', DATE '2026-01-01'),
|
||||
('RS', 'session_merge_hours', 4.000000, '会话合并阈值(小时)', DATE '2026-01-01'),
|
||||
('RS', 'incentive_weight', 1.500000, '激励课权重', DATE '2026-01-01'),
|
||||
('RS', 'halflife_session', 14.000000, '会话半衰期(天)', DATE '2026-01-01'),
|
||||
('RS', 'halflife_last', 10.000000, '最近一次服务半衰期(天)', DATE '2026-01-01'),
|
||||
('RS', 'weight_f', 1.000000, '频次项权重', DATE '2026-01-01'),
|
||||
('RS', 'weight_d', 0.700000, '时长项权重', DATE '2026-01-01'),
|
||||
('RS', 'gate_alpha', 0.600000, '最近服务门控指数', DATE '2026-01-01'),
|
||||
('RS', 'percentile_lower', 5.000000, '展示分下分位', DATE '2026-01-01'),
|
||||
('RS', 'percentile_upper', 95.000000, '展示分上分位', DATE '2026-01-01'),
|
||||
('RS', 'compression_mode', 1.000000, '压缩模式:0=none,1=log1p,2=asinh', DATE '2026-01-01'),
|
||||
('RS', 'use_smoothing', 1.000000, '是否启用分位平滑', DATE '2026-01-01'),
|
||||
('RS', 'ewma_alpha', 0.200000, 'EWMA平滑系数', DATE '2026-01-01'),
|
||||
|
||||
-- OS(归属份额)
|
||||
('OS', 'min_rs_raw_for_ownership', 0.050000, '参与归属计算的最小RS_raw', DATE '2026-01-01'),
|
||||
('OS', 'min_total_rs_raw', 0.100000, '形成稳定归属的最小sum_rs', DATE '2026-01-01'),
|
||||
('OS', 'ownership_main_threshold', 0.600000, '主责阈值', DATE '2026-01-01'),
|
||||
('OS', 'ownership_comanage_threshold', 0.350000, '共管阈值', DATE '2026-01-01'),
|
||||
('OS', 'ownership_gap_threshold', 0.150000, '主责与次席份额差阈值', DATE '2026-01-01'),
|
||||
('OS', 'eps', 0.000001, '数值稳定项', DATE '2026-01-01'),
|
||||
|
||||
-- MS(升温动量)
|
||||
('MS', 'lookback_days', 60.000000, '服务行为回溯窗口(天)', DATE '2026-01-01'),
|
||||
('MS', 'session_merge_hours', 4.000000, '会话合并阈值(小时)', DATE '2026-01-01'),
|
||||
('MS', 'incentive_weight', 1.500000, '激励课权重', DATE '2026-01-01'),
|
||||
('MS', 'halflife_short', 7.000000, '短期半衰期(天)', DATE '2026-01-01'),
|
||||
('MS', 'halflife_long', 30.000000, '长期半衰期(天)', DATE '2026-01-01'),
|
||||
('MS', 'eps', 0.000001, '数值稳定项', DATE '2026-01-01'),
|
||||
('MS', 'percentile_lower', 5.000000, '展示分下分位', DATE '2026-01-01'),
|
||||
('MS', 'percentile_upper', 95.000000, '展示分上分位', DATE '2026-01-01'),
|
||||
('MS', 'compression_mode', 1.000000, '压缩模式:0=none,1=log1p,2=asinh', DATE '2026-01-01'),
|
||||
('MS', 'use_smoothing', 1.000000, '是否启用分位平滑', DATE '2026-01-01'),
|
||||
('MS', 'ewma_alpha', 0.200000, 'EWMA平滑系数', DATE '2026-01-01'),
|
||||
|
||||
-- ML(付费关联)
|
||||
('ML', 'lookback_days', 60.000000, '充值行为回溯窗口(天)', DATE '2026-01-01'),
|
||||
('ML', 'amount_base', 500.000000, '金额压缩基准', DATE '2026-01-01'),
|
||||
('ML', 'halflife_recharge', 21.000000, '充值半衰期(天)', DATE '2026-01-01'),
|
||||
('ML', 'percentile_lower', 5.000000, '展示分下分位', DATE '2026-01-01'),
|
||||
('ML', 'percentile_upper', 95.000000, '展示分上分位', DATE '2026-01-01'),
|
||||
('ML', 'compression_mode', 1.000000, '压缩模式:0=none,1=log1p,2=asinh', DATE '2026-01-01'),
|
||||
('ML', 'use_smoothing', 1.000000, '是否启用分位平滑', DATE '2026-01-01'),
|
||||
('ML', 'ewma_alpha', 0.200000, 'EWMA平滑系数', DATE '2026-01-01')
|
||||
ON CONFLICT (index_type, param_name, effective_from) DO UPDATE SET
|
||||
param_value = EXCLUDED.param_value,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = NOW();
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- SPI(消费力指数)参数
|
||||
-- 生效时间:北京时间 2026-02-23
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO dws.cfg_index_parameters
|
||||
(index_type, param_name, param_value, description, effective_from)
|
||||
VALUES
|
||||
-- 窗口参数
|
||||
('SPI', 'spend_window_short_days', 30.000000, '短期消费窗口(天)', DATE '2026-02-23'),
|
||||
('SPI', 'spend_window_long_days', 90.000000, '长期消费窗口(天)', DATE '2026-02-23'),
|
||||
('SPI', 'ewma_alpha_daily_spend', 0.300000, '日消费 EWMA 平滑系数', DATE '2026-02-23'),
|
||||
-- 金额压缩基数(基于典型台球门店消费水平的初始默认值)
|
||||
('SPI', 'amount_base_spend_30', 500.000000, '30天消费额压缩基数', DATE '2026-02-23'),
|
||||
('SPI', 'amount_base_spend_90', 1500.000000, '90天消费额压缩基数', DATE '2026-02-23'),
|
||||
('SPI', 'amount_base_ticket_90', 200.000000, '90天客单价压缩基数', DATE '2026-02-23'),
|
||||
('SPI', 'amount_base_recharge_90', 1000.000000, '90天充值额压缩基数', DATE '2026-02-23'),
|
||||
('SPI', 'amount_base_speed_abs', 100.000000, '绝对速度压缩基数', DATE '2026-02-23'),
|
||||
('SPI', 'amount_base_ewma_90', 50.000000, '日消费EWMA压缩基数', DATE '2026-02-23'),
|
||||
-- Level 子分权重
|
||||
('SPI', 'w_level_spend_30', 0.300000, 'Level子分:30天消费权重', DATE '2026-02-23'),
|
||||
('SPI', 'w_level_spend_90', 0.350000, 'Level子分:90天消费权重', DATE '2026-02-23'),
|
||||
('SPI', 'w_level_ticket_90', 0.200000, 'Level子分:90天客单权重', DATE '2026-02-23'),
|
||||
('SPI', 'w_level_recharge_90', 0.150000, 'Level子分:90天充值权重', DATE '2026-02-23'),
|
||||
-- Speed 子分权重
|
||||
('SPI', 'w_speed_abs', 0.500000, 'Speed子分:绝对速度权重', DATE '2026-02-23'),
|
||||
('SPI', 'w_speed_rel', 0.300000, 'Speed子分:相对速度权重', DATE '2026-02-23'),
|
||||
('SPI', 'w_speed_ewma', 0.200000, 'Speed子分:EWMA速度权重', DATE '2026-02-23'),
|
||||
-- 总分权重
|
||||
('SPI', 'weight_level', 0.600000, 'SPI总分:Level子分权重', DATE '2026-02-23'),
|
||||
('SPI', 'weight_speed', 0.300000, 'SPI总分:Speed子分权重', DATE '2026-02-23'),
|
||||
('SPI', 'weight_stability', 0.100000, 'SPI总分:Stability子分权重', DATE '2026-02-23'),
|
||||
-- 稳定性参数
|
||||
('SPI', 'stability_window_days', 90.000000, '稳定性计算窗口(天)', DATE '2026-02-23'),
|
||||
('SPI', 'use_stability', 1.000000, '是否启用稳定性子分:0=关闭,1=启用', DATE '2026-02-23'),
|
||||
-- 映射与平滑
|
||||
('SPI', 'percentile_lower', 5.000000, '展示分下分位', DATE '2026-02-23'),
|
||||
('SPI', 'percentile_upper', 95.000000, '展示分上分位', DATE '2026-02-23'),
|
||||
('SPI', 'compression_mode', 1.000000, '压缩模式:0=none,1=log1p,2=asinh', DATE '2026-02-23'),
|
||||
('SPI', 'use_smoothing', 1.000000, '是否启用分位平滑', DATE '2026-02-23'),
|
||||
('SPI', 'ewma_alpha', 0.200000, 'EWMA平滑系数', DATE '2026-02-23'),
|
||||
-- 速度计算
|
||||
('SPI', 'speed_epsilon', 0.000001, '速度计算防除零小量', DATE '2026-02-23')
|
||||
ON CONFLICT (index_type, param_name, effective_from) DO UPDATE SET
|
||||
param_value = EXCLUDED.param_value,
|
||||
description = EXCLUDED.description,
|
||||
updated_at = NOW();
|
||||
|
||||
-- =============================================================================
|
||||
-- 验证
|
||||
-- =============================================================================
|
||||
DO $
|
||||
DECLARE
|
||||
rs_count INTEGER;
|
||||
os_count INTEGER;
|
||||
ms_count INTEGER;
|
||||
ml_count INTEGER;
|
||||
nci_count INTEGER;
|
||||
wbi_count INTEGER;
|
||||
spi_count INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*) INTO rs_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'RS';
|
||||
|
||||
SELECT COUNT(*) INTO os_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'OS';
|
||||
|
||||
SELECT COUNT(*) INTO ms_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'MS';
|
||||
|
||||
SELECT COUNT(*) INTO ml_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'ML';
|
||||
|
||||
SELECT COUNT(*) INTO nci_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'NCI';
|
||||
|
||||
SELECT COUNT(*) INTO wbi_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'WBI';
|
||||
|
||||
SELECT COUNT(*) INTO spi_count
|
||||
FROM dws.cfg_index_parameters
|
||||
WHERE index_type = 'SPI';
|
||||
|
||||
RAISE NOTICE 'RS 参数数量: %', rs_count;
|
||||
RAISE NOTICE 'OS 参数数量: %', os_count;
|
||||
RAISE NOTICE 'MS 参数数量: %', ms_count;
|
||||
RAISE NOTICE 'ML 参数数量: %', ml_count;
|
||||
RAISE NOTICE '新客转化参数数量: %', nci_count;
|
||||
RAISE NOTICE '唤回指数参数数量: %', wbi_count;
|
||||
RAISE NOTICE 'SPI 消费力指数参数数量: %', spi_count;
|
||||
END $;
|
||||
|
||||
SELECT
|
||||
index_type,
|
||||
param_name,
|
||||
param_value,
|
||||
description,
|
||||
effective_from
|
||||
FROM dws.cfg_index_parameters
|
||||
ORDER BY index_type, param_name, effective_from;
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- etl_feiqiu / meta(ETL 调度元数据)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -75,3 +75,105 @@ ALTER TABLE meta.etl_run ADD CONSTRAINT etl_run_pkey PRIMARY KEY (run_id);
|
||||
ALTER TABLE meta.etl_task ADD CONSTRAINT etl_task_pkey PRIMARY KEY (task_id);
|
||||
ALTER TABLE meta.etl_task ADD CONSTRAINT etl_task_task_code_store_id_key UNIQUE (task_code, store_id);
|
||||
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:ODS 任务注册
|
||||
-- =============================================================================
|
||||
|
||||
WITH target_store AS (
|
||||
SELECT 2790685415443269::bigint AS store_id -- TODO: 替换为实际 store_id
|
||||
),
|
||||
task_codes AS (
|
||||
SELECT unnest(ARRAY[
|
||||
'ODS_ASSISTANT_ACCOUNT',
|
||||
'ODS_ASSISTANT_LEDGER',
|
||||
'ODS_SETTLEMENT_RECORDS',
|
||||
'ODS_TABLE_USE',
|
||||
'ODS_PAYMENT',
|
||||
'ODS_REFUND',
|
||||
'ODS_PLATFORM_COUPON',
|
||||
'ODS_MEMBER',
|
||||
'ODS_MEMBER_CARD',
|
||||
'ODS_MEMBER_BALANCE',
|
||||
'ODS_RECHARGE_SETTLE',
|
||||
'ODS_GROUP_PACKAGE',
|
||||
'ODS_GROUP_BUY_REDEMPTION',
|
||||
'ODS_INVENTORY_STOCK',
|
||||
'ODS_INVENTORY_CHANGE',
|
||||
'ODS_TABLES',
|
||||
'ODS_GOODS_CATEGORY',
|
||||
'ODS_STORE_GOODS',
|
||||
'ODS_STORE_GOODS_SALES',
|
||||
'ODS_TABLE_FEE_DISCOUNT',
|
||||
'ODS_TENANT_GOODS'
|
||||
]) AS task_code
|
||||
)
|
||||
INSERT INTO meta.etl_task (task_code, store_id, enabled)
|
||||
SELECT t.task_code, s.store_id, TRUE
|
||||
FROM task_codes t CROSS JOIN target_store s
|
||||
ON CONFLICT (task_code, store_id) DO UPDATE
|
||||
SET enabled = EXCLUDED.enabled;
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:调度任务注册
|
||||
-- =============================================================================
|
||||
|
||||
WITH target_store AS (
|
||||
SELECT 2790685415443269::bigint AS store_id -- TODO: 替换为实际 store_id
|
||||
),
|
||||
task_codes AS (
|
||||
SELECT unnest(ARRAY[
|
||||
'ASSISTANTS',
|
||||
'COUPON_USAGE',
|
||||
'CHECK_CUTOFF',
|
||||
'DWD_LOAD_FROM_ODS',
|
||||
'DWD_QUALITY_CHECK',
|
||||
'INIT_DWD_SCHEMA',
|
||||
'INIT_DWS_SCHEMA',
|
||||
'INIT_ODS_SCHEMA',
|
||||
'INVENTORY_CHANGE',
|
||||
'LEDGER',
|
||||
'MANUAL_INGEST',
|
||||
'MEMBERS',
|
||||
'MEMBERS_DWD',
|
||||
'ODS_JSON_ARCHIVE',
|
||||
'ORDERS',
|
||||
'PACKAGES_DEF',
|
||||
'PAYMENTS',
|
||||
'PAYMENTS_DWD',
|
||||
'PRODUCTS',
|
||||
'REFUNDS',
|
||||
'TABLE_DISCOUNT',
|
||||
'TABLES',
|
||||
'TICKET_DWD',
|
||||
'TOPUPS',
|
||||
'DWS_BUILD_ORDER_SUMMARY',
|
||||
'DWS_ASSISTANT_DAILY',
|
||||
'DWS_ASSISTANT_MONTHLY',
|
||||
'DWS_ASSISTANT_CUSTOMER',
|
||||
'DWS_ASSISTANT_SALARY',
|
||||
'DWS_ASSISTANT_FINANCE',
|
||||
'DWS_MEMBER_CONSUMPTION',
|
||||
'DWS_MEMBER_VISIT',
|
||||
'DWS_FINANCE_DAILY',
|
||||
'DWS_FINANCE_RECHARGE',
|
||||
'DWS_FINANCE_INCOME_STRUCTURE',
|
||||
'DWS_FINANCE_DISCOUNT_DETAIL',
|
||||
'DWS_GOODS_STOCK_DAILY',
|
||||
'DWS_GOODS_STOCK_WEEKLY',
|
||||
'DWS_GOODS_STOCK_MONTHLY',
|
||||
'DWS_WINBACK_INDEX',
|
||||
'DWS_NEWCONV_INDEX',
|
||||
'DWS_RELATION_INDEX',
|
||||
'DWS_ASSISTANT_PROJECT_TAG',
|
||||
'DWS_MEMBER_PROJECT_TAG',
|
||||
'DWS_ML_MANUAL_IMPORT'
|
||||
]) AS task_code
|
||||
)
|
||||
INSERT INTO meta.etl_task (task_code, store_id, enabled)
|
||||
SELECT t.task_code, s.store_id, TRUE
|
||||
FROM task_codes t CROSS JOIN target_store s
|
||||
ON CONFLICT (task_code, store_id) DO UPDATE
|
||||
SET enabled = EXCLUDED.enabled,
|
||||
updated_at = now();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- etl_feiqiu / ods(原始数据层)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -193,12 +193,37 @@ CREATE TABLE ods.goods_stock_summary (
|
||||
rangesalemoney numeric(18,2),
|
||||
rangeinventory numeric(18,4),
|
||||
currentstock numeric(18,4),
|
||||
siteid bigint,
|
||||
content_hash text NOT NULL,
|
||||
source_file text,
|
||||
source_endpoint text,
|
||||
fetched_at timestamp with time zone DEFAULT now(),
|
||||
payload jsonb NOT NULL
|
||||
payload jsonb NOT NULL,
|
||||
siteid bigint
|
||||
);
|
||||
|
||||
CREATE TABLE ods.group_buy_package_details (
|
||||
coupon_id bigint NOT NULL,
|
||||
package_name text,
|
||||
duration integer,
|
||||
start_time timestamp with time zone,
|
||||
end_time timestamp with time zone,
|
||||
add_start_clock text,
|
||||
add_end_clock text,
|
||||
is_enabled integer,
|
||||
is_delete integer,
|
||||
site_id bigint,
|
||||
tenant_id bigint,
|
||||
create_time timestamp with time zone,
|
||||
creator_name text,
|
||||
table_area_ids jsonb,
|
||||
table_area_names jsonb,
|
||||
assistant_services jsonb,
|
||||
groupon_site_infos jsonb,
|
||||
package_services jsonb,
|
||||
coupon_details_list jsonb,
|
||||
content_hash text,
|
||||
payload jsonb,
|
||||
fetched_at timestamp with time zone DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE TABLE ods.group_buy_packages (
|
||||
@@ -1048,6 +1073,7 @@ ALTER TABLE ods.assistant_accounts_master ADD CONSTRAINT assistant_accounts_mast
|
||||
ALTER TABLE ods.assistant_service_records ADD CONSTRAINT assistant_service_records_pkey PRIMARY KEY (id, content_hash);
|
||||
ALTER TABLE ods.goods_stock_movements ADD CONSTRAINT goods_stock_movements_pkey PRIMARY KEY (sitegoodsstockid, content_hash);
|
||||
ALTER TABLE ods.goods_stock_summary ADD CONSTRAINT goods_stock_summary_pkey PRIMARY KEY (sitegoodsid, content_hash);
|
||||
ALTER TABLE ods.group_buy_package_details ADD CONSTRAINT pk_group_buy_package_details PRIMARY KEY (coupon_id);
|
||||
ALTER TABLE ods.group_buy_packages ADD CONSTRAINT group_buy_packages_pkey PRIMARY KEY (id, content_hash);
|
||||
ALTER TABLE ods.group_buy_redemption_records ADD CONSTRAINT group_buy_redemption_records_pkey PRIMARY KEY (id, content_hash);
|
||||
ALTER TABLE ods.member_balance_changes ADD CONSTRAINT member_balance_changes_pkey PRIMARY KEY (id, content_hash);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- FDW 跨库映射(在 zqyy_app 中执行)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:db/fdw/setup_fdw.sql
|
||||
-- =============================================================================
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- zqyy_app / auth(用户认证与权限)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -133,3 +133,53 @@ CREATE INDEX ix_user_site_roles_user_site ON auth.user_site_roles USING btree (u
|
||||
CREATE INDEX ix_users_status ON auth.users USING btree (status);
|
||||
CREATE INDEX ix_users_wx_openid ON auth.users USING btree (wx_openid);
|
||||
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:权限列表(5 条)
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO auth.permissions (code, name, description) VALUES
|
||||
('view_tasks', '查看任务', '允许查看任务列表和任务详情'),
|
||||
('view_board', '查看看板', '允许查看数据看板概览'),
|
||||
('view_board_finance', '查看财务看板', '允许查看财务相关的数据看板'),
|
||||
('view_board_customer', '查看客户看板', '允许查看客户相关的数据看板'),
|
||||
('view_board_coach', '查看助教看板', '允许查看助教相关的数据看板')
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:默认角色(4 条)
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO auth.roles (code, name, description) VALUES
|
||||
('coach', '助教', '球房助教,可查看任务和助教看板'),
|
||||
('staff', '员工', '球房员工,可查看任务和数据看板'),
|
||||
('site_admin', '店铺管理员', '单店管理员,可查看所有看板'),
|
||||
('tenant_admin', '租户管理员', '租户级管理员,拥有全部权限')
|
||||
ON CONFLICT (code) DO NOTHING;
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:角色-权限映射(14 条)
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO auth.role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id
|
||||
FROM auth.roles r
|
||||
CROSS JOIN auth.permissions p
|
||||
WHERE (r.code, p.code) IN (
|
||||
('coach', 'view_tasks'),
|
||||
('coach', 'view_board_coach'),
|
||||
('staff', 'view_tasks'),
|
||||
('staff', 'view_board'),
|
||||
('site_admin', 'view_tasks'),
|
||||
('site_admin', 'view_board'),
|
||||
('site_admin', 'view_board_finance'),
|
||||
('site_admin', 'view_board_customer'),
|
||||
('site_admin', 'view_board_coach'),
|
||||
('tenant_admin', 'view_tasks'),
|
||||
('tenant_admin', 'view_board'),
|
||||
('tenant_admin', 'view_board_finance'),
|
||||
('tenant_admin', 'view_board_customer'),
|
||||
('tenant_admin', 'view_board_coach')
|
||||
)
|
||||
ON CONFLICT (role_id, permission_id) DO NOTHING;
|
||||
|
||||
@@ -1,18 +1,53 @@
|
||||
-- =============================================================================
|
||||
-- zqyy_app / biz(核心业务表(任务/备注/触发器))
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
CREATE SCHEMA IF NOT EXISTS biz;
|
||||
|
||||
-- 序列
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.ai_cache_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.ai_conversations_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.ai_messages_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.coach_task_history_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.coach_tasks_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.notes_id_seq AS bigint;
|
||||
CREATE SEQUENCE IF NOT EXISTS biz.trigger_jobs_id_seq AS integer;
|
||||
|
||||
-- 表
|
||||
CREATE TABLE biz.ai_cache (
|
||||
id bigint DEFAULT nextval('biz.ai_cache_id_seq'::regclass) NOT NULL,
|
||||
cache_type character varying(30) NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
target_id character varying(100) NOT NULL,
|
||||
result_json jsonb NOT NULL,
|
||||
score integer,
|
||||
triggered_by character varying(100),
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
expires_at timestamp with time zone
|
||||
);
|
||||
|
||||
CREATE TABLE biz.ai_conversations (
|
||||
id bigint DEFAULT nextval('biz.ai_conversations_id_seq'::regclass) NOT NULL,
|
||||
user_id character varying(50) NOT NULL,
|
||||
nickname character varying(100) DEFAULT ''::character varying NOT NULL,
|
||||
app_id character varying(30) NOT NULL,
|
||||
site_id bigint NOT NULL,
|
||||
source_page character varying(100),
|
||||
source_context jsonb,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE biz.ai_messages (
|
||||
id bigint DEFAULT nextval('biz.ai_messages_id_seq'::regclass) NOT NULL,
|
||||
conversation_id bigint NOT NULL,
|
||||
role character varying(10) NOT NULL,
|
||||
content text NOT NULL,
|
||||
tokens_used integer,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE biz.coach_task_history (
|
||||
id bigint DEFAULT nextval('biz.coach_task_history_id_seq'::regclass) NOT NULL,
|
||||
task_id bigint NOT NULL,
|
||||
@@ -73,6 +108,10 @@ CREATE TABLE biz.trigger_jobs (
|
||||
);
|
||||
|
||||
-- 约束(主键 / 唯一 / 外键)
|
||||
ALTER TABLE biz.ai_cache ADD CONSTRAINT ai_cache_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE biz.ai_conversations ADD CONSTRAINT ai_conversations_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE biz.ai_messages ADD CONSTRAINT ai_messages_conversation_id_fkey FOREIGN KEY (conversation_id) REFERENCES biz.ai_conversations(id) ON DELETE CASCADE;
|
||||
ALTER TABLE biz.ai_messages ADD CONSTRAINT ai_messages_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE biz.coach_task_history ADD CONSTRAINT coach_task_history_task_id_fkey FOREIGN KEY (task_id) REFERENCES biz.coach_tasks(id);
|
||||
ALTER TABLE biz.coach_task_history ADD CONSTRAINT coach_task_history_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE biz.coach_tasks ADD CONSTRAINT coach_tasks_parent_task_id_fkey FOREIGN KEY (parent_task_id) REFERENCES biz.coach_tasks(id);
|
||||
@@ -83,7 +122,33 @@ ALTER TABLE biz.trigger_jobs ADD CONSTRAINT trigger_jobs_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE biz.trigger_jobs ADD CONSTRAINT trigger_jobs_job_name_key UNIQUE (job_name);
|
||||
|
||||
-- 索引
|
||||
CREATE INDEX idx_ai_cache_cleanup ON biz.ai_cache USING btree (cache_type, site_id, target_id, created_at);
|
||||
CREATE INDEX idx_ai_cache_lookup ON biz.ai_cache USING btree (cache_type, site_id, target_id, created_at DESC);
|
||||
CREATE INDEX idx_ai_conv_app_site ON biz.ai_conversations USING btree (app_id, site_id, created_at DESC);
|
||||
CREATE INDEX idx_ai_conv_user_site ON biz.ai_conversations USING btree (user_id, site_id, created_at DESC);
|
||||
CREATE INDEX idx_ai_msg_conv ON biz.ai_messages USING btree (conversation_id, created_at);
|
||||
CREATE INDEX idx_coach_tasks_assistant_status ON biz.coach_tasks USING btree (site_id, assistant_id, status);
|
||||
CREATE UNIQUE INDEX idx_coach_tasks_site_assistant_member_type ON biz.coach_tasks USING btree (site_id, assistant_id, member_id, task_type) WHERE ((status)::text = 'active'::text);
|
||||
CREATE INDEX idx_notes_target ON biz.notes USING btree (site_id, target_type, target_id);
|
||||
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:触发器配置(4 条)
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO biz.trigger_jobs (job_type, job_name, trigger_condition, trigger_config, next_run_at)
|
||||
VALUES
|
||||
('task_generator', 'task_generator', 'cron',
|
||||
'{"cron_expression": "0 7 * * *"}',
|
||||
(CURRENT_DATE + 1) + INTERVAL '7 hours'),
|
||||
('task_expiry_check', 'task_expiry_check', 'interval',
|
||||
'{"interval_seconds": 3600}',
|
||||
NOW() + INTERVAL '1 hour'),
|
||||
('recall_completion_check', 'recall_completion_check', 'event',
|
||||
'{"event_name": "etl_data_updated"}',
|
||||
NULL),
|
||||
('note_reclassify_backfill', 'note_reclassify_backfill', 'event',
|
||||
'{"event_name": "recall_completed"}',
|
||||
NULL)
|
||||
ON CONFLICT (job_name) DO NOTHING;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- =============================================================================
|
||||
-- zqyy_app / public(小程序业务表)
|
||||
-- 生成日期:2026-02-27
|
||||
-- 生成日期:2026-03-15
|
||||
-- 来源:测试库(通过脚本自动导出)
|
||||
-- =============================================================================
|
||||
|
||||
@@ -95,12 +95,13 @@ CREATE TABLE public.task_execution_log (
|
||||
started_at timestamp with time zone NOT NULL,
|
||||
finished_at timestamp with time zone,
|
||||
exit_code integer,
|
||||
duration_ms integer,
|
||||
duration_ms bigint,
|
||||
command text,
|
||||
output_log text,
|
||||
error_log text,
|
||||
summary jsonb,
|
||||
created_at timestamp with time zone DEFAULT now()
|
||||
created_at timestamp with time zone DEFAULT now(),
|
||||
schedule_id uuid
|
||||
);
|
||||
|
||||
CREATE TABLE public.task_queue (
|
||||
@@ -113,7 +114,9 @@ CREATE TABLE public.task_queue (
|
||||
started_at timestamp with time zone,
|
||||
finished_at timestamp with time zone,
|
||||
exit_code integer,
|
||||
error_message text
|
||||
error_message text,
|
||||
schedule_id uuid,
|
||||
enqueued_by character varying(255) DEFAULT NULL::character varying
|
||||
);
|
||||
|
||||
CREATE TABLE public.tasks (
|
||||
@@ -152,9 +155,6 @@ ALTER TABLE approvals ADD CONSTRAINT approvals_approver_id_fkey FOREIGN KEY (app
|
||||
ALTER TABLE approvals ADD CONSTRAINT approvals_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
|
||||
ALTER TABLE approvals ADD CONSTRAINT approvals_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE member_retention_clue ADD CONSTRAINT member_retention_clue_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE member_retention_clue ADD CONSTRAINT chk_retention_clue_category CHECK (
|
||||
category IN ('客户基础', '消费习惯', '玩法偏好', '促销偏好', '社交关系', '重要反馈')
|
||||
);
|
||||
ALTER TABLE permissions ADD CONSTRAINT permissions_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE permissions ADD CONSTRAINT permissions_resource_action_key UNIQUE (resource, action);
|
||||
ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE;
|
||||
@@ -164,7 +164,9 @@ ALTER TABLE roles ADD CONSTRAINT roles_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE roles ADD CONSTRAINT roles_name_key UNIQUE (name);
|
||||
ALTER TABLE scheduled_tasks ADD CONSTRAINT scheduled_tasks_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_queue_id_fkey FOREIGN KEY (queue_id) REFERENCES task_queue(id);
|
||||
ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_schedule_id_fkey FOREIGN KEY (schedule_id) REFERENCES scheduled_tasks(id) ON DELETE SET NULL;
|
||||
ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE task_queue ADD CONSTRAINT task_queue_schedule_id_fkey FOREIGN KEY (schedule_id) REFERENCES scheduled_tasks(id) ON DELETE SET NULL;
|
||||
ALTER TABLE task_queue ADD CONSTRAINT task_queue_pkey PRIMARY KEY (id);
|
||||
ALTER TABLE tasks ADD CONSTRAINT tasks_assignee_id_fkey FOREIGN KEY (assignee_id) REFERENCES users(id);
|
||||
ALTER TABLE tasks ADD CONSTRAINT tasks_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES users(id);
|
||||
@@ -185,6 +187,7 @@ CREATE INDEX idx_retention_clue_site ON public.member_retention_clue USING btree
|
||||
CREATE INDEX idx_roles_site_id ON public.roles USING btree (site_id);
|
||||
CREATE INDEX idx_scheduled_tasks_next_run ON public.scheduled_tasks USING btree (next_run_at) WHERE (enabled = true);
|
||||
CREATE INDEX idx_scheduled_tasks_site ON public.scheduled_tasks USING btree (site_id);
|
||||
CREATE INDEX idx_execution_log_schedule_id ON public.task_execution_log USING btree (schedule_id) WHERE (schedule_id IS NOT NULL);
|
||||
CREATE INDEX idx_execution_log_site_started ON public.task_execution_log USING btree (site_id, started_at DESC);
|
||||
CREATE INDEX idx_task_queue_site_position ON public.task_queue USING btree (site_id, "position") WHERE ((status)::text = 'pending'::text);
|
||||
CREATE INDEX idx_task_queue_status ON public.task_queue USING btree (status);
|
||||
@@ -195,3 +198,20 @@ CREATE INDEX idx_user_roles_site_id ON public.user_roles USING btree (site_id);
|
||||
CREATE INDEX idx_users_mobile ON public.users USING btree (mobile);
|
||||
CREATE INDEX idx_users_site_id ON public.users USING btree (site_id);
|
||||
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- 种子数据:Web 管理后台默认管理员账号
|
||||
-- 默认密码:admin123(bcrypt hash,cost=12)
|
||||
-- 生产环境部署后务必立即修改密码
|
||||
-- =============================================================================
|
||||
|
||||
INSERT INTO admin_users (username, password_hash, display_name, site_id, is_active)
|
||||
VALUES (
|
||||
'admin',
|
||||
'$2b$12$2MTWlJKL0HTgHIkv5Rmpie2pQ9PkeJu0iciLbzPEpPcA94ZakIQzq',
|
||||
'默认管理员',
|
||||
1,
|
||||
TRUE
|
||||
)
|
||||
ON CONFLICT (username) DO NOTHING;
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
[
|
||||
{
|
||||
"region_index": 0,
|
||||
"region_name": "经营一览",
|
||||
"scroll_mode": "scroll_into_view",
|
||||
"scroll_into_view_id": "section-overview",
|
||||
"wait_ms": 800,
|
||||
"screenshot_name": "mp-board-finance--seg-0.png",
|
||||
"notes": "scroll-into-view -> section-overview"
|
||||
},
|
||||
{
|
||||
"region_index": 1,
|
||||
"region_name": "预收资产",
|
||||
"scroll_mode": "scroll_into_view",
|
||||
"scroll_into_view_id": "section-recharge",
|
||||
"wait_ms": 1000,
|
||||
"screenshot_name": "mp-board-finance--seg-1.png",
|
||||
"notes": "scroll-into-view -> section-recharge"
|
||||
},
|
||||
{
|
||||
"region_index": 2,
|
||||
"region_name": "应计收入确认",
|
||||
"scroll_mode": "scroll_into_view",
|
||||
"scroll_into_view_id": "section-revenue",
|
||||
"wait_ms": 1000,
|
||||
"screenshot_name": "mp-board-finance--seg-2.png",
|
||||
"notes": "scroll-into-view -> section-revenue"
|
||||
},
|
||||
{
|
||||
"region_index": 3,
|
||||
"region_name": "现金流入",
|
||||
"scroll_mode": "scroll_into_view",
|
||||
"scroll_into_view_id": "section-cashflow",
|
||||
"wait_ms": 1000,
|
||||
"screenshot_name": "mp-board-finance--seg-3.png",
|
||||
"notes": "scroll-into-view -> section-cashflow"
|
||||
},
|
||||
{
|
||||
"region_index": 4,
|
||||
"region_name": "现金流出",
|
||||
"scroll_mode": "scroll_into_view",
|
||||
"scroll_into_view_id": "section-expense",
|
||||
"wait_ms": 1000,
|
||||
"screenshot_name": "mp-board-finance--seg-4.png",
|
||||
"notes": "scroll-into-view -> section-expense"
|
||||
},
|
||||
{
|
||||
"region_index": 5,
|
||||
"region_name": "助教分析",
|
||||
"scroll_mode": "scroll_into_view",
|
||||
"scroll_into_view_id": "section-coach",
|
||||
"wait_ms": 1000,
|
||||
"screenshot_name": "mp-board-finance--seg-5.png",
|
||||
"notes": "scroll-into-view -> section-coach"
|
||||
}
|
||||
]
|
||||
@@ -1,129 +0,0 @@
|
||||
{
|
||||
"pageHeight": 4976,
|
||||
"viewportHeight": 752,
|
||||
"anchorPositions": [
|
||||
{
|
||||
"name": "经营一览",
|
||||
"selector": "#section-overview",
|
||||
"found": true,
|
||||
"top": 132,
|
||||
"bottom": 736,
|
||||
"height": 604
|
||||
},
|
||||
{
|
||||
"name": "预收资产",
|
||||
"selector": "#section-recharge",
|
||||
"found": true,
|
||||
"top": 784,
|
||||
"bottom": 1466.796875,
|
||||
"height": 682.796875
|
||||
},
|
||||
{
|
||||
"name": "应计收入确认",
|
||||
"selector": "#section-revenue",
|
||||
"found": true,
|
||||
"top": 1508.796875,
|
||||
"bottom": 2857.09375,
|
||||
"height": 1348.296875
|
||||
},
|
||||
{
|
||||
"name": "现金流入",
|
||||
"selector": "#section-cashflow",
|
||||
"found": true,
|
||||
"top": 2873.09375,
|
||||
"bottom": 3333.390625,
|
||||
"height": 460.296875
|
||||
},
|
||||
{
|
||||
"name": "现金流出",
|
||||
"selector": "#section-expense",
|
||||
"found": true,
|
||||
"top": 3349.390625,
|
||||
"bottom": 4141.6875,
|
||||
"height": 792.296875
|
||||
},
|
||||
{
|
||||
"name": "助教分析",
|
||||
"selector": "#section-coach",
|
||||
"found": true,
|
||||
"top": 4157.6875,
|
||||
"bottom": 4679.984375,
|
||||
"height": 522.296875
|
||||
}
|
||||
],
|
||||
"stickyTotalHeight": 116,
|
||||
"stickyDetails": [
|
||||
{
|
||||
"selector": ".safe-area-top",
|
||||
"height": 45
|
||||
},
|
||||
{
|
||||
"selector": "#filterBar",
|
||||
"height": 71
|
||||
}
|
||||
],
|
||||
"fixedBottomHeight": 56,
|
||||
"fixedDetails": [
|
||||
{
|
||||
"selector": ".ai-float-btn-container",
|
||||
"height": 56
|
||||
}
|
||||
],
|
||||
"segments": [
|
||||
{
|
||||
"index": 0,
|
||||
"name": "经营一览",
|
||||
"scroll_y": 16,
|
||||
"screenshot": "docs\\h5_ui\\screenshots\\h5-board-finance--seg-0.png",
|
||||
"width": 1290,
|
||||
"height": 2256
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"name": "预收资产",
|
||||
"scroll_y": 668,
|
||||
"screenshot": "docs\\h5_ui\\screenshots\\h5-board-finance--seg-1.png",
|
||||
"width": 1290,
|
||||
"height": 2256
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"name": "应计收入确认",
|
||||
"scroll_y": 1392.796875,
|
||||
"screenshot": "docs\\h5_ui\\screenshots\\h5-board-finance--seg-2.png",
|
||||
"width": 1290,
|
||||
"height": 2256
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"name": "现金流入",
|
||||
"scroll_y": 2757.09375,
|
||||
"screenshot": "docs\\h5_ui\\screenshots\\h5-board-finance--seg-3.png",
|
||||
"width": 1290,
|
||||
"height": 2256
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"name": "现金流出",
|
||||
"scroll_y": 3233.390625,
|
||||
"screenshot": "docs\\h5_ui\\screenshots\\h5-board-finance--seg-4.png",
|
||||
"width": 1290,
|
||||
"height": 2256
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"name": "助教分析",
|
||||
"scroll_y": 4041.6875,
|
||||
"screenshot": "docs\\h5_ui\\screenshots\\h5-board-finance--seg-5.png",
|
||||
"width": 1290,
|
||||
"height": 2256
|
||||
}
|
||||
],
|
||||
"page_name": "board-finance",
|
||||
"viewport": {
|
||||
"width": 430,
|
||||
"height": 752
|
||||
},
|
||||
"dpr": 3,
|
||||
"timestamp": "2026-03-08 23:15:32"
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"extractedAt": "2026-03-06",
|
||||
"viewport": "375x667",
|
||||
"fontFamily": "\"Noto Sans SC\", -apple-system, BlinkMacSystemFont, sans-serif",
|
||||
"pages": {
|
||||
"task-list": {
|
||||
"Banner": { "fontSize": "16px", "fontWeight": "400", "color": "#fff", "backgroundColor": "transparent", "borderRadius": "0", "padding": "0 0 16px", "lineHeight": "24px" },
|
||||
"TaskCard": { "fontSize": "16px", "fontWeight": "400", "color": "#000", "backgroundColor": "#fff", "borderRadius": "12px", "padding": "16px", "lineHeight": "24px" },
|
||||
"ContextMenu": { "fontSize": "16px", "fontWeight": "400", "color": "#000", "backgroundColor": "#fff", "borderRadius": "14px", "padding": "6px 0", "lineHeight": "24px" },
|
||||
"SectionTitle": { "fontSize": "16px", "fontWeight": "600", "color": "rgb(36,36,36)", "lineHeight": "24px" },
|
||||
"ModalCard": { "fontSize": "16px", "fontWeight": "400", "color": "#000", "backgroundColor": "#fff", "borderRadius": "16px", "padding": "24px 20px 20px", "lineHeight": "24px" }
|
||||
},
|
||||
"task-detail": {
|
||||
"Banner": { "fontSize": "16px", "fontWeight": "400", "color": "#fff", "backgroundColor": "transparent", "padding": "0", "lineHeight": "24px" },
|
||||
"SectionTitle": { "fontSize": "14px", "fontWeight": "600", "color": "rgb(36,36,36)", "padding": "0 0 0 12px", "lineHeight": "20px" },
|
||||
"SpeechBubble": { "fontSize": "14px", "fontWeight": "400", "color": "rgb(94,94,94)", "backgroundColor": "rgb(240,244,255)", "borderRadius": "12px", "padding": "12px 16px", "lineHeight": "23.8px" },
|
||||
"PrimaryButton": { "fontSize": "12px", "fontWeight": "500", "color": "rgb(0,82,217)", "lineHeight": "16px" }
|
||||
},
|
||||
"board-finance": {
|
||||
"TabActive": { "fontSize": "14px", "fontWeight": "500", "color": "rgb(0,82,217)", "padding": "12px 0", "lineHeight": "20px" },
|
||||
"CompareToggle": { "fontSize": "16px", "backgroundColor": "rgb(220,220,220)", "borderRadius": "12px" }
|
||||
},
|
||||
"chat": {
|
||||
"MessageBubble": { "fontSize": "16px", "fontWeight": "400", "color": "#fff", "backgroundColor": "rgb(0,82,217)", "borderRadius": "16px 2px 16px 16px", "padding": "12px 16px", "lineHeight": "24px", "maxWidth": "80%" }
|
||||
},
|
||||
"login": {
|
||||
"LoginButton": { "fontSize": "16px", "fontWeight": "500", "color": "#fff", "backgroundColor": "rgb(220,220,220)", "borderRadius": "12px", "padding": "16px 0", "lineHeight": "24px" },
|
||||
"Title": { "fontSize": "24px", "fontWeight": "700", "color": "rgb(36,36,36)", "lineHeight": "32px" },
|
||||
"Subtitle": { "fontSize": "14px", "fontWeight": "400", "color": "rgb(139,139,139)", "lineHeight": "22.75px" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"colors": {
|
||||
"primary": "#0052d9",
|
||||
"primary-light": "#ecf2fe",
|
||||
"success": "#00a870",
|
||||
"warning": "#ed7b2f",
|
||||
"error": "#e34d59",
|
||||
"gray-1": "#f3f3f3",
|
||||
"gray-2": "#eeeeee",
|
||||
"gray-3": "#e7e7e7",
|
||||
"gray-4": "#dcdcdc",
|
||||
"gray-5": "#c5c5c5",
|
||||
"gray-6": "#a6a6a6",
|
||||
"gray-7": "#8b8b8b",
|
||||
"gray-8": "#777777",
|
||||
"gray-9": "#5e5e5e",
|
||||
"gray-10": "#4b4b4b",
|
||||
"gray-11": "#393939",
|
||||
"gray-12": "#2c2c2c",
|
||||
"gray-13": "#242424"
|
||||
},
|
||||
"spacing": {
|
||||
"comment": "Tailwind 默认 1 unit = 4px;缩放公式 rpx = px × 2 × 0.875,取偶数",
|
||||
"base": 8,
|
||||
"unit": "rpx"
|
||||
},
|
||||
"borderRadius": {
|
||||
"comment": "简单 ×2 缩放(A/B 对比验证差异 <0.02%,选择更整洁的 ×2 方案)",
|
||||
"sm": "8rpx",
|
||||
"md": "16rpx",
|
||||
"lg": "24rpx",
|
||||
"xl": "32rpx",
|
||||
"2xl": "32rpx",
|
||||
"3xl": "48rpx"
|
||||
},
|
||||
"fontSize": {
|
||||
"comment": "已应用 87.5% 缩放:H5 px × 2 × 0.875,取偶数",
|
||||
"xs": "22rpx",
|
||||
"sm": "24rpx",
|
||||
"base": "28rpx",
|
||||
"lg": "32rpx",
|
||||
"xl": "36rpx",
|
||||
"2xl": "42rpx"
|
||||
},
|
||||
"shadows": {
|
||||
"lg": "0 8rpx 32rpx rgba(0,0,0,0.06)",
|
||||
"xl": "0 16rpx 48rpx rgba(0,0,0,0.08)"
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
# 图标映射表
|
||||
|
||||
> 全局图标映射,TDesign 优先。自定义图标放 `apps/miniprogram/miniprogram/assets/icons/`。
|
||||
> 复杂内联 SVG 统一导出为图片资源,避免小程序中维护大段 SVG 代码。
|
||||
|
||||
## 全局通用图标
|
||||
|
||||
| H5 中的图标描述 | 处理方式 | 小程序引用 |
|
||||
|----------------|----------|-----------|
|
||||
| Logo 台球图标 | 自定义 SVG → 文件 | `/assets/icons/logo-billiard.svg` |
|
||||
| 微信图标 | 自定义 SVG → 文件 | `/assets/icons/icon-wechat.svg` |
|
||||
| 返回箭头 | TDesign | `<t-icon name="chevron-left" />` |
|
||||
| 右箭头 | TDesign | `<t-icon name="chevron-right" />` |
|
||||
| 关闭 | TDesign | `<t-icon name="close" />` |
|
||||
| 搜索 | TDesign | `<t-icon name="search" />` |
|
||||
| 更多(三点) | TDesign | `<t-icon name="ellipsis" />` |
|
||||
|
||||
## Banner 背景处理方案(统一)
|
||||
|
||||
原型中所有 Banner 使用 `banner.css` 的 CSS 渐变 + `texture-aurora` SVG 丝带纹理,结构复杂(多层渐变+伪元素+内联 SVG path)。
|
||||
|
||||
**处理方式:** 统一用 Playwright 截取各主题 Banner 区域,导出为图片资源。
|
||||
|
||||
| Banner 主题 | 使用页面 | 导出文件 |
|
||||
|-------------|----------|----------|
|
||||
| `theme-blue texture-aurora` | task-list, performance | `/assets/images/banner-blue.png` |
|
||||
| `theme-red texture-aurora` | task-detail(高优先召回) | `/assets/images/banner-red.png` |
|
||||
| `theme-orange texture-aurora` | task-detail(优先召回) | `/assets/images/banner-orange.png` |
|
||||
| `theme-pink texture-aurora` | task-detail-relationship(关系构建) | `/assets/images/banner-pink.png` |
|
||||
| `theme-teal texture-aurora` | task-detail-callback(客户回访) | `/assets/images/banner-teal.png` |
|
||||
| `theme-coral texture-aurora` | coach-detail | `/assets/images/banner-coral.png` |
|
||||
| `theme-dark-gold` | customer-detail | `/assets/images/banner-dark-gold.png` |
|
||||
|
||||
> 小程序中 Banner 区域使用 `<image>` 组件 + 绝对定位文字叠加,替代 CSS 渐变方案。
|
||||
|
||||
## 状态页图标(复杂 SVG → 图片)
|
||||
|
||||
| H5 中的图标 | 实际 SVG 内容 | 处理方式 | 小程序引用 |
|
||||
|-------------|--------------|----------|-----------|
|
||||
| reviewing 主图标 | amber→orange 渐变方块 + 白色时钟(圆形表盘+时针分针) | 导出 SVG | `/assets/icons/icon-clock-circle.svg` |
|
||||
| reviewing 进度对勾 | 绿色圆圈内白色对勾 polyline | TDesign | `<t-icon name="check-circle-filled" />` |
|
||||
| reviewing 信息图标 | Material 风格 info(圆+感叹号) | TDesign | `<t-icon name="info-circle-filled" />` |
|
||||
| reviewing 聊天气泡 | 聊天气泡 path | TDesign | `<t-icon name="chat" />` |
|
||||
| reviewing 登出箭头 | 右箭头+门框 path | TDesign | `<t-icon name="logout" />` |
|
||||
| no-permission 主图标 | rose→red 渐变方块 + 白色禁止符号(圆+对角线) | 导出 SVG | `/assets/icons/icon-forbidden.svg` |
|
||||
| no-permission 问号 | 问号圆圈 path | TDesign | `<t-icon name="help-circle-filled" />` |
|
||||
|
||||
## TabBar 图标
|
||||
|
||||
| Tab | 处理方式 | 小程序引用 |
|
||||
|-----|----------|-----------|
|
||||
| 任务(未选中) | 自定义 SVG(剪贴板+勾选,stroke 灰色) | `/assets/icons/tab-task.png` |
|
||||
| 任务(选中) | 自定义 SVG(剪贴板+勾选,fill 蓝色) | `/assets/icons/tab-task-active.png` |
|
||||
| 看板(未选中) | 自定义 SVG(三柱状图,stroke 灰色) | `/assets/icons/tab-board.png` |
|
||||
| 看板(选中) | 自定义 SVG(三柱状图,fill 蓝色) | `/assets/icons/tab-board-active.png` |
|
||||
| 我的(未选中) | 自定义 SVG(人物头像,stroke 灰色) | `/assets/icons/tab-my.png` |
|
||||
| 我的(选中) | 自定义 SVG(人物头像,fill 蓝色) | `/assets/icons/tab-my-active.png` |
|
||||
|
||||
> TabBar 图标由 `bottom-nav.js` 定义,包含完整的 active/inactive SVG。建议统一导出为 PNG 图片对。
|
||||
|
||||
## AI 助手图标
|
||||
|
||||
| H5 中的图标描述 | 实际 SVG 内容 | 处理方式 | 小程序引用 |
|
||||
|----------------|--------------|----------|-----------|
|
||||
| AI 悬浮按钮 | 可爱机器人(圆角矩形身体+天线+紫蓝色大眼睛+微笑+粉色腮红+小耳朵),渐变动画背景 | 截图导出按钮整体 | `/assets/icons/icon-ai-float.png` |
|
||||
| AI 内联图标(卡片中) | 同上机器人 SVG,小尺寸 | 截图导出 | `/assets/icons/icon-ai-inline.png` |
|
||||
| AI 标题徽章 | 同上机器人 + 随机配色 class | 截图导出 | `/assets/icons/icon-ai-badge.png` |
|
||||
| 对话发送 | TDesign | TDesign | `<t-icon name="send" />` |
|
||||
| 语音输入 | TDesign | TDesign | `<t-icon name="sound" />` |
|
||||
|
||||
> AI 图标由 `ai-icons.js` 统一管理,页面加载时随机分配配色(red/orange/yellow/blue/indigo/purple)。小程序中可固定一种配色或实现随机逻辑。
|
||||
|
||||
## 任务模块图标
|
||||
|
||||
| H5 中的图标描述 | 处理方式 | 小程序引用 |
|
||||
|----------------|----------|-----------|
|
||||
| 置顶 📌 | Emoji 文本 | `📌` |
|
||||
| 放弃 ❌ | Emoji 文本 | `❌` |
|
||||
| 备注指示器 📝 | Emoji 文本 | `📝` |
|
||||
| 爱心(💖>8.5) | Emoji 文本 | `💖` |
|
||||
| 爱心(🧡>7) | Emoji 文本 | `🧡` |
|
||||
| 爱心(💛>5) | Emoji 文本 | `💛` |
|
||||
| 爱心(💙<5) | Emoji 文本 | `💙` |
|
||||
| 喜好-中式 | Emoji 文本 | `🎱` |
|
||||
| 喜好-斯诺克 | 文本 | `斯` |
|
||||
| 喜好-麻将 | Emoji 文本 | `🀅` |
|
||||
| 喜好-团建 | Emoji 文本 | `🎤` |
|
||||
| "与我的关系"图标 | 可爱机器人 SVG(同 AI 图标),可视为心形 ICON 扩展 | 截图导出 | `/assets/icons/icon-ai-relationship.png` |
|
||||
|
||||
## 看板模块图标
|
||||
|
||||
| H5 中的图标描述 | 处理方式 | 小程序引用 |
|
||||
|----------------|----------|-----------|
|
||||
| 筛选下拉箭头 | TDesign | `<t-icon name="caret-down-small" />` |
|
||||
| 环比上升 | TDesign + 绿色 | `<t-icon name="arrow-up" />` |
|
||||
| 环比下降 | TDesign + 红色 | `<t-icon name="arrow-down" />` |
|
||||
| 目录导航按钮 | TDesign | `<t-icon name="view-list" />` |
|
||||
| 指标帮助"?" | TDesign | `<t-icon name="help-circle" />` |
|
||||
|
||||
## 我的模块图标
|
||||
|
||||
| H5 中的图标描述 | 处理方式 | 小程序引用 |
|
||||
|----------------|----------|-----------|
|
||||
| 备注记录 | TDesign | `<t-icon name="edit-1" />` |
|
||||
| 对话记录 | TDesign | `<t-icon name="chat" />` |
|
||||
| 退出账号 | TDesign | `<t-icon name="poweroff" />` |
|
||||
|
||||
## 星级评价组件
|
||||
|
||||
原型中星级评价由 `ai-icons.js` 渲染:读取 `data-score`(0-10),转换为 5 颗星(支持半星)。
|
||||
|
||||
- 空星:灰色 SVG 五角星
|
||||
- 满星/半星:彩色 SVG 五角星(通过 `clip-path` 实现半星)
|
||||
- 小程序建议使用 TDesign `<t-rate>` 组件替代
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
@@ -1,60 +0,0 @@
|
||||
# 页面名:apply(账号申请页)
|
||||
|
||||
> PRD 参考:`apps/miniprogram/doc/prd.md` 第七节 7.2;P3 认证系统
|
||||
> 已实现:是(`apps/miniprogram/miniprogram/pages/apply/`)
|
||||
|
||||
## 页面说明
|
||||
新用户提交入驻申请。顶部整合欢迎信息与审核流程步骤条,下方为结构化表单。
|
||||
|
||||
## 页面结构
|
||||
1. 顶部蓝色卡片:欢迎语 + 四步审核流程(提交申请 → 等待审核 → 审核通过 → 开始使用)
|
||||
2. 表单区域:5 个独立文本输入字段
|
||||
3. 底部固定提交按钮
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 必填 | 说明 |
|
||||
|--------|------|--------|------|------|
|
||||
| siteId | string | "" | 是 | 球房ID |
|
||||
| role | string | "" | 是 | 申请身份(如:助教、店长等) |
|
||||
| phone | string | "" | 是 | 手机号 |
|
||||
| staffNo | string | "" | 否 | 编号(选填) |
|
||||
| nickname | string | "" | 是 | 昵称 |
|
||||
| loading | boolean | false | — | 提交请求中 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 填写表单字段 | 无 | 更新对应状态变量;清除该字段错误状态 | 字段值更新 |
|
||||
| 点击"提交申请" | 表单校验通过 | POST /api/xcx-auth/apply | loading=true |
|
||||
| 点击"提交申请" | 表单校验失败 | 必填空字段高亮红框 + 下方红色提示文字,滚动到第一个错误字段 | 错误态 |
|
||||
| 提交成功 | API 返回 | 跳转 reviewing 页面 | redirectTo reviewing |
|
||||
| 提交失败 | API 报错 | Toast 提示错误信息 | loading=false |
|
||||
|
||||
## 表单校验规则
|
||||
| 字段 | 规则 | 错误提示 |
|
||||
|------|------|----------|
|
||||
| siteId | 必填 | 请输入球房ID |
|
||||
| role | 必填 | 请输入申请身份 |
|
||||
| phone | 必填 | 请输入手机号 |
|
||||
| staffNo | 选填,无校验 | — |
|
||||
| nickname | 必填 | 请输入昵称 |
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 默认态 | 空表单,提交按钮可用 | 初始 |
|
||||
| 校验错误态 | 必填空字段红色边框 + 下方红色提示文字 | 校验失败 |
|
||||
| 加载中 | 提交按钮 loading | loading=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `/api/xcx-auth/apply` | POST | 提交入驻申请 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:login(status=new)
|
||||
- 去向:reviewing(提交成功)
|
||||
|
||||
## 全局组件
|
||||
- 无底部 TabBar
|
||||
- 无 AI 悬浮按钮
|
||||
@@ -1,104 +0,0 @@
|
||||
# 页面名:board-coach(助教看板)
|
||||
|
||||
> PRD 参考:P8 `docs/prd/specs/P8-miniapp-fe-boards.md`;`apps/miniprogram/doc/prd.md` 第九节 9.3
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
按排序×技能×时间三重筛选查看助教排名列表。不同排序维度下卡片结构和突出数据不同。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| selectedSort | string | "定档业绩最高" | 排序筛选 |
|
||||
| selectedSkill | string | "不限" | 技能筛选 |
|
||||
| selectedTime | string | "本月" | 时间筛选 |
|
||||
| sortDropdownVisible | boolean | false | 排序筛选下拉展开 |
|
||||
| skillDropdownVisible | boolean | false | 技能筛选下拉展开 |
|
||||
| timeDropdownVisible | boolean | false | 时间筛选下拉展开 |
|
||||
| coaches | array | [] | 助教列表 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/board/coaches | loading→false |
|
||||
| 点击排序筛选 | 无 | 展开排序下拉,关闭其他 | sortDropdownVisible=true |
|
||||
| 选择排序 | 下拉展开 | 切换对应 dim-container 显隐,重新请求数据 | selectedSort 更新 |
|
||||
| 点击技能筛选 | 无 | 展开技能下拉,关闭其他 | skillDropdownVisible=true |
|
||||
| 选择技能 | 下拉展开 | 重新请求数据 | selectedSkill 更新 |
|
||||
| 点击时间筛选 | 无 | 展开时间下拉,关闭其他 | timeDropdownVisible=true |
|
||||
| 选择时间 | 下拉展开 | 重新请求数据 | selectedTime 更新 |
|
||||
| 点击助教卡片 | 无 | navigateTo coach-detail | — |
|
||||
| 切换看板 Tab | 顶部 Tab 栏 | navigateTo board-finance / board-customer | — |
|
||||
| 滚动页面 | 持续 | 下滑隐藏筛选栏,上滑显示 | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 筛选器选项(忠于原型 HTML)
|
||||
|
||||
### 排序筛选(6 个)
|
||||
1. 定档业绩最高
|
||||
2. 定档业绩最低
|
||||
3. 工资最高
|
||||
4. 工资最低
|
||||
5. 客源储值最高
|
||||
6. 任务完成最多
|
||||
|
||||
### 技能筛选
|
||||
不限 / 🎱 / 斯 / 🀄 / 🎤
|
||||
|
||||
### 时间筛选
|
||||
本月 / 本季度 / 上月 / 前3个月(不含本月)/ 上季度 / 最近6个月(不含本月,不支持客源储值最高)
|
||||
|
||||
## 排序切换 → 卡片结构映射(忠于原型 HTML)
|
||||
|
||||
切换排序时,通过 `selectSort(value)` 函数切换对应的 `dim-container` 显隐。每种排序的卡片右侧突出数据不同:
|
||||
|
||||
| 排序 | container id | 卡片右侧突出数据 |
|
||||
|------|-------------|-----------------|
|
||||
| 定档业绩最高/最低 | `dim-perf` | 定档 Xh + 折前 Xh + 距升档 Xh(或 ✅ 已达标) |
|
||||
| 工资最高/最低 | `dim-salary` | 预估标签 + ¥金额(大字)+ 定档/折前 |
|
||||
| 客源储值最高 | `dim-sv` | 储值 ¥金额(大字)+ 客户 X人 + 消耗 ¥X |
|
||||
|
||||
> 高客源储值定义(PRD 补充):RS > 2 的客户的会员卡储值合计(RS = 关系强度指数,> 2 表示有一定服务关系的客户)
|
||||
| 任务完成最多 | `dim-task` | 召回 X(蓝色大字)+ 回访 X |
|
||||
|
||||
### 所有卡片共有元素
|
||||
- 助教头像圆形 + 姓名
|
||||
- 等级标签(星级/高级/中级/初级)— 不同等级不同颜色
|
||||
- 技能标签(🎱/斯/🀄/🎤)
|
||||
- 底部 TOP3 客户 emoji 列表
|
||||
|
||||
## 等级标签颜色
|
||||
| 等级 | 颜色 |
|
||||
|------|------|
|
||||
| 星级 | 金色/amber |
|
||||
| 高级 | 蓝色/primary |
|
||||
| 中级 | 绿色/success |
|
||||
| 初级 | 灰色/gray |
|
||||
|
||||
## 筛选栏滚动行为
|
||||
- 下滑时筛选栏隐藏,上滑时重新显示
|
||||
- 由 `initFilterBarScrollBehavior()` 实现
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 助教列表 | 有数据 |
|
||||
| 空数据态 | "暂无数据" | coaches 为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/board/coaches` | GET | 助教看板(排序×技能×时间三重筛选) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:board-finance / board-customer(看板 Tab 切换)
|
||||
- 去向:coach-detail / chat
|
||||
|
||||
## 全局组件
|
||||
- 底部 TabBar(看板 active)
|
||||
- AI 悬浮按钮(右下角)
|
||||
- 看板顶部 Tab 栏(财务 / 客户 / 助教 active)
|
||||
@@ -1,90 +0,0 @@
|
||||
# 页面名:board-customer(客户看板)
|
||||
|
||||
> PRD 参考:P8 `docs/prd/specs/P8-miniapp-fe-boards.md`;`apps/miniprogram/doc/prd.md` 第九节 9.2
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
按 8 个维度查看前 100 名客户。支持维度切换和项目筛选,不同维度下卡片结构和展示内容不同。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| selectedType | string | "最应召回" | 维度/类型筛选(8 个维度) |
|
||||
| selectedProject | string | "全部" | 项目筛选 |
|
||||
| customers | array | [] | 客户列表(前 100 名) |
|
||||
| typeDropdownVisible | boolean | false | 维度筛选下拉展开 |
|
||||
| projectDropdownVisible | boolean | false | 项目筛选下拉展开 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/board/customers | loading→false |
|
||||
| 点击维度筛选 | 无 | 展开维度下拉,关闭其他 | typeDropdownVisible=true |
|
||||
| 选择维度 | 下拉展开 | 切换对应 dim-container 显隐,重新请求数据 | selectedType 更新 |
|
||||
| 点击项目筛选 | 无 | 展开项目下拉,关闭其他 | projectDropdownVisible=true |
|
||||
| 选择项目 | 下拉展开 | 重新请求数据 | selectedProject 更新 |
|
||||
| 点击客户卡片 | 无 | navigateTo customer-detail | — |
|
||||
| 切换看板 Tab | 顶部 Tab 栏 | navigateTo board-finance / board-coach | — |
|
||||
| 滚动页面 | 持续 | 下滑隐藏筛选栏,上滑显示 | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 筛选器选项(忠于原型 HTML)
|
||||
|
||||
### 维度/类型筛选(8 个)
|
||||
1. 最应召回 — WBI(加权流失指数),综合到店间隔、消费频率、余额等
|
||||
2. 最大消费潜力 — 综合权重(频率×客单×余额×活跃度)
|
||||
3. 最高余额
|
||||
4. 最近充值
|
||||
5. 最近到店
|
||||
6. 最高消费 近60天
|
||||
7. 最频繁 近60天
|
||||
8. 最专一 近60天 — 亲密度最大值(该客户对某助教的服务集中度)
|
||||
|
||||
### 项目筛选
|
||||
全部 / 中🎱 / 斯诺克 / 麻将 / 团建
|
||||
|
||||
## 维度切换 → 卡片结构映射(忠于原型 HTML)
|
||||
|
||||
切换维度时,通过 `selectType(value)` 函数切换对应的 `dim-container` 显隐。每个维度的卡片结构不同:
|
||||
|
||||
| 维度 | container id | 卡片特有内容 |
|
||||
|------|-------------|-------------|
|
||||
| 最应召回 | `dim-recall` | 理想天数 / 已过天数 / 超期天数(红色标签)+ 30天到店次数 / 余额 / 召回指数 |
|
||||
| 最大消费潜力 | `dim-potential` | 频率标签(高频/中频)+ 客单标签 + 余额标签 + 4列网格:30天消费/月均到店/余额/次均消费 |
|
||||
| 最高余额 | `dim-balance` | 最近到店/理想天数 + 3列网格:余额(大字橙色)/月均消耗/可用月数 |
|
||||
| 最近充值 | `dim-recharge` | 最近到店/理想天数 + 4列网格:最后充值/充值金额/60天充值次数/当前余额 |
|
||||
| 最近到店 | `dim-recent` | 到店天数 + 到店频率 + 余额 |
|
||||
| 最高消费 近60天 | `dim-spend60` | 高消费标签 + 3列网格:60天消费/次均消费/到店次数 |
|
||||
| 最频繁 近60天 | `dim-freq60` | 频率标签 + 到店次数/消费金额/次均消费 |
|
||||
| 最专一 近60天 | `dim-loyal` | 专一度指标 + 服务助教分布 |
|
||||
|
||||
### 所有卡片共有元素
|
||||
- 客户昵称 + 爱心 emoji(💖/🧡/💛/💙)+ 喜好标签(🎱/斯/🀅/🎤)
|
||||
- 底部助教行:助教名 + 关系 emoji + 跟/弃 badge
|
||||
- 助教标记样式:有助教跟进时显示助教名+关系状态
|
||||
|
||||
## 筛选栏滚动行为
|
||||
- 下滑时筛选栏隐藏,上滑时重新显示
|
||||
- 由 `initFilterBarScrollBehavior()` 实现
|
||||
|
||||
## 助教身份隐式过滤(PRD 补充)
|
||||
- 助教角色登录时,后台默认只显示该助教 14 天内服务过的客户
|
||||
- 店长角色无此限制,可查看全部客户
|
||||
|
||||
## 页面状态枚举
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/board/customers` | GET | 客户看板(维度+项目筛选) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:board-finance / board-coach(看板 Tab 切换)
|
||||
- 去向:customer-detail / chat
|
||||
|
||||
## 全局组件
|
||||
- 底部 TabBar(看板 active)
|
||||
- AI 悬浮按钮(右下角)
|
||||
- 看板顶部 Tab 栏(财务 / 客户 active / 助教)
|
||||
@@ -1,115 +0,0 @@
|
||||
# 页面名:board-finance(财务看板)
|
||||
|
||||
> PRD 参考:P8 `docs/prd/specs/P8-miniapp-fe-boards.md`;`apps/miniprogram/doc/prd.md` 第九节 9.1
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
看板 Tab 的默认页面。展示多维度交叉筛选的财务数据,含环比开关、目录导航、吸顶板块头、指标解释弹窗。顶部有时间和区域两组筛选器。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| selectedTime | string | "本月" | 时间筛选 |
|
||||
| selectedArea | string | "全部区域" | 区域筛选 |
|
||||
| compareEnabled | boolean | false | 环比对比开关 |
|
||||
| timeDropdownVisible | boolean | false | 时间筛选下拉展开 |
|
||||
| areaDropdownVisible | boolean | false | 区域筛选下拉展开 |
|
||||
| tocVisible | boolean | false | 目录导航面板展开 |
|
||||
| tipVisible | boolean | false | 指标解释弹窗显示 |
|
||||
| tipType | string | "" | 当前显示的指标解释类型 |
|
||||
| currentSection | number | 0 | 当前可视板块索引(用于吸顶和目录高亮) |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/board/finance | loading→false |
|
||||
| 点击时间筛选 | 无 | 展开时间下拉面板,关闭其他面板 | timeDropdownVisible=true |
|
||||
| 选择时间选项 | 下拉展开 | 重新请求数据,关闭下拉 | selectedTime 更新 |
|
||||
| 点击区域筛选 | 无 | 展开区域下拉面板,关闭其他面板 | areaDropdownVisible=true |
|
||||
| 选择区域选项 | 下拉展开 | 重新请求数据,关闭下拉 | selectedArea 更新 |
|
||||
| 切换环比开关 | 无 | 切换所有 `[data-compare]` 元素显隐 | compareEnabled=!compareEnabled |
|
||||
| 点击目录按钮 | 无 | 展开/关闭目录导航面板 | tocVisible=!tocVisible |
|
||||
| 点击目录项 | tocVisible=true | 滚动到对应板块,关闭目录 | currentSection 更新 |
|
||||
| 点击指标"?"图标 | 无 | 底部弹出指标解释弹窗+遮罩 | tipVisible=true |
|
||||
| 点击遮罩/关闭 | tipVisible=true | 关闭指标解释弹窗 | tipVisible=false |
|
||||
| 滚动页面 | 持续 | 检测当前可视板块 → 更新吸顶头+目录高亮;下滑隐藏筛选栏,上滑显示 | currentSection 更新 |
|
||||
| 切换看板 Tab | 顶部 Tab 栏 | navigateTo board-customer / board-coach | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 筛选器选项(忠于原型 HTML)
|
||||
|
||||
### 时间筛选
|
||||
本月 / 上月 / 本周 / 上周 / 前3个月 不含本月 / 本季度 / 上季度 / 最近6个月不含本月
|
||||
|
||||
### 区域筛选
|
||||
全部区域 / 大厅(含 A区/B区/C区)/ 麻将房 / 团建房
|
||||
|
||||
### 筛选联动规则
|
||||
- 选择非"全部区域"时,预收资产板块隐藏
|
||||
- 营业日以 08:00 为分割点
|
||||
|
||||
## 环比开关
|
||||
- 滑块开关样式:44×24px,默认灰色 `#dcdcdc`,激活后蓝色 `#0052d9`
|
||||
- 控制所有 `[data-compare]` 元素的显隐
|
||||
- 环比数据:上升绿色↑、下降红色↓
|
||||
|
||||
## 目录导航(6 个板块)
|
||||
| 序号 | 图标 | 板块名 | section id |
|
||||
|------|------|--------|------------|
|
||||
| 1 | 📈 | 经营一览 | section-overview |
|
||||
| 2 | 💳 | 预收资产 | section-recharge |
|
||||
| 3 | 💰 | 【记账】应计收入确认 | section-revenue |
|
||||
| 4 | 🧾 | 【现金流水】流入 | section-cashflow |
|
||||
| 5 | 📤 | 【现金流水】流出 | section-expense |
|
||||
| 6 | 🎱 | 助教分析 | section-coach |
|
||||
|
||||
## 吸顶板块头
|
||||
- 滚动时检测当前可视板块,在顶部显示对应板块标题
|
||||
- 由 `updateStickyHeader()` + `getCurrentSection()` + `initSectionScrollBehavior()` 实现
|
||||
|
||||
## 筛选栏滚动行为
|
||||
- 下滑时筛选栏隐藏(向上收起)
|
||||
- 上滑时筛选栏重新显示
|
||||
- 由 `initFilterBarScrollBehavior()` 实现
|
||||
|
||||
## 指标解释弹窗
|
||||
- 底部弹出式弹窗 + 半透明遮罩
|
||||
- 点击指标旁的"?"图标触发
|
||||
- 展示对应指标的计算口径和说明
|
||||
|
||||
## 数据板块
|
||||
1. 经营一览(副标题:快速了解收入与现金流的整体健康度)
|
||||
2. 预收资产(仅"全部区域"时显示)
|
||||
3. 【记账】应计收入确认
|
||||
4. 【现金流水】流入
|
||||
5. 【现金流水】流出
|
||||
6. 助教分析
|
||||
|
||||
## AI 智能洞察(PRD 补充)
|
||||
- 来源:AI 应用 2,`cache_type=app2_finance`
|
||||
- 数据格式:JSON 数组,每条含洞察标题+内容
|
||||
- 缓存策略:Redis / 内存缓存,key = `site_id` + 筛选条件(时间+区域),ETL 更新后失效,约 1 小时刷新
|
||||
- 展示位置:经营一览板块底部或独立洞察卡片区域
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 完整财务数据 + 环比 | 有数据 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/board/finance` | GET | 财务看板数据(交叉筛选) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:TabBar 切换 / login(approved,首页设置为看板)
|
||||
- 去向:board-customer / board-coach / chat
|
||||
|
||||
## 全局组件
|
||||
- 底部 TabBar(看板 active)
|
||||
- AI 悬浮按钮
|
||||
- 看板顶部 Tab 栏(财务 active / 客户 / 助教)— sticky 定位
|
||||
@@ -1,47 +0,0 @@
|
||||
# 页面名:chat-history(对话历史)
|
||||
|
||||
> PRD 参考:P9 `docs/prd/specs/P9-miniapp-fe-details.md`;`apps/miniprogram/doc/prd.md` 第十节
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示历史 AI 对话记录列表,按时间倒序排列。点击可进入继续对话。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| conversations | array | [] | 历史对话列表 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/chat/conversations | loading→false |
|
||||
| 点击对话记录 | 无 | navigateTo chat(带 sessionId,继续对话) | — |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 列表展示
|
||||
- 按时间倒序排列
|
||||
- 每条记录:对话标题/摘要 + 最后消息时间 + 消息数量
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 对话列表 | 有数据 |
|
||||
| 空数据态 | "暂无数据" | conversations 为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/chat/conversations` | GET | 对话历史列表 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:my-profile(点击"助手对话记录")
|
||||
- 去向:chat(点击对话记录,继续对话)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "对话记录")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,81 +0,0 @@
|
||||
# 页面名:chat(AI 对话)
|
||||
|
||||
> PRD 参考:P9 `docs/prd/specs/P9-miniapp-fe-details.md`;`apps/miniprogram/doc/prd.md` 第十节
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
与 AI 助手进行对话。支持文本输入和语音输入,AI 回复流式展示(SSE)。从其他页面进入时携带上下文引用。
|
||||
|
||||
> 原型 HTML 为纯静态展示(对话内容硬编码),仅有顶部返回 `history.back()` 一个交互事件。以下交互逻辑基于 PRD 设计。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| messages | array | [] | 对话消息列表 |
|
||||
| inputText | string | "" | 输入框内容 |
|
||||
| isRecording | boolean | false | 录音状态 |
|
||||
| referenceContent | object | null | 引用内容(来源页面 title + 基本信息) |
|
||||
| sessionId | string | "" | 会话 ID |
|
||||
| isStreaming | boolean | false | AI 正在流式回复 |
|
||||
| loading | boolean | false | 加载历史消息中 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载(新对话) | 从其他页面进入 | 创建新会话,第一条消息为页面上下文 | sessionId 设置 |
|
||||
| 页面加载(继续对话) | 从 chat-history 进入 | 加载历史消息 | messages 填充 |
|
||||
| 输入文本 + 点击发送 | inputText 非空 | POST /api/chat/conversations/:id/messages(SSE) | isStreaming=true |
|
||||
| 按住说话 | 无 | 开始录音 | isRecording=true |
|
||||
| 松开说话 | isRecording=true | 语音转文字 → 填充输入框 | isRecording=false |
|
||||
| AI 回复完成 | SSE 流结束 | 消息列表更新 | isStreaming=false |
|
||||
| 上拉加载 | 有更早记录 | 加载更早消息 | loading=true→false |
|
||||
| 距最后消息 >1 小时 | 时间判断 | 显示"新对话主题"和"继续对话"按钮 | — |
|
||||
| 点击"新对话主题" | 提示条显示 | 创建新会话 | sessionId 更新 |
|
||||
| 点击"继续对话" | 提示条显示 | 在当前会话继续 | — |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack / history.back() | — |
|
||||
|
||||
## 消息展示规则
|
||||
- IM 风格:左侧 AI 气泡,右侧用户气泡
|
||||
- AI 回复支持流式展示(逐字输出)
|
||||
- 引用内容:灰底卡片,含来源类型、标题、摘要
|
||||
- 发送后自动滚动到底部
|
||||
|
||||
## AI 对话来源展示规则(PRD 补充)
|
||||
从不同入口进入 chat 页面时,引用卡片的来源 title 定义:
|
||||
| 入口页面 | 来源 title | 携带上下文 |
|
||||
|----------|-----------|-----------|
|
||||
| task-list 长按菜单"问问AI助手" | 任务:{客户昵称} | 任务类型 + 客户基本信息 |
|
||||
| task-detail "问问助手" | 任务详情:{客户昵称} | 任务详情 + 客户信息 + AI 分析 |
|
||||
| customer-detail "问问助手" | 客户:{客户昵称} | 客户信息 + 消费记录 + 指数 |
|
||||
| AI 悬浮按钮(任意页面) | 当前页面名称 | 当前页面上下文 |
|
||||
| chat-history 继续对话 | 历史对话 | 历史消息 |
|
||||
|
||||
## 会话管理规则(PRD 补充)
|
||||
- 距最后一条消息超过 1 小时:页面顶部显示提示条,含两个按钮:
|
||||
- 「新对话主题」→ 创建新 sessionId,清空消息区
|
||||
- 「继续对话」→ 保持当前 sessionId,在原会话追加
|
||||
- 每个会话有独立 sessionId,用于后端关联上下文
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 空对话 | 引用卡片 + 空消息区 | 新对话,未发送 |
|
||||
| 对话中 | 消息列表 + 输入区 | 有消息 |
|
||||
| AI 回复中 | 最后一条消息逐字输出 | isStreaming=true |
|
||||
| 录音中 | 输入区显示录音动画 | isRecording=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `POST /api/chat/conversations` | POST | 创建对话 |
|
||||
| `POST /api/chat/conversations/:id/messages` | POST | 发送消息(SSE 流式返回) |
|
||||
| `GET /api/chat/conversations/:id/messages` | GET | 对话消息列表 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:任意业务页面(AI 悬浮按钮 / "问问助手"按钮)/ chat-history
|
||||
- 去向:无(末端页面)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "智能助手")
|
||||
- 无底部 TabBar
|
||||
- 无 AI 悬浮按钮(本页即为 AI 对话)
|
||||
@@ -1,100 +0,0 @@
|
||||
# 页面名:coach-detail(助教详情)
|
||||
|
||||
> PRD 参考:P9 `docs/prd/specs/P9-miniapp-fe-details.md`
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示助教完整信息:绩效概览、收入明细(本月/上月 Tab)、任务执行(展开/收起)、客户关系 TOP5、近期服务明细、更多信息。支持备注弹窗。
|
||||
|
||||
## Banner 主题
|
||||
`banner-bg theme-coral texture-aurora`(珊瑚粉主题 + 极光丝带纹理)
|
||||
|
||||
> ⚠️ Banner 背景使用 CSS 渐变+SVG 纹理,小程序实现时建议导出为图片资源 `/assets/images/banner-coral.png`
|
||||
|
||||
## 页面区域结构(忠于原型 HTML)
|
||||
1. Banner(助教信息:花名/等级/技能标签/工龄/客户数)
|
||||
- 工龄计算(PRD 补充):入职时间到当前日期的年数(精确到 0.1 年)
|
||||
2. 绩效概览(`st blue`)— 4宫格:本月定档业绩/本月工资预估/客源储值余额/本月任务完成 + 绩效档位进度条
|
||||
3. 收入明细(`st green`)— Tab 切换:本月预估 / 上月
|
||||
4. 任务执行(`st orange`)— 任务列表 + 展开/收起
|
||||
5. 客户关系 TOP5(`st pink`)— 近60天
|
||||
6. 近期服务明细(`st purple`)
|
||||
7. 更多信息(`st teal`)— 入职日期 + 历史月份表格
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| coachInfo | object | null | 助教信息(花名、级别、技能、工龄、客户数) |
|
||||
| incomeTab | string | "this" | 收入明细当前 Tab(this=本月/last=上月) |
|
||||
| tasksExpanded | boolean | false | 任务列表展开状态 |
|
||||
| noteModalVisible | boolean | false | 备注弹窗显示状态 |
|
||||
| noteText | string | "" | 备注输入内容 |
|
||||
| notesPopupVisible | boolean | false | 备注列表弹窗显示状态 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/coaches/:id(含全部区域数据) | loading→false |
|
||||
| 切换收入明细 Tab | 点击"本月"/"上月" | 切换对应内容显隐 | incomeTab 更新 |
|
||||
| 点击"展开全部 ↓" | tasksExpanded=false | 显示隐藏的任务列表(含已放弃任务) | tasksExpanded=true |
|
||||
| 点击"收起 ↑" | tasksExpanded=true | 隐藏多余任务 | tasksExpanded=false |
|
||||
| 点击"备注"按钮 | 无 | 打开备注弹窗 | noteModalVisible=true |
|
||||
| 备注弹窗-提交 | noteText 非空 | POST /api/xcx/notes | Toast "备注已保存",弹窗关闭 |
|
||||
| 点击客户卡片 | 客户关系 TOP5 区域 | navigateTo customer-detail | — |
|
||||
| 点击客户卡片的备注图标 | 无 | 弹出该客户的备注列表弹窗(阻止冒泡,不触发卡片跳转) | notesPopupVisible=true |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack / history.back() | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 收入明细 Tab
|
||||
- 本月(`id="incomeTab_this"`):含「预估」标签,active 状态
|
||||
- 上月(`id="incomeTab_last"`)
|
||||
- 明细项:基础课时费、激励课时费、充值提成、酒水提成、合计
|
||||
- 由 `switchIncomeTab(tab)` 控制切换
|
||||
|
||||
## 任务执行区域
|
||||
- 默认显示前 6 项任务
|
||||
- 隐藏区域 `id="hiddenTasks"`:更多任务 + 已放弃任务
|
||||
- 已放弃任务样式:opacity 0.55 + 删除线 + 放弃原因文字
|
||||
- 展开/收起按钮 `id="toggleTasksBtn"`:文字在「展开全部 ↓」/「收起 ↑」间切换
|
||||
- 由 `toggleAllTasks()` 控制
|
||||
|
||||
## 客户关系 TOP5
|
||||
- 标题右侧标注「近60天」
|
||||
- 5 个客户卡片,每个含:
|
||||
- 头像圆形 + 姓名 + 关系 emoji(❤️/💛)+ 关系分数(彩色)
|
||||
- 服务次数 / 储值 / 消费
|
||||
- 前 2 名有渐变背景(pink/amber),后 3 名灰色背景
|
||||
|
||||
## 备注弹窗
|
||||
- 底部弹出式弹窗
|
||||
- 包含:多行文本输入 + 提交按钮
|
||||
- 空值校验:内容为空时 Toast 提示
|
||||
- 由 `showNoteModal()` / `hideNoteModal()` / `saveNote()` 控制
|
||||
|
||||
## 备注列表弹窗
|
||||
- 点击客户卡片的备注图标触发
|
||||
- 动态渲染该客户的备注列表
|
||||
- 由 `showNotesPopup(name, notes)` / `hideNotesPopup()` 控制
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 完整助教详情 | 有数据 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/coaches/:id` | GET | 助教详情(含绩效、收入、任务、客户关系) |
|
||||
| `POST /api/xcx/notes` | POST | 创建备注 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:board-coach(点击助教卡片)
|
||||
- 去向:task-detail*(点击客户卡片)/ chat(通过悬浮按钮)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "助教详情")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,71 +0,0 @@
|
||||
# 页面名:customer-detail(客户详情)
|
||||
|
||||
> PRD 参考:P9 `docs/prd/specs/P9-miniapp-fe-details.md`
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示客户全信息、消费记录(三种样式)、指数总览、备注、AI 维客线索、AI 客户分析。纯静态展示页(原型中无复杂交互函数)。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| customerInfo | object | null | 客户信息(昵称、手机、会员卡等级、余额、注册日期) |
|
||||
| indexes | object | null | 指数总览(WBI/NCI/SPI + 爱心 icon) |
|
||||
| consumptionRecords | array | [] | 消费记录列表 |
|
||||
| consumptionPage | number | 1 | 消费记录当前页 |
|
||||
| hasMoreRecords | boolean | true | 是否还有更多消费记录 |
|
||||
| retentionClues | array | [] | AI 维客线索(应用 8) |
|
||||
| customerAnalysis | object | null | AI 客户分析(应用 7) |
|
||||
| notes | array | [] | 备注列表 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
| loadingMore | boolean | false | 加载更多消费记录中 |
|
||||
|
||||
## 用户操作 → 响应(忠于原型 HTML)
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | 请求客户详情+指数+消费记录+AI 数据 | loading→false |
|
||||
| 滚动到底部 | hasMoreRecords=true | GET 消费记录下一页(每次 10 条) | loadingMore=true→false |
|
||||
| 点击"问问助手" | 底部按钮 | navigateTo chat(`window.location.href='chat.html'`) | — |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack(`history.back()`) | — |
|
||||
|
||||
> 原型 HTML 中仅有两个内联事件:顶部返回 `history.back()` 和底部"问问助手" `window.location.href='chat.html'`,无其他动态交互函数。
|
||||
|
||||
## 消费记录三种样式
|
||||
1. 台桌结账:下沉到 `dwd_table_fee_log`,每条台费详情,关联总金额汇总
|
||||
2. 商城订单:助教列表(花名+级别+课程类型+服务时长+定档绩效)、支付金额、食品酒水总金额
|
||||
3. 充值:充值金额、支付方式
|
||||
|
||||
## 消费记录展示规则
|
||||
- 默认 10 条,拉到底懒加载(每次 10 条)
|
||||
- 金额为 0 的项不展示
|
||||
- 有团购/折扣时展示正价+实付
|
||||
- 总金额仅在消费条目 >1 时出现
|
||||
|
||||
## AI 区域展示
|
||||
- 维客线索(应用 8):Emoji 二级标签,提供者逗号分隔(By:系统/By:备注)
|
||||
- 客户分析(应用 7,`cache_type=app7_customer_analysis`):运营策略数组 + 总结
|
||||
- 触发时机(PRD 补充):客户结账单出现后自动生成
|
||||
- 应用 3 与应用 7 共用同一 cache_type,应用 3 为简版摘要,应用 7 为完整分析
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 完整客户详情 | 有数据 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/customers/:id` | GET | 客户详情 |
|
||||
| `GET /api/customers/:id/consumption-records` | GET | 消费记录(分页,懒加载) |
|
||||
| `GET /api/customers/:id/indexes` | GET | 客户指数总览 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:board-customer(点击客户卡片)/ task-detail / performance
|
||||
- 去向:chat(问问助手)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "客户详情")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,54 +0,0 @@
|
||||
# 页面名:customer-service-records(客户服务记录)
|
||||
|
||||
> PRD 参考:P9 `docs/prd/specs/P9-miniapp-fe-details.md`
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示某客户的服务记录列表,支持月份前后切换。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| records | array | [] | 服务记录列表 |
|
||||
| currentMonth | number | 当前月 | 当前显示月份 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/customers/:id/service-records | loading→false |
|
||||
| 点击"←"(上月) | currentMonth > 最小月 | 切换到上一月,更新月份标签 | currentMonth-- |
|
||||
| 点击"→"(下月) | currentMonth < 最大月 | 切换到下一月,更新月份标签 | currentMonth++ |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 月份切换器(忠于原型 HTML)
|
||||
- 样式:← 2026年X月 →
|
||||
- 到达边界时对应箭头按钮变灰禁用(opacity 0.3)
|
||||
- 由 `customer-service-records.js` 的 `switchMonth(direction)` 控制
|
||||
|
||||
## 记录展示
|
||||
- 每条记录:服务时间 + 持续时长
|
||||
- 按时间倒序排列
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 服务记录列表 | 有数据 |
|
||||
| 空数据态 | "暂无数据" | records 为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/customers/:id/service-records` | GET | 客户服务记录(支持月份参数) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:customer-detail / task-detail
|
||||
- 去向:无(末端页面)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "服务记录")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,52 +0,0 @@
|
||||
# 页面名:login(登录页)
|
||||
|
||||
> PRD 参考:`apps/miniprogram/doc/prd.md` 第七节 7.1;P3 认证系统
|
||||
> 已实现:是(`apps/miniprogram/miniprogram/pages/login/`)
|
||||
|
||||
## 页面说明
|
||||
微信授权登录入口页。用户需勾选协议后才能点击登录按钮。登录后根据用户状态跳转到不同页面。
|
||||
|
||||
## 视觉元素(忠于原型 HTML)
|
||||
- 顶部 Logo:台球图标 SVG(需转为图片资源 `/assets/icons/logo-billiard.svg`)
|
||||
- 应用名称文字
|
||||
- 微信登录按钮:渐变背景,含微信图标 SVG
|
||||
- 底部协议勾选区域:勾选框 + 协议链接文字
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| agreed | boolean | false | 协议勾选状态 |
|
||||
| loading | boolean | false | 登录请求中 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 点击协议勾选框 | 无 | 切换 agreed | agreed=!agreed |
|
||||
| 点击"使用微信登录" | agreed=true | 调用 wx.login() 获取 code → POST /api/xcx-auth/login | loading=true |
|
||||
| 点击"使用微信登录" | agreed=false | 无响应(按钮禁用态) | 不变 |
|
||||
| 登录成功(status=new) | API 返回 | 跳转 apply 页面 | redirectTo apply |
|
||||
| 登录成功(status=pending) | API 返回 | 跳转 reviewing 页面 | redirectTo reviewing |
|
||||
| 登录成功(status=approved) | API 返回 | 跳转默认首页(task-list 或 board-finance) | switchTab |
|
||||
| 登录成功(status=rejected) | API 返回 | 跳转 no-permission 页面 | redirectTo no-permission |
|
||||
| 登录成功(status=disabled) | API 返回 | 跳转 no-permission 页面 | redirectTo no-permission |
|
||||
| 登录失败 | API 报错 | Toast 提示错误信息 | loading=false |
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 默认态 | 按钮灰色禁用,协议未勾选 | agreed=false |
|
||||
| 可登录态 | 按钮蓝色渐变+阴影,协议已勾选 | agreed=true |
|
||||
| 加载中 | 按钮显示 loading 动画 | loading=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `/api/xcx-auth/login` | POST | 微信登录(code → JWT + user_status) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:小程序启动 / 退出账号后 / reviewing/no-permission 点击"更换登录账号"
|
||||
- 去向:apply / reviewing / no-permission / task-list / board-finance
|
||||
|
||||
## 全局组件
|
||||
- 无底部 TabBar
|
||||
- 无 AI 悬浮按钮
|
||||
@@ -1,48 +0,0 @@
|
||||
# 页面名:my-profile(我的首页)
|
||||
|
||||
> PRD 参考:`apps/miniprogram/doc/prd.md` 第十一节
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
用户个人中心菜单页(Tab 3)。展示用户信息和功能入口列表。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| userInfo | object | null | 用户信息(用户名、身份、门店) |
|
||||
| logoutConfirmVisible | boolean | false | 退出账号确认弹窗 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | 读取缓存用户信息 | — |
|
||||
| 点击"备注记录" | 无 | navigateTo notes | — |
|
||||
| 点击"助手对话记录" | 无 | navigateTo chat-history | — |
|
||||
| 点击"退出账号" | 无 | 显示确认弹窗 | logoutConfirmVisible=true |
|
||||
| 确认退出 | 弹窗确认 | 清除登录态 + redirectTo login | — |
|
||||
| 取消退出 | 弹窗取消 | 关闭弹窗 | logoutConfirmVisible=false |
|
||||
|
||||
## 菜单列表
|
||||
| 菜单项 | 图标 | 跳转目标 |
|
||||
|--------|------|----------|
|
||||
| 备注记录 | `<t-icon name="edit-1" />` | notes |
|
||||
| 助手对话记录 | `<t-icon name="chat" />` | chat-history |
|
||||
| 退出账号 | `<t-icon name="poweroff" />` | 确认弹窗 → login |
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 默认态 | 用户信息 + 菜单列表 | 始终 |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/xcx-auth/status` | GET | 获取用户信息(可从缓存读取) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:TabBar 切换
|
||||
- 去向:notes / chat-history / login(退出)
|
||||
|
||||
## 全局组件
|
||||
- 底部 TabBar(我的 active)— 由 `bottom-nav.js` 自动注入
|
||||
- AI 悬浮按钮
|
||||
@@ -1,44 +0,0 @@
|
||||
# 页面名:no-permission(无权限页)
|
||||
|
||||
> PRD 参考:`apps/miniprogram/doc/prd.md` 第七节 7.4
|
||||
> 已实现:是(`apps/miniprogram/miniprogram/pages/no-permission/`)
|
||||
|
||||
## 页面说明
|
||||
纯展示页,告知用户申请被拒或账号无权限。包含可能原因列表和联系管理员信息。底部可切换登录账号。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| (无) | — | — | 纯展示页,无交互状态 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 点击"更换登录账号" | 底部按钮 | 清除登录态 → redirectTo login | — |
|
||||
|
||||
## 视觉元素(忠于原型 HTML)
|
||||
- 主图标:rose→red 渐变圆角方块内,白色描边的禁止符号 SVG(圆形 + 对角线)
|
||||
- ⚠️ 此 SVG 较复杂,小程序实现时建议转为图片资源 `/assets/images/icon-no-permission.png`
|
||||
- 标题:「无访问权限」
|
||||
- 副标题:「很抱歉,您的访问申请未通过审核,或当前账号无访问权限」
|
||||
- 原因卡片:
|
||||
- 标题「可能的原因」(Material 风格 info 图标)
|
||||
- 列表项:申请信息不完整或不符合要求 / 非本店授权员工账号 / 账号权限已被管理员收回
|
||||
- 联系管理员:问号圆圈图标 + 「如有疑问,请联系管理员重新申请」
|
||||
- 底部按钮:登出箭头图标 + 「更换登录账号」
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 默认态 | 完整无权限展示(图标+原因+联系提示+底部按钮) | 始终 |
|
||||
|
||||
## 后端 API 依赖
|
||||
无(纯展示页)
|
||||
|
||||
## 页面导航
|
||||
- 来源:login(status=rejected / disabled)
|
||||
- 去向:login(点击"更换登录账号")/ 用户再次打开小程序时重新判断状态
|
||||
|
||||
## 全局组件
|
||||
- 无底部 TabBar
|
||||
- 无 AI 悬浮按钮
|
||||
@@ -1,56 +0,0 @@
|
||||
# 页面名:notes(备注记录)
|
||||
|
||||
> PRD 参考:P6 `docs/prd/specs/P6-miniapp-fe-tasks.md`;`apps/miniprogram/doc/prd.md` 第十一节
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示用户所有备注记录,支持按 Tab 切换「客户备注」和「助教备注」两个分类。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| activeTab | string | "customer" | 当前 Tab(customer/coach) |
|
||||
| customerNotes | array | [] | 客户备注列表 |
|
||||
| coachNotes | array | [] | 助教备注列表 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/xcx/notes | loading→false |
|
||||
| 点击"客户备注" Tab | activeTab≠customer | 切换显示客户备注列表,隐藏助教备注 | activeTab=customer |
|
||||
| 点击"助教备注" Tab | activeTab≠coach | 切换显示助教备注列表,隐藏客户备注 | activeTab=coach |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## Tab 切换(忠于原型 HTML)
|
||||
- 两个 Tab:客户备注(`id="tabCustomer"`)/ 助教备注(`id="tabCoach"`)
|
||||
- 切换时互斥显隐对应列表容器(`id="customerNotes"` / `id="coachNotes"`)
|
||||
- 由 `notes.js` 的 `switchTab(tab)` 控制
|
||||
|
||||
## 列表展示规则
|
||||
- 按时间倒序(由近到远)平铺
|
||||
- 每条记录:备注全文 + 关联对象(客户/助教)+ 创建时间
|
||||
- 不进入详情页,本页即为详情展示
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 备注列表 | 有数据 |
|
||||
| 空数据态 | "暂无数据" | 当前 Tab 列表为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/xcx/notes` | GET | 获取备注列表(含客户和助教两类) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:my-profile(点击"备注记录")
|
||||
- 去向:无(末端页面)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "备注记录")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,64 +0,0 @@
|
||||
# 页面名:performance-records(业绩明细 / 服务记录)
|
||||
|
||||
> PRD 参考:P7 `docs/prd/specs/P7-miniapp-fe-performance.md`
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示按月份切换的服务记录明细列表。顶部有统计概览(总记录/总时长/收入),下方按日期分组展示服务记录。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| records | array | [] | 服务记录列表 |
|
||||
| currentMonth | number | 当前月 | 当前显示月份 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/performance/records | loading→false |
|
||||
| 点击"←"(上月) | currentMonth > 最小月 | 切换到上一月,更新月份标签,重新请求数据 | currentMonth-- |
|
||||
| 点击"→"(下月) | currentMonth < 最大月 | 切换到下一月,更新月份标签,重新请求数据 | currentMonth++ |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack / history.back() | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 月份切换器(忠于原型 HTML)
|
||||
- 样式:← 2026年X月 →
|
||||
- 到达边界时对应箭头按钮变灰禁用(opacity 0.3)
|
||||
- 由 `customer-service-records.js` 的 `switchMonth(direction)` 控制
|
||||
|
||||
## 统计概览
|
||||
- 总记录数 / 总时长 / 收入合计
|
||||
- 当月数据标记"预估"
|
||||
|
||||
## 记录展示规则
|
||||
- 按日期分组,每组显示日期标题
|
||||
- 每条记录:服务时间、课程类型、台桌/房间、会员昵称、开始/结束时间、业绩分钟
|
||||
- 有定档折算惩罚时展示:「120分钟(定档折算30分钟)」格式
|
||||
- 营业日以 08:00 为分割点
|
||||
|
||||
## 记录点击交互
|
||||
- 原型 HTML 中记录条目无 onclick 跳转
|
||||
- 产品意图:点击记录可跳转对应任务详情页(需后续确认是否实现)
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 统计概览 + 明细列表 | 有数据 |
|
||||
| 空数据态 | "暂无数据" | records 为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/performance/records` | GET | 业绩明细(支持月份参数) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:performance(点击"查看全部")
|
||||
- 去向:无(末端页面,原型中无跳转)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "服务记录")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,88 +0,0 @@
|
||||
# 页面名:performance(我的业绩)
|
||||
|
||||
> PRD 参考:P7 `docs/prd/specs/P7-miniapp-fe-performance.md`
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示助教业绩全貌:收入档位、本月/上月业绩明细(含服务记录)、新客和常客列表。多个区域支持展开/收起和"查看全部"跳转。
|
||||
|
||||
## Banner 主题
|
||||
`banner-bg theme-blue texture-aurora`(蓝色主题)
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| performanceSummary | object | null | 业绩汇总(收入、档位、工资预估) |
|
||||
| thisMonthRecordsExpanded | boolean | false | 本月服务记录展开状态 |
|
||||
| lastMonthRecordsExpanded | boolean | false | 上月服务记录展开状态 |
|
||||
| newCustomerExpanded | boolean | false | 新客列表展开状态 |
|
||||
| regularCustomerExpanded | boolean | false | 常客列表展开状态 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 页面区域结构(忠于原型 HTML)
|
||||
1. Banner(个人信息:花名/身份/门店 + 核心数据:本月预计收入 + 上月收入)
|
||||
2. 收入情况(`bg-primary` 圆点)— 当前档位 + 下一阶段目标 + 升级提示(「距下一阶段需完成 X 小时,到达即得 Y 元」)
|
||||
- 跳档激励计算公式(PRD 补充):YYY = max(跳档线差值最小值, 实际差值)
|
||||
- 各档差值:Tier0→1: 1200元 / Tier1→2: 750元 / Tier2→3: 540元 / Tier3→4: 420元
|
||||
3. 本月业绩 预估(`bg-success` 圆点)— 基础课时费/激励课时费/充值激励/TOP3销冠奖/合计 + 我的服务记录明细
|
||||
4. 上月收入(`bg-warning` 圆点)— 同结构 + 我的服务记录明细
|
||||
5. 我的新客(`bg-cyan-500` 圆点)— 按时间顺序
|
||||
6. 我的常客(`bg-pink-500` 圆点)— 近2月贡献TOP20
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | 请求业绩汇总+服务记录+新客+常客 | loading→false |
|
||||
| 点击"展开更多"(本月服务记录) | thisMonthRecordsExpanded=false | 显示隐藏的更多记录条目,按钮文字变「收起」 | thisMonthRecordsExpanded=true |
|
||||
| 点击"收起"(本月服务记录) | thisMonthRecordsExpanded=true | 隐藏多余记录条目,按钮文字变「展开更多」 | thisMonthRecordsExpanded=false |
|
||||
| 点击"展开更多"(上月服务记录) | lastMonthRecordsExpanded=false | 同上 | lastMonthRecordsExpanded=true |
|
||||
| 点击"收起"(上月服务记录) | lastMonthRecordsExpanded=true | 同上 | lastMonthRecordsExpanded=false |
|
||||
| 点击"查看全部"(本月) | 服务记录区域 | navigateTo performance-records(本月口径) | — |
|
||||
| 点击"查看全部"(上月) | 服务记录区域 | navigateTo performance-records(上月口径) | — |
|
||||
| 点击"查看更多 ↓"(新客列表) | newCustomerExpanded=false | 展开完整新客列表 | newCustomerExpanded=true |
|
||||
| 点击"收起 ↑"(新客列表) | newCustomerExpanded=true | 收起新客列表 | newCustomerExpanded=false |
|
||||
| 点击"查看更多 ↓"(常客列表) | regularCustomerExpanded=false | 展开完整常客列表 | regularCustomerExpanded=true |
|
||||
| 点击"收起 ↑"(常客列表) | regularCustomerExpanded=true | 收起常客列表 | regularCustomerExpanded=false |
|
||||
| 点击新客/常客卡片 | 无 | navigateTo task-detail(按该客户当前任务类型跳转对应详情页) | — |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack / history.back() | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 服务记录展示
|
||||
- 按天归总,每天显示服务次数和总时长
|
||||
- 默认显示前几条,其余折叠
|
||||
- 展开/收起按钮:`id="thisMonthRecordsToggle"` / `id="lastMonthRecordsToggle"`
|
||||
- "查看全部"链接跳转 `performance-records.html`
|
||||
|
||||
## 新客/常客展示
|
||||
- 我的新客:该助教首次服务 + 2 月内 + 服务次数 ≤2,按最后服务时间排列
|
||||
- 我的常客:近2月贡献TOP20,按服务次数降序,展示次数、小时数、工资合计
|
||||
- 两个列表均支持展开/收起(`toggleNewCustomer()` / `toggleRegularCustomer()`)
|
||||
|
||||
## 业绩数据说明
|
||||
- 营业日以 08:00 为分割点("本月"= 当月1日 08:00 ~ 次月1日 08:00)
|
||||
- 当月数据标记"预估"
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 完整业绩展示 | 有数据 |
|
||||
| 空数据态 | 各区域"暂无数据" | 对应列表为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/performance/summary` | GET | 当月绩效汇总 |
|
||||
| `GET /api/performance/service-records` | GET | 服务记录明细(分页) |
|
||||
| `GET /api/performance/my-new-customers` | GET | 我的新客列表 |
|
||||
| `GET /api/performance/my-regulars` | GET | 我的常客列表 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:task-list(点击 Banner 业绩区域)
|
||||
- 去向:performance-records(查看全部)/ task-detail*(点击新客/常客卡片)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "我的业绩")
|
||||
- AI 悬浮按钮
|
||||
@@ -1,44 +0,0 @@
|
||||
# 页面名:reviewing(审核中页)
|
||||
|
||||
> PRD 参考:`apps/miniprogram/doc/prd.md` 第七节 7.3
|
||||
> 已实现:是(`apps/miniprogram/miniprogram/pages/reviewing/`)
|
||||
|
||||
## 页面说明
|
||||
纯展示页,告知用户申请正在审核中。包含审核进度展示和联系管理员提示。底部可切换登录账号。
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| (无) | — | — | 纯展示页,无交互状态 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 点击"更换登录账号" | 底部按钮 | 清除登录态 → redirectTo login | — |
|
||||
|
||||
## 视觉元素(忠于原型 HTML)
|
||||
- 主图标:amber→orange 渐变圆角方块内,白色描边的圆形时钟 SVG(圆形表盘 + 时针分针折线),带上下浮动动画
|
||||
- ⚠️ 此 SVG 较复杂,小程序实现时建议转为图片资源 `/assets/images/icon-reviewing.png`
|
||||
- 标题:「申请审核中」
|
||||
- 副标题:「您的访问申请已提交成功,正在等待管理员审核,请耐心等待」
|
||||
- 审核进度卡片:
|
||||
- 标题「审核进度」+ 副文字「通常需要 1-3 个工作日」
|
||||
- 三步进度条:已提交(绿色对勾圆圈)→ 审核中(高亮)→ 通过(灰色)
|
||||
- 联系提示:聊天气泡图标 + 「如有疑问,请联系管理员」
|
||||
- 底部按钮:登出箭头图标 + 「更换登录账号」
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 默认态 | 完整审核中展示(图标+进度+联系提示+底部按钮) | 始终 |
|
||||
|
||||
## 后端 API 依赖
|
||||
无(纯展示页)
|
||||
|
||||
## 页面导航
|
||||
- 来源:login(status=pending)/ apply(提交成功)
|
||||
- 去向:login(点击"更换登录账号")/ 用户再次打开小程序时重新判断状态
|
||||
|
||||
## 全局组件
|
||||
- 无底部 TabBar
|
||||
- 无 AI 悬浮按钮
|
||||
@@ -1,26 +0,0 @@
|
||||
# 页面名:task-detail-callback(任务详情 - 客户回访)
|
||||
|
||||
> 本页为 task-detail 系列的变体页面,完整交互说明见 `task-detail.md`。
|
||||
> 此文件仅记录与 task-detail.html 的差异。
|
||||
|
||||
## 与 task-detail.html 的差异
|
||||
|
||||
| 差异点 | task-detail(高优先召回) | task-detail-callback(客户回访) |
|
||||
|--------|--------------------------|----------------------------------|
|
||||
| Banner 主题 | `theme-red` 红色 | `theme-teal` 青绿色 |
|
||||
| 区域顺序 | ①与我的关系 → ②任务建议 → ③维客线索 → ④备注 → ⑤近期服务记录 | ①维客线索 → ②与我的关系(含近期服务记录)→ ③任务建议 → ④备注 |
|
||||
| 话术样式 | 气泡样式(`.speech-bubble`,带复制按钮) | 竖线样式(`border-l-2`,左侧竖线+左内边距) |
|
||||
| 任务建议标题 | 💡 建议执行 | 📞 常规回访要点 |
|
||||
| 底部按钮颜色 | `from-primary to-blue-500` | `from-teal-500 to-cyan-500` |
|
||||
| 导航栏"放弃"按钮 | 有 | 无 |
|
||||
| 近期服务记录 | 独立区域(第5区域) | 嵌入"与我的关系"卡片内(`.svc-section-bg`) |
|
||||
| ratingExpanded 初始值 | false(需点击"展开评价") | true(默认展开) |
|
||||
|
||||
## 实现建议
|
||||
在小程序中,task-detail 系列不需要 4 个独立页面。可以在同一页面通过路由参数 `taskType` 控制:
|
||||
- Banner 主题色
|
||||
- 区域排列顺序
|
||||
- 话术样式(气泡 vs 竖线)
|
||||
- 任务建议标题文案
|
||||
- 是否显示"放弃"按钮
|
||||
- ratingExpanded 初始值
|
||||
@@ -1,17 +0,0 @@
|
||||
# 页面名:task-detail-priority(任务详情 - 优先召回)
|
||||
|
||||
> 本页为 task-detail 系列的变体页面,完整交互说明见 `task-detail.md`。
|
||||
> 此文件仅记录与 task-detail.html(高优先召回)的差异。
|
||||
|
||||
## 与 task-detail.html 的差异
|
||||
|
||||
| 差异点 | task-detail(高优先召回) | task-detail-priority(优先召回) |
|
||||
|--------|--------------------------|----------------------------------|
|
||||
| Banner 主题 | `theme-red` 红色 | `theme-orange` 橙色 |
|
||||
| 任务类型标签 | 高优先召回 | 优先召回 |
|
||||
| 标签颜色 | 红色系 | 橙色系 |
|
||||
|
||||
其余结构(区域顺序、话术样式、底部操作栏、放弃按钮等)与 task-detail.html 完全一致。
|
||||
|
||||
## 实现建议
|
||||
在小程序中,task-detail 系列不需要 4 个独立页面。可以在同一页面通过路由参数 `taskType` 控制 Banner 主题色和标签样式。
|
||||
@@ -1,26 +0,0 @@
|
||||
# 页面名:task-detail-relationship(任务详情 - 关系构建)
|
||||
|
||||
> 本页为 task-detail 系列的变体页面,完整交互说明见 `task-detail.md`。
|
||||
> 此文件仅记录与 task-detail.html(高优先召回)的差异。
|
||||
|
||||
## 与 task-detail.html 的差异
|
||||
|
||||
| 差异点 | task-detail(高优先召回) | task-detail-relationship(关系构建) |
|
||||
|--------|--------------------------|--------------------------------------|
|
||||
| Banner 主题 | `theme-red` 红色 | `theme-pink` 粉色 |
|
||||
| 区域顺序 | ①与我的关系 → ②任务建议 → ③维客线索 → ④备注 → ⑤近期服务记录 | ①维客线索 → ②与我的关系(含近期服务记录)→ ③任务建议 → ④备注 |
|
||||
| 话术样式 | 气泡样式(`.speech-bubble`,带复制按钮) | 竖线样式(`border-l-2`,左侧竖线+左内边距) |
|
||||
| 任务建议标题 | 💡 建议执行 | 💝 关系构建重点 |
|
||||
| 任务建议背景 | 蓝色系 | `from-pink-50 to-rose-50` |
|
||||
| 底部按钮颜色 | `from-primary to-blue-500` | `from-pink-500 to-rose-500` |
|
||||
| 导航栏"放弃"按钮 | 有 | 无 |
|
||||
| 近期服务记录 | 独立区域(第5区域) | 嵌入"与我的关系"卡片内 |
|
||||
| 备注区域 | 有已有备注展示 | 可能为空状态(提示「快点击下方备注按钮,添加客人备注!」) |
|
||||
|
||||
## 实现建议
|
||||
在小程序中,task-detail 系列不需要 4 个独立页面。可以在同一页面通过路由参数 `taskType` 控制:
|
||||
- Banner 主题色
|
||||
- 区域排列顺序
|
||||
- 话术样式(气泡 vs 竖线)
|
||||
- 任务建议标题和背景色
|
||||
- 是否显示"放弃"按钮
|
||||
@@ -1,148 +0,0 @@
|
||||
# 页面名:task-detail 系列(任务详情)
|
||||
|
||||
> PRD 参考:P6 `docs/prd/specs/P6-miniapp-fe-tasks.md`;`apps/miniprogram/doc/prd.md` 第八节 8.2
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
展示客户详细信息、消费习惯、AI 分析(关系分析+任务建议+话术参考+备注评分)、维客线索、备注入口。底部固定操作栏。
|
||||
|
||||
task-detail 系列共 4 个页面,卡片内容相同(以 task-detail.html 为准),差异仅在:头部 Banner 主题/配色、区域排列顺序、话术样式、部分文案。
|
||||
|
||||
## Banner 主题映射表
|
||||
| 页面 | Banner class | 主题色 | 任务类型 |
|
||||
|------|-------------|--------|----------|
|
||||
| task-detail.html | `banner-bg theme-red texture-aurora` | 红色 | 高优先召回 |
|
||||
| task-detail-priority.html | (同 task-detail,橙色变体) | 橙色 | 优先召回 |
|
||||
| task-detail-relationship.html | `banner-bg theme-pink texture-aurora` | 粉色 | 关系构建 |
|
||||
| task-detail-callback.html | `banner-bg theme-teal texture-aurora` | 青绿色 | 客户回访 |
|
||||
|
||||
> ⚠️ Banner 背景使用 CSS 渐变+SVG 纹理(`banner.css` 中的 `texture-aurora`),内含复杂的 SVG 丝带效果。小程序实现时建议将各主题 Banner 背景导出为图片资源,统一放 `/assets/images/banner-{theme}.png`。
|
||||
|
||||
## 页面区域顺序差异
|
||||
| 区域 | task-detail(高优先/优先) | task-detail-relationship(关系构建) | task-detail-callback(客户回访) |
|
||||
|------|--------------------------|--------------------------------------|----------------------------------|
|
||||
| 1 | 与我的关系 | 维客线索 | 维客线索 |
|
||||
| 2 | 任务建议 | 与我的关系(含近期服务记录) | 与我的关系(含近期服务记录) |
|
||||
| 3 | 维客线索 | 任务建议 | 任务建议 |
|
||||
| 4 | 我给TA的备注 | 我给TA的备注 | 我给TA的备注 |
|
||||
| 5 | 近期服务记录 | (嵌入区域2) | (嵌入区域2) |
|
||||
|
||||
## 话术样式差异
|
||||
| 页面 | 话术样式 | 说明 |
|
||||
|------|----------|------|
|
||||
| task-detail(高优先/优先) | 气泡样式 `.speech-bubble` | 浅蓝背景+边框+圆角+右下角尖角,每条带「复制」按钮 |
|
||||
| task-detail-relationship | 竖线样式 `border-l-2` | 左侧 2px 竖线 + 左内边距 |
|
||||
| task-detail-callback | 竖线样式 `border-l-2` | 同上 |
|
||||
|
||||
## 任务建议标题差异
|
||||
| 页面 | 标题 | 背景色 |
|
||||
|------|------|--------|
|
||||
| task-detail | 💡 建议执行 | 蓝色系 |
|
||||
| task-detail-relationship | 💝 关系构建重点 | pink→rose |
|
||||
| task-detail-callback | 📞 常规回访要点 | teal→cyan |
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| taskDetail | object | null | 任务详情数据 |
|
||||
| customerInfo | object | null | 客户基本信息 |
|
||||
| serviceRecords | array | [] | 近期服务记录 |
|
||||
| aiAnalysis | object | null | AI 分析(应用 4:关系分析+任务建议+一句话总结) |
|
||||
| retentionClues | array | [] | 维客线索(应用 8 整合线索+人工) |
|
||||
| customerAnalysis | object | null | 客户分析(应用 7:运营策略+总结) |
|
||||
| talkingPoints | object | null | 话术参考(应用 5 缓存) |
|
||||
| noteScore | number | null | 备注分析评分(应用 6:1-10 分) |
|
||||
| noteModalVisible | boolean | false | 备注弹窗显示状态 |
|
||||
| noteText | string | "" | 备注输入内容 |
|
||||
| noteRating | object | {serviceWill: 0, returnChance: 0} | 星星评分(再次服务意愿+再来店可能性,各 1-5 星) |
|
||||
| ratingExpanded | boolean | false | 评分区域是否展开(回访任务默认 true) |
|
||||
| abandonModalVisible | boolean | false | 放弃客户弹窗显示状态(仅高优先/优先召回有) |
|
||||
| abandonReason | string | "" | 放弃原因 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/xcx/tasks/{id} | loading→false |
|
||||
| 点击"问问助手" | 底部操作栏 | navigateTo chat(带任务+客户上下文引用) | — |
|
||||
| 点击"备注" | 底部操作栏 | 打开备注弹窗 | noteModalVisible=true |
|
||||
| 点击"展开评价" | noteModalVisible=true, ratingExpanded=false | 展开星星评分区域,隐藏展开按钮 | ratingExpanded=true |
|
||||
| 拖动/点击星星 | 评分区域展开 | 更新对应评分值(支持触摸拖动+鼠标拖动+点击) | noteRating 更新 |
|
||||
| 备注弹窗-提交 | noteText 非空 | POST /api/xcx/notes(含评分) | Toast "备注已保存",弹窗关闭 |
|
||||
| 点击"复制"(话术气泡) | 气泡样式页面 | 复制话术文本到剪贴板,按钮变"已复制" | — |
|
||||
| 点击"放弃" | 顶部导航栏右侧(仅高优先/优先) | 打开放弃确认弹窗 | abandonModalVisible=true |
|
||||
| 放弃弹窗-确认 | abandonReason 非空 | POST /api/xcx/tasks/{id}/abandon | Toast "已放弃该客户的维护" |
|
||||
| 点击返回 | 顶部导航栏 | navigateBack / history.back() | — |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## "与我的关系"区域
|
||||
- 标题带 section-title pink 样式
|
||||
- AI 机器人图标(可爱机器人 SVG:圆角矩形身体+天线+紫蓝色大眼睛+微笑+粉色腮红+小耳朵)
|
||||
- 此图标可视为心形 ICON 的扩展,小程序中用 `/assets/icons/icon-ai-relationship.svg`
|
||||
- 关系等级色系:💖 非常好(>8.5 粉色渐变) / 🧡 良好(>7) / 💛 一般(>5) / 💙 待发展(<5 蓝色渐变)
|
||||
- 备注评分:星级展示(score ÷ 2 = 星数,支持半星,由 `ai-icons.js` 渲染)
|
||||
|
||||
## AI 应用编号映射(PRD 补充)
|
||||
| 应用编号 | 功能 | cache_type | 展示位置 |
|
||||
|----------|------|------------|----------|
|
||||
| 应用 4 | 关系分析 + 任务建议 + 一句话总结(summary) | `app4_analysis` | 与我的关系 / 任务建议 / 卡片底部 AI 文字 |
|
||||
| 应用 5 | 话术参考(5 条话术) | — | 话术区域 |
|
||||
| 应用 6 | 备注评分(1-10 分,6 分为标准分) | `app6_note_analysis` | 备注弹窗提交后 |
|
||||
| 应用 7 | 客户分析(运营策略 + 总结) | `app7_customer_analysis` | 客户分析区域 |
|
||||
| 应用 8 | 维客线索整合(`member_retention_clue` 表) | — | 维客线索区域 |
|
||||
|
||||
## AI 区域展示规则
|
||||
- 维客线索(应用 8):Emoji 作为二级标签,提供者逗号分隔展示
|
||||
- source=ai_consumption → "By:系统"
|
||||
- source=ai_note → "By:备注"
|
||||
- 客户分析(应用 7):运营策略数组 + 总结文本
|
||||
- 关系分析+任务建议+一句话总结(应用 4)
|
||||
- 话术参考(应用 5):5 条话术,气泡/竖线样式展示
|
||||
- 备注评分(应用 6):1-10 分,6 分为标准分
|
||||
|
||||
## 备注弹窗规则
|
||||
- 底部弹出式弹窗(`.modal-overlay` + `.modal-card`)
|
||||
- 包含:多行文本输入 + 星星评分(再次服务意愿 + 再来店可能性)
|
||||
- 回访任务(task-detail-callback):评分区域默认展开
|
||||
- 其他任务类型:评分区域默认隐藏,通过"展开评价"按钮手动打开
|
||||
- 星星打分交互:支持点击、触摸拖动、鼠标拖动(由 `task-detail-notes.js` 实现)
|
||||
|
||||
### 备注评分与回访完成判定(PRD 补充)
|
||||
- 提交备注后,后端调用应用 6 进行评分(1-10 分,6 分为标准分)
|
||||
- 评分细则:综合备注文本质量、服务意愿星级、再来店可能性星级
|
||||
- 回访任务完成条件:备注评分 ≥ 5 → 任务标记完成;< 5 → 不算完成
|
||||
- 只计第一个备注的评分(后续备注不影响完成判定)
|
||||
- 回访任务有效期 2 天:超过 2 天未完成则标签跳变(回到任务列表重新分配)
|
||||
|
||||
## 放弃客户弹窗(仅高优先/优先召回)
|
||||
- 遮罩层 + 居中弹窗
|
||||
- 包含:多行文本输入(放弃原因)+ 提交按钮(红色 `.danger`)
|
||||
- 空值校验:原因为空时显示错误提示
|
||||
- 关系构建和客户回访页面无"放弃"按钮
|
||||
|
||||
## 底部操作栏
|
||||
- 「问问助手」按钮:渐变背景(颜色随主题变化),聊天气泡图标
|
||||
- 「备注」按钮:灰色背景,编辑笔图标
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 完整详情展示 | 有数据 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/xcx/tasks/{id}` | GET | 获取任务详情(含客户信息+AI 分析) |
|
||||
| `POST /api/xcx/notes` | POST | 创建备注(含评分,触发回访完成判定) |
|
||||
| `POST /api/xcx/tasks/{id}/abandon` | POST | 放弃任务(仅高优先/优先) |
|
||||
|
||||
## 页面导航
|
||||
- 来源:task-list(点击任务卡片,按 task-type 跳转对应页面)
|
||||
- 去向:chat(问问助手)
|
||||
|
||||
## 全局组件
|
||||
- 自定义顶部导航栏(返回按钮 + "任务详情",高优先/优先召回右侧有"放弃"按钮)
|
||||
- AI 悬浮按钮
|
||||
@@ -1,134 +0,0 @@
|
||||
# 页面名:task-list(任务列表 + 业绩概览)
|
||||
|
||||
> PRD 参考:P6 `docs/prd/specs/P6-miniapp-fe-tasks.md`;`apps/miniprogram/doc/prd.md` 第八节 8.1
|
||||
> 已实现:否
|
||||
|
||||
## 页面说明
|
||||
小程序默认首页(Tab 1)。顶部 Banner 展示用户信息和业绩概览,下方为按优先级分组排序的任务列表。支持长按弹出操作菜单(置顶/放弃/问AI/备注)。
|
||||
|
||||
## Banner 主题
|
||||
`banner-bg theme-blue texture-aurora`(蓝色主题 + 极光丝带纹理)
|
||||
|
||||
## 状态变量
|
||||
| 变量名 | 类型 | 初始值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| tasks | array | [] | 任务列表(按优先级分组) |
|
||||
| userInfo | object | null | 用户信息(花名、身份、门店) |
|
||||
| performanceData | object | null | 业绩概览(当月业绩、档位、工资预估、跳档激励) |
|
||||
| contextMenuVisible | boolean | false | 长按菜单显示状态 |
|
||||
| contextMenuPosition | object | {x,y} | 菜单弹出坐标 |
|
||||
| contextMenuTarget | element | null | 长按的目标卡片 |
|
||||
| remarkModalVisible | boolean | false | 备注/放弃弹窗显示状态 |
|
||||
| loading | boolean | true | 数据加载中 |
|
||||
| error | boolean | false | 加载失败 |
|
||||
|
||||
## 用户操作 → 响应
|
||||
| 操作 | 触发条件 | 响应行为 | 目标状态 |
|
||||
|------|----------|----------|----------|
|
||||
| 页面加载 | 进入页面 | GET /api/xcx/tasks + 业绩数据 | loading→false |
|
||||
| 点击 Banner 业绩区域 | 无 | navigateTo performance 页面 | — |
|
||||
| 点击任务卡片 | 无 | 根据 task-type 跳转对应详情页(见跳转映射表) | — |
|
||||
| 长按任务卡片(500ms) | 触摸/鼠标按住 | 在按压坐标处弹出黑底浮层+白色菜单 | contextMenuVisible=true |
|
||||
| 菜单-「📌 置顶任务」 | 菜单显示 | POST /api/xcx/tasks/{id}/pin | 列表刷新,菜单关闭 |
|
||||
| 菜单-「❌ 放弃任务」 | 菜单显示 | 打开备注/放弃弹窗 | remarkModalVisible=true |
|
||||
| 菜单-「🤖 问问AI助手」 | 菜单显示 | navigateTo chat(带任务上下文引用) | 菜单关闭 |
|
||||
| 菜单-「📝 备注」 | 菜单显示 | 打开备注弹窗 | remarkModalVisible=true |
|
||||
| 弹窗-提交 | 文本非空 | POST 对应接口 | Toast 提示,弹窗关闭 |
|
||||
| 点击遮罩层 | contextMenuVisible=true | 关闭菜单 | contextMenuVisible=false |
|
||||
| 下拉刷新 | 无 | 重新请求任务列表 | loading=true |
|
||||
| 点击"重试" | error=true | 重新请求数据 | loading=true |
|
||||
|
||||
## 任务卡片跳转映射
|
||||
| data-task-type | 跳转目标 |
|
||||
|----------------|----------|
|
||||
| high-priority | task-detail.html(高优先召回) |
|
||||
| priority | task-detail-priority.html(优先召回) |
|
||||
| relationship | task-detail-relationship.html(关系构建) |
|
||||
| callback | task-detail-callback.html(客户回访) |
|
||||
|
||||
## 任务优先级定义(PRD 补充)
|
||||
| 优先级 | 类型 | 触发条件 | 标签颜色 |
|
||||
|--------|------|----------|----------|
|
||||
| P0 高优先召回 | high-priority | WBI + NCI > 7 | 红色 |
|
||||
| P0 优先召回 | priority | WBI + NCI > 5 | 橙色 |
|
||||
| P1 客户回访 | callback | 已完成召回但未备注(或备注评分 < 5) | 蓝色 |
|
||||
| P2 关系构建 | relationship | RS < 6 | 粉色 |
|
||||
|
||||
> 列表内按优先级分组 → 组内按指数分数降序排列
|
||||
|
||||
## 任务完成条件(PRD 补充)
|
||||
| 任务类型 | 完成条件 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 召回(P0) | 客户出现新的服务订单 | 系统自动判定 |
|
||||
| 回访(P1) | 备注评分 ≥ 5(应用 6 评分) | 评分 < 5 不算完成;只计第一个备注;2 天有效期 |
|
||||
| 关系构建(P2) | RS 指数提升至 ≥ 6 | 系统自动判定 |
|
||||
|
||||
## 任务卡片结构(忠于原型 HTML)
|
||||
- 外层 `.task-card`:左侧 4px 彩色边框(颜色随任务类型变化)
|
||||
- 置顶卡片额外 `.pinned` class(微亮边框阴影)
|
||||
- 内部结构:
|
||||
- 第一行:任务类型标签(渐变背景圆角矩形)+ 客户昵称 + 关系 emoji + 备注指示器(📝,有备注时显示)
|
||||
- 第二行:「最近到店:X天前 · 余额:XXX」
|
||||
- 第三行:AI 机器人小图标 + AI 一句话智能建议文字(来源:AI 应用 4 的 `summary` 字段,`cache_type=app4_analysis`)
|
||||
- 右侧:向右箭头 chevron
|
||||
|
||||
## 列表分区结构
|
||||
1. 📌 置顶区域(amber 背景标签):用户手动置顶的任务
|
||||
2. 一般任务区域(灰色背景标签):按优先级分组 → 组内按分数降序
|
||||
3. ❌ 已放弃区域(灰色背景标签):
|
||||
- 卡片 `.abandoned`:opacity 0.55,左边框变灰,标签背景变灰,客户名变灰
|
||||
- 无右侧箭头
|
||||
- 显示放弃原因文字
|
||||
|
||||
## 长按菜单样式
|
||||
- 遮罩层 `.context-overlay`(半透明黑色)
|
||||
- 白色菜单 `.context-menu`:min-width 192px,圆角 14px,阴影
|
||||
- 4 个菜单项,项间 1px 分隔线:
|
||||
- 📌 置顶任务(已置顶时显示「取消置顶」)
|
||||
- ❌ 放弃任务
|
||||
- 🤖 问问AI助手
|
||||
- 📝 备注
|
||||
|
||||
## 业绩 Banner 展示
|
||||
- 用户花名 + 身份
|
||||
- 当月业绩进度条
|
||||
- 预计收入(标记"预估")
|
||||
- 跳档激励:「到达 XXX 即得 YYY」
|
||||
- YYY = max(跳档线差值最小值, 实际差值)
|
||||
- 各档差值:Tier0→1: 1200元 / Tier1→2: 750元 / Tier2→3: 540元 / Tier3→4: 420元
|
||||
|
||||
## 跟/弃 icon 规则(PRD 补充)
|
||||
- 跟:助教主动跟进中(绿色标记)
|
||||
- 弃:助教已放弃该客户(灰色标记)
|
||||
- 无标记:未分配助教或无跟进状态
|
||||
|
||||
## 爱心 icon 规则
|
||||
💖(>8.5) / 🧡(>7) / 💛(>5) / 💙(<5)
|
||||
|
||||
## 喜好标签
|
||||
🎱(中式) / 斯(斯诺克) / 🀅(麻将) / 🎤(团建)
|
||||
|
||||
## 页面状态枚举
|
||||
| 状态名 | 视觉表现 | 触发条件 |
|
||||
|--------|----------|----------|
|
||||
| 加载中 | 区域文案"加载中..." | loading=true |
|
||||
| 正常态 | 任务列表 + 业绩 Banner | 有数据 |
|
||||
| 空数据态 | "暂无任务" | tasks 为空 |
|
||||
| 错误态 | "加载失败,请点击重试" + 重试按钮 | error=true |
|
||||
|
||||
## 后端 API 依赖
|
||||
| API | 方法 | 说明 |
|
||||
|-----|------|------|
|
||||
| `GET /api/xcx/tasks` | GET | 获取任务列表 |
|
||||
| `POST /api/xcx/tasks/{id}/pin` | POST | 置顶/取消置顶 |
|
||||
| `POST /api/xcx/tasks/{id}/abandon` | POST | 放弃任务 |
|
||||
| `POST /api/xcx/notes` | POST | 创建备注 |
|
||||
| `GET /api/performance/summary` | GET | 业绩概览 |
|
||||
|
||||
## 页面导航
|
||||
- 来源:login(approved)/ TabBar 切换
|
||||
- 去向:task-detail* / performance / chat
|
||||
|
||||
## 全局组件
|
||||
- 底部 TabBar(任务 active)— 由 `bottom-nav.js` 自动注入
|
||||
- AI 悬浮按钮(右下角,渐变动画背景,可爱机器人 SVG 图标,点击 → chat)
|
||||
@@ -1,80 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AI 标识配色演示</title>
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Noto Sans SC', -apple-system, sans-serif; background: #f5f5f5; padding: 20px; }
|
||||
h1 { font-size: 18px; color: #242424; margin-bottom: 20px; text-align: center; }
|
||||
h2 { font-size: 15px; color: #5e5e5e; margin: 24px 0 12px; padding-left: 8px; border-left: 3px solid #667eea; }
|
||||
.demo-row { display: flex; align-items: center; gap: 16px; padding: 14px 16px; background: #fff; border-radius: 12px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
|
||||
.demo-row .label { font-size: 13px; color: #8b8b8b; min-width: 36px; }
|
||||
.demo-row .sample-text { font-size: 14px; color: #5e5e5e; display: flex; align-items: center; }
|
||||
.note { font-size: 12px; color: #a6a6a6; text-align: center; margin-top: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AI 标识配色方案演示</h1>
|
||||
|
||||
<!-- ===== 嵌入 Icon ===== -->
|
||||
<h2>嵌入 Icon(行首小图标 · 机器人)</h2>
|
||||
|
||||
<div class="demo-row">
|
||||
<span class="label">红</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-red"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">橙</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-orange"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">黄</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-yellow"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">蓝</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-blue"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">靛</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-indigo"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">紫</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-purple"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<p class="note">每个页面所有嵌入 Icon 统一使用一种配色,刷新后随机分配</p>
|
||||
|
||||
<!-- ===== Title AI 标识 ===== -->
|
||||
<h2>Title AI 标识(标题行右侧 · 机器人 · 浅色背景+边框)</h2>
|
||||
|
||||
<div class="demo-row">
|
||||
<span class="label">红</span>
|
||||
<span class="ai-title-badge ai-color-red"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">橙</span>
|
||||
<span class="ai-title-badge ai-color-orange"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">黄</span>
|
||||
<span class="ai-title-badge ai-color-yellow"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">蓝</span>
|
||||
<span class="ai-title-badge ai-color-blue"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">靛</span>
|
||||
<span class="ai-title-badge ai-color-indigo"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">紫</span>
|
||||
<span class="ai-title-badge ai-color-purple"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<p class="note">每个页面所有 Title AI 标识统一使用一种配色,刷新后随机分配</p>
|
||||
</body>
|
||||
</html>
|
||||
402
docs/h5_ui/pages/board-finance-style-map.md
Normal file
@@ -0,0 +1,402 @@
|
||||
# board-finance.html 完整样式清单
|
||||
|
||||
换算公式:rpx = CSS_px × 1.8204(四舍五入到整数)
|
||||
|
||||
---
|
||||
|
||||
## 一、Inline Style 定义
|
||||
|
||||
### 1. Tailwind Config 自定义颜色
|
||||
|
||||
| Token | 值 |
|
||||
|-------|-----|
|
||||
| primary | #0052d9 |
|
||||
| primary-light | #ecf2fe |
|
||||
| success | #00a870 |
|
||||
| warning | #ed7b2f |
|
||||
| error | #e34d59 |
|
||||
| gray-1 | #f3f3f3 |
|
||||
| gray-2 | #eeeeee |
|
||||
| gray-3 | #e7e7e7 |
|
||||
| gray-4 | #dcdcdc |
|
||||
| gray-5 | #c5c5c5 |
|
||||
| gray-6 | #a6a6a6 |
|
||||
| gray-7 | #8b8b8b |
|
||||
| gray-8 | #777777 |
|
||||
| gray-9 | #5e5e5e |
|
||||
| gray-10 | #4b4b4b |
|
||||
| gray-11 | #393939 |
|
||||
| gray-12 | #2c2c2c |
|
||||
| gray-13 | #242424 |
|
||||
| fontFamily.sans | 'Noto Sans SC', sans-serif |
|
||||
|
||||
### 2. `<style>` 中所有选择器及属性
|
||||
|
||||
| 选择器 | 属性 | H5 值(px) | 正确 rpx (×1.8204) |
|
||||
|--------|------|-----------|---------------------|
|
||||
| `body` | padding-bottom | 280px | 510rpx |
|
||||
| `.safe-area-top` | padding-top | env(safe-area-inset-top, 44px) | 80rpx (fallback) |
|
||||
| `.tab-active::after` | width | 24px | 44rpx |
|
||||
| `.tab-active::after` | height | 3px | 5rpx |
|
||||
| `.tab-active::after` | border-radius | 2px | 4rpx |
|
||||
| `.filter-overlay` | z-index | 1000 | — |
|
||||
| `.filter-dropdown` | border-radius | 0 0 16px 16px | 0 0 29rpx 29rpx |
|
||||
| `.filter-dropdown` | z-index | 1001 | — |
|
||||
| `.filter-dropdown` | max-height | 60vh | — |
|
||||
| `.summary-header` | padding | 14px 16px | 25rpx 29rpx |
|
||||
| `.summary-content` | padding | 16px | 29rpx |
|
||||
| `.compare-toggle` | width | 44px | 80rpx |
|
||||
| `.compare-toggle` | height | 24px | 44rpx |
|
||||
| `.compare-toggle` | border-radius | 12px | 22rpx |
|
||||
| `.compare-toggle::after` | width | 20px | 36rpx |
|
||||
| `.compare-toggle::after` | height | 20px | 36rpx |
|
||||
| `.compare-toggle::after` | top | 2px | 4rpx |
|
||||
| `.compare-toggle::after` | left | 2px | 4rpx |
|
||||
| `.compare-toggle.active::after` | left | 22px | 40rpx |
|
||||
| `.compare-data` | font-size | 12px | 22rpx |
|
||||
| `.compare-data` | margin-top | 2px | 4rpx |
|
||||
| `.compare-data.show` | gap | 2px | 4rpx |
|
||||
| `.tip-overlay` | z-index | 1999 | — |
|
||||
| `.tip-toast` | bottom | 100px | 182rpx |
|
||||
| `.tip-toast` | left | 16px | 29rpx |
|
||||
| `.tip-toast` | right | 16px | 29rpx |
|
||||
| `.tip-toast` | border-radius | 12px | 22rpx |
|
||||
| `.tip-toast` | padding | 16px | 29rpx |
|
||||
| `.tip-toast` | z-index | 2000 | — |
|
||||
| `.tip-toast-content` | font-size | 13px | 24rpx |
|
||||
| `.tip-toast-content` | line-height | 1.6 | — |
|
||||
| `.help-icon` | width | 16px | 29rpx |
|
||||
| `.help-icon` | height | 16px | 29rpx |
|
||||
| `.help-icon` | font-size | 10px | 18rpx |
|
||||
| `.help-icon` | margin-left | 4px | 7rpx |
|
||||
| `.card-section-title` | font-size | 13px | 24rpx |
|
||||
| `.card-section-title` | margin-bottom | 12px | 22rpx |
|
||||
| `.flow-item` | padding | 10px 0 | 18rpx 0 |
|
||||
| `.flow-dot` | width | 8px | 15rpx |
|
||||
| `.flow-dot` | height | 8px | 15rpx |
|
||||
| `.flow-dot` | margin-right | 12px | 22rpx |
|
||||
| `.flow-line` | width | 2px | 4rpx |
|
||||
| `.flow-line` | height | 16px | 29rpx |
|
||||
| `.flow-line` | margin-left | 3px | 5rpx |
|
||||
| `.flow-line` | margin-top | -10px | -18rpx |
|
||||
| `.flow-line` | margin-bottom | -10px | -18rpx |
|
||||
| `.gift-row` | padding | 14px 16px | 25rpx 29rpx |
|
||||
| `.gift-row` | border-radius | 12px | 22rpx |
|
||||
| `.gift-row` | margin-bottom | 10px | 18rpx |
|
||||
| `.gift-tag` | padding | 3px 8px | 5rpx 15rpx |
|
||||
| `.gift-tag` | border-radius | 4px | 7rpx |
|
||||
| `.gift-tag` | font-size | 11px | 20rpx |
|
||||
| `.gift-tag` | margin-left | 6px | 11rpx |
|
||||
| `.filter-toc-btn` | width | 40px | 73rpx |
|
||||
| `.filter-toc-btn` | height | 40px | 73rpx |
|
||||
| `.filter-toc-btn` | border-radius | 8px | 15rpx |
|
||||
| `.filter-toc-btn svg` | width | 20px | 36rpx |
|
||||
| `.filter-toc-btn svg` | height | 20px | 36rpx |
|
||||
| `.toc-dropdown` | top | 108px | 197rpx |
|
||||
| `.toc-dropdown` | left | 16px | 29rpx |
|
||||
| `.toc-dropdown` | right | 16px | 29rpx |
|
||||
| `.toc-dropdown` | border-radius | 16px | 29rpx |
|
||||
| `.toc-dropdown` | max-height | 60vh | — |
|
||||
| `.toc-dropdown` | z-index | 1001 | — |
|
||||
| `.toc-dropdown-header` | padding | 14px 16px | 25rpx 29rpx |
|
||||
| `.toc-dropdown-header h4` | font-size | 14px | 25rpx |
|
||||
| `.toc-dropdown-list` | padding | 8px 0 | 15rpx 0 |
|
||||
| `.toc-item` | gap | 12px | 22rpx |
|
||||
| `.toc-item` | padding | 12px 16px | 22rpx 29rpx |
|
||||
| `.toc-item-emoji` | font-size | 18px | 33rpx |
|
||||
| `.toc-item-text` | font-size | 14px | 25rpx |
|
||||
| `.toc-overlay` | z-index | 1000 | — |
|
||||
| `.card-header` | gap | 10px | 18rpx |
|
||||
| `.card-header` | margin | -16px -16px 16px -16px | -29rpx -29rpx 29rpx -29rpx |
|
||||
| `.card-header` | padding | 12px 16px | 22rpx 29rpx |
|
||||
| `.card-header-emoji` | font-size | 18px | 33rpx |
|
||||
| `.card-header-title` | font-size | 14px | 25rpx |
|
||||
| `.card-header-title` | margin-bottom | 2px | 4rpx |
|
||||
| `.card-header-desc` | font-size | 11px | 20rpx |
|
||||
| `.card-section` | margin-bottom | 42px | 76rpx |
|
||||
| `.card-section` | padding-bottom | 28px | 51rpx |
|
||||
| `.card-section` | border-radius | 8px | 15rpx |
|
||||
| `.card-section::after` | height | 14px | 25rpx |
|
||||
| `.card-section::after` | background-size | 16px 14px | 29rpx 25rpx |
|
||||
| `.sticky-section-header` | top | 58px | 106rpx |
|
||||
| `.sticky-section-header` | left | 70px | 127rpx |
|
||||
| `.sticky-section-header` | right | 22px | 40rpx |
|
||||
| `.sticky-section-header` | height | 40px | 73rpx |
|
||||
| `.sticky-section-header` | z-index | 15 | — |
|
||||
| `.sticky-section-header` | padding | 0 12px | 0 22rpx |
|
||||
| `.sticky-section-header` | gap | 8px | 15rpx |
|
||||
| `.sticky-section-header` | border-radius | 0 6px 6px 0 | 0 11rpx 11rpx 0 |
|
||||
| `.sticky-section-emoji` | font-size | 18px | 33rpx |
|
||||
| `.sticky-section-content` | gap | 8px | 15rpx |
|
||||
| `.sticky-section-title` | font-size | 14px | 25rpx |
|
||||
| `.sticky-section-desc` | font-size | 11px | 20rpx |
|
||||
| `.sticky-section-filters` | gap | 8px | 15rpx |
|
||||
| `.sticky-filter-tag` | font-size | 11px | 20rpx |
|
||||
| `.sticky-filter-tag` | padding | 4px 8px | 7rpx 15rpx |
|
||||
| `.sticky-filter-tag` | border-radius | 6px | 11rpx |
|
||||
| `.ai-insight-section` | margin | 16px -16px -16px -16px | 29rpx -29rpx -29rpx -29rpx |
|
||||
| `.ai-insight-section` | padding | 16px | 29rpx |
|
||||
| `.ai-insight-icon` | width | 24px | 44rpx |
|
||||
| `.ai-insight-icon` | height | 24px | 44rpx |
|
||||
| `.ai-insight-icon` | border-radius | 8px | 15rpx |
|
||||
| `.ai-insight-icon` | font-size | 14px | 25rpx |
|
||||
| `.ai-insight-header` | gap | 8px | 15rpx |
|
||||
| `.ai-insight-header` | margin-bottom | 12px | 22rpx |
|
||||
| `.ai-insight-title` | font-size | 13px | 24rpx |
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 二、Body 区域 Tailwind Class 映射
|
||||
|
||||
### 1. 顶部 Tab 导航(.safe-area-top 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 导航容器 | `bg-white sticky top-0 z-20 shadow-sm` | — | — |
|
||||
| Tab 行 | `flex border-b border-gray-2` | — | — |
|
||||
| 单个 Tab | `flex-1 py-3 text-center text-sm font-medium` | py: 12px, font: 14px/20px | py: 22rpx, font: 26rpx/36rpx |
|
||||
| 激活 Tab | 同上 + `.tab-active`(CSS 定义) | — | — |
|
||||
| 非激活 Tab | 同上 + `text-gray-7` | color: #8b8b8b | — |
|
||||
|
||||
### 2. 筛选栏(#filterBar 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 筛选栏容器 | `bg-gray-1 sticky top-[44px] z-10 px-4 py-2 border-b border-gray-2` | px: 16px, py: 8px, top: 44px | px: 29rpx, py: 14rpx, top: 80rpx |
|
||||
| 内部白色容器 | `bg-white rounded-lg p-1.5 flex gap-2 border border-gray-200` | p: 6px, gap: 8px, radius: 8px | p: 11rpx, gap: 14rpx, radius: 14rpx |
|
||||
| 目录按钮 | `.filter-toc-btn`(CSS 定义) | 40×40px, radius: 8px | 73×73rpx, radius: 15rpx |
|
||||
| 时间筛选按钮 | `flex-1 px-3 py-2 bg-gray-100 rounded text-sm text-gray-700 flex items-center justify-center gap-1 border border-gray-200` | px: 12px, py: 8px, font: 14px, gap: 4px, radius: 4px | px: 22rpx, py: 14rpx, font: 26rpx, gap: 7rpx, radius: 7rpx |
|
||||
| 区域筛选按钮 | `flex-1 px-3 py-2 bg-gray-50 rounded text-sm text-gray-700 flex items-center justify-center gap-1 border border-gray-200` | 同上 | 同上 |
|
||||
| 下拉箭头 SVG | `w-4 h-4 text-gray-500` / `text-gray-5` | 16×16px | 29×29rpx |
|
||||
| 环比开关容器 | `flex items-center gap-2 px-2` | gap: 8px, px: 8px | gap: 14rpx, px: 14rpx |
|
||||
| 环比文字 | `text-xs text-gray-7` | font: 12px/16px | font: 22rpx/29rpx |
|
||||
| 环比开关 | `.compare-toggle`(CSS 定义) | 44×24px | 80×44rpx |
|
||||
|
||||
### 3. 经营一览(#section-overview 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 板块容器 | `summary-gradient mx-4 mt-4 mb-8 rounded-lg text-white overflow-hidden` | mx: 16px, mt: 16px, mb: 32px, radius: 8px | mx: 29rpx, mt: 29rpx, mb: 58rpx, radius: 14rpx |
|
||||
| 板块头 | `.summary-header flex items-start gap-3` | gap: 12px; padding: 14px 16px (CSS) | gap: 22rpx; padding: 25rpx 29rpx |
|
||||
| 板块头 emoji | `text-xl` | 20px/28px | 36rpx/51rpx |
|
||||
| 板块头标题 | `text-base font-semibold text-white` | 16px/24px | 29rpx/44rpx |
|
||||
| 板块头副标题 | `text-xs text-white/50 mt-0.5` | 12px/16px, mt: 2px | 22rpx/29rpx, mt: 4rpx |
|
||||
| 板块正文 | `.summary-content` | padding: 16px (CSS) | padding: 29rpx |
|
||||
| 小节标签 | `text-xs text-white/70 font-medium` | 12px/16px | 22rpx/29rpx |
|
||||
| 小节副标签 | `text-xs text-white/40` | 12px/16px | 22rpx/29rpx |
|
||||
| 收入概览 grid | `grid grid-cols-3 gap-3 mb-3` | gap: 12px, mb: 12px | gap: 22rpx, mb: 22rpx |
|
||||
| 指标标签 | `text-white/60 text-xs` | 12px/16px | 22rpx/29rpx |
|
||||
| 指标标签行 | `flex items-center justify-center mb-1` | mb: 4px | mb: 7rpx |
|
||||
| 大数字 | `text-xl font-bold text-white` | 20px/28px | 36rpx/51rpx |
|
||||
| 红色大数字 | `text-xl font-bold text-red-500/85` | 20px/28px | 36rpx/51rpx |
|
||||
| 灰色大数字 | `text-xl font-bold text-gray-300` | 20px/28px | 36rpx/51rpx |
|
||||
| 成交收入行 | `bg-white/10 rounded-xl px-4 py-3 flex justify-between items-center` | px: 16px, py: 12px, radius: 12px | px: 29rpx, py: 22rpx, radius: 22rpx |
|
||||
| 成交收入标签 | `text-white/70 text-sm` | 14px/20px | 26rpx/36rpx |
|
||||
| 成交收入数字 | `text-xl font-bold text-gray-100` | 20px/28px | 36rpx/51rpx |
|
||||
| 分隔线 | `border-t border-white/10 my-4` | my: 16px | my: 29rpx |
|
||||
| 现金流水 grid | `grid grid-cols-2 gap-3` | gap: 12px | gap: 22rpx |
|
||||
| 现金流水卡片 | `bg-white/5 rounded-xl p-3 text-center` | p: 12px, radius: 12px | p: 22rpx, radius: 22rpx |
|
||||
| 现金流水数字 | `text-lg font-bold text-gray-100` | 18px/28px | 33rpx/51rpx |
|
||||
| 对比数据 SVG | `w-3 h-3` | 12×12px | 22×22rpx |
|
||||
|
||||
### 4. 预收资产(#section-recharge 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 板块容器 | `bg-white rounded-lg p-4 border border-gray-200 card-section` | p: 16px, radius: 8px (CSS card-section) | p: 29rpx, radius: 15rpx |
|
||||
| 板块头 | `.card-header`(CSS 定义) | gap: 10px, p: 12px 16px | gap: 18rpx, p: 22rpx 29rpx |
|
||||
| 板块头 emoji | `.card-header-emoji` | font: 18px | font: 33rpx |
|
||||
| 板块头标题 | `.card-header-title` | font: 14px, mb: 2px | font: 25rpx, mb: 4rpx |
|
||||
| 板块头描述 | `.card-header-desc` | font: 11px | font: 20rpx |
|
||||
| 小节标题 | `.card-section-title` | font: 13px, mb: 12px | font: 24rpx, mb: 22rpx |
|
||||
| 表格容器 | `border border-gray-200 rounded-lg overflow-hidden` | radius: 8px | radius: 14rpx |
|
||||
| 储值卡充值行 | `bg-gray-50 px-4 py-3 flex justify-between items-center border-b border-gray-100` | px: 16px, py: 12px | px: 29rpx, py: 22rpx |
|
||||
| 储值卡标签 | `text-sm text-gray-700 font-medium` | 14px/20px | 26rpx/36rpx |
|
||||
| 储值卡大数字 | `text-lg font-bold text-gray-900` | 18px/28px | 33rpx/51rpx |
|
||||
| 三列 grid | `bg-white px-4 py-3 grid grid-cols-3 gap-3 border-b border-gray-100` | px: 16px, py: 12px, gap: 12px | px: 29rpx, py: 22rpx, gap: 22rpx |
|
||||
| 三列小标签 | `text-xs text-gray-500` | 12px/16px | 22rpx/29rpx |
|
||||
| 三列小标签行 | `flex items-center justify-center gap-0.5 mb-1` | gap: 2px, mb: 4px | gap: 4rpx, mb: 7rpx |
|
||||
| 三列数值 | `text-sm font-medium text-gray-700` | 14px/20px | 26rpx/36rpx |
|
||||
| 小帮助图标 | `.help-icon .help-icon-dark text-[9px]` | 9px (font) | 16rpx |
|
||||
| 储值卡余额行 | `bg-gray-100 px-4 py-3 flex justify-between items-center` | px: 16px, py: 12px | px: 29rpx, py: 22rpx |
|
||||
| 赠送卡表头 | `grid grid-cols-4 gap-1 px-4 py-2 bg-gray-100 text-sm text-gray-800 font-medium` | gap: 4px, px: 16px, py: 8px, font: 14px | gap: 7rpx, px: 29rpx, py: 14rpx, font: 26rpx |
|
||||
| 赠送卡数据行 | `grid grid-cols-4 gap-1 px-4 py-3 border-b border-gray-100 items-center` | gap: 4px, px: 16px, py: 12px | gap: 7rpx, px: 29rpx, py: 22rpx |
|
||||
| 赠送卡行标题 | `text-sm text-gray-700 font-medium` | 14px/20px | 26rpx/36rpx |
|
||||
| 赠送卡行金额 | `text-[13px] text-gray-800 font-semibold` | 13px | 24rpx |
|
||||
| 赠送卡子列数值 | `text-sm text-gray-500` | 14px/20px | 26rpx/36rpx |
|
||||
| 赠送卡余额行 | `grid grid-cols-4 gap-1 px-4 py-3 bg-gray-50 items-center` | 同上 | 同上 |
|
||||
| 赠送卡余额金额 | `text-[13px] font-bold text-gray-900` | 13px | 24rpx |
|
||||
| 全类别合计容器 | `bg-gray-100 rounded-lg px-4 py-3 flex justify-between items-center border border-gray-200` | px: 16px, py: 12px, radius: 8px | px: 29rpx, py: 22rpx, radius: 14rpx |
|
||||
| 全类别合计标签 | `text-sm text-gray-700 font-medium` | 14px/20px | 26rpx/36rpx |
|
||||
| 全类别合计副标签 | `text-[10px] text-gray-400` | 10px | 18rpx |
|
||||
| 全类别合计数字 | `text-xl font-bold text-gray-900` | 20px/28px | 36rpx/51rpx |
|
||||
| 对比数据(11px) | `compare-data compare-up text-[11px]` | 11px | 20rpx |
|
||||
| 对比数据(10px) | `compare-data compare-up text-[10px]` | 10px | 18rpx |
|
||||
| 对比 SVG 小 | `w-2.5 h-2.5` | 10×10px | 18×18rpx |
|
||||
| 对比 SVG 极小 | `w-2 h-2` | 8×8px | 15×15rpx |
|
||||
|
||||
### 5. 应计收入(#section-revenue 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 板块容器 | `bg-white rounded-lg p-4 border border-gray-200 card-section` | p: 16px, radius: 8px | p: 29rpx, radius: 15rpx |
|
||||
| 板块头 | `.card-header`(同上) | — | — |
|
||||
| 收入结构标题行 | `flex items-center gap-2 mb-3` | gap: 8px, mb: 12px | gap: 14rpx, mb: 22rpx |
|
||||
| 收入结构标题 | `text-sm font-semibold text-gray-700` | 14px/20px | 26rpx/36rpx |
|
||||
| 收入结构副标题 | `text-xs text-gray-400` | 12px/16px | 22rpx/29rpx |
|
||||
| 收入结构容器 | `mb-5` | mb: 20px | mb: 36rpx |
|
||||
| 表格容器 | `border border-gray-200 rounded-lg overflow-hidden` | radius: 8px | radius: 14rpx |
|
||||
| 表头 | `grid grid-cols-4 gap-1 px-4 py-2 bg-gray-100 text-xs text-gray-600` | gap: 4px, px: 16px, py: 8px, font: 12px | gap: 7rpx, px: 29rpx, py: 14rpx, font: 22rpx |
|
||||
| 表体行(主项) | `grid grid-cols-4 gap-1 px-4 py-3` | gap: 4px, px: 16px, py: 12px | gap: 7rpx, px: 29rpx, py: 22rpx |
|
||||
| 表体行(子项) | `grid grid-cols-4 gap-1 px-4 py-2 text-sm bg-white/50` | gap: 4px, px: 16px, py: 8px, font: 14px | gap: 7rpx, px: 29rpx, py: 14rpx, font: 26rpx |
|
||||
| 主项名称 | `text-sm text-gray-11 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 主项数值 | `text-base text-gray-10` | 16px/24px | 29rpx/44rpx |
|
||||
| 主项入账数值 | `text-base text-gray-11 font-semibold` | 16px/24px | 29rpx/44rpx |
|
||||
| 子项名称 | `text-gray-7 pl-4` | pl: 16px | pl: 29rpx |
|
||||
| 子项数值 | `text-right text-gray-7` | — | — |
|
||||
| 红色优惠数值 | `text-right text-base text-red-500/85` | 16px/24px | 29rpx/44rpx |
|
||||
| 子项红色数值 | `text-right text-red-500/85` | — | — |
|
||||
| 助教子标签 | `text-xs text-gray-6` | 12px/16px | 22rpx/29rpx |
|
||||
| 对比数据(12px) | `compare-data compare-up text-[12px] justify-end` | 12px | 22rpx |
|
||||
| 收入确认标题行 | `flex items-center gap-2 mb-3` | gap: 8px, mb: 12px | gap: 14rpx, mb: 22rpx |
|
||||
| 收入确认标题 | `text-sm font-semibold text-gray-700` | 14px/20px | 26rpx/36rpx |
|
||||
| 收入确认副标题 | `text-xs text-gray-400` | 12px/16px | 22rpx/29rpx |
|
||||
| 项目正价标题栏 | `bg-gray-50 px-4 py-2.5` | px: 16px, py: 10px | px: 29rpx, py: 18rpx |
|
||||
| 项目正价标题 | `text-sm text-gray-700 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 项目正价副标题 | `text-xs text-gray-500` | 12px/16px | 22rpx/29rpx |
|
||||
| 竖线缩进区 | `bg-white px-4 py-3 border-l-2 border-gray-300 ml-4 mr-4 my-2` | px: 16px, py: 12px, ml/mr: 16px, my: 8px, border-l: 2px | px: 29rpx, py: 22rpx, ml/mr: 29rpx, my: 14rpx, border-l: 4rpx |
|
||||
| 缩进区间距 | `space-y-2` | gap: 8px | gap: 14rpx |
|
||||
| 缩进区项目名 | `text-sm text-gray-600` | 14px/20px | 26rpx/36rpx |
|
||||
| 缩进区数值 | `text-sm font-medium text-gray-700` | 14px/20px | 26rpx/36rpx |
|
||||
| 缩进区红色数值 | `text-sm font-medium text-red-500/85` | 14px/20px | 26rpx/36rpx |
|
||||
| 发生额汇总栏 | `bg-gray-100 px-4 py-3` | px: 16px, py: 12px | px: 29rpx, py: 22rpx |
|
||||
| 发生额汇总标题 | `text-sm text-gray-700 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 发生额汇总数字 | `text-lg font-semibold text-gray-900` | 18px/28px | 33rpx/51rpx |
|
||||
| 成交收入汇总数字 | `text-lg font-bold text-gray-900` | 18px/28px | 33rpx/51rpx |
|
||||
| 成交收入说明 | `text-xs text-gray-500 leading-relaxed` | 12px/16px | 22rpx/29rpx |
|
||||
| 优惠子项副标签 | `text-xs text-gray-400 mt-0.5` | 12px/16px, mt: 2px | 22rpx/29rpx, mt: 4rpx |
|
||||
| 灰色占位 | `text-sm font-medium text-gray-400` | 14px/20px | 26rpx/36rpx |
|
||||
| 收款渠道标签 | `text-xs text-gray-500 mb-2` | 12px/16px, mb: 8px | 22rpx/29rpx, mb: 14rpx |
|
||||
| 竖线缩进区(底部) | `bg-white px-4 py-3 border-l-2 border-gray-300 ml-4 mr-4 mb-3` | mb: 12px | mb: 22rpx |
|
||||
| 对比数据(11px) | `compare-data compare-up text-[11px]` | 11px | 20rpx |
|
||||
|
||||
### 6. 现金流入(#section-cashflow 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 板块容器 | `bg-white rounded-lg p-4 border border-gray-200 card-section` | p: 16px, radius: 8px | p: 29rpx, radius: 15rpx |
|
||||
| 板块头 | `.card-header`(同上) | — | — |
|
||||
| 分类标签 | `text-xs text-gray-500 font-medium px-1` | 12px/16px, px: 4px | 22rpx/29rpx, px: 7rpx |
|
||||
| 分类标签(mt) | `text-xs text-gray-500 font-medium px-1 mt-3` | mt: 12px | mt: 22rpx |
|
||||
| 流水项容器 | `flex justify-between items-center border-b border-gray-100 px-2 py-2` | px: 8px, py: 8px | px: 14rpx, py: 14rpx |
|
||||
| 流水项名称 | `text-sm text-gray-700 font-medium` | 14px/20px | 26rpx/36rpx |
|
||||
| 流水项副标签 | `text-xs text-gray-400 mt-0.5` | 12px/16px, mt: 2px | 22rpx/29rpx, mt: 4rpx |
|
||||
| 流水项数值 | `text-base font-semibold text-gray-900` | 16px/24px | 29rpx/44rpx |
|
||||
| 合计容器 | `flex justify-between items-center bg-gray-100 rounded-lg px-4 py-3 mt-2 border-t border-gray-200` | px: 16px, py: 12px, mt: 8px, radius: 8px | px: 29rpx, py: 22rpx, mt: 14rpx, radius: 14rpx |
|
||||
| 合计标签 | `text-sm text-gray-700 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 合计数字 | `text-lg font-bold text-gray-900` | 18px/28px | 33rpx/51rpx |
|
||||
|
||||
### 7. 现金流出(#section-expense 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 板块容器 | `bg-white rounded-lg p-4 border border-gray-200 card-section` | p: 16px, radius: 8px | p: 29rpx, radius: 15rpx |
|
||||
| 板块头 | `.card-header`(同上) | — | — |
|
||||
| 分类标题 | `text-sm font-medium text-gray-700 mb-2` | 14px/20px, mb: 8px | 26rpx/36rpx, mb: 14rpx |
|
||||
| 分类标题(mb-1) | `text-sm font-medium text-gray-700 mb-1` | mb: 4px | mb: 7rpx |
|
||||
| 分类副标题 | `text-xs text-gray-400 mb-2` | 12px/16px, mb: 8px | 22rpx/29rpx, mb: 14rpx |
|
||||
| 进货 3列 grid | `grid grid-cols-3 gap-2 mb-4` | gap: 8px, mb: 16px | gap: 14rpx, mb: 29rpx |
|
||||
| 固定支出 2列 grid | `grid grid-cols-2 gap-2 mb-4` | gap: 8px, mb: 16px | gap: 14rpx, mb: 29rpx |
|
||||
| 支出卡片 | `bg-gray-50 border border-gray-200 rounded-lg px-3 py-3 text-center` | px: 12px, py: 12px, radius: 8px | px: 22rpx, py: 22rpx, radius: 14rpx |
|
||||
| 支出卡片标签 | `text-xs text-gray-500 mb-1` | 12px/16px, mb: 4px | 22rpx/29rpx, mb: 7rpx |
|
||||
| 支出卡片数值 | `text-base font-semibold text-gray-900` | 16px/24px | 29rpx/44rpx |
|
||||
| 支出合计容器 | `bg-gray-100 rounded-lg px-4 py-3 flex justify-between items-center border-t border-gray-200` | px: 16px, py: 12px, radius: 8px | px: 29rpx, py: 22rpx, radius: 14rpx |
|
||||
| 支出合计标签 | `text-sm font-semibold text-gray-700` | 14px/20px | 26rpx/36rpx |
|
||||
| 支出合计数字 | `text-lg font-bold text-gray-900` | 18px/28px | 33rpx/51rpx |
|
||||
|
||||
### 8. 助教分析(#section-coach 区域)
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 板块容器 | `bg-white rounded-lg p-4 border border-gray-200 card-section` | p: 16px, radius: 8px | p: 29rpx, radius: 15rpx |
|
||||
| 板块头 | `.card-header`(同上) | — | — |
|
||||
| 小节标题 | `.card-section-title` | font: 13px, mb: 12px | font: 24rpx, mb: 22rpx |
|
||||
| 小节标题内 span | `text-xs text-gray-500 font-normal` | 12px/16px | 22rpx/29rpx |
|
||||
| 表格容器 | `border border-gray-200 rounded-lg overflow-hidden` | radius: 8px | radius: 14rpx |
|
||||
| 表头 | `grid grid-cols-4 gap-1 px-4 py-2 bg-gray-100 text-xs text-gray-600` | gap: 4px, px: 16px, py: 8px, font: 12px | gap: 7rpx, px: 29rpx, py: 14rpx, font: 22rpx |
|
||||
| 合计行(基础课) | `grid grid-cols-4 gap-1 px-4 py-2 bg-gray-50 border-b border-gray-200` | gap: 4px, px: 16px, py: 8px | gap: 7rpx, px: 29rpx, py: 14rpx |
|
||||
| 合计行标签 | `text-sm text-gray-700 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 合计行数值 | `text-sm text-gray-900 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 合计行小时均 | `text-sm text-gray-700` | 14px/20px | 26rpx/36rpx |
|
||||
| 明细行 | `grid grid-cols-4 gap-1 px-4 py-2.5` | gap: 4px, px: 16px, py: 10px | gap: 7rpx, px: 29rpx, py: 18rpx |
|
||||
| 明细行级别 | `text-sm text-gray-9` | 14px/20px | 26rpx/36rpx |
|
||||
| 明细行数值 | `text-base text-gray-9` | 16px/24px | 29rpx/44rpx |
|
||||
| 明细行小时均 | `text-sm text-gray-7` | 14px/20px | 26rpx/36rpx |
|
||||
| 激励课合计行 | `grid grid-cols-4 gap-1 px-4 py-3` | gap: 4px, px: 16px, py: 12px | gap: 7rpx, px: 29rpx, py: 22rpx |
|
||||
| 激励课合计标签 | `text-sm text-gray-11 font-semibold` | 14px/20px | 26rpx/36rpx |
|
||||
| 激励课合计数值 | `text-base text-gray-11 font-semibold` | 16px/24px | 29rpx/44rpx |
|
||||
| 激励课分成数值 | `text-base text-gray-900 font-semibold` | 16px/24px | 29rpx/44rpx |
|
||||
| 激励课小时均 | `text-base text-gray-9` | 16px/24px | 29rpx/44rpx |
|
||||
| 对比持平文字 | `compare-data text-[12px] text-gray-5 justify-end` | 12px | 22rpx |
|
||||
|
||||
### 9. 目录面板(#tocDropdown 区域)
|
||||
|
||||
| 元素描述 | Tailwind class / CSS 选择器 | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------------------|------------|----------|
|
||||
| 遮罩 | `.toc-overlay` | z-index: 1000 | — |
|
||||
| 面板容器 | `.toc-dropdown` | top: 108px, left/right: 16px, radius: 16px, max-height: 60vh, z-index: 1001 | top: 197rpx, left/right: 29rpx, radius: 29rpx |
|
||||
| 面板头 | `.toc-dropdown-header` | padding: 14px 16px | padding: 25rpx 29rpx |
|
||||
| 面板头标题 | `.toc-dropdown-header h4` | font: 14px | font: 25rpx |
|
||||
| 列表容器 | `.toc-dropdown-list` | padding: 8px 0 | padding: 15rpx 0 |
|
||||
| 列表项 | `.toc-item` | gap: 12px, padding: 12px 16px | gap: 22rpx, padding: 22rpx 29rpx |
|
||||
| 列表项 emoji | `.toc-item-emoji` | font: 18px | font: 33rpx |
|
||||
| 列表项文字 | `.toc-item-text` | font: 14px | font: 25rpx |
|
||||
|
||||
### 10. 提示弹窗(.tip-toast 区域)
|
||||
|
||||
| 元素描述 | Tailwind class / CSS 选择器 | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------------------|------------|----------|
|
||||
| 遮罩 | `.tip-overlay` | z-index: 1999 | — |
|
||||
| 弹窗容器 | `.tip-toast` | bottom: 100px, left/right: 16px, radius: 12px, padding: 16px, z-index: 2000 | bottom: 182rpx, left/right: 29rpx, radius: 22rpx, padding: 29rpx |
|
||||
| 弹窗标题行 | `flex justify-between items-start mb-2` | mb: 8px | mb: 14rpx |
|
||||
| 弹窗标题 | `text-sm text-primary font-medium` | 14px/20px | 26rpx/36rpx |
|
||||
| 关闭按钮 SVG | `w-5 h-5` | 20×20px | 36×36rpx |
|
||||
| 弹窗内容 | `.tip-toast-content` | font: 13px, line-height: 1.6 | font: 24rpx |
|
||||
| 帮助图标(白底) | `.help-icon` | 16×16px, font: 10px, ml: 4px | 29×29rpx, font: 18rpx, ml: 7rpx |
|
||||
| 帮助图标(暗底) | `.help-icon .help-icon-dark` | 同上 | 同上 |
|
||||
|
||||
---
|
||||
|
||||
## 三、AI 洞察区域(.ai-insight-section)
|
||||
|
||||
| 元素描述 | Tailwind class / CSS 选择器 | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------------------|------------|----------|
|
||||
| 容器 | `.ai-insight-section` | margin: 16px -16px -16px -16px, padding: 16px | margin: 29rpx -29rpx -29rpx -29rpx, padding: 29rpx |
|
||||
| 头部 | `.ai-insight-header` | gap: 8px, mb: 12px | gap: 15rpx, mb: 22rpx |
|
||||
| 图标 | `.ai-insight-icon` | 24×24px, radius: 8px, font: 14px | 44×44rpx, radius: 15rpx, font: 25rpx |
|
||||
| 标题 | `.ai-insight-title` | font: 13px | font: 24rpx |
|
||||
| 内容行 | `space-y-2 text-sm text-white/85` | gap: 8px, font: 14px/20px | gap: 14rpx, font: 26rpx/36rpx |
|
||||
| 内容标签 | `text-white/50` | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 四、筛选弹窗区域
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| 弹窗遮罩 | `.filter-overlay` | z-index: 1000 | — |
|
||||
| 弹窗容器 | `.filter-dropdown` | radius: 0 0 16px 16px, z-index: 1001, max-height: 60vh | radius: 0 0 29rpx 29rpx |
|
||||
| 弹窗内容 | `p-4 space-y-2` | p: 16px, gap: 8px | p: 29rpx, gap: 14rpx |
|
||||
| 选项行 | `px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer flex items-center justify-between` | px: 16px, py: 12px, font: 14px, radius: 8px | px: 29rpx, py: 22rpx, font: 26rpx, radius: 14rpx |
|
||||
| 子区域选项 | 同上 + `text-gray-7 pl-8` | pl: 32px | pl: 58rpx |
|
||||
| 分组标题选项 | 同上 + `font-medium` | — | — |
|
||||
|
||||
---
|
||||
|
||||
## 五、页面级容器
|
||||
|
||||
| 元素描述 | Tailwind class | CSS 值(px) | 正确 rpx |
|
||||
|----------|---------------|------------|----------|
|
||||
| body | `bg-gray-1 min-h-screen` | bg: #f3f3f3 | — |
|
||||
| 指标内容容器 | `p-4 space-y-4` | p: 16px, gap: 16px | p: 29rpx, gap: 29rpx |
|
||||
@@ -1,155 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>首页设置 - 球房运营助手</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#0052d9',
|
||||
'primary-light': '#ecf2fe',
|
||||
success: '#00a870',
|
||||
warning: '#ed7b2f',
|
||||
error: '#e34d59',
|
||||
'gray-1': '#f3f3f3',
|
||||
'gray-2': '#eeeeee',
|
||||
'gray-3': '#e7e7e7',
|
||||
'gray-4': '#dcdcdc',
|
||||
'gray-5': '#c5c5c5',
|
||||
'gray-6': '#a6a6a6',
|
||||
'gray-7': '#8b8b8b',
|
||||
'gray-8': '#777777',
|
||||
'gray-9': '#5e5e5e',
|
||||
'gray-10': '#4b4b4b',
|
||||
'gray-11': '#393939',
|
||||
'gray-12': '#2c2c2c',
|
||||
'gray-13': '#242424',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Noto Sans SC', 'sans-serif'],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
.radio-checked {
|
||||
border-color: #0052d9;
|
||||
background: #0052d9;
|
||||
}
|
||||
.radio-checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.option-card {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.option-card.selected {
|
||||
border-color: #0052d9;
|
||||
background: linear-gradient(135deg, #ecf2fe 0%, #f8faff 100%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-10">
|
||||
<div class="h-11 flex items-center relative border-b border-gray-2 px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-gray-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium text-gray-13">首页设置</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 说明文字 -->
|
||||
<div class="px-4 py-4">
|
||||
<p class="text-sm text-gray-7">选择登录后默认显示的首页</p>
|
||||
</div>
|
||||
|
||||
<!-- 选项列表 -->
|
||||
<div class="px-4 space-y-3">
|
||||
<div id="option-task" class="option-card bg-white rounded-2xl p-4 border-2 border-transparent cursor-pointer selected" onclick="selectHome('task')">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-primary to-blue-400 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<svg class="w-6 h-6 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-base font-medium text-gray-13 mb-1">任务</p>
|
||||
<p class="text-xs text-gray-6">查看待办任务和业绩概览</p>
|
||||
</div>
|
||||
<div id="radio-task" class="w-5 h-5 border-2 border-gray-4 rounded-full relative radio-checked"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="option-board" class="option-card bg-white rounded-2xl p-4 border-2 border-transparent cursor-pointer" onclick="selectHome('board')">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-success to-green-400 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<svg class="w-6 h-6 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-base font-medium text-gray-13 mb-1">看板</p>
|
||||
<p class="text-xs text-gray-6">查看财务、客户、助教数据</p>
|
||||
</div>
|
||||
<div id="radio-board" class="w-5 h-5 border-2 border-gray-4 rounded-full relative"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<div class="px-4 py-6">
|
||||
<div class="flex items-start gap-3 p-4 bg-primary/5 rounded-xl">
|
||||
<svg class="w-5 h-5 text-primary flex-shrink-0 mt-0.5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
|
||||
</svg>
|
||||
<p class="text-xs text-gray-7 leading-relaxed">设置会自动保存,切换选项后即刻生效。退出登录后重新登录仍会保持您的设置。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function selectHome(type) {
|
||||
const taskRadio = document.getElementById('radio-task');
|
||||
const boardRadio = document.getElementById('radio-board');
|
||||
const taskOption = document.getElementById('option-task');
|
||||
const boardOption = document.getElementById('option-board');
|
||||
|
||||
if (type === 'task') {
|
||||
taskRadio.classList.add('radio-checked');
|
||||
boardRadio.classList.remove('radio-checked');
|
||||
taskOption.classList.add('selected');
|
||||
boardOption.classList.remove('selected');
|
||||
} else {
|
||||
boardRadio.classList.add('radio-checked');
|
||||
taskRadio.classList.remove('radio-checked');
|
||||
boardOption.classList.add('selected');
|
||||
taskOption.classList.remove('selected');
|
||||
}
|
||||
|
||||
console.log('已设置默认首页为:', type);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -51,24 +51,26 @@
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">任务详情</h1>
|
||||
<h1 class="flex-1 text-center text-base font-medium">客户回访</h1>
|
||||
</div>
|
||||
|
||||
<!-- 客户信息 -->
|
||||
<div class="px-5 pt-2 pb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg">
|
||||
<span class="text-2xl font-bold text-white">赵</span>
|
||||
<span class="text-2xl font-bold text-white">王</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xl font-semibold">赵女士</span>
|
||||
<span class="px-2 py-0.5 bg-white/25 backdrop-blur-sm text-white rounded-full text-xs font-medium">客户回访</span>
|
||||
<span class="text-xl font-semibold">王先生</span>
|
||||
<span class="px-2 py-0.5 bg-white/25 backdrop-blur-sm text-white rounded-full text-xs font-medium">高优先召回</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-sm">
|
||||
<span>135****6677</span>
|
||||
<button onclick="this.previousElementSibling.textContent='13566776677';this.style.display='none'" class="px-2 py-0.5 bg-white/20 rounded text-white/90 text-xs">查看</button>
|
||||
<span>💰 储值 <span style="background: linear-gradient(135deg, #d4af37 0%, #f4d03f 50%, #d4af37 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600;">非常多</span></span>
|
||||
<span>138****5678</span>
|
||||
<button onclick="this.previousElementSibling.textContent='13812345678';this.style.display='none'" class="px-2 py-0.5 bg-white/20 rounded text-white/90 text-xs">查看</button>
|
||||
</div>
|
||||
<div class="mt-1 text-white/70 text-sm">
|
||||
<span>黄金会员</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -88,7 +90,7 @@
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-primary/10 text-primary text-[11px] font-medium rounded-sm leading-normal tracking-wide">客户<br>基础</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">👩 女性 · VIP会员 · 入会1年半 · 忠实老客户</p>
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎂 生日 3月15日 · VIP会员 · 注册2年</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,41 +98,32 @@
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">☀️ 偏好周末下午 · 月均6-8次</p>
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🌙 常来夜场 · 月均4-5次</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💰 高客单价 · 爱点酒水</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💰 高客单价</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">场均消费 ¥420,高于门店均值 ¥180;酒水小食附加消费占比 40%,偏好VIP包厢</p>
|
||||
</div>
|
||||
<!-- 玩法偏好 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 斯诺克爱好者 · 技术中上 · 喜欢研究杆法</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 偏爱中式八球 · 斯诺克进阶中 · 最近对花式九球也有兴趣</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">斯诺克占比 85%,偶尔玩中式八球;对高级杆法有浓厚兴趣,正在学习走位技巧</p>
|
||||
</div>
|
||||
<!-- 重要反馈 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">⭐ 上次服务好评,新球杆手感满意</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">⚠️ 上次提到想练斯诺克走位</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">2月4日到店时表示新球杆手感很好,希望下次能提前预留VIP包厢;满意度持续保持高位</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,93 +131,40 @@
|
||||
<!-- 与我的关系 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">与我的关系</h2>
|
||||
<h2 class="section-title pink text-sm font-semibold text-gray-13">与我的关系</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-4 py-2 bg-gradient-to-r from-pink-500 to-rose-500 text-white text-sm font-semibold rounded-xl shadow-sm">💖 非常好</span>
|
||||
<span class="px-4 py-2 bg-gradient-to-r from-pink-500 to-rose-500 text-white text-sm font-semibold rounded-xl shadow-sm">🧡 良好</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="h-3 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-pink-400 to-rose-500 rounded-full" style="width: 88%"></div>
|
||||
<div class="h-full bg-gradient-to-r from-pink-400 to-rose-500 rounded-full" style="width: 85%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-lg font-bold text-pink-500">0.88</span>
|
||||
<span class="text-lg font-bold text-pink-500">0.85</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed mb-4">
|
||||
长期合作关系良好,共有 45 次服务记录。客户多次指定您服务,评价均为 5 星。是您的核心客户之一,需要持续维护。
|
||||
最近 3 个月每周均有 1-2 次课程互动,客户反馈良好。上次服务评价 5 星,多次指定您为服务助教。
|
||||
</p>
|
||||
<!-- 近期服务记录 -->
|
||||
<div class="svc-section-bg">
|
||||
<p class="text-sm font-semibold text-gray-13 mb-3">📋 近期服务记录</p>
|
||||
<div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">VIP2号房</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.0h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥190</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 红牛x2 花生米x1</span>
|
||||
<span class="svc-date">2026-02-04 15:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">8号台</span>
|
||||
<span class="svc-type incentive">激励课</span>
|
||||
<span class="svc-duration">1.5h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥120</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 可乐x2</span>
|
||||
<span class="svc-date">2026-01-30 16:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">VIP2号房</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.5h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥200</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 百威x3 薯条x1</span>
|
||||
<span class="svc-date">2026-01-25 14:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button onclick="window.location.href='customer-service-records.html'" class="text-xs text-primary font-medium">查看全部服务记录 →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 任务建议 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="section-title purple text-sm font-semibold text-gray-13 mb-4">任务建议</h2>
|
||||
<div class="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl p-4 border border-blue-100">
|
||||
<h2 class="section-title orange text-sm font-semibold text-gray-13 mb-4">任务建议</h2>
|
||||
<div class="bg-gradient-to-br from-teal-50 to-cyan-50 rounded-xl p-4 border border-teal-200">
|
||||
<p class="text-sm text-primary leading-relaxed font-medium mb-3">
|
||||
<span class="flex items-center justify-between">
|
||||
<span>📞 常规回访要点</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed mb-2">
|
||||
该客户上次到店是 3 天前,关系良好,进行常规关怀回访:
|
||||
</p>
|
||||
<ul class="text-sm text-gray-9 space-y-1.5 list-disc list-inside">
|
||||
<li>询问上次体验是否满意,是否有改进建议</li>
|
||||
<li>告知近期新到的斯诺克相关设备或活动</li>
|
||||
<li>提前预约下次到店时间,提供专属服务</li>
|
||||
<li>询问近期是否有空,邀请体验新到的器材</li>
|
||||
<li>告知本周末有会员专属活动</li>
|
||||
<li>根据其偏好时段(晚间)推荐合适的时间</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-4 p-4 bg-gray-50 rounded-xl border border-gray-100">
|
||||
@@ -234,19 +174,19 @@
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐您好!上次打球感觉怎么样?新到的球杆手感还习惯吗?这周末您有空的话,可以提前帮您预留老位置~"
|
||||
"王哥您好,好久不见!最近店里新到了几张国际标准的斯诺克球桌,知道您是斯诺克爱好者,想邀请您有空来体验一下~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐,最近店里新进了一批斯诺克专用巧克粉,手感特别好,下次来的时候可以试试~"
|
||||
"王哥,最近忙吗?这周末我们有个老客户专属的球友交流赛,奖品还挺丰富的,您要不要来参加?"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐好呀,上次您说想学几个高级杆法,我最近整理了一些教学视频,要不要发给您先看看?"
|
||||
"王哥好呀,上次您提到想练练斯诺克的走位,我最近研究了一些新的训练方法,下次来的时候可以一起试试~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐,这周六下午VIP包厢有空位,要不要帮您提前预留?可以叫上朋友一起来打球~"
|
||||
"王哥,好久没见您了,您的老位置 A12 号台一直给您留着呢!最近晚上人不多,环境特别好,随时欢迎您来~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐您好,我们下个月有个会员积分兑换活动,您的积分可以换不少好东西,到时候提醒您哦~"
|
||||
"王哥您好,我们这个月推出了储值会员专属的夜场优惠套餐,包含球台+酒水,性价比很高,给您留意着呢~"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -256,31 +196,17 @@
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">我给TA的备注</h2>
|
||||
<span class="text-xs text-gray-6">2 条备注</span>
|
||||
<span class="text-xs text-gray-6">0 条备注</span>
|
||||
</div>
|
||||
<div id="noteList" class="space-y-3">
|
||||
<div class="note-card-wrap flex items-start gap-3 p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs text-gray-6 mb-1.5">2026-02-07</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">赵姐反馈上次体验很满意,新球杆手感不错,希望下次能预留VIP包厢。</p>
|
||||
</div>
|
||||
<div class="star-rating" data-score="9"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="note-card-wrap flex items-start gap-3 p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs text-gray-6 mb-1.5">2026-01-25</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">已预约本周六下午到店,需要提前安排靠窗位置。</p>
|
||||
</div>
|
||||
<div class="star-rating" data-score="9"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="noteEmpty" class="text-center py-6 hidden">
|
||||
<div id="noteEmpty" class="text-center py-6">
|
||||
<svg class="w-10 h-10 text-gray-4 mx-auto mb-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-5">暂无备注</p>
|
||||
</div>
|
||||
<svg class="w-10 h-10 text-gray-4 mx-auto mb-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AI 标识配色演示</title>
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: 'Noto Sans SC', -apple-system, sans-serif; background: #f5f5f5; padding: 20px; }
|
||||
h1 { font-size: 18px; color: #242424; margin-bottom: 20px; text-align: center; }
|
||||
h2 { font-size: 15px; color: #5e5e5e; margin: 24px 0 12px; padding-left: 8px; border-left: 3px solid #667eea; }
|
||||
.demo-row { display: flex; align-items: center; gap: 16px; padding: 14px 16px; background: #fff; border-radius: 12px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
|
||||
.demo-row .label { font-size: 13px; color: #8b8b8b; min-width: 36px; }
|
||||
.demo-row .sample-text { font-size: 14px; color: #5e5e5e; display: flex; align-items: center; }
|
||||
.note { font-size: 12px; color: #a6a6a6; text-align: center; margin-top: 8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>AI 标识配色方案演示</h1>
|
||||
|
||||
<!-- ===== 嵌入 Icon ===== -->
|
||||
<h2>嵌入 Icon(行首小图标 · 机器人)</h2>
|
||||
|
||||
<div class="demo-row">
|
||||
<span class="label">红</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-red"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">橙</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-orange"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">黄</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-yellow"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">蓝</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-blue"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">靛</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-indigo"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">紫</span>
|
||||
<span class="sample-text"><span class="ai-inline-icon ai-color-purple"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</span>
|
||||
</div>
|
||||
<p class="note">每个页面所有嵌入 Icon 统一使用一种配色,刷新后随机分配</p>
|
||||
|
||||
<!-- ===== Title AI 标识 ===== -->
|
||||
<h2>Title AI 标识(标题行右侧 · 机器人 · 浅色背景+边框)</h2>
|
||||
|
||||
<div class="demo-row">
|
||||
<span class="label">红</span>
|
||||
<span class="ai-title-badge ai-color-red"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">橙</span>
|
||||
<span class="ai-title-badge ai-color-orange"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">黄</span>
|
||||
<span class="ai-title-badge ai-color-yellow"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">蓝</span>
|
||||
<span class="ai-title-badge ai-color-blue"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">靛</span>
|
||||
<span class="ai-title-badge ai-color-indigo"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="demo-row">
|
||||
<span class="label">紫</span>
|
||||
<span class="ai-title-badge ai-color-purple"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="currentColor" opacity="0.12" stroke="currentColor" stroke-width="0.7"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="currentColor"/><circle cx="9" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="15" cy="11.5" r="1.8" fill="white" stroke="currentColor" stroke-width="0.6"/><circle cx="9.4" cy="11.2" r="0.7" fill="currentColor"/><circle cx="15.4" cy="11.2" r="0.7" fill="currentColor"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.5"/><rect x="3" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/><rect x="19" y="10" width="2" height="4" rx="1" fill="currentColor" opacity="0.15" stroke="currentColor" stroke-width="0.5"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<p class="note">每个页面所有 Title AI 标识统一使用一种配色,刷新后随机分配</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,124 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>账号申请 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.bg-gradient-main {
|
||||
background: linear-gradient(135deg, #e0f2fe 0%, #f0f9ff 50%, #ecfeff 100%);
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-main min-h-screen flex flex-col">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white/80 backdrop-blur-lg sticky top-0 z-10">
|
||||
<div class="h-11 flex items-center justify-center relative border-b border-gray-200/50">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-gray-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="text-base font-medium text-gray-13">申请访问权限</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="flex-1 p-4">
|
||||
<!-- 欢迎卡片 -->
|
||||
<div class="bg-gradient-to-br from-primary to-blue-400 rounded-2xl p-5 mb-4 text-white shadow-lg shadow-primary/20">
|
||||
<div class="flex items-center gap-4 mb-3">
|
||||
<div class="w-12 h-12 bg-white/20 backdrop-blur-sm rounded-xl flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold mb-1">欢迎加入球房运营助手</h2>
|
||||
<p class="text-white/80 text-sm">请填写申请信息,等待管理员审核</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 说明文字 -->
|
||||
<div class="bg-primary/5 border border-primary/10 rounded-xl p-4 mb-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<svg class="w-5 h-5 text-primary flex-shrink-0 mt-0.5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
|
||||
</svg>
|
||||
<div>
|
||||
<p class="text-sm text-primary font-medium mb-1">申请说明</p>
|
||||
<p class="text-xs text-gray-7 leading-relaxed">
|
||||
请填写您的真实信息,包括姓名、岗位和所属门店等,以便管理员快速审核您的申请。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表单区域 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-lg shadow-gray-200/50">
|
||||
<div class="mb-3 flex items-center gap-1">
|
||||
<span class="text-error text-sm">*</span>
|
||||
<span class="text-sm font-medium text-gray-13">申请说明</span>
|
||||
</div>
|
||||
<textarea
|
||||
id="applyReason"
|
||||
class="w-full h-36 p-4 bg-gray-50 rounded-xl border border-gray-100 resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary/30 transition-all"
|
||||
placeholder="点击填写申请信息: 1. 您的姓名 2. 您的岗位(如:助教、店长等) 3. 所属门店 4. 其他说明(可选)"
|
||||
></textarea>
|
||||
<p id="errorTip" class="text-error text-xs mt-2 hidden">申请说明不能为空</p>
|
||||
<div class="flex items-center justify-between mt-3">
|
||||
<span class="text-xs text-gray-5">请认真填写,信息不完整可能导致审核不通过</span>
|
||||
<span class="text-xs text-gray-6"><span id="charCount">0</span>/200</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 审核流程说明 -->
|
||||
<div class="mt-4 bg-white rounded-2xl p-5 shadow-lg shadow-gray-200/50">
|
||||
<h3 class="text-sm font-medium text-gray-13 mb-4">审核流程</h3>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-8 h-8 bg-primary rounded-full flex items-center justify-center text-white text-xs font-medium mb-2">1</div>
|
||||
<span class="text-xs text-gray-7">提交申请</span>
|
||||
</div>
|
||||
<div class="flex-1 h-0.5 bg-gray-200 mx-2"></div>
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center text-gray-6 text-xs font-medium mb-2">2</div>
|
||||
<span class="text-xs text-gray-6">等待审核</span>
|
||||
</div>
|
||||
<div class="flex-1 h-0.5 bg-gray-200 mx-2"></div>
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center text-gray-6 text-xs font-medium mb-2">3</div>
|
||||
<span class="text-xs text-gray-6">审核通过</span>
|
||||
</div>
|
||||
<div class="flex-1 h-0.5 bg-gray-200 mx-2"></div>
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="w-8 h-8 bg-gray-200 rounded-full flex items-center justify-center text-gray-6 text-xs font-medium mb-2">4</div>
|
||||
<span class="text-xs text-gray-6">开始使用</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="p-4 pb-8 bg-white/80 backdrop-blur-lg border-t border-gray-100">
|
||||
<button id="submitBtn" class="w-full py-4 bg-gradient-to-r from-primary to-blue-500 rounded-xl text-white font-medium text-base shadow-lg shadow-primary/30 active:scale-[0.98] transition-transform">
|
||||
提交申请
|
||||
</button>
|
||||
<p class="text-xs text-gray-5 text-center mt-3">
|
||||
审核通常需要 1-3 个工作日
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,812 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>看板-助教 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
.tab-active {
|
||||
color: #0052d9;
|
||||
position: relative;
|
||||
}
|
||||
.tab-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 24px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #0052d9, #5b9cf8);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.filter-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
.filter-overlay.show {
|
||||
display: block;
|
||||
}
|
||||
.filter-dropdown {
|
||||
display: none;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
border-radius: 0 0 16px 16px;
|
||||
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
|
||||
z-index: 1001;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.filter-dropdown.show {
|
||||
display: block;
|
||||
}
|
||||
/* 二级筛选栏层级与动效 */
|
||||
#filterBar {
|
||||
overflow: hidden;
|
||||
max-height: 120px;
|
||||
transition: transform 220ms ease, opacity 220ms ease, max-height 220ms ease;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
/* 仅用于「首次进入页面」的下滑出现(用 transition 触发一次) */
|
||||
#filterBar.filter-bar-enter {
|
||||
transform: translateY(-16px);
|
||||
opacity: 0;
|
||||
}
|
||||
#filterBar.filter-bar-hidden {
|
||||
opacity: 0;
|
||||
transform: translateY(-110%);
|
||||
pointer-events: none;
|
||||
}
|
||||
@keyframes filterBarDrop {
|
||||
from { transform: translateY(-16px); opacity: 0; }
|
||||
to { transform: translateY(0); opacity: 1; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#filterBar { animation: none; transition: none; }
|
||||
}
|
||||
.coach-card {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.dim-container { display: none; }
|
||||
.dim-container.active { display: block; }
|
||||
.coach-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-20 shadow-sm">
|
||||
<!-- 一级 Tab -->
|
||||
<div class="flex border-b border-gray-2">
|
||||
<a href="board-finance.html" class="flex-1 py-3 text-center text-sm font-medium text-gray-7">财务</a>
|
||||
<a href="board-customer.html" class="flex-1 py-3 text-center text-sm font-medium text-gray-7">客户</a>
|
||||
<a href="board-coach.html" class="flex-1 py-3 text-center text-sm font-medium tab-active">助教</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域(二级)— 高度与财务客户看板一致,文字放大 -->
|
||||
<div id="filterBar" class="bg-gray-1 sticky top-[44px] z-10 px-4 py-2 border-b border-gray-2">
|
||||
<div class="bg-white rounded-lg p-1.5 flex gap-2 shadow-sm border border-gray-2">
|
||||
<button onclick="toggleFilter('sort')" class="flex-[2] px-3 py-2 bg-gray-50 rounded-lg text-sm text-gray-10 flex items-center justify-center gap-1 border border-gray-100 whitespace-nowrap">
|
||||
<span id="sortLabel" class="truncate font-medium">定档业绩最高</span>
|
||||
<svg class="w-4 h-4 text-gray-5 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button onclick="toggleFilter('skill')" class="flex-1 px-3 py-2 bg-gray-50 rounded-lg text-sm text-gray-10 flex items-center justify-center gap-1 border border-gray-100 whitespace-nowrap">
|
||||
<span id="skillLabel" class="truncate">不限</span>
|
||||
<svg class="w-4 h-4 text-gray-5 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button onclick="toggleFilter('time')" class="flex-1 px-3 py-2 bg-gray-50 rounded-lg text-sm text-gray-10 flex items-center justify-center gap-1 border border-gray-100 whitespace-nowrap">
|
||||
<span id="timeLabel" class="truncate">本月</span>
|
||||
<svg class="w-4 h-4 text-gray-5 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 12 15 18 9"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 遮罩层 -->
|
||||
<div id="filterOverlay" class="filter-overlay" onclick="closeAllFilters()"></div>
|
||||
|
||||
<!-- 排序筛选弹窗 -->
|
||||
<div id="sortDropdown" class="filter-dropdown">
|
||||
<div class="p-4 space-y-2">
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSort('定档业绩最高')">定档业绩最高</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSort('定档业绩最低')">定档业绩最低</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSort('工资最高')">工资最高</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSort('工资最低')">工资最低</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSort('客源储值最高')">客源储值最高</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSort('任务完成最多')">任务完成最多</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 擅长项目筛选弹窗 -->
|
||||
<div id="skillDropdown" class="filter-dropdown">
|
||||
<div class="p-4 space-y-2">
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSkill('不限')">不限</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSkill('🎱')">🎱</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSkill('斯')">斯</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSkill('🀄')">🀄</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectSkill('🎤')">🎤</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 时间筛选弹窗 -->
|
||||
<div id="timeDropdown" class="filter-dropdown">
|
||||
<div class="p-4 space-y-2">
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectTime('本月')">本月</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectTime('本季度')">本季度</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectTime('上月')">上月</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectTime('前3个月')">前3个月(不含本月)</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectTime('上季度')">上季度</div>
|
||||
<div class="px-4 py-3 text-sm text-gray-10 hover:bg-primary/5 rounded-lg cursor-pointer" onclick="selectTime('最近6个月')">最近6个月(不含本月,不支持客源储值最高)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 定档业绩最高/最低 ====== -->
|
||||
<div id="dim-perf" class="dim-container active p-4 space-y-3">
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">小</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">小燕</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto flex items-center gap-2 text-xs flex-shrink-0">
|
||||
<span>定档 <b class="text-primary text-sm">86.2h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">92.0h</span></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 王先生</span><span>💖 李女士</span><span>💛 赵总</span>
|
||||
</div>
|
||||
<span class="text-warning font-medium flex-shrink-0">距升档 13.8h</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-green-400 to-emerald-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">泡</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">泡芙</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-purple-400 to-violet-400 text-white text-xs rounded flex-shrink-0">高级</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto flex items-center gap-2 text-xs flex-shrink-0">
|
||||
<span>定档 <b class="text-primary text-sm">72.5h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">78.0h</span></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 陈先生</span><span>💛 刘女士</span><span>💛 黄总</span>
|
||||
</div>
|
||||
<span class="text-warning font-medium flex-shrink-0">距升档 7.5h</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">A</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Amy</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto flex items-center gap-2 text-xs flex-shrink-0">
|
||||
<span>定档 <b class="text-primary text-sm">68.0h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">72.5h</span></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 张先生</span><span>💛 周女士</span><span>💛 吴总</span>
|
||||
</div>
|
||||
<span class="text-warning font-medium flex-shrink-0">距升档 32.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">M</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Mia</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded flex-shrink-0">🀄</span>
|
||||
<span class="ml-auto flex items-center gap-2 text-xs flex-shrink-0">
|
||||
<span>定档 <b class="text-primary text-sm">55.0h</b></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 赵先生</span><span>💛 吴女士</span><span>💛 孙总</span>
|
||||
</div>
|
||||
<span class="text-warning font-medium flex-shrink-0">距升档 5.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">糖</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">糖糖</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-gray-400 to-gray-500 text-white text-xs rounded flex-shrink-0">初级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto flex items-center gap-2 text-xs flex-shrink-0">
|
||||
<span>定档 <b class="text-primary text-sm">42.0h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">45.0h</span></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 钱先生</span><span>💛 孙女士</span><span>💛 周总</span>
|
||||
</div>
|
||||
<span class="text-success font-medium flex-shrink-0">✅ 已达标</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-cyan-400 to-teal-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">露</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">露露</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-error/10 text-error text-xs rounded flex-shrink-0">🎤</span>
|
||||
<span class="ml-auto flex items-center gap-2 text-xs flex-shrink-0">
|
||||
<span>定档 <b class="text-primary text-sm">38.0h</b></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 郑先生</span><span>💛 冯女士</span><span>💛 陈总</span>
|
||||
</div>
|
||||
<span class="text-warning font-medium flex-shrink-0">距升档 22.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- ====== 工资最高/最低 ====== -->
|
||||
<div id="dim-salary" class="dim-container p-4 space-y-3">
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">小</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">小燕</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥12,680</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 王先生</span><span>💖 李女士</span><span>💛 赵总</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-10 font-semibold">定档 <b>86.2h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">92.0h</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-green-400 to-emerald-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">泡</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">泡芙</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-purple-400 to-violet-400 text-white text-xs rounded flex-shrink-0">高级</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥10,200</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 陈先生</span><span>💛 刘女士</span><span>💛 黄总</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-10 font-semibold">定档 <b>72.5h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">78.0h</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">A</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Amy</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥9,800</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 张先生</span><span>💛 周女士</span><span>💛 吴总</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-10 font-semibold">定档 <b>68.0h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">72.5h</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">M</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Mia</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded flex-shrink-0">🀄</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥7,500</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 赵先生</span><span>💛 吴女士</span><span>💛 孙总</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-10 font-semibold">定档 <b>55.0h</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">糖</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">糖糖</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-gray-400 to-gray-500 text-white text-xs rounded flex-shrink-0">初级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥6,200</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 钱先生</span><span>💛 孙女士</span><span>💛 周总</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-10 font-semibold">定档 <b>42.0h</b></span>
|
||||
<span class="text-gray-5">折前 <span class="text-gray-7">45.0h</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-cyan-400 to-teal-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">露</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">露露</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-error/10 text-error text-xs rounded flex-shrink-0">🎤</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded">预估</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥5,100</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 郑先生</span><span>💛 冯女士</span><span>💛 陈总</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-10 font-semibold">定档 <b>38.0h</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- ====== 客源储值最高 ====== -->
|
||||
<div id="dim-sv" class="dim-container p-4 space-y-3">
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">小</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">小燕</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-xs text-gray-6">储值</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥45,200</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 王先生</span><span>💖 李女士</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-7">客户 <b class="text-gray-10">18</b>人</span>
|
||||
<span class="text-gray-5">|</span>
|
||||
<span class="text-gray-7">消耗 <b class="text-gray-10">¥8,600</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-green-400 to-emerald-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">泡</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">泡芙</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-purple-400 to-violet-400 text-white text-xs rounded flex-shrink-0">高级</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-xs text-gray-6">储值</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥38,600</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 陈先生</span><span>💛 刘女士</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-7">客户 <b class="text-gray-10">15</b>人</span>
|
||||
<span class="text-gray-5">|</span>
|
||||
<span class="text-gray-7">消耗 <b class="text-gray-10">¥6,200</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">A</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Amy</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-xs text-gray-6">储值</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥32,100</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 张先生</span><span>💛 周女士</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-7">客户 <b class="text-gray-10">14</b>人</span>
|
||||
<span class="text-gray-5">|</span>
|
||||
<span class="text-gray-7">消耗 <b class="text-gray-10">¥5,800</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">M</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Mia</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded flex-shrink-0">🀄</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-xs text-gray-6">储值</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥28,500</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 赵先生</span><span>💛 吴女士</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-7">客户 <b class="text-gray-10">12</b>人</span>
|
||||
<span class="text-gray-5">|</span>
|
||||
<span class="text-gray-7">消耗 <b class="text-gray-10">¥4,100</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">糖</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">糖糖</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-gray-400 to-gray-500 text-white text-xs rounded flex-shrink-0">初级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-xs text-gray-6">储值</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥22,000</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 钱先生</span><span>💛 孙女士</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-7">客户 <b class="text-gray-10">10</b>人</span>
|
||||
<span class="text-gray-5">|</span>
|
||||
<span class="text-gray-7">消耗 <b class="text-gray-10">¥3,500</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-cyan-400 to-teal-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">露</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">露露</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-error/10 text-error text-xs rounded flex-shrink-0">🎤</span>
|
||||
<span class="ml-auto flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-xs text-gray-6">储值</span>
|
||||
<span class="text-lg font-bold text-gray-13">¥18,300</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 郑先生</span><span>💛 冯女士</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<span class="text-gray-7">客户 <b class="text-gray-10">9</b>人</span>
|
||||
<span class="text-gray-5">|</span>
|
||||
<span class="text-gray-7">消耗 <b class="text-gray-10">¥2,800</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- ====== 任务完成最多 ====== -->
|
||||
<div id="dim-task" class="dim-container p-4 space-y-3">
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">小</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">小燕</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto text-sm text-gray-7 flex-shrink-0">召回 <b class="text-primary text-base">18</b></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 王先生</span><span>💖 李女士</span><span>💛 赵总</span>
|
||||
</div>
|
||||
<span class="flex-shrink-0 text-gray-7">回访 <b class="text-gray-10">14</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-green-400 to-emerald-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">泡</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">泡芙</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-purple-400 to-violet-400 text-white text-xs rounded flex-shrink-0">高级</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto text-sm text-gray-7 flex-shrink-0">召回 <b class="text-primary text-base">15</b></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 陈先生</span><span>💛 刘女士</span><span>💛 黄总</span>
|
||||
</div>
|
||||
<span class="flex-shrink-0 text-gray-7">回访 <b class="text-gray-10">13</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">A</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Amy</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-amber-400 to-orange-400 text-white text-xs rounded flex-shrink-0">星级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-xs rounded flex-shrink-0">斯</span>
|
||||
<span class="ml-auto text-sm text-gray-7 flex-shrink-0">召回 <b class="text-primary text-base">12</b></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💖 张先生</span><span>💛 周女士</span><span>💛 吴总</span>
|
||||
</div>
|
||||
<span class="flex-shrink-0 text-gray-7">回访 <b class="text-gray-10">13</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">M</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">Mia</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-warning/10 text-warning text-xs rounded flex-shrink-0">🀄</span>
|
||||
<span class="ml-auto text-sm text-gray-7 flex-shrink-0">召回 <b class="text-primary text-base">10</b></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 赵先生</span><span>💛 吴女士</span><span>💛 孙总</span>
|
||||
</div>
|
||||
<span class="flex-shrink-0 text-gray-7">回访 <b class="text-gray-10">10</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">糖</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">糖糖</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-gray-400 to-gray-500 text-white text-xs rounded flex-shrink-0">初级</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-xs rounded flex-shrink-0">🎱</span>
|
||||
<span class="ml-auto text-sm text-gray-7 flex-shrink-0">召回 <b class="text-primary text-base">8</b></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 钱先生</span><span>💛 孙女士</span><span>💛 周总</span>
|
||||
</div>
|
||||
<span class="flex-shrink-0 text-gray-7">回访 <b class="text-gray-10">10</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="coach-detail.html" class="block bg-white rounded-2xl p-4 shadow-sm coach-card">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-11 h-11 rounded-full bg-gradient-to-br from-cyan-400 to-teal-500 flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-white font-semibold text-base">露</span>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5 flex-wrap">
|
||||
<span class="text-base font-semibold text-gray-13">露露</span>
|
||||
<span class="px-1.5 py-0.5 bg-gradient-to-r from-blue-400 to-indigo-400 text-white text-xs rounded flex-shrink-0">中级</span>
|
||||
<span class="px-1.5 py-0.5 bg-error/10 text-error text-xs rounded flex-shrink-0">🎤</span>
|
||||
<span class="ml-auto text-sm text-gray-7 flex-shrink-0">召回 <b class="text-primary text-base">6</b></span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1.5 text-xs">
|
||||
<div class="flex items-center gap-2 text-gray-6 truncate">
|
||||
<span>💛 郑先生</span><span>💛 冯女士</span><span>💛 陈总</span>
|
||||
</div>
|
||||
<span class="flex-shrink-0 text-gray-7">回访 <b class="text-gray-10">9</b></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 悬浮助手按钮 -->
|
||||
|
||||
|
||||
<!-- 通用底部导航 -->
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,167 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>助手对话记录 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
.chat-item {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.chat-item:active {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-10">
|
||||
<div class="h-11 flex items-center relative border-b border-gray-2 px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-gray-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium text-gray-13">助手对话记录</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 对话列表 -->
|
||||
<div class="divide-y divide-gray-100">
|
||||
<!-- 对话记录 1 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-primary to-blue-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">如何提升王先生的到店频率?</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">10分钟前</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 8 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 对话记录 2 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-success to-green-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">帮我分析本月财务数据</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">2小时前</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 15 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 对话记录 3 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-warning to-orange-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">李女士的消费习惯分析</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">昨天</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 12 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 对话记录 4 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-primary to-blue-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">如何提高客户满意度?</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">昨天</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 20 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 对话记录 5 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-error to-red-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">小燕本月业绩如何?</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">2天前</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 6 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 对话记录 6 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-success to-green-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">推荐一些促销活动方案</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">3天前</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 25 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- 对话记录 7 -->
|
||||
<a href="chat.html" class="block bg-white px-4 py-4 chat-item">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-11 h-11 bg-gradient-to-br from-warning to-orange-400 rounded-xl flex items-center justify-center flex-shrink-0 shadow-sm">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between mb-1">
|
||||
<h3 class="text-sm font-medium text-gray-13 truncate">分析高流失客户群体</h3>
|
||||
<span class="text-xs text-gray-6 flex-shrink-0 ml-2">1周前</span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-6">共 18 条消息</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,155 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>助手对话 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
.chat-container {
|
||||
height: calc(100vh - 44px - 70px - env(safe-area-inset-top, 44px));
|
||||
overflow-y: auto;
|
||||
}
|
||||
.message-bubble {
|
||||
max-width: 80%;
|
||||
}
|
||||
.voice-btn:active {
|
||||
background: #0052d9;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen flex flex-col">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-10">
|
||||
<div class="h-11 flex items-center relative border-b border-gray-2 px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-gray-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium text-gray-13">智能助手</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 对话内容区域 -->
|
||||
<div class="chat-container flex-1 p-4 space-y-4">
|
||||
<!-- 引用内容卡片 -->
|
||||
<div class="bg-gray-2 rounded-lg p-3 text-sm">
|
||||
<div class="flex items-center gap-2 text-gray-7 mb-1">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
|
||||
</svg>
|
||||
<span>来源:任务 - 高优先召回</span>
|
||||
</div>
|
||||
<p class="text-gray-9">王先生 · 最近到店15天前 · VIP客户</p>
|
||||
</div>
|
||||
|
||||
<!-- 用户消息 -->
|
||||
<div class="flex justify-end">
|
||||
<div class="message-bubble bg-primary text-white rounded-2xl rounded-tr-sm px-4 py-3">
|
||||
<p class="text-sm">如何提升这位客户的到店频率?</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 助手消息 -->
|
||||
<div class="flex justify-start gap-2">
|
||||
<div class="w-8 h-8 bg-gradient-to-br from-primary to-blue-400 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<svg class="w-4 h-4 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="message-bubble bg-white rounded-2xl rounded-tl-sm px-4 py-3 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed">
|
||||
根据王先生的消费数据分析,我有以下建议:
|
||||
</p>
|
||||
<ol class="text-sm text-gray-13 leading-relaxed mt-2 list-decimal list-inside space-y-2">
|
||||
<li><strong>个性化邀约</strong>:王先生偏好晚间21:00后到店,建议在这个时间段前发送邀约消息。</li>
|
||||
<li><strong>活动推荐</strong>:他对斯诺克感兴趣,可以推荐即将举办的斯诺克比赛活动。</li>
|
||||
<li><strong>储值提醒</strong>:他的储值余额还有8600元,可以提醒他来消费,避免余额长期闲置。</li>
|
||||
<li><strong>专属服务</strong>:安排他熟悉的助教张三接待,提升服务体验。</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户消息 -->
|
||||
<div class="flex justify-end">
|
||||
<div class="message-bubble bg-primary text-white rounded-2xl rounded-tr-sm px-4 py-3">
|
||||
<p class="text-sm">能帮我生成一条邀约话术吗?</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 助手消息 -->
|
||||
<div class="flex justify-start gap-2">
|
||||
<div class="w-8 h-8 bg-gradient-to-br from-primary to-blue-400 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<svg class="w-4 h-4 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="message-bubble bg-white rounded-2xl rounded-tl-sm px-4 py-3 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed">
|
||||
好的,根据王先生的特点,为您生成以下邀约话术:
|
||||
</p>
|
||||
<div class="mt-3 p-3 bg-primary-light rounded-lg">
|
||||
<p class="text-sm text-primary leading-relaxed">
|
||||
"王哥您好!好久不见了,最近工作顺利吧?😊 我们店里最近新到了几张英国进口的斯诺克球桌,球感特别好,知道您是斯诺克爱好者,第一时间想到邀请您来体验一下。这周末晚上有空吗?我提前给您预留好包厢~"
|
||||
</p>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2">💡 提示:建议在晚间8点左右发送,这是王先生活跃的时间段。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户消息 -->
|
||||
<div class="flex justify-end">
|
||||
<div class="message-bubble bg-primary text-white rounded-2xl rounded-tr-sm px-4 py-3">
|
||||
<p class="text-sm">太棒了,谢谢!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 助手消息 -->
|
||||
<div class="flex justify-start gap-2">
|
||||
<div class="w-8 h-8 bg-gradient-to-br from-primary to-blue-400 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<svg class="w-4 h-4 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="message-bubble bg-white rounded-2xl rounded-tl-sm px-4 py-3 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed">
|
||||
不客气!祝您沟通顺利!如果需要更多帮助,随时问我。😊
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 输入区域 -->
|
||||
<div class="bg-white border-t border-gray-2 p-3 pb-6">
|
||||
<div class="flex items-end gap-2">
|
||||
<div class="flex-1 bg-gray-1 rounded-2xl px-4 py-2.5 flex items-center">
|
||||
<input type="text" placeholder="输入消息..." class="flex-1 bg-transparent text-sm text-gray-13 placeholder-gray-6 outline-none">
|
||||
</div>
|
||||
<button class="voice-btn w-10 h-10 bg-gray-1 rounded-full flex items-center justify-center text-gray-7 transition-colors">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/>
|
||||
<path d="M19 10v2a7 7 0 01-14 0v-2"/>
|
||||
<line x1="12" y1="19" x2="12" y2="23"/>
|
||||
<line x1="8" y1="23" x2="16" y2="23"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="w-10 h-10 bg-primary rounded-full flex items-center justify-center text-white">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,487 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>助教详情 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/coach-detail.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- Banner -->
|
||||
<div class="banner-bg theme-coral texture-aurora relative text-white">
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">助教详情</h1>
|
||||
</div>
|
||||
<div class="px-5 pt-2 pb-5">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-14 h-14 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg overflow-hidden flex-shrink-0">
|
||||
<img src="../img/zjtx.png" class="w-full h-full object-cover" alt="助教头像">
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-lg font-semibold">小燕</span>
|
||||
<span class="px-2 py-0.5 bg-amber-400/30 text-amber-100 rounded-full text-xs">星级</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-white/70 text-xs">
|
||||
<span class="px-2 py-0.5 bg-white/20 rounded">中🎱</span>
|
||||
<span class="px-2 py-0.5 bg-white/20 rounded">🎯 斯诺克</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-shrink-0 text-right space-y-1.5">
|
||||
<div class="text-white/70 text-xs">工龄 <span class="text-white font-bold text-base">3年</span></div>
|
||||
<div class="text-white/70 text-xs">客户 <span class="text-white font-bold text-base">68人</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="p-4 space-y-4">
|
||||
|
||||
<!-- 绩效概览 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="st blue text-base font-semibold text-gray-13 mb-4">绩效概览</h2>
|
||||
<div class="grid grid-cols-2 gap-3 mb-4">
|
||||
<div class="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl p-3 border border-blue-100/50">
|
||||
<p class="text-xs text-gray-6 mb-1">本月定档业绩</p>
|
||||
<p class="text-2xl font-bold text-primary pv">87.5<span class="text-xs font-normal text-gray-6">h</span></p>
|
||||
<p class="text-xs text-gray-5 mt-0.5">折算前 89.0h</p>
|
||||
</div>
|
||||
<div class="bg-gradient-to-br from-green-50 to-emerald-50 rounded-xl p-3 border border-green-100/50">
|
||||
<p class="text-xs text-gray-6 mb-1">本月工资(预估)</p>
|
||||
<p class="text-2xl font-bold text-success pv">¥6,950</p>
|
||||
<p class="text-xs text-warning mt-0.5">含预估部分</p>
|
||||
</div>
|
||||
<div class="bg-gradient-to-br from-orange-50 to-amber-50 rounded-xl p-3 border border-orange-100/50">
|
||||
<p class="text-xs text-gray-6 mb-1">客源储值余额</p>
|
||||
<p class="text-2xl font-bold text-warning pv">¥86,200</p>
|
||||
<p class="text-xs text-gray-5 mt-0.5">68位客户合计</p>
|
||||
</div>
|
||||
<div class="bg-gradient-to-br from-purple-50 to-violet-50 rounded-xl p-3 border border-purple-100/50">
|
||||
<p class="text-xs text-gray-6 mb-1">本月任务完成</p>
|
||||
<p class="text-2xl font-bold text-purple-600 pv">38<span class="text-xs font-normal text-gray-6">个</span></p>
|
||||
<p class="text-xs text-gray-5 mt-0.5">覆盖 22 位客户</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl p-3">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs text-gray-9 font-medium">绩效档位进度</span>
|
||||
<span class="text-xs text-primary font-medium">距下一档还差 12.5h</span>
|
||||
</div>
|
||||
<div class="progress-sm">
|
||||
<div class="fill bg-gradient-to-r from-primary to-blue-400" style="width:72%"></div>
|
||||
</div>
|
||||
<div class="flex justify-between mt-1.5 text-[10px] text-gray-5">
|
||||
<span>当前 80h</span>
|
||||
<span>目标 100h</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 收入明细 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="st green text-base font-semibold text-gray-13">收入明细</h2>
|
||||
<div class="flex items-center gap-1">
|
||||
<span id="incomeTab_this" class="income-tab active" onclick="switchIncomeTab('this')">本月<span class="text-[10px] text-warning ml-0.5">预估</span></span>
|
||||
<span id="incomeTab_last" class="income-tab" onclick="switchIncomeTab('last')">上月</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 本月 -->
|
||||
<div id="incomeThisMonth" class="space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-primary"></span><span class="text-base text-gray-9">基础课时费</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥3,500</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-success"></span><span class="text-base text-gray-9">激励课时费</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥1,800</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-warning"></span><span class="text-base text-gray-9">充值提成</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥1,200</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-purple-500"></span><span class="text-base text-gray-9">酒水提成</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥450</span>
|
||||
</div>
|
||||
<div class="border-t border-gray-100 pt-2 flex items-center justify-between">
|
||||
<span class="text-base font-semibold text-gray-9">合计(预估)</span>
|
||||
<span class="text-base font-bold text-success pv">¥6,950</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 上月 -->
|
||||
<div id="incomeLastMonth" class="space-y-3 hidden">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-primary"></span><span class="text-base text-gray-9">基础课时费</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥3,800</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-success"></span><span class="text-base text-gray-9">激励课时费</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥1,900</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-warning"></span><span class="text-base text-gray-9">充值提成</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥1,100</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-purple-500"></span><span class="text-base text-gray-9">酒水提成</span></div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥400</span>
|
||||
</div>
|
||||
<div class="border-t border-gray-100 pt-2 flex items-center justify-between">
|
||||
<span class="text-base font-semibold text-gray-9">合计</span>
|
||||
<span class="text-base font-bold text-success pv">¥7,200</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务执行 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="st orange text-base font-semibold text-gray-13">任务执行</h2>
|
||||
<div class="flex items-center gap-3 text-sm text-gray-7">
|
||||
<span class="font-bold text-gray-10">完成</span>
|
||||
<span class="text-primary font-bold">召回<span class="text-base">24</span>个</span>
|
||||
<span class="text-success font-bold">回访<span class="text-base">14</span>个</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 前6项任务 -->
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-red-50/60 rounded-lg border border-red-100/60">
|
||||
<span class="task-tag-text high-priority flex-shrink-0">高优先召回</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">王先生</span>
|
||||
<button onclick="showNotesPopup('王先生', [{pinned:true,text:'重点客户,每周必须联系',date:'2026-02-06'},{text:'上次来说最近出差多',date:'2026-02-01'}])" class="flex items-center gap-0.5 text-gray-8 flex-shrink-0"><svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span class="text-xs font-medium">2</span></button>
|
||||
<span class="text-sm flex-shrink-0">📌</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-red-50/60 rounded-lg border border-red-100/60">
|
||||
<span class="task-tag-text high-priority flex-shrink-0">高优先召回</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">李女士</span>
|
||||
<span class="text-sm flex-shrink-0">📌</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-red-50/60 rounded-lg border border-red-100/60">
|
||||
<span class="task-tag-text high-priority flex-shrink-0">高优先召回</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">陈女士</span>
|
||||
<button onclick="showNotesPopup('陈女士', [{text:'喜欢斯诺克,周末常来',date:'2026-01-28'}])" class="flex items-center gap-0.5 text-gray-8 flex-shrink-0"><svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span class="text-xs font-medium">1</span></button>
|
||||
<span class="text-sm flex-shrink-0">📌</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-orange-50/40 rounded-lg border border-orange-100/40">
|
||||
<span class="task-tag-text priority flex-shrink-0">优先召回</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">张先生</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-pink-50/40 rounded-lg border border-pink-100/40">
|
||||
<span class="task-tag-text relationship flex-shrink-0">关系构建</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">赵总</span>
|
||||
<button onclick="showNotesPopup('赵总', [{pinned:true,text:'大客户,注意维护关系',date:'2026-02-03'},{text:'上次带了3个朋友来',date:'2026-01-25'},{text:'喜欢VIP包厢',date:'2026-01-15'}])" class="flex items-center gap-0.5 text-gray-8 flex-shrink-0"><svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg><span class="text-xs font-medium">3</span></button>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-teal-50/40 rounded-lg border border-teal-100/40">
|
||||
<span class="task-tag-text callback flex-shrink-0">客户回访</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">周女士</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 隐藏的更多任务 -->
|
||||
<div id="hiddenTasks" class="space-y-2 mt-2 hidden">
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-orange-50/40 rounded-lg border border-orange-100/40">
|
||||
<span class="task-tag-text priority flex-shrink-0">优先召回</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">刘先生</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-teal-50/40 rounded-lg border border-teal-100/40">
|
||||
<span class="task-tag-text callback flex-shrink-0">客户回访</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">孙先生</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-pink-50/40 rounded-lg border border-pink-100/40">
|
||||
<span class="task-tag-text relationship flex-shrink-0">关系构建</span>
|
||||
<span class="text-sm text-gray-13 flex-1 min-w-0 truncate">吴女士</span>
|
||||
</div>
|
||||
<!-- 已放弃 -->
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-gray-50 rounded-lg border border-gray-200 opacity-55">
|
||||
<span class="text-sm text-gray-5 line-through flex-1 min-w-0 truncate">吴先生</span>
|
||||
<span class="text-[10px] text-gray-5">客户拒绝</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2.5 p-2.5 bg-gray-50 rounded-lg border border-gray-200 opacity-55">
|
||||
<span class="text-sm text-gray-5 line-through flex-1 min-w-0 truncate">郑女士</span>
|
||||
<span class="text-[10px] text-gray-5">超时未响应</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button id="toggleTasksBtn" onclick="toggleAllTasks()" class="text-sm text-primary font-medium">展开全部 ↓</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 客户关系 TOP5 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="st pink text-base font-semibold text-gray-13">客户关系 TOP5</h2>
|
||||
<span class="text-xs text-gray-6">近60天</span>
|
||||
</div>
|
||||
<div class="space-y-2.5">
|
||||
<!-- 客户1 -->
|
||||
<div class="flex items-center gap-3 p-3 bg-gradient-to-r from-pink-50/80 to-rose-50/40 rounded-xl border border-pink-100/40">
|
||||
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center text-white text-xs font-medium flex-shrink-0">王</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="text-sm font-semibold text-gray-13">王先生</span>
|
||||
<span class="text-xs">❤️</span>
|
||||
<span class="text-sm text-success font-bold pv">9.5</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-1 text-xs">
|
||||
<div class="text-gray-6">服务 <span class="text-gray-11 font-semibold">25</span>次</div>
|
||||
<div class="text-gray-6">储值 <span class="text-gray-11 font-semibold">¥8,600</span></div>
|
||||
<div class="text-gray-6">消费 <span class="text-gray-11 font-semibold">¥12,800</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 客户2 -->
|
||||
<div class="flex items-center gap-3 p-3 bg-gradient-to-r from-amber-50/80 to-yellow-50/40 rounded-xl border border-amber-100/40">
|
||||
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center text-white text-xs font-medium flex-shrink-0">李</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="text-sm font-semibold text-gray-13">李女士</span>
|
||||
<span class="text-xs">❤️</span>
|
||||
<span class="text-sm text-success font-bold pv">9.2</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-1 text-xs">
|
||||
<div class="text-gray-6">服务 <span class="text-gray-11 font-semibold">22</span>次</div>
|
||||
<div class="text-gray-6">储值 <span class="text-gray-11 font-semibold">¥6,200</span></div>
|
||||
<div class="text-gray-6">消费 <span class="text-gray-11 font-semibold">¥9,500</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 客户3 -->
|
||||
<div class="flex items-center gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-green-400 to-emerald-500 flex items-center justify-center text-white text-xs font-medium flex-shrink-0">陈</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="text-sm font-semibold text-gray-13">陈女士</span>
|
||||
<span class="text-xs">❤️</span>
|
||||
<span class="text-sm text-warning font-bold pv">8.5</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-1 text-xs">
|
||||
<div class="text-gray-6">服务 <span class="text-gray-11 font-semibold">18</span>次</div>
|
||||
<div class="text-gray-6">储值 <span class="text-gray-11 font-semibold">¥5,000</span></div>
|
||||
<div class="text-gray-6">消费 <span class="text-gray-11 font-semibold">¥7,200</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 客户4 -->
|
||||
<div class="flex items-center gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center text-white text-xs font-medium flex-shrink-0">张</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="text-sm font-semibold text-gray-13">张先生</span>
|
||||
<span class="text-xs">💛</span>
|
||||
<span class="text-sm text-warning font-bold pv">7.8</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-1 text-xs">
|
||||
<div class="text-gray-6">服务 <span class="text-gray-11 font-semibold">12</span>次</div>
|
||||
<div class="text-gray-6">储值 <span class="text-gray-11 font-semibold">¥3,800</span></div>
|
||||
<div class="text-gray-6">消费 <span class="text-gray-11 font-semibold">¥5,600</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 客户5 -->
|
||||
<div class="flex items-center gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="w-9 h-9 rounded-full bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center text-white text-xs font-medium flex-shrink-0">赵</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="text-sm font-semibold text-gray-13">赵先生</span>
|
||||
<span class="text-xs">💛</span>
|
||||
<span class="text-sm text-gray-7 font-bold pv">6.8</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mt-1 text-xs">
|
||||
<div class="text-gray-6">服务 <span class="text-gray-11 font-semibold">8</span>次</div>
|
||||
<div class="text-gray-6">储值 <span class="text-gray-11 font-semibold">¥2,000</span></div>
|
||||
<div class="text-gray-6">消费 <span class="text-gray-11 font-semibold">¥3,200</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 近期服务明细 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="st purple text-base font-semibold text-gray-13 mb-4">近期服务明细</h2>
|
||||
<div class="space-y-3">
|
||||
<!-- 服务记录1 -->
|
||||
<div class="service-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-medium text-gray-13">王先生</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-[10px] rounded">基础课</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-gray-6">2026-02-07 21:30</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 text-xs text-gray-7">
|
||||
<span class="px-2 py-0.5 bg-blue-50 text-primary rounded font-medium">A12号台</span>
|
||||
<span>2.5h</span>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥200</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 服务记录2 -->
|
||||
<div class="service-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-medium text-gray-13">李女士</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-[10px] rounded">激励课</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-gray-6">2026-02-07 19:00</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 text-xs text-gray-7">
|
||||
<span class="px-2 py-0.5 bg-blue-50 text-primary rounded font-medium">VIP1号房</span>
|
||||
<span>1.5h</span>
|
||||
<span class="text-orange-500">定档绩效:2h</span>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥150</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 服务记录3 -->
|
||||
<div class="service-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-medium text-gray-13">陈女士</span>
|
||||
<span class="px-1.5 py-0.5 bg-primary/10 text-primary text-[10px] rounded">基础课</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-gray-6">2026-02-06 20:00</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 text-xs text-gray-7">
|
||||
<span class="px-2 py-0.5 bg-blue-50 text-primary rounded font-medium">2号台</span>
|
||||
<span>2h</span>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥160</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 服务记录4 -->
|
||||
<div class="service-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-medium text-gray-13">张先生</span>
|
||||
<span class="px-1.5 py-0.5 bg-success/10 text-success text-[10px] rounded">激励课</span>
|
||||
</div>
|
||||
<span class="text-[10px] text-gray-6">2026-02-05 14:00</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 text-xs text-gray-7">
|
||||
<span class="px-2 py-0.5 bg-blue-50 text-primary rounded font-medium">5号台</span>
|
||||
<span>1h</span>
|
||||
</div>
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥80</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button onclick="window.location.href='performance-records.html'" class="text-xs text-primary font-medium">查看更多服务记录 →</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 更多信息 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="st teal text-base font-semibold text-gray-13 mb-4">更多信息</h2>
|
||||
<div class="flex items-center justify-between py-2 border-b border-gray-100 mb-4">
|
||||
<span class="text-base text-gray-7">入职日期</span>
|
||||
<span class="text-base text-gray-13">2023-03-15</span>
|
||||
</div>
|
||||
<div class="overflow-x-auto -mx-1">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200">
|
||||
<th class="text-left py-2 px-2 text-gray-7 font-medium text-xs">月份</th>
|
||||
<th class="text-right py-2 px-2 text-gray-7 font-medium text-xs">服务客户</th>
|
||||
<th class="text-right py-2 px-2 text-gray-7 font-medium text-xs">业绩时长</th>
|
||||
<th class="text-right py-2 px-2 text-gray-7 font-medium text-xs">工资</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-b border-gray-50 bg-blue-50/30">
|
||||
<td class="py-2.5 px-2 text-gray-13 font-medium">本月<span class="text-[10px] text-warning ml-1">预估</span></td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv font-medium">22人</td>
|
||||
<td class="py-2.5 px-2 text-right text-primary pv font-bold">87.5h</td>
|
||||
<td class="py-2.5 px-2 text-right text-success pv font-bold">¥6,950</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-50">
|
||||
<td class="py-2.5 px-2 text-gray-13">上月</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">25人</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">92.0h</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">¥7,200</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-50">
|
||||
<td class="py-2.5 px-2 text-gray-13">4月</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">20人</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">85.0h</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">¥6,600</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-50">
|
||||
<td class="py-2.5 px-2 text-gray-13">3月</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">18人</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">78.5h</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">¥6,100</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-2.5 px-2 text-gray-13">2月</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">15人</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">65.0h</td>
|
||||
<td class="py-2.5 px-2 text-right text-gray-13 pv">¥5,200</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="fixed bottom-0 left-0 right-0 h-16 bg-white/95 backdrop-blur-lg border-t border-gray-2 flex items-center gap-3 px-4 z-10">
|
||||
<button onclick="window.location.href='chat.html'" class="flex-1 h-11 bg-gradient-to-r from-primary to-blue-500 text-white font-medium rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-primary/30">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></svg>
|
||||
问问助手
|
||||
</button>
|
||||
<button onclick="showNoteModal()" class="flex-1 h-11 bg-gray-100 text-gray-13 font-medium rounded-xl flex items-center justify-center gap-2">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||
备注
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 备注弹窗 -->
|
||||
<div id="noteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-end">
|
||||
<div class="w-full bg-white rounded-t-3xl p-5 pb-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<span class="text-base font-semibold text-gray-13">添加备注</span>
|
||||
<button onclick="hideNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<textarea id="noteText" class="w-full h-32 p-4 bg-gray-50 rounded-xl resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-primary/20 border border-gray-100" placeholder="请输入备注内容..."></textarea>
|
||||
<button onclick="saveNote()" class="w-full h-12 bg-gradient-to-r from-primary to-blue-500 text-white font-medium rounded-xl mt-4 shadow-lg shadow-primary/30">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast -->
|
||||
<div id="toast" class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-13/80 text-white text-sm px-6 py-3 rounded-xl z-[100] hidden backdrop-blur-sm"></div>
|
||||
|
||||
<!-- 备注列表弹窗 -->
|
||||
<div id="notesPopup" class="fixed inset-0 bg-black/50 z-50 hidden items-end" onclick="if(event.target===this)hideNotesPopup()">
|
||||
<div class="w-full bg-white rounded-t-3xl p-5 pb-8 max-h-[70vh] overflow-y-auto">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<span id="notesPopupTitle" class="text-base font-semibold text-gray-13">备注列表</span>
|
||||
<button onclick="hideNotesPopup()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div id="notesPopupList" class="space-y-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,430 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>客户详情 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body { font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif; padding-bottom: 80px; }
|
||||
.st { position: relative; padding-left: 12px; }
|
||||
.st::before { content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 4px; height: 16px; border-radius: 2px; }
|
||||
.st.blue::before { background: linear-gradient(180deg, #0052d9, #5b9cf8); }
|
||||
.st.green::before { background: linear-gradient(180deg, #00a870, #4cd964); }
|
||||
.st.orange::before { background: linear-gradient(180deg, #ed7b2f, #ffc107); }
|
||||
.st.pink::before { background: linear-gradient(180deg, #e851a4, #f5a0c0); }
|
||||
.pv { font-variant-numeric: tabular-nums; }
|
||||
.orig-price { text-decoration: line-through; color: #a6a6a6; font-size: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- Banner -->
|
||||
<div class="banner-bg theme-dark-gold texture-aurora relative text-white">
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">客户详情</h1>
|
||||
</div>
|
||||
<div class="px-5 pt-2 pb-6">
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg">
|
||||
<span class="text-2xl font-bold text-white">王</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xl font-semibold">王先生</span>
|
||||
<span class="px-2 py-0.5 bg-gradient-to-r from-amber-500 to-yellow-400 text-black font-medium rounded-full text-xs">VIP</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-sm">
|
||||
<span>138****5678</span>
|
||||
<span>VIP20231215</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white/10 rounded-xl backdrop-blur-sm">
|
||||
<div class="grid grid-cols-4">
|
||||
<div class="text-center py-3 border-r border-white/10">
|
||||
<p class="font-medium text-emerald-300 text-sm">¥8,600</p>
|
||||
<p class="text-white/60 text-xs mt-1">储值余额</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-white/10">
|
||||
<p class="font-medium text-sm">¥2,800</p>
|
||||
<p class="text-white/60 text-xs mt-1">60天消费</p>
|
||||
</div>
|
||||
<div class="text-center py-3 border-r border-white/10">
|
||||
<p class="font-medium text-sm">7天</p>
|
||||
<p class="text-white/60 text-xs mt-1">理想间隔</p>
|
||||
</div>
|
||||
<div class="text-center py-3">
|
||||
<p class="font-medium text-amber-300 text-sm">12天</p>
|
||||
<p class="text-white/60 text-xs mt-1">距今到店</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- AI 智能洞察(客户全貌总结) -->
|
||||
<div class="rounded-2xl overflow-hidden shadow-sm">
|
||||
<div class="bg-gradient-to-br from-[#667eea] to-[#764ba2] p-5 text-white">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<div class="w-6 h-6 bg-white/20 rounded-lg flex items-center justify-center">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg>
|
||||
</div>
|
||||
<span class="text-sm font-medium text-white/90">AI 智能洞察</span>
|
||||
</div>
|
||||
<!-- 客户画像总结 -->
|
||||
<p class="text-sm text-white/90 leading-relaxed mb-3">高价值 VIP 客户,月均到店 4-5 次,偏好夜场中式台球,近期对斯诺克产生兴趣。社交属性强,常带固定球搭子,有拉新能力。储值余额充足,对促销活动响应积极。</p>
|
||||
<!-- 营销策略建议 -->
|
||||
<div class="bg-white/10 rounded-xl p-3 backdrop-blur-sm">
|
||||
<p class="text-xs text-white/60 mb-2">📋 当前推荐策略</p>
|
||||
<div class="space-y-1.5">
|
||||
<div class="flex items-start gap-2">
|
||||
<span class="shrink-0 w-1.5 h-1.5 bg-emerald-300 rounded-full mt-1.5"></span>
|
||||
<p class="text-xs text-white/85 leading-relaxed">最后到店距今 12 天,超出理想间隔 7 天,建议尽快安排助教小燕主动联系召回</p>
|
||||
</div>
|
||||
<div class="flex items-start gap-2">
|
||||
<span class="shrink-0 w-1.5 h-1.5 bg-amber-300 rounded-full mt-1.5"></span>
|
||||
<p class="text-xs text-white/85 leading-relaxed">客户提到想练斯诺克走位,可推荐斯诺克专项课程包,结合储值优惠提升客单价</p>
|
||||
</div>
|
||||
<div class="flex items-start gap-2">
|
||||
<span class="shrink-0 w-1.5 h-1.5 bg-pink-300 rounded-full mt-1.5"></span>
|
||||
<p class="text-xs text-white/85 leading-relaxed">社交属性强,可邀请参加门店球友赛事活动,带动球搭子到店消费</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 维客线索 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="st green text-sm font-semibold text-gray-13">维客线索</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<!-- 线索列表 -->
|
||||
<div class="space-y-2.5">
|
||||
<!-- 客户基础 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-primary/10 text-primary text-[11px] font-medium rounded-sm leading-normal tracking-wide">客户<br>基础</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎂 生日 3月15日 · VIP会员 · 注册2年</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 消费习惯 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🌙 常来夜场 · 月均4-5次</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💰 高客单价</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">近60天场均消费 ¥420,高于门店均值 ¥180;偏好夜场时段,酒水附加消费占比 35%</p>
|
||||
</div>
|
||||
<!-- 玩法偏好 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 偏爱中式 · 斯诺克进阶中</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 促销接受 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-warning/10 text-warning text-[11px] font-medium rounded-sm leading-normal tracking-wide">促销<br>接受</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🍷 爱点酒水套餐 · 对储值活动敏感</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">最近3次到店均点了酒水套餐;上次 ¥5000 储值活动当天即充值,对满赠类活动响应率高</p>
|
||||
</div>
|
||||
<!-- 社交关系 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-pink-500/10 text-pink-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">社交<br>关系</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">👥 常带朋友 · 固定球搭子2人</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">近60天 80% 的到店为多人局,常与「李哥」「阿杰」同行;曾介绍2位新客办卡</p>
|
||||
</div>
|
||||
<!-- 重要反馈 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">⚠️ 上次提到想练斯诺克走位,对球桌维护质量比较在意,建议优先安排VIP房</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 助教任务 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="st blue text-sm font-semibold text-gray-13">助教任务</h2>
|
||||
<span class="text-xs text-gray-6">当前进行中</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<!-- 小燕 - 高优先召回 -->
|
||||
<div class="p-3 bg-gradient-to-br from-red-50/80 to-rose-50/60 rounded-xl border border-red-100/60">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-semibold text-gray-13">小燕</span>
|
||||
<span class="px-2 py-0.5 bg-pink-100 text-pink-700 text-xs rounded-full font-medium">高级助教</span>
|
||||
</div>
|
||||
<span class="px-2 py-0.5 bg-red-100 text-red-700 text-xs rounded-full font-medium">高优先召回</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-xs text-gray-7 mb-2">
|
||||
<span>上次服务:02-20 21:30 · 2.5h</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="bg-white/80 rounded-lg py-1.5 text-center"><p class="text-[10px] text-gray-6 mb-0.5">近60天次数</p><p class="text-sm font-bold text-primary">18次</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-1.5 text-center"><p class="text-[10px] text-gray-6 mb-0.5">总时长</p><p class="text-sm font-bold text-gray-13">17h</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-1.5 text-center"><p class="text-[10px] text-gray-6 mb-0.5">次均时长</p><p class="text-sm font-bold text-warning">0.9h</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 泡芙 - 关系构建 -->
|
||||
<div class="p-3 bg-gradient-to-br from-pink-50/80 to-fuchsia-50/60 rounded-xl border border-pink-100/60">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-semibold text-gray-13">泡芙</span>
|
||||
<span class="px-2 py-0.5 bg-purple-100 text-purple-700 text-xs rounded-full font-medium">中级助教</span>
|
||||
</div>
|
||||
<span class="px-2 py-0.5 bg-pink-100 text-pink-700 text-xs rounded-full font-medium">关系构建</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-xs text-gray-7 mb-2">
|
||||
<span>上次服务:02-15 14:00 · 1.5h</span>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-2">
|
||||
<div class="bg-white/80 rounded-lg py-1.5 text-center"><p class="text-[10px] text-gray-6 mb-0.5">近60天次数</p><p class="text-sm font-bold text-primary">12次</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-1.5 text-center"><p class="text-[10px] text-gray-6 mb-0.5">总时长</p><p class="text-sm font-bold text-gray-13">11h</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-1.5 text-center"><p class="text-[10px] text-gray-6 mb-0.5">次均时长</p><p class="text-sm font-bold text-warning">0.9h</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最喜欢的助教 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="st pink text-sm font-semibold text-gray-13">最喜欢的助教</h2>
|
||||
<span class="text-xs text-gray-6">近60天</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<div class="p-4 bg-gradient-to-br from-pink-50/80 to-rose-50/60 rounded-xl border border-pink-100/60">
|
||||
<div class="flex items-center justify-between mb-2.5">
|
||||
<div class="flex items-center gap-2.5"><span class="text-lg">❤️</span><span class="text-sm font-semibold text-gray-13">小燕</span></div>
|
||||
<div class="flex items-center gap-1.5"><span class="text-xs text-gray-7">关系指数</span><span class="text-lg font-bold text-success">0.92</span></div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mb-1.5 pl-0.5">近60天</p>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">基础</p><p class="text-base font-bold text-primary">12h</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">激励</p><p class="text-base font-bold text-warning">5h</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">上课</p><p class="text-base font-bold text-gray-13">18次</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">充值</p><p class="text-base font-bold text-success">¥5,000</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 bg-gradient-to-br from-amber-50/80 to-yellow-50/60 rounded-xl border border-amber-100/60">
|
||||
<div class="flex items-center justify-between mb-2.5">
|
||||
<div class="flex items-center gap-2.5"><span class="text-lg">💛</span><span class="text-sm font-semibold text-gray-13">泡芙</span></div>
|
||||
<div class="flex items-center gap-1.5"><span class="text-xs text-gray-7">关系指数</span><span class="text-lg font-bold text-warning">0.78</span></div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mb-1.5 pl-0.5">近60天</p>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">基础</p><p class="text-base font-bold text-primary">8h</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">激励</p><p class="text-base font-bold text-warning">3h</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">上课</p><p class="text-base font-bold text-gray-13">12次</p></div>
|
||||
<div class="bg-white/80 rounded-lg py-2 text-center"><p class="text-xs text-gray-7 mb-0.5">充值</p><p class="text-base font-bold text-success">¥3,000</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 消费记录(放在最下方) -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="st orange text-sm font-semibold text-gray-13 mb-4">消费记录</h2>
|
||||
<div class="space-y-4">
|
||||
|
||||
<!-- 台桌详情 Record 1:有团购折扣,2位助教,有食品酒水 -->
|
||||
<div class="rounded-xl border border-gray-200 overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-blue-50 to-indigo-50 px-4 py-2 flex items-center justify-between border-b border-blue-100/50">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-1.5 h-1.5 bg-primary rounded-full"></span>
|
||||
<span class="text-sm font-semibold text-primary">A12号台</span>
|
||||
</div>
|
||||
<span class="text-sm text-gray-8">2026-02-05</span>
|
||||
</div>
|
||||
<!-- 时间信息:紧凑一行 -->
|
||||
<div class="px-4 py-2.5 border-b border-gray-100 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 text-base">
|
||||
<span class="text-gray-13 font-medium pv">21:30</span>
|
||||
<span class="text-gray-7">→</span>
|
||||
<span class="text-gray-13 font-medium pv">00:50</span>
|
||||
<span class="px-2 py-0.5 bg-primary/10 text-primary text-xs rounded-full font-medium">3h20min</span>
|
||||
</div>
|
||||
<!-- 台费(有团购折扣) -->
|
||||
<div class="text-right flex-shrink-0">
|
||||
<span class="text-base font-bold text-gray-13 pv">¥180</span>
|
||||
<span class="orig-price ml-1">¥240</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 助教列表:一行2个卡片 -->
|
||||
<div class="px-4 py-3">
|
||||
<div class="grid grid-cols-2 gap-2 mb-3">
|
||||
<!-- 助教卡片1:小燕 -->
|
||||
<div class="bg-gray-50 rounded-lg p-2.5">
|
||||
<div class="flex items-center gap-1 mb-0.5">
|
||||
<span class="text-sm font-medium text-gray-13">小燕</span>
|
||||
<span class="px-1 py-px bg-pink-50 text-pink-600 text-[10px] rounded">高级</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-8">基础课 · 2.5h</div>
|
||||
<div class="text-right mt-0.5">
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥200</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 助教卡片2:Amy -->
|
||||
<div class="bg-gray-50 rounded-lg p-2.5">
|
||||
<div class="flex items-center gap-1 mb-0.5">
|
||||
<span class="text-sm font-medium text-gray-13">Amy</span>
|
||||
<span class="px-1 py-px bg-green-50 text-green-600 text-[10px] rounded">初级</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-8">激励课 · 0.5h</div>
|
||||
<div class="flex items-center justify-between mt-0.5">
|
||||
<span class="text-xs text-orange-500">定档绩效:1h</span>
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥50</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 食品酒水 -->
|
||||
<div class="flex items-center justify-between py-2 border-t border-gray-100">
|
||||
<span class="text-sm text-gray-8">🍷 食品酒水</span>
|
||||
<div class="text-right">
|
||||
<span class="text-base font-medium text-warning pv">¥210</span>
|
||||
<span class="orig-price ml-1">¥260</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 总金额 -->
|
||||
<div class="flex items-center justify-between pt-2 border-t border-gray-200">
|
||||
<span class="text-sm font-semibold text-gray-9">总金额</span>
|
||||
<div class="text-right">
|
||||
<span class="text-lg font-bold text-error pv">¥640</span>
|
||||
<span class="orig-price ml-1">¥750</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 台桌详情 Record 2:无食品酒水,有定档绩效,无折扣 -->
|
||||
<div class="rounded-xl border border-gray-200 overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-blue-50 to-indigo-50 px-4 py-2 flex items-center justify-between border-b border-blue-100/50">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-1.5 h-1.5 bg-primary rounded-full"></span>
|
||||
<span class="text-sm font-semibold text-primary">888号台</span>
|
||||
</div>
|
||||
<span class="text-sm text-gray-8">2026-02-01</span>
|
||||
</div>
|
||||
<div class="px-4 py-2.5 border-b border-gray-100 flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 text-base">
|
||||
<span class="text-gray-13 font-medium pv">14:00</span>
|
||||
<span class="text-gray-7">→</span>
|
||||
<span class="text-gray-13 font-medium pv">16:00</span>
|
||||
<span class="px-2 py-0.5 bg-primary/10 text-primary text-xs rounded-full font-medium">2h00min</span>
|
||||
</div>
|
||||
<span class="text-base font-bold text-gray-13 pv">¥120</span>
|
||||
</div>
|
||||
<div class="px-4 py-3">
|
||||
<div class="grid grid-cols-2 gap-2 mb-3">
|
||||
<div class="bg-gray-50 rounded-lg p-2.5">
|
||||
<div class="flex items-center gap-1 mb-0.5">
|
||||
<span class="text-sm font-medium text-gray-13">泡芙</span>
|
||||
<span class="px-1 py-px bg-purple-50 text-purple-600 text-[10px] rounded">中级</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-8">激励课 · 1.5h</div>
|
||||
<div class="flex items-center justify-between mt-0.5">
|
||||
<span class="text-xs text-orange-500">定档绩效:2h</span>
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥100</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 总金额(无食品酒水,不展示该行) -->
|
||||
<div class="flex items-center justify-between pt-2 border-t border-gray-200">
|
||||
<span class="text-sm font-semibold text-gray-9">总金额</span>
|
||||
<span class="text-lg font-bold text-error pv">¥220</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 商城订单 Record 3:有食品酒水 -->
|
||||
<div class="rounded-xl border border-gray-200 overflow-hidden">
|
||||
<div class="bg-gradient-to-r from-emerald-50 to-green-50 px-4 py-2 flex items-center justify-between border-b border-green-100/50">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-1.5 h-1.5 bg-success rounded-full"></span>
|
||||
<span class="text-sm font-semibold text-success">商城订单</span>
|
||||
</div>
|
||||
<span class="text-sm text-gray-8">2026-01-28</span>
|
||||
</div>
|
||||
<div class="px-4 py-3 space-y-2.5">
|
||||
<!-- 助教卡片列表:同台桌详情风格 -->
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="bg-gray-50 rounded-lg p-2.5">
|
||||
<div class="flex items-center gap-1 mb-0.5">
|
||||
<span class="text-sm font-medium text-gray-13">小燕</span>
|
||||
<span class="px-1 py-px bg-pink-50 text-pink-600 text-[10px] rounded">高级</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-8">基础课 · 1h</div>
|
||||
<div class="text-right mt-0.5">
|
||||
<span class="text-sm font-bold text-gray-13 pv">¥100</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 食品酒水 -->
|
||||
<div class="flex items-center justify-between pt-2 border-t border-gray-100">
|
||||
<span class="text-sm text-gray-8">🍷 食品酒水</span>
|
||||
<span class="text-base font-medium text-warning pv">¥180</span>
|
||||
</div>
|
||||
<!-- 总金额 -->
|
||||
<div class="flex items-center justify-between pt-2 border-t border-gray-200">
|
||||
<span class="text-sm font-semibold text-gray-9">总金额</span>
|
||||
<span class="text-lg font-bold text-error pv">¥280</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="fixed bottom-0 left-0 right-0 h-16 bg-white/95 backdrop-blur-lg border-t border-gray-2 flex items-center gap-3 px-4">
|
||||
<button onclick="window.location.href='chat.html'" class="flex-1 h-11 bg-gradient-to-r from-primary to-blue-500 text-white font-medium rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-primary/30">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></svg>
|
||||
问问助手
|
||||
</button>
|
||||
<button class="flex-1 h-11 bg-gray-100 text-gray-13 font-medium rounded-xl flex items-center justify-center gap-2">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||
备注
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,186 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>服务记录 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/customer-service-records.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen pb-8">
|
||||
<!-- Banner -->
|
||||
<div class="banner-bg theme-coral texture-aurora relative text-white">
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">服务记录</h1>
|
||||
</div>
|
||||
<div class="px-5 pt-1 pb-5">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center text-white text-lg font-semibold shadow-lg flex-shrink-0">王</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-lg font-semibold">王先生</span>
|
||||
<span class="text-xs text-white/50">139****5678</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-xs">
|
||||
<span>累计服务 <span class="text-white font-bold text-sm">28</span> 次</span>
|
||||
<span>关系指数 <span class="text-white font-bold text-sm">0.85</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 月份切换 -->
|
||||
<div class="bg-white px-4 py-3 border-b border-gray-2 flex items-center justify-center gap-6">
|
||||
<button id="prevMonthBtn" onclick="switchMonth('prev')" class="p-1.5 rounded-full hover:bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<span id="monthLabel" class="text-sm font-semibold text-gray-13">2026年2月</span>
|
||||
<button id="nextMonthBtn" onclick="switchMonth('next')" class="p-1.5 rounded-full hover:bg-gray-100 opacity-30" disabled>
|
||||
<svg class="w-4 h-4 text-gray-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 6 15 12 9 18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 月度统计概览 -->
|
||||
<div class="px-4 py-3 bg-white border-b border-gray-2">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="text-center flex-1">
|
||||
<p class="text-[10px] text-gray-6 mb-0.5">本月服务</p>
|
||||
<p class="text-lg font-bold text-gray-13 tabnum" id="monthCount">6次</p>
|
||||
</div>
|
||||
<div class="w-px h-10 bg-gray-2 mt-0.5"></div>
|
||||
<div class="text-center flex-1">
|
||||
<p class="text-[10px] text-gray-6 mb-0.5">服务时长</p>
|
||||
<p class="text-lg font-bold text-primary tabnum" id="monthHours">11.5h</p>
|
||||
</div>
|
||||
<div class="w-px h-10 bg-gray-2 mt-0.5"></div>
|
||||
<div class="text-center flex-1">
|
||||
<p class="text-[10px] text-gray-6 mb-0.5">关系指数</p>
|
||||
<p class="text-lg font-bold text-warning tabnum" id="monthDrinks">0.85</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 记录列表 -->
|
||||
<div class="p-4">
|
||||
<div id="recordsList" class="space-y-3">
|
||||
<!-- 2月7日 -->
|
||||
<div class="record-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="record-date">2月7日</span>
|
||||
<span class="record-time">20:00 - 22:30</span>
|
||||
</div>
|
||||
<span class="record-duration">2.5h</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="record-table">A12号台</span>
|
||||
<span class="record-type type-basic">基础课</span>
|
||||
<span class="record-income">¥200</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2月5日 -->
|
||||
<div class="record-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="record-date">2月5日</span>
|
||||
<span class="record-time">15:00 - 17:00</span>
|
||||
</div>
|
||||
<span class="record-duration">2.0h</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="record-table">3号台</span>
|
||||
<span class="record-type type-basic">基础课</span>
|
||||
<span class="record-income">¥160</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2月3日 -->
|
||||
<div class="record-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="record-date">2月3日</span>
|
||||
<span class="record-time">19:30 - 21:30</span>
|
||||
</div>
|
||||
<span class="record-duration">2.0h</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="record-table">VIP1号房</span>
|
||||
<span class="record-type type-vip">包厢课</span>
|
||||
<span class="record-income">¥190</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2月1日 -->
|
||||
<div class="record-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="record-date">2月1日</span>
|
||||
<span class="record-time">20:30 - 22:30</span>
|
||||
</div>
|
||||
<span class="record-duration">2.0h</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="record-table">5号台</span>
|
||||
<span class="record-type type-basic">基础课</span>
|
||||
<span class="record-income">¥160</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 1月28日 -->
|
||||
<div class="record-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="record-date">1月28日</span>
|
||||
<span class="record-time">19:00 - 21:00</span>
|
||||
</div>
|
||||
<span class="record-duration">2.0h</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="record-table">VIP2号房</span>
|
||||
<span class="record-type type-vip">包厢课</span>
|
||||
<span class="record-income">¥190</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 1月22日 -->
|
||||
<div class="record-card">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="record-date">1月22日</span>
|
||||
<span class="record-time">14:00 - 15:00</span>
|
||||
</div>
|
||||
<span class="record-duration">1.0h</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="record-table">8号台</span>
|
||||
<span class="record-type type-tip">打赏课</span>
|
||||
<span class="record-income">¥80</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center py-3">
|
||||
<p class="text-[10px] text-gray-5">— 已加载全部记录 —</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 悬浮助手按钮 -->
|
||||
|
||||
|
||||
<!-- 月份切换交互 -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,104 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>首页设置 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
.radio-checked {
|
||||
border-color: #0052d9;
|
||||
background: #0052d9;
|
||||
}
|
||||
.radio-checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.option-card {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.option-card.selected {
|
||||
border-color: #0052d9;
|
||||
background: linear-gradient(135deg, #ecf2fe 0%, #f8faff 100%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-10">
|
||||
<div class="h-11 flex items-center relative border-b border-gray-2 px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-gray-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium text-gray-13">首页设置</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 说明文字 -->
|
||||
<div class="px-4 py-4">
|
||||
<p class="text-sm text-gray-7">选择登录后默认显示的首页</p>
|
||||
</div>
|
||||
|
||||
<!-- 选项列表 -->
|
||||
<div class="px-4 space-y-3">
|
||||
<div id="option-task" class="option-card bg-white rounded-2xl p-4 border-2 border-transparent cursor-pointer selected" onclick="selectHome('task')">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-primary to-blue-400 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<svg class="w-6 h-6 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-base font-medium text-gray-13 mb-1">任务</p>
|
||||
<p class="text-xs text-gray-6">查看待办任务和业绩概览</p>
|
||||
</div>
|
||||
<div id="radio-task" class="w-5 h-5 border-2 border-gray-4 rounded-full relative radio-checked"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="option-board" class="option-card bg-white rounded-2xl p-4 border-2 border-transparent cursor-pointer" onclick="selectHome('board')">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-success to-green-400 rounded-xl flex items-center justify-center shadow-sm">
|
||||
<svg class="w-6 h-6 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-base font-medium text-gray-13 mb-1">看板</p>
|
||||
<p class="text-xs text-gray-6">查看财务、客户、助教数据</p>
|
||||
</div>
|
||||
<div id="radio-board" class="w-5 h-5 border-2 border-gray-4 rounded-full relative"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<div class="px-4 py-6">
|
||||
<div class="flex items-start gap-3 p-4 bg-primary/5 rounded-xl">
|
||||
<svg class="w-5 h-5 text-primary flex-shrink-0 mt-0.5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
|
||||
</svg>
|
||||
<p class="text-xs text-gray-7 leading-relaxed">设置会自动保存,切换选项后即刻生效。退出登录后重新登录仍会保持您的设置。</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,145 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>登录 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.bg-gradient-main {
|
||||
background: linear-gradient(135deg, #e0f2fe 0%, #f0f9ff 50%, #ecfeff 100%);
|
||||
}
|
||||
.checkbox-custom {
|
||||
position: relative;
|
||||
}
|
||||
.checkbox-custom:checked {
|
||||
background-color: #0052d9;
|
||||
border-color: #0052d9;
|
||||
}
|
||||
.checkbox-custom:checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 1px;
|
||||
width: 5px;
|
||||
height: 9px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.btn-disabled {
|
||||
background-color: #dcdcdc !important;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-8px); }
|
||||
}
|
||||
.float-animation {
|
||||
animation: float 4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse-soft {
|
||||
0%, 100% { opacity: 0.4; }
|
||||
50% { opacity: 0.8; }
|
||||
}
|
||||
.pulse-soft {
|
||||
animation: pulse-soft 3s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-main min-h-screen flex flex-col">
|
||||
<!-- 装饰元素 -->
|
||||
<div class="absolute top-20 left-8 w-16 h-16 bg-primary/10 rounded-full blur-xl pulse-soft"></div>
|
||||
<div class="absolute top-40 right-6 w-20 h-20 bg-cyan-400/10 rounded-full blur-xl pulse-soft" style="animation-delay: 1s;"></div>
|
||||
<div class="absolute bottom-40 left-12 w-12 h-12 bg-blue-400/10 rounded-full blur-xl pulse-soft" style="animation-delay: 0.5s;"></div>
|
||||
|
||||
<!-- 顶部区域 - Logo 和名称 -->
|
||||
<div class="flex-1 flex flex-col items-center justify-center px-8 relative z-10">
|
||||
<!-- Logo -->
|
||||
<div class="relative mb-6 float-animation">
|
||||
<div class="w-24 h-24 bg-gradient-to-br from-primary to-blue-400 rounded-3xl flex items-center justify-center shadow-xl shadow-primary/30">
|
||||
<svg class="w-14 h-14 text-white" viewBox="0 0 24 24" fill="currentColor">
|
||||
<circle cx="12" cy="12" r="10" fill="currentColor" opacity="0.3"/>
|
||||
<circle cx="12" cy="12" r="6" fill="currentColor"/>
|
||||
<circle cx="12" cy="12" r="2" fill="white"/>
|
||||
</svg>
|
||||
</div>
|
||||
<!-- 装饰点 -->
|
||||
<div class="absolute -top-1 -right-1 w-4 h-4 bg-cyan-400 rounded-full shadow-lg"></div>
|
||||
<div class="absolute -bottom-2 -left-2 w-3 h-3 bg-blue-300 rounded-full shadow-lg"></div>
|
||||
</div>
|
||||
|
||||
<!-- 应用名称 -->
|
||||
<h1 class="text-2xl font-bold text-gray-13 mb-2">球房运营助手</h1>
|
||||
|
||||
<!-- 产品描述 -->
|
||||
<p class="text-gray-7 text-sm text-center leading-relaxed mb-8">
|
||||
为台球厅提升运营效率的内部管理工具
|
||||
</p>
|
||||
|
||||
<!-- 功能亮点 -->
|
||||
<div class="w-full max-w-sm bg-white/60 backdrop-blur-sm rounded-2xl p-5 mb-6">
|
||||
<div class="grid grid-cols-3 gap-4 text-center">
|
||||
<div>
|
||||
<div class="w-10 h-10 bg-primary/10 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-5 h-5 text-primary" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-xs text-gray-9 font-medium">任务管理</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="w-10 h-10 bg-success/10 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-5 h-5 text-success" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-xs text-gray-9 font-medium">数据看板</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="w-10 h-10 bg-warning/10 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-xs text-gray-9 font-medium">智能助手</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部区域 - 登录按钮和协议 -->
|
||||
<div class="px-8 pb-10 relative z-10">
|
||||
<!-- 微信登录按钮 -->
|
||||
<button id="loginBtn" class="btn-disabled w-full py-4 rounded-xl text-white font-medium text-base flex items-center justify-center gap-2 transition-all duration-200 shadow-lg">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.32.32 0 0 0 .165-.054l1.9-1.106a.96.96 0 0 1 .465-.116.94.94 0 0 1 .272.04 10.6 10.6 0 0 0 2.822.384c.136 0 .271-.002.405-.009a6.9 6.9 0 0 1-.315-2.053c0-3.694 3.614-6.69 8.076-6.69.233 0 .463.01.691.027C16.964 4.837 13.132 2.188 8.691 2.188zm-2.97 5.28a1.03 1.03 0 1 1 0-2.06 1.03 1.03 0 0 1 0 2.06zm5.96 0a1.03 1.03 0 1 1 0-2.06 1.03 1.03 0 0 1 0 2.06zM24 14.2c0-3.355-3.4-6.08-7.59-6.08s-7.59 2.725-7.59 6.08c0 3.356 3.4 6.08 7.59 6.08.772 0 1.515-.094 2.215-.268a.77.77 0 0 1 .224-.033.79.79 0 0 1 .382.095l1.565.912a.26.26 0 0 0 .135.044c.13 0 .238-.108.238-.242 0-.06-.024-.117-.04-.175l-.32-1.218a.48.48 0 0 1 .175-.547C22.95 17.89 24 16.165 24 14.2zm-10.14-.426a.85.85 0 1 1 0-1.7.85.85 0 0 1 0 1.7zm5.1 0a.85.85 0 1 1 0-1.7.85.85 0 0 1 0 1.7z"/>
|
||||
</svg>
|
||||
使用微信登录
|
||||
</button>
|
||||
|
||||
<!-- 协议勾选 -->
|
||||
<div class="flex items-start gap-3 mt-5">
|
||||
<input type="checkbox" id="agreeCheckbox" class="checkbox-custom w-4 h-4 mt-0.5 border-2 border-gray-4 rounded appearance-none cursor-pointer transition-all duration-200 flex-shrink-0">
|
||||
<label for="agreeCheckbox" class="text-xs text-gray-7 leading-relaxed cursor-pointer">
|
||||
我已阅读并同意
|
||||
<a href="#" class="text-primary font-medium">《用户协议》</a>
|
||||
和
|
||||
<a href="#" class="text-primary font-medium">《隐私政策》</a>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- 底部说明 -->
|
||||
<p class="text-xs text-gray-5 text-center mt-6">
|
||||
仅限球房内部员工使用
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,113 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>我的 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
.safe-area-top {
|
||||
padding-top: env(safe-area-inset-top, 44px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white">
|
||||
<div class="h-11 flex items-center justify-center relative border-b border-gray-2">
|
||||
<h1 class="text-base font-medium text-gray-13">我的</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户信息区域 -->
|
||||
<div class="bg-white p-6 flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-full overflow-hidden shadow-lg">
|
||||
<img src="../img/zjtx.png" class="w-full h-full object-cover" alt="助教头像">
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-lg font-semibold text-gray-13">小燕</span>
|
||||
<span class="px-2 py-0.5 bg-primary/10 text-primary text-xs rounded">助教</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7">广州朗朗桌球</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 菜单列表 -->
|
||||
<div class="mt-4">
|
||||
<a href="notes.html" class="flex items-center justify-between bg-white px-4 py-4 border-b border-gray-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-primary/10 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-sm text-gray-13">备注记录</span>
|
||||
</div>
|
||||
<svg class="w-4 h-4 text-gray-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<a href="chat-history.html" class="flex items-center justify-between bg-white px-4 py-4 border-b border-gray-1">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-success/10 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-success" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-sm text-gray-13">助手对话记录</span>
|
||||
</div>
|
||||
<svg class="w-4 h-4 text-gray-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<button onclick="showLogoutModal()" class="w-full flex items-center justify-between bg-white px-4 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 bg-error/10 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-error" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/>
|
||||
<polyline points="16 17 21 12 16 7"/>
|
||||
<line x1="21" y1="12" x2="9" y2="12"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-sm text-gray-13">退出账号</span>
|
||||
</div>
|
||||
<svg class="w-4 h-4 text-gray-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 退出确认弹窗 -->
|
||||
<div id="logoutModal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center">
|
||||
<div class="bg-white rounded-2xl w-72 overflow-hidden">
|
||||
<div class="p-6 text-center">
|
||||
<h3 class="text-base font-medium text-gray-13 mb-2">确认退出</h3>
|
||||
<p class="text-sm text-gray-7">确认退出当前账号吗?</p>
|
||||
</div>
|
||||
<div class="flex border-t border-gray-2">
|
||||
<button onclick="hideLogoutModal()" class="flex-1 py-3 text-sm text-gray-7 border-r border-gray-2">取消</button>
|
||||
<button onclick="logout()" class="flex-1 py-3 text-sm text-error font-medium">退出</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 悬浮助手按钮 -->
|
||||
|
||||
|
||||
<!-- 通用底部导航 -->
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>无权限 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.bg-pattern {
|
||||
background-color: #f8fafc;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23e34d59' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: rotate(0deg); }
|
||||
25% { transform: rotate(-5deg); }
|
||||
75% { transform: rotate(5deg); }
|
||||
}
|
||||
.shake-animation {
|
||||
animation: shake 0.5s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-pattern min-h-screen flex flex-col">
|
||||
<!-- 顶部装饰 -->
|
||||
<div class="absolute top-0 left-0 right-0 h-64 bg-gradient-to-b from-error/10 to-transparent"></div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="flex-1 flex flex-col items-center justify-center px-8 relative z-10">
|
||||
<!-- 图标区域 -->
|
||||
<div class="relative mb-8">
|
||||
<!-- 背景光晕 -->
|
||||
<div class="absolute inset-0 w-32 h-32 bg-error/20 rounded-full blur-xl"></div>
|
||||
|
||||
<!-- 主图标 -->
|
||||
<div class="relative w-28 h-28 bg-gradient-to-br from-rose-400 to-red-500 rounded-3xl flex items-center justify-center shadow-xl shadow-error/30">
|
||||
<svg class="w-14 h-14 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<line x1="4.93" y1="4.93" x2="19.07" y2="19.07"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 装饰点 -->
|
||||
<div class="absolute -top-2 -right-2 w-4 h-4 bg-error rounded-full opacity-60"></div>
|
||||
<div class="absolute -bottom-1 -left-3 w-3 h-3 bg-rose-300 rounded-full opacity-60"></div>
|
||||
</div>
|
||||
|
||||
<!-- 文字区域 -->
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-2xl font-bold text-gray-10 mb-3">无访问权限</h1>
|
||||
<p class="text-sm text-gray-7 leading-relaxed max-w-xs mx-auto">
|
||||
很抱歉,您的访问申请未通过审核,或当前账号无访问权限
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 原因说明卡片 -->
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-lg shadow-gray-200/50 mb-6">
|
||||
<div class="flex items-start gap-4 mb-4">
|
||||
<div class="w-10 h-10 bg-error/10 rounded-xl flex items-center justify-center flex-shrink-0">
|
||||
<svg class="w-5 h-5 text-error" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium text-gray-13 mb-1">可能的原因</p>
|
||||
<ul class="text-xs text-gray-6 space-y-1">
|
||||
<li>• 申请信息不完整或不符合要求</li>
|
||||
<li>• 非本店授权员工账号</li>
|
||||
<li>• 账号权限已被管理员收回</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-4 border-t border-gray-100">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-xs text-gray-6">请联系管理员</span>
|
||||
<span class="text-sm text-gray-13 font-medium">厉超</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 帮助提示 -->
|
||||
<div class="flex items-center gap-2 text-gray-6 mb-8">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/>
|
||||
</svg>
|
||||
<span class="text-xs">如有疑问,请联系管理员重新申请</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="px-8 pb-12">
|
||||
<button onclick="switchAccount()" class="w-full py-3.5 bg-white border border-gray-200 rounded-xl text-gray-9 font-medium text-sm flex items-center justify-center gap-2 shadow-sm">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/>
|
||||
<polyline points="16 17 21 12 16 7"/>
|
||||
<line x1="21" y1="12" x2="9" y2="12"/>
|
||||
</svg>
|
||||
更换登录账号
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,139 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>备注 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/notes.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部导航 -->
|
||||
<div class="safe-area-top bg-white sticky top-0 z-10">
|
||||
<div class="h-11 flex items-center relative border-b border-gray-2 px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-gray-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium text-gray-13">备注</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 备注列表(按时间由近及远) -->
|
||||
<div class="p-4 space-y-3">
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
小燕本月表现优秀,课时完成率达到120%,客户评价全部5星。建议下月提升课时费标准,同时安排更多VIP客户给她。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-coach">助教:小燕</span>
|
||||
<span class="text-xs text-gray-6">2024-11-27 16:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
客户今天表示下周有朋友生日聚会,想预约包厢。已告知包厢需要提前3天预约,客户说会尽快确定时间再联系。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:王先生</span>
|
||||
<span class="text-xs text-gray-6">2024-11-27 15:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
完成高优先召回任务。客户反馈最近工作太忙,这周末会来店里。已提醒客户储值卡还有2000元余额,下月到期需要续费。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:王先生</span>
|
||||
<span class="text-xs text-gray-6">2024-11-26 18:45</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
Amy最近工作状态很好,主动承担了培训新员工的任务。但需要注意她最近加班较多,避免过度疲劳。建议适当调整排班。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-coach">助教:Amy</span>
|
||||
<span class="text-xs text-gray-6">2024-11-26 11:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
泡芙本月表现优秀,课时完成率达到120%,客户评价全部5星。建议下月提升课时费标准。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:陈女士</span>
|
||||
<span class="text-xs text-gray-6">2024-11-25 10:20</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
泡芙的斯诺克教学水平有明显提升,最近几位客户反馈都很好。可以考虑让她带更多斯诺克方向的课程。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-coach">助教:泡芙</span>
|
||||
<span class="text-xs text-gray-6">2024-11-25 14:20</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
客户对今天的服务非常满意,特别提到小燕的教学很专业。客户表示会推荐朋友来店里体验。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:李女士</span>
|
||||
<span class="text-xs text-gray-6">2024-11-24 21:15</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
小燕反馈近期有几位客户希望增加晚间时段的课程,建议协调排班,增加21:00-23:00时段的助教配置。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-coach">助教:小燕</span>
|
||||
<span class="text-xs text-gray-6">2024-11-24 09:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
关系构建任务完成。与客户进行了30分钟的深入交流,了解到客户是企业高管,经常需要商务宴请场地。已记录客户需求,后续可以推荐团建套餐。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:张先生</span>
|
||||
<span class="text-xs text-gray-6">2024-11-23 19:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
客户今天充值了5000元,选择的是尊享套餐。客户提到喜欢安静的环境,以后尽量安排包厢。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:张先生</span>
|
||||
<span class="text-xs text-gray-6">2024-11-22 14:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
Amy本周请假2天处理家事,已安排泡芙和小燕分担她的客户。回来后需要跟进客户交接情况。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-coach">助教:Amy</span>
|
||||
<span class="text-xs text-gray-6">2024-11-22 10:15</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl p-4 shadow-sm">
|
||||
<p class="text-sm text-gray-13 leading-relaxed mb-3">
|
||||
Amy最近工作状态很好,主动承担了培训新员工的任务。但需要注意她最近加班较多,避免过度疲劳。
|
||||
</p>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="note-tag tag-customer">客户:李女士</span>
|
||||
<span class="text-xs text-gray-6">2024-11-21 09:45</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,789 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>业绩明细 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.record-item {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.record-item:active {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.perf-value {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.date-divider {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 14px 16px 4px;
|
||||
}
|
||||
.date-divider .dd-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: #dcdcdc;
|
||||
}
|
||||
.date-divider .dd-date {
|
||||
font-size: 11px;
|
||||
color: #8b8b8b;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.date-divider .dd-stats {
|
||||
font-size: 11px;
|
||||
color: #a6a6a6;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen pb-8">
|
||||
<!-- Tailwind 动态类预加载 -->
|
||||
<div class="hidden">
|
||||
<span class="rounded-lg from-blue-400 to-indigo-500 from-pink-400 to-rose-500 from-teal-400 to-emerald-500 from-green-400 to-teal-500 from-orange-400 to-amber-500 from-purple-400 to-violet-500 from-violet-400 to-purple-500 from-teal-300 to-emerald-400 from-amber-400 to-yellow-500 from-sky-400 to-blue-500 from-fuchsia-400 to-pink-500 from-rose-400 to-red-500 from-lime-400 to-green-500 from-slate-400 to-gray-500 from-indigo-300 to-violet-400 from-pink-300 to-rose-400 from-emerald-300 to-teal-400 from-cyan-400 to-sky-500 from-orange-300 to-red-400 from-yellow-400 to-orange-500 from-blue-300 to-purple-400 from-gray-300 to-gray-400"></span>
|
||||
</div>
|
||||
|
||||
<!-- Banner -->
|
||||
<div class="banner-bg theme-coral texture-aurora relative text-white">
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">业绩明细</h1>
|
||||
</div>
|
||||
<div class="px-5 pt-1 pb-5">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-14 h-14 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg overflow-hidden flex-shrink-0">
|
||||
<img src="../img/zjtx.png" class="w-full h-full object-cover" alt="助教头像">
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-lg font-semibold">小燕</span>
|
||||
<span class="px-2 py-0.5 bg-amber-400/30 text-amber-100 rounded-full text-xs">星级</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-white/70 text-xs">
|
||||
<span>球会名称店</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 月份切换 -->
|
||||
<div class="bg-white px-4 py-3 border-b border-gray-2 flex items-center justify-center gap-6">
|
||||
<button id="prevMonthBtn" onclick="switchMonth('prev')" class="p-1.5 rounded-full hover:bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<span id="monthLabel" class="text-sm font-semibold text-gray-13">2026年2月</span>
|
||||
<button id="nextMonthBtn" onclick="switchMonth('next')" class="p-1.5 rounded-full hover:bg-gray-100 opacity-30" disabled>
|
||||
<svg class="w-4 h-4 text-gray-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 6 15 12 9 18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 统计概览 -->
|
||||
<div class="px-4 py-3 bg-white border-b border-gray-2">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="text-center flex-1">
|
||||
<p class="text-[10px] text-gray-6 mb-0.5">总记录</p>
|
||||
<p class="text-lg font-bold text-gray-13 perf-value" id="totalCount">32笔</p>
|
||||
</div>
|
||||
<div class="w-px h-10 bg-gray-2 mt-0.5"></div>
|
||||
<div class="text-center flex-1">
|
||||
<p class="text-[10px] text-gray-6 mb-0.5">总业绩时长</p>
|
||||
<p class="text-lg font-bold text-primary perf-value" id="totalMinutes">59.0h</p>
|
||||
<p class="text-[10px] text-gray-5">折算前 60.5h</p>
|
||||
<p class="text-[10px] text-warning">预估</p>
|
||||
</div>
|
||||
<div class="w-px h-10 bg-gray-2 mt-0.5"></div>
|
||||
<div class="text-center flex-1">
|
||||
<p class="text-[10px] text-gray-6 mb-0.5">收入</p>
|
||||
<p class="text-lg font-bold text-success perf-value" id="totalIncome">¥4,720</p>
|
||||
<p class="text-[10px] text-warning">预估</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 记录列表 -->
|
||||
<div class="p-4">
|
||||
<div id="recordsList" class="bg-white rounded-2xl shadow-sm overflow-hidden">
|
||||
<!-- 2月7日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月7日</span><div class="dd-line"></div><span class="dd-stats">时长 6.0h · 预估收入 ¥510</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">王</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">王先生</span>
|
||||
<span class="text-xs text-gray-6">20:00-22:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">3号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">李</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">李女士</span>
|
||||
<span class="text-xs text-gray-6">16:00-18:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-blue-50 text-blue-700 rounded text-[11px] font-medium flex-shrink-0">包厢课</span>
|
||||
<span class="text-xs text-gray-7">VIP1号房</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥190</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-teal-400 to-emerald-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">陈</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">陈女士</span>
|
||||
<span class="text-xs text-gray-6">10:00-12:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">2号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2月6日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月6日</span><div class="dd-line"></div><span class="dd-stats">时长 3.5h · 预估收入 ¥280</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-green-400 to-teal-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">张</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">张先生</span>
|
||||
<span class="text-xs text-gray-6">19:00-21:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">5号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-orange-400 to-amber-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">刘</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">刘先生</span>
|
||||
<span class="text-xs text-gray-6">15:30-17:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-amber-600 perf-value">1.5h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-amber-50 text-amber-700 rounded text-[11px] font-medium flex-shrink-0">打赏课</span>
|
||||
<span class="text-xs text-gray-7">打赏</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥120</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2月5日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月5日</span><div class="dd-line"></div><span class="dd-stats">时长 4.0h · 预估收入 ¥320</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-teal-400 to-emerald-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">陈</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">陈女士</span>
|
||||
<span class="text-xs text-gray-6">20:00-22:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">2号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">赵</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">赵先生</span>
|
||||
<span class="text-xs text-gray-6">14:00-16:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span> <span class="text-[10px] text-gray-5 font-normal">(折0.5h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">7号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2月4日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月4日</span><div class="dd-line"></div><span class="dd-stats">时长 4.0h · 预估收入 ¥350</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-violet-400 to-purple-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">孙</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">孙先生</span>
|
||||
<span class="text-xs text-gray-6">19:00-21:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-blue-50 text-blue-700 rounded text-[11px] font-medium flex-shrink-0">包厢课</span>
|
||||
<span class="text-xs text-gray-7">VIP2号房</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥190</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-teal-300 to-emerald-400 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">吴</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">吴女士</span>
|
||||
<span class="text-xs text-gray-6">15:00-17:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">1号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2月3日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月3日</span><div class="dd-line"></div><span class="dd-stats">时长 3.5h · 预估收入 ¥280</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-amber-400 to-yellow-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">郑</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">郑先生</span>
|
||||
<span class="text-xs text-gray-6">20:00-22:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">4号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-sky-400 to-blue-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">黄</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">黄女士</span>
|
||||
<span class="text-xs text-gray-6">14:30-16:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-amber-600 perf-value">1.5h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-amber-50 text-amber-700 rounded text-[11px] font-medium flex-shrink-0">打赏课</span>
|
||||
<span class="text-xs text-gray-7">打赏</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥120</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2月2日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月2日</span><div class="dd-line"></div><span class="dd-stats">时长 4.0h · 预估收入 ¥350</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-fuchsia-400 to-pink-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">林</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">林先生</span>
|
||||
<span class="text-xs text-gray-6">19:00-21:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">6号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-rose-400 to-red-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">何</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">何女士</span>
|
||||
<span class="text-xs text-gray-6">13:00-15:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-blue-50 text-blue-700 rounded text-[11px] font-medium flex-shrink-0">包厢课</span>
|
||||
<span class="text-xs text-gray-7">VIP3号房</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥190</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2月1日 -->
|
||||
<div class="date-divider"><span class="dd-date">2月1日</span><div class="dd-line"></div><span class="dd-stats">时长 6.0h · 预估收入 ¥510</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-blue-400 to-indigo-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">王</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">王先生</span>
|
||||
<span class="text-xs text-gray-6">20:30-22:30</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">3号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-lime-400 to-green-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">马</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">马先生</span>
|
||||
<span class="text-xs text-gray-6">16:00-18:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">8号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-slate-400 to-gray-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">罗</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">罗女士</span>
|
||||
<span class="text-xs text-gray-6">12:30-14:30</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span> <span class="text-[10px] text-gray-5 font-normal">(折0.5h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">2号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-indigo-300 to-violet-400 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">梁</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">梁先生</span>
|
||||
<span class="text-xs text-gray-6">10:00-12:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">5号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-pink-300 to-rose-400 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">宋</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">宋女士</span>
|
||||
<span class="text-xs text-gray-6">8:30-10:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-amber-600 perf-value">1.5h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-amber-50 text-amber-700 rounded text-[11px] font-medium flex-shrink-0">打赏课</span>
|
||||
<span class="text-xs text-gray-7">打赏</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥120</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-emerald-300 to-teal-400 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">谢</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">谢先生</span>
|
||||
<span class="text-xs text-gray-6">7:00-8:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">1.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">1号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的预估收入 <span class="font-medium text-gray-9">¥80</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 1月31日 -->
|
||||
<div class="date-divider"><span class="dd-date">1月31日</span><div class="dd-line"></div><span class="dd-stats">时长 5.5h · 收入 ¥470</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-cyan-400 to-sky-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">韩</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">韩女士</span>
|
||||
<span class="text-xs text-gray-6">21:00-23:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">4号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-orange-300 to-red-400 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">唐</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">唐先生</span>
|
||||
<span class="text-xs text-gray-6">18:30-20:30</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span> <span class="text-[10px] text-gray-5 font-normal">(折0.5h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-blue-50 text-blue-700 rounded text-[11px] font-medium flex-shrink-0">包厢课</span>
|
||||
<span class="text-xs text-gray-7">VIP2号房</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥190</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-yellow-400 to-orange-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">冯</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">冯女士</span>
|
||||
<span class="text-xs text-gray-6">14:00-16:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">6号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 1月30日 -->
|
||||
<div class="date-divider"><span class="dd-date">1月30日</span><div class="dd-line"></div><span class="dd-stats">时长 3.5h · 收入 ¥280</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-green-400 to-teal-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">张</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">张先生</span>
|
||||
<span class="text-xs text-gray-6">19:30-21:30</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">5号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-orange-400 to-amber-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">刘</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">刘先生</span>
|
||||
<span class="text-xs text-gray-6">14:30-16:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-amber-600 perf-value">1.5h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-amber-50 text-amber-700 rounded text-[11px] font-medium flex-shrink-0">打赏课</span>
|
||||
<span class="text-xs text-gray-7">打赏</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥120</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 1月29日 -->
|
||||
<div class="date-divider"><span class="dd-date">1月29日</span><div class="dd-line"></div><span class="dd-stats">时长 4.0h · 收入 ¥320</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-teal-400 to-emerald-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">陈</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">陈女士</span>
|
||||
<span class="text-xs text-gray-6">20:00-22:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">2号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-pink-400 to-rose-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">李</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">李女士</span>
|
||||
<span class="text-xs text-gray-6">13:00-15:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-blue-50 text-blue-700 rounded text-[11px] font-medium flex-shrink-0">包厢课</span>
|
||||
<span class="text-xs text-gray-7">VIP1号房</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥190</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 1月28日 -->
|
||||
<div class="date-divider"><span class="dd-date">1月28日</span><div class="dd-line"></div><span class="dd-stats">时长 4.0h · 收入 ¥350</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-purple-400 to-violet-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">赵</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">赵先生</span>
|
||||
<span class="text-xs text-gray-6">19:00-21:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span> <span class="text-[10px] text-gray-5 font-normal">(折0.5h)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">7号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-blue-300 to-purple-400 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">董</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">董先生</span>
|
||||
<span class="text-xs text-gray-6">15:00-17:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-emerald-50 text-emerald-700 rounded text-[11px] font-medium flex-shrink-0">基础课</span>
|
||||
<span class="text-xs text-gray-7">3号台</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥160</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 1月27日 -->
|
||||
<div class="date-divider"><span class="dd-date">1月27日</span><div class="dd-line"></div><span class="dd-stats">时长 4.0h · 收入 ¥350</span></div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-violet-400 to-purple-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">孙</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">孙先生</span>
|
||||
<span class="text-xs text-gray-6">20:00-22:00</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-emerald-600 perf-value">2.0h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-blue-50 text-blue-700 rounded text-[11px] font-medium flex-shrink-0">包厢课</span>
|
||||
<span class="text-xs text-gray-7">VIP2号房</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥190</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-item flex items-center gap-3 px-4 py-2.5">
|
||||
<div class="w-[38px] h-[38px] rounded-lg bg-gradient-to-br from-sky-400 to-blue-500 flex items-center justify-center text-white text-sm font-medium shadow-sm flex-shrink-0">黄</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm font-medium text-gray-13 flex-shrink-0">黄女士</span>
|
||||
<span class="text-xs text-gray-6">14:30-16:30</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 flex-shrink-0 ml-2">
|
||||
<span class="text-sm font-bold text-amber-600 perf-value">1.5h</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-1">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="px-1.5 py-px bg-amber-50 text-amber-700 rounded text-[11px] font-medium flex-shrink-0">打赏课</span>
|
||||
<span class="text-xs text-gray-7">打赏</span>
|
||||
</div>
|
||||
<span class="text-[11px] text-gray-5 flex-shrink-0">我的收入 <span class="font-medium text-gray-9">¥120</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-4 py-4 text-center"><p class="text-[10px] text-gray-5">— 已加载全部记录 —</p></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 悬浮助手按钮 -->
|
||||
|
||||
|
||||
<!-- 月份切换交互 -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,129 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>审核中 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
}
|
||||
.bg-pattern {
|
||||
background-color: #f8fafc;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%230052d9' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
||||
}
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
.float-animation {
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse-soft {
|
||||
0%, 100% { opacity: 0.6; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
.pulse-soft {
|
||||
animation: pulse-soft 2s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-pattern min-h-screen flex flex-col">
|
||||
<!-- 顶部装饰 -->
|
||||
<div class="absolute top-0 left-0 right-0 h-64 bg-gradient-to-b from-warning/10 to-transparent"></div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="flex-1 flex flex-col items-center justify-center px-8 relative z-10">
|
||||
<!-- 图标区域 -->
|
||||
<div class="relative mb-8 float-animation">
|
||||
<!-- 背景光晕 -->
|
||||
<div class="absolute inset-0 w-32 h-32 bg-warning/20 rounded-full blur-xl"></div>
|
||||
|
||||
<!-- 主图标 -->
|
||||
<div class="relative w-28 h-28 bg-gradient-to-br from-amber-400 to-orange-500 rounded-3xl flex items-center justify-center shadow-xl shadow-warning/30">
|
||||
<svg class="w-14 h-14 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<polyline points="12 6 12 12 16 14"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 装饰点 -->
|
||||
<div class="absolute -top-2 -right-2 w-4 h-4 bg-warning rounded-full pulse-soft"></div>
|
||||
<div class="absolute -bottom-1 -left-3 w-3 h-3 bg-amber-300 rounded-full pulse-soft" style="animation-delay: 0.5s;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 文字区域 -->
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-2xl font-bold text-gray-10 mb-3">申请审核中</h1>
|
||||
<p class="text-sm text-gray-7 leading-relaxed max-w-xs mx-auto">
|
||||
您的访问申请已提交成功,正在等待管理员审核,请耐心等待
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 进度提示卡片 -->
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-lg shadow-gray-200/50 mb-6">
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="w-10 h-10 bg-warning/10 rounded-xl flex items-center justify-center">
|
||||
<svg class="w-5 h-5 text-warning" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<p class="text-sm font-medium text-gray-13">审核进度</p>
|
||||
<p class="text-xs text-gray-6">通常需要 1-3 个工作日</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-6 h-6 bg-success rounded-full flex items-center justify-center">
|
||||
<svg class="w-4 h-4 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
|
||||
<polyline points="20 6 9 17 4 12"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="text-xs text-gray-9">已提交</span>
|
||||
</div>
|
||||
<div class="flex-1 h-0.5 bg-gray-200">
|
||||
<div class="h-full w-1/2 bg-warning rounded-full"></div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-6 h-6 bg-warning/20 rounded-full flex items-center justify-center">
|
||||
<div class="w-2 h-2 bg-warning rounded-full pulse-soft"></div>
|
||||
</div>
|
||||
<span class="text-xs text-gray-6">审核中</span>
|
||||
</div>
|
||||
<div class="flex-1 h-0.5 bg-gray-200"></div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-6 h-6 bg-gray-100 rounded-full"></div>
|
||||
<span class="text-xs text-gray-5">通过</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 联系提示 -->
|
||||
<div class="flex items-center gap-2 text-gray-6 mb-8">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
<span class="text-xs">如有疑问,请联系管理员</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="px-8 pb-12">
|
||||
<button onclick="switchAccount()" class="w-full py-3.5 bg-white border border-gray-200 rounded-xl text-gray-9 font-medium text-sm flex items-center justify-center gap-2 shadow-sm">
|
||||
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/>
|
||||
<polyline points="16 17 21 12 16 7"/>
|
||||
<line x1="21" y1="12" x2="9" y2="12"/>
|
||||
</svg>
|
||||
更换登录账号
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,356 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>任务详情 - 客户回访</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/task-detail.css" rel="stylesheet">
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 通栏 Banner - 客户信息 -->
|
||||
<div class="banner-bg theme-teal texture-aurora relative text-white">
|
||||
<!-- 导航栏 -->
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">任务详情</h1>
|
||||
</div>
|
||||
|
||||
<!-- 客户信息 -->
|
||||
<div class="px-5 pt-2 pb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg">
|
||||
<span class="text-2xl font-bold text-white">赵</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xl font-semibold">赵女士</span>
|
||||
<span class="px-2 py-0.5 bg-white/25 backdrop-blur-sm text-white rounded-full text-xs font-medium">客户回访</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-sm">
|
||||
<span>135****6677</span>
|
||||
<button onclick="this.previousElementSibling.textContent='13566776677';this.style.display='none'" class="px-2 py-0.5 bg-white/20 rounded text-white/90 text-xs">查看</button>
|
||||
<span>💰 储值 <span style="background: linear-gradient(135deg, #d4af37 0%, #f4d03f 50%, #d4af37 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600;">非常多</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- 维客线索 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title green text-sm font-semibold text-gray-13">维客线索</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-2.5">
|
||||
<!-- 客户基础 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-primary/10 text-primary text-[11px] font-medium rounded-sm leading-normal tracking-wide">客户<br>基础</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">👩 女性 · VIP会员 · 入会1年半 · 忠实老客户</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 消费习惯 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">☀️ 偏好周末下午 · 月均6-8次</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💰 高客单价 · 爱点酒水</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">场均消费 ¥420,高于门店均值 ¥180;酒水小食附加消费占比 40%,偏好VIP包厢</p>
|
||||
</div>
|
||||
<!-- 玩法偏好 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 斯诺克爱好者 · 技术中上 · 喜欢研究杆法</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">斯诺克占比 85%,偶尔玩中式八球;对高级杆法有浓厚兴趣,正在学习走位技巧</p>
|
||||
</div>
|
||||
<!-- 重要反馈 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">⭐ 上次服务好评,新球杆手感满意</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">2月4日到店时表示新球杆手感很好,希望下次能提前预留VIP包厢;满意度持续保持高位</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 与我的关系 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">与我的关系</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-4 py-2 bg-gradient-to-r from-pink-500 to-rose-500 text-white text-sm font-semibold rounded-xl shadow-sm">💖 非常好</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="h-3 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-pink-400 to-rose-500 rounded-full" style="width: 88%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-lg font-bold text-pink-500">0.88</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed mb-4">
|
||||
长期合作关系良好,共有 45 次服务记录。客户多次指定您服务,评价均为 5 星。是您的核心客户之一,需要持续维护。
|
||||
</p>
|
||||
<!-- 近期服务记录 -->
|
||||
<div class="svc-section-bg">
|
||||
<p class="text-sm font-semibold text-gray-13 mb-3">📋 近期服务记录</p>
|
||||
<div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">VIP2号房</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.0h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥190</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 红牛x2 花生米x1</span>
|
||||
<span class="svc-date">2026-02-04 15:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">8号台</span>
|
||||
<span class="svc-type incentive">激励课</span>
|
||||
<span class="svc-duration">1.5h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥120</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 可乐x2</span>
|
||||
<span class="svc-date">2026-01-30 16:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">VIP2号房</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.5h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥200</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 百威x3 薯条x1</span>
|
||||
<span class="svc-date">2026-01-25 14:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button onclick="window.location.href='customer-service-records.html'" class="text-xs text-primary font-medium">查看全部服务记录 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务建议 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="section-title purple text-sm font-semibold text-gray-13 mb-4">任务建议</h2>
|
||||
<div class="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl p-4 border border-blue-100">
|
||||
<p class="text-sm text-primary leading-relaxed font-medium mb-3">
|
||||
<span class="flex items-center justify-between">
|
||||
<span>📞 常规回访要点</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed mb-2">
|
||||
该客户上次到店是 3 天前,关系良好,进行常规关怀回访:
|
||||
</p>
|
||||
<ul class="text-sm text-gray-9 space-y-1.5 list-disc list-inside">
|
||||
<li>询问上次体验是否满意,是否有改进建议</li>
|
||||
<li>告知近期新到的斯诺克相关设备或活动</li>
|
||||
<li>提前预约下次到店时间,提供专属服务</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-4 p-4 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="font-medium text-gray-13 text-sm">💬 话术参考</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐您好!上次打球感觉怎么样?新到的球杆手感还习惯吗?这周末您有空的话,可以提前帮您预留老位置~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐,最近店里新进了一批斯诺克专用巧克粉,手感特别好,下次来的时候可以试试~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐好呀,上次您说想学几个高级杆法,我最近整理了一些教学视频,要不要发给您先看看?"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐,这周六下午VIP包厢有空位,要不要帮您提前预留?可以叫上朋友一起来打球~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"赵姐您好,我们下个月有个会员积分兑换活动,您的积分可以换不少好东西,到时候提醒您哦~"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 我给TA的备注 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">我给TA的备注</h2>
|
||||
<span class="text-xs text-gray-6">2 条备注</span>
|
||||
</div>
|
||||
<div id="noteList" class="space-y-3">
|
||||
<div class="note-card-wrap flex items-start gap-3 p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs text-gray-6 mb-1.5">2026-02-07</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">赵姐反馈上次体验很满意,新球杆手感不错,希望下次能预留VIP包厢。</p>
|
||||
</div>
|
||||
<div class="star-rating" data-score="9"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="note-card-wrap flex items-start gap-3 p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs text-gray-6 mb-1.5">2026-01-25</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">已预约本周六下午到店,需要提前安排靠窗位置。</p>
|
||||
</div>
|
||||
<div class="star-rating" data-score="9"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="noteEmpty" class="text-center py-6 hidden">
|
||||
<svg class="w-10 h-10 text-gray-4 mx-auto mb-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-5">暂无备注</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="fixed bottom-0 left-0 right-0 h-16 bg-white/95 backdrop-blur-lg border-t border-gray-2 flex items-center gap-3 px-4">
|
||||
<button onclick="window.location.href='chat.html'" class="flex-1 h-11 bg-gradient-to-r from-teal-500 to-cyan-500 text-white font-medium rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-teal-500/30">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
问问助手
|
||||
</button>
|
||||
<button onclick="showNoteModal()" class="flex-1 h-11 bg-gray-100 text-gray-13 font-medium rounded-xl flex items-center justify-center gap-2">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
备注
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 备注弹窗 -->
|
||||
<div id="noteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-end">
|
||||
<div class="w-full bg-white rounded-t-3xl p-5 pb-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-semibold text-gray-13">添加备注</span>
|
||||
<button id="noteExpandBtn" onclick="expandNoteRating()" class="note-expand-btn">展开评价 ▾</button>
|
||||
</div>
|
||||
<button onclick="hideNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div id="noteRatingSection" class="hidden">
|
||||
<!-- 星星打分:再次服务意愿 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再次服务此客户</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不想</span><span></span><span>一般</span><span></span><span>非常想</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 星星打分:再来店可能性 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再来店可能性</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不可能</span><span></span><span>不好说</span><span></span><span>肯定能</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="noteText" class="w-full h-32 p-4 bg-gray-50 rounded-xl resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-primary/20 border border-gray-100" placeholder="请输入备注内容..."></textarea>
|
||||
<button onclick="saveNote()" class="w-full h-12 bg-gradient-to-r from-teal-500 to-cyan-500 text-white font-medium rounded-xl mt-4 shadow-lg shadow-teal-500/30">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除备注确认弹窗 -->
|
||||
<div id="deleteNoteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center px-6">
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-xl">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<span class="text-base font-semibold text-gray-13">删除备注</span>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 mb-5">确定要删除这条备注吗?删除后无法恢复。</p>
|
||||
<button onclick="deleteNote()" class="w-full h-12 bg-gradient-to-r from-error to-red-400 text-white font-medium rounded-xl shadow-lg shadow-error/30 text-sm">确认删除</button>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-full text-center text-sm text-gray-6 py-2 mt-2 bg-transparent border-0 cursor-pointer">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast 提示 -->
|
||||
<div id="toast" class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-13/80 text-white text-sm px-6 py-3 rounded-xl z-[100] hidden backdrop-blur-sm"></div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,356 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>任务详情 - 优先召回</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/task-detail.css" rel="stylesheet">
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 通栏 Banner - 客户信息 -->
|
||||
<div class="banner-bg theme-orange texture-aurora relative text-white">
|
||||
<!-- 导航栏 -->
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">任务详情</h1>
|
||||
</div>
|
||||
|
||||
<!-- 客户信息 -->
|
||||
<div class="px-5 pt-2 pb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg">
|
||||
<span class="text-2xl font-bold text-white">张</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xl font-semibold">张先生</span>
|
||||
<span class="px-2 py-0.5 bg-white/25 backdrop-blur-sm text-white rounded-full text-xs font-medium">优先召回</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-sm">
|
||||
<span>139****1234</span>
|
||||
<button onclick="this.previousElementSibling.textContent='13912341234';this.style.display='none'" class="px-2 py-0.5 bg-white/20 rounded text-white/90 text-xs">查看</button>
|
||||
<span>💰 储值 <span style="background: linear-gradient(135deg, #d4af37 0%, #f4d03f 50%, #d4af37 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600;">多</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- 维客线索 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title green text-sm font-semibold text-gray-13">维客线索</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-2.5">
|
||||
<!-- 客户基础 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-primary/10 text-primary text-[11px] font-medium rounded-sm leading-normal tracking-wide">客户<br>基础</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">👤 普通会员 · 注册10个月 · 近期活跃度下降</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 消费习惯 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🌙 偏好夜场 20:00-23:00 · 之前月均3-4次</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">📉 频率下降 · 爱组局</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">场均消费 ¥220,近月到店仅 1 次(之前月均 3-4 次);喜欢和朋友组局,酒水消费占比 25%</p>
|
||||
</div>
|
||||
<!-- 玩法偏好 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 中式八球为主 · 喜欢组局对战 · 想练组合球</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">中式八球占比 90%,技术水平中等;喜欢 3-4 人组局对战,社交属性强</p>
|
||||
</div>
|
||||
<!-- 重要反馈 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">⚠️ 换了工作,下班时间不固定</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">2月3日沟通时提到最近换了工作,下班时间不固定,周末可能更方便;建议调整联系时段为周末</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 与我的关系 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">与我的关系</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-4 py-2 bg-gradient-to-r from-amber-400 to-yellow-500 text-white text-sm font-semibold rounded-xl shadow-sm">💛 一般</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="h-3 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-amber-300 to-yellow-500 rounded-full" style="width: 55%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-lg font-bold text-amber-500">0.55</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed">
|
||||
最近 2 个月互动较少,仅有 3 次服务记录。客户对您的印象中等,有提升空间。建议增加互动频次,建立更好的服务关系。
|
||||
</p>
|
||||
<!-- 最近服务记录 -->
|
||||
<div class="svc-section-bg">
|
||||
<p class="text-sm font-semibold text-gray-13 mb-3">📋 近期服务记录</p>
|
||||
<div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">5号台</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.0h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥160</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 雪花x2 矿泉水x1</span>
|
||||
<span class="svc-date">2026-02-06 19:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">A08号台</span>
|
||||
<span class="svc-type incentive">激励课</span>
|
||||
<span class="svc-duration">1.5h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥150</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 百威x1</span>
|
||||
<span class="svc-date">2026-01-20 20:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">3号台</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.0h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥160</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 可乐x2 红牛x1</span>
|
||||
<span class="svc-date">2026-01-05 21:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button onclick="window.location.href='customer-service-records.html'" class="text-xs text-primary font-medium">查看全部服务记录 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务建议 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="section-title orange text-sm font-semibold text-gray-13 mb-4">任务建议</h2>
|
||||
<div class="bg-gradient-to-br from-orange-50 to-amber-50 rounded-xl p-4 border border-orange-100">
|
||||
<p class="text-sm text-warning leading-relaxed font-medium mb-3">
|
||||
<span class="flex items-center justify-between">
|
||||
<span>💡 建议执行</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed mb-2">
|
||||
该客户消费频率从月均 4 次下降到近月仅 1 次,需要关注原因:
|
||||
</p>
|
||||
<ul class="text-sm text-gray-9 space-y-1.5 list-disc list-inside">
|
||||
<li>了解是否工作变动或搬家导致不便</li>
|
||||
<li>询问对门店服务是否有改进建议</li>
|
||||
<li>推荐近期的会员优惠活动</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-4 p-4 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="font-medium text-gray-13 text-sm">💬 话术参考</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"张哥,好久没见您来打球了,最近忙吗?店里这周六有个球友聚会活动,想邀请您来玩,顺便认识一些新球友~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"张哥好呀,最近工作还顺利吧?周末有空的话过来放松一下,我帮您约几个水平差不多的球友一起切磋~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"张哥,店里最近新上了几款精酿啤酒,打完球来一杯特别爽,周末要不要来试试?"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"张哥,上次您说想练练组合球,我最近研究了几个不错的训练方法,下次来的时候教您~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"张哥您好,这个月会员充值有额外赠送活动,力度挺大的,要不要了解一下?"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 我给TA的备注 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">我给TA的备注</h2>
|
||||
<span class="text-xs text-gray-6">2 条备注</span>
|
||||
</div>
|
||||
<div id="noteList" class="space-y-3">
|
||||
<div class="note-card-wrap flex items-start gap-3 p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs text-gray-6 mb-1.5">2026-02-03</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">张先生说最近换了工作,下班时间不固定,周末可能更方便。</p>
|
||||
</div>
|
||||
<div class="star-rating" data-score="5"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="note-card-wrap flex items-start gap-3 p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-xs text-gray-6 mb-1.5">2026-01-15</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">推荐了周末球友聚会活动,客户表示有兴趣但还没确认。</p>
|
||||
</div>
|
||||
<div class="star-rating" data-score="5"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="noteEmpty" class="text-center py-6 hidden">
|
||||
<svg class="w-10 h-10 text-gray-4 mx-auto mb-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-5">暂无备注</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="fixed bottom-0 left-0 right-0 h-16 bg-white/95 backdrop-blur-lg border-t border-gray-2 flex items-center gap-3 px-4">
|
||||
<button onclick="window.location.href='chat.html'" class="flex-1 h-11 bg-gradient-to-r from-orange-500 to-amber-500 text-white font-medium rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-orange-500/30">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
问问助手
|
||||
</button>
|
||||
<button onclick="showNoteModal()" class="flex-1 h-11 bg-gray-100 text-gray-13 font-medium rounded-xl flex items-center justify-center gap-2">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
备注
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 备注弹窗 -->
|
||||
<div id="noteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-end">
|
||||
<div class="w-full bg-white rounded-t-3xl p-5 pb-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-semibold text-gray-13">添加备注</span>
|
||||
<button id="noteExpandBtn" onclick="expandNoteRating()" class="note-expand-btn">展开评价 ▾</button>
|
||||
</div>
|
||||
<button onclick="hideNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div id="noteRatingSection" class="hidden">
|
||||
<!-- 星星打分:再次服务意愿 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再次服务此客户</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不想</span><span></span><span>一般</span><span></span><span>非常想</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 星星打分:再来店可能性 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再来店可能性</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不可能</span><span></span><span>不好说</span><span></span><span>肯定能</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="noteText" class="w-full h-32 p-4 bg-gray-50 rounded-xl resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-orange-500/20 border border-gray-100" placeholder="请输入备注内容..."></textarea>
|
||||
<button onclick="saveNote()" class="w-full h-12 bg-gradient-to-r from-orange-500 to-amber-500 text-white font-medium rounded-xl mt-4 shadow-lg shadow-orange-500/30">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除备注确认弹窗 -->
|
||||
<div id="deleteNoteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center px-6">
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-xl">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<span class="text-base font-semibold text-gray-13">删除备注</span>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 mb-5">确定要删除这条备注吗?删除后无法恢复。</p>
|
||||
<button onclick="deleteNote()" class="w-full h-12 bg-gradient-to-r from-error to-red-400 text-white font-medium rounded-xl shadow-lg shadow-error/30 text-sm">确认删除</button>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-full text-center text-sm text-gray-6 py-2 mt-2 bg-transparent border-0 cursor-pointer">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast 提示 -->
|
||||
<div id="toast" class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-13/80 text-white text-sm px-6 py-3 rounded-xl z-[100] hidden backdrop-blur-sm"></div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>任务详情 - 关系构建</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/task-detail.css" rel="stylesheet">
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 通栏 Banner - 客户信息 -->
|
||||
<div class="banner-bg theme-pink texture-aurora relative text-white">
|
||||
<!-- 导航栏 -->
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">任务详情</h1>
|
||||
</div>
|
||||
|
||||
<!-- 客户信息 -->
|
||||
<div class="px-5 pt-2 pb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg">
|
||||
<span class="text-2xl font-bold text-white">陈</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xl font-semibold">陈先生</span>
|
||||
<span class="px-2 py-0.5 bg-white/25 backdrop-blur-sm text-white rounded-full text-xs font-medium">关系构建</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-sm">
|
||||
<span>137****8899</span>
|
||||
<button onclick="this.previousElementSibling.textContent='13788998899';this.style.display='none'" class="px-2 py-0.5 bg-white/20 rounded text-white/90 text-xs">查看</button>
|
||||
<span>💰 储值 <span style="background: linear-gradient(135deg, #d4af37 0%, #f4d03f 50%, #d4af37 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600;">一般</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- 维客线索 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title green text-sm font-semibold text-gray-13">维客线索</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-2.5">
|
||||
<!-- 客户基础 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-primary/10 text-primary text-[11px] font-medium rounded-sm leading-normal tracking-wide">客户<br>基础</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🆕 新客户 · 入会2个月 · 消费潜力大</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 消费习惯 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">☀️ 偏好下午 14:00-18:00 · 到店2次</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💎 消费潜力大</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">单次消费 ¥180,高于新客均值 ¥120;消费能力较强,有提升空间,适合推荐课程套餐</p>
|
||||
</div>
|
||||
<!-- 玩法偏好 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 初学者 · 对台球感兴趣 · 技术待提升</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">尚未形成明确偏好,对各类玩法都有兴趣;技术水平初级,适合推荐入门课程和基础训练</p>
|
||||
</div>
|
||||
<!-- 重要反馈 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💬 上次课后反馈良好,想继续学习</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">2月5日基础课后表示很有收获,希望能有更多练习机会;建议安排球友交流活动帮助融入</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 与我的关系 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">与我的关系</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-4 py-2 bg-gradient-to-r from-blue-500 to-cyan-500 text-white text-sm font-semibold rounded-xl shadow-sm">💙 待发展</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="h-3 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-blue-400 to-cyan-500 rounded-full" style="width: 45%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-lg font-bold text-blue-500">0.45</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed">
|
||||
接触次数较少,仅有 2 次服务记录。客户对您还不太熟悉,但反馈良好。建议通过专业服务和关心,逐步建立信任关系。
|
||||
</p>
|
||||
<!-- 最近服务记录 -->
|
||||
<div class="svc-section-bg">
|
||||
<p class="text-sm font-semibold text-gray-13 mb-3">📋 近期服务记录</p>
|
||||
<div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">2号台</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">1.5h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥120</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 矿泉水x2</span>
|
||||
<span class="svc-date">2026-02-05 15:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">A03号台</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration">2.0h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥160</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 可乐x1 雪碧x1</span>
|
||||
<span class="svc-date">2026-01-22 16:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">6号台</span>
|
||||
<span class="svc-type incentive">激励课</span>
|
||||
<span class="svc-duration">1.0h</span>
|
||||
</div>
|
||||
<span class="svc-income">¥100</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 红牛x1</span>
|
||||
<span class="svc-date">2026-01-10 14:30</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-center">
|
||||
<button onclick="window.location.href='customer-service-records.html'" class="text-xs text-primary font-medium">查看全部服务记录 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务建议 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="section-title pink text-sm font-semibold text-gray-13 mb-4">任务建议</h2>
|
||||
<div class="bg-gradient-to-br from-pink-50 to-rose-50 rounded-xl p-4 border border-pink-100">
|
||||
<p class="text-sm text-pink-600 leading-relaxed font-medium mb-3">
|
||||
<span class="flex items-center justify-between">
|
||||
<span>💝 关系构建重点</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed mb-2">
|
||||
该客户消费潜力大但关系指数较低,建议重点培养:
|
||||
</p>
|
||||
<ul class="text-sm text-gray-9 space-y-1.5 list-disc list-inside">
|
||||
<li>主动关心学习进度,提供技术指导</li>
|
||||
<li>了解其兴趣爱好,建立共同话题</li>
|
||||
<li>适时推荐适合初学者的课程套餐</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-4 p-4 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="font-medium text-gray-13 text-sm">💬 话术参考</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"陈哥您好,上次看您打球进步很快呀!我们这周有个初学者交流会,可以认识一些同水平的球友一起练习,您有兴趣参加吗?"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"陈哥好呀,上次教您的那个发力技巧练得怎么样了?下次来的时候我再帮您看看,争取早日突破~"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"陈哥,我们店里新推出了一个入门课程套餐,专门针对想快速提升的球友,性价比很高,要不要了解一下?"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"陈哥您好,这周六下午有几位球友约了练习赛,水平都差不多,要不要一起来切磋切磋?"
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed pl-3 border-l-2 border-primary/30">
|
||||
"陈哥,最近天气不错,下午来打打球放松一下吧,我帮您留个好位置~"
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 我给TA的备注 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">我给TA的备注</h2>
|
||||
<span class="text-xs text-gray-6">暂无备注</span>
|
||||
</div>
|
||||
<div id="noteList" class="space-y-3 hidden"></div>
|
||||
<div id="noteEmpty" class="text-center py-6">
|
||||
<svg class="w-10 h-10 text-gray-4 mx-auto mb-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-5">快点击下方备注按钮,添加客人备注!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="fixed bottom-0 left-0 right-0 h-16 bg-white/95 backdrop-blur-lg border-t border-gray-2 flex items-center gap-3 px-4">
|
||||
<button onclick="window.location.href='chat.html'" class="flex-1 h-11 bg-gradient-to-r from-pink-500 to-rose-500 text-white font-medium rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-pink-500/30">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
问问助手
|
||||
</button>
|
||||
<button onclick="showNoteModal()" class="flex-1 h-11 bg-gray-100 text-gray-13 font-medium rounded-xl flex items-center justify-center gap-2">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
备注
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 备注弹窗 -->
|
||||
<div id="noteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-end">
|
||||
<div class="w-full bg-white rounded-t-3xl p-5 pb-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-semibold text-gray-13">添加备注</span>
|
||||
<button id="noteExpandBtn" onclick="expandNoteRating()" class="note-expand-btn">展开评价 ▾</button>
|
||||
</div>
|
||||
<button onclick="hideNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div id="noteRatingSection" class="hidden">
|
||||
<!-- 星星打分:再次服务意愿 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再次服务此客户</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不想</span><span></span><span>一般</span><span></span><span>非常想</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 星星打分:再来店可能性 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再来店可能性</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不可能</span><span></span><span>不好说</span><span></span><span>肯定能</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="noteText" class="w-full h-32 p-4 bg-gray-50 rounded-xl resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-pink-500/20 border border-gray-100" placeholder="请输入备注内容..."></textarea>
|
||||
<button onclick="saveNote()" class="w-full h-12 bg-gradient-to-r from-pink-500 to-rose-500 text-white font-medium rounded-xl mt-4 shadow-lg shadow-pink-500/30">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除备注确认弹窗 -->
|
||||
<div id="deleteNoteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center px-6">
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-xl">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<span class="text-base font-semibold text-gray-13">删除备注</span>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 mb-5">确定要删除这条备注吗?删除后无法恢复。</p>
|
||||
<button onclick="deleteNote()" class="w-full h-12 bg-gradient-to-r from-error to-red-400 text-white font-medium rounded-xl shadow-lg shadow-error/30 text-sm">确认删除</button>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-full text-center text-sm text-gray-6 py-2 mt-2 bg-transparent border-0 cursor-pointer">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast 提示 -->
|
||||
<div id="toast" class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-13/80 text-white text-sm px-6 py-3 rounded-xl z-[100] hidden backdrop-blur-sm"></div>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>任务详情 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/task-detail.css" rel="stylesheet">
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
/* 话术气泡 */
|
||||
.speech-bubble {
|
||||
position: relative;
|
||||
background: #f0f4ff;
|
||||
border: 1px solid #c5c5c5;
|
||||
border-radius: 12px;
|
||||
padding: 12px 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.7;
|
||||
color: #5e5e5e;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
/* 尖角:旋转正方形,右下角伸出 */
|
||||
.speech-bubble::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
right: 24px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: #f0f4ff;
|
||||
border-right: 1px solid #c5c5c5;
|
||||
border-bottom: 1px solid #c5c5c5;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
/* 复制按钮 */
|
||||
.copy-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 0;
|
||||
font-size: 12px;
|
||||
color: #a6a6a6;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.copy-btn:active { color: #0052d9; }
|
||||
.copy-btn svg { width: 14px; height: 14px; }
|
||||
.copy-btn.copied { color: #00a870; }
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 通栏 Banner - 客户信息 -->
|
||||
<div class="banner-bg theme-red texture-aurora relative text-white">
|
||||
<!-- 导航栏 -->
|
||||
<div class="h-11 flex items-center relative px-4">
|
||||
<button onclick="history.back()" class="absolute left-4 p-1">
|
||||
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="flex-1 text-center text-base font-medium">任务详情</h1>
|
||||
<button onclick="showAbandonModal()" class="absolute right-4 text-white/50 text-sm">放弃</button>
|
||||
</div>
|
||||
|
||||
<!-- 客户信息 -->
|
||||
<div class="px-5 pt-2 pb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg">
|
||||
<span class="text-2xl font-bold text-white">王</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xl font-semibold">王先生</span>
|
||||
<span class="px-2 py-0.5 bg-white/25 backdrop-blur-sm text-white rounded-full text-xs font-medium">高优先召回</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-white/70 text-sm">
|
||||
<span>138****5678</span>
|
||||
<button onclick="this.previousElementSibling.textContent='13812345678';this.style.display='none'" class="px-2 py-0.5 bg-white/20 rounded text-white/90 text-xs">查看</button>
|
||||
<span>💰 储值 <span style="background: linear-gradient(135deg, #d4af37 0%, #f4d03f 50%, #d4af37 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 600;">非常多</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主体内容 -->
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- 与我的关系(置顶) -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title pink text-sm font-semibold text-gray-13">与我的关系</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-4 py-2 bg-gradient-to-r from-pink-500 to-rose-500 text-white text-sm font-semibold rounded-xl shadow-sm">💖 非常好</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="h-3 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div class="h-full bg-gradient-to-r from-pink-400 to-rose-500 rounded-full" style="width: 85%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-lg font-bold text-pink-500">0.85</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed">
|
||||
最近 3 个月每周均有 1-2 次课程互动,客户反馈良好。上次服务评价 5 星,多次指定您为服务助教。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 任务建议 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<h2 class="section-title orange text-sm font-semibold text-gray-13 mb-4">任务建议</h2>
|
||||
<div class="bg-gradient-to-br from-blue-50 to-indigo-50 rounded-xl p-4 border border-blue-100">
|
||||
<p class="text-sm text-primary leading-relaxed font-medium mb-3">
|
||||
<span class="flex items-center justify-between">
|
||||
<span>💡 建议执行</span>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</span>
|
||||
</p>
|
||||
<p class="text-sm text-gray-9 leading-relaxed mb-2">
|
||||
该客户已有 15 天未到店,存在流失风险。建议通过微信联系:
|
||||
</p>
|
||||
<ul class="text-sm text-gray-9 space-y-1.5 list-disc list-inside">
|
||||
<li>询问近期是否有空,邀请体验新到的器材</li>
|
||||
<li>告知本周末有会员专属活动</li>
|
||||
<li>根据其偏好时段(晚间)推荐合适的时间</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<span class="font-medium text-gray-13 text-sm">💬 话术参考</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-5">
|
||||
<div class="speech-bubble"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>王哥您好,好久不见!最近店里新到了几张国际标准的斯诺克球桌,知道您是斯诺克爱好者,想邀请您有空来体验一下~<div class="flex justify-end mt-0"><button class="copy-btn" onclick="copySpeech(this)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg><span>复制</span></button></div></div>
|
||||
<div class="speech-bubble"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>王哥,最近忙吗?这周末我们有个老客户专属的球友交流赛,奖品还挺丰富的,您要不要来参加?<div class="flex justify-end mt-0"><button class="copy-btn" onclick="copySpeech(this)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg><span>复制</span></button></div></div>
|
||||
<div class="speech-bubble"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>王哥好呀,上次您提到想练练斯诺克的走位,我最近研究了一些新的训练方法,下次来的时候可以一起试试~<div class="flex justify-end mt-0"><button class="copy-btn" onclick="copySpeech(this)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg><span>复制</span></button></div></div>
|
||||
<div class="speech-bubble"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>王哥,好久没见您了,您的老位置 A12 号台一直给您留着呢!最近晚上人不多,环境特别好,随时欢迎您来~<div class="flex justify-end mt-0"><button class="copy-btn" onclick="copySpeech(this)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg><span>复制</span></button></div></div>
|
||||
<div class="speech-bubble"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>王哥您好,我们这个月推出了储值会员专属的夜场优惠套餐,包含球台+酒水,性价比很高,给您留意着呢~<div class="flex justify-end mt-0"><button class="copy-btn" onclick="copySpeech(this)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg><span>复制</span></button></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 维客线索 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title green text-sm font-semibold text-gray-13">维客线索</h2>
|
||||
<span class="ai-title-badge"><span class="ai-title-badge-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white" stroke="currentColor" stroke-width="0.8"/><path d="M12 7V4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white" stroke="currentColor" stroke-width="0.7"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white" stroke="currentColor" stroke-width="0.7"/></svg></span>AI智能洞察</span>
|
||||
</div>
|
||||
<div class="space-y-2.5">
|
||||
<!-- 客户基础 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-primary/10 text-primary text-[11px] font-medium rounded-sm leading-normal tracking-wide">客户<br>基础</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎂 生日 3月15日 · VIP会员 · 注册2年</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 消费习惯 -->
|
||||
<div class="flex items-start gap-3 p-3 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🌙 常来夜场 · 月均4-5次</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-success/10 text-success text-[11px] font-medium rounded-sm leading-normal tracking-wide">消费<br>习惯</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">💰 高客单价</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">近60天场均消费 ¥420,高于门店均值 ¥180;偏好夜场时段,酒水附加消费占比 35%</p>
|
||||
</div>
|
||||
<!-- 玩法偏好 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-purple-500/10 text-purple-600 text-[11px] font-medium rounded-sm leading-normal tracking-wide">玩法<br>偏好</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">🎱 偏爱中式八球 · 斯诺克进阶中 · 最近对花式九球也有兴趣</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:系统</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">中式八球占比 60%,斯诺克 30%;近2周开始尝试花式九球,技术水平中等偏上</p>
|
||||
</div>
|
||||
<!-- 重要反馈 -->
|
||||
<div class="bg-gray-50 rounded-xl border border-gray-100 p-3">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="shrink-0 w-10 h-10 flex items-center justify-center px-0.5 bg-error/10 text-error text-[11px] font-medium rounded-sm leading-normal tracking-wide">重要<br>反馈</span>
|
||||
<div class="flex-1 relative min-h-[2.5rem]">
|
||||
<p class="text-sm text-gray-13 leading-snug line-clamp-2">⚠️ 上次提到想练斯诺克走位</p>
|
||||
<span class="absolute bottom-0 right-0 text-[11px] text-gray-6 whitespace-nowrap bg-gray-50 pl-1">By:小燕</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs text-gray-7 mt-2 leading-relaxed">2月7日到店时主动提及,希望有针对性的走位训练;建议下次安排斯诺克专项课程</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 我给TA的备注 -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">我给TA的备注</h2>
|
||||
<span class="text-xs text-gray-6">3 条备注</span>
|
||||
</div>
|
||||
<div id="noteList" class="space-y-3">
|
||||
<div class="note-card-wrap p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<p class="text-xs text-gray-6">2026-02-05</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="star-rating" data-score="7"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">已通过微信联系王先生,表示对新到的斯诺克球桌感兴趣,周末可能来体验。</p>
|
||||
</div>
|
||||
<div class="note-card-wrap p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<p class="text-xs text-gray-6">2026-01-20</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="star-rating" data-score="7"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">王先生最近出差较多,到店频率降低。建议等他回来后再约。</p>
|
||||
</div>
|
||||
<div class="note-card-wrap p-3.5 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<p class="text-xs text-gray-6">2026-01-08</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="star-rating" data-score="7"><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:100%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:50%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span><span class="star"><svg class="star-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><span class="star-fill" style="width:0%"><svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span></span></div>
|
||||
<button onclick="confirmDeleteNote()" class="shrink-0 w-7 h-7 flex items-center justify-center rounded-lg bg-white border border-gray-200 text-gray-5">
|
||||
<svg class="w-3.5 h-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-9 leading-relaxed">上次到店时推荐了会员续费活动,客户说考虑一下。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="noteEmpty" class="text-center py-6 hidden">
|
||||
<svg class="w-10 h-10 text-gray-4 mx-auto mb-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
<p class="text-sm text-gray-5">暂无备注</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 近期服务记录(置底) -->
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="section-title blue text-sm font-semibold text-gray-13">近期服务记录</h2>
|
||||
<span class="text-xs text-gray-6">共 3 次</span>
|
||||
</div>
|
||||
<!-- 汇总统计 -->
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="flex-1 text-center py-2.5 bg-primary/5 rounded-xl">
|
||||
<p class="text-lg font-bold text-primary">6.0<span class="text-xs font-normal text-gray-6 ml-0.5">h</span></p>
|
||||
<p class="text-[11px] text-gray-6 mt-0.5">总时长</p>
|
||||
</div>
|
||||
<div class="flex-1 text-center py-2.5 bg-success/5 rounded-xl">
|
||||
<p class="text-lg font-bold text-success">¥510</p>
|
||||
<p class="text-[11px] text-gray-6 mt-0.5">总收入</p>
|
||||
</div>
|
||||
<div class="flex-1 text-center py-2.5 bg-warning/5 rounded-xl">
|
||||
<p class="text-lg font-bold text-warning">¥170</p>
|
||||
<p class="text-[11px] text-gray-6 mt-0.5">场均</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 记录列表 -->
|
||||
<div class="space-y-2.5">
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">A12号台</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration text-base">2.5h</span>
|
||||
</div>
|
||||
<span class="svc-income text-base">¥200</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 百威x2 红牛x1</span>
|
||||
<span class="svc-date text-xs">2026-02-07 21:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">3号台</span>
|
||||
<span class="svc-type basic">基础课</span>
|
||||
<span class="svc-duration text-base">2.0h</span>
|
||||
</div>
|
||||
<span class="svc-income text-base">¥160</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 可乐x1</span>
|
||||
<span class="svc-date text-xs">2026-02-01 20:30</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="svc-record">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="svc-table">VIP1号房</span>
|
||||
<span class="svc-type incentive">激励课</span>
|
||||
<span class="svc-duration text-base">1.5h</span>
|
||||
</div>
|
||||
<span class="svc-income text-base">¥150</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="svc-drinks">🍷 芝华士x1 矿泉水x2</span>
|
||||
<span class="svc-date text-xs">2026-01-28 19:00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 text-center">
|
||||
<button onclick="window.location.href='customer-service-records.html'" class="text-xs text-primary font-medium">查看全部服务记录 →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<div class="fixed bottom-0 left-0 right-0 h-16 bg-white/95 backdrop-blur-lg border-t border-gray-2 flex items-center gap-3 px-4">
|
||||
<button onclick="window.location.href='chat.html'" class="flex-1 h-11 bg-gradient-to-r from-primary to-blue-500 text-white font-medium rounded-xl flex items-center justify-center gap-2 shadow-lg shadow-primary/30">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/>
|
||||
</svg>
|
||||
问问助手
|
||||
</button>
|
||||
<button onclick="showNoteModal()" class="flex-1 h-11 bg-gray-100 text-gray-13 font-medium rounded-xl flex items-center justify-center gap-2">
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
</svg>
|
||||
备注
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 备注弹窗 -->
|
||||
<div id="noteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-end">
|
||||
<div class="w-full bg-white rounded-t-3xl p-5 pb-8">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-base font-semibold text-gray-13">添加备注</span>
|
||||
<button id="noteExpandBtn" onclick="expandNoteRating()" class="note-expand-btn">展开评价 ▾</button>
|
||||
</div>
|
||||
<button onclick="hideNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div id="noteRatingSection" class="hidden">
|
||||
<!-- 星星打分:再次服务意愿 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再次服务此客户</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不想</span><span></span><span>一般</span><span></span><span>非常想</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 星星打分:再来店可能性 -->
|
||||
<div class="note-rating-group">
|
||||
<span class="note-rating-label">再来店可能性</span>
|
||||
<div class="note-rating-right">
|
||||
<div class="note-rating-row" data-score="0">
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
<span class="nr-star"><svg class="nr-empty" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg><svg class="nr-filled" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg></span>
|
||||
</div>
|
||||
<div class="note-rating-hints"><span>不可能</span><span></span><span>不好说</span><span></span><span>肯定能</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="noteText" class="w-full h-32 p-4 bg-gray-50 rounded-xl resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-primary/20 border border-gray-100" placeholder="请输入备注内容..."></textarea>
|
||||
<button onclick="saveNote()" class="w-full h-12 bg-gradient-to-r from-primary to-blue-500 text-white font-medium rounded-xl mt-4 shadow-lg shadow-primary/30">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除备注确认弹窗 -->
|
||||
<div id="deleteNoteModal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center px-6">
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-xl">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<span class="text-base font-semibold text-gray-13">删除备注</span>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 mb-5">确定要删除这条备注吗?删除后无法恢复。</p>
|
||||
<button onclick="deleteNote()" class="w-full h-12 bg-gradient-to-r from-error to-red-400 text-white font-medium rounded-xl shadow-lg shadow-error/30 text-sm">确认删除</button>
|
||||
<button onclick="hideDeleteNoteModal()" class="w-full text-center text-sm text-gray-6 py-2 mt-2 bg-transparent border-0 cursor-pointer">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 放弃弹窗 -->
|
||||
<div id="abandonModal" class="fixed inset-0 bg-black/50 z-50 hidden items-center justify-center px-6">
|
||||
<div class="w-full max-w-sm bg-white rounded-2xl p-5 shadow-xl">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<span class="text-base font-semibold text-gray-13">放弃维护</span>
|
||||
<button onclick="hideAbandonModal()" class="w-8 h-8 flex items-center justify-center rounded-full bg-gray-100">
|
||||
<svg class="w-4 h-4 text-gray-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 mb-3">请填写放弃原因(必填):</p>
|
||||
<textarea id="abandonReason" class="w-full h-28 p-4 bg-gray-50 rounded-xl resize-none text-sm text-gray-13 placeholder-gray-5 focus:outline-none focus:ring-2 focus:ring-primary/20 border border-gray-100" placeholder="请输入放弃维护该客户的原因..."></textarea>
|
||||
<p id="abandonError" class="text-xs text-error mt-1.5 hidden">请输入放弃原因后再提交</p>
|
||||
<button onclick="submitAbandon()" class="w-full h-12 bg-gradient-to-r from-error to-red-400 text-white font-medium rounded-xl mt-4 shadow-lg shadow-error/30 text-sm">确认原因 放弃该客户的维护</button>
|
||||
<button onclick="hideAbandonModal()" class="w-full text-center text-sm text-gray-6 py-2 mt-2 bg-transparent border-0 cursor-pointer">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast 提示 -->
|
||||
<div id="toast" class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-13/80 text-white text-sm px-6 py-3 rounded-xl z-[100] hidden backdrop-blur-sm"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,665 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>任务列表 - 球房运营助手</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="../css/banner.css" rel="stylesheet">
|
||||
<link href="../css/ai-icons.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
/* 任务卡片边框颜色 */
|
||||
.task-card {
|
||||
position: relative;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
.task-card.high-priority {
|
||||
border-left-color: #f43f5e;
|
||||
}
|
||||
.task-card.priority {
|
||||
border-left-color: #f97316;
|
||||
}
|
||||
.task-card.relationship {
|
||||
border-left-color: #ec4899;
|
||||
}
|
||||
.task-card.callback {
|
||||
border-left-color: #14b8a6;
|
||||
}
|
||||
/* 标签颜色 - 圆角矩形 */
|
||||
.tag-high-priority {
|
||||
background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tag-priority {
|
||||
background: linear-gradient(135deg, #ea580c 0%, #f97316 100%);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tag-relationship {
|
||||
background: linear-gradient(135deg, #db2777 0%, #ec4899 100%);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.tag-callback {
|
||||
background: linear-gradient(135deg, #0d9488 0%, #14b8a6 100%);
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* 进度条动画 */
|
||||
.progress-bar {
|
||||
background: linear-gradient(90deg, #f59e0b 0%, #fbbf24 50%, #fcd34d 100%);
|
||||
transition: width 0.6s ease-out;
|
||||
}
|
||||
/* 6段档位进度条 */
|
||||
.tier-progress {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
height: 8px;
|
||||
}
|
||||
.tier-segment {
|
||||
border-radius: 2px;
|
||||
background: rgba(255,255,255,0.25);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tier-segment.completed {
|
||||
background: linear-gradient(135deg, #34d399 0%, #10b981 100%);
|
||||
}
|
||||
.tier-segment.current {
|
||||
background: linear-gradient(90deg, rgba(255,255,255,0.25) 0%, rgba(255,255,255,0.25) 50%, rgba(255,255,255,0.25) 100%);
|
||||
overflow: hidden;
|
||||
}
|
||||
.tier-segment.current .tier-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
/* 红戳样式 - 透明印章风格 */
|
||||
.red-stamp {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.stamp-badge {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
right: -28px;
|
||||
transform: rotate(-12deg) scale(0);
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border: 3px solid rgb(239, 68, 68);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
box-shadow:
|
||||
inset 0 0 0 2px rgba(255, 255, 255, 0.95),
|
||||
inset 0 0 10px 2px rgba(255, 255, 255, 0.7),
|
||||
inset 0 0 20px 4px rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
/* 盖戳动画 */
|
||||
@keyframes stampDown {
|
||||
0% {
|
||||
transform: rotate(-12deg) scale(3);
|
||||
opacity: 0;
|
||||
}
|
||||
50% {
|
||||
transform: rotate(-12deg) scale(0.9);
|
||||
opacity: 0.9;
|
||||
}
|
||||
70% {
|
||||
transform: rotate(-12deg) scale(1.05);
|
||||
opacity: 0.85;
|
||||
}
|
||||
100% {
|
||||
transform: rotate(-12deg) scale(1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
.stamp-badge.stamp-animate {
|
||||
animation: stampDown 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
||||
}
|
||||
.stamp-badge .thumb {
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
.stamp-badge .stamp-text {
|
||||
font-size: 11px;
|
||||
color: rgb(220, 38, 38);
|
||||
font-weight: bold;
|
||||
margin-top: 1px;
|
||||
text-shadow:
|
||||
0 0 2px rgba(255,255,255,1),
|
||||
0 0 4px rgba(255,255,255,0.9),
|
||||
1px 1px 0 rgba(255,255,255,0.9),
|
||||
-1px -1px 0 rgba(255,255,255,0.9),
|
||||
1px -1px 0 rgba(255,255,255,0.9),
|
||||
-1px 1px 0 rgba(255,255,255,0.9);
|
||||
}
|
||||
/* 进度条按比例宽度:0-100(45.45%), 100-130(13.64%), 130-160(13.64%), 160-190(13.64%), 190-220(13.64%) */
|
||||
.tier-segment-0 { flex: 100; }
|
||||
.tier-segment-1 { flex: 30; }
|
||||
.tier-segment-2 { flex: 30; }
|
||||
.tier-segment-3 { flex: 30; }
|
||||
.tier-segment-4 { flex: 30; }
|
||||
/* 下降趋势样式 */
|
||||
.trend-down {
|
||||
color: rgba(255,255,255,0.5);
|
||||
font-size: 12px;
|
||||
}
|
||||
/* 业绩卡片文字样式 */
|
||||
.stat-value {
|
||||
color: #ffffff;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.25);
|
||||
}
|
||||
.stat-highlight {
|
||||
color: #6ee7b7;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
}
|
||||
.stat-label {
|
||||
color: rgba(255,255,255,0.9);
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||||
}
|
||||
.stat-secondary {
|
||||
color: rgba(255,255,255,0.7);
|
||||
}
|
||||
.stat-accent {
|
||||
color: #fcd34d;
|
||||
text-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
}
|
||||
/* 奖金金额突出样式 */
|
||||
.bonus-amount {
|
||||
text-shadow:
|
||||
0 2px 4px rgba(0, 0, 0, 0.35),
|
||||
0 0 12px rgba(251, 191, 36, 0.5);
|
||||
}
|
||||
/* === 任务分区 === */
|
||||
.section-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* 置顶卡片微亮边框 */
|
||||
.task-card.pinned {
|
||||
box-shadow: 0 1px 4px rgba(245, 158, 11, 0.12), 0 0 0 1px rgba(245, 158, 11, 0.08);
|
||||
}
|
||||
/* 放弃任务 */
|
||||
.task-card.abandoned {
|
||||
border-left-color: #d1d5db !important;
|
||||
opacity: 0.55;
|
||||
}
|
||||
.task-card.abandoned .task-name {
|
||||
color: #9ca3af;
|
||||
}
|
||||
.task-card.abandoned .task-desc {
|
||||
color: #c5c5c5;
|
||||
}
|
||||
.task-card.abandoned .task-tag-wrap > span:first-child {
|
||||
background: #d1d5db !important;
|
||||
}
|
||||
/* 备注指示器 */
|
||||
.note-indicator {
|
||||
font-size: 12px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
/* === 长按上下文菜单 === */
|
||||
.context-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
z-index: 100;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
.context-overlay.active {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
z-index: 101;
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
|
||||
min-width: 192px;
|
||||
padding: 6px 0;
|
||||
opacity: 0;
|
||||
transform: scale(0.88);
|
||||
pointer-events: none;
|
||||
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||
transform-origin: top left;
|
||||
}
|
||||
.context-menu.active {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
pointer-events: all;
|
||||
}
|
||||
.ctx-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 13px 18px;
|
||||
font-size: 14px;
|
||||
color: #393939;
|
||||
cursor: pointer;
|
||||
transition: background 0.12s;
|
||||
user-select: none;
|
||||
}
|
||||
.ctx-item:active {
|
||||
background: #f3f3f3;
|
||||
}
|
||||
.ctx-item + .ctx-item {
|
||||
border-top: 1px solid #f3f3f3;
|
||||
}
|
||||
/* === 备注 / 放弃弹窗 === */
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding-top: 18vh;
|
||||
padding-bottom: 40vh;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
.modal-overlay.active {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
.modal-card {
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
width: 88%;
|
||||
max-width: 360px;
|
||||
padding: 24px 20px 20px;
|
||||
transform: translateY(24px);
|
||||
transition: transform 0.25s ease;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.modal-overlay.active .modal-card {
|
||||
transform: translateY(0);
|
||||
}
|
||||
.modal-card textarea {
|
||||
width: 100%;
|
||||
border: 1.5px solid #e7e7e7;
|
||||
border-radius: 10px;
|
||||
padding: 12px 14px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
resize: none;
|
||||
outline: none;
|
||||
font-family: inherit;
|
||||
color: #2c2c2c;
|
||||
transition: border-color 0.2s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.modal-card textarea:focus {
|
||||
border-color: #0052d9;
|
||||
}
|
||||
.modal-card textarea.error-border {
|
||||
border-color: #e34d59;
|
||||
}
|
||||
.modal-error {
|
||||
color: #e34d59;
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
display: none;
|
||||
}
|
||||
.modal-error.show {
|
||||
display: block;
|
||||
}
|
||||
.modal-submit-btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
margin-top: 14px;
|
||||
transition: background 0.2s, opacity 0.2s;
|
||||
font-family: inherit;
|
||||
}
|
||||
.modal-submit-btn.primary {
|
||||
background: #0052d9;
|
||||
color: #fff;
|
||||
}
|
||||
.modal-submit-btn.primary:active {
|
||||
background: #003eb3;
|
||||
}
|
||||
.modal-submit-btn.danger {
|
||||
background: #e34d59;
|
||||
color: #fff;
|
||||
}
|
||||
.modal-submit-btn.danger:active {
|
||||
background: #c9363f;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-1 min-h-screen">
|
||||
<!-- 顶部区域 - 用户信息和业绩卡片 -->
|
||||
<div class="banner-bg theme-blue texture-aurora text-white pb-4">
|
||||
<!-- 用户信息 -->
|
||||
<div class="px-5 pt-10 pb-3">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-14 h-14 rounded-2xl bg-white/20 backdrop-blur-sm flex items-center justify-center shadow-lg overflow-hidden">
|
||||
<img src="../img/zjtx.png" class="w-full h-full object-cover" alt="助教头像">
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="text-xl font-semibold">小燕</span>
|
||||
<span class="px-2 py-0.5 bg-white/20 rounded-full text-xs">助教</span>
|
||||
</div>
|
||||
<p class="text-white/70 text-sm">广州朗朗桌球</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 业绩进度卡片 -->
|
||||
<div class="mx-4">
|
||||
<div class="bg-white/15 backdrop-blur-md rounded-2xl px-4 py-3 border border-white/20">
|
||||
<!-- 第一层:标题行 -->
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-baseline gap-2">
|
||||
<span class="stat-label text-sm font-medium">距离100小时仅剩</span>
|
||||
<span class="stat-accent text-xl font-bold">12.5小时</span>
|
||||
</div>
|
||||
<a href="performance.html" class="stat-secondary text-xs flex items-center gap-1 hover:text-white transition-colors">
|
||||
查看详情
|
||||
<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 第二层:5段档位进度条 + 边界小时数(按比例宽度) -->
|
||||
<div class="relative mb-6">
|
||||
<div class="tier-progress">
|
||||
<div class="tier-segment tier-segment-0 completed" title="0档 <100h"></div>
|
||||
<div class="tier-segment tier-segment-1 current" title="1档 100-130h">
|
||||
<div class="tier-fill" style="width: 58%"></div>
|
||||
</div>
|
||||
<div class="tier-segment tier-segment-2" title="2档 130-160h"></div>
|
||||
<div class="tier-segment tier-segment-3" title="3档 160-190h"></div>
|
||||
<div class="tier-segment tier-segment-4" title="4档 190-220h"></div>
|
||||
</div>
|
||||
<!-- 档位边界小时数(按比例定位:0, 100/220≈45.45%, 130/220≈59.09%, 160/220≈72.73%, 190/220≈86.36%, 220/220=100%) -->
|
||||
<div class="absolute w-full top-full mt-1.5 flex text-[9px]" style="left: 0;">
|
||||
<span class="text-white/60" style="position:absolute; left:0; transform:translateX(0);">0</span>
|
||||
<span class="text-white/60" style="position:absolute; left:45.45%; transform:translateX(-50%);">100</span>
|
||||
<span class="text-white/80 font-medium" style="position:absolute; left:59.09%; transform:translateX(-50%);">130</span>
|
||||
<span class="text-white/60" style="position:absolute; left:72.73%; transform:translateX(-50%);">160</span>
|
||||
<span class="text-white/60" style="position:absolute; left:86.36%; transform:translateX(-50%);">190</span>
|
||||
<span class="text-white/60" style="position:absolute; right:0; transform:translateX(0);">220</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第三层:核心数据 - 两列布局(左宽右窄) -->
|
||||
<div class="flex items-stretch mb-2.5">
|
||||
<!-- 左侧:课时数据 + 红戳(占60%) -->
|
||||
<div class="pr-4 border-r border-white/25 flex justify-center items-center" style="flex: 3;">
|
||||
<!-- 自动宽度容器:包含课时数据和红戳,居中显示 -->
|
||||
<div class="red-stamp inline-block relative" style="padding-right: 35px;">
|
||||
<div class="text-center">
|
||||
<div class="flex items-baseline justify-center gap-1.5">
|
||||
<span class="stat-highlight text-xl font-bold">77.5</span>
|
||||
<span class="stat-secondary text-sm">|</span>
|
||||
<span class="stat-accent text-xl font-bold">12</span>
|
||||
<span class="stat-secondary text-sm">|</span>
|
||||
<span class="stat-value text-xl font-bold">87.5</span>
|
||||
</div>
|
||||
<p class="stat-label text-xs mt-1.5">基础课 | 激励课 | 全部</p>
|
||||
</div>
|
||||
<!-- 红戳徽章 -->
|
||||
<div class="stamp-badge" style="right: -5px; top: 5px;">
|
||||
<span class="thumb">👍</span>
|
||||
<span class="stamp-text">已完成</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧:奖金激励(占40%) -->
|
||||
<div class="pl-3 text-center flex flex-col justify-center" style="flex: 2;">
|
||||
<div class="bonus-amount">
|
||||
<span class="text-3xl font-bold text-amber-300">800</span>
|
||||
<span class="text-base text-amber-300/80">元</span>
|
||||
</div>
|
||||
<p class="stat-label text-xs mt-1.5">达100h即得</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第四层:预计收入 -->
|
||||
<div class="flex items-center justify-between pt-2 border-t border-white/25">
|
||||
<span class="stat-label text-xs">2月预计收入 | 比1月同期</span>
|
||||
<a href="performance.html" class="flex items-center gap-1.5 group">
|
||||
<span class="stat-value text-lg font-bold">¥6,206</span>
|
||||
<span class="trend-down">↓368</span>
|
||||
<svg class="w-3.5 h-3.5 stat-secondary group-hover:text-white transition-colors" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 待办任务列表 -->
|
||||
<div class="px-4 py-5">
|
||||
<!-- 标题 -->
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-base font-semibold text-gray-13">今日 客户维护</h2>
|
||||
<span class="text-sm text-gray-6">共 7 项</span>
|
||||
</div>
|
||||
|
||||
<!-- 📌 置顶区域 -->
|
||||
<div class="mb-5">
|
||||
<div class="flex items-center gap-1.5 mb-2.5">
|
||||
<span class="section-label text-amber-700 bg-amber-50">📌 置顶</span>
|
||||
<span class="text-sm text-gray-6">2项</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<!-- 置顶: 王先生 -->
|
||||
<div class="task-card high-priority pinned block bg-white rounded-xl p-4 shadow-sm cursor-pointer" data-task-id="1" data-task-name="王先生" data-task-type="high-priority">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-high-priority px-2 py-0.5 text-white text-xs font-medium">高优先召回</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">王先生</span>
|
||||
<span class="text-sm">💖</span>
|
||||
<span class="note-indicator" title="有备注">📝</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:15天前 · 余额:非常多</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>高流失风险,建议尽快联系</p>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-5 flex-shrink-0 ml-2 mt-1" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 置顶: 李女士 -->
|
||||
<div class="task-card high-priority pinned block bg-white rounded-xl p-4 shadow-sm cursor-pointer" data-task-id="2" data-task-name="李女士" data-task-type="high-priority">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-high-priority px-2 py-0.5 text-white text-xs font-medium">高优先召回</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">李女士</span>
|
||||
<span class="text-sm">🧡</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:20天前 · 余额:非常多</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>VIP客户,储值余额较多</p>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-5 flex-shrink-0 ml-2 mt-1" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 一般任务区域 -->
|
||||
<div class="mb-5">
|
||||
<div class="flex items-center gap-1.5 mb-2.5">
|
||||
<span class="section-label text-gray-9 bg-gray-2">一般任务</span>
|
||||
<span class="text-sm text-gray-6">3项</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<!-- 张先生 -->
|
||||
<div class="task-card priority block bg-white rounded-xl p-4 shadow-sm cursor-pointer" data-task-id="3" data-task-name="张先生" data-task-type="priority">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-priority px-2 py-0.5 text-white text-xs font-medium">优先召回</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">张先生</span>
|
||||
<span class="text-sm">💛</span>
|
||||
<span class="note-indicator" title="有备注">📝</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:10天前 · 余额:一般</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>消费频率下降,需关注</p>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-5 flex-shrink-0 ml-2 mt-1" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 刘先生 -->
|
||||
<div class="task-card priority block bg-white rounded-xl p-4 shadow-sm cursor-pointer" data-task-id="4" data-task-name="刘先生" data-task-type="priority">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-priority px-2 py-0.5 text-white text-xs font-medium">优先召回</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">刘先生</span>
|
||||
<span class="text-sm">💙</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:8天前 · 余额:一般</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>偏好晚间时段,可推荐夜场套餐</p>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-5 flex-shrink-0 ml-2 mt-1" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 陈先生 -->
|
||||
<div class="task-card relationship block bg-white rounded-xl p-4 shadow-sm cursor-pointer" data-task-id="5" data-task-name="陈先生" data-task-type="relationship">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-relationship px-2 py-0.5 text-white text-xs font-medium">关系构建</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">陈先生</span>
|
||||
<span class="text-sm">💙</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:5天前 · 余额:无</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc"><span class="ai-inline-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="5" y="7" width="14" height="12" rx="4" fill="white"/><path d="M12 7V4" stroke="white" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="3" r="1.5" fill="white"/><circle cx="9" cy="11.5" r="2" fill="#667eea"/><circle cx="15" cy="11.5" r="2" fill="#667eea"/><circle cx="9.5" cy="11" r="0.7" fill="white"/><circle cx="15.5" cy="11" r="0.7" fill="white"/><path d="M9.5 15C10 16 14 16 14.5 15" stroke="#667eea" stroke-width="1.5" stroke-linecap="round"/><circle cx="7" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><circle cx="17" cy="13.5" r="1" fill="#f5a0c0" opacity="0.6"/><rect x="3" y="10" width="2" height="4" rx="1" fill="white"/><rect x="19" y="10" width="2" height="4" rx="1" fill="white"/></svg></span>潜力客户,建议加强互动</p>
|
||||
</div>
|
||||
<svg class="w-5 h-5 text-gray-5 flex-shrink-0 ml-2 mt-1" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="9 18 15 12 9 6"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ❌ 放弃的任务区域 -->
|
||||
<div class="mb-2">
|
||||
<div class="flex items-center gap-1.5 mb-2.5">
|
||||
<span class="section-label text-gray-6 bg-gray-2">已放弃</span>
|
||||
<span class="text-sm text-gray-6">2项</span>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<!-- 放弃: 赵女士 -->
|
||||
<div class="task-card callback abandoned block bg-white rounded-xl p-4 shadow-sm" data-task-id="6" data-task-name="赵女士" data-task-type="callback">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-callback px-2 py-0.5 text-white text-xs font-medium">客户回访</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">赵女士</span>
|
||||
<span class="text-sm">🧡</span>
|
||||
<span class="note-indicator" title="有备注">📝</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:3天前 · 余额:非常多</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc">放弃原因:客户已转会至其他球房</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 放弃: 周先生 -->
|
||||
<div class="task-card callback abandoned block bg-white rounded-xl p-4 shadow-sm" data-task-id="7" data-task-name="周先生" data-task-type="callback">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2 mb-1.5 task-tag-wrap">
|
||||
<span class="tag-callback px-2 py-0.5 text-white text-xs font-medium">客户回访</span>
|
||||
<span class="text-base font-semibold text-gray-13 task-name">周先生</span>
|
||||
<span class="text-sm">💛</span>
|
||||
<span class="note-indicator" title="有备注">📝</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-7 leading-relaxed task-desc">最近到店:5天前 · 余额:一般</p>
|
||||
<p class="text-sm text-gray-6 leading-relaxed task-desc">放弃原因:联系方式失效,无法触达</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 长按上下文菜单 -->
|
||||
<div class="context-overlay" id="contextOverlay"></div>
|
||||
<div class="context-menu" id="contextMenu">
|
||||
<div class="ctx-item" data-action="pin">
|
||||
<span>📌</span><span>置顶任务</span>
|
||||
</div>
|
||||
<div class="ctx-item" data-action="abandon">
|
||||
<span>❌</span><span>放弃任务</span>
|
||||
</div>
|
||||
<div class="ctx-item" data-action="ai">
|
||||
<span>🤖</span><span>问问AI助手</span>
|
||||
</div>
|
||||
<div class="ctx-item" data-action="remark">
|
||||
<span>📝</span><span>备注</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 备注 / 放弃 弹窗(可复用组件) -->
|
||||
<div class="modal-overlay" id="remarkModal">
|
||||
<div class="modal-card">
|
||||
<h3 class="text-base font-semibold text-gray-13 mb-1" id="modalTitle">添加备注</h3>
|
||||
<p class="text-xs text-gray-6 mb-3" id="modalSubtitle">为该客户的维护任务添加备注</p>
|
||||
<textarea id="remarkInput" rows="4" placeholder="请输入备注内容..."></textarea>
|
||||
<div class="modal-error" id="remarkError">请填写放弃原因,不能为空</div>
|
||||
<button class="modal-submit-btn primary" id="modalSubmitBtn">保存备注</button>
|
||||
<button class="mt-2 w-full text-center text-sm text-gray-6 py-2 bg-transparent border-0 cursor-pointer" id="modalCancelBtn">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI 标识配色 -->
|
||||
|
||||
|
||||
<!-- 悬浮助手按钮 -->
|
||||
|
||||
|
||||
<!-- 通用底部导航 -->
|
||||
|
||||
|
||||
<!-- 盖戳动画 -->
|
||||
|
||||
|
||||
<!-- 长按菜单 + 备注弹窗 交互 -->
|
||||
|
||||
</body>
|
||||
|
Before Width: | Height: | Size: 601 KiB |
|
Before Width: | Height: | Size: 316 KiB |
|
Before Width: | Height: | Size: 329 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 193 KiB |
|
Before Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 383 KiB |