diff --git a/Moncter/runtime/logs/workerman.log b/Moncter/runtime/logs/workerman.log index 9f4c1a7e..36fd4faa 100644 --- a/Moncter/runtime/logs/workerman.log +++ b/Moncter/runtime/logs/workerman.log @@ -3,3 +3,7 @@ 2025-11-07 18:26:50 pid:842 Workerman[start.php] received signal SIGHUP 2025-11-07 18:26:50 pid:842 Workerman[start.php] stopping 2025-11-07 18:26:50 pid:842 Workerman[start.php] has been stopped +2026-01-05 10:45:32 pid:112703 Workerman[start.php] reloading +2026-01-05 10:46:34 pid:112703 Workerman[start.php] received signal SIGINT +2026-01-05 10:46:34 pid:112703 Workerman[start.php] stopping +2026-01-05 10:46:34 pid:112703 Workerman[start.php] has been stopped diff --git a/Moncter/提示词/106服务器消费记录采集表分析.md b/Moncter/提示词/106服务器消费记录采集表分析.md new file mode 100644 index 00000000..7c9e4953 --- /dev/null +++ b/Moncter/提示词/106服务器消费记录采集表分析.md @@ -0,0 +1,164 @@ +# 106服务器消费记录采集表分析报告 + +## 分析时间 +2025年12月 + +## 消费记录Handler字段要求 + +### 必填字段 +- `amount` (消费金额) - 必填 +- `actual_amount` (实际支付金额) - 必填 +- `consume_time` (消费时间) - 必填 + +### 用户标识字段(三选一,Handler会自动解析) +- `phone_number` (手机号) - 推荐 +- `id_card` (身份证) - 推荐 +- `user_id` (用户ID) - 如果源数据已有可直接使用 + +### 门店标识字段(二选一,Handler会自动转换) +- `store_name` (门店名称) - 推荐 +- `store_id` (门店ID) - 如果源数据已有可直接使用 + +### 可选字段 +- `currency` (币种) - 默认CNY +- `status` (记录状态) - 默认0 + +--- + +## 支持消费记录采集的表 + +### ✅ 1. KR_商城.21年贝蒂喜订单整合 + +**数据库**: `KR_商城` +**集合**: `21年贝蒂喜订单整合` +**记录数**: 10,439条 +**数据状态**: ✅ 可用 + +#### 字段映射关系 + +| 目标字段 | 源字段 | 字段类型 | 说明 | +|---------|--------|---------|------| +| `phone_number` | `联系手机` | String | 手机号(需去除单引号前缀) | +| `store_name` | `店铺名称` | String | 门店名称(如:贝蒂喜旗舰店) | +| `amount` | `买家应付货款` 或 `总金额` | String→Float | 消费金额(需转换为数字) | +| `actual_amount` | `买家实际支付金额` | String→Float | 实际支付金额(需转换为数字,可能为"0") | +| `consume_time` | `订单付款时间` 或 `订单创建时间` | String→DateTime | 消费时间(格式:YYYY-MM-DD HH:mm:ss) | +| `store_id` | `店铺Id` | String | 门店ID(如:"0") | +| `status` | `订单状态` | String→Int | 订单状态(需转换:交易成功 →0,交易关闭 →1) | + +#### 字段说明 + +**源字段详情**: +- `联系手机`: 格式为 `'13759198903`(带单引号前缀),需要处理 +- `买家实际支付金额`: 可能是字符串 "0"(表示未支付),需要过滤或处理 +- `订单付款时间`: 可能为 null(未支付订单),优先使用此字段 +- `订单创建时间`: 作为备用时间字段 +- `订单状态`: 示例值:"卖家已发货,等待买家确认"、"交易关闭" 等 + +#### 数据示例 +```json +{ + "_id": "68ad49c51d4abb1611aee2b9", + "联系手机": "'13759198903", + "买家应付货款": "248", + "总金额": "248", + "买家实际支付金额": "248", + "订单状态": "卖家已发货,等待买家确认", + "订单创建时间": "2021-01-31 23:44:53", + "订单付款时间": "2021-01-31 23:45:06", + "店铺名称": "贝蒂喜旗舰店", + "店铺Id": "0" +} +``` + +#### 推荐配置 + +**字段映射配置**: +```json +{ + "phone_number": "联系手机", + "amount": "买家应付货款", + "actual_amount": "买家实际支付金额", + "consume_time": "订单付款时间", + "store_name": "店铺名称" +} +``` + +**转换函数**: +- `联系手机`: 使用 `parse_phone` 去除单引号并验证 +- `买家应付货款` / `买家实际支付金额`: 使用 `parse_amount` 转换为数字 +- `订单付款时间`: 使用 `parse_datetime` 解析时间 +- `订单状态`: 自定义转换逻辑(正常→0,关闭→2) + +**过滤条件建议**: +- 过滤 `买家实际支付金额` 为 "0" 或 null 的记录(未支付订单) +- 过滤 `订单付款时间` 为 null 的记录(未支付订单) +- 或保留所有记录,在Handler中根据状态判断 + +--- + +## 其他数据库分析 + +### ❌ 2. KR_商城.凡客诚品_vancl.com +**状态**: ❌ 不支持 +**原因**: 仅包含地址、姓名、电话信息,无金额、时间等消费记录字段 + +### ❌ 3. KR_商城.嘟嘟牛 +**状态**: ❌ 不支持 +**原因**: 仅包含邮箱、用户名、密码等账户信息,无消费记录字段 + +### ❌ 4. KR_商城.购物-北京一电购公司2月整理版30万 +**状态**: ❌ 不支持 +**原因**: 仅包含号码、名字、省市等基本信息,无消费记录字段 + +### ❌ 5. KR_淘宝.卖家邮箱(去重复后300万) +**状态**: ❌ 不支持 +**原因**: 仅包含邮箱字段,无消费记录相关信息 + +### ❌ 6. KR_卡若私域.老坑爹商店 shop.lkdie.com +**状态**: ❌ 不支持 +**原因**: 包含用户账户信息(邮箱、手机、密码等),但无订单、支付等消费记录字段 + +--- + +## 总结 + +### 可用的表 +1. **KR_商城.21年贝蒂喜订单整合** ✅ + +### 使用建议 + +1. **数据预处理**: + - 手机号字段需要去除单引号前缀 + - 金额字段需要从字符串转换为数字 + - 时间字段格式为 `YYYY-MM-DD HH:mm:ss`,需要解析 + +2. **数据过滤**: + - 建议过滤未支付的订单(`买家实际支付金额` 为 "0" 或 `订单付款时间` 为 null) + - 或根据 `订单状态` 字段过滤无效订单 + +3. **字段映射**: + - 使用 `订单付款时间` 作为 `consume_time`(优先) + - 如果 `订单付款时间` 为空,可以使用 `订单创建时间` 作为备用 + - `店铺名称` 可以映射到 `store_name`,Handler会自动转换为 `store_id` + +4. **注意事项**: + - 该集合包含2021年的订单数据 + - 数据量:10,439条记录 + - 部分订单可能未支付,需要根据业务需求决定是否采集 + +--- + +## 下一步操作 + +1. 在TaskForm中创建采集任务 +2. 配置数据源:选择106服务器(ckb数据库) +3. 选择Handler:`消费记录处理(ConsumptionCollectionHandler)` +4. 配置源数据: + - 数据库:`KR_商城` + - 集合:`21年贝蒂喜订单整合` +5. 配置字段映射(按上述映射关系) +6. 配置过滤条件(可选):过滤未支付订单 +7. 预览查询结果验证字段映射 +8. 保存并启动采集任务 + diff --git a/Moncter/提示词/QueryBuilder折叠功能说明.md b/Moncter/提示词/QueryBuilder折叠功能说明.md new file mode 100644 index 00000000..99d01a45 --- /dev/null +++ b/Moncter/提示词/QueryBuilder折叠功能说明.md @@ -0,0 +1,319 @@ +# QueryBuilder 折叠功能说明 + +## 更新概览 + +为了改善用户体验,QueryBuilder 组件的过滤条件和联表查询区域现在支持折叠,默认为折叠状态,让界面更加简洁。 + +--- + +## 功能特性 + +### 1. 默认折叠状态 + +**过滤条件(WHERE)**: +- 默认:折叠 +- 图标:`→` (折叠) / `↓` (展开) +- 点击标题栏任意位置即可切换 + +**联表查询(JOIN/LOOKUP)**: +- 默认:折叠 +- 图标:`→` (折叠) / `↓` (展开) +- 点击标题栏任意位置即可切换 + +### 2. 智能展开 + +**自动展开时机**: +- 点击"添加条件"按钮 → 自动展开过滤条件区域 +- 点击"添加关联"按钮 → 自动展开联表查询区域 + +**好处**: +- 用户添加配置时自动展开,无需手动操作 +- 提升操作流畅度 + +### 3. 条件数量提示 + +**过滤条件**: +- 显示绿色标签:`3 个条件` +- 一目了然当前配置数量 + +**联表查询**: +- 显示橙色标签:`2 个关联` +- 直观了解关联表数量 + +--- + +## 界面效果 + +### 折叠状态(默认) + +``` +┌─ 基础配置 ─────────────────────────────────────────┐ +│ 数据源:[MongoDB数据源] │ +│ 数据库:[ckb] │ +│ 主集合:[consumption_records_202101] │ +└────────────────────────────────────────────────────┘ + +┌─ → 过滤条件(WHERE) [3个条件] [添加条件] ───┐ +│ (折叠状态,内容隐藏) │ +└────────────────────────────────────────────────────┘ + +┌─ → 联表查询(JOIN/LOOKUP) [2个关联] [添加关联] ─┐ +│ (折叠状态,内容隐藏) │ +└────────────────────────────────────────────────────┘ + +┌─ 排序和限制 ───────────────────────────────────────┐ +│ 排序字段:[create_time] 排序方式:[降序] │ +│ 限制数量:[1000] │ +└────────────────────────────────────────────────────┘ +``` + +### 展开状态 + +``` +┌─ ↓ 过滤条件(WHERE) [3个条件] [添加条件] ───┐ +│ ┌──────────────────────────────────────────────────┐│ +│ │ 逻辑 | 字段 | 运算符 | 值 | 操作 ││ +│ │ - | status | 等于 | success | [删除] ││ +│ │ AND | amount | 大于 | 1000 | [删除] ││ +│ │ AND | shop_name | 包含 | 淘宝 | [删除] ││ +│ └──────────────────────────────────────────────────┘│ +└────────────────────────────────────────────────────┘ + +┌─ ↓ 联表查询(JOIN/LOOKUP) [2个关联] [添加关联] ─┐ +│ ┌──────────────────────────────────────────────────┐│ +│ │ 关联集合 | 主字段 | 关联字段 | 结果名 | 操作 ││ +│ │ user_profile | user_id | user_id | user | [删除]││ +│ │ stores | store_id | _id | store_info | [删除] ││ +│ └──────────────────────────────────────────────────┘│ +└────────────────────────────────────────────────────┘ +``` + +--- + +## 交互设计 + +### 标题栏样式 + +**视觉提示**: +- 鼠标悬停:标题栏背景变为浅灰色 `#f5f7fa` +- 光标变化:`cursor: pointer` +- 过渡动画:0.2s 平滑过渡 + +**元素组成**: +``` +[图标 →/↓] [标题] [条件数量标签] [操作按钮] +``` + +### 点击行为 + +**标题栏点击**: +- 点击标题栏任意位置 → 切换折叠/展开状态 +- 图标跟随变化 + +**按钮点击**: +- 使用 `@click.stop` 阻止事件冒泡 +- 点击"添加条件/关联"按钮不会触发折叠切换 +- 但会自动展开对应区域 + +--- + +## 技术实现 + +### 1. 折叠状态管理 + +```typescript +// 折叠状态 +const collapseStates = reactive({ + filter: false, // 过滤条件默认折叠 + lookup: false // 联表查询默认折叠 +}) +``` + +### 2. 模板结构 + +```vue + + + + + +
+ +
+
+
+``` + +### 3. 自动展开逻辑 + +```typescript +// 添加过滤条件 +const handleAddFilter = () => { + if (!hasCollection.value) { + ElMessage.warning('请先选择主集合') + return + } + + // 添加新条件 + queryConfig.filter.push({ + logic: queryConfig.filter.length > 0 ? 'and' : undefined, + field: '', + operator: 'eq', + value: '' + }) + + // 自动展开区域 + collapseStates.filter = true +} +``` + +### 4. 样式设计 + +```scss +.card-header { + display: flex; + justify-content: space-between; + align-items: center; + font-weight: 500; + font-size: 14px; + + // 针对可点击的标题栏 + &[style*="cursor: pointer"] { + user-select: none; + transition: background-color 0.2s; + margin: -12px -20px; + padding: 12px 20px; + border-radius: 4px; + + &:hover { + background-color: #f5f7fa; + } + } +} +``` + +--- + +## 用户操作流程 + +### 场景1:查看已有配置 + +**用户动作**: +1. 打开数据列表配置页面 +2. 看到折叠的过滤条件和联表查询 +3. 标签显示:"3 个条件"、"2 个关联" + +**优势**: +- 一眼看出配置数量 +- 界面简洁,不需要滚动 + +### 场景2:添加新配置 + +**用户动作**: +1. 点击"添加条件"按钮 +2. 区域自动展开 +3. 开始配置新条件 + +**优势**: +- 无需手动展开 +- 操作流畅,减少点击次数 + +### 场景3:查看详细配置 + +**用户动作**: +1. 点击标题栏 +2. 展开查看详细配置 +3. 再次点击可折叠 + +**优势**: +- 快速切换查看状态 +- 标题栏整行可点击,点击区域大 + +--- + +## 优势总结 + +### 1. 界面简洁 +- 默认折叠,减少视觉干扰 +- 特别适合复杂配置场景 +- 聚焦当前操作 + +### 2. 信息密度优化 +- 数量标签直观显示配置数量 +- 不需要展开即可了解配置情况 +- 快速定位需要修改的区域 + +### 3. 操作便捷 +- 整行标题栏可点击 +- 自动展开机制 +- 视觉反馈清晰 + +### 4. 性能优化 +- 折叠状态下不渲染内容 +- 大量条件时渲染性能更好 +- 使用 `el-collapse-transition` 平滑动画 + +--- + +## 兼容性说明 + +### 向后兼容 +- 不影响现有数据结构 +- 只是UI层面的改进 +- 所有功能保持不变 + +### 默认行为 +- 新建时:默认折叠 +- 编辑时:默认折叠 +- 添加配置时:自动展开 + +### 状态保持 +- 折叠状态不保存 +- 每次进入页面都是默认折叠 +- 符合大多数用户习惯 + +--- + +## 相关组件 + +使用了以下 Element Plus 组件: +- `el-collapse-transition`: 折叠动画 +- `el-icon`: 图标组件 +- `el-tag`: 数量标签 + +使用了以下图标: +- `ArrowRight`: 折叠状态(→) +- `ArrowDown`: 展开状态(↓) + +--- + +**更新时间**:2025-01-XX +**版本**:QueryBuilder v2.1 +**更新内容**:添加折叠功能,优化界面布局 diff --git a/Moncter/提示词/可视化查询构建器使用说明.md b/Moncter/提示词/可视化查询构建器使用说明.md new file mode 100644 index 00000000..895bdfbb --- /dev/null +++ b/Moncter/提示词/可视化查询构建器使用说明.md @@ -0,0 +1,311 @@ +# 可视化查询构建器使用说明 + +## 一、概述 + +可视化查询构建器是一个用于配置MongoDB查询的UI组件,支持通过图形界面配置复杂的查询条件,包括过滤条件、联表查询、排序等功能。 + +--- + +## 二、功能特性 + +### 2.1 基础配置 +- **数据源选择**:选择已配置的数据源 +- **数据库选择**:选择数据源中的数据库 +- **主集合选择**:选择查询的主集合(表) + +### 2.2 过滤条件(WHERE) +- **逻辑关系**:支持 AND/OR 逻辑组合 +- **字段选择**:从集合字段列表中选择 +- **运算符**: + - `eq` - 等于 + - `ne` - 不等于 + - `gt` - 大于 + - `gte` - 大于等于 + - `lt` - 小于 + - `lte` - 小于等于 + - `in` - 包含(数组) + - `nin` - 不包含(数组) + - `regex` - 正则匹配 + - `exists` - 字段存在 +- **值输入**:根据字段类型自动调整输入方式 + +### 2.3 联表查询(JOIN/LOOKUP) +- **关联集合**:选择要关联的其他集合 +- **主集合字段**:主集合的关联字段 +- **关联集合字段**:关联集合的关联字段 +- **结果字段名**:关联结果存储的字段名 +- **解构**:是否将数组结果展开为对象 +- **保留空值**:LEFT JOIN效果,保留没有关联的记录 + +### 2.4 排序和限制 +- **排序字段**:选择排序的字段 +- **排序方式**:升序/降序 +- **限制数量**:限制返回的记录数 + +### 2.5 查询预览 +- **SQL预览**:实时显示生成的MongoDB聚合管道代码 +- **数据预览**:预览查询结果(最多显示预览数据) + +--- + +## 三、使用流程 + +### 3.1 创建数据列表 + +1. **进入数据列表管理页面** + - 路径:`/tag-data-lists` + - 点击"创建数据列表"按钮 + +2. **填写基本信息** + - 列表名称:如"消费记录表" + - 列表编码:如"consumption_records" + - 描述:可选 + - 状态:启用/禁用 + +3. **配置查询** + - 选择数据源 + - 选择数据库 + - 选择主集合 + - 添加过滤条件(可选) + - 添加联表查询(可选) + - 配置排序和限制(可选) + +4. **预览查询** + - 点击"预览数据"按钮 + - 查看生成的MongoDB查询代码 + - 查看预览数据 + +5. **保存配置** + - 点击"保存"按钮 + - 数据列表配置保存成功 + +### 3.2 在标签定义中使用 + +1. **创建标签定义** + - 进入标签定义管理页面 + - 点击"创建标签定义" + +2. **选择数据列表** + - 在"数据列表"下拉框中选择已创建的数据列表 + - 系统自动加载该列表的字段 + +3. **配置规则** + - 选择规则类型(运算规则/正则规则) + - 添加规则条件 + - 每个条件选择字段、运算符、值、标签值 + +4. **保存标签定义** + +--- + +## 四、配置示例 + +### 4.1 简单查询示例 + +**场景**:查询消费记录表中金额大于1000的记录 + +**配置**: +- 数据源:选择MongoDB数据源 +- 数据库:`tag_engine` +- 主集合:`consumption_records` +- 过滤条件: + - 字段:`amount` + - 运算符:`gt` + - 值:`1000` +- 排序:按 `create_time` 降序 +- 限制:1000条 + +**生成的查询**: +```javascript +db.consumption_records.aggregate([ + { $match: { amount: { $gt: 1000 } } }, + { $sort: { create_time: -1 } }, + { $limit: 1000 } +]) +``` + +### 4.2 联表查询示例 + +**场景**:查询消费记录,并关联用户信息 + +**配置**: +- 数据源:选择MongoDB数据源 +- 数据库:`tag_engine` +- 主集合:`consumption_records` +- 联表查询: + - 关联集合:`user_profile` + - 主集合字段:`user_id` + - 关联集合字段:`user_id` + - 结果字段名:`user_info` + - 解构:是 + - 保留空值:是 +- 过滤条件: + - 字段:`status` + - 运算符:`eq` + - 值:`success` +- 限制:1000条 + +**生成的查询**: +```javascript +db.consumption_records.aggregate([ + { $match: { status: { $eq: "success" } } }, + { $lookup: { + from: "user_profile", + localField: "user_id", + foreignField: "user_id", + as: "user_info" + } }, + { $unwind: { + path: "$user_info", + preserveNullAndEmptyArrays: true + } }, + { $limit: 1000 } +]) +``` + +### 4.3 复杂条件查询示例 + +**场景**:查询最近30天、金额大于1000、状态为成功的消费记录 + +**配置**: +- 数据源:选择MongoDB数据源 +- 数据库:`tag_engine` +- 主集合:`consumption_records` +- 过滤条件: + 1. 字段:`amount`,运算符:`gt`,值:`1000`,逻辑:- + 2. 字段:`status`,运算符:`eq`,值:`success`,逻辑:AND + 3. 字段:`create_time`,运算符:`gte`,值:`2024-12-01`,逻辑:AND +- 排序:按 `create_time` 降序 +- 限制:1000条 + +**生成的查询**: +```javascript +db.consumption_records.aggregate([ + { $match: { + amount: { $gt: 1000 }, + status: { $eq: "success" }, + create_time: { $gte: ISODate("2024-12-01T00:00:00Z") } + } }, + { $sort: { create_time: -1 } }, + { $limit: 1000 } +]) +``` + +--- + +## 五、技术实现 + +### 5.1 组件结构 + +``` +QueryBuilder/ + ├── QueryBuilder.vue # 主组件 + └── index.ts # 导出(可选) +``` + +### 5.2 数据格式 + +**输入格式**(v-model): +```typescript +{ + data_source_id: string + database: string + collection: string + filter: Array<{ + logic?: 'and' | 'or' + field: string + operator: string + value: any + }> + lookups: Array<{ + from: string + local_field: string + foreign_field: string + as: string + unwrap?: boolean + preserve_null?: boolean + }> + sort_field: string + sort_order: '1' | '-1' + limit: number +} +``` + +**输出格式**(保存到数据库): +```json +{ + "list_id": "uuid", + "list_name": "消费记录表", + "list_code": "consumption_records", + "data_source_id": "source_123", + "database": "tag_engine", + "collection": "consumption_records", + "query_config": { + "filter": [ + { + "field": "amount", + "operator": "gt", + "value": 1000 + } + ], + "lookups": [ + { + "from": "user_profile", + "local_field": "user_id", + "foreign_field": "user_id", + "as": "user_info", + "unwrap": true, + "preserve_null": true + } + ], + "sort": { + "create_time": -1 + }, + "limit": 1000 + } +} +``` + +### 5.3 API接口 + +**需要实现的接口**: + +1. `GET /api/data-sources` - 获取数据源列表 +2. `GET /api/data-sources/{id}/databases` - 获取数据库列表 +3. `GET /api/data-sources/{id}/collections` - 获取集合列表(需要database参数) +4. `GET /api/data-sources/{id}/fields` - 获取字段列表(需要database和collection参数) +5. `POST /api/data-sources/preview-query` - 预览查询结果 +6. `GET /api/tag-data-lists` - 获取数据列表列表 +7. `POST /api/tag-data-lists` - 创建数据列表 +8. `GET /api/tag-data-lists/{id}` - 获取数据列表详情 +9. `PUT /api/tag-data-lists/{id}` - 更新数据列表 +10. `DELETE /api/tag-data-lists/{id}` - 删除数据列表 +11. `GET /api/tag-data-lists/{id}/fields` - 获取数据列表字段(用于标签定义) + +--- + +## 六、使用注意事项 + +1. **数据源配置**:必须先配置数据源,才能使用查询构建器 +2. **字段类型**:系统会自动识别字段类型,调整输入方式 +3. **联表查询**:支持多个联表查询,按顺序执行 +4. **性能考虑**:建议设置合理的limit值,避免查询过多数据 +5. **预览功能**:预览数据最多显示一定数量,用于验证查询配置是否正确 + +--- + +## 七、扩展功能 + +### 7.1 未来可扩展的功能 + +1. **聚合函数**:支持 $group、$sum、$avg 等聚合操作 +2. **子查询**:支持嵌套查询 +3. **条件分支**:支持 $cond、$switch 等条件表达式 +4. **字段映射**:支持字段重命名、计算字段 +5. **查询模板**:保存常用查询为模板 +6. **查询历史**:记录查询历史,支持回滚 + +--- + +**文档更新时间**:2025-01-XX +**组件版本**:v1.0.0 diff --git a/Moncter/提示词/多集合模式使用说明.md b/Moncter/提示词/多集合模式使用说明.md new file mode 100644 index 00000000..2ba6175d --- /dev/null +++ b/Moncter/提示词/多集合模式使用说明.md @@ -0,0 +1,425 @@ +# 多集合模式使用说明 + +## 问题背景 + +在实际业务中,**消费记录表**并非单一集合,而是由多个集合构成: + +### 场景1:按月分片的消费记录 +在 `ckb` 数据库中,消费记录按月分片存储: +- `consumption_records_202101` +- `consumption_records_202102` +- `consumption_records_202103` +- ... (每月一个集合) + +### 场景2:按商品类型分散的消费记录 +在 `KR_淘宝` 数据库中,消费记录按商品类型分散: +- 女士内衣(132.6万条) +- 办公设备文具(64.5万条) +- 包(71万条) +- zippo1, zippo2, ... (多个集合) + +**问题**:如何在数据列表配置中选择这些分散的消费记录表? + +--- + +## 解决方案:多集合模式 + +QueryBuilder 组件现已支持**多集合模式**,允许同时选择多个集合,查询时自动合并数据。 + +--- + +## 使用方法 + +### 1. 启用多集合模式 + +在数据列表配置页面(QueryBuilder 基础配置区域): + +1. 选择数据源 +2. 选择数据库 +3. **开启"多集合模式"开关** + +``` +┌─ 基础配置 ─────────────────────────────────┐ +│ 数据源:[MongoDB标签引擎数据源] │ +│ 数据库:[ckb] │ +│ 多集合模式:[●启用] ○禁用 │ +│ 说明:启用后可同时选择多个集合 │ +└─────────────────────────────────────────────┘ +``` + +### 2. 选择多个集合 + +启用后,会显示集合复选框列表,并提供强大的筛选和操作功能: + +#### 筛选功能 +``` +[🔍 筛选集合名称...] +``` +- 输入关键词实时筛选集合列表 +- 例如输入 `2021` 只显示包含 2021 的集合 +- 支持模糊匹配,不区分大小写 + +#### 批量操作按钮 +``` +[全选] - 选择当前筛选结果的所有集合 +[清空] - 清空所有已选集合 +[反选] - 反选当前筛选结果的集合 +``` + +#### 快捷筛选(智能识别) +当检测到按日期分片的集合时,自动显示快捷筛选按钮: +``` +快捷筛选: +[2021年] [2022年] [2023年] [2024年] [2025年] +[最近3个月] [最近6个月] [最近12个月] +``` + +**功能说明**: +- **按年份筛选**:点击 `2021年` 自动选择所有包含 `2021` 的集合 +- **按时间范围**:点击 `最近3个月` 自动选择最近3个月的集合 + - 例如当前是 2025-01,点击"最近3个月"会选择: + - consumption_records_202501 + - consumption_records_202412 + - consumption_records_202411 + +#### 集合列表 +``` +┌─ 集合列表 ─────────────────────────────────┐ +│ ☑ consumption_records_202101 │ +│ ☑ consumption_records_202102 │ +│ ☑ consumption_records_202103 │ +│ ☑ consumption_records_202104 │ +│ ☑ consumption_records_202105 │ +│ ☑ consumption_records_202106 │ +│ ☐ user_profile │ +│ ☐ user_tags_shard_0 │ +│ ... (最多300px高度,超出可滚动) │ +└─────────────────────────────────────────────┘ + +筛选结果:28 个集合 | 已选择 6 个集合 +查询时将自动合并这些集合的数据 +``` + +### 3. 配置查询条件 + +多集合模式下,可以正常配置: +- 过滤条件(WHERE) +- 联表查询(JOIN) +- 排序和限制 + +字段列表会从**第一个选中的集合**加载。 + +### 4. 预览查询 + +点击"预览数据",SQL预览会显示: + +```javascript +// 多集合模式:将查询以下 6 个集合并合并结果 +// consumption_records_202101, consumption_records_202102, consumption_records_202103, consumption_records_202104, consumption_records_202105, consumption_records_202106 + +db.consumption_records_202101.aggregate([ + { $match: { status: { $eq: "success" } } }, + { $sort: { create_time: -1 } }, + { $limit: 1000 } +]) +``` + +--- + +## 完整示例 + +### 示例1:按月分片的消费记录(使用快捷筛选) + +**需求**:创建一个包含2021年所有消费记录的数据列表 + +**步骤**: +1. 列表名称:`2021年全年消费记录` +2. 列表编码:`consumption_records_2021` +3. 数据源:MongoDB标签引擎 +4. 数据库:`ckb` +5. **启用多集合模式** +6. **点击快捷筛选按钮 `2021年`** 👈 自动选择所有2021年的集合! + - ✅ 自动选中: + - consumption_records_202101 + - consumption_records_202102 + - consumption_records_202103 + - ... (所有12个月) + - 💡 提示:"已选择 12 个集合" +7. 添加过滤条件(可选): + - 字段:`status` + - 运算符:`等于` + - 值:`success` +8. 保存 + +**传统方式 vs 快捷筛选**: +- ❌ 传统方式:需要手动勾选12个复选框 +- ✅ 快捷筛选:点击1次按钮即可 + +### 示例1-2:最近半年消费记录(智能时间范围) + +**需求**:创建一个包含最近6个月消费记录的数据列表 + +**步骤**: +1. 列表名称:`最近半年消费记录` +2. 列表编码:`consumption_records_recent_6m` +3. 数据源:MongoDB标签引擎 +4. 数据库:`ckb` +5. **启用多集合模式** +6. **点击快捷筛选按钮 `最近6个月`** 👈 自动选择最近6个月的集合! + - 系统自动计算时间范围 + - 如果当前是 2025-01,则选择: + - consumption_records_202501 + - consumption_records_202412 + - consumption_records_202411 + - consumption_records_202410 + - consumption_records_202409 + - consumption_records_202408 +7. 保存 + +### 示例2:使用筛选功能精确选择 + +**需求**:只选择2021年第一季度的消费记录 + +**步骤**: +1. 启用多集合模式 +2. **在筛选框输入 `202101`** + - 筛选结果:只显示 `consumption_records_202101` +3. **点击 `全选`** 按钮 +4. **清空筛选框,输入 `202102`** +5. **点击 `全选`** 按钮(追加选择) +6. **清空筛选框,输入 `202103`** +7. **点击 `全选`** 按钮(追加选择) +8. 最终选中3个集合 + +**高级技巧**: +- 输入 `20210` 可以同时筛选出 202101-202109 +- 点击"全选"后,再输入 `202107`,点击"反选"可以排除7月的数据 + +**保存的数据结构**: +```json +{ + "list_name": "2021年上半年消费记录", + "list_code": "consumption_records_2021_h1", + "data_source_id": "source_001", + "database": "ckb", + "collection": "consumption_records_202101", + "multi_collection": true, + "collections": [ + "consumption_records_202101", + "consumption_records_202102", + "consumption_records_202103", + "consumption_records_202104", + "consumption_records_202105", + "consumption_records_202106" + ], + "query_config": { + "filter": [ + { "field": "status", "operator": "eq", "value": "success" } + ], + "lookups": [], + "sort": { "create_time": -1 }, + "limit": 1000 + } +} +``` + +### 示例3:按商品类型的消费记录(使用文本筛选) + +**需求**:创建一个包含女性用品的消费记录数据列表 + +**步骤**: +1. 列表名称:`女性用品消费记录` +2. 列表编码:`female_products_consumption` +3. 数据源:MongoDB标签引擎 +4. 数据库:`KR_淘宝` +5. **启用多集合模式** +6. **在筛选框输入 `女`** + - 筛选结果显示:女士内衣 +7. **点击 `全选`** +8. **清空筛选框,输入 `包`** +9. **点击 `全选`**(追加选择) +10. 最终选中: + - ☑ 女士内衣(去重复后132.6万) + - ☑ 包(去重复后71万) +11. 保存 + +### 示例4:反选功能的妙用 + +**需求**:选择2021年除了1月和12月以外的所有月份 + +**步骤**: +1. **点击快捷筛选 `2021年`**(选中全年12个月) +2. **在筛选框输入 `202101`** +3. **点击 `反选`**(取消选择1月) +4. **清空筛选框,输入 `202112`** +5. **点击 `反选`**(取消选择12月) +6. 最终选中:202102-202111(10个月) + +--- + +## 技术实现 + +### 前端数据结构 + +```typescript +const queryConfig = reactive({ + data_source_id: string + database: string + collection: string // 单集合模式或多集合的第一个(兼容性) + multi_collection: boolean // 是否启用多集合模式 + collections: string[] // 多集合模式下选中的集合列表 + filter: Array<...> + lookups: Array<...> + sort_field: string + sort_order: string + limit: number +}) +``` + +### 后端查询逻辑(待实现) + +后端在执行查询时,需要处理多集合: + +```php +if ($dataList['multi_collection'] && !empty($dataList['collections'])) { + // 多集合模式:对每个集合执行查询,然后合并结果 + $allResults = []; + foreach ($dataList['collections'] as $collection) { + $results = $this->executeQuery($dataSource, $database, $collection, $queryConfig); + $allResults = array_merge($allResults, $results); + } + + // 如果有排序,需要对合并结果重新排序 + if ($queryConfig['sort']) { + $allResults = $this->sortResults($allResults, $queryConfig['sort']); + } + + // 如果有限制,需要对合并结果应用限制 + if ($queryConfig['limit']) { + $allResults = array_slice($allResults, 0, $queryConfig['limit']); + } + + return $allResults; +} else { + // 单集合模式 + return $this->executeQuery($dataSource, $database, $collection, $queryConfig); +} +``` + +--- + +## API 调整(待实现) + +### 预览查询 API + +需要支持 `collections` 参数: + +**请求**: +```json +POST /data-collection-tasks/preview-query +{ + "data_source_id": "source_001", + "database": "ckb", + "collection": "consumption_records_202101", // 兼容性保留 + "collections": [ // 多集合模式 + "consumption_records_202101", + "consumption_records_202102", + "consumption_records_202103" + ], + "filter_conditions": [...], + "lookups": [...], + "limit": 10 +} +``` + +**响应**: +```json +{ + "code": 200, + "data": { + "fields": [...], + "data": [...], // 合并后的数据 + "count": 30, // 总条数 + "collections_count": { // 各集合的数据条数(可选) + "consumption_records_202101": 10, + "consumption_records_202102": 10, + "consumption_records_202103": 10 + } + } +} +``` + +--- + +## 使用场景 + +### 1. 时间分片数据 +- 消费记录按月/季度/年分表 +- 日志数据按日期分表 +- 订单数据按时间分表 + +### 2. 业务分类数据 +- 按商品类型分表的交易数据 +- 按地区分表的用户数据 +- 按渠道分表的营销数据 + +### 3. 分库分表数据 +- 数据水平切分后的多个分片 +- 跨库查询场景 + +--- + +## 注意事项 + +### 1. 字段一致性 +多个集合应该有**相同或相似的字段结构**,否则合并查询可能出错。 + +### 2. 性能考虑 +- 选择的集合越多,查询性能越慢 +- 建议根据实际需求选择合适的集合范围 +- 可以设置合理的 `limit` 限制返回数据量 + +### 3. 排序和限制 +- 多集合模式下,排序和限制会在**合并后的结果**上应用 +- 如果每个集合返回1000条,3个集合合并后是3000条,再应用limit + +### 4. 联表查询 +- 联表查询在**每个集合上独立执行** +- 关联表应该是同一个集合(不跨集合联表) + +--- + +## 界面效果 + +### 单集合模式(默认) +``` +多集合模式:○启用 ●禁用 +主集合:[consumption_records_202101 ▼] +``` + +### 多集合模式(带筛选和快捷操作) +``` +多集合模式:●启用 ○禁用 + +┌─────────────────────────────────────────────────────┐ +│ [🔍 筛选集合名称...] [全选] [清空] [反选] │ +│ │ +│ 快捷筛选:[2021年] [2022年] [2023年] [2024年] │ +│ [最近3个月] [最近6个月] [最近12个月] │ +├─────────────────────────────────────────────────────┤ +│ 集合列表: │ +│ ☑ consumption_records_202101 │ +│ ☑ consumption_records_202102 │ +│ ☑ consumption_records_202103 │ +│ ☐ consumption_records_202104 │ +│ ☐ consumption_records_202105 │ +│ ... (滚动查看更多) │ +└─────────────────────────────────────────────────────┘ + +已选择 3 个集合,查询时将自动合并这些集合的数据 +``` + +--- + +**更新时间**:2025-01-XX +**状态**:前端已实现,后端待开发 diff --git a/Moncter/提示词/字段定义配置管理方案对比.md b/Moncter/提示词/字段定义配置管理方案对比.md new file mode 100644 index 00000000..486bc084 --- /dev/null +++ b/Moncter/提示词/字段定义配置管理方案对比.md @@ -0,0 +1,491 @@ +# 字段定义配置管理方案对比 + +## 一、问题 + +标签定义创建时,需要选择数据源类型(user_profile、user_phone_relations、consumption_records),然后显示该数据源的字段列表供用户选择。 + +**问题**:这些字段列表应该: +1. 存储在数据库中(配置化),通过管理界面动态管理? +2. 还是写在代码中(纯代码实现),前端直接调用API即可? + +--- + +## 二、方案对比 + +### 方案一:纯代码实现(⭐推荐第一阶段) + +**实现方式**: +- 字段定义直接写在代码中(Service 或 Config 类) +- API 接口直接返回硬编码的字段列表 +- 需要修改字段时,修改代码并重新部署 + +**代码示例**: + +```php +// app/service/DataSourceFieldService.php +class DataSourceFieldService +{ + /** + * 获取数据源的字段列表 + */ + public function getFields(string $dataSourceType): array + { + $fieldsMap = [ + 'user_profile' => [ + [ + 'field' => 'user_id', + 'type' => 'string', + 'description' => '用户ID', + 'source' => 'user_profile', + ], + [ + 'field' => 'total_amount', + 'type' => 'number', + 'description' => '总消费金额', + 'source' => 'user_profile', + 'pre_aggregated_from' => 'consumption_records', + ], + // ... 更多字段 + ], + 'user_phone_relations' => [ + [ + 'field' => 'phone_number', + 'type' => 'string', + 'description' => '手机号', + 'source' => 'user_phone_relations', + ], + // ... + ], + 'consumption_records' => [ + // 消费记录表的预聚合字段 + [ + 'field' => 'total_amount', + 'type' => 'number', + 'description' => '总消费金额', + 'source' => 'pre_aggregated', + 'original_source' => 'consumption_records', + 'note' => '从消费记录表预聚合到 user_profile', + ], + // ... + ], + ]; + + return $fieldsMap[$dataSourceType] ?? []; + } +} +``` + +**优点**: +- ✅ **实现简单**:代码简洁,无需额外的数据库表和管理界面 +- ✅ **性能好**:直接返回,无需数据库查询 +- ✅ **类型安全**:代码中可以定义完整的类型和验证 +- ✅ **版本控制**:字段定义的变更可以通过 Git 追踪 +- ✅ **易于测试**:单元测试容易编写 + +**缺点**: +- ⚠️ **灵活性较低**:修改字段需要改代码、重新部署 +- ⚠️ **需要开发人员**:非技术人员无法直接修改字段配置 + +**适用场景**: +- 字段定义相对稳定,不频繁变化 +- 第一阶段快速实现 +- 团队较小,技术栈统一 + +--- + +### 方案二:数据库配置(🔶适合长期) + +**实现方式**: +- 创建 `data_source_fields` 集合(MongoDB) +- 存储每个数据源类型的字段定义 +- 提供管理界面,允许管理员动态添加/修改字段 + +**数据结构**: + +```javascript +// data_source_fields 集合 +{ + field_id: "uuid", + data_source_type: "consumption_records", + field: "total_amount", + type: "number", + description: "总消费金额", + source: "pre_aggregated", + original_source: "consumption_records", + note: "从消费记录表预聚合到 user_profile", + is_active: true, + sort_order: 1, + create_time: ISODate(), + update_time: ISODate(), +} +``` + +**代码示例**: + +```php +// app/repository/DataSourceFieldRepository.php +class DataSourceFieldRepository extends Model +{ + protected $table = 'data_source_fields'; + protected $primaryKey = 'field_id'; + // ... +} + +// app/service/DataSourceFieldService.php +class DataSourceFieldService +{ + public function __construct( + protected DataSourceFieldRepository $fieldRepository + ) {} + + public function getFields(string $dataSourceType): array + { + return $this->fieldRepository + ->where('data_source_type', $dataSourceType) + ->where('is_active', true) + ->orderBy('sort_order') + ->get() + ->toArray(); + } +} +``` + +**优点**: +- ✅ **灵活性高**:可以动态添加/修改字段,无需重新部署 +- ✅ **非技术人员友好**:管理员可以通过界面管理字段 +- ✅ **支持多环境**:不同环境可以有不同的字段配置 +- ✅ **支持字段元数据**:可以存储更多信息(如验证规则、默认值等) + +**缺点**: +- ⚠️ **实现复杂**:需要创建 Repository、Service、Controller、前端界面 +- ⚠️ **性能稍差**:每次请求需要查询数据库(可加缓存优化) +- ⚠️ **需要维护**:需要维护字段配置数据的正确性 +- ⚠️ **版本控制困难**:配置变更无法通过 Git 追踪 + +**适用场景**: +- 字段定义频繁变化 +- 有非技术人员需要管理字段配置 +- 需要支持多环境不同配置 +- 长期维护的大型项目 + +--- + +### 方案三:混合方案(🔶平衡方案) + +**实现方式**: +- 基础字段定义写在代码中(作为默认值) +- 支持数据库配置覆盖/扩展 +- 合并代码配置和数据库配置 + +**代码示例**: + +```php +class DataSourceFieldService +{ + /** + * 获取字段列表(代码 + 数据库) + */ + public function getFields(string $dataSourceType): array + { + // 1. 从代码获取默认字段 + $defaultFields = $this->getDefaultFields($dataSourceType); + + // 2. 从数据库获取自定义字段(如果有) + $customFields = $this->fieldRepository + ->where('data_source_type', $dataSourceType) + ->where('is_active', true) + ->get() + ->toArray(); + + // 3. 合并:数据库字段覆盖代码字段(按 field 名匹配) + $merged = []; + foreach ($defaultFields as $field) { + $merged[$field['field']] = $field; + } + foreach ($customFields as $field) { + $merged[$field['field']] = $field; + } + + // 4. 排序 + usort($merged, fn($a, $b) => ($a['sort_order'] ?? 999) <=> ($b['sort_order'] ?? 999)); + + return array_values($merged); + } + + /** + * 从代码获取默认字段 + */ + private function getDefaultFields(string $dataSourceType): array + { + // 硬编码的默认字段定义 + // ... + } +} +``` + +**优点**: +- ✅ **灵活性**:支持动态扩展 +- ✅ **稳定性**:默认字段来自代码,相对稳定 +- ✅ **向后兼容**:即使数据库没有配置,也能正常工作 + +**缺点**: +- ⚠️ **实现更复杂**:需要处理合并逻辑 +- ⚠️ **可能混淆**:代码和数据库配置可能冲突 + +--- + +## 三、项目现状分析 + +### 当前项目的配置管理方式 + +1. **数据源配置** (`data_sources` 集合): + - ✅ 存储在数据库中 + - ✅ 有管理界面(DataSourceController) + - 说明:业务级配置,需要动态管理 + +2. **标签定义** (`tag_definitions` 集合): + - ✅ 存储在数据库中 + - ✅ 有管理界面(TagDefinitionController) + - 说明:业务级配置,需要动态管理 + +3. **系统配置** (`config/` 目录): + - ✅ 配置文件(如 `data_collection_tasks.php`) + - 说明:系统级配置,相对稳定 + +### 字段定义的特点 + +- **相对稳定**:表结构不会频繁变化 +- **与代码耦合**:字段名必须与实际数据库字段一致 +- **需要验证**:字段类型、可用性需要与代码逻辑保持一致 +- **可能扩展**:未来可能需要添加新的预聚合字段 + +--- + +## 四、推荐方案 + +### 推荐:方案一(纯代码实现)+ 后续扩展为方案三 + +#### 第一阶段:纯代码实现(立即实施) + +**理由**: +1. ✅ **快速实现**:代码实现简单,可以快速上线 +2. ✅ **字段相对稳定**:表字段不会频繁变化 +3. ✅ **与代码耦合**:字段名必须与代码中的字段一致,代码管理更安全 +4. ✅ **符合当前项目风格**:系统级配置用代码,业务级配置用数据库 + +**实现步骤**: + +1. 创建 `DataSourceFieldService` 类,硬编码字段定义 +2. 在 `TagDefinitionController` 添加 `getDataSourceFields()` 方法 +3. 前端调用 API 获取字段列表 + +#### 第二阶段:如需扩展,升级为混合方案 + +**如果后续需要**: +- 非技术人员管理字段配置 +- 多环境不同配置 +- 动态添加字段(如新的预聚合字段) + +**则可以升级为方案三**: +- 保留代码中的默认字段定义 +- 添加数据库配置表和管理界面 +- 支持数据库配置覆盖/扩展代码配置 + +--- + +## 五、具体实现建议 + +### 第一阶段实现(纯代码) + +```php +// app/service/DataSourceFieldService.php +> 字段列表 + */ + public function getFields(string $dataSourceType): array + { + $fieldsMap = $this->getFieldsMap(); + return $fieldsMap[$dataSourceType] ?? []; + } + + /** + * 获取所有数据源的字段映射 + * + * @return array>> + */ + private function getFieldsMap(): array + { + return [ + 'user_profile' => [ + [ + 'field' => 'user_id', + 'type' => 'string', + 'description' => '用户ID', + ], + [ + 'field' => 'total_amount', + 'type' => 'number', + 'description' => '总消费金额', + 'pre_aggregated_from' => 'consumption_records', + ], + [ + 'field' => 'total_count', + 'type' => 'number', + 'description' => '总消费次数', + 'pre_aggregated_from' => 'consumption_records', + ], + [ + 'field' => 'last_consume_time', + 'type' => 'datetime', + 'description' => '最后消费时间', + ], + [ + 'field' => 'gender', + 'type' => 'number', + 'description' => '性别(0=女,1=男,2=未知)', + ], + [ + 'field' => 'birthday', + 'type' => 'datetime', + 'description' => '生日', + ], + // ... 更多字段 + ], + + 'user_phone_relations' => [ + [ + 'field' => 'phone_number', + 'type' => 'string', + 'description' => '手机号', + ], + [ + 'field' => 'user_id', + 'type' => 'string', + 'description' => '用户ID', + ], + [ + 'field' => 'effective_time', + 'type' => 'datetime', + 'description' => '生效时间', + ], + [ + 'field' => 'expire_time', + 'type' => 'datetime', + 'description' => '失效时间', + ], + // ... 更多字段 + ], + + 'consumption_records' => [ + // 注意:这些字段实际上来自 user_profile 的预聚合字段 + [ + 'field' => 'total_amount', + 'type' => 'number', + 'description' => '总消费金额', + 'source' => 'pre_aggregated', + 'original_source' => 'consumption_records', + 'note' => '从消费记录表预聚合到 user_profile', + ], + [ + 'field' => 'total_count', + 'type' => 'number', + 'description' => '总消费次数', + 'source' => 'pre_aggregated', + 'original_source' => 'consumption_records', + 'note' => '从消费记录表预聚合到 user_profile', + ], + [ + 'field' => 'last_consume_time', + 'type' => 'datetime', + 'description' => '最后消费时间', + 'source' => 'pre_aggregated', + 'original_source' => 'consumption_records', + ], + // 未来可以添加更多预聚合字段: + // - recent_30_days_amount + // - recent_90_days_amount + // - avg_amount + // - max_amount + // ... + ], + ]; + } +} +``` + +```php +// app/controller/TagDefinitionController.php +// 添加新方法 + +/** + * 获取数据源的字段列表 + * + * GET /api/tag-definitions/data-sources/{dataSourceType}/fields + */ +public function getDataSourceFields(Request $request, string $dataSourceType): Response +{ + try { + $fieldService = new \app\service\DataSourceFieldService(); + $fields = $fieldService->getFields($dataSourceType); + + return ApiResponseHelper::success([ + 'data_source_type' => $dataSourceType, + 'fields' => $fields, + ]); + } catch (\Throwable $e) { + return ApiResponseHelper::exception($e); + } +} +``` + +```php +// config/route.php +// 添加路由 + +Route::get('/api/tag-definitions/data-sources/{dataSourceType}/fields', [TagDefinitionController::class, 'getDataSourceFields']); +``` + +--- + +## 六、总结 + +### 推荐方案 + +**第一阶段:纯代码实现** +- ✅ 简单、快速、稳定 +- ✅ 符合字段定义的特性(与代码耦合、相对稳定) +- ✅ 符合当前项目的配置管理风格 + +**后续如需要:升级为混合方案** +- 保留代码默认字段 +- 添加数据库配置支持动态扩展 +- 两全其美 + +### 关键决策点 + +- **字段定义是否频繁变化?** → 否,代码实现 +- **是否需要非技术人员管理?** → 现阶段不需要,代码实现 +- **是否需要多环境不同配置?** → 不需要,代码实现 +- **字段与代码是否强耦合?** → 是,代码实现更安全 + +**结论**:现阶段推荐纯代码实现,简单高效! + +--- + +**文档生成时间**: 2025-01-28 diff --git a/Moncter/提示词/当前架构设计/人物主表生成逻辑说明.md b/Moncter/提示词/当前架构设计/人物主表生成逻辑说明.md new file mode 100644 index 00000000..d862566a --- /dev/null +++ b/Moncter/提示词/当前架构设计/人物主表生成逻辑说明.md @@ -0,0 +1,330 @@ +# 人物主表生成逻辑说明 + +## 一、设计原则 + +### 1. 用户ID策略 +- **所有用户统一使用 UUID 作为 `user_id`** +- 身份证号只是 `user_profile` 表中的一个字段,不作为主键 +- 转为正式用户时,直接更新身份证相关字段(`id_card_hash`、`id_card_encrypted`),无需变更 `user_id` + +### 2. 表结构说明 +- **`user_profile`(用户主表)**: + - 主键:`user_id` (UUID) + - 身份证字段:`id_card_hash`、`id_card_encrypted`、`id_card_type` + - 标识字段:`is_temporary` (true=临时用户, false=正式用户) + +- **`user_phone_relations`(手机关联表)**: + - 管理手机号与用户的历史关联关系 + - 支持时间窗口:`effective_time`(生效时间)、`expire_time`(失效时间) + - 支持手机号回收后二次分配的场景 + +### 3. 数据来源 +- 主表数据来源于消费记录表(`consumption_records`) +- 消费记录可能来自不同的数据库,时间线可能不一致 + +## 二、核心处理流程 + +### 场景1:消费记录只有手机号,没有身份证号 + +**流程:** +``` +1. 接收消费记录:{ phone_number: "13800138000", id_card: null, consume_time: "2024-01-01 10:00:00" } +2. 使用 consume_time 作为查询时间点,在 user_phone_relations 表中查找该手机号在该时间点有效的关联 +3. 如果找到关联: + - 使用关联的 user_id + - 更新该用户的统计信息(total_amount, total_count, last_consume_time) +4. 如果找不到关联: + - 创建临时用户(is_temporary=true, user_id=UUID) + - 在 user_phone_relations 中建立关联(effective_time = consume_time) + - 更新临时用户的统计信息 +``` + +**关键点:** +- 必须使用 `consume_time` 作为查询时间点,而不是当前时间 +- 临时用户创建后,必须建立手机关联,不能跳过 + +### 场景2:消费记录只有身份证号,没有手机号 + +**流程:** +``` +1. 接收消费记录:{ phone_number: null, id_card: "110101199001011234", consume_time: "2024-01-01 10:00:00" } +2. 通过 id_card_hash 在 user_profile 中查找 +3. 如果找到: + - 使用该 user_id(可能是正式用户,也可能是临时用户) + - 更新统计信息 +4. 如果找不到: + - 创建正式用户(is_temporary=false, user_id=UUID) + - 设置 id_card_hash 和 id_card_encrypted + - 更新统计信息 +``` + +### 场景3:消费记录同时有手机号和身份证号(核心场景 - 触发合并) + +**处理逻辑:** + +#### 情况A:身份证找到用户A,手机号也关联到用户A +``` +→ 直接使用用户A,更新统计信息 +``` + +#### 情况B:身份证找到用户A(正式用户),手机号关联到用户B(可能是临时用户),且 A ≠ B +``` +→ 触发合并逻辑: + 1. 检查用户B是否为临时用户(is_temporary=true) + 2. 如果用户B是临时用户: + a. 合并用户B到用户A(PersonMergeService.mergeUsers(B, A)) + b. 合并内容包括:统计数据、标签、消费记录等 + c. 将手机号从用户B的关联标记为过期(expire_time = consume_time) + d. 建立手机号到用户A的新关联(effective_time = consume_time) + e. 标记用户B为已合并(status=1, merged_from_user_id=A) + f. 使用用户A + 3. 如果用户B也是正式用户(酒店预订等代订场景): + a. 策略:以身份证为准,消费记录归属到身份证用户(用户A) + b. 手机号关联保持不变(不强制转移,因为可能是代订) + c. 记录异常日志,便于后续人工审核 + d. 使用用户A(身份证用户) +``` + +#### 情况C:身份证找到用户A(正式用户),手机号未关联 +``` +→ 建立手机关联到用户A(effective_time = consume_time) +→ 使用用户A,更新统计信息 +``` + +#### 情况D:身份证未找到,手机号关联到用户B +``` +→ 检查用户B是否为临时用户: + 1. 如果用户B是临时用户: + a. 更新用户B的身份证字段(id_card_hash, id_card_encrypted) + b. 将用户B标记为正式用户(is_temporary=false) + c. 使用用户B + 2. 如果用户B不是临时用户,但身份证不匹配: + a. 创建新的正式用户(user_id=UUID,设置身份证字段) + b. 将手机号从用户B的关联标记为过期(expire_time = consume_time) + c. 建立手机号到新用户的关联(effective_time = consume_time) + d. 使用新用户 +``` + +#### 情况E:身份证未找到,手机号也未关联 +``` +→ 创建正式用户(user_id=UUID, is_temporary=false) +→ 设置身份证字段(id_card_hash, id_card_encrypted) +→ 建立手机关联(effective_time = consume_time) +→ 使用新用户,更新统计信息 +``` + +## 三、时间线冲突处理方案 + +### 问题描述 + +**场景示例:** +``` +2024-01-01: 用户A(身份证I1)使用手机M,产生消费记录 +2024-06-01: 用户A更换手机,手机M不再使用 +2024-12-01: 用户B(身份证I2)开始使用手机M,产生消费记录 +``` + +### 解决方案:基于消费记录时间点的精确匹配 + 智能过期处理 + +#### 1. 查询时使用消费记录的实际时间点 +```php +// 在处理消费记录时,必须传入 consume_time +$consumeTime = new \DateTimeImmutable($payload['consume_time']); +$userId = $this->userPhoneService->findUserByPhone($phoneNumber, $consumeTime); +``` + +#### 2. 手机关联的过期时间设置策略 + +**自动过期检测:** +- 当发现同一手机号需要关联到新用户时,自动将旧关联标记为过期 +- 过期时间设置为新关联的 `effective_time`(保证时间连续,避免间隙) + +**处理逻辑:** +```php +// 当建立新关联时 +if (手机号在 effective_time 已有有效关联 && 关联的用户ID不同) { + 旧关联.expire_time = effective_time; // 标记为过期 + 旧关联.is_active = false; + 创建新关联(effective_time = consume_time); +} +``` + +#### 3. 时间线匹配示例 + +**处理 2024-01-01 的消费记录(只有手机号M):** +``` +1. 查询手机M在 2024-01-01 的有效关联 → 未找到 +2. 创建临时用户A(UUID-xxx) +3. 建立手机M关联(effective_time = 2024-01-01, expire_time = null) +``` + +**处理 2024-12-01 的消费记录(手机M + 身份证I2):** +``` +1. 通过身份证I2查找用户 → 未找到 +2. 查询手机M在 2024-12-01 的有效关联 → 找到用户A的关联(expire_time=null,仍然有效) +3. 检查冲突:用户A的关联有效期包含 2024-12-01 +4. 由于提供了新身份证,判断为手机号回收场景: + a. 将用户A的手机关联标记为过期(expire_time = 2024-12-01) + b. 创建新用户B(UUID-yyy,设置身份证I2) + c. 建立手机M到用户B的新关联(effective_time = 2024-12-01) +``` + +## 四、关键实现要点 + +### 1. 时间点查询机制 +- `UserPhoneService::findUserByPhone()` 必须支持 `$atTime` 参数 +- 查询时使用 `consume_time`,而不是当前时间 +- `UserPhoneRelationRepository::findActiveByPhoneHash()` 需要基于时间窗口查询 + +### 2. 合并触发时机 +- **仅在手机号和身份证号同时出现时触发合并** +- 合并前检查是否为临时用户 +- 合并后需要处理手机关联的转移和过期 + +### 3. 用户ID一致性 +- 所有用户统一使用 UUID +- 转为正式用户时,只更新身份证字段,不改变 `user_id` +- 合并时,保持目标用户的 `user_id` 不变 + +### 4. 数据完整性 +- 临时用户必须建立手机关联(不能跳过) +- 正式用户的手机关联需要正确设置时间窗口 +- 合并时需要处理统计数据、标签、消费记录等所有关联数据 + +## 五、合并逻辑详细说明 + +### 合并内容 +1. **统计数据合并**:total_amount、total_count、last_consume_time +2. **手机号关联合并**:将所有手机号关联转移到目标用户 +3. **标签合并**:根据标签类型智能合并(数值型累加/取最值,布尔型取OR等) +4. **消费记录合并**:更新所有消费记录的 `user_id` + +### 合并后处理 +1. 标记源用户为已合并(`status=1`, `merged_from_user_id=目标用户ID`) +2. 更新目标用户的标签更新时间 +3. 触发标签重新计算(异步) +4. 记录合并历史日志 + +## 六、特殊场景处理 + +### 场景1:手机号被转手多次(历史记录链) + +**场景描述:** +一个手机号在不同时间段被分配给不同的用户,形成完整的历史记录链。 + +**时间线示例:** +``` +13800138000 的历史关联: +├─ 2024-01-01 → 2024-06-01: 用户A (effective_time: 2024-01-01, expire_time: 2024-06-01) +├─ 2024-06-01 → 2024-12-01: 用户B (effective_time: 2024-06-01, expire_time: 2024-12-01) +└─ 2024-12-01 → 永久: 用户C (effective_time: 2024-12-01, expire_time: null) +``` + +**处理逻辑:** +1. 每次手机号转手时,系统自动检测冲突 +2. 将旧关联的 `expire_time` 设置为新关联的 `effective_time`(保证时间连续) +3. 创建新关联,设置 `effective_time` 和 `expire_time` +4. 查询时按 `effective_time` 降序排序,取时间窗口内有效的关联 + +**查询示例:** +```php +// 查询 2024-03-01 时谁在使用该手机号 +$userId = $userPhoneService->findUserByPhone('13800138000', new DateTime('2024-03-01')); +// 返回:用户A(因为 2024-01-01 <= 2024-03-01 < 2024-06-01) + +// 查询 2024-08-01 时谁在使用该手机号 +$userId = $userPhoneService->findUserByPhone('13800138000', new DateTime('2024-08-01')); +// 返回:用户B(因为 2024-06-01 <= 2024-08-01 < 2024-12-01) +``` + +**性能考虑:** +- 如果转手非常频繁,历史记录可能很多 +- 查询时使用索引优化(`phone_hash` + `effective_time`) +- 考虑定期归档过期很久的历史记录 + +### 场景2:酒店预订等代订场景(手机号和身份证不匹配) + +**场景描述:** +用户使用自己的手机号,但提供了其他人的身份证(如代订酒店、代买商品等)。 + +**示例:** +``` +张三的手机号:13800138000(用户A,正式用户) +李四的身份证:110101199001011234(用户B,正式用户) + +消费记录: +{ + phone_number: "13800138000", + id_card: "110101199001011234", + consume_time: "2024-01-15 10:00:00" +} +``` + +**处理策略:** + +1. **检测冲突**: + - 通过身份证找到用户B + - 通过手机号在消费时间点查询,找到用户A + - 发现用户A ≠ 用户B,且两者都是正式用户 + +2. **决策逻辑**: + - **以身份证为准**:消费记录归属到身份证用户(用户B) + - **手机号关联保持不变**:不强制转移手机号到身份证用户 + - **原因**:这可能是代订场景,手机号仍属于原用户,不应自动转移 + +3. **日志记录**: + ```php + LoggerHelper::logBusiness('phone_id_card_mismatch_formal_users', [ + 'phone_number' => '13800138000', + 'phone_user_id' => 'user-a-uuid', + 'id_card_user_id' => 'user-b-uuid', + 'consume_time' => '2024-01-15 10:00:00', + 'decision' => 'use_id_card_user', + 'note' => '正式用户冲突,以身份证为准(可能是代订场景)', + ]); + ``` + +4. **结果**: + - 消费记录归属到用户B(身份证用户) + - 用户A的手机号关联保持不变 + - 记录异常日志,便于后续人工审核 + +**为什么这样处理?** +- 身份证在业务场景中通常更可信(需要实名验证) +- 代订场景很常见,不应该自动合并不同的正式用户 +- 保持手机号关联的准确性,避免误操作 +- 通过日志记录异常情况,可以后续人工审核是否需要调整 + +**对比:临时用户合并场景** +- 如果是临时用户(手机号)vs 正式用户(身份证),则自动合并 +- 因为临时用户通常是系统自动创建的,合并是合理的 + +## 七、与现有架构的对比 + +### 现有实现已满足的点: +✅ 手机号关联表支持时间窗口 +✅ 临时用户创建和手机关联 +✅ 用户合并服务(PersonMergeService) +✅ 身份证哈希和加密存储 + +### 需要改进的点: +⚠️ `resolvePersonId()` 需要支持 `$atTime` 参数 +⚠️ `ConsumptionService::createRecord()` 需要传入 `consume_time` +⚠️ 合并逻辑需要在手机号+身份证同时出现时自动触发 +⚠️ 手机关联建立时需要自动处理过期旧关联 + +## 八、总结 + +现有主用户表数据生成逻辑**基本满足要求**,但需要以下改进: + +1. **时间线处理**:所有手机号查询必须基于消费记录的实际时间点 +2. **自动合并**:当手机号和身份证号同时出现且关联到不同用户时,自动触发合并 +3. **冲突解决**:建立新关联时,自动将旧关联标记为过期 +4. **用户ID策略**:统一使用UUID,身份证仅作为字段存储 + +这些改进确保了: +- 用户身份信息的最大化有效性 +- 手机号回收后的正确匹配 +- 临时用户到正式用户的平滑转换 +- 跨数据源时间线不一致的正确处理 +g \ No newline at end of file diff --git a/Moncter/提示词/当前架构设计/前端代码风格和设计思路.md b/Moncter/提示词/当前架构设计/前端代码风格和设计思路.md new file mode 100644 index 00000000..48465d03 --- /dev/null +++ b/Moncter/提示词/当前架构设计/前端代码风格和设计思路.md @@ -0,0 +1,407 @@ +# 前端代码风格和设计思路 + +## 一、技术栈 + +### 核心技术 +- **Vue 3** (v3.4.21) - 采用 Composition API 和 ` +``` + +### 3. 组件设计规范 + +- **组件命名**:使用 PascalCase,如 `StatusBadge.vue`、`TaskForm.vue` +- **单文件组件**:每个组件一个文件,文件名与组件名一致 +- **Props 定义**:使用 `defineProps` 定义,并指定类型 +- **Emits 定义**:使用 `defineEmits` 定义,并指定事件类型 +- **组件拆分**:保持组件职责单一,复杂组件拆分为多个子组件 + +```vue + +``` + +### 4. API 调用规范 + +- **统一封装**:所有 API 调用通过 `utils/request.ts` 封装的 `request` 实例 +- **按模块划分**:API 文件按业务模块划分,如 `tagQuery.ts`、`dataCollection.ts` +- **类型安全**:所有 API 方法都有完整的类型定义 +- **错误处理**:统一在请求拦截器中处理错误,组件中只需处理业务逻辑 + +```typescript +// ✅ API 定义示例 +export const getTagStatistics = (params?: { + tag_id?: string + start_date?: string + end_date?: string +}) => { + return request.get('/tags/statistics', params) +} + +// ✅ 组件中使用 +const loadStatistics = async () => { + try { + const response = await getTagStatistics() + statistics.value = response.data + } catch (error) { + console.error('加载统计失败:', error) + } +} +``` + +### 5. 状态管理规范 + +- **使用 Pinia**:所有状态管理使用 Pinia +- **按模块划分**:Store 按业务模块划分,如 `dataCollection.ts`、`tagTask.ts` +- **Actions 命名**:使用动词开头,如 `fetchTasks`、`createTask`、`updateTask` +- **Getters 使用**:使用 getters 计算派生状态 + +```typescript +// ✅ Store 定义示例 +export const useDataCollectionStore = defineStore('dataCollection', () => { + const tasks = ref([]) + + const fetchTasks = async (params: any) => { + const response = await getDataCollectionTaskList(params) + tasks.value = response.data.tasks + return response.data + } + + return { + tasks, + fetchTasks + } +}) +``` + +### 6. 样式规范 + +- **使用 Scoped CSS**:组件样式使用 ` +``` + +### 7. 文件命名规范 + +- **组件文件**:PascalCase,如 `TaskForm.vue`、`StatusBadge.vue` +- **工具文件**:camelCase,如 `request.ts`、`format.ts` +- **类型文件**:camelCase,如 `api.ts`、`index.ts` +- **目录名**:kebab-case 或 PascalCase,保持一致性 + +## 四、设计思路 + +### 1. 请求封装设计 + +**设计目标**:统一处理 HTTP 请求,提供类型安全、错误处理、Loading 状态等功能。 + +**实现特点**: +- 自动添加 Token 到请求头 +- 统一错误处理和提示 +- 自动显示/隐藏 Loading +- 完整的 TypeScript 类型支持 +- 支持自定义配置(showLoading、showError、timeout 等) + +**使用方式**: +```typescript +// GET 请求 +const response = await request.get('/tags/statistics', params) + +// POST 请求 +const response = await request.post('/data-collection-tasks', data) +``` + +### 2. 状态管理设计 + +**设计思路**: +- 按业务模块划分 Store,每个模块独立管理自己的状态 +- 使用 Composition API 风格的 Store 定义(`setup` 函数) +- Store 中封装 API 调用逻辑,组件直接调用 Store 方法 +- 支持响应式更新,组件自动响应状态变化 + +**优势**: +- 代码组织清晰,易于维护 +- 状态复用方便 +- 类型安全 + +### 3. 路由设计 + +**设计思路**: +- 使用嵌套路由,Layout 组件作为父路由 +- 路由按功能模块组织,路径清晰 +- 路由元信息(meta)存储页面标题等信息 +- 支持动态路由参数 + +**路由结构**: +``` +/ (Layout) + ├── /dashboard (首页) + ├── /data-collection (数据采集) + │ ├── /tasks (任务列表) + │ ├── /tasks/create (创建任务) + │ └── /tasks/:id (任务详情) + ├── /tag-tasks (标签任务) + ├── /tag-definitions (标签定义) + ├── /tag-filter (标签筛选) + ├── /tag-query (标签查询) + └── /data-sources (数据源) +``` + +### 4. 组件设计 + +**设计原则**: +- **单一职责**:每个组件只负责一个功能 +- **可复用性**:公共组件设计为可复用 +- **可维护性**:组件结构清晰,易于理解和修改 +- **类型安全**:Props 和 Emits 都有完整类型定义 + +**组件分类**: +- **布局组件**:Layout、Header、Sidebar +- **业务组件**:TaskForm、TaskList、StatusBadge +- **工具组件**:ProgressDisplay、各种工具函数 + +### 5. 类型系统设计 + +**设计思路**: +- 所有业务实体都有对应的 TypeScript 接口定义 +- API 请求和响应都有完整类型定义 +- 使用联合类型定义枚举值(如状态、类型等) +- 类型定义统一管理,便于维护 + +**类型文件组织**: +- `types/index.ts`:业务实体类型(Task、Tag、User 等) +- `types/api.ts`:API 相关类型(ApiResponse、RequestConfig 等) + +### 6. 工具函数设计 + +**设计原则**: +- 函数职责单一,易于测试 +- 完整的类型定义 +- 错误处理完善 +- 支持多种输入格式 + +**工具函数分类**: +- **格式化工具**:日期时间格式化(format.ts) +- **数据脱敏**:手机号、身份证等脱敏(mask.ts) +- **表单验证**:表单字段验证(validator.ts) +- **HTTP 请求**:请求封装(request.ts) + +## 五、最佳实践 + +### 1. 错误处理 + +```typescript +// ✅ 好的实践:在组件中处理错误 +const loadData = async () => { + try { + const response = await getData() + data.value = response.data + } catch (error: any) { + // 错误已在拦截器中提示,这里只需处理业务逻辑 + console.error('加载数据失败:', error) + } +} +``` + +### 2. Loading 状态 + +```typescript +// ✅ 使用组件级别的 loading 状态 +const loading = ref(false) + +const loadData = async () => { + loading.value = true + try { + await fetchData() + } finally { + loading.value = false + } +} +``` + +### 3. 响应式数据 + +```typescript +// ✅ 优先使用 ref +const count = ref(0) +const name = ref('') + +// ✅ 对象使用 reactive 或 ref +const form = reactive({ + name: '', + age: 0 +}) + +// 或 +const form = ref({ + name: '', + age: 0 +}) +``` + +### 4. 计算属性 + +```typescript +// ✅ 使用 computed 计算派生状态 +const filteredTasks = computed(() => { + return tasks.value.filter(task => task.status === 'running') +}) +``` + +### 5. 组件通信 + +```typescript +// ✅ Props 向下传递 +interface Props { + task: DataCollectionTask +} +const props = defineProps() + +// ✅ Emits 向上传递 +const emit = defineEmits<{ + update: [task: DataCollectionTask] + delete: [id: string] +}>() +``` + +## 六、开发规范总结 + +1. **代码风格**:使用 ESLint 自动格式化,保持代码风格一致 +2. **类型安全**:充分利用 TypeScript,避免使用 `any` +3. **组件化**:保持组件小而专一,提高可复用性 +4. **状态管理**:合理使用 Pinia,避免过度使用全局状态 +5. **API 调用**:统一使用封装的 request 方法,保持一致性 +6. **错误处理**:统一错误处理机制,提供良好的用户体验 +7. **代码注释**:关键逻辑添加注释,提高代码可读性 + diff --git a/Moncter/提示词/当前架构设计/前端功能说明.md b/Moncter/提示词/当前架构设计/前端功能说明.md new file mode 100644 index 00000000..c1fde74b --- /dev/null +++ b/Moncter/提示词/当前架构设计/前端功能说明.md @@ -0,0 +1,666 @@ +# 前端功能说明 + +## 一、系统概述 + +TaskShow 是一个基于 Vue 3 + TypeScript + Element Plus 的前端管理系统,主要用于数据采集任务管理、标签任务管理、标签查询和用户管理等核心功能。 + +## 二、功能模块 + +### 1. 首页仪表盘 (Dashboard) + +**路由**: `/dashboard` +**组件**: `src/views/Dashboard/index.vue` + +**功能说明**: +- 显示系统核心统计数据 + - 数据采集任务总数 + - 标签任务总数 + - 运行中任务数量 + - 用户总数 +- 展示最近任务列表(数据采集任务和标签任务) +- 提供快速操作入口 + - 创建数据采集任务 + - 创建标签任务 + - 标签筛选 + - 标签查询 + +**数据来源**: +- 通过 Pinia Store 获取任务列表 +- 统计运行中任务数量 +- 展示最近更新的任务 + +--- + +### 2. 数据采集模块 (Data Collection) + +#### 2.1 数据采集任务列表 + +**路由**: `/data-collection/tasks` +**组件**: `src/views/DataCollection/TaskList.vue` + +**功能说明**: +- 展示所有数据采集任务列表 +- 支持按任务名称、状态筛选 +- 支持分页显示 +- 提供任务操作功能: + - 查看任务详情 + - 编辑任务 + - 删除任务 + - 启动/暂停/停止任务 + - 查看任务进度 + +**API 接口**: +- `getDataCollectionTaskList` - 获取任务列表 +- `deleteDataCollectionTask` - 删除任务 +- `startDataCollectionTask` - 启动任务 +- `pauseDataCollectionTask` - 暂停任务 +- `stopDataCollectionTask` - 停止任务 + +#### 2.2 创建/编辑数据采集任务 + +**路由**: +- 创建:`/data-collection/tasks/create` +- 编辑:`/data-collection/tasks/:id/edit` + +**组件**: `src/views/DataCollection/TaskForm.vue` + +**功能说明**: +- 创建或编辑数据采集任务 +- 配置任务基本信息: + - 任务名称、描述 + - 数据源选择(源数据源、目标数据源) + - 数据库和集合选择 + - 单集合/多集合模式 +- 配置字段映射: + - 源字段到目标字段的映射 + - 字段转换规则 + - 值映射配置 +- 配置 Lookup 关联: + - 多集合关联查询配置 +- 配置过滤条件: + - 数据筛选条件 +- 配置调度计划: + - 启用/禁用定时任务 + - Cron 表达式配置 +- 预览查询结果: + - 验证配置是否正确 + - 查看查询结果示例 + +**API 接口**: +- `getDataSources` - 获取数据源列表 +- `getDatabases` - 获取数据库列表 +- `getCollections` - 获取集合列表 +- `getFields` - 获取字段列表 +- `getHandlerTargetFields` - 获取目标字段列表 +- `previewQuery` - 预览查询结果 +- `createDataCollectionTask` - 创建任务 +- `updateDataCollectionTask` - 更新任务 +- `getDataCollectionTaskDetail` - 获取任务详情 + +#### 2.3 数据采集任务详情 + +**路由**: `/data-collection/tasks/:id` +**组件**: `src/views/DataCollection/TaskDetail.vue` + +**功能说明**: +- 展示任务详细信息 +- 显示任务配置信息 +- 显示任务执行进度: + - 处理数量、成功数量、错误数量 + - 进度百分比 + - 开始时间、结束时间 + - 最后同步时间 +- 显示任务统计信息 +- 显示任务执行历史 +- 提供任务操作按钮(启动、暂停、停止、编辑、删除) + +**API 接口**: +- `getDataCollectionTaskDetail` - 获取任务详情 +- `getDataCollectionTaskProgress` - 获取任务进度 +- 任务操作相关接口 + +--- + +### 3. 数据源管理模块 (Data Source) + +#### 3.1 数据源列表 + +**路由**: `/data-sources` +**组件**: `src/views/DataSource/List.vue` + +**功能说明**: +- 展示所有数据源配置列表 +- 支持按类型、状态、名称筛选 +- 支持分页显示 +- 显示数据源基本信息: + - 名称、类型、主机、端口、数据库 + - 状态(启用/禁用) +- 提供数据源操作: + - 查看详情 + - 编辑配置 + - 删除数据源 + - 测试连接 + +**API 接口**: +- `getDataSourceList` - 获取数据源列表 +- `deleteDataSource` - 删除数据源 +- `testDataSourceConnection` - 测试连接 + +#### 3.2 创建/编辑数据源 + +**路由**: +- 创建:`/data-sources/create` +- 编辑:`/data-sources/:id/edit` + +**组件**: `src/views/DataSource/Form.vue` + +**功能说明**: +- 创建或编辑数据源配置 +- 配置数据源基本信息: + - 名称、类型(MongoDB、MySQL、PostgreSQL) + - 主机、端口、数据库名 + - 用户名、密码(加密存储) + - 认证源(MongoDB) + - 其他选项配置 +- 测试数据源连接 +- 标记是否为标签引擎数据库 + +**API 接口**: +- `createDataSource` - 创建数据源 +- `updateDataSource` - 更新数据源 +- `getDataSourceDetail` - 获取数据源详情 +- `testDataSourceConnection` - 测试连接 + +--- + +### 4. 标签任务模块 (Tag Task) + +#### 4.1 标签任务列表 + +**路由**: `/tag-tasks` +**组件**: `src/views/TagTask/TaskList.vue` + +**功能说明**: +- 展示所有标签任务列表 +- 支持按任务名称、类型、状态筛选 +- 支持分页显示 +- 显示任务基本信息: + - 任务名称、类型、状态 + - 目标标签、用户范围 + - 创建时间、更新时间 +- 提供任务操作: + - 查看任务详情 + - 编辑任务 + - 删除任务 + - 启动/暂停/停止任务 + +**API 接口**: +- `getTagTaskList` - 获取任务列表 +- `deleteTagTask` - 删除任务 +- `startTagTask` - 启动任务 +- `pauseTagTask` - 暂停任务 +- `stopTagTask` - 停止任务 + +#### 4.2 创建/编辑标签任务 + +**路由**: +- 创建:`/tag-tasks/create` +- 编辑:`/tag-tasks/:id/edit` + +**组件**: `src/views/TagTask/TaskForm.vue` + +**功能说明**: +- 创建或编辑标签任务 +- 配置任务基本信息: + - 任务名称、描述 + - 任务类型(全量、增量、指定) +- 配置目标标签: + - 选择要计算的标签列表 +- 配置用户范围: + - 全部用户 + - 指定用户列表 + - 按条件筛选用户 +- 配置调度计划: + - 启用/禁用定时任务 + - Cron 表达式配置 +- 配置任务参数: + - 并发数、批次大小 + - 错误处理策略 + +**API 接口**: +- `getTagDefinitionList` - 获取标签定义列表(用于选择目标标签) +- `createTagTask` - 创建任务 +- `updateTagTask` - 更新任务 +- `getTagTaskDetail` - 获取任务详情 + +#### 4.3 标签任务详情 + +**路由**: `/tag-tasks/:id` +**组件**: `src/views/TagTask/TaskDetail.vue` + +**功能说明**: +- 展示任务详细信息 +- 显示任务配置信息 +- 显示任务执行进度: + - 总用户数、已处理用户数 + - 成功数量、错误数量 + - 进度百分比 +- 显示任务统计信息: + - 总执行次数 + - 成功/失败次数 + - 最后执行时间 +- 显示任务执行记录列表 +- 提供任务操作按钮(启动、暂停、停止、编辑、删除) + +**API 接口**: +- `getTagTaskDetail` - 获取任务详情 +- `getTagTaskExecutions` - 获取执行记录 + +--- + +### 5. 标签定义模块 (Tag Definition) + +#### 5.1 标签定义列表 + +**路由**: `/tag-definitions` +**组件**: `src/views/TagDefinition/List.vue` + +**功能说明**: +- 展示所有标签定义列表 +- 支持按名称、分类、状态筛选 +- 支持分页显示 +- 显示标签基本信息: + - 标签代码、名称、分类 + - 规则类型、更新频率 + - 状态(启用/禁用) + - 优先级、版本 +- 提供标签操作: + - 查看详情 + - 编辑标签 + - 删除标签 + - 批量初始化 + +**API 接口**: +- `getTagDefinitionList` - 获取标签定义列表 +- `deleteTagDefinition` - 删除标签定义 +- `batchInitTagDefinitions` - 批量初始化 + +#### 5.2 创建/编辑标签定义 + +**路由**: +- 创建:`/tag-definitions/create` +- 编辑:`/tag-definitions/:id/edit` + +**组件**: `src/views/TagDefinition/Form.vue` + +**功能说明**: +- 创建或编辑标签定义 +- 配置标签基本信息: + - 标签代码、名称、分类 + - 描述 +- 配置规则类型: + - 简单规则 + - 管道规则 + - 自定义规则 +- 配置规则条件: + - 字段、操作符、值 + - 多个条件的逻辑关系 +- 配置标签值: + - 标签值的计算方式 +- 配置更新频率: + - 实时、每日、每周、每月 +- 配置优先级和版本 + +**API 接口**: +- `createTagDefinition` - 创建标签定义 +- `updateTagDefinition` - 更新标签定义 +- `getTagDefinitionDetail` - 获取标签定义详情 + +#### 5.3 标签定义详情 + +**路由**: `/tag-definitions/:id` +**组件**: `src/views/TagDefinition/Detail.vue` + +**功能说明**: +- 展示标签定义详细信息 +- 显示标签配置信息 +- 显示规则配置详情 +- 显示标签统计信息(如果有) +- 提供编辑和删除操作 + +**API 接口**: +- `getTagDefinitionDetail` - 获取标签定义详情 + +--- + +### 6. 标签筛选模块 (Tag Filter) + +**路由**: `/tag-filter` +**组件**: `src/views/TagFilter/index.vue` + +**功能说明**: +- 根据标签条件筛选用户 +- 支持多条件组合: + - 添加多个标签条件 + - 设置条件逻辑关系(AND/OR) +- 支持多种操作符: + - 等于、不等于 + - 大于、大于等于、小于、小于等于 + - 包含、不包含 + - 在列表中、不在列表中 +- 显示筛选结果: + - 用户列表 + - 用户基本信息(姓名、手机号等) + - 用户标签信息 +- 支持分页显示 +- 支持导出筛选结果 +- 支持保存为人群快照 + +**API 接口**: +- `filterUsersByTags` - 根据标签筛选用户 +- `createTagCohort` - 创建人群快照(保存筛选结果) + +--- + +### 7. 标签查询模块 (Tag Query) + +#### 7.1 用户标签查询 + +**路由**: `/tag-query/user` +**组件**: `src/views/TagQuery/User.vue` + +**功能说明**: +- 通过用户ID或手机号查询用户标签 +- 显示用户基本信息: + - 用户ID、姓名、手机号 + - 消费总额、消费次数 + - 最后消费时间 +- 显示用户所有标签: + - 标签名称、代码、分类 + - 标签值、值类型 + - 置信度 + - 生效时间、过期时间 + - 更新时间 +- 支持重新计算用户标签 +- 支持删除用户标签 +- 支持查看标签历史记录 + +**API 接口**: +- `getUserTags` - 获取用户标签 +- `recalculateUserTags` - 重新计算用户标签 +- `deleteUserTag` - 删除用户标签 +- `getTagHistory` - 获取标签历史(按用户筛选) + +#### 7.2 标签统计 + +**路由**: `/tag-query/statistics` +**组件**: `src/views/TagQuery/Statistics.vue` + +**功能说明**: +- 展示标签统计信息 +- 标签覆盖度统计: + - 总用户数 + - 已打标签用户数 + - 覆盖率(百分比) +- 标签值分布: + - 各标签值的出现次数 + - 分布图表展示 +- 标签趋势数据: + - 按日期统计标签变更次数 + - 趋势图表展示 +- 支持按标签筛选 +- 支持按时间范围筛选 + +**API 接口**: +- `getTagStatistics` - 获取标签统计信息 + +#### 7.3 标签历史 + +**路由**: `/tag-query/history` +**组件**: `src/views/TagQuery/History.vue` + +**功能说明**: +- 展示标签变更历史记录 +- 支持多维度筛选: + - 按用户筛选 + - 按标签筛选 + - 按时间范围筛选 +- 显示历史记录详情: + - 用户ID + - 标签ID、标签名称 + - 旧值、新值 + - 变更原因 + - 变更时间 + - 操作人 +- 支持分页显示 +- 支持导出历史记录 + +**API 接口**: +- `getTagHistory` - 获取标签历史记录 + +--- + +## 三、公共组件 + +### 1. Layout 布局组件 + +**组件**: `src/components/Layout/index.vue` + +**功能说明**: +- 提供系统整体布局结构 +- 侧边栏导航菜单: + - 首页 + - 数据采集(任务列表、数据源配置) + - 标签任务(任务列表、标签定义) + - 标签筛选 + - 标签查询(用户标签、标签统计、标签历史) +- 顶部导航栏: + - 侧边栏折叠/展开按钮 + - 用户信息下拉菜单 +- 主内容区域: + - 路由视图容器 + +### 2. StatusBadge 状态徽章 + +**组件**: `src/components/StatusBadge/index.vue` + +**功能说明**: +- 显示任务状态的可视化组件 +- 支持多种状态: + - pending(待处理)- 灰色 + - running(运行中)- 蓝色 + - paused(已暂停)- 黄色 + - stopped(已停止)- 橙色 + - completed(已完成)- 绿色 + - error(错误)- 红色 + +### 3. ProgressDisplay 进度显示 + +**组件**: `src/components/ProgressDisplay/index.vue` + +**功能说明**: +- 显示任务执行进度的可视化组件 +- 显示进度条和百分比 +- 显示处理数量、成功数量、错误数量 + +--- + +## 四、工具函数 + +### 1. 格式化工具 (`utils/format.ts`) + +- `formatDateTime` - 格式化日期时间(默认格式:YYYY-MM-DD HH:mm:ss) +- `formatDate` - 格式化日期(格式:YYYY-MM-DD) +- `formatTime` - 格式化时间(格式:HH:mm:ss) +- `formatRelativeTime` - 相对时间格式化(如:1分钟前、2小时前) + +### 2. 数据脱敏工具 (`utils/mask.ts`) + +- `maskPhone` - 脱敏手机号(如:138****8000) +- `maskIdCard` - 脱敏身份证号(如:110101********1234) +- `maskBankCard` - 脱敏银行卡号 +- `maskName` - 脱敏姓名(如:张*、李**) +- `maskEmail` - 脱敏邮箱 + +### 3. 表单验证工具 (`utils/validator.ts`) + +- 提供常用的表单验证规则 +- 手机号、邮箱、身份证等格式验证 + +--- + +## 五、路由配置 + +### 路由结构 + +``` +/ (Layout) + ├── /dashboard (首页) + │ + ├── /data-collection (数据采集) + │ ├── /tasks (任务列表) + │ ├── /tasks/create (创建任务) + │ ├── /tasks/:id (任务详情) + │ └── /tasks/:id/edit (编辑任务) + │ + ├── /data-sources (数据源) + │ ├── / (数据源列表) + │ ├── /create (创建数据源) + │ └── /:id/edit (编辑数据源) + │ + ├── /tag-tasks (标签任务) + │ ├── / (任务列表) + │ ├── /create (创建任务) + │ ├── /:id (任务详情) + │ └── /:id/edit (编辑任务) + │ + ├── /tag-definitions (标签定义) + │ ├── / (标签列表) + │ ├── /create (创建标签) + │ ├── /:id (标签详情) + │ └── /:id/edit (编辑标签) + │ + ├── /tag-filter (标签筛选) + │ + └── /tag-query (标签查询) + ├── /user (用户标签查询) + ├── /statistics (标签统计) + └── /history (标签历史) +``` + +--- + +## 六、状态管理 (Pinia Store) + +### 1. User Store (`store/user.ts`) + +- 管理用户登录状态 +- 管理 Token +- 用户信息 + +### 2. DataCollection Store (`store/dataCollection.ts`) + +- 管理数据采集任务列表 +- 提供任务操作方法(获取、创建、更新、删除等) + +### 3. TagTask Store (`store/tagTask.ts`) + +- 管理标签任务列表 +- 提供任务操作方法 + +### 4. TagDefinition Store (`store/tagDefinition.ts`) + +- 管理标签定义列表 +- 提供标签定义操作方法 + +### 5. DataSource Store (`store/dataSource.ts`) + +- 管理数据源列表 +- 提供数据源操作方法 + +--- + +## 七、功能特性总结 + +### 1. 核心功能 + +- ✅ 数据采集任务管理(创建、编辑、删除、启动、暂停、停止) +- ✅ 数据源管理(配置、测试连接) +- ✅ 标签任务管理(创建、编辑、删除、执行) +- ✅ 标签定义管理(创建、编辑、删除、批量初始化) +- ✅ 标签查询(用户标签、标签统计、标签历史) +- ✅ 标签筛选(多条件组合筛选用户) +- ✅ 人群快照(保存筛选结果、导出) + +### 2. 用户体验 + +- ✅ 统一的 UI 设计(Element Plus) +- ✅ 响应式布局 +- ✅ Loading 状态提示 +- ✅ 错误提示和处理 +- ✅ 数据脱敏显示 +- ✅ 日期时间格式化显示 + +### 3. 技术特性 + +- ✅ TypeScript 类型安全 +- ✅ 组件化开发 +- ✅ 状态管理(Pinia) +- ✅ 路由管理(Vue Router) +- ✅ API 统一封装 +- ✅ 工具函数复用 + +--- + +## 八、使用说明 + +### 1. 开发环境启动 + +```bash +cd TaskShow +npm install # 或 yarn install 或 pnpm install +npm run dev # 启动开发服务器 +``` + +### 2. 构建生产版本 + +```bash +npm run build +``` + +### 3. 预览构建结果 + +```bash +npm run preview +``` + +### 4. 代码检查 + +```bash +npm run lint +``` + +--- + +## 九、注意事项 + +1. **API 地址配置**: + - 开发环境通过 Vite 代理配置 + - 生产环境通过环境变量 `VITE_API_BASE_URL` 配置 + +2. **Token 管理**: + - Token 存储在 Pinia Store 中 + - 请求时自动添加到请求头 + +3. **错误处理**: + - HTTP 错误和业务错误在请求拦截器中统一处理 + - 组件中只需处理业务逻辑 + +4. **数据脱敏**: + - 敏感信息(手机号、身份证等)使用脱敏工具函数处理 + - 确保数据安全显示 + +5. **类型安全**: + - 所有 API 接口都有完整的 TypeScript 类型定义 + - 建议启用严格模式以获得更好的类型检查 + diff --git a/Moncter/提示词/当前架构设计/前端已对接API说明.md b/Moncter/提示词/当前架构设计/前端已对接API说明.md new file mode 100644 index 00000000..5d9adb5f --- /dev/null +++ b/Moncter/提示词/当前架构设计/前端已对接API说明.md @@ -0,0 +1,693 @@ +# 前端已对接API说明 + +## 一、API 架构设计 + +### 1. 请求封装 + +所有 API 调用通过 `src/utils/request.ts` 封装的 `request` 实例,提供以下特性: + +- ✅ 自动添加 Token 到请求头(从 Pinia Store 获取) +- ✅ 统一错误处理和提示(HTTP 错误、业务错误) +- ✅ 自动显示/隐藏 Loading(可配置) +- ✅ 完整的 TypeScript 类型支持 +- ✅ 支持自定义配置(showLoading、showError、timeout 等) + +### 2. API 文件组织 + +API 文件按业务模块划分,位于 `src/api/` 目录: + +- `dataCollection.ts` - 数据采集任务相关 API +- `dataSource.ts` - 数据源管理相关 API +- `tagTask.ts` - 标签任务相关 API +- `tagDefinition.ts` - 标签定义相关 API +- `tagQuery.ts` - 标签查询相关 API +- `tagCohort.ts` - 人群快照相关 API +- `user.ts` - 用户相关 API + +### 3. 类型定义 + +所有 API 的请求参数和响应数据都有完整的 TypeScript 类型定义,位于: +- `src/types/index.ts` - 业务实体类型 +- `src/types/api.ts` - API 响应类型 + +## 二、已对接 API 列表 + +### 1. 数据采集任务 API (`dataCollection.ts`) + +#### 1.1 获取数据采集任务列表 +```typescript +getDataCollectionTaskList(params: { + name?: string + status?: string + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /data-collection-tasks` +- **功能**: 获取数据采集任务列表,支持按名称、状态筛选和分页 + +#### 1.2 获取数据采集任务详情 +```typescript +getDataCollectionTaskDetail(taskId: string): Promise> +``` +- **路径**: `GET /data-collection-tasks/:id` +- **功能**: 获取指定任务的详细信息 + +#### 1.3 创建数据采集任务 +```typescript +createDataCollectionTask(data: Partial): Promise> +``` +- **路径**: `POST /data-collection-tasks` +- **功能**: 创建新的数据采集任务 + +#### 1.4 更新数据采集任务 +```typescript +updateDataCollectionTask(taskId: string, data: Partial): Promise> +``` +- **路径**: `PUT /data-collection-tasks/:id` +- **功能**: 更新指定任务的信息 + +#### 1.5 删除数据采集任务 +```typescript +deleteDataCollectionTask(taskId: string): Promise +``` +- **路径**: `DELETE /data-collection-tasks/:id` +- **功能**: 删除指定任务 + +#### 1.6 启动数据采集任务 +```typescript +startDataCollectionTask(taskId: string): Promise +``` +- **路径**: `POST /data-collection-tasks/:id/start` +- **功能**: 启动指定任务 + +#### 1.7 暂停数据采集任务 +```typescript +pauseDataCollectionTask(taskId: string): Promise +``` +- **路径**: `POST /data-collection-tasks/:id/pause` +- **功能**: 暂停指定任务 + +#### 1.8 停止数据采集任务 +```typescript +stopDataCollectionTask(taskId: string): Promise +``` +- **路径**: `POST /data-collection-tasks/:id/stop` +- **功能**: 停止指定任务 + +#### 1.9 获取任务进度 +```typescript +getDataCollectionTaskProgress(taskId: string): Promise +``` +- **路径**: `GET /data-collection-tasks/:id/progress` +- **功能**: 获取任务执行进度 + +#### 1.10 获取数据源列表 +```typescript +getDataSources(): Promise> +``` +- **路径**: `GET /data-collection-tasks/data-sources` +- **功能**: 获取所有可用的数据源列表 + +#### 1.11 获取数据库列表 +```typescript +getDatabases(dataSourceId: string): Promise>> +``` +- **路径**: `GET /data-collection-tasks/data-sources/:id/databases` +- **功能**: 获取指定数据源的数据库列表 + +#### 1.12 获取集合列表 +```typescript +getCollections(dataSourceId: string, database: string | { name: string; id: string }): Promise>> +``` +- **路径**: `GET /data-collection-tasks/data-sources/:id/databases/:db/collections` +- **功能**: 获取指定数据库的集合列表 + +#### 1.13 获取字段列表 +```typescript +getFields(dataSourceId: string, database: string | { name: string; id: string }, collection: string | { name: string; id: string }): Promise>> +``` +- **路径**: `GET /data-collection-tasks/data-sources/:id/databases/:db/collections/:coll/fields` +- **功能**: 获取指定集合的字段列表 + +#### 1.14 获取Handler目标字段列表 +```typescript +getHandlerTargetFields(handlerType: string): Promise>> +``` +- **路径**: `GET /data-collection-tasks/handlers/:type/target-fields` +- **功能**: 获取指定 Handler 类型的目标字段列表 + +#### 1.15 预览查询结果 +```typescript +previewQuery(data: { + data_source_id: string + database: string + collection: string + lookups?: any[] + filter_conditions?: any[] + limit?: number +}): Promise + data: Array + count: number +}>> +``` +- **路径**: `POST /data-collection-tasks/preview-query` +- **功能**: 预览查询结果,用于验证配置 + +--- + +### 2. 数据源管理 API (`dataSource.ts`) + +#### 2.1 获取数据源列表 +```typescript +getDataSourceList(params?: { + type?: string + status?: number + name?: string + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /data-sources` +- **功能**: 获取数据源列表,支持按类型、状态、名称筛选和分页 + +#### 2.2 获取数据源详情 +```typescript +getDataSourceDetail(dataSourceId: string): Promise> +``` +- **路径**: `GET /data-sources/:id` +- **功能**: 获取指定数据源的详细信息 + +#### 2.3 创建数据源 +```typescript +createDataSource(data: Partial): Promise> +``` +- **路径**: `POST /data-sources` +- **功能**: 创建新的数据源配置 + +#### 2.4 更新数据源 +```typescript +updateDataSource(dataSourceId: string, data: Partial): Promise> +``` +- **路径**: `PUT /data-sources/:id` +- **功能**: 更新指定数据源的配置 + +#### 2.5 删除数据源 +```typescript +deleteDataSource(dataSourceId: string): Promise +``` +- **路径**: `DELETE /data-sources/:id` +- **功能**: 删除指定数据源 + +#### 2.6 测试数据源连接 +```typescript +testDataSourceConnection(data: { + type: string + host: string + port: number + database: string + username?: string + password?: string + auth_source?: string + options?: Record +}): Promise> +``` +- **路径**: `POST /data-sources/test-connection` +- **功能**: 测试数据源连接是否正常 + +--- + +### 3. 标签任务 API (`tagTask.ts`) + +#### 3.1 获取标签任务列表 +```typescript +getTagTaskList(params: { + name?: string + task_type?: string + status?: string + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /tag-tasks` +- **功能**: 获取标签任务列表,支持按名称、类型、状态筛选和分页 + +#### 3.2 获取标签任务详情 +```typescript +getTagTaskDetail(taskId: string): Promise> +``` +- **路径**: `GET /tag-tasks/:id` +- **功能**: 获取指定标签任务的详细信息 + +#### 3.3 创建标签任务 +```typescript +createTagTask(data: Partial): Promise> +``` +- **路径**: `POST /tag-tasks` +- **功能**: 创建新的标签任务 + +#### 3.4 更新标签任务 +```typescript +updateTagTask(taskId: string, data: Partial): Promise> +``` +- **路径**: `PUT /tag-tasks/:id` +- **功能**: 更新指定标签任务的信息 + +#### 3.5 删除标签任务 +```typescript +deleteTagTask(taskId: string): Promise +``` +- **路径**: `DELETE /tag-tasks/:id` +- **功能**: 删除指定标签任务 + +#### 3.6 启动标签任务 +```typescript +startTagTask(taskId: string): Promise +``` +- **路径**: `POST /tag-tasks/:id/start` +- **功能**: 启动指定标签任务 + +#### 3.7 暂停标签任务 +```typescript +pauseTagTask(taskId: string): Promise +``` +- **路径**: `POST /tag-tasks/:id/pause` +- **功能**: 暂停指定标签任务 + +#### 3.8 停止标签任务 +```typescript +stopTagTask(taskId: string): Promise +``` +- **路径**: `POST /tag-tasks/:id/stop` +- **功能**: 停止指定标签任务 + +#### 3.9 获取任务执行记录 +```typescript +getTagTaskExecutions(taskId: string, params?: { + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /tag-tasks/:id/executions` +- **功能**: 获取指定任务的执行记录列表 + +--- + +### 4. 标签定义 API (`tagDefinition.ts`) + +#### 4.1 获取标签定义列表 +```typescript +getTagDefinitionList(params?: { + name?: string + category?: string + status?: number + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /tag-definitions` +- **功能**: 获取标签定义列表,支持按名称、分类、状态筛选和分页 + +#### 4.2 获取标签定义详情 +```typescript +getTagDefinitionDetail(tagId: string): Promise> +``` +- **路径**: `GET /tag-definitions/:id` +- **功能**: 获取指定标签定义的详细信息 + +#### 4.3 创建标签定义 +```typescript +createTagDefinition(data: Partial): Promise> +``` +- **路径**: `POST /tag-definitions` +- **功能**: 创建新的标签定义 + +#### 4.4 更新标签定义 +```typescript +updateTagDefinition(tagId: string, data: Partial): Promise> +``` +- **路径**: `PUT /tag-definitions/:id` +- **功能**: 更新指定标签定义的信息 + +#### 4.5 删除标签定义 +```typescript +deleteTagDefinition(tagId: string): Promise +``` +- **路径**: `DELETE /tag-definitions/:id` +- **功能**: 删除指定标签定义 + +#### 4.6 批量初始化标签定义 +```typescript +batchInitTagDefinitions(data: { + definitions: Partial[] +}): Promise +``` +- **路径**: `POST /tag-definitions/batch` +- **功能**: 批量创建标签定义 + +--- + +### 5. 标签查询 API (`tagQuery.ts`) + +#### 5.1 获取用户标签 +```typescript +getUserTags(userIdOrPhone: string): Promise> +``` +- **路径**: `GET /users/:userIdOrPhone/tags` +- **功能**: 获取指定用户(通过用户ID或手机号)的所有标签 + +#### 5.2 重新计算用户标签 +```typescript +recalculateUserTags(userId: string): Promise + count: number +}>> +``` +- **路径**: `PUT /users/:userId/tags` +- **功能**: 重新计算指定用户的所有标签 + +#### 5.3 根据标签筛选用户 +```typescript +filterUsersByTags(params: { + tag_conditions: TagCondition[] + logic: 'AND' | 'OR' + page?: number + page_size?: number + include_user_info?: boolean +}): Promise> +``` +- **路径**: `POST /tags/filter` +- **功能**: 根据标签条件筛选用户列表 + +#### 5.4 获取标签统计信息 +```typescript +getTagStatistics(params?: { + tag_id?: string + start_date?: string + end_date?: string +}): Promise> +``` +- **路径**: `GET /tags/statistics` +- **功能**: 获取标签统计信息(值分布、趋势数据、覆盖度统计) + +#### 5.5 获取标签历史记录 +```typescript +getTagHistory(params?: { + user_id?: string + tag_id?: string + start_date?: string + end_date?: string + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /tags/history` +- **功能**: 获取标签变更历史记录,支持按用户、标签、时间范围筛选和分页 + +--- + +### 6. 人群快照 API (`tagCohort.ts`) + +#### 6.1 获取人群快照列表 +```typescript +getTagCohortList(params?: { + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `GET /tag-cohorts` +- **功能**: 获取人群快照列表,支持分页 + +#### 6.2 获取人群快照详情 +```typescript +getTagCohortDetail(cohortId: string): Promise> +``` +- **路径**: `GET /tag-cohorts/:id` +- **功能**: 获取指定人群快照的详细信息 + +#### 6.3 创建人群快照 +```typescript +createTagCohort(data: { + name: string + description?: string + conditions: TagCondition[] + logic?: 'AND' | 'OR' + user_ids?: string[] + created_by?: string +}): Promise> +``` +- **路径**: `POST /tag-cohorts` +- **功能**: 创建新的人群快照(支持条件筛选或直接指定用户列表) + +#### 6.4 删除人群快照 +```typescript +deleteTagCohort(cohortId: string): Promise +``` +- **路径**: `DELETE /tag-cohorts/:id` +- **功能**: 删除指定人群快照 + +#### 6.5 导出人群快照 +```typescript +exportTagCohort(cohortId: string): Promise +``` +- **路径**: `POST /tag-cohorts/:id/export` +- **功能**: 导出人群快照为 CSV 文件(返回 Blob 对象) + +--- + +### 7. 用户 API (`user.ts`) + +#### 7.1 搜索用户 +```typescript +searchUsers(params: { + id_card?: string + phone?: string + name?: string + page?: number + page_size?: number +}): Promise> +``` +- **路径**: `POST /users/search` +- **功能**: 根据身份证、手机号、姓名搜索用户 + +#### 7.2 解密身份证 +```typescript +decryptIdCard(userId: string): Promise> +``` +- **路径**: `GET /users/:userId/decrypt-id-card` +- **功能**: 解密指定用户的身份证号(需要权限) + +#### 7.3 删除用户标签 +```typescript +deleteUserTag(userId: string, tagId: string): Promise +``` +- **路径**: `DELETE /users/:userId/tags/:tagId` +- **功能**: 删除指定用户的指定标签 + +--- + +## 三、API 使用示例 + +### 1. 基本使用 + +```typescript +import { getTagStatistics } from '@/api/tagQuery' + +// 获取所有标签的覆盖度统计 +const stats = await getTagStatistics() + +// 获取指定标签的值分布和趋势 +const tagStats = await getTagStatistics({ + tag_id: 'tag1', + start_date: '2025-01-01', + end_date: '2025-01-31' +}) +``` + +### 2. 错误处理 + +```typescript +try { + const response = await getTagStatistics() + // 处理成功响应 + console.log(response.data) +} catch (error: any) { + // 错误已在拦截器中提示,这里只需处理业务逻辑 + console.error('加载统计失败:', error) +} +``` + +### 3. 在组件中使用 + +```vue + +``` + +### 4. 在 Store 中使用 + +```typescript +import { defineStore } from 'pinia' +import { getTagStatistics } from '@/api/tagQuery' +import type { TagStatistics } from '@/types' + +export const useTagQueryStore = defineStore('tagQuery', () => { + const statistics = ref(null) + + const fetchStatistics = async (params?: any) => { + const response = await getTagStatistics(params) + statistics.value = response.data + return response.data + } + + return { + statistics, + fetchStatistics + } +}) +``` + +## 四、API 配置说明 + +### 1. 后端地址配置 + +- **开发环境**:通过 Vite 代理配置,请求 `/api` 自动转发到 `http://127.0.0.1:8787` +- **生产环境**:通过环境变量 `VITE_API_BASE_URL` 配置实际 API 地址 + +### 2. 请求拦截器 + +- 自动从 Pinia Store 获取 Token 并添加到请求头:`Authorization: Bearer ${token}` +- 自动显示 Loading(可配置 `showLoading: false` 关闭) +- 统一处理 HTTP 错误和业务错误 + +### 3. 响应拦截器 + +- 自动关闭 Loading +- 根据业务状态码(code === 200 或 code === 0)判断成功 +- 统一错误提示(可配置 `showError: false` 关闭) + +## 五、API 统计 + +| 模块 | API 数量 | 状态 | +|------|---------|------| +| 数据采集任务 | 15 | ✅ 已对接 | +| 数据源管理 | 6 | ✅ 已对接 | +| 标签任务 | 9 | ✅ 已对接 | +| 标签定义 | 6 | ✅ 已对接 | +| 标签查询 | 5 | ✅ 已对接 | +| 人群快照 | 5 | ✅ 已对接 | +| 用户 | 3 | ✅ 已对接 | +| **总计** | **49** | **✅ 全部完成** | + +## 六、注意事项 + +1. **分页参数**: + - `page` 从 1 开始 + - `page_size` 默认 20,最大 100 + +2. **日期格式**: + - `start_date` 和 `end_date` 使用 `YYYY-MM-DD` 格式 + - 例如:`'2025-01-01'` + +3. **人群快照创建**: + - 如果提供 `user_ids`,直接使用提供的用户列表 + - 如果不提供 `user_ids`,会根据 `conditions` 自动筛选用户 + - 最多支持 10000 个用户 + +4. **导出功能**: + - `exportTagCohort` 返回的是 Blob 对象 + - 需要使用 `window.URL.createObjectURL` 创建下载链接 + +5. **类型安全**: + - 所有接口都有完整的 TypeScript 类型定义 + - 建议启用严格模式以获得更好的类型检查 + +6. **错误处理**: + - HTTP 错误(401、403、404、500 等)会在拦截器中自动处理 + - 业务错误(code !== 200 && code !== 0)会在拦截器中提示 + - 组件中只需处理业务逻辑,无需重复处理错误提示 + diff --git a/Moncter/提示词/当前架构设计/数据采集业务逻辑.md b/Moncter/提示词/当前架构设计/数据采集业务逻辑.md new file mode 100644 index 00000000..1a03c759 --- /dev/null +++ b/Moncter/提示词/当前架构设计/数据采集业务逻辑.md @@ -0,0 +1,1089 @@ +# 数据采集业务逻辑 + +## 一、系统概述 + +数据采集系统是项目的核心模块之一,负责从多个数据源采集数据并写入目标数据库。系统支持批量采集和实时监听两种模式,通过配置化的方式灵活管理采集任务。 + +### 1.1 核心组件 + +- **DataSyncScheduler** - 数据采集任务调度器(Workerman进程) +- **DataCollectionTaskService** - 数据采集任务管理服务 +- **DataSourceService** - 数据源管理服务 +- **DataSourceAdapterFactory** - 数据源适配器工厂 +- **Handler** - 业务处理类(ConsumptionCollectionHandler、GenericCollectionHandler、DatabaseSyncHandler) +- **DataSyncWorker** - 数据同步Worker(消费RabbitMQ消息队列) + +### 1.2 数据存储 + +- **data_collection_tasks** - 数据采集任务集合 +- **data_sources** - 数据源配置集合 +- **consumption_records** - 消费记录集合(按时间分表) +- **user_profile** - 用户画像集合 +- **user_phone_relations** - 手机号关联集合 + +--- + +## 二、任务配置体系 + +### 2.1 配置方式 + +系统支持两种任务配置方式: + +#### 2.1.1 配置文件方式 + +配置文件:`config/data_collection_tasks.php` + +**适用场景**: +- 系统级任务(如数据库实时同步) +- 需要版本控制的配置 +- 固定不变的采集任务 + +**配置示例**: +```php +'tasks' => [ + 'database_sync' => [ + 'name' => '数据库实时同步', + 'enabled' => false, + 'source_data_source' => 'kr_mongodb', + 'target_data_source' => 'sync_mongodb', + 'handler_class' => DatabaseSyncHandler::class, + 'schedule' => [ + 'enabled' => false, // 持续运行,不需要定时调度 + ], + 'sharding' => [ + 'strategy' => 'by_database', // 按数据库分片 + ], + ], +] +``` + +#### 2.1.2 数据库方式 + +集合:`data_collection_tasks` + +**适用场景**: +- 通过前端界面动态创建的任务 +- 需要频繁修改的配置 +- 用户自定义的采集任务 + +**任务结构**: +```javascript +{ + task_id: String, // 任务ID(UUID) + name: String, // 任务名称 + description: String, // 任务描述 + data_source_id: String, // 源数据源ID + database: String, // 源数据库名 + collection: String, // 源集合名(单集合模式) + collections: Array, // 源集合列表(多集合模式) + target_type: String, // 目标类型(consumption_record/generic) + target_data_source_id: String, // 目标数据源ID + target_database: String, // 目标数据库名 + target_collection: String, // 目标集合名 + mode: String, // 采集模式(batch/realtime) + field_mappings: Array, // 字段映射配置 + collection_field_mappings: Object, // 多集合字段映射(key为集合名) + lookups: Array, // 连表查询配置 + collection_lookups: Object, // 多集合连表查询配置 + filter_conditions: Array, // 过滤条件 + schedule: { // 调度计划 + enabled: Boolean, // 是否启用定时任务 + cron: String // Cron 表达式 + }, + status: String, // 任务状态(pending/running/paused/stopped/error) + progress: { // 任务进度 + status: String, // 进度状态(idle/running/paused/completed/error) + processed_count: Number, // 已处理数量 + success_count: Number, // 成功数量 + error_count: Number, // 错误数量 + total_count: Number, // 总数量 + percentage: Number, // 完成百分比 + start_time: Date, // 开始时间 + end_time: Date, // 结束时间 + last_sync_time: Date // 最后同步时间 + }, + statistics: { // 任务统计 + total_processed: Number, // 总处理数量 + total_success: Number, // 总成功数量 + total_error: Number, // 总错误数量 + last_run_time: Date // 最后执行时间 + }, + created_by: String, + created_at: Date, + updated_at: Date +} +``` + +### 2.2 数据源配置 + +数据源配置存储在 `data_sources` 集合中,支持从数据库动态加载。 + +**数据源结构**: +```javascript +{ + data_source_id: String, // 数据源ID + name: String, // 数据源名称 + type: String, // 数据源类型(mongodb/mysql/postgresql) + host: String, // 主机地址 + port: Number, // 端口号 + database: String, // 数据库名 + username: String, // 用户名 + password: String, // 密码(加密存储) + auth_source: String, // 认证源(MongoDB) + is_tag_engine: Boolean, // 是否为标签引擎数据库 + status: Number, // 状态(0:禁用, 1:启用) + options: Object, // 连接选项 + created_at: Date, + updated_at: Date +} +``` + +--- + +## 三、任务执行流程 + +### 3.1 任务创建流程 + +``` +用户在前端创建任务 + ↓ +填写任务配置: + - 数据源选择 + - 数据库/集合选择 + - 字段映射配置 + - 过滤条件 + - 调度计划 + ↓ +API: POST /api/data-collection-tasks + ↓ +DataCollectionTaskService->createTask() + ├─→ 根据 target_type 自动处理目标数据源配置 + │ ├─→ consumption_record: 自动使用标签数据库 + │ └─→ generic: 使用用户指定的目标数据源 + ├─→ 清理字段映射(移除无效项) + ├─→ 构建任务文档 + └─→ 保存到 data_collection_tasks 集合 + ↓ +如果任务状态为 running,设置 Redis 启动标志 +``` + +### 3.2 任务启动流程 + +``` +用户点击"启动"按钮 + ↓ +API: POST /api/data-collection-tasks/{taskId}/start + ↓ +DataCollectionTaskService->startTask() + ├─→ 检查任务状态(不能是 running) + ├─→ 更新任务状态为 running + ├─→ 更新进度状态为 running + └─→ 设置 Redis 标志:data_collection_task:{taskId}:start + ↓ +DataSyncScheduler 进程检测到 Redis 标志 + ├─→ 从数据库加载任务配置 + ├─→ 转换为内部配置格式 + └─→ 根据任务模式执行: + ├─→ batch 模式:根据 schedule 配置定时执行或立即执行 + └─→ realtime 模式:立即启动,持续运行(Change Stream监听) +``` + +### 3.3 任务执行流程 + +``` +DataSyncScheduler->executeTask() + ├─→ 获取分布式锁(防止重复执行) + ├─→ 查询数据源配置(从缓存或数据库) + ├─→ 创建数据源适配器(DataSourceAdapterFactory) + ├─→ 实例化 Handler(根据 target_type 选择) + └─→ 调用 Handler->collect(adapter, taskConfig) + ↓ + Handler 执行采集逻辑 + ├─→ batch 模式:分页查询数据,批量处理 + └─→ realtime 模式:启动 Change Stream 监听 +``` + +### 3.4 任务状态管理 + +#### 3.4.1 暂停任务 + +``` +用户点击"暂停"按钮 + ↓ +API: POST /api/data-collection-tasks/{taskId}/pause + ↓ +DataCollectionTaskService->pauseTask() + ├─→ 检查任务状态(必须是 running) + ├─→ 更新任务状态为 paused + └─→ 设置 Redis 标志:data_collection_task:{taskId}:pause + ↓ +Handler 检测到暂停标志 + ↓ +停止处理新数据,等待当前批次完成 +``` + +#### 3.4.2 停止任务 + +``` +用户点击"停止"按钮 + ↓ +API: POST /api/data-collection-tasks/{taskId}/stop + ↓ +DataCollectionTaskService->stopTask() + ├─→ 更新任务状态为 stopped + ├─→ 更新进度状态为 stopped + └─→ 设置 Redis 标志:data_collection_task:{taskId}:stop + ↓ +Handler 检测到停止标志 + ↓ +立即停止处理 +``` + +--- + +## 四、数据采集模式 + +### 4.1 批量采集模式(Batch) + +**适用场景**: +- 历史数据迁移 +- 定时增量同步 +- 一次性数据采集 + +**执行流程**: +``` +1. 构建查询条件 + - 如果有 last_sync_time,只查询新数据 + - 应用 filter_conditions 过滤条件 + +2. 分页查询数据 + - 使用 batch_size 控制每批数量(默认1000) + - 按时间排序,确保顺序处理 + +3. 批量处理数据 + For each batch: + a. 应用字段映射(field_mappings) + b. 执行字段转换(类型转换、值映射) + c. 执行连表查询(lookups,如果有) + d. 写入目标数据库 + e. 更新任务进度 + +4. 更新同步状态 + - 记录 last_sync_time + - 更新任务进度和统计 +``` + +**调度方式**: +- **定时执行**:根据 Cron 表达式定时执行 +- **立即执行**:调度被禁用时,立即执行一次 + +### 4.2 实时监听模式(Realtime) + +**适用场景**: +- 实时数据同步 +- 数据库变更监听 +- 持续运行的数据采集 + +**执行流程**: +``` +1. 启动 Change Stream 监听 + - 监听指定集合的变更事件 + - 过滤操作类型(insert/update/delete) + +2. 持续监听变更 + For each change event: + a. 解析变更文档 + b. 应用字段映射和转换 + c. 写入目标数据库 + d. 更新同步状态 + +3. 错误处理和重连 + - 连接断开时自动重连 + - 记录错误日志 +``` + +**特点**: +- 持续运行,不自动停止 +- 实时响应数据变更 +- 支持断点续传(记录同步位置) + +--- + +## 五、Handler 处理机制 + +### 5.1 Handler 类型 + +系统通过 Handler 模式实现不同类型的数据采集: + +#### 5.1.1 ConsumptionCollectionHandler(消费记录采集) + +**职责**: +- 专门处理消费记录/订单数据采集 +- 支持 KR_商城 和 KR_金融 两种数据源 +- 自动提取手机号、解析用户ID +- 写入消费记录表(按时间分表) + +**处理流程**: +``` +1. 从源数据库查询订单数据 + - 支持单集合和多集合模式 + - 应用过滤条件 + +2. 字段映射和转换 + - 提取手机号(去除单引号等特殊字符) + - 转换金额字段(字符串→数字) + - 解析时间字段(字符串→DateTime) + - 转换订单状态 + +3. 身份解析 + - 通过手机号解析 user_id + - 如果不存在,创建临时人 + +4. 门店处理 + - 通过门店名称查找或创建门店 + - 获取或生成 store_id + +5. 写入消费记录 + - 调用 ConsumptionService->createRecord() + - 自动按时间分表(consumption_records_YYYYMM) + - 更新用户统计信息(total_amount, total_count) + - 触发标签计算(异步) + +6. 更新任务进度 +``` + +**字段映射示例**(KR_商城.21年贝蒂喜订单整合): +```json +{ + "phone_number": "联系手机", // 需要去除单引号 + "amount": "买家应付货款", // 字符串转数字 + "actual_amount": "买家实际支付金额", // 字符串转数字 + "consume_time": "订单付款时间", // 字符串转DateTime + "store_name": "店铺名称" // 自动转换为store_id +} +``` + +#### 5.1.2 GenericCollectionHandler(通用数据采集) + +**职责**: +- 支持动态字段映射 +- 支持批量采集和实时监听两种模式 +- 支持连表查询(lookup) +- 支持多集合采集 + +**处理流程**: +``` +1. 确定要处理的集合 + - 单集合模式:使用 collection + - 多集合模式:使用 collections 数组 + +2. 批量采集模式 + For each collection: + a. 构建查询条件(filter_conditions) + b. 分页查询数据 + c. 应用字段映射(field_mappings 或 collection_field_mappings) + d. 执行连表查询(lookups 或 collection_lookups) + e. 写入目标数据库 + f. 更新任务进度 + +3. 实时监听模式 + For each collection: + a. 启动 Change Stream 监听 + b. 处理变更事件 + c. 应用字段映射和转换 + d. 写入目标数据库 +``` + +**字段映射配置**: +```json +{ + "field_mappings": [ + { + "source_field": "源字段名", + "target_field": "目标字段名", + "transform": "转换函数名", // 可选 + "value_mapping": [ // 可选:值映射 + { + "source_value": "源值", + "target_value": "目标值" + } + ] + } + ] +} +``` + +**连表查询配置**: +```json +{ + "lookups": [ + { + "from": "关联集合名", + "local_field": "本地字段", + "foreign_field": "关联字段", + "as": "结果字段名" + } + ] +} +``` + +#### 5.1.3 DatabaseSyncHandler(数据库同步) + +**职责**: +- 全量同步:首次启动时同步所有数据 +- 增量同步:使用 MongoDB Change Streams 实时监听 +- 支持按数据库分片(多进程并行) + +**处理流程**: +``` +1. 全量同步(首次启动) + - 遍历源数据库的所有集合 + - 批量读取数据 + - 写入目标数据库 + - 记录同步进度 + +2. 增量同步(持续运行) + - 启动 Change Stream 监听 + - 监听所有集合的变更 + - 实时同步到目标数据库 + - 记录同步位置 +``` + +### 5.2 Handler 选择规则 + +系统根据任务的 `target_type` 自动选择 Handler: + +- `target_type = 'consumption_record'` → `ConsumptionCollectionHandler` +- `target_type = 'generic'` → `GenericCollectionHandler` +- 配置文件中的 `database_sync` 任务 → `DatabaseSyncHandler` + +--- + +## 六、数据源适配器 + +### 6.1 适配器工厂 + +`DataSourceAdapterFactory` 负责创建数据源适配器: + +```php +$adapter = DataSourceAdapterFactory::create( + $dataSourceConfig['type'], // mongodb/mysql/postgresql + $dataSourceConfig // 数据源配置 +); +``` + +### 6.2 支持的适配器类型 + +#### 6.2.1 MongoDBAdapter + +**功能**: +- 连接 MongoDB 数据库 +- 执行查询操作 +- 支持 Change Stream 监听 + +**使用场景**: +- MongoDB 数据源采集 +- 数据库实时同步 + +#### 6.2.2 MySQLAdapter + +**功能**: +- 连接 MySQL 数据库 +- 执行 SQL 查询 +- 支持事务处理 + +**使用场景**: +- MySQL 数据源采集 +- 关系型数据库同步 + +### 6.3 适配器接口 + +所有适配器实现 `DataSourceAdapterInterface` 接口: + +```php +interface DataSourceAdapterInterface +{ + public function connect(array $config): bool; + public function isConnected(): bool; + public function query(string $sql, array $params = []): array; + public function close(): void; +} +``` + +--- + +## 七、消息队列处理 + +### 7.1 数据同步队列 + +**队列名**:`data_sync` + +**消息格式**: +```json +{ + "source_id": "数据源ID", + "data": [ + { + "action": "insert|update|delete", + "collection": "集合名", + "document": {...} + } + ] +} +``` + +### 7.2 DataSyncWorker 处理流程 + +``` +Worker 启动 + ↓ +初始化 RabbitMQ 连接 + ├─→ 建立连接 + ├─→ 声明队列 + ├─→ 设置 QoS(prefetch_count = 10) + └─→ 开始消费消息 + ↓ +监听消息 + ↓ +收到消息 + ↓ +processMessage() + ├─→ 解析消息(JSON) + ├─→ 调用 DataSyncService->syncData() + │ ├─→ 写入目标数据库 + │ ├─→ 更新用户统计(如果是消费记录) + │ └─→ 返回同步结果 + ├─→ 记录日志 + └─→ 确认消息(ACK) + ├─→ 成功:message->ack() + └─→ 失败:记录错误,ack(不重试,避免重复数据) +``` + +### 7.3 错误处理 + +- **业务错误**:直接确认消息,不重试(避免重复数据) +- **系统错误**:记录错误日志,确认消息(不重试) + +--- + +## 八、任务调度机制 + +### 8.1 DataSyncScheduler 调度流程 + +``` +Worker 启动 + ↓ +onWorkerStart() + ├─→ 加载配置文件中的任务 + ├─→ 从数据库加载数据源配置 + ├─→ 加载数据库中的动态任务 + └─→ 每30秒刷新一次数据库任务列表 + ↓ +加载配置文件任务 + ├─→ 检查任务是否启用 + ├─→ 检查是否应该由当前 Worker 处理(分片分配) + └─→ 根据调度配置执行: + ├─→ schedule.enabled = false:立即启动(持续运行) + └─→ schedule.enabled = true:使用 Cron 定时执行 + ↓ +加载数据库任务 + ├─→ 查询所有 status = 'running' 的任务 + ├─→ 检查 Redis 启动标志 + └─→ 根据任务模式执行: + ├─→ realtime 模式:立即启动,持续运行 + └─→ batch 模式:根据 schedule 配置执行 + ↓ +定时刷新(每30秒) + ├─→ 检查新任务(status = 'running') + ├─→ 检查任务状态变更(启动/暂停/停止) + └─→ 更新运行中的任务列表 +``` + +### 8.2 分片策略 + +系统支持多种分片策略,实现多进程并行处理: + +#### 8.2.1 None(无分片) + +- 所有 Worker 都处理 +- 通过分布式锁保证只有一个执行 + +#### 8.2.2 By Database(按数据库分片) + +- 所有 Worker 都处理 +- 每个 Worker 处理不同的数据库 +- 在 Handler 中进行数据库分配 + +#### 8.2.3 其他分片策略 + +- 按 Worker ID 取模分配 +- 根据 `shard_count` 配置分片数量 + +### 8.3 分布式锁 + +**锁键**:`lock:data_collection:{taskId}` + +**配置**: +- TTL:300秒(默认) +- 重试次数:3次 +- 重试延迟:1000毫秒 + +**使用场景**: +- 防止同一任务被多个 Worker 重复执行 +- 保证任务执行的唯一性 + +--- + +## 九、字段映射和转换 + +### 9.1 字段映射配置 + +**单集合模式**: +```json +{ + "field_mappings": [ + { + "source_field": "源字段名", + "target_field": "目标字段名", + "transform": "转换函数名", + "value_mapping": [ + { + "source_value": "源值", + "target_value": "目标值" + } + ] + } + ] +} +``` + +**多集合模式**: +```json +{ + "collection_field_mappings": { + "集合1": [ + { + "source_field": "源字段名", + "target_field": "目标字段名" + } + ], + "集合2": [ + { + "source_field": "源字段名", + "target_field": "目标字段名" + } + ] + } +} +``` + +### 9.2 支持的转换函数 + +- `parse_phone` - 解析手机号(去除特殊字符) +- `parse_amount` - 解析金额(字符串转数字) +- `parse_datetime` - 解析时间(字符串转DateTime) +- `parse_int` - 解析整数 +- `parse_float` - 解析浮点数 +- `parse_bool` - 解析布尔值 + +### 9.3 值映射 + +支持将源字段的值映射为目标值: + +```json +{ + "value_mapping": [ + { + "source_value": "交易成功", + "target_value": "0" + }, + { + "source_value": "交易关闭", + "target_value": "1" + } + ] +} +``` + +--- + +## 十、连表查询(Lookup) + +### 10.1 Lookup 配置 + +**单集合模式**: +```json +{ + "lookups": [ + { + "from": "关联集合名", + "local_field": "本地字段", + "foreign_field": "关联字段", + "as": "结果字段名" + } + ] +} +``` + +**多集合模式**: +```json +{ + "collection_lookups": { + "集合1": [ + { + "from": "关联集合名", + "local_field": "本地字段", + "foreign_field": "关联字段", + "as": "结果字段名" + } + ] + } +} +``` + +### 10.2 Lookup 执行 + +系统使用 MongoDB 的 `$lookup` 聚合管道实现连表查询: + +```javascript +{ + $lookup: { + from: "关联集合名", + localField: "本地字段", + foreignField: "关联字段", + as: "结果字段名" + } +} +``` + +--- + +## 十一、过滤条件 + +### 11.1 过滤条件配置 + +```json +{ + "filter_conditions": [ + { + "field": "字段名", + "operator": "操作符", + "value": "值" + } + ] +} +``` + +### 11.2 支持的操作符 + +- `>` - 大于 +- `>=` - 大于等于 +- `<` - 小于 +- `<=` - 小于等于 +- `=` / `==` - 等于 +- `!=` - 不等于 +- `in` - 在列表中 +- `not_in` - 不在列表中 +- `like` - 模糊匹配(MongoDB 使用正则表达式) + +### 11.3 过滤条件应用 + +系统将过滤条件转换为 MongoDB 查询条件: + +```php +$filter = []; +foreach ($filterConditions as $condition) { + $field = $condition['field']; + $operator = $condition['operator']; + $value = $condition['value']; + + switch ($operator) { + case '>': + $filter[$field] = ['$gt' => $value]; + break; + case '>=': + $filter[$field] = ['$gte' => $value]; + break; + // ... 其他操作符 + } +} +``` + +--- + +## 十二、任务进度跟踪 + +### 12.1 进度更新 + +Handler 在处理数据时,定期更新任务进度: + +```php +$this->taskService->updateProgress($taskId, [ + 'status' => 'running', + 'processed_count' => $processedCount, + 'success_count' => $successCount, + 'error_count' => $errorCount, + 'total_count' => $totalCount, + 'percentage' => ($processedCount / $totalCount) * 100, + 'last_sync_time' => new \MongoDB\BSON\UTCDateTime(time() * 1000), +]); +``` + +### 12.2 进度查询 + +**API**:`GET /api/data-collection-tasks/{taskId}/progress` + +**返回格式**: +```json +{ + "status": "running", + "processed_count": 1000, + "success_count": 995, + "error_count": 5, + "total_count": 10000, + "percentage": 10.0, + "start_time": "2025-01-01T10:00:00.000Z", + "last_sync_time": "2025-01-01T10:05:00.000Z" +} +``` + +--- + +## 十三、错误处理和重试 + +### 13.1 错误处理策略 + +**单个记录错误**: +- 记录错误日志 +- 错误计数 +1 +- 继续处理下一条记录 + +**任务级错误**: +- 更新任务状态为 `error` +- 记录错误信息到 `progress.last_error` +- 记录错误日志 + +### 13.2 重试机制 + +**批量采集**: +- 支持断点续传(记录 `last_sync_time`) +- 下次执行时从上次位置继续 + +**实时监听**: +- 连接断开时自动重连 +- 记录同步位置,避免数据丢失 + +--- + +## 十四、数据流图 + +### 14.1 批量采集数据流 + +``` +数据源(MongoDB/MySQL) + ↓ +DataSyncScheduler(调度器) + ├─→ 创建数据源适配器 + └─→ 调用 Handler->collect() + ↓ + Handler 执行采集 + ├─→ 分页查询数据 + ├─→ 应用字段映射 + ├─→ 执行字段转换 + ├─→ 执行连表查询 + └─→ 写入目标数据库 + ├─→ 直接写入(同步) + └─→ 推送到队列(异步) + ↓ + DataSyncWorker 消费消息 + ↓ + 写入目标数据库 +``` + +### 14.2 实时监听数据流 + +``` +数据源(MongoDB) + ↓ +DataSyncScheduler(调度器) + ├─→ 创建数据源适配器 + └─→ 调用 Handler->collect() + ↓ + Handler 启动 Change Stream + ↓ + 持续监听变更事件 + ↓ + 处理变更事件 + ├─→ 解析变更文档 + ├─→ 应用字段映射 + └─→ 写入目标数据库 +``` + +### 14.3 消费记录采集数据流 + +``` +订单数据(KR_商城) + ↓ +ConsumptionCollectionHandler + ├─→ 提取手机号 + ├─→ 字段映射和转换 + └─→ 调用 ConsumptionService->createRecord() + ├─→ 身份解析(IdentifierService) + │ ├─→ 通过手机号解析 user_id + │ └─→ 如果不存在,创建临时人 + ├─→ 门店处理(StoreService) + │ └─→ 查找或创建门店,获取 store_id + ├─→ 写入 consumption_records(按时间分表) + ├─→ 更新 user_profile 统计信息 + └─→ 触发标签计算(推送到 RabbitMQ) + ↓ + TagCalculationWorker 消费消息 + ↓ + 计算用户标签 +``` + +--- + +## 十五、API 接口汇总 + +### 15.1 数据采集任务接口 + +- `GET /api/data-collection-tasks` - 获取任务列表 +- `POST /api/data-collection-tasks` - 创建任务 +- `GET /api/data-collection-tasks/{taskId}` - 获取任务详情 +- `PUT /api/data-collection-tasks/{taskId}` - 更新任务 +- `DELETE /api/data-collection-tasks/{taskId}` - 删除任务 +- `POST /api/data-collection-tasks/{taskId}/start` - 启动任务 +- `POST /api/data-collection-tasks/{taskId}/pause` - 暂停任务 +- `POST /api/data-collection-tasks/{taskId}/stop` - 停止任务 +- `GET /api/data-collection-tasks/{taskId}/progress` - 获取任务进度 + +### 15.2 数据源接口 + +- `GET /api/data-sources` - 获取数据源列表 +- `POST /api/data-sources` - 创建数据源 +- `GET /api/data-sources/{dataSourceId}` - 获取数据源详情 +- `PUT /api/data-sources/{dataSourceId}` - 更新数据源 +- `DELETE /api/data-sources/{dataSourceId}` - 删除数据源 +- `POST /api/data-sources/test-connection` - 测试数据源连接 + +### 15.3 辅助接口 + +- `GET /api/data-collection-tasks/data-sources` - 获取数据源列表(用于选择) +- `GET /api/data-collection-tasks/data-sources/{id}/databases` - 获取数据库列表 +- `GET /api/data-collection-tasks/data-sources/{id}/databases/{db}/collections` - 获取集合列表 +- `GET /api/data-collection-tasks/data-sources/{id}/databases/{db}/collections/{coll}/fields` - 获取字段列表 +- `GET /api/data-collection-tasks/handlers/{type}/target-fields` - 获取Handler目标字段列表 +- `POST /api/data-collection-tasks/preview-query` - 预览查询结果 + +--- + +## 十六、关键设计要点 + +### 16.1 配置化设计 + +- **任务配置**:支持配置文件和数据库两种方式 +- **字段映射**:通过配置实现灵活的字段映射 +- **数据源配置**:统一管理,支持动态加载 + +### 16.2 高可用性 + +- **分布式锁**:防止任务重复执行 +- **断点续传**:支持从上次位置继续 +- **错误隔离**:单个记录错误不影响整体任务 +- **自动重连**:实时监听模式支持自动重连 + +### 16.3 可扩展性 + +- **Handler 模式**:易于添加新的采集类型 +- **适配器模式**:易于支持新的数据源类型 +- **分片策略**:支持多进程并行处理 + +### 16.4 可观测性 + +- **进度跟踪**:实时跟踪任务进度 +- **日志记录**:完整的业务日志和错误日志 +- **统计信息**:记录任务执行统计 + +--- + +## 十七、使用示例 + +### 17.1 创建消费记录采集任务 + +**场景**:从 KR_商城.21年贝蒂喜订单整合 采集消费记录 + +**配置步骤**: + +1. **选择数据源**:选择 KR_商城 数据源 +2. **选择数据库和集合**:`KR_商城` / `21年贝蒂喜订单整合` +3. **选择Handler**:`消费记录处理(ConsumptionCollectionHandler)` +4. **配置字段映射**: + ```json + { + "phone_number": "联系手机", + "amount": "买家应付货款", + "actual_amount": "买家实际支付金额", + "consume_time": "订单付款时间", + "store_name": "店铺名称" + } + ``` +5. **配置过滤条件**(可选): + ```json + [ + { + "field": "买家实际支付金额", + "operator": "!=", + "value": "0" + } + ] + ``` +6. **配置调度计划**: + - 模式:`batch`(批量采集) + - 调度:启用定时任务,Cron 表达式 `0 2 * * *`(每天凌晨2点) +7. **保存并启动任务** + +### 17.2 创建通用数据采集任务 + +**场景**:从多个集合采集数据并写入目标数据库 + +**配置步骤**: + +1. **选择数据源**:选择源数据源 +2. **选择数据库和集合**:支持多集合模式 +3. **选择Handler**:`通用数据采集(GenericCollectionHandler)` +4. **配置目标数据源**:选择目标数据源、数据库、集合 +5. **配置字段映射**:为每个集合配置字段映射 +6. **配置连表查询**(可选):配置 lookup 查询 +7. **配置过滤条件**(可选) +8. **配置调度计划** +9. **保存并启动任务** + +--- + +## 十八、总结 + +数据采集系统提供了完整的数据采集、同步和管理功能,支持批量采集和实时监听两种模式,通过配置化的方式灵活管理采集任务。 + +### 18.1 核心特性 + +- ✅ **多数据源支持**:MongoDB、MySQL、PostgreSQL +- ✅ **多种采集模式**:批量采集、实时监听 +- ✅ **灵活的字段映射**:支持字段转换、值映射 +- ✅ **连表查询支持**:支持 MongoDB lookup 查询 +- ✅ **任务管理**:完整的任务创建、执行、监控功能 +- ✅ **进度跟踪**:实时跟踪任务进度和统计 +- ✅ **错误处理**:完善的错误处理和重试机制 + +### 18.2 使用场景 + +1. **历史数据迁移**:批量采集历史数据 +2. **实时数据同步**:实时监听数据变更 +3. **消费记录采集**:采集订单数据并触发标签计算 +4. **数据库同步**:数据库间的实时同步 + +--- + +**文档生成时间**:2025-01-XX +**项目版本**:基于当前代码库分析 + diff --git a/Moncter/提示词/当前架构设计/标签引擎相关功能流程逻辑.md b/Moncter/提示词/当前架构设计/标签引擎相关功能流程逻辑.md new file mode 100644 index 00000000..c24210d7 --- /dev/null +++ b/Moncter/提示词/当前架构设计/标签引擎相关功能流程逻辑.md @@ -0,0 +1,884 @@ +# 标签引擎相关功能流程逻辑 + +## 一、系统概述 + +标签引擎是系统的核心功能模块,负责根据用户数据自动计算和更新用户标签。系统支持实时计算、批量计算和定时计算三种模式,通过规则引擎实现灵活的标签计算逻辑。 + +### 1.1 核心组件 + +- **TagService** - 标签计算服务,核心业务逻辑 +- **TagTaskService** - 标签任务管理服务 +- **TagTaskExecutor** - 标签任务执行器 +- **SimpleRuleEngine** - 简单规则引擎 +- **TagCalculationWorker** - 标签计算Worker(异步处理) +- **TagDefinitionRepository** - 标签定义数据访问 +- **UserTagRepository** - 用户标签数据访问 +- **TagHistoryRepository** - 标签历史数据访问 + +### 1.2 数据存储 + +- **tag_definitions** - 标签定义集合(规则配置) +- **user_tags** - 用户标签集合(标签值) +- **tag_history** - 标签变更历史集合 +- **tag_tasks** - 标签任务集合 +- **tag_task_executions** - 标签任务执行记录集合 + +--- + +## 二、标签定义管理 + +### 2.1 标签定义结构 + +标签定义存储在 `tag_definitions` 集合中,包含以下关键字段: + +```javascript +{ + tag_id: String, // 标签ID(UUID) + tag_code: String, // 标签代码(唯一标识) + tag_name: String, // 标签名称 + category: String, // 标签分类 + rule_type: String, // 规则类型(simple/pipeline/custom) + rule_config: Object, // 规则配置(JSON) + update_frequency: String, // 更新频率(real_time/daily/weekly/monthly) + status: Number, // 状态(0:启用, 1:禁用) + priority: Number, // 优先级 + version: Number, // 版本号 + create_time: Date, + update_time: Date +} +``` + +### 2.2 规则配置格式 + +#### Simple 规则配置示例 + +```json +{ + "rule_type": "simple", + "conditions": [ + { + "field": "total_amount", + "operator": ">=", + "value": 1000 + }, + { + "field": "total_count", + "operator": ">=", + "value": 10 + } + ], + "tag_value": "VIP", + "confidence": 0.9 +} +``` + +#### 支持的运算符 + +- `>` - 大于 +- `>=` - 大于等于 +- `<` - 小于 +- `<=` - 小于等于 +- `=` / `==` - 等于 +- `!=` - 不等于 +- `in` - 在列表中 +- `not_in` - 不在列表中 + +### 2.3 标签定义管理流程 + +``` +创建/编辑标签定义 + ↓ +验证规则配置格式 + ↓ +保存到 tag_definitions 集合 + ↓ +如果状态为启用,立即生效 +``` + +--- + +## 三、标签计算流程 + +### 3.1 标签计算触发方式 + +系统支持三种标签计算触发方式: + +#### 3.1.1 实时计算(Real-time) + +**触发场景**: +- 消费记录写入时自动触发 +- 用户数据更新时触发 + +**流程**: +``` +消费记录写入 + ↓ +ConsumptionService->createRecord() + ├─→ 写入 consumption_records + ├─→ 更新 user_profile 统计信息 + └─→ 推送标签计算消息到 RabbitMQ + ↓ + TagCalculationWorker 消费消息 + ↓ + TagService->calculateTags() + ├─→ 获取用户数据 + ├─→ 获取所有 real_time 标签定义 + ├─→ 规则引擎计算标签值 + ├─→ 更新 user_tags + └─→ 记录 tag_history(如果值变化) +``` + +**消息格式**: +```json +{ + "user_id": "用户ID", + "tag_ids": null, // null 表示计算所有 real_time 标签 + "trigger_type": "consumption_record", + "record_id": "记录ID", + "timestamp": 1234567890 +} +``` + +#### 3.1.2 批量计算(Batch) + +**触发场景**: +- 通过标签任务手动触发 +- 定时任务触发(Cron) + +**流程**: +``` +创建标签任务 + ├─→ 任务类型:full(全量)/ incremental(增量)/ specified(指定) + ├─→ 目标标签:指定标签ID列表 + ├─→ 用户范围:all(全部)/ list(指定用户)/ filter(条件筛选) + └─→ 调度计划:Cron 表达式 + ↓ +用户点击"启动"按钮 + ↓ +TagTaskService->startTask() + ├─→ 更新任务状态为 running + └─→ 设置 Redis 标志:tag_task:{taskId}:start + ↓ +TagTaskExecutor->execute() + ├─→ 获取用户ID列表(根据 user_scope) + ├─→ 批量处理用户(批次大小可配置) + │ ├─→ 遍历每个用户 + │ ├─→ TagService->calculateTags(userId, targetTagIds) + │ └─→ 更新任务进度 + └─→ 记录执行结果 +``` + +#### 3.1.3 手动计算(Manual) + +**触发场景**: +- 通过 API 手动触发单个用户的标签计算 +- 用户标签查询页面点击"重新计算" + +**流程**: +``` +API: PUT /api/users/{user_id}/tags + ↓ +TagController->calculate() + ↓ +TagService->calculateTags(userId) + ├─→ 获取用户数据 + ├─→ 获取所有 real_time 标签定义 + ├─→ 规则引擎计算 + └─→ 更新标签 +``` + +### 3.2 标签计算核心流程 + +#### 3.2.1 TagService->calculateTags() 详细流程 + +```php +1. 获取用户数据 + - 从 user_profile 获取用户统计信息 + - 准备用户数据数组: + * total_amount: 总消费金额 + * total_count: 总消费次数 + * last_consume_time: 最后消费时间(时间戳) + +2. 获取标签定义列表 + - 如果指定 tagIds,只获取指定的标签定义 + - 如果 tagIds 为 null,获取所有启用且 update_frequency = 'real_time' 的标签 + - 只获取 status = 0(启用)的标签 + +3. 遍历每个标签定义 + For each tagDef: + a. 解析规则配置(rule_config) + b. 根据规则类型选择计算引擎 + - simple: 使用 SimpleRuleEngine + - pipeline: 暂不支持 + - custom: 暂不支持 + c. 规则引擎计算标签值 + - 评估所有条件(conditions) + - 如果所有条件满足,返回 tag_value 和 confidence + - 如果条件不满足,返回 false 和 confidence = 0.0 + d. 获取旧标签值(用于历史记录) + e. 更新或创建 user_tags 记录 + - 如果标签已存在,更新 tag_value、confidence、update_time + - 如果标签不存在,创建新记录 + f. 记录标签变更历史(仅当值发生变化时) + - 写入 tag_history 集合 + - 记录 old_value、new_value、change_reason、change_time + g. 记录计算日志 + +4. 更新用户的标签更新时间 + - user_profile.tags_update_time = now() + +5. 返回更新的标签列表 +``` + +#### 3.2.2 SimpleRuleEngine 计算逻辑 + +```php +1. 验证规则配置 + - rule_type 必须是 'simple' + - conditions 必须存在且为数组 + +2. 评估所有条件 + For each condition: + a. 从 userData 获取字段值 + b. 根据 operator 进行比较 + - >, >=, <, <=: 数值比较 + - =, !=: 相等比较 + - in, not_in: 数组包含判断 + c. 如果字段不存在,默认值为 0 + +3. 判断结果 + - 如果所有条件都满足(allMatch = true): + * value = ruleConfig['tag_value'] ?? true + * confidence = ruleConfig['confidence'] ?? 1.0 + - 如果任一条件不满足: + * value = false + * confidence = 0.0 + +4. 返回计算结果 + { + value: mixed, + confidence: float + } +``` + +### 3.3 标签值存储格式 + +标签值统一转换为字符串格式存储: + +- **布尔值**:`true` → `"true"`, `false` → `"false"` +- **数值**:直接转换为字符串 +- **数组/对象**:JSON 序列化 +- **字符串**:直接存储 + +标签值类型(tag_value_type): +- `boolean` - 布尔类型 +- `number` - 数值类型 +- `string` - 字符串类型 +- `json` - JSON 类型 + +--- + +## 四、标签任务管理 + +### 4.1 标签任务结构 + +```javascript +{ + task_id: String, // 任务ID(UUID) + name: String, // 任务名称 + description: String, // 任务描述 + task_type: String, // 任务类型(full/incremental/specified) + target_tag_ids: Array, // 目标标签ID列表 + user_scope: { // 用户范围 + type: String, // all/list/filter + user_ids: Array, // 指定用户列表(type=list时) + conditions: Array // 筛选条件(type=filter时) + }, + schedule: { // 调度计划 + enabled: Boolean, // 是否启用定时任务 + cron: String // Cron 表达式 + }, + config: { // 任务配置 + concurrency: Number, // 并发数 + batch_size: Number, // 批次大小 + error_handling: String // 错误处理策略(skip/stop) + }, + status: String, // 任务状态(pending/running/paused/stopped/error) + progress: { // 任务进度 + total_users: Number, // 总用户数 + processed_users: Number, // 已处理用户数 + success_count: Number, // 成功数量 + error_count: Number, // 错误数量 + percentage: Number // 完成百分比 + }, + statistics: { // 任务统计 + total_executions: Number, // 总执行次数 + success_executions: Number, // 成功执行次数 + failed_executions: Number, // 失败执行次数 + last_run_time: Date // 最后执行时间 + }, + created_by: String, + created_at: Date, + updated_at: Date +} +``` + +### 4.2 任务类型说明 + +#### 4.2.1 Full(全量计算) + +- 计算所有用户的所有指定标签 +- 适用于首次初始化或全量更新 + +#### 4.2.2 Incremental(增量计算) + +- 只计算有数据变更的用户 +- 适用于定期更新场景 + +#### 4.2.3 Specified(指定计算) + +- 只计算指定用户列表的标签 +- 适用于特定用户群体 + +### 4.3 用户范围配置 + +#### 4.3.1 All(全部用户) + +```json +{ + "type": "all" +} +``` + +获取所有 `status = 0` 的用户。 + +#### 4.3.2 List(指定用户列表) + +```json +{ + "type": "list", + "user_ids": ["user1", "user2", "user3"] +} +``` + +只计算指定用户ID列表的标签。 + +#### 4.3.3 Filter(条件筛选) + +```json +{ + "type": "filter", + "conditions": [ + { + "field": "total_amount", + "operator": ">=", + "value": 1000 + }, + { + "field": "total_count", + "operator": ">=", + "value": 10 + } + ] +} +``` + +根据条件筛选用户,支持多个条件(AND 逻辑)。 + +### 4.4 任务执行流程 + +``` +1. 创建执行记录 + - execution_id: UUID + - task_id: 任务ID + - started_at: 开始时间 + - status: running + +2. 获取用户ID列表 + - 根据 user_scope 配置获取用户列表 + - 计算总用户数 + +3. 更新任务进度 + - total_users: 总用户数 + - processed_users: 0 + - success_count: 0 + - error_count: 0 + - percentage: 0 + +4. 批量处理用户 + For each batch (batch_size = 100): + a. 检查任务状态(是否被暂停/停止) + b. 遍历批次中的每个用户 + - TagService->calculateTags(userId, targetTagIds) + - 成功:success_count++ + - 失败:error_count++ + - 根据 error_handling 策略决定是否继续 + c. 每处理 10 个用户更新一次进度 + - processed_users + - success_count + - error_count + - percentage = (processed_users / total_users) * 100 + +5. 更新最终进度 + - percentage = 100(或实际完成百分比) + +6. 更新执行记录 + - status: completed/failed + - finished_at: 结束时间 + - processed_users, success_count, error_count + +7. 更新任务统计 + - total_executions++ + - success_executions++ / failed_executions++ + - last_run_time = now() +``` + +### 4.5 任务状态管理 + +#### 4.5.1 启动任务 + +``` +用户点击"启动"按钮 + ↓ +API: POST /api/tag-tasks/{task_id}/start + ↓ +TagTaskService->startTask() + ├─→ 检查任务状态(不能是 running) + ├─→ 更新任务状态为 running + └─→ 设置 Redis 标志:tag_task:{taskId}:start + ↓ +TagTaskExecutor 检测到标志 + ↓ +执行任务(见 4.4 任务执行流程) +``` + +#### 4.5.2 暂停任务 + +``` +用户点击"暂停"按钮 + ↓ +API: POST /api/tag-tasks/{task_id}/pause + ↓ +TagTaskService->pauseTask() + ├─→ 检查任务状态(必须是 running) + ├─→ 更新任务状态为 paused + └─→ 设置 Redis 标志:tag_task:{taskId}:pause + ↓ +TagTaskExecutor 检测到标志 + ↓ +停止处理新批次,等待当前批次完成 +``` + +#### 4.5.3 停止任务 + +``` +用户点击"停止"按钮 + ↓ +API: POST /api/tag-tasks/{task_id}/stop + ↓ +TagTaskService->stopTask() + ├─→ 更新任务状态为 stopped + └─→ 设置 Redis 标志:tag_task:{taskId}:stop + ↓ +TagTaskExecutor 检测到标志 + ↓ +立即停止处理 +``` + +--- + +## 五、标签查询和筛选 + +### 5.1 用户标签查询 + +#### 5.1.1 查询单个用户的所有标签 + +``` +API: GET /api/users/{user_id}/tags + ↓ +TagController->getUserTags() + ↓ +TagService->getUserTags(userId) + ├─→ 从 user_tags 查询该用户的所有标签 + ├─→ 关联 tag_definitions 获取标签定义信息 + └─→ 返回标签列表(包含标签值、置信度、生效时间等) +``` + +**返回格式**: +```json +{ + "user_id": "用户ID", + "tags": [ + { + "tag_id": "标签ID", + "tag_code": "标签代码", + "tag_name": "标签名称", + "category": "标签分类", + "tag_value": "标签值", + "tag_value_type": "值类型", + "confidence": 0.9, + "effective_time": "生效时间", + "expire_time": "过期时间", + "update_time": "更新时间" + } + ], + "count": 10 +} +``` + +#### 5.1.2 重新计算用户标签 + +``` +API: PUT /api/users/{user_id}/tags + ↓ +TagController->calculate() + ↓ +TagService->calculateTags(userId) + └─→ 执行标签计算流程(见 3.2.1) +``` + +### 5.2 标签筛选用户 + +#### 5.2.1 根据标签条件筛选用户 + +``` +API: POST /api/tags/filter + ↓ +TagController->filterUsers() + ↓ +TagService->filterUsersByTags() + ├─→ 根据 tag_code 获取 tag_id 列表 + ├─→ 根据逻辑类型处理查询 + │ ├─→ AND 逻辑:分别查询每个条件,取交集 + │ └─→ OR 逻辑:使用 orWhere 查询 + ├─→ 如果标签未计算,基于规则从 user_profile 筛选 + ├─→ 分页处理 + └─→ 返回用户列表(可选包含用户信息) +``` + +**请求格式**: +```json +{ + "tag_conditions": [ + { + "tag_code": "VIP", + "operator": "=", + "value": "true" + }, + { + "tag_code": "消费金额等级", + "operator": ">=", + "value": "1000" + } + ], + "logic": "AND", + "page": 1, + "page_size": 20, + "include_user_info": true +} +``` + +**筛选逻辑**: + +1. **AND 逻辑**: + - 分别查询每个条件满足的用户ID + - 取所有条件的交集 + - 如果标签未计算,基于规则从 `user_profile` 筛选 + +2. **OR 逻辑**: + - 使用 `orWhere` 查询满足任一条件的用户 + - 去重后返回 + +3. **支持的操作符**: + - `=`, `!=` - 等于/不等于 + - `>`, `>=`, `<`, `<=` - 数值比较 + - `in`, `not_in` - 列表包含判断 + +### 5.3 标签统计 + +#### 5.3.1 获取标签统计信息 + +``` +API: GET /api/tags/statistics + ↓ +TagController->getStatistics() + ↓ +TagService->getTagStatistics() + ├─→ 标签覆盖度统计 + │ ├─→ 总用户数 + │ ├─→ 已打标签用户数 + │ └─→ 覆盖率 = (已打标签用户数 / 总用户数) * 100 + ├─→ 标签值分布 + │ └─→ 各标签值的出现次数 + └─→ 标签趋势数据 + └─→ 按日期统计标签变更次数 +``` + +### 5.4 标签历史查询 + +#### 5.4.1 获取标签变更历史 + +``` +API: GET /api/tags/history + ↓ +TagController->getHistory() + ↓ +TagHistoryRepository->query() + ├─→ 支持筛选条件: + │ ├─→ user_id: 按用户筛选 + │ ├─→ tag_id: 按标签筛选 + │ └─→ start_date, end_date: 按时间范围筛选 + ├─→ 分页查询 + └─→ 返回历史记录列表 +``` + +**历史记录结构**: +```javascript +{ + history_id: String, // 历史记录ID + user_id: String, // 用户ID + tag_id: String, // 标签ID + old_value: String, // 旧值 + new_value: String, // 新值 + change_reason: String, // 变更原因(auto_calculate/manual/tag_deleted) + change_time: Date, // 变更时间 + operator: String // 操作人(system/user_id) +} +``` + +--- + +## 六、异步处理机制 + +### 6.1 RabbitMQ 队列配置 + +#### 6.1.1 标签计算队列 + +- **队列名**:`tag_calculation` +- **交换机**:`tag_calculation_exchange` +- **路由键**:`tag.calculation` +- **持久化**:是 +- **消息格式**:JSON + +#### 6.1.2 消息推送 + +```php +QueueService::pushTagCalculation([ + 'user_id' => $userId, + 'tag_ids' => null, // null 表示计算所有 real_time 标签 + 'trigger_type' => 'consumption_record', + 'record_id' => $recordId, + 'timestamp' => time(), +]); +``` + +### 6.2 TagCalculationWorker 处理流程 + +``` +Worker 启动 + ↓ +初始化 RabbitMQ 连接 + ├─→ 建立连接 + ├─→ 声明队列 + ├─→ 设置 QoS(prefetch_count = 1) + └─→ 开始消费消息 + ↓ +监听消息(每 0.1 秒检查一次) + ↓ +收到消息 + ↓ +processMessage() + ├─→ 解析消息(JSON) + ├─→ 验证必要字段(user_id) + ├─→ 创建 TagService 实例 + ├─→ 执行标签计算 + │ └─→ TagService->calculateTags(userId, tagIds) + ├─→ 记录日志和性能指标 + └─→ 确认消息(ACK) + ├─→ 成功:message->ack() + └─→ 失败: + ├─→ 业务错误(InvalidArgumentException):ack(不重试) + └─→ 系统错误:nack(重新入队) +``` + +### 6.3 错误处理和重试 + +#### 6.3.1 业务错误 + +- **类型**:`InvalidArgumentException`(如用户不存在) +- **处理**:直接确认消息(ACK),不重试 +- **原因**:业务逻辑错误,重试不会改变结果 + +#### 6.3.2 系统错误 + +- **类型**:数据库连接失败、网络错误等 +- **处理**:拒绝消息并重新入队(NACK with requeue = true) +- **原因**:临时性错误,重试可能成功 + +### 6.4 降级策略 + +如果 RabbitMQ 不可用或推送失败: + +``` +推送消息到队列失败 + ↓ +记录错误日志 + ↓ +降级到同步调用 + ↓ +TagService->calculateTags()(同步执行) + ↓ +返回结果(包含标签信息) +``` + +--- + +## 七、数据流图 + +### 7.1 实时标签计算数据流 + +``` +数据采集任务 + ↓ +消费记录写入 + ↓ +ConsumptionService->createRecord() + ├─→ 写入 consumption_records + ├─→ 更新 user_profile(total_amount, total_count) + └─→ 推送消息到 RabbitMQ + ↓ + TagCalculationWorker(异步) + ↓ + TagService->calculateTags() + ├─→ 获取用户数据(user_profile) + ├─→ 获取标签定义(tag_definitions) + ├─→ 规则引擎计算(SimpleRuleEngine) + ├─→ 更新用户标签(user_tags) + └─→ 记录变更历史(tag_history) +``` + +### 7.2 批量标签计算数据流 + +``` +创建标签任务 + ↓ +用户启动任务 + ↓ +TagTaskService->startTask() + ├─→ 更新任务状态 + └─→ 设置 Redis 标志 + ↓ +TagTaskExecutor->execute() + ├─→ 获取用户列表(根据 user_scope) + ├─→ 批量处理用户 + │ └─→ TagService->calculateTags() + └─→ 更新任务进度和统计 +``` + +### 7.3 标签查询数据流 + +``` +API 请求 + ↓ +TagController + ↓ +TagService + ├─→ 查询 user_tags(用户标签) + ├─→ 关联 tag_definitions(标签定义) + ├─→ 筛选条件处理(AND/OR) + └─→ 返回结果 +``` + +--- + +## 八、关键设计要点 + +### 8.1 性能优化 + +1. **异步处理**:标签计算通过 RabbitMQ 异步处理,不阻塞主流程 +2. **批量处理**:标签任务支持批量处理,提高效率 +3. **增量更新**:只计算有数据变更的用户 +4. **缓存机制**:标签定义可以缓存,减少数据库查询 + +### 8.2 数据一致性 + +1. **事务处理**:标签更新和历史记录在同一事务中 +2. **幂等性**:标签计算支持重复执行,结果一致 +3. **错误隔离**:单个标签计算失败不影响其他标签 + +### 8.3 可扩展性 + +1. **规则引擎扩展**:支持添加新的规则类型(pipeline/custom) +2. **多数据源**:可以从多个数据源获取用户数据 +3. **自定义计算**:支持自定义计算逻辑 + +### 8.4 可观测性 + +1. **日志记录**:完整的业务日志和性能日志 +2. **进度跟踪**:实时跟踪任务进度 +3. **历史记录**:记录所有标签变更历史 +4. **统计信息**:提供标签统计和趋势分析 + +--- + +## 九、API 接口汇总 + +### 9.1 标签定义接口 + +- `GET /api/tag-definitions` - 获取标签定义列表 +- `POST /api/tag-definitions` - 创建标签定义 +- `GET /api/tag-definitions/{tag_id}` - 获取标签定义详情 +- `PUT /api/tag-definitions/{tag_id}` - 更新标签定义 +- `DELETE /api/tag-definitions/{tag_id}` - 删除标签定义 +- `POST /api/tag-definitions/batch` - 批量创建标签定义 + +### 9.2 标签任务接口 + +- `GET /api/tag-tasks` - 获取标签任务列表 +- `POST /api/tag-tasks` - 创建标签任务 +- `GET /api/tag-tasks/{task_id}` - 获取任务详情 +- `PUT /api/tag-tasks/{task_id}` - 更新任务 +- `DELETE /api/tag-tasks/{task_id}` - 删除任务 +- `POST /api/tag-tasks/{task_id}/start` - 启动任务 +- `POST /api/tag-tasks/{task_id}/pause` - 暂停任务 +- `POST /api/tag-tasks/{task_id}/stop` - 停止任务 +- `GET /api/tag-tasks/{task_id}/executions` - 获取执行记录 + +### 9.3 标签查询接口 + +- `GET /api/users/{user_id}/tags` - 获取用户标签 +- `PUT /api/users/{user_id}/tags` - 重新计算用户标签 +- `DELETE /api/users/{user_id}/tags/{tag_id}` - 删除用户标签 +- `POST /api/tags/filter` - 根据标签筛选用户 +- `GET /api/tags/statistics` - 获取标签统计信息 +- `GET /api/tags/history` - 获取标签历史记录 + +--- + +## 十、总结 + +标签引擎系统提供了完整的标签计算、管理和查询功能,支持实时计算、批量计算和定时计算三种模式。通过规则引擎实现灵活的标签计算逻辑,通过异步处理保证系统性能,通过历史记录提供完整的审计追踪。 + +### 10.1 核心特性 + +- ✅ **实时计算**:消费记录写入时自动触发标签计算 +- ✅ **批量计算**:支持全量、增量、指定用户的批量计算 +- ✅ **规则引擎**:支持简单规则,可扩展支持复杂规则 +- ✅ **异步处理**:通过 RabbitMQ 异步处理,不阻塞主流程 +- ✅ **任务管理**:完整的任务创建、执行、监控功能 +- ✅ **标签筛选**:支持多条件组合筛选用户 +- ✅ **历史追踪**:完整的标签变更历史记录 + +### 10.2 使用场景 + +1. **实时标签更新**:用户消费后自动更新标签 +2. **批量标签初始化**:首次上线时批量计算所有用户标签 +3. **定时标签更新**:按日/周/月定期更新标签 +4. **用户分群**:根据标签筛选特定用户群体 +5. **标签分析**:统计标签覆盖度、值分布、趋势数据 + +--- + +**文档生成时间**:2025-01-XX +**项目版本**:基于当前代码库分析 + diff --git a/Moncter/提示词/当前架构设计/采集进度100%停止机制分析报告.md b/Moncter/提示词/当前架构设计/采集进度100%停止机制分析报告.md new file mode 100644 index 00000000..288f7d28 --- /dev/null +++ b/Moncter/提示词/当前架构设计/采集进度100%停止机制分析报告.md @@ -0,0 +1,278 @@ +# 采集进度100%停止机制分析报告 + +## 分析目标 +检查当采集进度达到100%后,代码是否会正确停止采集。 + +## 代码流程分析 + +### 1. ConsumptionCollectionHandler::collectFromKrMall() 方法 + +#### 流程概览 +``` +初始化 → do-while循环 → 查询批次数据 → 处理批次 → 更新进度 → 检查退出条件 +``` + +#### 详细流程 + +**步骤1:初始化(第166-172行)** +```php +$offset = 0; +$processedCount = 0; +$successCount = 0; +$errorCount = 0; +$lastUpdateCount = 0; +$isCompleted = false; // 标记是否已完成 +``` + +**步骤2:主循环开始(第174行)** +```php +do { + // 查询批次数据 + // 处理批次 + // 更新进度 +} while (count($batch) === $batchSize && !$isCompleted); +``` +**退出条件**:当批次为空(`count($batch) < $batchSize`)**或** `$isCompleted = true` 时退出循环。 + +**步骤3:批次处理循环(第212-248行)** +```php +foreach ($batch as $index => $orderData) { + // 检查是否已达到总数(第222-225行) + if ($totalCount > 0 && $processedCount >= $totalCount) { + $isCompleted = true; + break; // 跳出当前批次处理循环 + } + + $processedCount++; // 第227行:递增处理计数 + + // 处理订单数据 + $this->processKrMallOrder($orderData, $taskConfig); + $successCount++; +} +``` + +**⚠️ 问题1:检查时机问题** +- 第222行检查 `processedCount >= totalCount` 时,`processedCount` 还没有递增 +- 第227行才会递增 `processedCount` +- **这意味着**:如果 `processedCount == totalCount - 1`,检查通过,然后递增后变成 `totalCount`,但此时已经处理了 `totalCount` 条数据 +- **实际上**:这个检查应该能正常工作,因为检查的是"是否已经达到或超过总数" + +**步骤4:批次处理完成后更新进度(第250-279行)** +```php +if (!empty($taskId) && $totalCount > 0) { + if (($processedCount - $lastUpdateCount) >= $updateInterval || $processedCount >= $totalCount) { + $percentage = round(($processedCount / $totalCount) * 100, 2); + + // 检查是否达到100%(第257-268行) + if ($processedCount >= $totalCount) { + // 进度达到100%,停止采集并更新状态为已完成 + $this->updateProgress($taskId, [ + 'status' => 'completed', + 'processed_count' => $processedCount, + 'success_count' => $successCount, + 'error_count' => $errorCount, + 'percentage' => 100, + 'end_time' => new \MongoDB\BSON\UTCDateTime(time() * 1000), + ]); + \Workerman\Worker::safeEcho("[ConsumptionCollectionHandler] ✅ 采集完成,进度已达到100%,已停止采集\n"); + $isCompleted = true; // 标记为已完成 + } + } +} +``` + +**步骤5:循环退出检查(第296行)** +```php +} while (count($batch) === $batchSize && !$isCompleted); +``` +- 如果 `$isCompleted = true`,循环会退出 +- 如果批次为空(`count($batch) < $batchSize`),循环也会退出 + +#### 停止机制分析 + +**✅ 停止机制1:在批次处理循环中检查(第222-225行)** +- **触发条件**:`processedCount >= totalCount` +- **动作**:设置 `$isCompleted = true`,`break` 跳出内层循环 +- **效果**:停止处理当前批次的剩余数据,但**不会立即退出主循环** + +**✅ 停止机制2:在批次处理完成后检查(第257-268行)** +- **触发条件**:`processedCount >= totalCount` +- **动作**:设置 `$isCompleted = true`,更新状态为 `completed` +- **效果**:标记任务完成,下次循环检查时会退出 + +**✅ 停止机制3:主循环退出条件(第296行)** +- **退出条件**:`!$isCompleted` 为 false(即 `$isCompleted = true`) +- **效果**:退出主循环,停止采集 + +#### 潜在问题 + +**问题1:第222行检查后,第227行仍会执行** +- 如果 `processedCount == totalCount - 1`,第222行检查通过,不会 break +- 第227行递增后,`processedCount` 变成 `totalCount` +- 然后处理数据,`processedCount` 实际上会超过 `totalCount` +- **影响**:可能会多处理一条数据 + +**问题2:第222行 break 后,第257行的检查不会执行** +- 如果第222行 break,会跳出内层循环 +- 第257行的检查不会执行(因为已经跳出循环) +- 但是 `$isCompleted` 已经设置为 `true`,主循环会在下次迭代时退出 +- **影响**:状态可能不会立即更新为 `completed`,但会在循环结束后更新(第298-316行) + +**问题3:循环退出后再次检查状态(第298-316行)** +- 循环退出后,会再次检查任务状态 +- 如果任务状态不是 `completed`、`paused`、`stopped`,会更新为 `completed` +- **这是好的**:确保状态最终被更新 + +### 2. ConsumptionCollectionHandler::collectFromKrFinance() 方法 + +#### 流程概览 +``` +初始化 → foreach循环遍历集合 → 查询数据 → 处理数据 → 更新进度 → 检查退出条件 +``` + +#### 详细流程 + +**步骤1:初始化(第570-590行)** +```php +$processedCount = 0; +$successCount = 0; +$errorCount = 0; +$lastUpdateCount = 0; +$isCompleted = false; +``` + +**步骤2:外层循环遍历集合(第592行)** +```php +foreach ($collections as $collectionName) { + if ($isCompleted) { + break; // 如果已完成,退出外层循环 + } + + // 查询和处理数据 +} +``` + +**步骤3:内层循环处理数据(第590-655行)** +```php +foreach ($cursor as $doc) { + // 检查任务状态(第608-612行) + if (!empty($taskId) && !$this->checkTaskStatus($taskId)) { + $isCompleted = true; + break 2; // 跳出两层循环 + } + + // 检查是否已达到总数(第615-618行) + if ($totalCount > 0 && $processedCount >= $totalCount) { + $isCompleted = true; + break 2; // 跳出两层循环 + } + + $processedCount++; + + // 处理数据 + // 更新进度(第626-659行) + if ($totalCount > 0 && $processedCount >= $totalCount) { + // 更新状态为 completed + $isCompleted = true; + break 2; // 跳出两层循环 + } +} +``` + +#### 停止机制分析 + +**✅ 停止机制1:在每条处理前检查(第615-618行)** +- **触发条件**:`processedCount >= totalCount` +- **动作**:设置 `$isCompleted = true`,`break 2` 跳出两层循环 +- **效果**:立即停止采集 + +**✅ 停止机制2:在进度更新时检查(第637-650行)** +- **触发条件**:`processedCount >= totalCount` +- **动作**:设置 `$isCompleted = true`,`break 2` 跳出两层循环,更新状态为 `completed` +- **效果**:立即停止采集并更新状态 + +**✅ 停止机制3:外层循环退出条件(第594-596行)** +- **退出条件**:`$isCompleted = true` +- **效果**:退出外层循环,停止采集 + +### 3. GenericCollectionHandler::collect() 方法 + +#### 流程概览 +``` +初始化 → do-while循环 → 查询批次数据 → 处理批次 → 更新进度 → 检查退出条件 +``` + +#### 详细流程 + +**步骤1:主循环(第274行)** +```php +do { + // 查询和处理数据 +} while (count($batch) === $batchSize && $processedCount < $totalCount); +``` +**退出条件**:当批次为空**或** `processedCount >= totalCount` 时退出循环。 + +**步骤2:进度更新检查(第247-259行)** +```php +if ($totalCount > 0 && $processedCount >= $totalCount) { + // 更新状态为 completed + break 2; // 跳出两层循环 +} +``` + +#### 停止机制分析 + +**✅ 停止机制1:循环退出条件(第274行)** +- **退出条件**:`$processedCount >= $totalCount` +- **效果**:退出主循环,停止采集 + +**✅ 停止机制2:进度更新时检查(第247-259行)** +- **触发条件**:`processedCount >= totalCount` +- **动作**:更新状态为 `completed`,`break 2` 跳出两层循环 +- **效果**:立即停止采集并更新状态 + +## 总结 + +### ✅ 停止机制正常工作的情况 + +1. **ConsumptionCollectionHandler::collectFromKrMall()** + - ✅ 在批次处理循环中检查 `processedCount >= totalCount`,设置 `$isCompleted = true` + - ✅ 在批次处理完成后检查,设置 `$isCompleted = true` 并更新状态 + - ✅ 主循环退出条件检查 `!$isCompleted`,当 `$isCompleted = true` 时退出 + - ✅ 循环退出后再次检查状态,确保更新为 `completed` + +2. **ConsumptionCollectionHandler::collectFromKrFinance()** + - ✅ 在每条处理前检查,`break 2` 跳出两层循环 + - ✅ 在进度更新时检查,`break 2` 跳出两层循环并更新状态 + - ✅ 外层循环检查 `$isCompleted`,当为 `true` 时退出 + +3. **GenericCollectionHandler::collect()** + - ✅ 循环退出条件直接检查 `$processedCount < $totalCount` + - ✅ 在进度更新时检查,`break 2` 跳出两层循环 + +### ⚠️ 潜在问题 + +1. **ConsumptionCollectionHandler::collectFromKrMall() 第222行检查时机** + - 检查在 `$processedCount++` 之前 + - 可能导致多处理一条数据(影响较小) + +2. **状态更新时机** + - 如果第222行 break,状态可能不会立即更新 + - 但会在循环结束后更新(第298-316行),所以最终状态是正确的 + +### 建议优化 + +1. **优化检查时机**:将第222行的检查移到 `$processedCount++` 之后 +2. **确保状态立即更新**:如果第222行 break,也应该立即更新状态 + +## 结论 + +**✅ 采集进度达到100%后,代码会停止采集** + +所有三个Handler都有多个停止机制,确保当 `processedCount >= totalCount` 时: +1. 设置完成标志 +2. 退出循环 +3. 更新状态为 `completed` + +虽然存在一些小的时机问题,但整体逻辑是正确的,能够确保采集在达到100%后停止。 + diff --git a/Moncter/提示词/数据列表动态打标签实现方案.md b/Moncter/提示词/数据列表动态打标签实现方案.md new file mode 100644 index 00000000..7b041b6d --- /dev/null +++ b/Moncter/提示词/数据列表动态打标签实现方案.md @@ -0,0 +1,682 @@ +# 数据列表动态打标签实现方案 + +## 一、核心思路 + +将SQL/MongoDB查询配置保存到数据表中,标签任务执行时从配置表读取查询配置,动态执行查询并打标签。 + +--- + +## 二、数据表设计 + +### 2.1 数据列表配置表(tag_data_lists) + +```javascript +{ + list_id: String, // 列表ID(UUID) + list_code: String, // 列表编码(唯一,如: consumption_records) + list_name: String, // 列表名称(如: 消费记录表) + data_source_id: String, // 数据源ID + database: String, // 数据库名 + collection: String, // 主集合名 + query_config: { // 查询配置 + filter: [ // 过滤条件(WHERE) + { + logic: 'and', // 逻辑关系(and/or) + field: String, // 字段名 + operator: String, // 运算符 + value: Any // 值 + } + ], + lookups: [ // 联表查询(JOIN) + { + from: String, // 关联集合 + local_field: String, // 主集合字段 + foreign_field: String, // 关联集合字段 + as: String, // 结果字段名 + unwrap: Boolean, // 是否解构 + preserve_null: Boolean // 是否保留空值 + } + ], + sort: { // 排序 + field_name: 1/-1 // 1=升序,-1=降序 + }, + limit: Number // 限制数量 + }, + description: String, // 描述 + status: Number, // 状态(0=禁用,1=启用) + create_time: Date, + update_time: Date +} +``` + +### 2.2 标签定义表(tag_definitions) + +```javascript +{ + tag_id: String, + tag_code: String, + tag_name: String, + category: String, + description: String, + rule_type: String, // 规则类型(simple/regex) + rule_config: { + rule_type: String, + data_list_id: String, // 关联的数据列表ID ⭐ + data_list_name: String, // 数据列表名称 + conditions: [ // 规则条件 + { + field: String, // 字段中文名 + field_name: String, // 字段英文名 + operator: String, // 运算符 + value: Any, // 值 + tag_value: String // 标签值 ⭐ + } + ] + }, + update_frequency: String, + status: Number, + create_time: Date, + update_time: Date +} +``` + +--- + +## 三、执行流程 + +### 3.1 标签任务启动流程 + +``` +1. 用户启动标签任务 + ↓ +2. TagTaskExecutor->execute() + ├─→ 获取目标标签ID列表(target_tag_ids) + ├─→ 遍历每个标签定义 + │ ↓ + 3. 读取标签定义 + ├─→ 从 tag_definitions 表读取 + ├─→ 获取 rule_config.data_list_id + │ ↓ + 4. 读取数据列表配置 + ├─→ 根据 data_list_id 从 tag_data_lists 表读取 + ├─→ 获取 query_config(查询配置) + │ ↓ + 5. 执行动态查询 + ├─→ 连接数据源 + ├─→ 根据 query_config 构建查询 + │ ├─→ 构建过滤条件(filter) + │ ├─→ 构建联表查询(lookups) + │ ├─→ 构建排序(sort) + │ └─→ 构建限制(limit) + ├─→ 执行查询,获取数据 + │ ↓ + 6. 遍历查询结果,动态打标签 + For each record in results: + ├─→ 提取 user_id(从记录中获取) + ├─→ 遍历 rule_config.conditions + │ ├─→ 根据 field_name 获取字段值 + │ ├─→ 根据 operator 进行比较 + │ │ ├─→ 运算规则:>, >=, <, <=, =, !=, in, not_in + │ │ └─→ 正则规则:正则表达式匹配 + │ └─→ 如果条件满足,使用该条件的 tag_value + ├─→ 更新或创建 user_tags 记录 + ├─→ 记录标签变更历史(tag_history) + └─→ 更新进度 +``` + +### 3.2 查询构建示例 + +**数据列表配置**: +```json +{ + "list_id": "list_001", + "list_name": "消费记录表", + "data_source_id": "source_001", + "database": "tag_engine", + "collection": "consumption_records", + "query_config": { + "filter": [ + { + "logic": "and", + "field": "status", + "operator": "eq", + "value": "success" + } + ], + "lookups": [ + { + "from": "user_profile", + "local_field": "user_id", + "foreign_field": "user_id", + "as": "user_info", + "unwrap": true, + "preserve_null": true + } + ], + "sort": { + "create_time": -1 + }, + "limit": 10000 + } +} +``` + +**执行时构建的MongoDB查询**: +```javascript +db.consumption_records.aggregate([ + { $match: { status: { $eq: "success" } } }, + { $lookup: { + from: "user_profile", + localField: "user_id", + foreignField: "user_id", + as: "user_info" + } }, + { $unwind: { + path: "$user_info", + preserveNullAndEmptyArrays: true + } }, + { $sort: { create_time: -1 } }, + { $limit: 10000 } +]) +``` + +### 3.3 标签计算示例 + +**标签定义**: +```json +{ + "tag_id": "tag_001", + "tag_code": "consumer_level", + "tag_name": "消费等级", + "rule_type": "simple", + "rule_config": { + "rule_type": "simple", + "data_list_id": "list_001", + "data_list_name": "消费记录表", + "conditions": [ + { + "field": "交易金额", + "field_name": "amount", + "operator": "<", + "value": 3000, + "tag_value": "低价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">=", + "value": 3000, + "tag_value": "中等价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">", + "value": 9000, + "tag_value": "高价值用户" + } + ] + } +} +``` + +**执行流程**: +```php +// 1. 读取数据列表配置 +$dataList = TagDataListRepository::find('list_001'); +$queryConfig = $dataList->query_config; + +// 2. 执行查询 +$results = $this->executeQuery($dataList->data_source_id, $dataList->database, $dataList->collection, $queryConfig); + +// 3. 遍历结果,打标签 +foreach ($results as $record) { + $userId = $record['user_id']; + $amount = $record['amount']; + + // 4. 根据规则条件匹配标签值 + $tagValue = null; + foreach ($tagDef->rule_config['conditions'] as $condition) { + $fieldValue = $record[$condition['field_name']]; // 获取字段值 + + // 5. 判断条件是否满足 + if ($this->evaluateCondition($fieldValue, $condition['operator'], $condition['value'])) { + $tagValue = $condition['tag_value']; + break; // 满足第一个条件即可 + } + } + + // 6. 保存标签 + if ($tagValue !== null) { + $this->saveUserTag($userId, $tagDef->tag_id, $tagValue); + } +} +``` + +--- + +## 四、后端实现要点 + +### 4.1 需要创建的文件 + +**控制器**: +- `app/controller/TagDataListController.php` - 数据列表管理控制器 + +**服务**: +- `app/service/TagDataListService.php` - 数据列表服务 + +**仓储**: +- `app/repository/TagDataListRepository.php` - 数据列表数据访问 + +**修改的文件**: +- `app/service/TagTaskExecutor.php` - 标签任务执行器(核心逻辑) +- `app/service/TagService.php` - 标签计算服务 + +### 4.2 TagDataListController 接口 + +```php +taskRepository->find($taskId); + $targetTagIds = $task->target_tag_ids; + + // 遍历每个标签定义 + foreach ($targetTagIds as $tagId) { + $tagDef = $this->tagDefinitionRepository->find($tagId); + $ruleConfig = $tagDef->rule_config; + + // ⭐ 获取数据列表配置 + $dataListId = $ruleConfig['data_list_id']; + $dataList = $this->tagDataListRepository->find($dataListId); + + if (!$dataList) { + // 记录错误并跳过 + continue; + } + + // ⭐ 执行动态查询 + $results = $this->executeDynamicQuery($dataList); + + // ⭐ 遍历查询结果,动态打标签 + foreach ($results as $record) { + $userId = $this->extractUserId($record); + + if (!$userId) { + continue; + } + + // 根据规则条件计算标签值 + $tagValue = $this->calculateTagValue($record, $ruleConfig); + + if ($tagValue !== null) { + // 保存标签 + $this->saveUserTag($userId, $tagId, $tagValue); + } + + // 更新进度 + $this->updateProgress($taskId); + } + } + } + + /** + * 执行动态查询 + */ + private function executeDynamicQuery(TagDataList $dataList): array + { + $queryConfig = $dataList->query_config; + + // 1. 连接数据源 + $adapter = $this->getDataSourceAdapter($dataList->data_source_id); + + // 2. 构建MongoDB聚合管道 + $pipeline = []; + + // 2.1 过滤条件($match) + if (!empty($queryConfig['filter'])) { + $filter = $this->buildFilter($queryConfig['filter']); + $pipeline[] = ['$match' => $filter]; + } + + // 2.2 联表查询($lookup) + if (!empty($queryConfig['lookups'])) { + foreach ($queryConfig['lookups'] as $lookup) { + $pipeline[] = [ + '$lookup' => [ + 'from' => $lookup['from'], + 'localField' => $lookup['local_field'], + 'foreignField' => $lookup['foreign_field'], + 'as' => $lookup['as'] + ] + ]; + + // 解构 + if ($lookup['unwrap'] ?? false) { + $pipeline[] = [ + '$unwind' => [ + 'path' => '$' . $lookup['as'], + 'preserveNullAndEmptyArrays' => $lookup['preserve_null'] ?? true + ] + ]; + } + } + } + + // 2.3 排序($sort) + if (!empty($queryConfig['sort'])) { + $pipeline[] = ['$sort' => $queryConfig['sort']]; + } + + // 2.4 限制($limit) + if (!empty($queryConfig['limit'])) { + $pipeline[] = ['$limit' => $queryConfig['limit']]; + } + + // 3. 执行查询 + $collection = $adapter->getCollection($dataList->database, $dataList->collection); + $cursor = $collection->aggregate($pipeline); + + return iterator_to_array($cursor); + } + + /** + * 构建过滤条件 + */ + private function buildFilter(array $filterConditions): array + { + $filter = []; + + foreach ($filterConditions as $condition) { + $field = $condition['field']; + $operator = $condition['operator']; + $value = $condition['value']; + + // 转换为MongoDB运算符 + $mongoFilter = match($operator) { + 'eq' => ['$eq' => $value], + 'ne' => ['$ne' => $value], + 'gt' => ['$gt' => $value], + 'gte' => ['$gte' => $value], + 'lt' => ['$lt' => $value], + 'lte' => ['$lte' => $value], + 'in' => ['$in' => (array)$value], + 'nin' => ['$nin' => (array)$value], + 'regex' => ['$regex' => $value, '$options' => 'i'], + 'exists' => ['$exists' => $value], + default => $value + }; + + $filter[$field] = $mongoFilter; + } + + return $filter; + } + + /** + * 计算标签值 + */ + private function calculateTagValue(array $record, array $ruleConfig): ?string + { + $conditions = $ruleConfig['conditions']; + + foreach ($conditions as $condition) { + $fieldName = $condition['field_name']; + $operator = $condition['operator']; + $expectedValue = $condition['value']; + $tagValue = $condition['tag_value']; + + // 获取字段值(支持嵌套字段,如:user_info.mobile) + $actualValue = $this->getFieldValue($record, $fieldName); + + // 判断条件是否满足 + $match = $this->evaluateCondition($actualValue, $operator, $expectedValue); + + // 满足第一个条件即返回 + if ($match) { + return $tagValue; + } + } + + // 所有条件都不满足 + return null; + } + + /** + * 评估条件 + */ + private function evaluateCondition($actualValue, string $operator, $expectedValue): bool + { + // 运算规则 + if (in_array($operator, ['>', '>=', '<', '<=', '=', '!=', 'in', 'not_in'])) { + return match($operator) { + '>' => $actualValue > $expectedValue, + '>=' => $actualValue >= $expectedValue, + '<' => $actualValue < $expectedValue, + '<=' => $actualValue <= $expectedValue, + '=' => $actualValue == $expectedValue, + '!=' => $actualValue != $expectedValue, + 'in' => in_array($actualValue, (array)$expectedValue), + 'not_in' => !in_array($actualValue, (array)$expectedValue), + default => false + }; + } + + // 正则规则(operator是正则表达式字符串) + if (str_starts_with($operator, '/')) { + $pattern = $operator; + return preg_match($pattern, (string)$actualValue) ? true : false; + } + + return false; + } + + /** + * 提取用户ID + */ + private function extractUserId(array $record): ?string + { + // 优先从record中获取user_id + if (isset($record['user_id'])) { + return (string)$record['user_id']; + } + + // 如果有联表的user_info,从user_info中获取 + if (isset($record['user_info']['user_id'])) { + return (string)$record['user_info']['user_id']; + } + + return null; + } + + /** + * 获取字段值(支持嵌套字段) + */ + private function getFieldValue(array $record, string $fieldName) + { + // 支持嵌套字段,如:user_info.mobile + if (str_contains($fieldName, '.')) { + $parts = explode('.', $fieldName); + $value = $record; + foreach ($parts as $part) { + if (!isset($value[$part])) { + return null; + } + $value = $value[$part]; + } + return $value; + } + + return $record[$fieldName] ?? null; + } +} +``` + +--- + +## 五、API接口实现 + +### 5.1 数据列表管理接口 + +``` +GET /api/tag-data-lists - 获取数据列表列表 +POST /api/tag-data-lists - 创建数据列表 +GET /api/tag-data-lists/{list_id} - 获取数据列表详情 +PUT /api/tag-data-lists/{list_id} - 更新数据列表 +DELETE /api/tag-data-lists/{list_id} - 删除数据列表 +GET /api/tag-data-lists/{list_id}/fields - 获取数据列表字段 +``` + +### 5.2 辅助接口 + +``` +GET /api/data-sources/{id}/databases - 获取数据库列表 +GET /api/data-sources/{id}/collections - 获取集合列表 +GET /api/data-sources/{id}/fields - 获取字段列表 +POST /api/data-sources/preview-query - 预览查询结果 +``` + +--- + +## 六、使用场景示例 + +### 场景1:根据消费金额分级 + +**步骤**: +1. 创建数据列表"消费记录表" + - 主集合:`consumption_records` + - 过滤:`status = success` + - 联表:关联 `user_profile` + +2. 创建标签定义"消费等级" + - 选择数据列表:消费记录表 + - 添加条件: + - `amount < 3000` → `"低价值用户"` + - `amount >= 3000` → `"中等价值用户"` + - `amount > 9000` → `"高价值用户"` + +3. 创建标签任务 + - 选择标签:消费等级 + - 启动任务 + +4. 任务执行 + - 查询消费记录(状态=成功,关联用户信息) + - 遍历记录,根据金额判断等级 + - 保存标签到 user_tags + +### 场景2:识别淘宝用户 + +**步骤**: +1. 创建数据列表"消费记录表" + - 主集合:`consumption_records` + - 过滤:无 + - 联表:无 + +2. 创建标签定义"平台识别" + - 选择数据列表:消费记录表 + - 规则类型:正则规则 + - 添加条件: + - 字段:`shop_name` + - 运算符:`/淘宝/` + - 值:`匹配` + - 标签值:`"淘宝平台"` + +3. 启动任务,自动识别淘宝用户 + +--- + +## 七、优势 + +1. **配置化**:SQL/查询配置保存在数据表,无需修改代码 +2. **可复用**:同一个数据列表可被多个标签定义使用 +3. **灵活性**:支持复杂查询,包括联表、过滤、排序 +4. **可视化**:通过UI界面配置,无需手写SQL +5. **动态执行**:任务执行时动态读取配置并执行 + +--- + +## 八、注意事项 + +1. **性能优化**: + - 设置合理的 limit 值 + - 建立合适的索引 + - 避免查询过多数据 + +2. **错误处理**: + - 数据列表配置不存在时的处理 + - 查询执行失败时的处理 + - 字段不存在时的默认值处理 + +3. **数据一致性**: + - user_id 必须存在 + - 字段名必须与实际字段匹配 + - 联表字段必须正确 + +--- + +**文档更新时间**:2025-01-XX +**实现方案**:基于数据列表动态打标签 diff --git a/Moncter/提示词/数据列表管理_真实API接入说明.md b/Moncter/提示词/数据列表管理_真实API接入说明.md new file mode 100644 index 00000000..5f52eb39 --- /dev/null +++ b/Moncter/提示词/数据列表管理_真实API接入说明.md @@ -0,0 +1,417 @@ +# 数据列表管理 - 真实API接入说明 + +## 修改概览 + +已将 `QueryBuilder` 组件中的基础配置部分从 Mock 数据切换到真实 API,复用了数据采集页面的 API。 + +## 修改的文件 + +### TaskShow/src/components/QueryBuilder/QueryBuilder.vue + +**主要修改**: +1. 导入数据采集API模块 +2. 替换所有基础配置相关的 Mock 数据为真实 API 调用 +3. 添加数据库和集合对象的缓存机制 + +**修改详情**: + +#### 1. 导入 API 模块 + +```typescript +import * as dataCollectionApi from '@/api/dataCollection' +``` + +#### 2. 添加对象缓存变量 + +```typescript +// 保存完整的对象用于API调用 +const databaseObjects = ref([]) +const collectionObjects = ref([]) +``` + +**用途**:因为 API 可能返回对象格式(如 `{ id, name }`),需要缓存这些对象用于后续 API 调用。 + +#### 3. 真实 API 调用 + +##### 加载数据源 + +**API路径**:`GET /data-collection-tasks/data-sources` + +```typescript +const loadDataSources = async () => { + try { + dataSourceLoading.value = true + const response = await dataCollectionApi.getDataSources() + + // 转换数据格式,兼容旧的data_source_id字段 + dataSources.value = (response.data || []).map((ds: any) => ({ + data_source_id: ds.id || ds.data_source_id, + name: ds.name || ds.id, + type: ds.type, + status: 1 + })) + } catch (error: any) { + ElMessage.error(error.message || '加载数据源失败') + } finally { + dataSourceLoading.value = false + } +} +``` + +##### 加载数据库列表 + +**API路径**:`GET /data-collection-tasks/data-sources/{dataSourceId}/databases` + +```typescript +const loadDatabases = async (dataSourceId: string) => { + try { + databaseLoading.value = true + const response = await dataCollectionApi.getDatabases(dataSourceId) + + // 转换为字符串数组(只返回数据库名称) + databases.value = (response.data || []).map((db: any) => + typeof db === 'string' ? db : db.name + ) + + // 保存完整的数据库对象供后续使用 + databaseObjects.value = response.data || [] + } catch (error: any) { + ElMessage.error(error.message || '加载数据库列表失败') + } finally { + databaseLoading.value = false + } +} +``` + +##### 加载集合列表 + +**API路径**:`GET /data-collection-tasks/data-sources/{dataSourceId}/databases/{databaseId}/collections` + +```typescript +const loadCollections = async (dataSourceId: string, database: string) => { + try { + collectionLoading.value = true + + // 查找数据库对象 + const dbObj = databaseObjects.value.find((db: any) => + (typeof db === 'object' && db.name === database) || db === database + ) + + const response = await dataCollectionApi.getCollections( + dataSourceId, + dbObj || database + ) + + // 转换为字符串数组(只返回集合名称) + collections.value = (response.data || []).map((coll: any) => + typeof coll === 'string' ? coll : coll.name + ) + + // 保存完整的集合对象供后续使用 + collectionObjects.value = response.data || [] + } catch (error: any) { + ElMessage.error(error.message || '加载集合列表失败') + } finally { + collectionLoading.value = false + } +} +``` + +##### 加载字段列表 + +**API路径**:`GET /data-collection-tasks/data-sources/{dataSourceId}/databases/{databaseId}/collections/{collectionId}/fields` + +```typescript +const loadFields = async (dataSourceId: string, database: string, collection: string) => { + try { + // 查找数据库和集合对象 + const dbObj = databaseObjects.value.find((db: any) => + (typeof db === 'object' && db.name === database) || db === database + ) + const collObj = collectionObjects.value.find((coll: any) => + (typeof coll === 'object' && coll.name === collection) || coll === collection + ) + + const response = await dataCollectionApi.getFields( + dataSourceId, + dbObj || database, + collObj || collection + ) + + // 转换字段格式:API返回的是 { name, type },需要转换为 { field, field_name, type } + availableFields.value = (response.data || []).map((field: any) => ({ + field: field.name, // 显示名称使用字段名 + field_name: field.name, // 实际字段名 + type: field.type || 'string' + })) + } catch (error: any) { + ElMessage.error(error.message || '加载字段列表失败') + availableFields.value = [] + } +} +``` + +##### 预览查询数据 + +**API路径**:`POST /data-collection-tasks/preview-query` + +```typescript +const handlePreview = async () => { + if (!canPreview.value) { + ElMessage.warning('请先完成基础配置') + return + } + + try { + // 构建查询预览请求 + const lookups = queryConfig.lookups.map((lookup: any) => ({ + from: lookup.foreign_collection, + localField: lookup.local_field, + foreignField: lookup.foreign_field, + as: lookup.as, + unwind: lookup.unwind, + preserveNullAndEmptyArrays: lookup.preserve_null + })) + + const filterConditions = queryConfig.filter.map((filter: any) => ({ + field: filter.field_name, + operator: filter.operator, + value: filter.value, + logic: filter.logic || 'and' + })) + + const response = await dataCollectionApi.previewQuery({ + data_source_id: queryConfig.data_source_id, + database: queryConfig.database, + collection: queryConfig.collection, + lookups: lookups.length > 0 ? lookups : undefined, + filter_conditions: filterConditions.length > 0 ? filterConditions : undefined, + limit: queryConfig.limit || 10 + }) + + previewData.value = response.data?.data || [] + ElMessage.success(`预览成功,共 ${previewData.value.length} 条数据`) + } catch (error: any) { + ElMessage.error(error.message || '预览失败') + } +} +``` + +#### 4. 变化处理函数优化 + +添加了对缓存对象的清理: + +```typescript +const handleDataSourceChange = async (dataSourceId: string) => { + if (!dataSourceId) { + databases.value = [] + collections.value = [] + availableFields.value = [] + databaseObjects.value = [] // 新增 + collectionObjects.value = [] // 新增 + queryConfig.database = '' + queryConfig.collection = '' + return + } + await loadDatabases(dataSourceId) +} + +const handleDatabaseChange = async (database: string) => { + if (!database || !queryConfig.data_source_id) { + collections.value = [] + availableFields.value = [] + collectionObjects.value = [] // 新增 + queryConfig.collection = '' + return + } + await loadCollections(queryConfig.data_source_id, database) +} +``` + +## 复用的 API 模块 + +### 文件位置 +`TaskShow/src/api/dataCollection.ts` + +### API 列表 + +| API 函数 | HTTP 方法 | 路径 | 用途 | +|---------|----------|------|------| +| `getDataSources()` | GET | `/data-collection-tasks/data-sources` | 获取数据源列表 | +| `getDatabases(dataSourceId)` | GET | `/data-collection-tasks/data-sources/{id}/databases` | 获取数据库列表 | +| `getCollections(dataSourceId, database)` | GET | `/data-collection-tasks/data-sources/{id}/databases/{dbId}/collections` | 获取集合列表 | +| `getFields(dataSourceId, database, collection)` | GET | `/data-collection-tasks/data-sources/{id}/databases/{dbId}/collections/{collId}/fields` | 获取字段列表 | +| `previewQuery(data)` | POST | `/data-collection-tasks/preview-query` | 预览查询结果 | + +## 数据格式说明 + +### 数据源(Data Source) +```typescript +{ + id: string + name: string + type: 'mongodb' | 'mysql' | ... +} +``` + +### 数据库(Database) +```typescript +{ + id: string + name: string +} +// 或简单的字符串数组 +string[] +``` + +### 集合(Collection) +```typescript +{ + id: string + name: string +} +// 或简单的字符串数组 +string[] +``` + +### 字段(Field) +```typescript +{ + name: string + type: 'string' | 'number' | 'datetime' | ... +} +``` + +### 预览查询请求(Preview Query Request) +```typescript +{ + data_source_id: string + database: string + collection: string + lookups?: Array<{ + from: string + localField: string + foreignField: string + as: string + unwind?: boolean + preserveNullAndEmptyArrays?: boolean + }> + filter_conditions?: Array<{ + field: string + operator: string + value: any + logic: 'and' | 'or' + }> + limit?: number +} +``` + +### 预览查询响应(Preview Query Response) +```typescript +{ + fields: Array<{ name: string; type: string }> + data: Array + count: number +} +``` + +## 兼容性处理 + +### 1. 数据库/集合对象 vs 字符串 +API 可能返回对象(`{ id, name }`)或字符串数组,代码中做了兼容处理: + +```typescript +// 显示用字符串数组 +databases.value = (response.data || []).map((db: any) => + typeof db === 'string' ? db : db.name +) + +// 缓存完整对象 +databaseObjects.value = response.data || [] + +// 查找时兼容两种格式 +const dbObj = databaseObjects.value.find((db: any) => + (typeof db === 'object' && db.name === database) || db === database +) +``` + +### 2. 字段名转换 +API 返回的字段格式与 QueryBuilder 使用的格式不同: + +```typescript +// API 返回: { name, type } +// QueryBuilder 需要: { field, field_name, type } + +availableFields.value = (response.data || []).map((field: any) => ({ + field: field.name, // 显示名称 + field_name: field.name, // 实际字段名 + type: field.type || 'string' +})) +``` + +## 测试建议 + +1. **数据源加载测试** + - 打开数据列表配置页面 + - 检查数据源下拉框是否正确加载 + +2. **级联加载测试** + - 选择数据源 → 检查数据库列表 + - 选择数据库 → 检查集合列表 + - 选择集合 → 检查字段列表 + +3. **预览功能测试** + - 配置完整查询(包含过滤、联表) + - 点击"预览数据" + - 检查返回结果是否正确 + +4. **错误处理测试** + - 模拟网络错误 + - 检查错误提示是否友好 + +## 注意事项 + +1. **后端 API 必须已实现** + - 所有使用的 API 端点都必须在后端正确实现 + - 数据格式必须与前端期望一致 + +2. **性能优化** + - 字段列表加载可能较慢(特别是大集合) + - 建议后端添加缓存机制 + +3. **错误处理** + - 所有 API 调用都有 try-catch 包裹 + - 错误信息会通过 ElMessage 显示给用户 + +4. **数据转换** + - 注意 API 返回的数据格式 + - 确保前端正确转换为组件所需格式 + +## 剩余 Mock 数据 + +以下部分仍使用 Mock 数据(可后续接入真实 API): + +1. **TagDataList/List.vue** + - 数据列表的 CRUD 操作 + - API 端点:`/api/tag-data-lists` + +2. **TagDataList/Form.vue** + - 数据列表配置的保存 + - API 端点:`/api/tag-data-lists` + +3. **TagDefinition/Form.vue** + - 数据列表下拉选择 + - 字段列表加载 + - API 端点:`/api/tag-data-lists` 和 `/api/tag-data-lists/{id}/fields` + +## 下一步工作 + +1. 开发数据列表管理的后端 API +2. 将 TagDataList 的 CRUD 操作接入真实 API +3. 将 TagDefinition 中的数据列表选择接入真实 API +4. 完整的集成测试 + +--- + +**更新时间**:2025-01-XX +**状态**:QueryBuilder 基础配置已接入真实 API diff --git a/Moncter/提示词/数据列表管理界面使用说明.md b/Moncter/提示词/数据列表管理界面使用说明.md new file mode 100644 index 00000000..45c8e067 --- /dev/null +++ b/Moncter/提示词/数据列表管理界面使用说明.md @@ -0,0 +1,327 @@ +# 数据列表管理界面使用说明 + +## 一、界面概览 + +数据列表管理界面用于可视化配置MongoDB查询,支持过滤条件、联表查询、排序等功能。配置保存后,可在标签定义中引用。 + +### 访问路径 +- 列表页面:http://localhost:5173/tag-data-lists +- 创建页面:http://localhost:5173/tag-data-lists/create +- 编辑页面:http://localhost:5173/tag-data-lists/:id/edit + +### 菜单位置 +左侧菜单 → 标签任务 → 数据列表管理 + +--- + +## 二、界面功能 + +### 2.1 数据列表管理(List.vue) + +**功能列表**: +- ✅ 展示所有数据列表配置 +- ✅ 按名称搜索 +- ✅ 按状态筛选 +- ✅ 创建新数据列表 +- ✅ 编辑数据列表 +- ✅ 删除数据列表 +- ✅ 分页展示 + +**表格列**: +- 列表名称 +- 列表编码 +- 数据源ID +- 数据库 +- 主集合 +- 状态(启用/禁用) +- 描述 +- 创建时间 +- 操作(编辑、删除) + +### 2.2 数据列表配置(Form.vue) + +**基本信息配置**: +- 列表名称(必填)- 如:"消费记录表" +- 列表编码(必填)- 如:"consumption_records" +- 描述(可选) +- 状态(启用/禁用) + +**查询配置(QueryBuilder组件)**: + +#### 1. 基础配置 +- 数据源选择 +- 数据库选择 +- 主集合选择 + +#### 2. 过滤条件(WHERE) +- 支持多个条件 +- 逻辑关系:AND/OR +- 字段选择(自动加载) +- 运算符选择: + - 等于、不等于 + - 大于、大于等于、小于、小于等于 + - 包含、不包含 + - 模糊匹配、存在 +- 值输入(根据字段类型自动调整) + +#### 3. 联表查询(JOIN/LOOKUP) +- 支持多个联表 +- 关联集合选择 +- 主集合字段选择 +- 关联集合字段输入 +- 结果字段名配置 +- 解构开关(是否展开数组) +- 保留空值开关(LEFT JOIN效果) + +#### 4. 排序和限制 +- 排序字段选择 +- 排序方式(升序/降序) +- 限制数量(默认1000) + +#### 5. 查询预览 +- 实时显示生成的MongoDB聚合管道代码 +- 预览查询结果数据(最多显示配置的limit条) + +--- + +## 三、使用示例 + +### 示例1:创建简单的消费记录查询 + +**步骤**: +1. 访问 `/tag-data-lists`,点击"创建数据列表" +2. 填写基本信息: + - 列表名称:`消费记录表` + - 列表编码:`consumption_records` + - 描述:`用于标签定义的消费记录数据` + - 状态:`启用` +3. 配置查询: + - 数据源:选择"MongoDB标签引擎数据源" + - 数据库:选择"tag_engine" + - 主集合:选择"consumption_records" +4. 添加过滤条件: + - 字段:`交易状态` + - 运算符:`等于` + - 值:`success` +5. 配置排序: + - 排序字段:`创建时间` + - 排序方式:`降序` + - 限制数量:`1000` +6. 点击"预览数据"查看效果 +7. 点击"保存" + +**生成的查询**: +```javascript +db.consumption_records.aggregate([ + { $match: { status: { $eq: "success" } } }, + { $sort: { create_time: -1 } }, + { $limit: 1000 } +]) +``` + +### 示例2:创建带联表的查询 + +**步骤**: +1. 基本配置同上 +2. 添加过滤条件: + - 字段:`交易金额` + - 运算符:`大于` + - 值:`1000` +3. 添加联表查询: + - 关联集合:`user_profile` + - 主集合字段:`user_id` + - 关联集合字段:`user_id` + - 结果字段名:`user_info` + - 解构:`是` + - 保留空值:`是` +4. 保存 + +**生成的查询**: +```javascript +db.consumption_records.aggregate([ + { $match: { amount: { $gt: 1000 } } }, + { $lookup: { + from: "user_profile", + localField: "user_id", + foreignField: "user_id", + as: "user_info" + } }, + { $unwind: { + path: "$user_info", + preserveNullAndEmptyArrays: true + } }, + { $limit: 1000 } +]) +``` + +### 示例3:在标签定义中使用 + +**步骤**: +1. 访问 `/tag-definitions/create` +2. 填写标签编码和名称 +3. 选择数据列表:`消费记录表` +4. 系统自动加载字段:`交易金额`、`店铺名称`、`交易状态`等 +5. 添加规则条件: + - 字段:`交易金额` + - 运算符:`<` + - 值:`3000` + - 标签值:`低价值用户` +6. 保存 + +--- + +## 四、Mock数据位置 + +所有Mock数据都标记为 `TODO: 替换为真实API`,方便后续替换。 + +### 4.1 List.vue + +**位置**:`loadData()` 函数 + +```typescript +// 第106-142行 +// Mock数据 +const mockData = [ + { + list_id: 'list_001', + list_code: 'consumption_records', + list_name: '消费记录表', + // ... + }, + // ... +] +``` + +### 4.2 QueryBuilder.vue + +**位置1**:`loadDataSources()` - 第368-383行 +```typescript +dataSources.value = [ + { data_source_id: 'source_001', name: 'MongoDB标签引擎数据源' } +] +``` + +**位置2**:`loadDatabases()` - 第398-410行 +```typescript +databases.value = ['tag_engine', 'business_db', 'analytics_db'] +``` + +**位置3**:`loadCollections()` - 第425-443行 +```typescript +if (database === 'tag_engine') { + collections.value = ['consumption_records', 'user_profile', ...] +} +``` + +**位置4**:`loadFields()` - 第458-492行 +```typescript +if (collection === 'consumption_records') { + availableFields.value = [ + { field: '交易金额', field_name: 'amount', type: 'number' }, + // ... + ] +} +``` + +**位置5**:`handlePreview()` - 第530-569行 +```typescript +previewData.value = [ + { user_id: 'user_001', amount: 5000, ... }, + // ... +] +``` + +### 4.3 TagDefinition/Form.vue + +**位置1**:`loadDataLists()` - 第285-303行 +```typescript +dataLists.value = [ + { list_id: 'list_001', list_name: '消费记录表' }, + { list_id: 'list_002', list_name: '用户档案表' } +] +``` + +**位置2**:`loadFields()` - 第318-347行 +```typescript +if (listId === 'list_001') { + fields.value = [ + { field: '交易金额', field_name: 'amount', ... }, + // ... + ] +} +``` + +--- + +## 五、后续开发计划 + +### 阶段1:完善界面(✅ 已完成) +- ✅ QueryBuilder可视化查询构建器 +- ✅ 数据列表管理(列表、创建、编辑) +- ✅ 标签定义表单(集成数据列表选择) +- ✅ 所有Mock数据,界面可独立运行 + +### 阶段2:后端API开发(待开发) +- ⏳ TagDataListController - 数据列表管理API +- ⏳ TagDataListRepository - 数据访问层 +- ⏳ TagDataListService - 业务逻辑层 +- ⏳ 数据源相关API(databases、collections、fields) +- ⏳ 查询预览API + +### 阶段3:集成联调(待开发) +- ⏳ 删除Mock代码 +- ⏳ 集成真实API +- ⏳ 测试完整流程 +- ⏳ 错误处理优化 + +### 阶段4:标签任务执行(待开发) +- ⏳ 修改TagTaskExecutor +- ⏳ 从tag_data_lists读取配置 +- ⏳ 执行动态查询 +- ⏳ 遍历结果打标签 + +--- + +## 六、界面预览 + +### 数据列表管理列表 +![列表页面](略) +- 显示所有配置的数据列表 +- 支持搜索和筛选 +- 操作按钮:编辑、删除 + +### 数据列表配置表单 +![配置表单](略) +- 基本信息区域 +- 可视化查询构建器 +- 实时查询预览 +- 数据预览 + +### 标签定义表单 +![标签定义](略) +- 选择数据列表 +- 自动加载字段 +- 配置规则条件 + +--- + +## 七、技术要点 + +### 7.1 组件通信 +- QueryBuilder使用 `v-model` 双向绑定 +- 父组件监听配置变化 + +### 7.2 字段映射 +- 前端显示:中文字段名(field) +- 后端存储:英文字段名(field_name) +- 保存时同时存储两者 + +### 7.3 查询构建 +- 实时生成MongoDB聚合管道 +- 支持复杂的嵌套查询 +- 可视化预览查询结果 + +--- + +**文档更新时间**:2025-01-XX +**状态**:界面已完成,使用Mock数据 diff --git a/Moncter/提示词/最新架构逻辑.md b/Moncter/提示词/最新架构逻辑.md new file mode 100644 index 00000000..51ac630a --- /dev/null +++ b/Moncter/提示词/最新架构逻辑.md @@ -0,0 +1,454 @@ +# Moncter 系统最新架构逻辑提示词 + +> **用途说明**:本文档作为系统架构的核心记忆点,用于快速理解和开发维护 Moncter 系统。 + +--- + +## 一、系统定位 + +**Moncter** 是一个基于 **Webman (Workerman)** 框架的**用户标签引擎和数据采集中心**,核心功能包括: + +1. **多数据源数据采集**:支持 MongoDB、MySQL 等多种数据源,支持批量采集和实时监听两种模式 +2. **用户标签计算引擎**:基于用户消费数据实时计算和更新标签,支持规则引擎配置 +3. **用户身份管理**:支持身份证、手机号等标识的统一管理,处理临时用户、正式用户转换和身份合并 +4. **数据库实时同步**:使用 MongoDB Change Streams 实现数据库间实时同步 + +--- + +## 二、技术栈 + +### 后端 +- **框架**:Webman (Workerman) - 高性能 PHP 框架,多进程架构 +- **PHP版本**:>= 8.1 +- **数据库**:MongoDB (主数据库) +- **消息队列**:RabbitMQ - 异步任务处理 +- **缓存/锁**:Redis - 分布式锁、任务状态存储 + +### 前端 +- **框架**:Vue 3 + TypeScript +- **UI组件**:Element Plus +- **状态管理**:Pinia +- **构建工具**:Vite + +--- + +## 三、系统架构 + +### 3.1 分层架构 + +``` +┌─────────────────────────────────────────┐ +│ 应用层 (HTTP API) │ +│ Controller 层:处理HTTP请求 │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 业务服务层 (Service) │ +│ - ConsumptionService: 消费记录处理 │ +│ - IdentifierService: 身份解析 │ +│ - TagService: 标签计算 │ +│ - DataCollectionTaskService: 任务管理 │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 数据访问层 (Repository) │ +│ - UserProfileRepository │ +│ - UserPhoneRelationRepository │ +│ - ConsumptionRecordRepository │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 数据存储层 │ +│ MongoDB / Redis / RabbitMQ │ +└─────────────────────────────────────────┘ +``` + +### 3.2 进程架构(Workerman) + +系统包含以下进程(配置在 `config/process.php`): + +1. **webman (HTTP Server)** + - 处理 HTTP API 请求 + - 进程数:`CPU核心数 × 4` + - 监听端口:`8787` + +2. **monitor (文件监控)** + - 监控文件变化,自动重载 + - 单进程 + +3. **data_sync_scheduler (数据采集任务调度器)** + - 读取任务配置(配置文件 + 数据库) + - 启动和管理所有数据采集任务 + - 进程数:`10` + +4. **data_sync_worker (数据同步Worker)** + - 消费 RabbitMQ `data_sync` 队列 + - 写入目标数据库,更新用户统计 + - 进程数:`20` + +5. **tag_calculation_worker (标签计算Worker)** + - 消费 RabbitMQ `tag_calculation` 队列 + - 根据用户数据计算标签值 + - 进程数:`2` + +--- + +## 四、核心业务逻辑 + +### 4.1 消费记录到用户创建流程 + +**核心流程:消费记录 → 身份解析 → 用户创建/关联 → 手机关联建立 → 写入记录** + +#### 关键步骤 + +1. **身份解析** (`IdentifierService::resolvePersonId`) + - 优先级:身份证 > 手机号 + - 如果只有手机号,通过 `UserPhoneService::findUserByPhone` 查询 + - **关键**:使用 `consume_time` 作为查询时间点(不是当前时间) + +2. **临时用户创建** (`IdentifierService::createTemporaryPerson`) + - 生成 UUID 作为 `user_id` + - 设置 `is_temporary = true` + - **必须**建立手机关联(使用消费时间作为 `effective_time`) + +3. **手机关联建立** (`UserPhoneService::addPhoneToUser`) + - 冲突检测:检查手机号在 `effective_time` 是否已有有效关联 + - 自动过期旧关联:如果冲突,将旧关联的 `expire_time` 设置为新关联的 `effective_time` + - 创建新关联:`effective_time = consume_time`,`expire_time = null` + +4. **用户合并** (`ConsumptionService::handleMergeIfNeeded`) + - 当手机号和身份证同时出现,且关联到不同用户时触发 + - 临时用户 → 自动合并到正式用户 + - 正式用户冲突 → 以身份证为准(代订场景),记录日志 + +5. **写入消费记录** (`ConsumptionService::createRecord`) + - 写入 `consumption_records` 表(按时间分表:`consumption_records_YYYYMM`) + - 更新 `user_profile` 统计信息(`total_amount`、`total_count`、`last_consume_time`) + - 触发标签计算(推送到 RabbitMQ 队列) + +#### 关键设计要点 + +- **时间点精确匹配**:所有手机号查询必须基于 `consume_time`,支持历史数据导入 +- **时间窗口管理**:手机关联支持 `effective_time` 和 `expire_time`,支持手机号回收 +- **临时用户机制**:处理只有手机号的情况,后续可转换为正式用户 +- **UUID策略**:所有用户使用 UUID 作为 `user_id`,身份证只作为字段存储 + +### 4.2 数据采集系统 + +#### 任务配置方式 + +1. **配置文件方式** (`config/data_collection_tasks.php`) + - 适用于系统级任务(如数据库实时同步) + - 需要版本控制 + +2. **数据库方式** (`data_collection_tasks` 集合) + - 通过前端界面动态创建和管理 + - 支持批量采集(batch)和实时监听(realtime)两种模式 + +#### Handler 类型 + +- **ConsumptionCollectionHandler**:消费记录采集,自动处理用户身份解析 +- **GenericCollectionHandler**:通用数据采集,支持字段映射、过滤条件、连表查询 +- **DatabaseSyncHandler**:数据库同步,支持全量同步和增量同步(Change Streams) + +#### 采集模式 + +- **批量采集(Batch)**:分页查询数据,支持定时调度(Cron) +- **实时监听(Realtime)**:使用 MongoDB Change Streams 持续监听变更 + +### 4.3 标签计算系统 + +#### 标签定义 + +存储在 `tag_definitions` 集合,包含: +- `tag_id`、`tag_code`、`tag_name` +- `rule_config`(规则配置,JSON格式) +- `update_frequency`(real_time/daily/weekly) + +#### 标签计算流程 + +``` +消费记录写入 + ↓ +更新用户统计信息 + ↓ +推送标签计算消息到 RabbitMQ + ↓ +TagCalculationWorker 消费消息 + ↓ +TagService::calculateTags() + ├─→ 获取用户数据 + ├─→ 获取标签定义列表 + ├─→ SimpleRuleEngine 计算标签值 + ├─→ 更新或创建 user_tags 记录 + └─→ 记录 tag_history 变更历史 +``` + +--- + +## 五、数据存储设计 + +### 5.1 MongoDB 核心集合 + +#### 用户相关 + +**user_profile**(用户画像) +- `user_id`:UUID(主键) +- `id_card_hash`:身份证哈希值 +- `id_card_encrypted`:加密的身份证号 +- `is_temporary`:是否为临时用户(true/false) +- `total_amount`:总消费金额 +- `total_count`:总消费次数 +- `last_consume_time`:最后消费时间 + +**user_phone_relations**(手机关联表) +- `phone_number`:手机号 +- `phone_hash`:手机号哈希值 +- `user_id`:关联的用户ID +- `effective_time`:生效时间 +- `expire_time`:过期时间(null 表示当前有效) +- `is_active`:是否有效 + +**consumption_records**(消费记录) +- 按时间分表:`consumption_records_YYYYMM` +- `record_id`:记录ID(UUID) +- `user_id`:用户ID +- `consume_time`:消费时间 +- `amount`:消费金额 +- `actual_amount`:实际金额 + +#### 标签相关 + +**tag_definitions**(标签定义) +- `tag_id`、`tag_code`、`tag_name` +- `rule_config`:规则配置(JSON) +- `update_frequency`:更新频率 + +**user_tags**(用户标签) +- `user_id`、`tag_id` +- `tag_value`:标签值 +- `confidence`:置信度 + +**tag_history**(标签变更历史) +- `user_id`、`tag_id` +- `old_value`、`new_value` +- `change_time`:变更时间 + +#### 任务相关 + +**data_collection_tasks**(数据采集任务) +- `task_id`:任务ID(UUID) +- `mode`:采集模式(batch/realtime) +- `field_mappings`:字段映射配置 +- `filter_conditions`:过滤条件 +- `progress`:任务进度 +- `status`:任务状态(pending/running/paused/stopped) + +**data_sources**(数据源) +- `data_source_id`:数据源ID +- `type`:数据源类型(mongodb/mysql) +- `host`、`port`、`database` + +### 5.2 Redis 存储 + +- **分布式锁**:`lock:data_collection:{task_id}` +- **任务状态标志**:`data_collection_task:{task_id}:start/pause/stop` +- **同步状态**:`data_collection:{task_id}:last_sync_time` + +### 5.3 RabbitMQ 队列 + +- **data_sync**:数据同步队列 +- **tag_calculation**:标签计算队列 + +--- + +## 六、设计模式 + +### 6.1 Handler 模式 +- `ConsumptionCollectionHandler`:消费记录采集 +- `GenericCollectionHandler`:通用数据采集 +- `DatabaseSyncHandler`:数据库同步 + +### 6.2 适配器模式 +- `DataSourceAdapterInterface`:数据源适配器接口 +- `MongoDBAdapter`:MongoDB适配器 +- `MySQLAdapter`:MySQL适配器 + +### 6.3 仓库模式(Repository) +- 所有 Repository 类封装数据访问逻辑 +- 提供统一的查询接口 + +### 6.4 工厂模式 +- `DataSourceAdapterFactory`:创建数据源适配器 +- `PollingStrategyFactory`:创建轮询策略 + +--- + +## 七、关键代码位置 + +### 核心服务类 + +**ConsumptionService** (`app/service/ConsumptionService.php`) +- `createRecord()`:创建消费记录的主入口 +- `handleMergeIfNeeded()`:处理用户合并逻辑 + +**IdentifierService** (`app/service/IdentifierService.php`) +- `resolvePersonId()`:解析用户ID(统一入口) +- `resolvePersonIdByPhone()`:通过手机号解析 +- `resolvePersonIdByIdCard()`:通过身份证解析 +- `createTemporaryPerson()`:创建临时用户 +- `bindIdCardToPerson()`:绑定身份证 + +**UserPhoneService** (`app/service/UserPhoneService.php`) +- `addPhoneToUser()`:添加手机号关联(核心方法) +- `findUserByPhone()`:根据手机号查找用户(支持时间点查询) +- `removePhoneFromUser()`:移除手机号关联 + +**TagService** (`app/service/TagService.php`) +- `calculateTags()`:计算用户标签 + +**DataCollectionTaskService** (`app/service/DataCollectionTaskService.php`) +- 数据采集任务的创建、启动、暂停、停止等操作 + +### 进程类 + +- **DataSyncScheduler** (`app/process/DataSyncScheduler.php`):数据采集任务调度器 +- **DataSyncWorker** (`app/process/DataSyncWorker.php`):数据同步Worker +- **TagCalculationWorker** (`app/process/TagCalculationWorker.php`):标签计算Worker + +--- + +## 八、API 接口体系 + +### 用户相关 +- `POST /api/users`:创建用户 +- `GET /api/users/{user_id}`:查询用户 +- `POST /api/users/search`:搜索用户 + +### 标签相关 +- `GET /api/users/{user_id}/tags`:查询用户标签 +- `PUT /api/users/{user_id}/tags`:计算/更新用户标签 +- `POST /api/tags/filter`:根据标签筛选用户 + +### 数据采集任务 +- `POST /api/data-collection-tasks`:创建任务 +- `POST /api/data-collection-tasks/{task_id}/start`:启动任务 +- `POST /api/data-collection-tasks/{task_id}/pause`:暂停任务 +- `POST /api/data-collection-tasks/{task_id}/stop`:停止任务 +- `GET /api/data-collection-tasks/{task_id}/progress`:获取任务进度 + +### 数据源 +- `GET /api/data-sources`:获取数据源列表 +- `POST /api/data-sources`:创建数据源 +- `POST /api/data-sources/test-connection`:测试连接 + +--- + +## 九、关键设计原则 + +### 9.1 时间点精确匹配 +- 所有手机号查询必须基于消费记录的实际时间点(`consume_time`) +- 支持历史数据导入和批量处理 +- 正确处理手机号回收后的重新分配 + +### 9.2 临时用户机制 +- 只有手机号时创建临时用户(`is_temporary=true`) +- 临时用户必须建立手机关联 +- 绑定身份证后自动转为正式用户 + +### 9.3 时间窗口管理 +- 手机关联支持 `effective_time` 和 `expire_time` +- 时间窗口必须连续,不能有间隙 +- 支持手机号在不同时间段属于不同用户 + +### 9.4 UUID 策略 +- 所有用户统一使用 UUID 作为 `user_id` +- 身份证只作为字段存储,不作为主键 +- 转为正式用户时,只更新身份证字段,不改变 `user_id` + +### 9.5 配置化设计 +- 任务配置支持配置文件和数据库两种方式 +- 数据源配置统一管理 +- 业务逻辑与配置分离 + +--- + +## 十、特殊场景处理 + +### 场景1:手机号回收 +- 一个手机号在不同时间段被不同用户使用 +- 通过时间窗口精确管理历史关联 +- 新关联建立时,自动将旧关联标记为过期 + +### 场景2:临时用户转正式用户 +- 第一次消费:只有手机号 → 创建临时用户 +- 第二次消费:手机号 + 身份证 → 临时用户转为正式用户 + +### 场景3:代订场景 +- 手机号和身份证关联到不同的正式用户 +- 策略:以身份证为准,消费记录归属到身份证用户 +- 手机号关联保持不变(可能是代订),记录日志 + +### 场景4:用户合并 +- 临时用户自动合并到正式用户 +- 合并内容:统计数据、标签、消费记录、手机关联 + +--- + +## 十一、数据流图 + +``` +数据源 (MongoDB/MySQL) + ↓ +数据采集任务 (DataSyncScheduler) + ├─→ ConsumptionCollectionHandler + │ ├─→ 批量采集:分页查询 + │ └─→ 实时监听:Change Streams + │ + └─→ DatabaseSyncHandler + ├─→ 全量同步:批量读取写入 + └─→ 增量同步:Change Streams + ↓ +消费记录写入 (ConsumptionService) + ├─→ 身份解析 (IdentifierService) + │ ├─→ 手机号 → user_id + │ └─→ 如果不存在,创建临时用户 + │ + ├─→ 写入 consumption_records + ├─→ 更新 user_profile 统计 + └─→ 触发标签计算(RabbitMQ) + ↓ +标签计算 (TagCalculationWorker) + ├─→ TagService::calculateTags() + ├─→ SimpleRuleEngine 计算 + ├─→ 更新 user_tags + └─→ 记录 tag_history +``` + +--- + +## 十二、配置文件位置 + +- **应用配置**:`config/app.php` +- **进程配置**:`config/process.php` +- **路由配置**:`config/route.php` +- **数据采集任务配置**:`config/data_collection_tasks.php` +- **数据源配置**:`config/data_sources.php` +- **数据库配置**:`config/database.php` + +--- + +## 十三、关键注意事项 + +1. **时间点查询**:所有手机号查询必须传入 `consume_time`,不能使用当前时间 +2. **临时用户关联**:临时用户创建后必须建立手机关联,不能跳过 +3. **时间窗口连续性**:手机关联的时间窗口必须连续,不能有间隙 +4. **UUID策略**:用户ID统一使用UUID,身份证只作为字段存储 +5. **合并时机**:仅在手机号和身份证号同时出现且关联到不同用户时触发合并 +6. **代订场景**:正式用户冲突时,以身份证为准,手机号关联保持不变 + +--- + +**文档版本**:v1.0 +**最后更新**:2025-01-28 +**维护说明**:本文档作为系统架构的核心记忆点,如有架构变更,请及时更新本文档 diff --git a/Moncter/提示词/标签定义逻辑对比分析.md b/Moncter/提示词/标签定义逻辑对比分析.md new file mode 100644 index 00000000..e993317a --- /dev/null +++ b/Moncter/提示词/标签定义逻辑对比分析.md @@ -0,0 +1,294 @@ +# 标签定义逻辑文档对比分析 + +## 一、文档概述 + +- **`标签定逻辑.md`**:原始需求文档(66行)- 简洁版本 +- **`标签定逻辑真实.md`**:完善后的技术文档(579行)- 详细版本 + +--- + +## 二、核心含义一致性分析 + +### ✅ 2.1 一致的部分 + +#### 1. **后台预先工作** +- **原始版本**:提到需要预先处理数据列表API,通过SQL查询配置化数据集合 +- **详细版本**:详细说明了数据源类型和字段API的实现 +- **结论**:✅ **含义一致**,详细版本是对原始需求的扩展说明 + +#### 2. **规则配置概念** +- **原始版本**:提到运算规则和正则规则两种类型 +- **详细版本**:详细说明了simple规则和regex规则(扩展方案) +- **结论**:✅ **含义一致**,详细版本补充了实现细节 + +#### 3. **标签任务处理流程** +- **原始版本**:4个简单步骤 + ``` + 1、选择已定义的标签 + 2、选择后点击保存,状态为待启动 + 3、在列表启动的时候,后台先从后台读取定义标签的集合,并查询出来 + 4、根据定义标签的规则条件,直接根据用户表遍历过去进行打标签,然后将标签存储。 + ``` +- **详细版本**:详细的流程图和代码逻辑 +- **结论**:✅ **含义一致**,详细版本是对原始流程的细化 + +#### 4. **标签基本信息** +- **原始版本**:提到"标签编码、标签名称" +- **详细版本**:详细列出了所有字段(tag_code、tag_name、category、description等) +- **结论**:✅ **含义一致**,详细版本补充了完整字段列表 + +--- + +## 三、存在差异的部分 + +### ⚠️ 3.1 JSON配置格式差异 + +#### 原始版本的格式: +```json +[ + { + field:"交易金额", + operator:"<", + value:3000, + tag_value:"低价值用户" // ❌ tag_value在条件中 + }, + { + field:"交易金额", + operator:">=", + value:3000, + tag_value:"中等价值用户" // ❌ tag_value在条件中 + } +] +``` + +#### 详细版本的格式(符合实际代码): +```json +{ + "rule_type": "simple", + "conditions": [ + { + "field": "total_amount", + "operator": "<", + "value": 3000 + // ✅ tag_value不在条件中 + } + ], + "tag_value": "低价值用户", // ✅ tag_value在rule_config中 + "confidence": 1.0 +} +``` + +**差异说明**: +- ❌ **原始版本**:每个条件都有独立的 `tag_value`,这不符合实际的数据结构 +- ✅ **详细版本**:`tag_value` 在 `rule_config` 中,所有条件满足时使用同一个 `tag_value` + +**实际代码验证**: +根据 `SimpleRuleEngine.php` 和 `TagService.php` 的代码,正确的格式应该是: +- `tag_value` 在 `rule_config` 中,不在 `conditions` 中 +- 多个条件之间是 AND 关系,所有条件满足时使用同一个 `tag_value` + +**建议**: +- 原始版本可能是业务需求的简化描述 +- 实际实现应该按照详细版本的格式 + +--- + +### ⚠️ 3.2 字段命名差异 + +#### 原始版本: +- 使用中文字段名:`"交易金额"`、`"店铺名称"`、`"交易状态"`、`"手机号"` + +#### 详细版本: +- 使用英文字段名:`"total_amount"`、`"shop_name"`、`"status"`、`"phone"` + +**差异说明**: +- 原始版本可能是面向业务人员的描述 +- 详细版本是面向开发人员的技术实现 +- 实际数据库中应该使用英文字段名 + +**建议**: +- 前端界面可以显示中文名称 +- 后端存储和计算使用英文字段名 +- 需要建立字段映射关系 + +--- + +### ⚠️ 3.3 "数据列表"概念差异 + +#### 原始版本: +``` +-先用sql语句查询出符合条件的结果,这段数据库的查询操作可以配置化,来增减数据集合,这个结果可以命名,例如:消费记录表。 +``` + +#### 详细版本: +``` +系统支持以下数据源类型: +1. user_profile - 用户档案表 +2. consumption_records - 消费记录表 +3. user_phone_relations - 用户手机号关系表 +``` + +**差异说明**: +- 原始版本提到"SQL语句",但MongoDB使用查询语句,不是SQL +- 原始版本提到"配置化查询",可能是指数据源配置 +- 详细版本明确了数据源类型和字段定义 + +**建议**: +- 原始版本中的"数据列表"应该理解为"数据源" +- "SQL语句"应该理解为"MongoDB查询"或"数据源配置" +- 需要明确数据源配置的管理方式 + +--- + +### ⚠️ 3.4 正则规则实现差异 + +#### 原始版本: +```json +{ + field:"店铺名称", + operator:"/淘宝/", // ❌ 直接使用正则表达式作为operator + value:true, + tag_value:"淘宝平台" +} +``` + +#### 详细版本: +```json +{ + "rule_type": "regex", // ✅ 使用rule_type区分 + "conditions": [ + { + "field": "shop_name", + "operator": "match", + "pattern": "/淘宝/", // ✅ pattern字段 + "value": true + } + ], + "tag_value": "淘宝平台" +} +``` + +**差异说明**: +- 原始版本:正则表达式直接作为 `operator` +- 详细版本:需要 `rule_type="regex"` 和 `pattern` 字段 +- **当前代码**:实际只支持 `simple` 规则,正则规则需要扩展实现 + +**建议**: +- 如果使用 `simple` 规则,可以用 `in` 运算符替代: + ```json + { + "field": "shop_name", + "operator": "in", + "value": ["淘宝", "天猫"] + } + ``` + +--- + +## 四、关键差异总结 + +| 对比项 | 原始版本 | 详细版本 | 实际代码 | 建议 | +|--------|---------|---------|---------|------| +| **JSON格式** | tag_value在条件中 | tag_value在rule_config中 | ✅ 详细版本正确 | 使用详细版本格式 | +| **字段命名** | 中文名称 | 英文名称 | ✅ 详细版本正确 | 前端显示中文,后端使用英文 | +| **数据列表** | SQL查询配置 | 数据源类型定义 | ✅ 详细版本更准确 | 明确为数据源配置 | +| **正则规则** | operator直接使用正则 | 需要rule_type和pattern | ⚠️ 当前未实现 | 使用simple规则的in运算符替代 | + +--- + +## 五、一致性结论 + +### ✅ 核心含义:**基本一致** + +1. **业务逻辑一致**: + - 都描述了标签定义、规则配置、任务处理的流程 + - 都支持运算规则和正则规则的概念 + +2. **实现细节差异**: + - 原始版本是业务需求的简化描述 + - 详细版本是技术实现的完整说明 + - 差异主要体现在数据格式和实现细节上 + +3. **建议**: + - ✅ **使用详细版本的JSON格式**(符合实际代码) + - ✅ **使用英文字段名**(符合数据库设计) + - ✅ **明确数据源配置方式**(不是SQL,是MongoDB查询或配置) + - ⚠️ **正则规则当前未实现**,建议使用simple规则的in运算符替代 + +--- + +## 六、修正建议 + +### 6.1 修正原始版本的JSON格式 + +**原始版本(需要修正)**: +```json +[ + { + field:"交易金额", + operator:"<", + value:3000, + tag_value:"低价值用户" // ❌ 错误位置 + } +] +``` + +**修正后的格式**: +```json +{ + "rule_type": "simple", + "conditions": [ + { + "field": "total_amount", // ✅ 使用英文字段名 + "operator": "<", + "value": 3000 + } + ], + "tag_value": "低价值用户", // ✅ 在rule_config中 + "confidence": 1.0 +} +``` + +### 6.2 明确数据源配置 + +**原始版本描述**: +> "先用sql语句查询出符合条件的结果,这段数据库的查询操作可以配置化" + +**修正为**: +> "配置数据源类型(如:consumption_records),系统提供该数据源的字段列表API,前端选择字段进行规则配置" + +### 6.3 正则规则说明 + +**原始版本**: +> operator:"/淘宝/" + +**修正为**: +> 当前系统支持 `simple` 规则,正则匹配可以通过 `in` 运算符实现: +> ```json +> { +> "field": "shop_name", +> "operator": "in", +> "value": ["淘宝", "天猫"] +> } +> ``` + +--- + +## 七、最终结论 + +**两个文档的核心含义基本一致**,但存在以下差异: + +1. ✅ **业务逻辑**:完全一致 +2. ⚠️ **数据格式**:原始版本需要修正(tag_value位置、字段命名) +3. ⚠️ **技术细节**:详细版本更准确(符合实际代码实现) +4. ✅ **流程描述**:详细版本是对原始版本的细化 + +**建议**: +- 保留详细版本作为技术实现文档 +- 修正原始版本中的格式问题 +- 明确数据源配置方式(不是SQL,是MongoDB数据源配置) + +--- + +**分析时间**:2025-01-XX +**基于代码版本**:当前代码库分析 diff --git a/Moncter/提示词/标签定逻辑.md b/Moncter/提示词/标签定逻辑.md new file mode 100644 index 00000000..8cbfaddd --- /dev/null +++ b/Moncter/提示词/标签定逻辑.md @@ -0,0 +1,68 @@ +1、标签定义 + +## 后台预先工作: +// 标签定义数据列表API,由于mongodb表具有特殊性,因此需要预先处理 +-用代码先写好数据查询,如果可以,可以做个手动配置sql的方式,例如 +标签表:[ + 消费数据=> 消费记录表的sql +] + +// 数据列表字段API +-通过上方的列表id,返回展示下字段 + +## 前台界面 +-标签规则配置,这块在UI界面是可以选择的 + +1、运算规则 + 选择"数据列表字段API"展示出来的API,例如消费记录展示了字段:交易金额、店铺名称、交易状态、手机号 + 配置示例JSON: + + [ + { + field:"交易金额", + operator:"<" , + value:3000, + tag_value:"低价值用户" + }, + { + field:"交易金额", + operator:">=" , + value:3000, + tag_value:"中等价值用户" + }, + { + field:"交易金额", + operator:">" , + value:9000, + tag_value:"高价值用户" + }, + + ] + 注意:一个item代表一个条件, + + + +2、正则规则 + #判断字符串是否含有淘宝二字,如果有就是淘宝平台的 + [ + { + field:"店铺名称", + operator:"/淘宝/" , + value:true, + tag_value:"淘宝平台" + }, + + ] + 注意:一个item代表一个条件。 + + +标签保存的时候,要输入标签编码、标签名称 + + +##标签任务处理逻辑顺序 + +1、选择已定义的标签 +2、选择后点击保存,状态为待启动 +3、在列表启动的时候,后台先从后台读取定义标签的集合,并查询出来 +4、根据定义标签的规则条件,直接根据用户表遍历过去进行打标签,然后将标签存储。 + \ No newline at end of file diff --git a/Moncter/提示词/标签定逻辑真实.md b/Moncter/提示词/标签定逻辑真实.md new file mode 100644 index 00000000..2587d318 --- /dev/null +++ b/Moncter/提示词/标签定逻辑真实.md @@ -0,0 +1,737 @@ +# 标签定义逻辑说明 + +## 一、概述 + +标签定义是标签引擎的核心功能,用于定义如何根据用户数据自动计算和打标签。系统支持两种规则类型:运算规则和正则规则。 + +--- + +## 二、后台预先工作 + +### 2.1 标签定义数据列表API + +由于 MongoDB 表的特殊性,需要预先配置数据查询操作。 + +#### 2.1.1 数据列表配置 + +**功能说明**: +- 通过配置化的查询操作,从 MongoDB 集合中查询出符合条件的结果 +- 这个查询操作可以配置化,支持动态增减数据集合 +- 每个查询结果可以命名,例如:`消费记录表`、`用户档案表`、`订单明细表` 等 + +**配置示例**: +```json +{ + "list_id": "consumption_records_list", + "list_name": "消费记录表", + "data_source_id": "source_123", + "database": "tag_engine", + "collection": "consumption_records", + "query_config": { + "filter": {}, + "sort": { "create_time": -1 }, + "limit": 1000 + }, + "description": "消费记录数据列表", + "status": 1, + "create_time": "2025-01-01T00:00:00Z" +} +``` + +**数据结构**: +```javascript +{ + list_id: String, // 列表ID(唯一标识) + list_name: String, // 列表名称(如:消费记录表) + data_source_id: String, // 数据源ID + database: String, // 数据库名 + collection: String, // 集合名 + query_config: Object, // 查询配置(MongoDB查询条件) + description: String, // 描述 + status: Number, // 状态(0:禁用, 1:启用) + create_time: Date, + update_time: Date +} +``` + +**API接口**: +- `GET /api/tag-data-lists` - 获取数据列表列表 +- `POST /api/tag-data-lists` - 创建数据列表配置 +- `GET /api/tag-data-lists/{list_id}` - 获取数据列表详情 +- `PUT /api/tag-data-lists/{list_id}` - 更新数据列表配置 +- `DELETE /api/tag-data-lists/{list_id}` - 删除数据列表配置 + +#### 2.1.2 数据列表字段API + +**功能说明**: +- 通过数据列表ID,返回该列表的字段信息 +- 用于前端界面选择字段进行规则配置 + +**API接口**:`GET /api/tag-data-lists/{list_id}/fields` + +**返回格式**: +```json +{ + "code": 200, + "message": "查询成功", + "data": { + "list_id": "consumption_records_list", + "list_name": "消费记录表", + "fields": [ + { + "field": "交易金额", + "field_name": "amount", + "type": "number", + "description": "交易金额" + }, + { + "field": "店铺名称", + "field_name": "shop_name", + "type": "string", + "description": "店铺名称" + }, + { + "field": "交易状态", + "field_name": "status", + "type": "string", + "description": "交易状态" + }, + { + "field": "手机号", + "field_name": "phone", + "type": "string", + "description": "手机号" + } + ] + } +} +``` + +**字段说明**: +- `field`:前端显示的字段名称(中文) +- `field_name`:数据库中的实际字段名(英文) +- `type`:字段类型(number、string、datetime、boolean等) +- `description`:字段描述 + +**实现方式**: +1. 从数据列表配置中获取 `collection` 信息 +2. 查询该集合的样本数据(如:前10条) +3. 分析样本数据的字段结构 +4. 返回字段列表(包含中英文映射) + +--- + +## 三、前台界面配置 + +### 3.1 标签基本信息 + +创建标签定义时需要填写以下基本信息: + +- **标签编码** (`tag_code`):唯一标识,如 `high_consumer`、`vip_user` +- **标签名称** (`tag_name`):显示名称,如 `高消费用户`、`VIP用户` + +**可选字段**: +- **分类** (`category`):标签分类,如 `消费能力`、`活跃度`、`风险等级`、`生命周期` +- **描述** (`description`):标签的详细说明 +- **更新频率** (`update_frequency`): + - `real_time` - 实时更新 + - `daily` - 每日更新 + - `weekly` - 每周更新 + - `monthly` - 每月更新 +- **状态** (`status`): + - `0` - 启用 + - `1` - 禁用 + +### 3.2 规则配置 + +标签规则配置在UI界面可以选择两种类型:**运算规则** 和 **正则规则**。 + +#### 3.2.1 运算规则 + +**配置流程**: +1. 选择数据列表(如:消费记录表) +2. 调用数据列表字段API,获取字段列表 +3. 选择字段(如:交易金额、店铺名称、交易状态、手机号) +4. 配置条件:字段、运算符、值、标签值 + +**配置示例JSON**: +```json +[ + { + "field": "交易金额", + "field_name": "amount", + "operator": "<", + "value": 3000, + "tag_value": "低价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">=", + "value": 3000, + "tag_value": "中等价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">", + "value": 9000, + "tag_value": "高价值用户" + } +] +``` + +**重要说明**: +- **一个item代表一个条件** +- 每个条件都有独立的 `tag_value` +- 当条件满足时,用户将被标记为该条件的 `tag_value` +- 多个条件之间是**互斥**的(OR关系),满足任一条件即可 + +**支持的运算符**: +- `>` - 大于 +- `>=` - 大于等于 +- `<` - 小于 +- `<=` - 小于等于 +- `=` / `==` - 等于 +- `!=` - 不等于 +- `in` - 在列表中(值为数组) +- `not_in` - 不在列表中(值为数组) + +**存储格式**(转换为标准格式): +```json +{ + "rule_type": "simple", + "data_list_id": "consumption_records_list", + "conditions": [ + { + "field": "交易金额", + "field_name": "amount", + "operator": "<", + "value": 3000, + "tag_value": "低价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">=", + "value": 3000, + "tag_value": "中等价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">", + "value": 9000, + "tag_value": "高价值用户" + } + ] +} +``` + +#### 3.2.2 正则规则 + +**配置说明**: +- 使用正则表达式匹配字符串字段 +- 判断字符串是否含有指定的模式 + +**配置示例**: +```json +[ + { + "field": "店铺名称", + "field_name": "shop_name", + "operator": "/淘宝/", + "value": true, + "tag_value": "淘宝平台" + } +] +``` + +**重要说明**: +- **一个item代表一个条件** +- `operator` 字段直接使用正则表达式(如:`/淘宝/`) +- `value` 字段表示是否匹配(`true` 表示匹配,`false` 表示不匹配) +- 当正则匹配成功时,用户将被标记为 `tag_value` + +**存储格式**(转换为标准格式): +```json +{ + "rule_type": "regex", + "data_list_id": "consumption_records_list", + "conditions": [ + { + "field": "店铺名称", + "field_name": "shop_name", + "operator": "/淘宝/", + "pattern": "淘宝", + "value": true, + "tag_value": "淘宝平台" + } + ] +} +``` + +**正则表达式说明**: +- 支持标准的正则表达式语法 +- 常用模式: + - `/淘宝/` - 包含"淘宝" + - `/^淘宝/` - 以"淘宝"开头 + - `/淘宝$/` - 以"淘宝"结尾 + - `/淘宝|天猫/` - 包含"淘宝"或"天猫" + +### 3.3 完整的标签定义数据结构 + +```json +{ + "tag_id": "uuid", + "tag_code": "consumer_level", + "tag_name": "消费等级", + "category": "消费能力", + "description": "根据消费金额划分用户等级", + "rule_type": "simple", + "rule_config": { + "rule_type": "simple", + "data_list_id": "consumption_records_list", + "data_list_name": "消费记录表", + "conditions": [ + { + "field": "交易金额", + "field_name": "amount", + "operator": "<", + "value": 3000, + "tag_value": "低价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">=", + "value": 3000, + "tag_value": "中等价值用户" + }, + { + "field": "交易金额", + "field_name": "amount", + "operator": ">", + "value": 9000, + "tag_value": "高价值用户" + } + ] + }, + "update_frequency": "real_time", + "status": 0, + "priority": 1, + "version": 1, + "create_time": "2025-01-01T00:00:00Z", + "update_time": "2025-01-01T00:00:00Z" +} +``` + +--- + +## 四、标签任务处理逻辑 + +### 4.1 标签任务创建流程 + +``` +1. 用户在前台创建标签任务 + ├─→ 选择已定义的标签(可多选) + ├─→ 配置任务类型(full/incremental/specified) + ├─→ 配置用户范围(all/list/filter) + ├─→ 配置调度计划(可选) + └─→ 点击保存 + +2. 任务保存后 + ├─→ 状态设置为 "pending"(待启动) + ├─→ 任务信息保存到 tag_tasks 集合 + └─→ 返回任务ID +``` + +### 4.2 标签任务启动流程 + +``` +1. 用户在任务列表点击"启动"按钮 + ↓ +2. 调用API: POST /api/tag-tasks/{task_id}/start + ↓ +3. TagTaskService->startTask() + ├─→ 检查任务状态(不能是 running) + ├─→ 更新任务状态为 "running" + └─→ 设置 Redis 标志:tag_task:{taskId}:start + ↓ +4. TagTaskExecutor->execute() + ├─→ 创建执行记录(tag_task_executions) + ├─→ 获取目标标签ID列表(target_tag_ids) + ├─→ 遍历每个标签定义 + │ ├─→ 从 tag_definitions 读取标签定义 + │ ├─→ 获取 rule_config 中的 data_list_id + │ ├─→ 根据 data_list_id 查询数据列表配置 + │ ├─→ 根据数据列表配置查询数据集合 + │ └─→ 获取用户ID列表(从数据集合中提取) + │ + └─→ 批量处理用户(批次大小可配置,默认100) + ↓ + 5. 遍历每个用户批次 + For each user in batch: + ├─→ 检查任务状态(是否被暂停/停止) + ├─→ 根据标签定义的规则条件计算标签值 + │ ├─→ 获取用户在该数据列表中的数据 + │ ├─→ 遍历 rule_config.conditions + │ │ ├─→ 根据 field_name 获取字段值 + │ │ ├─→ 根据 operator 进行比较 + │ │ │ ├─→ 运算规则:数值/字符串比较 + │ │ │ └─→ 正则规则:正则表达式匹配 + │ │ └─→ 如果条件满足,使用该条件的 tag_value + │ ├─→ 如果多个条件满足,使用第一个满足条件的 tag_value + │ └─→ 如果所有条件都不满足,标签值为 null(不打标签) + ├─→ 更新或创建 user_tags 记录 + ├─→ 记录标签变更历史(tag_history) + ├─→ 成功:success_count++ + ├─→ 失败:error_count++ + └─→ 每处理10个用户更新一次进度 + ├─→ processed_users + ├─→ success_count + ├─→ error_count + └─→ percentage = (processed_users / total_users) * 100 + ↓ +6. 更新最终进度和统计 + ├─→ percentage = 100 + ├─→ 更新执行记录状态为 "completed" + └─→ 更新任务统计信息 +``` + +### 4.3 标签计算核心逻辑 + +#### 4.3.1 数据获取 + +**步骤1:读取标签定义** +```php +// 从 tag_definitions 集合读取标签定义 +$tagDefinition = TagDefinitionRepository::find($tagId); +$ruleConfig = $tagDefinition->rule_config; +$dataListId = $ruleConfig['data_list_id']; +``` + +**步骤2:获取数据列表配置** +```php +// 根据 data_list_id 查询数据列表配置 +$dataList = TagDataListRepository::find($dataListId); +$collection = $dataList->collection; +$database = $dataList->database; +$queryConfig = $dataList->query_config; +``` + +**步骤3:查询数据集合** +```php +// 根据数据列表配置查询数据 +$collectionObj = MongoDB::connection($database)->collection($collection); +$data = $collectionObj->find($queryConfig['filter']) + ->sort($queryConfig['sort'] ?? []) + ->limit($queryConfig['limit'] ?? 1000) + ->toArray(); +``` + +#### 4.3.2 规则计算 + +**运算规则计算**: +```php +foreach ($ruleConfig['conditions'] as $condition) { + $fieldName = $condition['field_name']; + $operator = $condition['operator']; + $expectedValue = $condition['value']; + $tagValue = $condition['tag_value']; + + // 从数据中获取字段值 + $actualValue = $data[$fieldName] ?? null; + + // 根据运算符进行比较 + $match = false; + switch ($operator) { + case '>': + $match = $actualValue > $expectedValue; + break; + case '>=': + $match = $actualValue >= $expectedValue; + break; + case '<': + $match = $actualValue < $expectedValue; + break; + case '<=': + $match = $actualValue <= $expectedValue; + break; + case '=': + case '==': + $match = $actualValue == $expectedValue; + break; + case '!=': + $match = $actualValue != $expectedValue; + break; + case 'in': + $match = in_array($actualValue, (array)$expectedValue); + break; + case 'not_in': + $match = !in_array($actualValue, (array)$expectedValue); + break; + } + + // 如果条件满足,返回该条件的 tag_value + if ($match) { + return $tagValue; + } +} + +// 所有条件都不满足,返回 null +return null; +``` + +**正则规则计算**: +```php +foreach ($ruleConfig['conditions'] as $condition) { + $fieldName = $condition['field_name']; + $pattern = $condition['pattern'] ?? $condition['operator']; // 从operator或pattern获取正则 + $expectedMatch = $condition['value']; // true表示匹配,false表示不匹配 + $tagValue = $condition['tag_value']; + + // 从数据中获取字段值 + $actualValue = $data[$fieldName] ?? ''; + + // 执行正则匹配 + $isMatch = preg_match($pattern, $actualValue); + + // 判断是否满足条件 + if (($expectedMatch && $isMatch) || (!$expectedMatch && !$isMatch)) { + return $tagValue; + } +} + +// 所有条件都不满足,返回 null +return null; +``` + +#### 4.3.3 标签值存储 + +**存储到 user_tags 集合**: +```javascript +{ + user_id: "用户ID", + tag_id: "标签ID", + tag_value: "标签值(字符串)", // 从条件的tag_value获取 + tag_value_type: "string", + confidence: 1.0, + effective_time: "生效时间", + create_time: "创建时间", + update_time: "更新时间" +} +``` + +**重要说明**: +- 如果计算出的标签值为 `null`,则不创建或删除该用户的该标签记录 +- 如果标签值发生变化,记录到 `tag_history` 集合 + +--- + +## 五、数据存储结构 + +### 5.1 标签定义集合(tag_definitions) + +```javascript +{ + tag_id: String, // 标签ID(UUID) + tag_code: String, // 标签代码(唯一标识) + tag_name: String, // 标签名称 + category: String, // 标签分类(可选) + description: String, // 描述(可选) + rule_type: String, // 规则类型(simple/regex) + rule_config: Object, // 规则配置(JSON) + update_frequency: String, // 更新频率(可选) + status: Number, // 状态(0:启用, 1:禁用) + priority: Number, // 优先级(可选) + version: Number, // 版本号(可选) + create_time: Date, + update_time: Date +} +``` + +### 5.2 数据列表配置集合(tag_data_lists) + +```javascript +{ + list_id: String, // 列表ID(UUID) + list_name: String, // 列表名称(如:消费记录表) + data_source_id: String, // 数据源ID + database: String, // 数据库名 + collection: String, // 集合名 + query_config: Object, // 查询配置(MongoDB查询条件) + description: String, // 描述 + status: Number, // 状态(0:禁用, 1:启用) + create_time: Date, + update_time: Date +} +``` + +### 5.3 用户标签集合(user_tags) + +```javascript +{ + user_id: String, // 用户ID + tag_id: String, // 标签ID + tag_value: String, // 标签值(字符串格式) + tag_value_type: String, // 值类型(string) + confidence: Number, // 置信度(0.0-1.0) + effective_time: Date, // 生效时间 + expire_time: Date, // 过期时间(可选) + create_time: Date, + update_time: Date +} +``` + +### 5.4 标签历史集合(tag_history) + +```javascript +{ + history_id: String, // 历史记录ID + user_id: String, // 用户ID + tag_id: String, // 标签ID + old_value: String, // 旧值 + new_value: String, // 新值 + change_reason: String, // 变更原因 + change_time: Date, // 变更时间 + operator: String // 操作人 +} +``` + +### 5.5 标签任务集合(tag_tasks) + +```javascript +{ + task_id: String, // 任务ID + name: String, // 任务名称 + description: String, // 任务描述 + task_type: String, // 任务类型(full/incremental/specified) + target_tag_ids: Array, // 目标标签ID列表 + user_scope: Object, // 用户范围配置 + schedule: Object, // 调度计划 + config: Object, // 任务配置 + status: String, // 任务状态(pending/running/paused/stopped/error) + progress: Object, // 任务进度 + statistics: Object, // 任务统计 + created_by: String, + created_at: Date, + updated_at: Date +} +``` + +--- + +## 六、API接口说明 + +### 6.1 数据列表接口 + +- `GET /api/tag-data-lists` - 获取数据列表列表 +- `POST /api/tag-data-lists` - 创建数据列表配置 +- `GET /api/tag-data-lists/{list_id}` - 获取数据列表详情 +- `PUT /api/tag-data-lists/{list_id}` - 更新数据列表配置 +- `DELETE /api/tag-data-lists/{list_id}` - 删除数据列表配置 +- `GET /api/tag-data-lists/{list_id}/fields` - 获取数据列表字段 + +### 6.2 标签定义接口 + +- `GET /api/tag-definitions` - 获取标签定义列表 +- `POST /api/tag-definitions` - 创建标签定义 +- `GET /api/tag-definitions/{tag_id}` - 获取标签定义详情 +- `PUT /api/tag-definitions/{tag_id}` - 更新标签定义 +- `DELETE /api/tag-definitions/{tag_id}` - 删除标签定义 + +### 6.3 标签任务接口 + +- `GET /api/tag-tasks` - 获取标签任务列表 +- `POST /api/tag-tasks` - 创建标签任务 +- `GET /api/tag-tasks/{task_id}` - 获取任务详情 +- `POST /api/tag-tasks/{task_id}/start` - 启动任务 +- `POST /api/tag-tasks/{task_id}/pause` - 暂停任务 +- `POST /api/tag-tasks/{task_id}/stop` - 停止任务 + +--- + +## 七、关键代码文件 + +### 7.1 后端代码(需要实现) + +- `app/controller/TagDataListController.php` - 数据列表控制器 +- `app/repository/TagDataListRepository.php` - 数据列表数据访问 +- `app/service/TagDataListService.php` - 数据列表服务 +- `app/controller/TagDefinitionController.php` - 标签定义控制器 +- `app/service/TagService.php` - 标签计算服务(需要修改) +- `app/service/TagRuleEngine/SimpleRuleEngine.php` - 简单规则引擎(需要修改) +- `app/service/TagRuleEngine/RegexRuleEngine.php` - 正则规则引擎(需要新增) +- `app/service/TagTaskService.php` - 标签任务服务 +- `app/service/TagTaskExecutor.php` - 标签任务执行器(需要修改) + +### 7.2 前端代码(需要实现) + +- `TaskShow/src/views/TagDataList/List.vue` - 数据列表管理 +- `TaskShow/src/views/TagDataList/Form.vue` - 数据列表配置表单 +- `TaskShow/src/views/TagDefinition/Form.vue` - 标签定义表单(需要修改) +- `TaskShow/src/views/TagDefinition/List.vue` - 标签定义列表 +- `TaskShow/src/views/TagTask/TaskForm.vue` - 标签任务表单 +- `TaskShow/src/store/tagDataList.ts` - 数据列表状态管理(需要新增) + +--- + +## 八、注意事项 + +1. **数据列表配置**:必须先配置数据列表,才能创建标签定义 +2. **字段映射**:前端使用中文字段名(field),后端使用英文字段名(field_name) +3. **条件逻辑**:多个条件之间是互斥的(OR关系),满足第一个条件即使用该条件的tag_value +4. **标签值**:如果所有条件都不满足,标签值为null,不创建标签记录 +5. **数据查询**:根据数据列表配置的query_config查询数据,支持MongoDB查询语法 +6. **正则规则**:operator字段直接存储正则表达式字符串,需要解析后使用preg_match匹配 + +--- + +## 九、实现要点 + +### 9.1 数据列表配置 + +1. **查询配置格式**: + ```json + { + "filter": { "status": "active" }, + "sort": { "create_time": -1 }, + "limit": 1000 + } + ``` + +2. **字段自动识别**: + - 查询样本数据(前10条) + - 分析字段结构 + - 返回字段列表(包含中英文映射) + +### 9.2 规则计算逻辑 + +1. **运算规则**: + - 从数据中获取字段值 + - 根据运算符进行比较 + - 满足条件即返回该条件的tag_value + +2. **正则规则**: + - 从数据中获取字段值 + - 使用preg_match进行正则匹配 + - 匹配成功即返回该条件的tag_value + +### 9.3 标签任务执行 + +1. **数据获取**: + - 根据标签定义的data_list_id获取数据列表配置 + - 根据数据列表配置查询数据集合 + - 提取用户ID列表 + +2. **标签计算**: + - 遍历每个用户 + - 获取该用户在数据列表中的数据 + - 根据规则条件计算标签值 + - 存储标签结果 + +--- + +**文档更新时间**:2025-01-XX +**基于需求**:按照原始思路完善 diff --git a/Moncter/提示词/集合筛选功能使用技巧.md b/Moncter/提示词/集合筛选功能使用技巧.md new file mode 100644 index 00000000..93c64aab --- /dev/null +++ b/Moncter/提示词/集合筛选功能使用技巧.md @@ -0,0 +1,342 @@ +# 集合筛选功能使用技巧 + +## 功能概览 + +在多集合模式下,提供了强大的筛选和批量操作功能,让选择大量集合变得简单快捷。 + +--- + +## 核心功能 + +### 1. 文本筛选 + +**输入框筛选**: +``` +[🔍 筛选集合名称...] +``` + +**功能**: +- 实时筛选集合列表 +- 支持模糊匹配 +- 不区分大小写 +- 支持中文和英文 + +**示例**: +``` +输入 "2021" → 显示所有包含"2021"的集合 +输入 "女" → 显示所有包含"女"的集合 +输入 "cons" → 显示所有包含"cons"的集合 +``` + +### 2. 批量操作按钮 + +#### 全选 +- **功能**:选择当前筛选结果的**所有**集合 +- **行为**:追加到已选列表(不清除其他已选项) +- **场景**:快速选择某一类集合 + +**示例**: +``` +1. 输入 "2021" +2. 点击 [全选] +3. 清空筛选 +4. 输入 "2022" +5. 点击 [全选] +→ 结果:同时选中2021和2022的所有集合 +``` + +#### 清空 +- **功能**:清空**所有**已选集合 +- **行为**:清除整个选择列表 +- **场景**:重新开始选择 + +#### 反选 +- **功能**:反选当前筛选结果的集合 +- **行为**: + - 已选中的 → 取消选择 + - 未选中的 → 选中 + - 不在筛选结果中的已选项 → 保持选中 +- **场景**:排除某些集合 + +**示例**: +``` +1. 点击快捷筛选 [2021年](选中全年) +2. 输入 "202101"(只显示1月) +3. 点击 [反选](取消选择1月) +→ 结果:选中2021年的2-12月 +``` + +### 3. 快捷筛选(智能按钮) + +当检测到按日期格式的集合(如 `collection_202101`)时,自动显示快捷筛选按钮。 + +#### 按年份筛选 +``` +[2021年] [2022年] [2023年] [2024年] [2025年] +``` + +**功能**:一键选择某一年的所有集合 + +**匹配规则**:包含年份字符串(如 `2021`)的集合 + +**示例**: +``` +点击 [2021年] +→ 自动选中: + consumption_records_202101 + consumption_records_202102 + ... + consumption_records_202112 +``` + +#### 按时间范围筛选 +``` +[最近3个月] [最近6个月] [最近12个月] +``` + +**功能**:智能计算并选择最近N个月的集合 + +**匹配规则**: +1. 获取当前年月(如 2025-01) +2. 向前推算N个月 +3. 查找包含这些年月(YYYYMM格式)的集合 + +**示例**(假设当前是 2025-01): +``` +点击 [最近3个月] +→ 自动选中: + consumption_records_202501 (2025-01) + consumption_records_202412 (2024-12) + consumption_records_202411 (2024-11) +``` + +``` +点击 [最近6个月] +→ 自动选中: + consumption_records_202501 + consumption_records_202412 + consumption_records_202411 + consumption_records_202410 + consumption_records_202409 + consumption_records_202408 +``` + +--- + +## 使用技巧 + +### 技巧1:组合使用快捷筛选和文本筛选 + +**需求**:选择2021年第一季度 + +**方法**: +``` +1. 输入筛选 "20210" + → 显示 202101, 202102, 202103, ..., 202109 +2. 点击 [全选] +3. 输入 "202104" + → 只显示 202104 +4. 点击 [反选](取消4月) +5. 重复步骤3-4,排除5-9月 +``` + +**更简单的方法**: +``` +1. 输入 "202101",点击 [全选] +2. 输入 "202102",点击 [全选] +3. 输入 "202103",点击 [全选] +``` + +### 技巧2:使用反选排除特定月份 + +**需求**:选择2021年除了春节月份(1、2月)的所有数据 + +**方法**: +``` +1. 点击快捷筛选 [2021年] + → 选中全年12个月 +2. 输入 "202101" +3. 点击 [反选] + → 取消1月 +4. 输入 "202102" +5. 点击 [反选] + → 取消2月 +6. 清空筛选框查看结果 + → 已选中:202103-202112(10个月) +``` + +### 技巧3:跨年选择 + +**需求**:选择2020年下半年和2021年上半年 + +**方法**: +``` +1. 输入 "202007",点击 [全选] +2. 输入 "202008",点击 [全选] +3. 输入 "202009",点击 [全选] +4. 输入 "202010",点击 [全选] +5. 输入 "202011",点击 [全选] +6. 输入 "202012",点击 [全选] +7. 输入 "202101",点击 [全选] +8. 输入 "202102",点击 [全选] +9. 输入 "202103",点击 [全选] +10. 输入 "202104",点击 [全选] +11. 输入 "202105",点击 [全选] +12. 输入 "202106",点击 [全选] +``` + +**更快的方法**(如果命名规则一致): +``` +1. 输入 "2020" +2. 点击 [全选](选中2020全年) +3. 输入 "20200"(202001-202009,前9个月) +4. 点击 [反选](排除前6个月,只留7-12月) +5. 输入 "2021" +6. 点击 [全选] +7. 输入 "202107"(7月及以后) +8. 向后筛选并反选,只留1-6月 +``` + +### 技巧4:按商品类型批量选择 + +**需求**:在 `KR_淘宝` 数据库中选择所有zippo相关的集合 + +**方法**: +``` +1. 启用多集合模式 +2. 输入 "zippo" + → 显示:zippo1, zippo2, zippo3, zippo4, zippo5 +3. 点击 [全选] + → 一次性选中所有5个zippo集合 +``` + +### 技巧5:逐步累加选择 + +**需求**:精确选择特定几个月份(不连续) + +**方法**: +``` +需要:1月、3月、6月、9月、12月 + +1. 输入 "202101",点击 [全选] +2. 输入 "202103",点击 [全选] +3. 输入 "202106",点击 [全选] +4. 输入 "202109",点击 [全选] +5. 输入 "202112",点击 [全选] +6. 清空筛选框查看 + → 已选中5个月份 +``` + +--- + +## 最佳实践 + +### 1. 大量集合的选择策略 + +**场景**:有100+个集合,需要选择大部分 + +**推荐流程**: +``` +1. 使用快捷筛选或全选按钮一次性选中 +2. 使用文本筛选+反选排除不需要的 +3. 清空筛选查看最终结果 +``` + +**示例**: +``` +选择2021-2023的所有数据,但排除测试月份 + +1. 点击 [2021年] +2. 点击 [2022年] +3. 点击 [2023年] + → 已选36个月 +4. 输入 "test" +5. 点击 [反选] + → 排除测试集合 +``` + +### 2. 少量集合的选择策略 + +**场景**:只需要选择几个集合 + +**推荐流程**: +``` +直接使用文本筛选+全选 +``` + +**示例**: +``` +只选择3个月 + +1. 输入 "202101",点击 [全选] +2. 输入 "202102",点击 [全选] +3. 输入 "202103",点击 [全选] +``` + +### 3. 动态时间范围 + +**场景**:需要最近的数据(随时间变化) + +**推荐**: +``` +使用 [最近N个月] 快捷按钮 +优点: +- 自动计算当前时间 +- 配置一次,永久有效 +- 不需要手动更新月份 +``` + +### 4. 固定时间范围 + +**场景**:需要特定历史时期的数据 + +**推荐**: +``` +使用年份按钮或文本筛选 +例如:统计2021年的历史数据 +→ 点击 [2021年] +``` + +--- + +## 常见场景快速指南 + +| 需求 | 最佳方法 | 步骤 | +|------|----------|------| +| 选择某一年全年数据 | 年份按钮 | 点击 `[2021年]` | +| 选择最近半年数据 | 时间范围按钮 | 点击 `[最近6个月]` | +| 选择第一季度 | 文本筛选+全选 | 输入 `Q1` 或逐月选择 | +| 选择所有zippo集合 | 文本筛选+全选 | 输入 `zippo`,点击 `[全选]` | +| 排除某几个月 | 全选+反选 | 先全选年份,再筛选排除项并反选 | +| 选择不连续月份 | 逐个筛选+全选 | 每个月份单独筛选后全选 | +| 跨年选择 | 多次年份按钮 | 点击多个年份按钮 | + +--- + +## 注意事项 + +1. **筛选不影响已选项** + - 筛选只影响显示,不会取消已选中的集合 + - 即使筛选后看不到某个已选集合,它仍然被选中 + +2. **全选是追加操作** + - 点击"全选"会追加到已选列表 + - 不会清除之前的选择 + - 如需重新开始,先点击"清空" + +3. **反选的作用域** + - 反选只对当前筛选结果生效 + - 不在筛选结果中的已选项不受影响 + +4. **快捷筛选的智能识别** + - 快捷按钮仅在检测到日期格式集合时显示 + - 如果集合命名不包含日期,不会显示这些按钮 + +5. **性能考虑** + - 选择大量集合(50+)可能影响查询性能 + - 建议根据实际需求选择合适的时间范围 + +--- + +**更新时间**:2025-01-XX +**适用版本**:QueryBuilder v2.0+ diff --git a/Moncter/提示词/项目完整代码逻辑分析报告.md b/Moncter/提示词/项目完整代码逻辑分析报告.md new file mode 100644 index 00000000..f1275446 --- /dev/null +++ b/Moncter/提示词/项目完整代码逻辑分析报告.md @@ -0,0 +1,858 @@ +# 项目完整代码逻辑分析报告 + +## 一、项目概述 + +### 1.1 项目定位 +本项目是一个**基于Webman框架的用户标签引擎和数据采集中心**,主要功能包括: +- **多数据源数据采集**:支持MongoDB、MySQL等多种数据源 +- **数据库实时同步**:使用MongoDB Change Streams实现数据库间实时同步 +- **用户标签计算引擎**:基于用户消费数据实时计算和更新标签 +- **任务配置化管理**:通过配置文件统一管理所有数据采集任务 +- **用户身份管理**:支持身份证、手机号等标识的统一管理 + +### 1.2 技术栈 +- **框架**:Webman (Workerman) - 高性能PHP框架 +- **数据库**:MongoDB (主数据库) +- **消息队列**:RabbitMQ - 异步任务处理 +- **缓存/锁**:Redis - 分布式锁、状态存储 +- **前端**:Vue 3 + TypeScript + Element Plus +- **PHP版本**:>= 8.1 + +--- + +## 二、系统架构 + +### 2.1 分层架构 + +``` +┌─────────────────────────────────────────┐ +│ 应用层 (HTTP API) │ +│ User/Tag/Task/DataSource API │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 业务服务层 (Service) │ +│ UserService / TagService / │ +│ DataCollectionTaskService / │ +│ ConsumptionService │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 数据访问层 (Repository) │ +│ UserProfile / UserTag / │ +│ ConsumptionRecord / DataCollectionTask │ +└──────────────────┬──────────────────────┘ + │ +┌──────────────────▼──────────────────────┐ +│ 数据存储层 │ +│ MongoDB / Redis / RabbitMQ │ +└─────────────────────────────────────────┘ +``` + +### 2.2 进程架构 + +系统使用Workerman多进程架构,包含以下进程: + +1. **webman (HTTP Server)** + - 处理HTTP请求 + - 进程数:CPU核心数 × 4 + +2. **monitor (文件监控)** + - 监控文件变化,自动重载 + +3. **data_sync_scheduler (数据采集任务调度器)** + - 读取任务配置(配置文件 + 数据库) + - 启动和管理所有数据采集任务 + - 进程数:10 + +4. **data_sync_worker (数据同步Worker)** + - 消费RabbitMQ消息队列 + - 写入目标数据库,更新用户统计 + - 进程数:20 + +5. **tag_calculation_worker (标签计算Worker)** + - 消费RabbitMQ标签计算队列 + - 根据用户数据计算标签值 + - 进程数:2 + +--- + +## 三、核心业务逻辑 + +### 3.1 数据采集系统 + +#### 3.1.1 任务配置体系 + +系统支持两种任务配置方式: + +**1. 配置文件方式** (`config/data_collection_tasks.php`) +```php +'tasks' => [ + 'database_sync' => [ + 'name' => '数据库实时同步', + 'source_data_source' => 'kr_mongodb', + 'target_data_source' => 'sync_mongodb', + 'handler_class' => DatabaseSyncHandler::class, + 'schedule' => ['enabled' => false], // 持续运行 + ], +] +``` + +**2. 数据库方式** (`data_collection_tasks`集合) +- 通过前端界面动态创建和管理任务 +- 支持批量采集(batch)和实时监听(realtime)两种模式 +- 支持字段映射、过滤条件、连表查询等配置 + +#### 3.1.2 任务执行流程 + +``` +用户创建任务 + ↓ +保存到MongoDB (data_collection_tasks集合) + ↓ +用户点击"启动"按钮 + ↓ +API: POST /api/data-collection-tasks/{taskId}/start + ↓ +DataCollectionTaskService->startTask() + - 更新任务状态为 'running' + - Redis设置标志: data_collection_task:{taskId}:start + ↓ +DataSyncScheduler进程检测到Redis标志 + ↓ +从数据库加载任务配置 + ↓ +根据任务模式执行: + - batch模式:根据schedule配置定时执行或立即执行 + - realtime模式:立即启动,持续运行(Change Stream监听) +``` + +#### 3.1.3 Handler处理机制 + +系统通过Handler模式实现不同类型的数据采集: + +**ConsumptionCollectionHandler** - 消费记录采集 +- 专门处理消费记录采集 +- 支持KR_商城和KR_金融两种数据源 +- 自动提取手机号、解析用户ID、写入消费记录 + +**GenericCollectionHandler** - 通用数据采集 +- 支持动态字段映射 +- 支持批量采集和实时监听两种模式 +- 支持连表查询(lookup) + +**DatabaseSyncHandler** - 数据库同步 +- 全量同步:首次启动时同步所有数据 +- 增量同步:使用MongoDB Change Streams实时监听 + +### 3.2 用户身份管理系统 + +#### 3.2.1 身份标识体系 + +系统采用**以身份证为主键,手机号为弱标识**的设计: + +1. **user_profile (用户画像表)** + - `user_id`: 用户唯一标识(UUID) + - `id_card_hash`: 身份证哈希值(用于匹配) + - `id_card_encrypted`: 加密的身份证号 + - `is_temporary`: 是否为临时人(true/false) + - `total_amount`: 总消费金额 + - `total_count`: 总消费次数 + +2. **user_phone_relations (手机号关联表)** + - `phone_number`: 手机号 + - `user_id`: 关联的用户ID + - `is_primary`: 是否为主手机号 + +#### 3.2.2 身份解析流程 + +``` +收到数据(包含手机号) + ↓ +IdentifierService->resolvePersonIdByPhone() + ↓ +查询user_phone_relations表 + ├─→ 找到 → 返回user_id + └─→ 未找到 → 创建临时人 + ├─→ 创建user_profile记录(is_temporary=true) + ├─→ 创建user_phone_relations关联 + └─→ 返回user_id +``` + +#### 3.2.3 身份合并机制 + +当发现手机号对应的身份证后: + +``` +发现身份证 + ↓ +IdentifierService->bindIdCardToPerson() + ↓ +检查身份证是否已被其他用户使用 + ├─→ 是 → 抛出异常 + └─→ 否 → 更新用户信息 + ├─→ 设置id_card_hash和id_card_encrypted + ├─→ is_temporary = false + └─→ 标记为正式人 + ↓ +PersonMergeService->mergePhoneToIdCard() + ↓ +重新计算所有标签 +``` + +### 3.3 标签计算系统 + +#### 3.3.1 标签定义 + +标签定义存储在`tag_definitions`集合中: + +```javascript +{ + tag_id: "标签ID", + tag_code: "标签代码", + tag_name: "标签名称", + rule_config: { + rule_type: "simple", + conditions: [...], + // 规则配置 + }, + update_frequency: "real_time" | "daily" | "weekly", + status: 0 // 0:启用, 1:禁用 +} +``` + +#### 3.3.2 标签计算流程 + +``` +消费记录写入 + ↓ +ConsumptionService->createRecord() + ├─→ 写入consumption_records表 + ├─→ 更新user_profile统计信息(total_amount, total_count) + └─→ 触发标签计算(异步) + ↓ + 推送到RabbitMQ队列 + ↓ + TagCalculationWorker消费消息 + ↓ + TagService->calculateTags() + ├─→ 获取用户数据 + ├─→ 获取标签定义列表 + ├─→ 遍历每个标签 + │ ├─→ 解析规则配置 + │ ├─→ SimpleRuleEngine计算标签值 + │ ├─→ 更新或创建user_tags记录 + │ └─→ 记录标签变更历史(如果值发生变化) + └─→ 返回更新的标签列表 +``` + +#### 3.3.3 规则引擎 + +系统使用`SimpleRuleEngine`计算标签值: + +```php +// 示例规则配置 +{ + "rule_type": "simple", + "conditions": [ + { + "field": "total_amount", + "operator": ">=", + "value": 1000 + } + ], + "result": { + "value": "VIP", + "confidence": 0.9 + } +} +``` + +### 3.4 消费记录处理 + +#### 3.4.1 消费记录数据结构 + +```javascript +{ + record_id: "记录ID", + user_id: "用户ID", + consume_time: "消费时间", + amount: 100.00, // 消费金额 + actual_amount: 95.00, // 实际金额 + currency: "CNY", + store_id: "店铺ID", + status: 0, + create_time: "创建时间" +} +``` + +#### 3.4.2 处理流程 + +``` +数据采集任务采集到订单数据 + ↓ +ConsumptionCollectionHandler处理 + ├─→ 提取手机号 + ├─→ 字段映射和转换 + └─→ 调用ConsumptionService->createRecord() + ↓ + IdentifierService->resolvePersonId() + ├─→ 通过手机号解析user_id + └─→ 如果不存在,创建临时人 + ↓ + 写入consumption_records表 + ↓ + UserProfileRepository->increaseStats() + ├─→ total_amount += actual_amount + ├─→ total_count += 1 + └─→ last_consume_time = consume_time + ↓ + 触发标签计算(异步) +``` + +--- + +## 四、数据存储设计 + +### 4.1 MongoDB集合 + +#### 4.1.1 用户相关集合 + +**user_profile (用户画像)** +```javascript +{ + user_id: String, // 用户唯一标识 + id_card_hash: String, // 身份证哈希 + id_card_encrypted: String, // 加密身份证 + id_card_type: String, // 身份证类型 + is_temporary: Boolean, // 是否临时人 + name: String, + phone: String, + total_amount: Number, // 总消费金额 + total_count: Number, // 总消费次数 + last_consume_time: Date, // 最后消费时间 + tags_update_time: Date, // 标签更新时间 + status: Number, + create_time: Date, + update_time: Date +} +``` + +**user_phone_relations (手机号关联)** +```javascript +{ + phone_number: String, // 手机号 + user_id: String, // 用户ID + is_primary: Boolean, // 是否为主手机号 + effective_time: Date, + expire_time: Date, + create_time: Date +} +``` + +**consumption_records (消费记录)** +```javascript +{ + record_id: String, + user_id: String, + consume_time: Date, + amount: Number, + actual_amount: Number, + currency: String, + store_id: String, + status: Number, + create_time: Date +} +``` + +#### 4.1.2 标签相关集合 + +**tag_definitions (标签定义)** +```javascript +{ + tag_id: String, + tag_code: String, + tag_name: String, + rule_config: Object, // 规则配置(JSON) + update_frequency: String, // real_time/daily/weekly + status: Number, + create_time: Date, + update_time: Date +} +``` + +**user_tags (用户标签)** +```javascript +{ + user_id: String, + tag_id: String, + tag_value: String, // 标签值 + tag_value_type: String, // 值类型 + confidence: Number, // 置信度 + effective_time: Date, + create_time: Date, + update_time: Date +} +``` + +**tag_history (标签变更历史)** +```javascript +{ + user_id: String, + tag_id: String, + old_value: String, + new_value: String, + change_time: Date +} +``` + +#### 4.1.3 任务相关集合 + +**data_collection_tasks (数据采集任务)** +```javascript +{ + task_id: String, + name: String, + data_source_id: String, + database: String, + collection: String, + target_type: String, // consumption_record/generic + handler_type: String, + mode: String, // batch/realtime + schedule: { + enabled: Boolean, + cron: String + }, + field_mappings: Array, + filter_conditions: Object, + progress: { + status: String, + processed_count: Number, + success_count: Number, + error_count: Number, + total_count: Number, + percentage: Number + }, + status: String, // pending/running/paused/stopped + create_time: Date, + update_time: Date +} +``` + +**data_sources (数据源)** +```javascript +{ + data_source_id: String, + name: String, + type: String, // mongodb/mysql + host: String, + port: Number, + database: String, + username: String, + password: String, + is_tag_engine: Boolean, // 是否为标签引擎数据库 + status: Number, + create_time: Date, + update_time: Date +} +``` + +### 4.2 Redis存储 + +#### 4.2.1 分布式锁 +- `lock:data_collection:{task_id}` - 数据采集任务锁 +- `lock:database_sync` - 数据库同步锁 + +#### 4.2.2 任务状态标志 +- `data_collection_task:{task_id}:start` - 启动标志 +- `data_collection_task:{task_id}:pause` - 暂停标志 +- `data_collection_task:{task_id}:stop` - 停止标志 + +#### 4.2.3 同步状态 +- `data_collection:{task_id}:last_sync_time` - 上次同步时间 +- `data_collection:{task_id}:last_sync_id` - 上次同步ID + +### 4.3 RabbitMQ队列 + +#### 4.3.1 数据同步队列 +- 队列名:`data_sync` +- 消息格式: +```json +{ + "user_id": "用户ID", + "data": {...}, + "action": "insert|update|delete" +} +``` + +#### 4.3.2 标签计算队列 +- 队列名:`tag_calculation` +- 消息格式: +```json +{ + "user_id": "用户ID", + "tag_ids": null, // null表示计算所有real_time标签 + "trigger_type": "consumption_record", + "record_id": "记录ID", + "timestamp": 1234567890 +} +``` + +--- + +## 五、API接口体系 + +### 5.1 用户相关接口 + +- `POST /api/users` - 创建用户 +- `GET /api/users/{user_id}` - 查询用户 +- `PUT /api/users/{user_id}` - 更新用户 +- `DELETE /api/users/{user_id}` - 删除用户 +- `POST /api/users/search` - 搜索用户(复杂查询) +- `GET /api/users/{user_id}/decrypt-id-card` - 解密身份证 + +### 5.2 标签相关接口 + +- `GET /api/users/{user_id}/tags` - 查询用户标签 +- `PUT /api/users/{user_id}/tags` - 计算/更新用户标签 +- `DELETE /api/users/{user_id}/tags/{tag_id}` - 删除用户标签 +- `POST /api/tags/filter` - 根据标签筛选用户 +- `GET /api/tags/statistics` - 获取标签统计信息 +- `GET /api/tags/history` - 获取标签历史记录 + +### 5.3 标签定义接口 + +- `GET /api/tag-definitions` - 获取标签定义列表 +- `POST /api/tag-definitions` - 创建标签定义 +- `GET /api/tag-definitions/{tag_id}` - 获取标签定义详情 +- `PUT /api/tag-definitions/{tag_id}` - 更新标签定义 +- `DELETE /api/tag-definitions/{tag_id}` - 删除标签定义 + +### 5.4 数据采集任务接口 + +- `POST /api/data-collection-tasks` - 创建任务 +- `PUT /api/data-collection-tasks/{task_id}` - 更新任务 +- `DELETE /api/data-collection-tasks/{task_id}` - 删除任务 +- `GET /api/data-collection-tasks` - 任务列表 +- `GET /api/data-collection-tasks/{task_id}` - 任务详情 +- `GET /api/data-collection-tasks/{task_id}/progress` - 任务进度 +- `POST /api/data-collection-tasks/{task_id}/start` - 启动任务 +- `POST /api/data-collection-tasks/{task_id}/pause` - 暂停任务 +- `POST /api/data-collection-tasks/{task_id}/stop` - 停止任务 + +### 5.5 数据源接口 + +- `GET /api/data-sources` - 获取数据源列表 +- `GET /api/data-sources/{data_source_id}` - 获取数据源详情 +- `POST /api/data-sources` - 创建数据源 +- `PUT /api/data-sources/{data_source_id}` - 更新数据源 +- `DELETE /api/data-sources/{data_source_id}` - 删除数据源 +- `POST /api/data-sources/test-connection` - 测试数据源连接 + +### 5.6 身份合并接口 + +- `POST /api/person-merge/phone-to-id-card` - 合并手机号到身份证 +- `POST /api/person-merge/temporary-to-formal` - 合并临时人到正式人 + +### 5.7 数据库同步接口 + +- `GET /api/database-sync/progress` - 查询同步进度 +- `GET /api/database-sync/stats` - 查询同步统计 +- `POST /api/database-sync/reset` - 重置同步进度 +- `POST /api/database-sync/skip-error` - 跳过错误数据库 + +--- + +## 六、关键设计模式 + +### 6.1 工厂模式 +- `DataSourceAdapterFactory` - 创建数据源适配器 +- `PollingStrategyFactory` - 创建轮询策略 + +### 6.2 策略模式 +- `PollingStrategyInterface` - 轮询策略接口 + - `MongoDBConsumptionStrategy` - MongoDB消费策略 + - `DefaultConsumptionStrategy` - 默认消费策略 + +### 6.3 适配器模式 +- `DataSourceAdapterInterface` - 数据源适配器接口 + - `MongoDBAdapter` - MongoDB适配器 + - `MySQLAdapter` - MySQL适配器 + +### 6.4 仓库模式 +- 所有Repository类继承MongoDB Model +- 封装数据访问逻辑 +- 提供统一的查询接口 + +### 6.5 Handler模式 +- `ConsumptionCollectionHandler` - 消费记录采集 +- `GenericCollectionHandler` - 通用数据采集 +- `DatabaseSyncHandler` - 数据库同步 + +--- + +## 七、数据流图 + +### 7.1 完整数据流 + +``` +数据源 (KR MongoDB) + ↓ +数据采集任务 (DataSyncScheduler) + ├─→ ConsumptionCollectionHandler + │ ├─→ 批量采集模式:分页查询数据 + │ └─→ 实时监听模式:Change Stream监听 + │ + └─→ DatabaseSyncHandler + ├─→ 全量同步:批量读取写入 + └─→ 增量同步:Change Stream监听 + ↓ +消费记录写入 (ConsumptionService) + ├─→ 身份解析 (IdentifierService) + │ ├─→ 手机号 → user_id + │ └─→ 如果不存在,创建临时人 + │ + ├─→ 写入consumption_records表 + ├─→ 更新user_profile统计信息 + └─→ 触发标签计算(推送到RabbitMQ) + ↓ +标签计算 (TagCalculationWorker) + ├─→ TagService->calculateTags() + ├─→ SimpleRuleEngine计算标签值 + ├─→ 更新user_tags表 + └─→ 记录tag_history变更历史 +``` + +### 7.2 任务执行时序图 + +``` +用户操作 + │ + ├─→ 创建任务 → 保存到MongoDB + │ + └─→ 启动任务 → API → DataCollectionTaskService + │ + ├─→ 更新任务状态为running + └─→ Redis设置启动标志 + │ +DataSyncScheduler进程 + │ + ├─→ 检测Redis标志 + ├─→ 从数据库加载任务配置 + ├─→ 创建数据源适配器 + ├─→ 实例化Handler + └─→ 调用Handler->collect() + │ + ├─→ 批量模式:定时执行 + └─→ 实时模式:持续运行 +``` + +--- + +## 八、关键技术实现 + +### 8.1 MongoDB Change Streams实时监听 + +```php +// 实时监听集合变更 +$changeStream = $collection->watch( + [ + ['$match' => ['operationType' => ['$in' => ['insert', 'update']]]], + ], + ['fullDocument' => 'updateLookup'] +); + +foreach ($changeStream as $change) { + // 处理变更事件 + $document = $change['fullDocument']; + // 处理数据... +} +``` + +### 8.2 分布式锁实现 + +```php +// 使用Redis实现分布式锁 +$lockKey = "lock:data_collection:{$taskId}"; +$locked = RedisHelper::setnx($lockKey, time(), 300); // TTL 300秒 + +if ($locked) { + try { + // 执行任务 + } finally { + RedisHelper::del($lockKey); + } +} +``` + +### 8.3 异步消息队列 + +```php +// 推送标签计算任务到队列 +QueueService::pushTagCalculation([ + 'user_id' => $userId, + 'tag_ids' => null, + 'trigger_type' => 'consumption_record', + 'record_id' => $recordId, +]); + +// Worker消费队列 +$message = $channel->basic_get('tag_calculation'); +if ($message) { + $data = json_decode($message->body, true); + $tagService->calculateTags($data['user_id']); + $channel->basic_ack($message->delivery_info['delivery_tag']); +} +``` + +### 8.4 身份证加密存储 + +```php +// 加密存储 +$idCardEncrypted = EncryptionHelper::encrypt($idCard); +$idCardHash = EncryptionHelper::hash($idCard); // 用于匹配 + +// 解密读取(需要权限) +$idCard = EncryptionHelper::decrypt($idCardEncrypted); +``` + +--- + +## 九、系统特性 + +### 9.1 配置化设计 +- 数据源配置统一管理 +- 任务配置支持配置文件和数据库两种方式 +- 业务逻辑与配置分离 + +### 9.2 高可用性 +- 多进程架构,提高并发能力 +- 分布式锁防止任务重复执行 +- 错误重试机制 +- 断点续传支持 + +### 9.3 可扩展性 +- Handler模式易于添加新的采集任务 +- 适配器模式易于支持新的数据源类型 +- 策略模式易于扩展业务逻辑 + +### 9.4 可观测性 +- 完善的日志系统(业务日志、错误日志、性能日志) +- 实时进度跟踪 +- API接口提供进度和统计查询 + +### 9.5 数据安全性 +- 身份证加密存储 +- 支持数据脱敏 +- 日志脱敏处理 + +--- + +## 十、前端架构 + +### 10.1 技术栈 +- Vue 3 + TypeScript +- Element Plus (UI组件库) +- Pinia (状态管理) +- Vue Router (路由) +- Axios (HTTP请求) +- Vite (构建工具) + +### 10.2 主要功能模块 + +1. **数据采集任务管理** + - 任务列表、创建、编辑、删除 + - 任务启动、暂停、停止 + - 任务进度查看 + - 数据源选择、数据库/集合选择 + - 字段映射配置 + +2. **标签管理** + - 标签定义管理 + - 用户标签查看 + - 标签筛选功能 + +3. **数据源管理** + - 数据源列表、创建、编辑、删除 + - 连接测试 + +--- + +## 十一、总结 + +### 11.1 系统核心价值 + +1. **统一的数据采集中心** + - 支持多种数据源 + - 支持批量采集和实时监听 + - 配置化管理,易于扩展 + +2. **智能的用户标签引擎** + - 基于规则引擎自动计算标签 + - 支持实时更新和定时更新 + - 标签变更历史追踪 + +3. **灵活的身份管理体系** + - 支持身份证、手机号等多种标识 + - 临时人机制 + - 身份合并功能 + +### 11.2 系统优势 + +- ✅ **高性能**:基于Workerman多进程架构 +- ✅ **高可用**:分布式锁、错误重试、断点续传 +- ✅ **易扩展**:配置化、组件化设计 +- ✅ **可观测**:完善的日志和监控 +- ✅ **安全**:数据加密、权限控制 + +### 11.3 系统流程总结 + +**核心流程:数据源 → 采集任务 → 消息队列 → 数据同步 → 标签计算 → 存储** + +1. 数据采集:从多个数据源采集数据 +2. 身份解析:根据手机号/身份证解析用户ID +3. 数据存储:写入消费记录,更新用户统计 +4. 标签计算:基于用户数据计算标签值 +5. 标签应用:支持标签筛选、人群分析等应用场景 + +--- + +## 十二、扩展建议 + +### 12.1 功能扩展 + +1. **定时批量标签更新** + - 支持daily/weekly频率的标签批量更新 + - 添加定时任务配置 + +2. **标签血缘关系** + - 追踪标签来源和数据血缘 + - 标签影响分析 + +3. **人群分析功能** + - 基于标签的人群分群 + - 人群画像分析 + +4. **数据质量监控** + - 数据采集质量监控 + - 异常数据告警 + +### 12.2 性能优化 + +1. **批量处理优化** + - 增加批量大小 + - 优化数据库查询 + +2. **缓存优化** + - 标签定义缓存 + - 用户数据缓存 + +3. **分片策略优化** + - 按时间分片 + - 按数据库分片 + +--- + +**报告生成时间**: 2025-12-26 +**项目版本**: 基于当前代码库分析 +