Kaynağa Gözat

修改重复记录处理功能,添加重复记录处理表
修改查找重复记录的ID对应关系
添加删除重复记录功能
添加删除名片记录

maxiaolong 3 hafta önce
ebeveyn
işleme
393e012661

+ 0 - 261
API_DOCUMENTATION_DUPLICATE_RECORDS.md

@@ -1,261 +0,0 @@
-# 重复记录处理API文档
-
-## 概述
-
-本文档描述了DataOps平台中用于处理名片重复记录的API接口。当系统检测到新上传的名片可能与现有记录重复时,会创建重复记录条目供管理员处理。
-
-## API接口列表
-
-### 1. 获取重复记录列表
-
-**接口地址**: `GET /api/data-parse/get-duplicate-records`
-
-**查询参数**:
-- `status` (可选): 筛选特定状态的记录
-  - `pending`: 待处理
-  - `processed`: 已处理
-  - `ignored`: 已忽略
-
-**请求示例**:
-```bash
-# 获取所有重复记录
-GET /api/data-parse/get-duplicate-records
-
-# 获取待处理的重复记录
-GET /api/data-parse/get-duplicate-records?status=pending
-```
-
-**响应示例**:
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "获取重复记录列表成功",
-  "count": 2,
-  "data": [
-    {
-      "id": 1,
-      "main_card_id": 123,
-      "suspected_duplicates": [
-        {
-          "id": 101,
-          "name_zh": "张三",
-          "mobile": "13812345678",
-          "hotel_zh": "北京丽思卡尔顿酒店",
-          "title_zh": "总监",
-          "created_at": "2024-01-15 10:30:00"
-        }
-      ],
-      "duplicate_reason": "姓名相同但手机号码不同:张三,新手机号:13987654321",
-      "processing_status": "pending",
-      "created_at": "2024-01-16 09:15:00",
-      "main_card": {
-        "id": 123,
-        "name_zh": "张三",
-        "mobile": "13987654321",
-        "hotel_zh": "上海丽思卡尔顿酒店",
-        "title_zh": "总经理",
-        "image_path": "abc123def456.jpg"
-      }
-    }
-  ]
-}
-```
-
-### 2. 处理重复记录
-
-**接口地址**: `POST /api/data-parse/process-duplicate-record/<duplicate_id>`
-
-**路径参数**:
-- `duplicate_id`: 重复记录ID
-
-**请求参数**:
-```json
-{
-  "action": "merge_to_suspected|keep_main|ignore",
-  "selected_duplicate_id": 101,  // 当action为merge_to_suspected时必填
-  "processed_by": "admin",       // 可选
-  "notes": "确认为同一人,合并记录"  // 可选
-}
-```
-
-**处理动作说明**:
-- `merge_to_suspected`: 合并到选中的疑似重复记录,删除主记录
-- `keep_main`: 保留主记录,标记为已处理
-- `ignore`: 忽略重复提醒,标记为已处理
-
-**请求示例**:
-```bash
-POST /api/data-parse/process-duplicate-record/1
-Content-Type: application/json
-
-{
-  "action": "merge_to_suspected",
-  "selected_duplicate_id": 101,
-  "processed_by": "admin",
-  "notes": "确认为同一人,职位有升职,合并到原记录"
-}
-```
-
-**响应示例**:
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "重复记录处理成功,操作: merge_to_suspected",
-  "data": {
-    "duplicate_record": {
-      "id": 1,
-      "processing_status": "processed",
-      "processed_at": "2024-01-16 14:30:00",
-      "processed_by": "admin",
-      "processing_notes": "确认为同一人,职位有升职,合并到原记录"
-    },
-    "result": {
-      "id": 101,
-      "name_zh": "张三",
-      "mobile": "13987654321",
-      "hotel_zh": "上海丽思卡尔顿酒店",
-      "title_zh": "总经理",
-      "image_path": "abc123def456.jpg",
-      "career_path": [
-        {
-          "date": "2024-01-15",
-          "hotel_zh": "北京丽思卡尔顿酒店",
-          "title_zh": "总监",
-          "image_path": "old123image456.jpg",
-          "source": "business_card_creation"
-        },
-        {
-          "date": "2024-01-16",
-          "hotel_zh": "上海丽思卡尔顿酒店",
-          "title_zh": "总经理",
-          "image_path": "abc123def456.jpg",
-          "source": "business_card_update"
-        }
-      ]
-    }
-  }
-}
-```
-
-### 3. 获取重复记录详情
-
-**接口地址**: `GET /api/data-parse/get-duplicate-record-detail/<duplicate_id>`
-
-**路径参数**:
-- `duplicate_id`: 重复记录ID
-
-**请求示例**:
-```bash
-GET /api/data-parse/get-duplicate-record-detail/1
-```
-
-**响应示例**:
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "获取重复记录详情成功",
-  "data": {
-    "id": 1,
-    "main_card_id": 123,
-    "suspected_duplicates": [
-      {
-        "id": 101,
-        "name_zh": "张三",
-        "name_en": "John Zhang",
-        "mobile": "13812345678",
-        "hotel_zh": "北京丽思卡尔顿酒店",
-        "hotel_en": "The Ritz-Carlton Beijing",
-        "title_zh": "总监",
-        "title_en": "Director",
-        "created_at": "2024-01-15 10:30:00"
-      }
-    ],
-    "duplicate_reason": "姓名相同但手机号码不同:张三,新手机号:13987654321",
-    "processing_status": "pending",
-    "created_at": "2024-01-16 09:15:00",
-    "main_card": {
-      "id": 123,
-      "name_zh": "张三",
-      "name_en": "John Zhang",
-      "mobile": "13987654321",
-      "hotel_zh": "上海丽思卡尔顿酒店",
-      "hotel_en": "The Ritz-Carlton Shanghai",
-      "title_zh": "总经理",
-      "title_en": "General Manager",
-      "image_path": "abc123def456.jpg",
-      "career_path": [
-        {
-          "date": "2024-01-16",
-          "hotel_zh": "上海丽思卡尔顿酒店",
-          "hotel_en": "The Ritz-Carlton Shanghai",
-          "title_zh": "总经理",
-          "title_en": "General Manager",
-          "image_path": "abc123def456.jpg",
-          "source": "business_card_creation"
-        }
-      ]
-    }
-  }
-}
-```
-
-## 业务流程
-
-### 1. 重复记录检测流程
-
-```mermaid
-graph TD
-    A[上传新名片] --> B[AI解析名片信息]
-    B --> C[检查重复记录]
-    C --> D{是否发现重复?}
-    D -->|否| E[创建新记录]
-    D -->|是| F{姓名和手机号都相同?}
-    F -->|是| G[自动更新现有记录]
-    F -->|否| H[创建主记录 + 重复记录条目]
-    H --> I[等待管理员处理]
-```
-
-### 2. 重复记录处理流程
-
-```mermaid
-graph TD
-    A[管理员查看重复记录] --> B[选择处理方式]
-    B --> C{处理动作}
-    C -->|merge_to_suspected| D[合并到疑似重复记录]
-    C -->|keep_main| E[保留主记录]
-    C -->|ignore| F[忽略重复提醒]
-    D --> G[更新目标记录信息]
-    G --> H[添加职业轨迹条目]
-    H --> I[删除主记录]
-    E --> J[标记为已处理]
-    F --> J
-    I --> K[完成处理]
-    J --> K
-```
-
-## 错误码说明
-
-| HTTP状态码 | 错误码 | 说明 |
-|-----------|--------|------|
-| 200 | 200 | 操作成功 |
-| 400 | 400 | 请求参数错误 |
-| 404 | 404 | 记录不存在 |
-| 500 | 500 | 服务器内部错误 |
-
-## 注意事项
-
-1. **权限控制**: 重复记录处理操作建议仅对管理员开放
-2. **数据一致性**: 合并操作会删除主记录,请确保操作前数据备份
-3. **图片路径**: 合并后的记录会使用最新的名片图片路径
-4. **职业轨迹**: 合并操作会自动更新职业轨迹,包含对应的图片路径
-5. **处理状态**: 一旦处理状态改为`processed`,记录不能再次处理
-
-## 使用建议
-
-1. **定期检查**: 建议定期查看待处理的重复记录
-2. **谨慎合并**: 合并操作不可逆,请仔细核对信息再操作
-3. **添加备注**: 建议在处理时添加详细的处理备注便于追溯
-4. **批量处理**: 可以通过脚本批量处理大量重复记录 

+ 0 - 63
CHANGELOG.md

@@ -1,63 +0,0 @@
-# 更新日志
-
-本文档记录DataOps平台的所有重要变更。
-
-## [未发布]
-
-### 新增
-- 创建了初始项目结构
-- 添加了README.md文件
-
-### 修改
-- 尚无
-
-### 修复
-- 尚无
-
-## [0.1.0] - 2024-03-20
-
-### 新增
-- 初始化Flask应用结构
-- 创建了基本API蓝图:
-  - 元数据管理 (meta_data)
-  - 数据资源管理 (data_resource)
-  - 数据模型管理 (data_model)
-  - 数据接口管理 (data_interface)
-  - 数据指标管理 (data_metric)
-  - 生产线流程管理 (production_line)
-  - 图形化数据 (graph)
-  - 系统管理 (system)
-- 配置了日志系统
-- 配置了CORS支持
-- 添加了SQLAlchemy数据库连接
-
-### 修改
-- 优化了API路由结构,使用更简洁的前缀
-
-### 修复
-- 尚无
-
-## 格式说明
-
-变更记录格式如下:
-
-```
-## [版本号] - 发布日期
-
-### 新增
-- 新增的功能或文件
-
-### 修改
-- 修改的功能或文件
-
-### 修复
-- 修复的问题或缺陷
-
-### 移除
-- 移除的功能或文件
-```
-
-记录时请注明具体的修改内容,例如:
-- 修改了`app/services/data_service.py`中的`process_data`函数,增加了数据验证
-- 添加了`app/utils/validators.py`文件,实现数据验证功能
-- 修复了数据导入时的编码问题 

+ 0 - 204
README_hotel_positions.md

@@ -1,204 +0,0 @@
-# 酒店职位名称数据表
-
-## 概述
-
-本项目基于 `酒店职位名称20250519.xlsx` 文件中的"汇总版"sheet,创建了标准化的酒店职位数据表。该表包含了酒店行业的标准部门和职位信息,可用于人力资源管理、组织架构设计等用途。
-
-## 数据统计
-
-- **总记录数**: 150条
-- **部门数量**: 9个
-- **职位数量**: 144个不同职位
-- **职级分类**: 3个级别
-
-### 部门分布
-| 部门 | 职位数量 |
-|------|----------|
-| 餐饮部 | 61 |
-| 房务部 | 23 |
-| 市场销售部 | 17 |
-| 人力资源部 | 13 |
-| 财务部 | 13 |
-| 行政办公室 | 8 |
-| 工程部 | 8 |
-| 水疗部 | 4 |
-| 保安部 | 3 |
-
-### 职级分布
-| 职级 | 职位数量 | 占比 |
-|------|----------|------|
-| 经理级 | 120 | 80% |
-| 总监级 | 23 | 15.3% |
-| 总经理级 | 7 | 4.7% |
-
-## 文件说明
-
-### 1. `hotel_positions_ddl.sql`
-PostgreSQL数据库表创建脚本,包含:
-
-- **表结构定义**: 包含所有必要字段和约束
-- **索引创建**: 优化查询性能的索引
-- **中文注释**: 详细的字段和表注释
-- **触发器**: 自动更新`updated_at`字段
-- **统计视图**: 部门和职级统计视图
-- **示例查询**: 常用查询语句示例
-
-### 2. `import_hotel_positions.py`
-数据导入脚本,功能包括:
-
-- 从Excel文件读取数据
-- 数据清理和格式化
-- 批量导入PostgreSQL数据库
-- 导入结果验证和统计
-
-### 3. `read_excel.py` 和 `analyze_more.py`
-数据分析脚本,用于:
-
-- 分析Excel文件结构
-- 统计数据分布
-- 验证数据质量
-
-## 使用方法
-
-### 第一步:创建数据库表
-
-```bash
-# 连接到PostgreSQL数据库
-psql -h localhost -U your_username -d your_database
-
-# 执行DDL脚本
-\i hotel_positions_ddl.sql
-```
-
-### 第二步:导入数据
-
-1. 修改 `import_hotel_positions.py` 中的数据库连接参数:
-
-```python
-connection_params = {
-    'host': 'your_host',
-    'port': 5432,
-    'database': 'your_database_name',
-    'user': 'your_username',
-    'password': 'your_password'
-}
-```
-
-2. 确保Excel文件在当前目录下
-
-3. 运行导入脚本:
-
-```bash
-python import_hotel_positions.py
-```
-
-### 第三步:验证数据
-
-```sql
--- 查看数据总数
-SELECT COUNT(*) FROM hotel_positions;
-
--- 查看部门统计
-SELECT * FROM v_hotel_positions_dept_stats;
-
--- 查看职级统计
-SELECT * FROM v_hotel_positions_level_stats;
-```
-
-## 表结构
-
-### 主要字段
-
-| 字段名 | 类型 | 描述 |
-|--------|------|------|
-| `id` | SERIAL | 主键ID |
-| `sequence_no` | INTEGER | 原Excel序号 |
-| `department_zh` | VARCHAR(10) | 部门中文名称 |
-| `department_en` | VARCHAR(50) | 部门英文名称 |
-| `position_zh` | VARCHAR(20) | 职位中文名称 |
-| `position_en` | VARCHAR(100) | 职位英文名称 |
-| `position_abbr` | VARCHAR(20) | 职位英文缩写(可为空) |
-| `level_zh` | VARCHAR(10) | 职级中文名称 |
-| `level_en` | VARCHAR(30) | 职级英文名称 |
-
-### 审计字段
-
-| 字段名 | 类型 | 描述 |
-|--------|------|------|
-| `created_at` | TIMESTAMP WITH TIME ZONE | 创建时间 |
-| `updated_at` | TIMESTAMP WITH TIME ZONE | 更新时间 |
-| `created_by` | VARCHAR(50) | 创建者 |
-| `updated_by` | VARCHAR(50) | 更新者 |
-| `status` | VARCHAR(20) | 记录状态 |
-
-## 常用查询示例
-
-### 1. 查询特定部门的所有职位
-
-```sql
-SELECT position_zh, position_en, level_zh 
-FROM hotel_positions 
-WHERE department_zh = '餐饮部' AND status = 'active'
-ORDER BY sequence_no;
-```
-
-### 2. 查询高级职位(总监级及以上)
-
-```sql
-SELECT department_zh, position_zh, position_en, level_zh
-FROM hotel_positions 
-WHERE level_zh IN ('总监级', '总经理级') AND status = 'active'
-ORDER BY level_zh DESC, department_zh;
-```
-
-### 3. 查询有英文缩写的职位
-
-```sql
-SELECT department_zh, position_zh, position_en, position_abbr
-FROM hotel_positions 
-WHERE position_abbr IS NOT NULL AND position_abbr != '' 
-  AND status = 'active'
-ORDER BY department_zh;
-```
-
-### 4. 部门职位数量统计
-
-```sql
-SELECT * FROM v_hotel_positions_dept_stats;
-```
-
-### 5. 职级分布统计
-
-```sql
-SELECT * FROM v_hotel_positions_level_stats;
-```
-
-## 维护说明
-
-1. **数据更新**: 当有新的职位或组织结构变化时,更新相应记录的`status`字段
-2. **版本管理**: 建议保留历史数据,通过`status`字段区分有效/无效记录
-3. **定期同步**: 与HR系统定期同步,保持数据一致性
-4. **备份**: 定期备份数据表,确保数据安全
-
-## 依赖要求
-
-### Python环境
-```bash
-pip install pandas openpyxl psycopg2-binary
-```
-
-### PostgreSQL版本
-- PostgreSQL 10.0 或更高版本
-- 支持`COMMENT ON`语句
-- 支持触发器和函数
-
-## 注意事项
-
-1. **字符编码**: 确保数据库和客户端使用UTF-8编码
-2. **空值处理**: `position_abbr`字段允许为空,其他字段均为必填
-3. **索引优化**: 已创建常用查询的索引,如需其他查询模式可添加相应索引
-4. **数据完整性**: 建议添加外键约束连接到其他相关表
-
-## 支持与反馈
-
-如有问题或建议,请联系系统管理员或提交issue。 

+ 0 - 237
api-query-kg.md

@@ -1,237 +0,0 @@
-# 知识图谱查询 API 文档
-
-## API 接口: `/query-kg`
-
-该 API 接口允许您使用自然语言查询知识图谱数据库。它利用 Deepseek API 将您的查询需求转换为 Cypher 脚本,并在 Neo4j 数据库上执行。
-
-### 请求详情
-
-- **请求方法**: POST
-- **URL**: `/api/data_parse/query-kg`
-- **Content-Type**: application/json
-
-### 请求参数
-
-| 参数名 | 类型 | 是否必需 | 描述 |
-|-------|------|----------|------|
-| `query_requirement` | 字符串 | 是 | 对要从知识图谱中查询信息的自然语言描述 |
-
-#### 请求体示例
-```json
-{
-  "query_requirement": "查找所有在上海的五星级酒店担任总经理职位的人才"
-}
-```
-
-### 响应格式
-
-API 返回具有以下结构的 JSON 对象:
-
-| 字段 | 类型 | 描述 |
-|-----|------|------|
-| `code` | 整数 | HTTP 状态码(200 表示成功,4xx/5xx 表示错误)|
-| `success` | 布尔值 | 操作是否成功 |
-| `message` | 字符串 | 结果描述或错误信息 |
-| `query` | 字符串 | 执行的 Cypher 查询语句(供参考)|
-| `data` | 数组 | 包含查询结果的对象数组 |
-
-#### 成功响应示例
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "查询成功执行",
-  "query": "MATCH (t:talent)-[r:WORKS_FOR]->(h:hotel) WHERE r.title_zh CONTAINS '总经理' AND h.hotel_zh CONTAINS '上海' RETURN t.name_zh as 姓名, t.email as 邮箱, r.title_zh as 职位, h.hotel_zh as 酒店名称 ORDER BY h.hotel_zh",
-  "data": [
-    {
-      "姓名": "张三",
-      "邮箱": "zhang@example.com",
-      "职位": "总经理",
-      "酒店名称": "上海四季酒店"
-    },
-    {
-      "姓名": "李四",
-      "邮箱": "li@example.com",
-      "职位": "执行总经理",
-      "酒店名称": "上海浦东丽思卡尔顿酒店"
-    }
-  ]
-}
-```
-
-#### 错误响应示例
-```json
-{
-  "code": 400,
-  "success": false,
-  "message": "请求数据为空或缺少query_requirement字段",
-  "data": []
-}
-```
-
-### 响应状态码
-
-| 状态码 | 描述 |
-|-------|------|
-| 200 | 请求成功 |
-| 400 | 错误请求(缺少或无效参数)|
-| 500 | 服务器错误(处理错误或数据库连接失败)|
-
-### 错误处理
-
-如果发生错误,响应将包括:
-- 非 200 状态码
-- `success` 设置为 `false`
-- 描述性错误信息
-- 空的 `data` 数组
-
-## 知识图谱结构
-
-该 API 与包含以下节点和关系的知识图谱交互:
-
-### 节点
-1. **talent** - 人才节点
-   - 属性: `pg_id`, `name_zh`, `name_en`, `mobile`, `email`, `updated_at`
-
-2. **hotel** - 酒店节点
-   - 属性: `hotel_zh`, `hotel_en`, `updated_at`
-
-3. **talent_tag** - 人才标签节点
-   - 属性: `name`, `category`, `en_name`
-
-4. **hotel_tag** - 酒店标签节点
-   - 属性: `name`, `category`, `en_name`
-
-5. **brand_group** - 品牌集团节点
-   - 属性: `name`, `en_name`
-
-### 关系
-1. **WORKS_FOR** - 工作关系 (人才在酒店工作)
-   - `(talent)-[WORKS_FOR]->(hotel)`
-   - 属性: `title_zh`, `title_en`, `updated_at`
-
-2. **BELONGS_TO** - 从属关系
-   - `(talent)-[BELONGS_TO]->(talent_tag)` - 人才属于某标签
-   - `(hotel)-[BELONGS_TO]->(hotel_tag)` - 酒店属于某标签
-   - `(hotel)-[BELONGS_TO]->(brand_group)` - 酒店属于某品牌集团
-
-## 前端集成示例
-
-```javascript
-// 使用 Axios 的 Vue.js 示例
-import axios from 'axios';
-
-export default {
-  data() {
-    return {
-      queryInput: '',
-      queryResults: [],
-      isLoading: false,
-      error: null
-    }
-  },
-  methods: {
-    async queryKnowledgeGraph() {
-      this.isLoading = true;
-      this.error = null;
-      
-      try {
-        const response = await axios.post('/api/data_parse/query-kg', {
-          query_requirement: this.queryInput
-        });
-        
-        if (response.data.success) {
-          this.queryResults = response.data.data;
-        } else {
-          this.error = response.data.message;
-        }
-      } catch (error) {
-        this.error = error.response?.data?.message || '查询失败,请稍后重试';
-      } finally {
-        this.isLoading = false;
-      }
-    }
-  }
-}
-```
-
-```html
-<!-- Vue.js 模板示例 -->
-<template>
-  <div class="knowledge-graph-query">
-    <h2>知识图谱查询</h2>
-    
-    <div class="query-input">
-      <textarea 
-        v-model="queryInput"
-        placeholder="请输入查询需求,例如:查找所有在上海的五星级酒店担任总经理职位的人才"
-        rows="3"
-      ></textarea>
-      <button 
-        @click="queryKnowledgeGraph" 
-        :disabled="isLoading || !queryInput"
-      >
-        {{ isLoading ? '查询中...' : '查询' }}
-      </button>
-    </div>
-    
-    <div v-if="error" class="error-message">
-      {{ error }}
-    </div>
-    
-    <div v-if="queryResults.length > 0" class="results-table">
-      <table>
-        <thead>
-          <tr>
-            <th v-for="(value, key) in queryResults[0]" :key="key">{{ key }}</th>
-          </tr>
-        </thead>
-        <tbody>
-          <tr v-for="(item, index) in queryResults" :key="index">
-            <td v-for="(value, key) in item" :key="`${index}-${key}`">{{ value }}</td>
-          </tr>
-        </tbody>
-      </table>
-    </div>
-    
-    <div v-else-if="!isLoading && !error" class="no-results">
-      还没有查询结果,请输入查询需求并点击查询按钮
-    </div>
-  </div>
-</template>
-```
-
-## 查询示例
-
-以下是一些可以使用的查询示例:
-
-1. 查找特定酒店的所有员工:
-   ```
-   查找在上海四季酒店工作的所有人才及其职位
-   ```
-
-2. 查找特定职位的人才:
-   ```
-   查找所有担任总经理或执行总经理职位的人才及其所在酒店
-   ```
-
-3. 按标签查找人才:
-   ```
-   查找拥有"市场营销"标签的所有人才
-   ```
-
-4. 查找特定品牌集团的酒店:
-   ```
-   查找属于希尔顿集团的所有酒店
-   ```
-
-5. 复杂关系查询:
-   ```
-   查找在上海的酒店工作并且同时拥有"领导力"和"酒店管理"标签的人才
-   ```
-
-## 注意事项
-
-- 查询结果格式取决于生成的Cypher脚本,列名将根据查询内容动态生成
-- 复杂查询可能需要更详细的描述以生成准确的Cypher脚本
-- 查询结果默认没有分页,如需处理大量数据,请在查询中指明限制条件 

+ 0 - 338
api-talent-tags.md

@@ -1,338 +0,0 @@
-# 人才标签管理 API 文档
-
-本文档描述了与人才标签关系管理相关的 API 接口,包括获取人才标签和更新人才标签关系。
-
-## API 接口: `/talent-get-tags/{talent_id}`
-
-该 API 接口允许您根据人才 ID 获取关联的标签信息。
-
-### 请求详情
-
-- **请求方法**: GET
-- **URL**: `/api/data_parse/talent-get-tags/{talent_id}`
-- **Content-Type**: application/json
-
-### 路径参数
-
-| 参数名 | 类型 | 是否必需 | 描述 |
-|-------|------|----------|------|
-| `talent_id` | 整数 | 是 | 人才节点在 Neo4j 数据库中的 ID |
-
-#### 请求示例
-```
-GET /api/data_parse/talent-get-tags/12345
-```
-
-### 响应格式
-
-API 返回具有以下结构的 JSON 对象:
-
-| 字段 | 类型 | 描述 |
-|-----|------|------|
-| `code` | 整数 | HTTP 状态码(200 表示成功,4xx/5xx 表示错误)|
-| `success` | 布尔值 | 操作是否成功 |
-| `message` | 字符串 | 结果描述或错误信息 |
-| `data` | 数组 | 包含人才标签关系的对象数组 |
-
-#### 成功响应示例
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "获取人才标签成功",
-  "data": [
-    {
-      "talent": 12345,
-      "tag": "市场营销"
-    },
-    {
-      "talent": 12345,
-      "tag": "酒店管理"
-    }
-  ]
-}
-```
-
-#### 错误响应示例
-```json
-{
-  "code": 500,
-  "success": false,
-  "message": "获取人才标签失败: 人才节点ID 12345 不存在",
-  "data": []
-}
-```
-
-### 响应状态码
-
-| 状态码 | 描述 |
-|-------|------|
-| 200 | 请求成功 |
-| 500 | 服务器错误(处理错误或数据库连接失败)|
-
-### 错误处理
-
-如果发生错误,响应将包括:
-- 非 200 状态码
-- `success` 设置为 `false`
-- 描述性错误信息
-- 空的 `data` 数组
-
-
-## API 接口: `/talent-update-tags`
-
-该 API 接口允许您创建或更新人才与标签之间的关系。如果指定的标签不存在,系统会自动创建标签节点。
-
-### 请求详情
-
-- **请求方法**: POST
-- **URL**: `/api/data_parse/talent-update-tags`
-- **Content-Type**: application/json
-
-### 请求参数
-
-请求体应为 JSON 数组,包含多个对象,每个对象指定一个人才与标签的关系:
-
-| 字段 | 类型 | 是否必需 | 描述 |
-|-----|------|----------|------|
-| `talent` | 整数 | 是 | 人才节点在 Neo4j 数据库中的 ID |
-| `tag` | 字符串 | 是 | 标签名称 |
-
-#### 请求体示例
-```json
-[
-  {"talent": 12345, "tag": "市场营销"},
-  {"talent": 12345, "tag": "酒店管理"},
-  {"talent": 67890, "tag": "领导力"}
-]
-```
-
-### 响应格式
-
-API 返回具有以下结构的 JSON 对象:
-
-| 字段 | 类型 | 描述 |
-|-----|------|------|
-| `code` | 整数 | HTTP 状态码(200 表示成功,206 表示部分成功,4xx/5xx 表示错误)|
-| `success` | 布尔值 | 操作是否成功 |
-| `message` | 字符串 | 结果描述或错误信息 |
-| `data` | 对象 | 包含成功和失败信息的详细数据 |
-
-#### 成功响应示例
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "成功创建或更新了 3 个标签关系",
-  "data": {
-    "success_count": 3,
-    "total_count": 3,
-    "failed_items": []
-  }
-}
-```
-
-#### 部分成功响应示例
-```json
-{
-  "code": 206,
-  "success": true,
-  "message": "部分成功: 创建或更新了 2/3 个标签关系",
-  "data": {
-    "success_count": 2,
-    "total_count": 3,
-    "failed_items": [
-      {"talent": 67890, "tag": "领导力"}
-    ]
-  }
-}
-```
-
-#### 错误响应示例
-```json
-{
-  "code": 400,
-  "success": false,
-  "message": "参数格式错误,需要JSON数组",
-  "data": null
-}
-```
-
-### 响应状态码
-
-| 状态码 | 描述 |
-|-------|------|
-| 200 | 请求完全成功 |
-| 206 | 部分内容(部分更新成功,部分失败)|
-| 400 | 错误请求(缺少或无效参数)|
-| 404 | 未找到(指定的人才节点不存在)|
-| 500 | 服务器错误(处理错误或数据库连接失败)|
-
-### 错误处理
-
-如果发生错误,响应将包括:
-- 相应的状态码
-- `success` 设置为 `false`(对于完全失败的情况)
-- 描述性错误信息
-- 失败项目的详细信息(对于部分成功的情况)
-
-## 前端集成示例
-
-### 获取人才标签
-
-```javascript
-// 使用 Axios 的 Vue.js 示例
-import axios from 'axios';
-
-export default {
-  data() {
-    return {
-      talentId: null,
-      talentTags: [],
-      isLoading: false,
-      error: null
-    }
-  },
-  methods: {
-    async fetchTalentTags(talentId) {
-      this.isLoading = true;
-      this.error = null;
-      
-      try {
-        const response = await axios.get(`/api/data_parse/talent-get-tags/${talentId}`);
-        
-        if (response.data.success) {
-          this.talentTags = response.data.data;
-        } else {
-          this.error = response.data.message;
-        }
-      } catch (error) {
-        this.error = error.response?.data?.message || '获取标签失败,请稍后重试';
-      } finally {
-        this.isLoading = false;
-      }
-    }
-  }
-}
-```
-
-### 更新人才标签
-
-```javascript
-// 使用 Axios 的 Vue.js 示例
-import axios from 'axios';
-
-export default {
-  data() {
-    return {
-      talentTagsData: [
-        {talent: 12345, tag: "市场营销"},
-        {talent: 12345, tag: "酒店管理"}
-      ],
-      isUpdating: false,
-      updateResult: null,
-      error: null
-    }
-  },
-  methods: {
-    async updateTalentTags() {
-      this.isUpdating = true;
-      this.error = null;
-      this.updateResult = null;
-      
-      try {
-        const response = await axios.post('/api/data_parse/talent-update-tags', this.talentTagsData);
-        
-        this.updateResult = {
-          success: response.data.success,
-          message: response.data.message,
-          details: response.data.data
-        };
-      } catch (error) {
-        this.error = error.response?.data?.message || '更新标签失败,请稍后重试';
-      } finally {
-        this.isUpdating = false;
-      }
-    }
-  }
-}
-```
-
-```html
-<!-- Vue.js 模板示例:更新人才标签 -->
-<template>
-  <div class="talent-tags-update">
-    <h2>更新人才标签</h2>
-    
-    <div class="tag-input-form">
-      <div v-for="(item, index) in talentTagsData" :key="index" class="tag-input-row">
-        <div class="form-group">
-          <label>人才 ID:</label>
-          <input type="number" v-model.number="item.talent" />
-        </div>
-        <div class="form-group">
-          <label>标签名称:</label>
-          <input type="text" v-model="item.tag" />
-        </div>
-        <button @click="removeTag(index)" class="remove-btn">删除</button>
-      </div>
-      
-      <button @click="addTagRow" class="add-btn">添加标签</button>
-      <button 
-        @click="updateTalentTags" 
-        :disabled="isUpdating || !isValidData"
-        class="submit-btn"
-      >
-        {{ isUpdating ? '更新中...' : '提交更新' }}
-      </button>
-    </div>
-    
-    <div v-if="error" class="error-message">
-      {{ error }}
-    </div>
-    
-    <div v-if="updateResult" class="result-summary">
-      <h3>更新结果</h3>
-      <p :class="{'success': updateResult.success, 'partial': updateResult.success && updateResult.details?.failed_items?.length > 0}">
-        {{ updateResult.message }}
-      </p>
-      
-      <div v-if="updateResult.details?.failed_items?.length > 0" class="failed-items">
-        <h4>失败项目:</h4>
-        <ul>
-          <li v-for="(item, index) in updateResult.details.failed_items" :key="index">
-            人才 ID: {{ item.talent }}, 标签: {{ item.tag }}
-          </li>
-        </ul>
-      </div>
-    </div>
-  </div>
-</template>
-```
-
-## 使用场景示例
-
-### 场景一:获取人才标签
-
-1. 展示人才详情页面时,获取该人才的所有标签
-2. 根据获取的标签展示标签云或标签列表
-3. 让用户了解人才的专业领域和特长
-
-### 场景二:批量更新人才标签
-
-1. 人力资源部门根据人才评估结果为多个人才分配标签
-2. 在人才管理系统中,为选定的人才添加或更新专业能力标签
-3. 在知识图谱维护工具中,批量创建人才与标签的关联关系
-
-### 场景三:人才分类管理
-
-1. 先通过标签接口获取人才现有标签
-2. 根据业务需求调整和更新人才标签
-3. 利用更新后的标签体系进行人才筛选和分类
-
-## 注意事项
-
-- 更新操作使用 MERGE 语句,如果关系已存在则更新,不存在则创建
-- 如果指定的标签不存在,系统会自动创建标签节点,无需单独创建
-- 批量更新时,如果某些项目失败,其他项目仍会继续处理
-- 当传入大量数据时,建议分批处理以避免请求超时 

+ 106 - 19
app/api/data_parse/routes.py

@@ -1,8 +1,8 @@
 from flask import jsonify, request, make_response, Blueprint, current_app, send_file
 from app.api.data_parse import bp
-from app.core.data_parse.parse import parse_data, process_business_card, update_business_card, get_business_cards, update_business_card_status, create_talent_tag, get_talent_tag_list, update_talent_tag, delete_talent_tag, query_neo4j_graph, talent_get_tags, talent_update_tags, get_business_card, get_hotel_positions_list, add_hotel_positions, update_hotel_positions, query_hotel_positions, delete_hotel_positions, get_hotel_group_brands_list, add_hotel_group_brands, update_hotel_group_brands, query_hotel_group_brands, delete_hotel_group_brands, get_duplicate_records, process_duplicate_record, get_duplicate_record_detail
+from app.core.data_parse.parse import process_business_card, update_business_card, get_business_cards, update_business_card_status, create_talent_tag, get_talent_tag_list, update_talent_tag, delete_talent_tag, query_neo4j_graph, talent_get_tags, talent_update_tags, get_business_card, get_hotel_positions_list, add_hotel_positions, update_hotel_positions, query_hotel_positions, delete_hotel_positions, get_hotel_group_brands_list, add_hotel_group_brands, update_hotel_group_brands, query_hotel_group_brands, delete_hotel_group_brands, get_duplicate_records, process_duplicate_record, get_duplicate_record_detail, fix_broken_duplicate_records
 # 导入新的名片图片解析函数和添加名片函数
-from app.core.data_parse.parse_card import process_business_card_image, add_business_card
+from app.core.data_parse.parse_card import process_business_card_image, add_business_card, delete_business_card
 from app.config.config import DevelopmentConfig, ProductionConfig
 import logging
 import boto3
@@ -47,23 +47,6 @@ def get_minio_client():
         secure=config.MINIO_SECURE
     )
 
-# 测试用的解析数据接口。没有实际使用。
-@bp.route('/parse', methods=['POST'])
-def parse():
-    """
-    解析数据的接口
-    """
-    try:
-        data = request.get_json()
-        if not data:
-            return jsonify({'error': 'No data provided'}), 400
-            
-        result = parse_data(data)
-        return jsonify(result), 200
-        
-    except Exception as e:
-        return jsonify({'error': str(e)}), 500 
-    
 # 名片解析接口
 @bp.route('/business-card-parse', methods=['POST'])
 def parse_business_card_route():
@@ -1336,3 +1319,107 @@ def get_duplicate_record_detail_route(duplicate_id):
             'data': None
         }), 500
 
+# 删除名片记录接口
+@bp.route('/delete-business-card/<int:card_id>', methods=['DELETE'])
+def delete_business_card_route(card_id):
+    """
+    删除名片记录的API接口
+    
+    路径参数:
+        - card_id: 名片记录ID (必填)
+        
+    功能说明:
+        - 删除PostgreSQL数据库中business_cards表的指定记录
+        - 删除PostgreSQL数据库中duplicate_business_cards表的相关记录  
+        - 删除MinIO存储中的名片图片文件
+        - 删除Neo4j图数据库中talent节点及其关联关系
+        
+    返回:
+        - JSON: 包含删除操作的结果状态和被删除的记录信息
+        
+    状态码:
+        - 200: 完全成功删除所有相关数据
+        - 206: 部分成功 (PostgreSQL删除成功,但Neo4j删除失败)
+        - 404: 未找到指定ID的名片记录
+        - 500: 删除操作失败
+    """
+    try:
+        # 验证card_id参数
+        if not card_id or card_id <= 0:
+            return jsonify({
+                'success': False,
+                'message': '无效的名片记录ID',
+                'data': None
+            }), 400
+        
+        # 调用删除函数
+        result = delete_business_card(card_id)
+        
+        # 根据处理结果设置HTTP状态码和返回响应
+        if result['success']:
+            if result['code'] == 200:
+                status_code = 200  # 完全成功
+            elif result['code'] == 206:
+                status_code = 206  # 部分成功
+            else:
+                status_code = 200  # 默认成功
+        else:
+            if result['code'] == 404:
+                status_code = 404  # 未找到记录
+            elif result['code'] == 400:
+                status_code = 400  # 参数错误
+            else:
+                status_code = 500  # 服务器错误
+        
+        return jsonify(result), status_code
+        
+    except Exception as e:
+        logger.error(f"删除名片记录失败: {str(e)}")
+        return jsonify({
+            'success': False,
+            'message': f'删除名片记录失败: {str(e)}',
+            'data': None
+        }), 500
+
+# 修复损坏的重复记录接口
+@bp.route('/fix-broken-duplicate-records', methods=['POST'])
+def fix_broken_duplicate_records_route():
+    """
+    修复duplicate_business_cards表中main_card_id为null的损坏记录
+    
+    功能说明:
+        - 查找所有main_card_id为null的损坏记录
+        - 删除这些损坏的记录以维护数据完整性
+        - 返回修复操作的详细结果
+        
+    返回:
+        - JSON: 包含修复操作的结果和被删除记录的信息
+        
+    状态码:
+        - 200: 修复成功
+        - 500: 修复失败
+        
+    注意:
+        - 此操作会永久删除损坏的记录
+        - 建议在系统维护时执行此操作
+    """
+    try:
+        # 调用修复函数
+        result = fix_broken_duplicate_records()
+        
+        # 根据结果设置状态码
+        if result['success']:
+            status_code = 200
+        else:
+            status_code = 500
+        
+        return jsonify(result), status_code
+        
+    except Exception as e:
+        logger.error(f"修复损坏记录接口调用失败: {str(e)}")
+        return jsonify({
+            'success': False,
+            'message': f'修复损坏记录接口调用失败: {str(e)}',
+            'data': None
+        }), 500
+

+ 132 - 22
app/core/data_parse/parse.py

@@ -38,6 +38,8 @@ class BusinessCard(db.Model):
     brand_en = db.Column(db.String(100))
     affiliation_zh = db.Column(db.String(200))
     affiliation_en = db.Column(db.String(200))
+    birthday = db.Column(db.Date)  # 生日,存储年月日
+    residence = db.Column(db.Text)  # 居住地
     image_path = db.Column(db.String(255))  # MinIO中存储的路径
     career_path = db.Column(db.JSON)  # 职业轨迹,JSON格式
     brand_group = db.Column(db.String(200))  # 品牌组合
@@ -66,6 +68,8 @@ class BusinessCard(db.Model):
             'brand_en': self.brand_en,
             'affiliation_zh': self.affiliation_zh,
             'affiliation_en': self.affiliation_en,
+            'birthday': self.birthday.strftime('%Y-%m-%d') if self.birthday else None,
+            'residence': self.residence,
             'image_path': self.image_path,
             'career_path': self.career_path,
             'brand_group': self.brand_group,
@@ -321,6 +325,8 @@ def create_main_card_with_duplicates(extracted_data, minio_path, suspected_dupli
             brand_en=extracted_data.get('brand_en', ''),
             affiliation_zh=extracted_data.get('affiliation_zh', ''),
             affiliation_en=extracted_data.get('affiliation_en', ''),
+            birthday=datetime.strptime(extracted_data.get('birthday'), '%Y-%m-%d').date() if extracted_data.get('birthday') else None,
+            residence=extracted_data.get('residence', ''),
             image_path=minio_path,  # 最新的图片路径
             career_path=initial_career_path,  # 包含图片路径的职业轨迹
             brand_group=extracted_data.get('brand_group', ''),
@@ -637,7 +643,9 @@ def extract_fields_from_text(text):
         'brand_zh': '',
         'brand_en': '',
         'affiliation_zh': '',
-        'affiliation_en': ''
+        'affiliation_en': '',
+        'birthday': '',
+        'residence': ''
     }
     
     # 提取中文姓名
@@ -772,9 +780,11 @@ def parse_text_with_qwen25VLplus(image_data):
 11. 英文地址 (address_en)
 12. 中文邮政编码 (postal_code_zh)
 13. 英文邮政编码 (postal_code_en)
-14. 品牌组合 (brand_group) - 如有多个品牌,使用逗号分隔
-15. 职业轨迹 (career_path) - 如能从名片中推断,以JSON数组格式返回,包含当前日期,公司名称和职位。自动生成当前日期。
-16. 隶属关系 (affiliation) - 如能从名片中推断,以JSON数组格式返回,包含公司名称和隶属集团名称
+14. 生日 (birthday) - 格式为YYYY-MM-DD,如1990-01-01
+15. 居住地 (residence) - 个人居住地址信息
+16. 品牌组合 (brand_group) - 如有多个品牌,使用逗号分隔
+17. 职业轨迹 (career_path) - 如能从名片中推断,以JSON数组格式返回,包含当前日期,公司名称和职位。自动生成当前日期。
+18. 隶属关系 (affiliation) - 如能从名片中推断,以JSON数组格式返回,包含公司名称和隶属集团名称
 ## 输出格式
 请以严格的JSON格式返回结果,不要添加任何额外解释文字。JSON格式如下:
 ```json
@@ -792,6 +802,8 @@ def parse_text_with_qwen25VLplus(image_data):
   "address_en": "",
   "postal_code_zh": "",
   "postal_code_en": "",
+  "birthday": "",
+  "residence": "",
   "brand_group": "",
   "career_path": [],
   "affiliation": []
@@ -834,7 +846,8 @@ def parse_text_with_qwen25VLplus(image_data):
             'name_zh', 'name_en', 'title_zh', 'title_en', 
             'hotel_zh', 'hotel_en', 'mobile', 'phone', 
             'email', 'address_zh', 'address_en',
-            'postal_code_zh', 'postal_code_en', 'brand_group', 'career_path'
+            'postal_code_zh', 'postal_code_en', 'birthday', 'residence',
+            'brand_group', 'career_path'
         ]
         
         for field in required_fields:
@@ -951,6 +964,14 @@ def process_business_card(image_file):
                 existing_card.brand_en = extracted_data.get('brand_en', existing_card.brand_en)
                 existing_card.affiliation_zh = extracted_data.get('affiliation_zh', existing_card.affiliation_zh)
                 existing_card.affiliation_en = extracted_data.get('affiliation_en', existing_card.affiliation_en)
+                # 处理生日字段
+                if extracted_data.get('birthday'):
+                    try:
+                        existing_card.birthday = datetime.strptime(extracted_data.get('birthday'), '%Y-%m-%d').date()
+                    except ValueError:
+                        # 如果日期格式不正确,保持原值
+                        pass
+                existing_card.residence = extracted_data.get('residence', existing_card.residence)
                 existing_card.brand_group = extracted_data.get('brand_group', existing_card.brand_group)
                 existing_card.image_path = minio_path  # 更新为最新的图片路径
                 existing_card.updated_by = 'system'
@@ -1026,9 +1047,11 @@ def process_business_card(image_file):
                     brand_en=extracted_data.get('brand_en', ''),
                     affiliation_zh=extracted_data.get('affiliation_zh', ''),
                     affiliation_en=extracted_data.get('affiliation_en', ''),
+                    birthday=datetime.strptime(extracted_data.get('birthday'), '%Y-%m-%d').date() if extracted_data.get('birthday') else None,
+                    residence=extracted_data.get('residence', ''),
                     image_path=minio_path,  # 最新的图片路径
                     career_path=initial_career_path,  # 包含图片路径的职业轨迹
-                    brand_group=extracted_data.get('brand_group', ''),  # 添加品牌组合
+                    brand_group=extracted_data.get('brand_group', ''),
                     status='active',
                     updated_by='system'
                 )
@@ -1073,9 +1096,11 @@ def process_business_card(image_file):
                     'brand_en': extracted_data.get('brand_en', ''),
                     'affiliation_zh': extracted_data.get('affiliation_zh', ''),
                     'affiliation_en': extracted_data.get('affiliation_en', ''),
+                    'birthday': extracted_data.get('birthday', ''),
+                    'residence': extracted_data.get('residence', ''),
                     'image_path': minio_path,  # 返回相对路径
                     'career_path': initial_career_path,  # 包含图片路径的职业轨迹
-                    'brand_group': extracted_data.get('brand_group', ''),  # 添加品牌组合
+                    'brand_group': extracted_data.get('brand_group', ''),
                     'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
                     'updated_at': None,
                     'updated_by': 'system',
@@ -1136,6 +1161,17 @@ def update_business_card(card_id, data):
         card.brand_en = data.get('brand_en', card.brand_en)
         card.affiliation_zh = data.get('affiliation_zh', card.affiliation_zh)
         card.affiliation_en = data.get('affiliation_en', card.affiliation_en)
+        # 处理生日字段,支持字符串转日期
+        if 'birthday' in data:
+            if data['birthday']:
+                try:
+                    card.birthday = datetime.strptime(data['birthday'], '%Y-%m-%d').date()
+                except ValueError:
+                    # 如果日期格式不正确,设置为None
+                    card.birthday = None
+            else:
+                card.birthday = None
+        card.residence = data.get('residence', card.residence)
         card.career_path = data.get('career_path', card.career_path)  # 更新职业轨迹
         card.brand_group = data.get('brand_group', card.brand_group)  # 更新品牌组合
         card.updated_by = data.get('updated_by', 'user')  # 可以根据实际情况修改为当前用户
@@ -2673,6 +2709,7 @@ def add_hotel_group_brands(brand_data):
             brand_name_zh=brand_data['brand_name_zh'].strip()
         ).first()
         
+        
         if existing_brand:
             return {
                 'code': 409,
@@ -2974,7 +3011,7 @@ def process_duplicate_record(duplicate_id, action, selected_duplicate_id=None, p
     处理重复记录
     
     Args:
-        duplicate_id (int): 重复记录ID
+        duplicate_id (int): 名片记录ID(对应DuplicateBusinessCard表中的main_card_id字段)
         action (str): 处理动作 ('merge_to_suspected', 'keep_main', 'ignore')
         selected_duplicate_id (int, optional): 当action为'merge_to_suspected'时,选择的疑似重复记录ID
         processed_by (str, optional): 处理人
@@ -2984,13 +3021,13 @@ def process_duplicate_record(duplicate_id, action, selected_duplicate_id=None, p
         dict: 包含操作结果
     """
     try:
-        # 查找重复记录
-        duplicate_record = DuplicateBusinessCard.query.get(duplicate_id)
+        # 查找重复记录 - 使用main_card_id字段匹配
+        duplicate_record = DuplicateBusinessCard.query.filter_by(main_card_id=duplicate_id).first()
         if not duplicate_record:
             return {
                 'code': 404,
                 'success': False,
-                'message': f'未找到ID为{duplicate_id}的重复记录',
+                'message': f'未找到main_card_id为{duplicate_id}的重复记录',
                 'data': None
             }
         
@@ -3050,6 +3087,8 @@ def process_duplicate_record(duplicate_id, action, selected_duplicate_id=None, p
             target_card.brand_en = main_card.brand_en or target_card.brand_en
             target_card.affiliation_zh = main_card.affiliation_zh or target_card.affiliation_zh
             target_card.affiliation_en = main_card.affiliation_en or target_card.affiliation_en
+            target_card.birthday = main_card.birthday or target_card.birthday
+            target_card.residence = main_card.residence or target_card.residence
             target_card.brand_group = main_card.brand_group or target_card.brand_group
             target_card.image_path = main_card.image_path  # 更新为最新的MinIO图片路径
             target_card.updated_by = processed_by or 'system'
@@ -3063,7 +3102,10 @@ def process_duplicate_record(duplicate_id, action, selected_duplicate_id=None, p
             }
             target_card.career_path = update_career_path(target_card, new_data, main_card.image_path)
             
-            # 删除主记录
+            # 先删除重复记录表中的记录,避免外键约束冲突
+            db.session.delete(duplicate_record)
+            
+            # 然后删除主记录
             db.session.delete(main_card)
             
             result_data = target_card.to_dict()
@@ -3076,15 +3118,16 @@ def process_duplicate_record(duplicate_id, action, selected_duplicate_id=None, p
             # 忽略,不做任何操作
             result_data = main_card.to_dict()
         
-        # 更新重复记录状态
-        duplicate_record.processing_status = 'processed'
-        duplicate_record.processed_at = datetime.now()
-        duplicate_record.processed_by = processed_by or 'system'
-        duplicate_record.processing_notes = notes or f'执行操作: {action}'
+        # 更新重复记录状态(只有在非merge_to_suspected操作时才更新,因为merge_to_suspected已经删除了记录)
+        if action != 'merge_to_suspected':
+            duplicate_record.processing_status = 'processed'
+            duplicate_record.processed_at = datetime.now()
+            duplicate_record.processed_by = processed_by or 'system'
+            duplicate_record.processing_notes = notes or f'执行操作: {action}'
         
         db.session.commit()
         
-        logging.info(f"成功处理重复记录,ID: {duplicate_id},操作: {action}")
+        logging.info(f"成功处理重复记录,main_card_id: {duplicate_id},操作: {action}")
         
         return {
             'code': 200,
@@ -3113,19 +3156,19 @@ def get_duplicate_record_detail(duplicate_id):
     获取指定重复记录的详细信息
     
     Args:
-        duplicate_id (int): 重复记录ID
+        duplicate_id (int): 名片记录ID(对应DuplicateBusinessCard表中的main_card_id字段)
         
     Returns:
         dict: 包含重复记录详细信息
     """
     try:
-        # 查找重复记录
-        duplicate_record = DuplicateBusinessCard.query.get(duplicate_id)
+        # 查找重复记录 - 使用main_card_id字段匹配
+        duplicate_record = DuplicateBusinessCard.query.filter_by(main_card_id=duplicate_id).first()
         if not duplicate_record:
             return {
                 'code': 404,
                 'success': False,
-                'message': f'未找到ID为{duplicate_id}的重复记录',
+                'message': f'未找到main_card_id为{duplicate_id}的重复记录',
                 'data': None
             }
         
@@ -3153,3 +3196,70 @@ def get_duplicate_record_detail(duplicate_id):
             'message': error_msg,
             'data': None
         }
+
+def fix_broken_duplicate_records():
+    """
+    修复duplicate_business_cards表中main_card_id为null的损坏记录
+    
+    Returns:
+        dict: 修复操作的结果
+    """
+    try:
+        # 查找所有main_card_id为null的记录
+        broken_records = DuplicateBusinessCard.query.filter(
+            DuplicateBusinessCard.main_card_id.is_(None)
+        ).all()
+        
+        if not broken_records:
+            return {
+                'code': 200,
+                'success': True,
+                'message': '没有发现需要修复的损坏记录',
+                'data': {
+                    'fixed_count': 0,
+                    'total_broken': 0
+                }
+            }
+        
+        # 记录要删除的记录信息
+        broken_info = []
+        for record in broken_records:
+            broken_info.append({
+                'id': record.id,
+                'duplicate_reason': record.duplicate_reason,
+                'processing_status': record.processing_status,
+                'created_at': record.created_at.strftime('%Y-%m-%d %H:%M:%S') if record.created_at else None,
+                'processed_at': record.processed_at.strftime('%Y-%m-%d %H:%M:%S') if record.processed_at else None
+            })
+        
+        # 删除所有损坏的记录
+        for record in broken_records:
+            db.session.delete(record)
+        
+        # 提交事务
+        db.session.commit()
+        
+        logging.info(f"成功修复并删除了{len(broken_records)}条损坏的重复记录")
+        
+        return {
+            'code': 200,
+            'success': True,
+            'message': f'成功修复并删除了{len(broken_records)}条损坏的重复记录',
+            'data': {
+                'fixed_count': len(broken_records),
+                'total_broken': len(broken_records),
+                'deleted_records': broken_info
+            }
+        }
+    
+    except Exception as e:
+        db.session.rollback()
+        error_msg = f"修复损坏记录失败: {str(e)}"
+        logging.error(error_msg, exc_info=True)
+        
+        return {
+            'code': 500,
+            'success': False,
+            'message': error_msg,
+            'data': None
+        }

+ 136 - 0
app/core/data_parse/parse_card.py

@@ -211,6 +211,14 @@ def add_business_card(card_data, image_file=None):
                 existing_card.brand_en = card_data.get('brand_en', existing_card.brand_en)
                 existing_card.affiliation_zh = card_data.get('affiliation_zh', existing_card.affiliation_zh)
                 existing_card.affiliation_en = card_data.get('affiliation_en', existing_card.affiliation_en)
+                # 处理生日字段
+                if card_data.get('birthday'):
+                    try:
+                        existing_card.birthday = datetime.strptime(card_data.get('birthday'), '%Y-%m-%d').date()
+                    except ValueError:
+                        # 如果日期格式不正确,保持原值
+                        pass
+                existing_card.residence = card_data.get('residence', existing_card.residence)
                 existing_card.brand_group = card_data.get('brand_group', existing_card.brand_group)
                 existing_card.image_path = minio_path  # 更新为最新的图片路径
                 existing_card.updated_by = 'system'
@@ -286,6 +294,8 @@ def add_business_card(card_data, image_file=None):
                     brand_en=card_data.get('brand_en', ''),
                     affiliation_zh=card_data.get('affiliation_zh', ''),
                     affiliation_en=card_data.get('affiliation_en', ''),
+                    birthday=datetime.strptime(card_data.get('birthday'), '%Y-%m-%d').date() if card_data.get('birthday') else None,
+                    residence=card_data.get('residence', ''),
                     image_path=minio_path,  # 最新的图片路径
                     career_path=initial_career_path,  # 包含图片路径的职业轨迹
                     brand_group=card_data.get('brand_group', ''),
@@ -327,3 +337,129 @@ def add_business_card(card_data, image_file=None):
             'message': error_msg,
             'data': None
         }
+
+
+def delete_business_card(card_id):
+    """
+    删除名片记录
+    
+    Args:
+        card_id (int): 名片记录ID
+        
+    Returns:
+        dict: 删除操作的结果状态
+    """
+    try:
+        # 导入必要的模块
+        from app.services.neo4j_driver import neo4j_driver
+        
+        # 第一步:查找要删除的名片记录
+        business_card = BusinessCard.query.get(card_id)
+        if not business_card:
+            return {
+                'code': 404,
+                'success': False,
+                'message': f'未找到ID为{card_id}的名片记录',
+                'data': None
+            }
+        
+        # 保存被删除记录的信息,用于返回
+        deleted_card_info = business_card.to_dict()
+        
+        # 第二步:从MinIO删除图片文件(如果存在)
+        if business_card.image_path:
+            try:
+                minio_client = get_minio_client()
+                if minio_client:
+                    try:
+                        minio_client.delete_object(
+                            Bucket=minio_bucket,
+                            Key=business_card.image_path
+                        )
+                        logging.info(f"已从MinIO删除图片文件: {business_card.image_path}")
+                    except Exception as minio_error:
+                        logging.warning(f"从MinIO删除图片文件失败: {str(minio_error)}")
+                        # 继续执行,不因为MinIO删除失败而中断整个流程
+            except Exception as e:
+                logging.warning(f"MinIO删除操作失败: {str(e)}")
+        
+        # 第三步:删除PostgreSQL数据库中的相关记录
+        try:
+            # 删除duplicate_business_cards表中以该ID作为main_card_id的记录
+            duplicate_records_as_main = DuplicateBusinessCard.query.filter_by(main_card_id=card_id).all()
+            for duplicate_record in duplicate_records_as_main:
+                db.session.delete(duplicate_record)
+                logging.info(f"删除重复记录表中主记录ID为{card_id}的记录,重复记录ID: {duplicate_record.id}")
+            
+            # 删除business_cards表中的主记录
+            db.session.delete(business_card)
+            db.session.commit()
+            
+            logging.info(f"成功删除PostgreSQL数据库中的名片记录,ID: {card_id}")
+            
+        except Exception as db_error:
+            db.session.rollback()
+            error_msg = f"删除PostgreSQL数据库记录失败: {str(db_error)}"
+            logging.error(error_msg, exc_info=True)
+            return {
+                'code': 500,
+                'success': False,
+                'message': error_msg,
+                'data': None
+            }
+        
+        # 第四步:删除Neo4j图数据库中的talent节点及其关系
+        try:
+            # 构建删除talent节点及其所有关系的Cypher查询
+            delete_talent_query = """
+            MATCH (t:talent)
+            WHERE t.pg_id = $pg_id
+            OPTIONAL MATCH (t)-[r]-()
+            DELETE r, t
+            RETURN count(t) as deleted_count
+            """
+            
+            # 执行删除查询
+            with neo4j_driver.get_session() as session:
+                result = session.run(delete_talent_query, pg_id=int(card_id))
+                record = result.single()
+                deleted_count = record['deleted_count'] if record else 0
+                
+                if deleted_count > 0:
+                    logging.info(f"成功删除Neo4j中的talent节点及其关系,pg_id: {card_id}")
+                else:
+                    logging.info(f"Neo4j中未找到pg_id为{card_id}的talent节点")
+                    
+        except Exception as neo4j_error:
+            # Neo4j删除失败不影响整体操作的成功,因为PostgreSQL记录已经删除成功
+            logging.error(f"删除Neo4j数据失败: {str(neo4j_error)}", exc_info=True)
+            return {
+                'code': 206,  # Partial Content - 部分成功
+                'success': True,
+                'message': f'名片记录删除成功,但Neo4j图数据库清理失败: {str(neo4j_error)}',
+                'data': deleted_card_info
+            }
+        
+        return {
+            'code': 200,
+            'success': True,
+            'message': '名片记录删除成功',
+            'data': deleted_card_info
+        }
+        
+    except Exception as e:
+        # 确保数据库事务回滚
+        try:
+            db.session.rollback()
+        except:
+            pass
+            
+        error_msg = f"删除名片记录失败: {str(e)}"
+        logging.error(error_msg, exc_info=True)
+        
+        return {
+            'code': 500,
+            'success': False,
+            'message': error_msg,
+            'data': None
+        }

+ 0 - 385
data_parse_api_docs.md

@@ -1,385 +0,0 @@
-# 数据解析 API 文档
-
-本文档描述了数据解析模块的 API 接口,包括通用数据解析和名片解析功能。所有接口均采用 RESTful 风格,返回 JSON 格式的响应。
-
-## 基础路径
-
-所有 API 接口的基础路径为:`/api/parse`
-
-## 1. 通用数据解析接口
-
-### 1.1 解析数据
-
-**接口地址**:`/parse`
-
-**请求方法**:POST
-
-**功能描述**:测试用的数据解析接口,目前没有实际使用。
-
-**请求参数**:
-
-请求体为 JSON 格式,具体格式取决于实际使用场景。
-
-**返回结果**:
-
-```json
-{
-  "status": "success",
-  "message": "Data parsed successfully",
-  "data": {} // 解析后的数据
-}
-```
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述           |
-|---------|----------------|
-| 400     | No data provided |
-| 500     | 内部服务器错误       |
-
-## 2. 名片解析接口
-
-### 2.1 解析名片图片
-
-**接口地址**:`/business-card-parse`
-
-**请求方法**:POST
-
-**功能描述**:处理上传的名片图片,提取名片中的信息,并保存到数据库。
-
-**请求参数**:
-
-Content-Type: multipart/form-data
-
-| 参数名   | 参数类型 | 必须 | 描述   |
-|-------|------|----|----|
-| image | file | 是  | 名片图片 |
-
-**返回结果**:
-
-成功时返回:
-
-```json
-{
-  "success": true,
-  "message": "名片解析成功",
-  "data": {
-    "id": 1,
-    "name_zh": "张三",
-    "name_en": "Zhang San",
-    "title_zh": "项目经理",
-    "title_en": "Project Manager",
-    "mobile": "13800138000",
-    "phone": "010-12345678",
-    "email": "zhangsan@example.com",
-    "hotel_zh": "某酒店",
-    "hotel_en": "Some Hotel",
-    "address_zh": "北京市朝阳区某街某号",
-    "address_en": "Some Street, Chaoyang District, Beijing",
-    "postal_code_zh": "100000",
-    "postal_code_en": "100000",
-    "brand_zh": "某品牌",
-    "brand_en": "Some Brand",
-    "affiliation_zh": "某集团",
-    "affiliation_en": "Some Group",
-    "image_path": "unique-filename.jpg",
-    "career_path": [],
-    "brand_group": "",
-    "created_at": "2023-01-01 12:00:00",
-    "updated_at": null,
-    "updated_by": "system",
-    "status": "active"
-  }
-}
-```
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述       | 错误消息            |
-|---------|------------|-----------------|
-| 400     | 请求参数错误     | 未上传图片           |
-| 400     | 请求参数错误     | 未选择文件           |
-| 400     | 请求参数错误     | 上传的文件不是图片       |
-| 500     | 服务器内部错误    | 名片解析失败: {错误信息}  |
-| 500     | 服务器内部错误    | OCR无法从图像中提取文本   |
-| 500     | 服务器内部错误    | 保存名片信息到数据库失败    |
-
-### 2.2 更新名片信息
-
-**接口地址**:`/business-cards/<int:card_id>`
-
-**请求方法**:PUT
-
-**功能描述**:更新已有名片记录的信息。
-
-**路径参数**:
-
-| 参数名      | 参数类型 | 描述    |
-|----------|------|-------|
-| card_id  | int  | 名片记录ID |
-
-**请求参数**:
-
-请求体为 JSON 格式,可包含以下字段(所有字段都是可选的):
-
-```json
-{
-  "name_zh": "张三",
-  "name_en": "Zhang San",
-  "title_zh": "高级项目经理",
-  "title_en": "Senior Project Manager",
-  "mobile": "13800138000",
-  "phone": "010-12345678",
-  "email": "zhangsan@example.com",
-  "hotel_zh": "某酒店",
-  "hotel_en": "Some Hotel",
-  "address_zh": "北京市朝阳区某街某号",
-  "address_en": "Some Street, Chaoyang District, Beijing",
-  "postal_code_zh": "100000",
-  "postal_code_en": "100000",
-  "brand_zh": "某品牌",
-  "brand_en": "Some Brand",
-  "affiliation_zh": "某集团",
-  "affiliation_en": "Some Group",
-  "career_path": [{"company": "XX公司", "position": "经理"}],
-  "brand_group": "品牌A,品牌B",
-  "updated_by": "user"
-}
-```
-
-**返回结果**:
-
-成功时返回:
-
-```json
-{
-  "success": true,
-  "message": "名片信息已更新",
-  "data": {
-    // 更新后的完整名片信息对象
-  }
-}
-```
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述    | 错误消息                    |
-|---------|---------|-------------------------|
-| 400     | 请求参数错误  | 请求数据为空                  |
-| 404     | 资源不存在   | 未找到ID为{card_id}的名片记录    |
-| 500     | 服务器内部错误 | 更新名片信息失败: {错误信息}        |
-
-### 2.3 获取所有名片列表
-
-**接口地址**:`/get-business-cards`
-
-**请求方法**:GET
-
-**功能描述**:获取系统中所有的名片记录列表。
-
-**请求参数**:无
-
-**返回结果**:
-
-成功时返回:
-
-```json
-{
-  "success": true,
-  "message": "获取名片列表成功",
-  "data": [
-    {
-      // 名片1的完整信息对象
-    },
-    {
-      // 名片2的完整信息对象
-    }
-    // ...更多名片对象
-  ]
-}
-```
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述    | 错误消息              |
-|---------|---------|-------------------|
-| 500     | 服务器内部错误 | 获取名片列表失败: {错误信息}  |
-
-### 2.4 获取单个名片记录
-
-**接口地址**:`/get-business-card/<int:card_id>`
-
-**请求方法**:GET
-
-**功能描述**:根据ID获取单个名片的详细信息。
-
-**路径参数**:
-
-| 参数名      | 参数类型 | 描述    |
-|----------|------|-------|
-| card_id  | int  | 名片记录ID |
-
-**请求参数**:无
-
-**返回结果**:
-
-成功时返回:
-
-```json
-{
-  "code": 200,
-  "success": true,
-  "message": "获取名片记录成功",
-  "data": {
-    "id": 1,
-    "name_zh": "张三",
-    "name_en": "Zhang San",
-    "title_zh": "项目经理",
-    "title_en": "Project Manager",
-    "mobile": "13800138000",
-    "phone": "010-12345678",
-    "email": "zhangsan@example.com",
-    "hotel_zh": "某酒店",
-    "hotel_en": "Some Hotel",
-    "address_zh": "北京市朝阳区某街某号",
-    "address_en": "Some Street, Chaoyang District, Beijing",
-    "postal_code_zh": "100000",
-    "postal_code_en": "100000",
-    "brand_zh": "某品牌",
-    "brand_en": "Some Brand",
-    "affiliation_zh": "某集团",
-    "affiliation_en": "Some Group",
-    "image_path": "unique-filename.jpg",
-    "career_path": [],
-    "brand_group": "",
-    "created_at": "2023-01-01 12:00:00",
-    "updated_at": null,
-    "updated_by": "system",
-    "status": "active"
-  }
-}
-```
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述    | 错误消息                    |
-|---------|---------|-------------------------|
-| 404     | 资源不存在   | 未找到ID为{card_id}的名片记录    |
-| 500     | 服务器内部错误 | 获取名片记录失败: {错误信息}        |
-
-**使用示例**:
-
-```bash
-# 使用curl获取ID为1的名片记录
-curl -X GET http://localhost:5500/api/data_parse/get-business-card/1
-```
-
-**使用说明**:
-
-1. 该接口用于查询单个名片的详细信息,支持前端应用展示名片详情页面。
-2. 接口返回的数据结构与更新接口一致,包含名片的所有字段信息。
-3. 如需同时获取该名片关联的标签信息,可以配合`/talent-get-tags/{talent_id}`接口使用。
-4. 对于不存在的名片ID,接口将返回404状态码。
-5. 接口支持前端分页应用,可先使用列表接口获取所有名片ID,再通过此接口获取详细信息。
-
-### 2.5 更新名片状态
-
-**接口地址**:`/update-business-cards/<int:card_id>/status`
-
-**请求方法**:PUT
-
-**功能描述**:更新名片的状态(激活或禁用)。
-
-**路径参数**:
-
-| 参数名      | 参数类型 | 描述    |
-|----------|------|-------|
-| card_id  | int  | 名片记录ID |
-
-**请求参数**:
-
-```json
-{
-  "status": "active" // 可选值: "active" 或 "inactive"
-}
-```
-
-**返回结果**:
-
-成功时返回:
-
-```json
-{
-  "success": true,
-  "message": "名片状态已更新为: active",
-  "data": {
-    // 更新后的完整名片信息对象
-  }
-}
-```
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述    | 错误消息                          |
-|---------|---------|-------------------------------|
-| 400     | 请求参数错误  | 请求数据为空或缺少status字段             |
-| 400     | 请求参数错误  | 无效的状态值: {状态值},必须为 active 或 inactive |
-| 404     | 资源不存在   | 未找到ID为{card_id}的名片记录          |
-| 500     | 服务器内部错误 | 更新名片状态失败: {错误信息}              |
-
-### 2.6 获取名片图片
-
-**接口地址**:`/business-cards/image/<path:image_path>`
-
-**请求方法**:GET
-
-**功能描述**:从 MinIO 存储中获取名片图片。
-
-**路径参数**:
-
-| 参数名         | 参数类型   | 描述           |
-|-------------|--------|--------------|
-| image_path  | string | MinIO中的图片路径  |
-
-**返回结果**:
-
-成功时返回图片的二进制数据流,Content-Type 根据图片类型设置。
-
-**错误码**:
-
-| HTTP 状态码 | 错误描述    | 错误消息                |
-|---------|---------|---------------------|
-| 500     | 服务器内部错误 | MinIO客户端初始化失败       |
-| 404     | 资源不存在   | 获取图片失败: {错误信息}      |
-
-## 数据模型
-
-### 名片模型 (BusinessCard)
-
-| 字段名            | 类型       | 描述        |
-|----------------|----------|-----------|
-| id             | Integer  | 主键        |
-| name_zh        | String   | 中文姓名      |
-| name_en        | String   | 英文姓名      |
-| title_zh       | String   | 中文职位/头衔   |
-| title_en       | String   | 英文职位/头衔   |
-| mobile         | String   | 手机号码      |
-| phone          | String   | 固定电话      |
-| email          | String   | 电子邮箱      |
-| hotel_zh       | String   | 中文酒店/公司名称 |
-| hotel_en       | String   | 英文酒店/公司名称 |
-| address_zh     | Text     | 中文地址      |
-| address_en     | Text     | 英文地址      |
-| postal_code_zh | String   | 中文邮政编码    |
-| postal_code_en | String   | 英文邮政编码    |
-| brand_zh       | String   | 中文品牌名称    |
-| brand_en       | String   | 英文品牌名称    |
-| affiliation_zh | String   | 中文隶属关系    |
-| affiliation_en | String   | 英文隶属关系    |
-| image_path     | String   | MinIO中存储的路径 |
-| career_path    | JSON     | 职业轨迹      |
-| brand_group    | String   | 品牌组合      |
-| created_at     | DateTime | 创建时间      |
-| updated_at     | DateTime | 更新时间      |
-| updated_by     | String   | 更新者       |
-| status         | String   | 状态        | 

+ 0 - 0
hotel_group_brands_ddl.sql → database/hotel_group_brands_ddl.sql


+ 0 - 0
hotel_positions_ddl.sql → database/hotel_positions_ddl.sql


+ 908 - 0
docs/data_flow_apis.md

@@ -0,0 +1,908 @@
+# DataFlow API 操作说明文档
+
+## 概述
+
+DataFlow API 提供了完整的数据流管理功能,包括数据流的创建、查询、更新、删除、执行等操作。系统基于Neo4j图数据库和PostgreSQL关系数据库的混合架构,支持复杂的数据流编排和管理。
+
+**版本**: v1.0  
+**基础URL**: `/api/data-flow`  
+**内容类型**: `application/json`  
+**字符编码**: UTF-8
+
+## 通用响应格式
+
+所有API接口都遵循统一的响应格式:
+
+```json
+{
+  "code": 200,           // HTTP状态码
+  "message": "操作成功",  // 操作结果消息
+  "data": {}             // 返回的具体数据
+}
+```
+
+## 状态码说明
+
+| 状态码 | 含义 | 说明 |
+|--------|------|------|
+| 200 | 成功 | 请求成功执行 |
+| 400 | 请求错误 | 请求参数错误或缺失 |
+| 404 | 未找到 | 请求的资源不存在 |
+| 500 | 服务器错误 | 服务器内部错误 |
+
+---
+
+## API 接口详情
+
+### 1. 获取数据流列表
+
+**接口描述**: 获取数据流列表,支持分页和搜索功能。
+
+#### 请求信息
+- **HTTP方法**: `GET`
+- **请求路径**: `/get-dataflows-list`
+- **请求头**: `Content-Type: application/json`
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 默认值 | 说明 |
+|--------|------|------|--------|------|
+| page | int | 否 | 1 | 页码,从1开始 |
+| page_size | int | 否 | 10 | 每页记录数,最大100 |
+| search | string | 否 | "" | 搜索关键词,支持名称和描述模糊匹配 |
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": {
+    "list": [
+      {
+        "id": 1,
+        "name": "用户数据ETL流程",
+        "en_name": "user_data_etl_process",
+        "description": "处理用户数据的ETL流程",
+        "status": "active",
+        "created_at": "2023-12-01 10:00:00",
+        "updated_at": "2023-12-01 12:00:00",
+        "created_by": "admin",
+        "config": "{\"source\": \"mysql\", \"target\": \"elasticsearch\"}"
+      }
+    ],
+    "pagination": {
+      "page": 1,
+      "page_size": 10,
+      "total": 25,
+      "total_pages": 3
+    }
+  }
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+url = "http://your-domain/api/data-flow/get-dataflows-list"
+params = {
+    "page": 1,
+    "page_size": 10,
+    "search": "ETL"
+}
+
+response = requests.get(url, params=params)
+data = response.json()
+
+if data["code"] == 200:
+    dataflows = data["data"]["list"]
+    for df in dataflows:
+        print(f"数据流: {df['name']} - {df['description']}")
+```
+
+**JavaScript示例**:
+```javascript
+const params = new URLSearchParams({
+    page: 1,
+    page_size: 10,
+    search: 'ETL'
+});
+
+fetch(`/api/data-flow/get-dataflows-list?${params}`)
+    .then(response => response.json())
+    .then(data => {
+        if (data.code === 200) {
+            console.log('数据流列表:', data.data.list);
+        }
+    })
+    .catch(error => console.error('错误:', error));
+```
+
+#### 测试数据
+```
+GET /api/data-flow/get-dataflows-list?page=1&page_size=5&search=数据处理
+```
+
+---
+
+### 2. 获取数据流详情
+
+**接口描述**: 根据数据流ID获取详细信息,包括关联的标签、子节点和父节点。
+
+#### 请求信息
+- **HTTP方法**: `GET`
+- **请求路径**: `/get-dataflow/{dataflow_id}`
+- **请求头**: `Content-Type: application/json`
+
+#### 路径参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| dataflow_id | int | 是 | 数据流ID |
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": {
+    "id": 1,
+    "name": "用户数据ETL流程",
+    "en_name": "user_data_etl_process",
+    "description": "处理用户数据的ETL流程",
+    "status": "active",
+    "created_at": "2023-12-01 10:00:00",
+    "updated_at": "2023-12-01 12:00:00",
+    "created_by": "admin",
+    "config": "{\"source\": \"mysql\", \"target\": \"elasticsearch\"}",
+    "tags": [
+      {"id": 10, "name": "数据处理"},
+      {"id": 11, "name": "ETL"}
+    ],
+    "children": [
+      {"id": 2, "name": "数据清洗子流程"},
+      {"id": 3, "name": "数据转换子流程"}
+    ],
+    "parents": [
+      {"id": 0, "name": "主数据流"}
+    ]
+  }
+}
+```
+
+#### 错误响应
+
+```json
+{
+  "code": 404,
+  "message": "数据流不存在",
+  "data": null
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+dataflow_id = 1
+url = f"http://your-domain/api/data-flow/get-dataflow/{dataflow_id}"
+
+response = requests.get(url)
+data = response.json()
+
+if data["code"] == 200:
+    dataflow = data["data"]
+    print(f"数据流名称: {dataflow['name']}")
+    print(f"关联标签: {[tag['name'] for tag in dataflow['tags']]}")
+elif data["code"] == 404:
+    print("数据流不存在")
+```
+
+#### 测试数据
+```
+GET /api/data-flow/get-dataflow/1
+```
+
+---
+
+### 3. 创建数据流
+
+**接口描述**: 创建新的数据流,自动生成英文名称,支持标签和子节点关联。
+
+#### 请求信息
+- **HTTP方法**: `POST`
+- **请求路径**: `/add-dataflow`
+- **请求头**: `Content-Type: application/json`
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| name | string | 是 | 数据流名称 |
+| description | string | 是 | 数据流描述 |
+| status | string | 否 | 状态,默认"inactive",可选值: "active", "inactive" |
+| created_by | string | 否 | 创建者,默认"system" |
+| config | object | 否 | 配置信息,JSON对象 |
+| children_ids | array | 否 | 子节点ID列表 |
+| tag_id | int | 否 | 关联标签ID |
+
+#### 请求体示例
+
+```json
+{
+  "name": "客户数据同步流程",
+  "description": "将客户数据从CRM同步到数据仓库",
+  "status": "active",
+  "created_by": "admin",
+  "config": {
+    "source": {
+      "type": "mysql",
+      "host": "192.168.1.100",
+      "database": "crm"
+    },
+    "target": {
+      "type": "postgresql",
+      "host": "192.168.1.200",
+      "database": "datawarehouse"
+    },
+    "schedule": "0 2 * * *"
+  },
+  "children_ids": [2, 3],
+  "tag_id": 10
+}
+```
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "数据流创建成功",
+  "data": {
+    "id": 5,
+    "name": "客户数据同步流程",
+    "en_name": "customer_data_sync_process",
+    "description": "将客户数据从CRM同步到数据仓库",
+    "status": "active",
+    "created_at": "2023-12-01 14:30:00",
+    "updated_at": "2023-12-01 14:30:00",
+    "created_by": "admin",
+    "config": "{\"source\":{\"type\":\"mysql\",\"host\":\"192.168.1.100\",\"database\":\"crm\"},\"target\":{\"type\":\"postgresql\",\"host\":\"192.168.1.200\",\"database\":\"datawarehouse\"},\"schedule\":\"0 2 * * *\"}"
+  }
+}
+```
+
+#### 错误响应
+
+```json
+{
+  "code": 400,
+  "message": "参数错误: 缺少必填字段: name",
+  "data": null
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+import json
+
+url = "http://your-domain/api/data-flow/add-dataflow"
+data = {
+    "name": "订单数据处理流程",
+    "description": "处理电商订单数据",
+    "status": "active",
+    "created_by": "data_team",
+    "config": {
+        "batch_size": 1000,
+        "retry_count": 3
+    }
+}
+
+response = requests.post(url, json=data)
+result = response.json()
+
+if result["code"] == 200:
+    print(f"创建成功,数据流ID: {result['data']['id']}")
+else:
+    print(f"创建失败: {result['message']}")
+```
+
+#### 测试数据
+```json
+{
+  "name": "测试数据流",
+  "description": "用于测试的数据流",
+  "status": "inactive",
+  "config": {"test": true}
+}
+```
+
+---
+
+### 4. 更新数据流
+
+**接口描述**: 更新现有数据流的信息,支持部分字段更新。
+
+#### 请求信息
+- **HTTP方法**: `PUT`
+- **请求路径**: `/update-dataflow/{dataflow_id}`
+- **请求头**: `Content-Type: application/json`
+
+#### 路径参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| dataflow_id | int | 是 | 数据流ID |
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| name | string | 否 | 数据流名称 |
+| description | string | 否 | 数据流描述 |
+| status | string | 否 | 状态 |
+| config | object | 否 | 配置信息 |
+
+#### 请求体示例
+
+```json
+{
+  "description": "更新后的数据流描述",
+  "status": "active",
+  "config": {
+    "batch_size": 2000,
+    "timeout": 300
+  }
+}
+```
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "数据流更新成功",
+  "data": {
+    "id": 1,
+    "name": "用户数据ETL流程",
+    "en_name": "user_data_etl_process",
+    "description": "更新后的数据流描述",
+    "status": "active",
+    "created_at": "2023-12-01 10:00:00",
+    "updated_at": "2023-12-01 15:45:00",
+    "created_by": "admin",
+    "config": "{\"batch_size\":2000,\"timeout\":300}"
+  }
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+dataflow_id = 1
+url = f"http://your-domain/api/data-flow/update-dataflow/{dataflow_id}"
+data = {
+    "status": "active",
+    "config": {"enabled": True}
+}
+
+response = requests.put(url, json=data)
+result = response.json()
+
+if result["code"] == 200:
+    print("更新成功")
+elif result["code"] == 404:
+    print("数据流不存在")
+```
+
+---
+
+### 5. 删除数据流
+
+**接口描述**: 删除指定的数据流及其所有关联关系。
+
+#### 请求信息
+- **HTTP方法**: `DELETE`
+- **请求路径**: `/delete-dataflow/{dataflow_id}`
+
+#### 路径参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| dataflow_id | int | 是 | 数据流ID |
+
+#### 响应数据
+
+**成功响应**:
+```json
+{
+  "code": 200,
+  "message": "数据流删除成功",
+  "data": {}
+}
+```
+
+**失败响应**:
+```json
+{
+  "code": 404,
+  "message": "数据流不存在",
+  "data": {}
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+dataflow_id = 1
+url = f"http://your-domain/api/data-flow/delete-dataflow/{dataflow_id}"
+
+response = requests.delete(url)
+result = response.json()
+
+if result["code"] == 200:
+    print("删除成功")
+elif result["code"] == 404:
+    print("数据流不存在")
+```
+
+#### 测试数据
+```
+DELETE /api/data-flow/delete-dataflow/1
+```
+
+---
+
+### 6. 执行数据流
+
+**接口描述**: 启动数据流执行,支持传入执行参数。
+
+#### 请求信息
+- **HTTP方法**: `POST`
+- **请求路径**: `/execute-dataflow/{dataflow_id}`
+- **请求头**: `Content-Type: application/json`
+
+#### 路径参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| dataflow_id | int | 是 | 数据流ID |
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| params | object | 否 | 执行参数,JSON对象 |
+
+#### 请求体示例
+
+```json
+{
+  "params": {
+    "start_date": "2023-12-01",
+    "end_date": "2023-12-07",
+    "force_refresh": true
+  }
+}
+```
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "数据流执行成功",
+  "data": {
+    "execution_id": "exec_1_1701420000",
+    "dataflow_id": 1,
+    "status": "running",
+    "started_at": "2023-12-01T16:00:00",
+    "params": {
+      "start_date": "2023-12-01",
+      "end_date": "2023-12-07",
+      "force_refresh": true
+    },
+    "progress": 0
+  }
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+dataflow_id = 1
+url = f"http://your-domain/api/data-flow/execute-dataflow/{dataflow_id}"
+data = {
+    "params": {
+        "batch_size": 500,
+        "parallel_workers": 4
+    }
+}
+
+response = requests.post(url, json=data)
+result = response.json()
+
+if result["code"] == 200:
+    execution_id = result["data"]["execution_id"]
+    print(f"执行开始,执行ID: {execution_id}")
+```
+
+---
+
+### 7. 获取数据流执行状态
+
+**接口描述**: 查询数据流的当前执行状态和进度。
+
+#### 请求信息
+- **HTTP方法**: `GET`
+- **请求路径**: `/get-dataflow-status/{dataflow_id}`
+
+#### 路径参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| dataflow_id | int | 是 | 数据流ID |
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": {
+    "dataflow_id": 1,
+    "status": "running",
+    "progress": 45,
+    "started_at": "2023-12-01T16:00:00",
+    "completed_at": null,
+    "error_message": null
+  }
+}
+```
+
+#### 状态说明
+
+| 状态值 | 含义 | 说明 |
+|--------|------|------|
+| pending | 等待中 | 数据流等待执行 |
+| running | 运行中 | 数据流正在执行 |
+| completed | 已完成 | 数据流执行成功完成 |
+| failed | 执行失败 | 数据流执行过程中出现错误 |
+
+#### 示例代码
+
+**JavaScript示例**:
+```javascript
+function checkDataflowStatus(dataflowId) {
+    fetch(`/api/data-flow/get-dataflow-status/${dataflowId}`)
+        .then(response => response.json())
+        .then(data => {
+            if (data.code === 200) {
+                const status = data.data;
+                console.log(`状态: ${status.status}, 进度: ${status.progress}%`);
+                
+                if (status.status === 'running') {
+                    // 如果还在运行,5秒后再次检查
+                    setTimeout(() => checkDataflowStatus(dataflowId), 5000);
+                }
+            }
+        });
+}
+```
+
+---
+
+### 8. 获取数据流执行日志
+
+**接口描述**: 获取数据流执行过程中的详细日志信息,支持分页。
+
+#### 请求信息
+- **HTTP方法**: `GET`
+- **请求路径**: `/get-dataflow-logs/{dataflow_id}`
+
+#### 路径参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| dataflow_id | int | 是 | 数据流ID |
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 默认值 | 说明 |
+|--------|------|------|--------|------|
+| page | int | 否 | 1 | 页码 |
+| page_size | int | 否 | 50 | 每页记录数 |
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "success",
+  "data": {
+    "logs": [
+      {
+        "id": 1,
+        "timestamp": "2023-12-01T16:00:00",
+        "level": "INFO",
+        "message": "数据流开始执行",
+        "component": "source"
+      },
+      {
+        "id": 2,
+        "timestamp": "2023-12-01T16:00:30",
+        "level": "INFO",
+        "message": "成功连接到数据源",
+        "component": "source"
+      },
+      {
+        "id": 3,
+        "timestamp": "2023-12-01T16:01:00",
+        "level": "WARNING",
+        "message": "发现重复数据,已自动处理",
+        "component": "transform"
+      }
+    ],
+    "pagination": {
+      "page": 1,
+      "page_size": 50,
+      "total": 100,
+      "total_pages": 2
+    }
+  }
+}
+```
+
+#### 日志级别说明
+
+| 级别 | 含义 | 说明 |
+|------|------|------|
+| INFO | 信息 | 一般性信息日志 |
+| WARNING | 警告 | 警告信息,不影响执行 |
+| ERROR | 错误 | 错误信息,可能导致执行失败 |
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+dataflow_id = 1
+url = f"http://your-domain/api/data-flow/get-dataflow-logs/{dataflow_id}"
+params = {"page": 1, "page_size": 20}
+
+response = requests.get(url, params=params)
+data = response.json()
+
+if data["code"] == 200:
+    logs = data["data"]["logs"]
+    for log in logs:
+        print(f"[{log['timestamp']}] {log['level']}: {log['message']}")
+```
+
+---
+
+### 9. 使用AI生成脚本
+
+**接口描述**: 使用Deepseek AI模型根据文本描述生成数据处理脚本。
+
+#### 请求信息
+- **HTTP方法**: `POST`
+- **请求路径**: `/create-script`
+- **请求头**: `Content-Type: application/json`
+
+#### 请求参数
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| request_data | string | 是 | 需求描述文本 |
+
+#### 请求体示例
+
+```json
+{
+  "request_data": "请生成一个Python脚本,从MySQL数据库读取用户表数据,清洗无效数据后写入Elasticsearch。需要包含错误处理和日志记录功能。"
+}
+```
+
+#### 响应数据
+
+```json
+{
+  "code": 200,
+  "message": "脚本生成成功",
+  "data": {
+    "script_content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nimport mysql.connector\nfrom elasticsearch import Elasticsearch\nimport logging\nimport json\nfrom datetime import datetime\n\n# 配置日志\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\ndef main():\n    try:\n        # MySQL连接配置\n        mysql_config = {\n            'host': 'localhost',\n            'user': 'username',\n            'password': 'password',\n            'database': 'database_name'\n        }\n        \n        # Elasticsearch连接配置\n        es = Elasticsearch([{'host': 'localhost', 'port': 9200}])\n        \n        # 连接MySQL\n        conn = mysql.connector.connect(**mysql_config)\n        cursor = conn.cursor(dictionary=True)\n        \n        # 查询用户数据\n        query = \"SELECT * FROM users WHERE status = 'active'\"\n        cursor.execute(query)\n        \n        # 处理数据\n        for row in cursor:\n            # 数据清洗\n            if validate_user_data(row):\n                # 写入Elasticsearch\n                es.index(index='users', body=row)\n                logger.info(f\"用户数据已写入ES: {row['id']}\")\n            else:\n                logger.warning(f\"无效用户数据跳过: {row['id']}\")\n                \n    except Exception as e:\n        logger.error(f\"脚本执行失败: {str(e)}\")\n    finally:\n        if 'conn' in locals():\n            conn.close()\n\ndef validate_user_data(user):\n    \"\"\"验证用户数据有效性\"\"\"\n    return user.get('email') and '@' in user.get('email', '')\n\nif __name__ == '__main__':\n    main()",
+    "format": "txt",
+    "generated_at": "2023-12-01T16:30:00"
+  }
+}
+```
+
+#### 示例代码
+
+**Python示例**:
+```python
+import requests
+
+url = "http://your-domain/api/data-flow/create-script"
+data = {
+    "request_data": "生成一个数据备份脚本,每天凌晨2点自动备份PostgreSQL数据库到云存储"
+}
+
+response = requests.post(url, json=data)
+result = response.json()
+
+if result["code"] == 200:
+    script = result["data"]["script_content"]
+    # 保存脚本到文件
+    with open("backup_script.py", "w", encoding="utf-8") as f:
+        f.write(script)
+    print("脚本生成并保存成功")
+```
+
+#### 测试数据
+```json
+{
+  "request_data": "创建一个简单的CSV文件处理脚本,读取销售数据并计算月度汇总"
+}
+```
+
+---
+
+## 错误处理
+
+### 常见错误码
+
+| 错误码 | 错误类型 | 解决方案 |
+|--------|----------|----------|
+| 400 | 请求参数错误 | 检查请求参数格式和必填字段 |
+| 404 | 资源不存在 | 确认资源ID是否正确 |
+| 500 | 服务器内部错误 | 查看服务器日志,联系技术支持 |
+
+### 错误响应示例
+
+```json
+{
+  "code": 400,
+  "message": "参数错误: 缺少必填字段: name",
+  "data": null
+}
+```
+
+### 错误处理最佳实践
+
+1. **检查HTTP状态码**: 首先检查HTTP响应状态码
+2. **解析错误消息**: 根据返回的message字段了解具体错误
+3. **参数验证**: 发送请求前在客户端进行参数验证
+4. **重试机制**: 对于网络错误实现适当的重试机制
+5. **日志记录**: 记录API调用和错误信息便于排查
+
+---
+
+## 使用示例
+
+### 完整工作流示例
+
+以下是一个完整的数据流管理工作流示例:
+
+```python
+import requests
+import time
+import json
+
+class DataFlowClient:
+    def __init__(self, base_url):
+        self.base_url = base_url
+    
+    def create_dataflow(self, name, description, config=None):
+        """创建数据流"""
+        url = f"{self.base_url}/add-dataflow"
+        data = {
+            "name": name,
+            "description": description,
+            "status": "active",
+            "config": config or {}
+        }
+        response = requests.post(url, json=data)
+        return response.json()
+    
+    def execute_dataflow(self, dataflow_id, params=None):
+        """执行数据流"""
+        url = f"{self.base_url}/execute-dataflow/{dataflow_id}"
+        data = {"params": params or {}}
+        response = requests.post(url, json=data)
+        return response.json()
+    
+    def wait_for_completion(self, dataflow_id, timeout=300):
+        """等待数据流执行完成"""
+        start_time = time.time()
+        
+        while time.time() - start_time < timeout:
+            url = f"{self.base_url}/get-dataflow-status/{dataflow_id}"
+            response = requests.get(url)
+            data = response.json()
+            
+            if data["code"] == 200:
+                status = data["data"]["status"]
+                progress = data["data"]["progress"]
+                
+                print(f"执行状态: {status}, 进度: {progress}%")
+                
+                if status in ["completed", "failed"]:
+                    return status
+            
+            time.sleep(5)
+        
+        return "timeout"
+
+# 使用示例
+client = DataFlowClient("http://your-domain/api/data-flow")
+
+# 1. 创建数据流
+result = client.create_dataflow(
+    "销售数据分析",
+    "分析每日销售数据并生成报表",
+    {"source": "mysql", "target": "report"}
+)
+
+if result["code"] == 200:
+    dataflow_id = result["data"]["id"]
+    print(f"数据流创建成功,ID: {dataflow_id}")
+    
+    # 2. 执行数据流
+    exec_result = client.execute_dataflow(dataflow_id, {
+        "date_range": "2023-12-01,2023-12-07"
+    })
+    
+    if exec_result["code"] == 200:
+        print("数据流开始执行")
+        
+        # 3. 等待执行完成
+        final_status = client.wait_for_completion(dataflow_id)
+        print(f"最终状态: {final_status}")
+```
+
+---
+
+## 注意事项
+
+1. **认证授权**: 生产环境中需要添加适当的认证机制
+2. **限流控制**: 注意API调用频率限制
+3. **数据大小**: 大量数据操作可能需要较长时间
+4. **并发执行**: 同一数据流不能同时执行多个实例
+5. **资源清理**: 及时清理不需要的数据流以节省资源
+
+---
+
+## 更新日志
+
+- **v1.0** (2025-06-10): 初始版本,包含基础数据流管理功能
+- **v1.1** (待发布): 计划增加数据流模板功能
+
+---
+
+## 技术支持
+
+如有问题请联系技术支持团队或查看详细的开发文档。
+
+**文档版本**: v1.0  
+**最后更新**: 2025-06-10 

+ 1259 - 0
docs/data_parse_apis.md

@@ -0,0 +1,1259 @@
+# data_parse API 接口文档
+
+## 📖 概述
+
+本文档提供了DataOps平台数据解析模块的所有API接口使用说明,包括名片解析、酒店职位管理、人才标签管理、知识图谱查询等功能。
+
+**基础URL**: `http://your-domain/api/data_parse`
+
+## 🏷️ 接口分类
+
+- [名片解析接口](#名片解析接口)
+- [酒店职位管理接口](#酒店职位管理接口)
+- [酒店集团品牌管理接口](#酒店集团品牌管理接口)
+- [人才标签管理接口](#人才标签管理接口)
+- [知识图谱查询接口](#知识图谱查询接口)
+- [重复记录处理接口](#重复记录处理接口)
+- [系统工具接口](#系统工具接口)
+
+---
+
+## 名片解析接口
+
+### 1. 解析名片图片
+
+**功能**: 仅解析名片图片,提取信息但不保存到数据库
+
+```http
+POST /business-card-parse
+```
+
+#### 请求参数
+
+| 参数名   | 类型   | 必填  | 说明                           |
+| ----- | ---- | --- | ---------------------------- |
+| image | File | 是   | 名片图片文件 (multipart/form-data) |
+
+#### 响应格式
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "名片图片解析成功",
+  "data": {
+    "name_zh": "张三",
+    "name_en": "John Doe",
+    "title_zh": "总经理",
+    "title_en": "General Manager",
+    "mobile": "13800138000",
+    "phone": "021-12345678",
+    "email": "john.doe@example.com",
+    "hotel_zh": "上海希尔顿酒店",
+    "hotel_en": "Shanghai Hilton Hotel",
+    "address_zh": "上海市浦东新区...",
+    "address_en": "Pudong New Area, Shanghai...",
+    "postal_code_zh": "200000",
+    "postal_code_en": "200000",
+    "brand_zh": "希尔顿",
+    "brand_en": "Hilton",
+    "affiliation_zh": "希尔顿集团",
+    "affiliation_en": "Hilton Group",
+    "birthday": "1990-01-01",
+    "residence": "上海市浦东新区张江高科技园区",
+    "brand_group": "希尔顿,万豪",
+    "career_path": []
+  }
+}
+```
+
+#### 数据字段说明
+
+| 字段名             | 类型     | 说明                        |
+| --------------- | ------ | ------------------------- |
+| name_zh         | String | 中文姓名                      |
+| name_en         | String | 英文姓名                      |
+| title_zh        | String | 中文职位/头衔                   |
+| title_en        | String | 英文职位/头衔                   |
+| mobile          | String | 手机号码                      |
+| phone           | String | 固定电话                      |
+| email           | String | 电子邮箱                      |
+| hotel_zh        | String | 中文酒店/公司名称                |
+| hotel_en        | String | 英文酒店/公司名称                |
+| address_zh      | String | 中文地址                      |
+| address_en      | String | 英文地址                      |
+| postal_code_zh  | String | 中文邮政编码                    |
+| postal_code_en  | String | 英文邮政编码                    |
+| brand_zh        | String | 中文品牌名称                    |
+| brand_en        | String | 英文品牌名称                    |
+| affiliation_zh  | String | 中文隶属关系                    |
+| affiliation_en  | String | 英文隶属关系                    |
+| birthday        | String | 生日,格式为YYYY-MM-DD         |
+| residence       | String | 居住地址信息                    |
+| brand_group     | String | 品牌组合,多个品牌用逗号分隔            |
+| career_path     | Array  | 职业轨迹,JSON数组格式            |
+
+#### 状态码
+
+| 状态码 | 说明                    |
+| --- | --------------------- |
+| 200 | 解析成功                  |
+| 400 | 请求参数错误(未上传文件、文件类型错误等) |
+| 500 | 服务器错误或解析失败            |
+
+#### 示例代码
+
+```bash
+curl -X POST \
+  http://your-domain/api/data_parse/business-card-parse \
+  -H 'Content-Type: multipart/form-data' \
+  -F 'image=@business_card.jpg'
+```
+
+```python
+import requests
+
+url = "http://your-domain/api/data_parse/business-card-parse"
+files = {'image': open('business_card.jpg', 'rb')}
+
+response = requests.post(url, files=files)
+print(response.json())
+```
+
+---
+
+### 2. 添加名片记录
+
+**功能**: 保存名片信息到数据库,包括重复检查、MinIO上传等完整业务逻辑
+
+```http
+POST /add-business-card
+```
+
+#### 请求参数
+
+**方式1: JSON Body**
+
+```json
+{
+   "name_zh": "张三",
+    "name_en": "John Doe",
+    "title_zh": "总经理",
+    "title_en": "General Manager",
+    "mobile": "13800138000",
+    "phone": "021-12345678",
+    "email": "john.doe@example.com",
+    "hotel_zh": "上海希尔顿酒店",
+    "hotel_en": "Shanghai Hilton Hotel",
+    "address_zh": "上海市浦东新区...",
+    "address_en": "Pudong New Area, Shanghai...",
+    "postal_code_zh": "200000",
+    "postal_code_en": "200000",
+    "brand_zh": "希尔顿",
+    "brand_en": "Hilton",
+    "affiliation_zh": "希尔顿集团",
+    "affiliation_en": "Hilton Group",
+    "birthday": "1990-01-01",
+    "residence": "上海市浦东新区张江高科技园区",
+    "brand_group": "希尔顿,万豪",
+    "career_path": []
+}
+```
+
+**方式2: Form-Data**
+
+| 参数名       | 类型     | 必填  | 说明          |
+| --------- | ------ | --- | ----------- |
+| card_data | String | 是   | JSON格式的名片数据 |
+| image     | File   | 否   | 名片图片文件      |
+
+#### 响应格式
+
+**成功创建新记录**:
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "名片信息保存成功。未找到同名记录,创建新记录",
+  "data": {
+    "id": 123,
+    "name_zh": "张三",
+    "name_en": "John Doe",
+    "birthday": "1990-01-01",
+    "residence": "上海市浦东新区张江高科技园区",
+    "created_at": "2024-01-01 12:00:00",
+    "image_path": "abc123.jpg",
+    ...
+  }
+}
+```
+
+**发现疑似重复记录**:
+
+```json
+{
+  "code": 202,
+  "success": true,
+  "message": "创建新记录成功,发现疑似重复记录待处理",
+  "data": {
+    "main_card": { ... },
+    "duplicate_record_id": 45,
+    "suspected_duplicates_count": 2,
+    "processing_status": "pending"
+  }
+}
+```
+
+#### 状态码
+
+| 状态码 | 说明            |
+| --- | ------------- |
+| 200 | 成功创建或更新记录     |
+| 202 | 创建成功但发现疑似重复记录 |
+| 400 | 请求参数错误        |
+| 500 | 服务器错误         |
+
+#### 示例代码
+
+```python
+# 方式1: 纯JSON
+import requests
+
+url = "http://your-domain/api/data_parse/add-business-card"
+data = {
+    "name_zh": "张三",
+    "mobile": "13800138000",
+    "hotel_zh": "上海希尔顿酒店",
+    "birthday": "1990-01-01",
+    "residence": "上海市浦东新区张江高科技园区"
+}
+
+response = requests.post(url, json=data)
+print(response.json())
+
+# 方式2: 包含图片文件
+import json
+
+url = "http://your-domain/api/data_parse/add-business-card"
+card_data = {
+    "name_zh": "张三",
+    "mobile": "13800138000",
+    "birthday": "1990-01-01",
+    "residence": "上海市浦东新区张江高科技园区"
+}
+
+files = {'image': open('business_card.jpg', 'rb')}
+data = {'card_data': json.dumps(card_data)}
+
+response = requests.post(url, files=files, data=data)
+print(response.json())
+```
+
+---
+
+### 3. 获取所有名片记录
+
+```http
+GET /get-business-cards
+```
+
+#### 响应格式
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "获取名片列表成功",
+  "data": [
+    {
+      "id": 1,
+      "name_zh": "张三",
+      "name_en": "John Doe",
+      "mobile": "13800138000",
+      "birthday": "1990-01-01",
+      "residence": "上海市浦东新区张江高科技园区",
+      "created_at": "2024-01-01 12:00:00",
+      ...
+    }
+  ]
+}
+```
+
+---
+
+### 4. 获取单个名片记录
+
+```http
+GET /get-business-card/{card_id}
+```
+
+#### 路径参数
+
+| 参数名     | 类型      | 说明     |
+| ------- | ------- | ------ |
+| card_id | Integer | 名片记录ID |
+
+#### 示例
+
+```bash
+curl http://your-domain/api/data_parse/get-business-card/123
+```
+
+---
+
+### 5. 更新名片信息
+
+```http
+PUT /business-cards/{card_id}
+```
+
+#### 路径参数
+
+| 参数名     | 类型      | 说明     |
+| ------- | ------- | ------ |
+| card_id | Integer | 名片记录ID |
+
+#### 请求参数
+
+```json
+{
+  "name_zh": "李四",
+  "title_zh": "副总经理",
+  "mobile": "13900139000",
+  "birthday": "1985-06-15",
+  "residence": "北京市朝阳区建国门外大街"
+}
+```
+
+---
+
+### 6. 删除名片记录
+
+**功能**: 完全删除名片记录,包括PostgreSQL数据库记录、MinIO存储的图片文件和Neo4j图数据库中的相关节点和关系
+
+```http
+DELETE /delete-business-card/{card_id}
+```
+
+#### 路径参数
+
+| 参数名     | 类型      | 说明     |
+| ------- | ------- | ------ |
+| card_id | Integer | 名片记录ID |
+
+#### 删除范围
+
+1. **PostgreSQL数据库清理**:
+   - 删除 `business_cards` 表中指定ID的记录
+   - 删除 `duplicate_business_cards` 表中以该ID作为 `main_card_id` 的相关记录
+
+2. **MinIO文件存储清理**:
+   - 删除与该名片记录关联的图片文件
+
+3. **Neo4j图数据库清理**:
+   - 删除 `talent` 节点中 `pg_id` 等于传入ID的节点
+   - 同时删除该节点的所有关联关系 (BELONGS_TO, WORKS_FOR等)
+
+#### 响应格式
+
+**完全成功删除**:
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "名片记录删除成功",
+  "data": {
+    "id": 123,
+    "name_zh": "张三",
+    "name_en": "John Doe",
+    "mobile": "13800138000",
+    "birthday": "1990-01-01",
+    "residence": "上海市浦东新区张江高科技园区",
+    "image_path": "abc123.jpg",
+    "created_at": "2024-01-01 12:00:00",
+    "status": "active"
+  }
+}
+```
+
+**部分成功删除**:
+
+```json
+{
+  "code": 206,
+  "success": true,
+  "message": "名片记录删除成功,但Neo4j图数据库清理失败: 连接超时",
+  "data": {
+    "id": 123,
+    "name_zh": "张三",
+    ...
+  }
+}
+```
+
+#### 状态码
+
+| 状态码 | 说明                                   |
+| --- | ------------------------------------ |
+| 200 | 完全成功删除所有相关数据                         |
+| 206 | 部分成功 (PostgreSQL删除成功,但Neo4j删除失败)    |
+| 400 | 参数错误(无效的card_id)                     |
+| 404 | 未找到指定ID的名片记录                         |
+| 500 | 删除操作失败                               |
+
+#### 示例代码
+
+```bash
+curl -X DELETE \
+  http://your-domain/api/data_parse/delete-business-card/123
+```
+
+```python
+import requests
+
+url = "http://your-domain/api/data_parse/delete-business-card/123"
+response = requests.delete(url)
+print(response.json())
+```
+
+#### 注意事项
+
+⚠️ **警告**: 此操作不可逆,删除的数据无法恢复。建议在删除前:
+1. 确认要删除的记录ID正确
+2. 考虑是否需要备份相关数据
+3. 检查是否有其他系统依赖此记录
+
+---
+
+### 7. 更新名片状态
+
+```http
+PUT /update-business-cards/{card_id}/status
+```
+
+#### 请求参数
+
+```json
+{
+  "status": "inactive"
+}
+```
+
+#### 可选状态值
+
+| 状态值      | 说明  |
+| -------- | --- |
+| active   | 激活  |
+| inactive | 停用  |
+
+---
+
+### 8. 获取名片图片
+
+```http
+GET /business-cards/image/{image_path}
+```
+
+#### 路径参数
+
+| 参数名        | 类型     | 说明          |
+| ---------- | ------ | ----------- |
+| image_path | String | MinIO中的图片路径 |
+
+#### 示例
+
+```bash
+curl http://your-domain/api/data_parse/business-cards/image/abc123.jpg
+```
+
+---
+
+## 酒店职位管理接口
+
+### 1. 获取所有酒店职位
+
+```http
+GET /get-hotel-positions-list
+```
+
+#### 响应格式
+
+```json
+{
+  "success": true,
+  "message": "获取酒店职位列表成功",
+  "data": [
+    {
+      "id": 1,
+      "department_zh": "前厅部",
+      "department_en": "Front Office",
+      "position_zh": "前台经理",
+      "position_en": "Front Office Manager",
+      "position_abbr": "FOM",
+      "level_zh": "中层",
+      "level_en": "Middle Management",
+      "status": "active"
+    }
+  ],
+  "count": 50
+}
+```
+
+---
+
+### 2. 新增酒店职位
+
+```http
+POST /add-hotel-positions
+```
+
+#### 请求参数
+
+```json
+{
+  "department_zh": "前厅部",
+  "department_en": "Front Office",
+  "position_zh": "前台经理",
+  "position_en": "Front Office Manager",
+  "position_abbr": "FOM",
+  "level_zh": "中层",
+  "level_en": "Middle Management",
+  "created_by": "admin",
+  "status": "active"
+}
+```
+
+#### 必填字段
+
+| 字段名           | 说明     |
+| ------------- | ------ |
+| department_zh | 部门中文名称 |
+| department_en | 部门英文名称 |
+| position_zh   | 职位中文名称 |
+| position_en   | 职位英文名称 |
+| level_zh      | 职级中文名称 |
+| level_en      | 职级英文名称 |
+
+#### 状态码
+
+| 状态码 | 说明    |
+| --- | ----- |
+| 201 | 创建成功  |
+| 400 | 参数错误  |
+| 409 | 记录已存在 |
+| 500 | 服务器错误 |
+
+---
+
+### 3. 更新酒店职位
+
+```http
+PUT /update-hotel-positions/{position_id}
+```
+
+---
+
+### 4. 查询酒店职位
+
+```http
+GET /query-hotel-positions/{position_id}
+```
+
+---
+
+### 5. 删除酒店职位
+
+```http
+DELETE /delete-hotel-positions/{position_id}
+```
+
+---
+
+## 酒店集团品牌管理接口
+
+### 1. 获取所有酒店集团品牌
+
+```http
+GET /get-hotel-group-brands-list
+```
+
+#### 响应格式
+
+```json
+{
+  "success": true,
+  "message": "获取酒店集团品牌列表成功",
+  "data": [
+    {
+      "id": 1,
+      "group_name_en": "Hilton Worldwide",
+      "group_name_zh": "希尔顿集团",
+      "brand_name_en": "Hilton Hotels & Resorts",
+      "brand_name_zh": "希尔顿酒店",
+      "positioning_level_en": "Luxury",
+      "positioning_level_zh": "奢华",
+      "status": "active"
+    }
+  ],
+  "count": 25
+}
+```
+
+---
+
+### 2. 新增酒店集团品牌
+
+```http
+POST /add-hotel-group-brands
+```
+
+#### 请求参数
+
+```json
+{
+  "group_name_en": "Marriott International",
+  "group_name_zh": "万豪国际",
+  "brand_name_en": "The Ritz-Carlton",
+  "brand_name_zh": "丽思卡尔顿",
+  "positioning_level_en": "Luxury",
+  "positioning_level_zh": "奢华"
+}
+```
+
+---
+
+## 人才标签管理接口
+
+### 1. 创建人才标签
+
+```http
+POST /create-talent-tag
+```
+
+#### 请求参数
+
+```json
+{
+  "name": "酒店管理",
+  "category": "人才技能",
+  "description": "具备酒店运营管理经验",
+  "status": "active"
+}
+```
+
+---
+
+### 2. 获取人才标签列表
+
+```http
+GET /get-talent-tag-list
+```
+
+#### 响应格式
+
+```json
+{
+  "success": true,
+  "message": "获取人才标签列表成功",
+  "data": [
+    {
+      "id": 123,
+      "name": "酒店管理",
+      "en_name": "Hotel Management",
+      "category": "人才技能",
+      "description": "具备酒店运营管理经验",
+      "status": "active",
+      "time": "2024-01-01 12:00:00"
+    }
+  ]
+}
+```
+
+---
+
+### 3. 更新人才标签
+
+```http
+PUT /update-talent-tag/{tag_id}
+```
+
+---
+
+### 4. 删除人才标签
+
+```http
+DELETE /delete-talent-tag/{tag_id}
+```
+
+---
+
+### 5. 获取人才标签关系
+
+```http
+GET /talent-get-tags/{talent_id}
+```
+
+#### 路径参数
+
+| 参数名       | 类型      | 说明                |
+| --------- | ------- | ----------------- |
+| talent_id | Integer | 人才节点PostgreSQL ID |
+
+#### 响应格式
+
+```json
+{
+  "success": true,
+  "message": "获取人才标签成功",
+  "data": [
+    {
+      "talent": 12345,
+      "tag": "酒店管理"
+    },
+    {
+      "talent": 12345,
+      "tag": "市场营销"
+    }
+  ]
+}
+```
+
+---
+
+### 6. 更新人才标签关系
+
+```http
+POST /talent-update-tags
+```
+
+#### 请求参数
+
+```json
+[
+  {
+    "talent": 12345,
+    "tag": "酒店管理"
+  },
+  {
+    "talent": 12345,
+    "tag": "市场营销"
+  },
+  {
+    "talent": 12345,
+    "tag": "团队领导"
+  }
+]
+```
+
+#### 响应格式
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "成功创建或更新了 3 个标签关系",
+  "data": {
+    "success_count": 3,
+    "total_count": 3,
+    "failed_items": []
+  }
+}
+```
+
+---
+
+## 知识图谱查询接口
+
+### 1. 查询知识图谱
+
+```http
+POST /query-kg
+```
+
+#### 请求参数
+
+```json
+{
+  "query_requirement": "查找具有五星级酒店和总经理经验的人才"
+}
+```
+
+#### 响应格式
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "查询成功执行",
+  "query": "MATCH (t:talent)-[:BELONGS_TO]->(dl:data_label) WHERE dl.name IN ['五星级酒店', '总经理'] WITH t, COLLECT(DISTINCT dl.name) AS labels WHERE size(labels) = 2 RETURN t.pg_id as pg_id, t.name_zh as name_zh, t.name_en as name_en, t.mobile as mobile, t.email as email, t.updated_at as updated_at",
+  "matched_labels": ["五星级酒店", "总经理"],
+  "data": [
+    {
+      "pg_id": 123,
+      "name_zh": "张三",
+      "name_en": "John Doe",
+      "mobile": "13800138000",
+      "email": "john.doe@example.com",
+      "updated_at": "2024-01-01 12:00:00"
+    }
+  ]
+}
+```
+
+---
+
+## 重复记录处理接口
+
+### 1. 获取重复记录列表
+
+```http
+GET /get-duplicate-records?status=pending
+```
+
+#### 查询参数
+
+| 参数名    | 类型     | 可选值                         | 说明        |
+| ------ | ------ | --------------------------- | --------- |
+| status | String | pending, processed, ignored | 筛选特定状态的记录 |
+
+#### 响应格式
+
+```json
+{
+  "success": true,
+  "message": "获取重复记录列表成功",
+  "data": [
+    {
+      "id": 1,
+      "main_card_id": 123,
+      "suspected_duplicates": [
+        {
+          "id": 124,
+          "name_zh": "张三",
+          "mobile": "13900139000"
+        }
+      ],
+      "duplicate_reason": "姓名相同但手机号码不同",
+      "processing_status": "pending",
+      "created_at": "2024-01-01 12:00:00",
+      "main_card": { 
+        "id": 123,
+        "name_zh": "张三",
+        "name_en": "John Doe",
+        "mobile": "13800138000",
+        "birthday": "1990-01-01",
+        "residence": "上海市浦东新区张江高科技园区",
+        "created_at": "2024-01-01 11:30:00",
+        ...
+      }
+    }
+  ],
+  "count": 5
+}
+```
+
+---
+
+### 2. 处理重复记录
+
+```http
+POST /process-duplicate-record/{duplicate_id}
+```
+
+#### 路径参数
+
+| 参数名          | 类型      | 说明                                              |
+| ------------ | ------- | ----------------------------------------------- |
+| duplicate_id | Integer | 名片记录ID(对应DuplicateBusinessCard表中的main_card_id字段) |
+
+⚠️ **重要说明**: 
+- 此参数为名片记录的ID(即 `BusinessCard` 表的主键)
+- 系统会根据此ID查找 `DuplicateBusinessCard` 表中 `main_card_id` 字段匹配的重复记录
+- 不是 `DuplicateBusinessCard` 表的主键ID
+
+#### 请求参数
+
+```json
+{
+  "action": "merge_to_suspected",
+  "selected_duplicate_id": 124,
+  "processed_by": "admin",
+  "notes": "确认为同一人,合并记录"
+}
+```
+
+#### 操作类型
+
+| 操作                 | 说明                      |
+| ------------------ | ----------------------- |
+| merge_to_suspected | 合并到选中的疑似重复记录            |
+| keep_main          | 保留主记录,不做合并              |
+| ignore             | 忽略,标记为已处理               |
+
+#### 响应格式
+
+**成功处理**:
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "重复记录处理成功,操作: merge_to_suspected",
+  "data": {
+    "duplicate_record": {
+      "id": 1,
+      "main_card_id": 123,
+      "processing_status": "processed",
+      "processed_at": "2024-01-01 15:30:00",
+      "processed_by": "admin",
+      "processing_notes": "确认为同一人,合并记录"
+    },
+    "result": {
+      "id": 124,
+      "name_zh": "张三",
+      "name_en": "John Doe",
+      "birthday": "1990-01-01",
+      "residence": "上海市浦东新区张江高科技园区",
+      "updated_at": "2024-01-01 15:30:00",
+      ...
+    }
+  }
+}
+```
+
+#### 状态码
+
+| 状态码 | 说明                                     |
+| --- | -------------------------------------- |
+| 200 | 处理成功                                   |
+| 400 | 参数错误或重复记录状态不允许处理                       |
+| 404 | 未找到对应的重复记录或目标记录                        |
+| 500 | 处理失败                                   |
+
+#### 示例代码
+
+```bash
+curl -X POST \
+  http://your-domain/api/data_parse/process-duplicate-record/123 \
+  -H 'Content-Type: application/json' \
+  -d '{
+    "action": "merge_to_suspected",
+    "selected_duplicate_id": 124,
+    "processed_by": "admin",
+    "notes": "确认为同一人,合并记录"
+  }'
+```
+
+```python
+import requests
+
+url = "http://your-domain/api/data_parse/process-duplicate-record/123"
+data = {
+    "action": "merge_to_suspected",
+    "selected_duplicate_id": 124,
+    "processed_by": "admin",
+    "notes": "确认为同一人,合并记录"
+}
+
+response = requests.post(url, json=data)
+print(response.json())
+```
+
+---
+
+### 3. 获取重复记录详情
+
+```http
+GET /get-duplicate-record-detail/{duplicate_id}
+```
+
+#### 路径参数
+
+| 参数名          | 类型      | 说明                                              |
+| ------------ | ------- | ----------------------------------------------- |
+| duplicate_id | Integer | 名片记录ID(对应DuplicateBusinessCard表中的main_card_id字段) |
+
+⚠️ **重要说明**: 
+- 此参数为名片记录的ID(即 `BusinessCard` 表的主键)
+- 系统会根据此ID查找 `DuplicateBusinessCard` 表中 `main_card_id` 字段匹配的重复记录
+
+#### 响应格式
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "获取重复记录详情成功",
+  "data": {
+    "id": 1,
+    "main_card_id": 123,
+    "suspected_duplicates": [
+      {
+        "id": 124,
+        "name_zh": "张三",
+        "name_en": "John Doe",
+        "mobile": "13900139000",
+        "hotel_zh": "北京希尔顿酒店",
+        "created_at": "2024-01-01 10:00:00"
+      },
+      {
+        "id": 125,
+        "name_zh": "张三",
+        "name_en": "John Doe",
+        "mobile": "13700137000",
+        "hotel_zh": "广州万豪酒店",
+        "created_at": "2024-01-01 09:00:00"
+      }
+    ],
+    "duplicate_reason": "姓名相同但手机号码不同:张三,新手机号:13800138000,发现2条疑似重复记录",
+    "processing_status": "pending",
+    "created_at": "2024-01-01 12:00:00",
+    "processed_at": null,
+    "processed_by": null,
+    "processing_notes": null,
+    "main_card": {
+      "id": 123,
+      "name_zh": "张三",
+      "name_en": "John Doe",
+      "mobile": "13800138000",
+      "birthday": "1990-01-01",
+      "residence": "上海市浦东新区张江高科技园区",
+      "hotel_zh": "上海希尔顿酒店",
+      "created_at": "2024-01-01 12:00:00",
+      ...
+    }
+  }
+}
+```
+
+#### 状态码
+
+| 状态码 | 说明        |
+| --- | --------- |
+| 200 | 获取成功      |
+| 404 | 未找到对应的重复记录 |
+| 500 | 获取失败      |
+
+#### 示例代码
+
+```bash
+curl http://your-domain/api/data_parse/get-duplicate-record-detail/123
+```
+
+```python
+import requests
+
+url = "http://your-domain/api/data_parse/get-duplicate-record-detail/123"
+response = requests.get(url)
+print(response.json())
+```
+
+---
+
+## 系统工具接口
+
+### 1. 测试MinIO连接
+
+```http
+GET /test-minio-connection
+```
+
+#### 响应格式
+
+```json
+{
+  "success": true,
+  "message": "连接MinIO服务器成功,存储桶 dataops-bucket 存在",
+  "config": {
+    "host": "192.168.3.143:9000",
+    "bucket": "dataops-bucket",
+    "secure": false
+  }
+}
+```
+
+---
+
+### 2. 测试数据解析
+
+```http
+POST /parse
+```
+
+#### 请求参数
+
+```json
+{
+  "text": "这是测试数据"
+}
+```
+
+---
+
+### 3. 修复损坏的重复记录
+
+**功能**: 修复 `duplicate_business_cards` 表中 `main_card_id` 为 null 的损坏记录
+
+```http
+POST /fix-broken-duplicate-records
+```
+
+#### 功能说明
+
+此接口用于修复在处理重复记录合并操作时可能产生的数据完整性问题。当执行合并操作删除主记录时,如果外键约束处理不当,可能导致重复记录表中的 `main_card_id` 字段变成 null,违反数据库的非空约束。
+
+#### 修复范围
+
+- 查找所有 `main_card_id` 为 null 的损坏记录
+- 删除这些损坏的记录以维护数据完整性
+- 记录修复操作的详细结果
+
+#### 响应格式
+
+**成功修复**:
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "成功修复并删除了2条损坏的重复记录",
+  "data": {
+    "fixed_count": 2,
+    "total_broken": 2,
+    "deleted_records": [
+      {
+        "id": 1,
+        "duplicate_reason": "姓名相同但手机号码不同:洪松,新手机号:+86 ...",
+        "processing_status": "processed",
+        "created_at": "2025-06-10 11:35:35",
+        "processed_at": "2025-06-10 16:18:53"
+      }
+    ]
+  }
+}
+```
+
+**无需修复**:
+
+```json
+{
+  "code": 200,
+  "success": true,
+  "message": "没有发现需要修复的损坏记录",
+  "data": {
+    "fixed_count": 0,
+    "total_broken": 0
+  }
+}
+```
+
+#### 状态码
+
+| 状态码 | 说明   |
+| --- | ---- |
+| 200 | 修复成功 |
+| 500 | 修复失败 |
+
+#### 示例代码
+
+```bash
+curl -X POST \
+  http://your-domain/api/data_parse/fix-broken-duplicate-records
+```
+
+```python
+import requests
+
+url = "http://your-domain/api/data_parse/fix-broken-duplicate-records"
+response = requests.post(url)
+print(response.json())
+```
+
+#### 注意事项
+
+⚠️ **重要提醒**:
+1. **不可逆操作**: 此操作会永久删除损坏的记录,无法恢复
+2. **数据备份**: 建议在执行前备份 `duplicate_business_cards` 表
+3. **系统维护**: 推荐在系统维护时间窗口内执行
+4. **问题原因**: 通常由重复记录合并操作的外键约束处理不当引起
+5. **预防措施**: 已在 `process_duplicate_record` 函数中修复了根本原因
+
+---
+
+## 🧪 测试数据
+
+### 名片解析测试数据
+
+```json
+{
+  "name_zh": "王经理",
+  "name_en": "Manager Wang",
+  "title_zh": "总经理",
+  "title_en": "General Manager",
+  "mobile": "13812345678",
+  "phone": "021-88888888",
+  "email": "wang.manager@hotelgroup.com",
+  "hotel_zh": "上海国际大酒店",
+  "hotel_en": "Shanghai International Hotel",
+  "address_zh": "上海市黄浦区南京东路100号",
+  "address_en": "100 Nanjing East Road, Huangpu District, Shanghai",
+  "postal_code_zh": "200001",
+  "postal_code_en": "200001",
+  "brand_zh": "国际酒店集团",
+  "brand_en": "International Hotel Group",
+  "birthday": "1985-03-15",
+  "residence": "上海市黄浦区南京西路88号",
+  "brand_group": "希尔顿,万豪,洲际"
+}
+```
+
+### 酒店职位测试数据
+
+```json
+{
+  "department_zh": "客房部",
+  "department_en": "Housekeeping",
+  "position_zh": "客房部经理",
+  "position_en": "Housekeeping Manager",
+  "position_abbr": "HKM",
+  "level_zh": "中层管理",
+  "level_en": "Middle Management"
+}
+```
+
+### 人才标签测试数据
+
+```json
+{
+  "name": "奢华酒店经验",
+  "category": "人才经验",
+  "description": "具备奢华酒店运营管理经验,熟悉高端客户服务标准"
+}
+```
+
+---
+
+## 📝 注意事项
+
+1. **认证**: 所有接口可能需要适当的认证头信息
+2. **文件上传**: 图片文件建议大小不超过10MB,支持JPG、PNG格式
+3. **编码**: 请求和响应均使用UTF-8编码
+4. **时区**: 所有时间字段使用服务器本地时区
+5. **错误处理**: 建议对所有API调用进行适当的错误处理
+6. **数据删除**: 删除名片记录的操作不可逆,建议在删除前进行数据备份
+7. **重复记录处理**: 处理重复记录时,`duplicate_id` 参数使用的是名片记录ID,而非重复记录表的主键ID
+
+---
+
+## 🔗 相关链接
+
+- [API测试工具推荐](https://www.postman.com/)
+- [cURL使用手册](https://curl.se/docs/manpage.html)
+- [Python Requests库文档](https://docs.python-requests.org/)
+
+---
+
+*文档版本: v1.1*  
+*最后更新: 2025年06月*

+ 112 - 0
fix_duplicate_records.py

@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+"""
+修复 duplicate_business_cards 表中 main_card_id 为 null 的损坏记录
+
+使用方法:
+    python fix_duplicate_records.py
+
+描述:
+    此脚本用于修复在处理重复记录时出现的数据完整性问题。
+    当 main_card_id 字段为 null 时,会违反数据库的非空约束。
+    
+注意:
+    - 此操作会永久删除损坏的记录
+    - 建议在执行前备份数据库
+    - 仅在确认数据损坏时使用
+"""
+
+import sys
+import os
+
+# 添加项目根目录到 Python 路径
+project_root = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, project_root)
+
+try:
+    from app import create_app, db
+    from app.core.data_parse.parse import DuplicateBusinessCard
+    import logging
+    from datetime import datetime
+    
+    # 设置日志
+    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+    logger = logging.getLogger(__name__)
+    
+    def fix_broken_records():
+        """修复损坏的重复记录"""
+        try:
+            logger.info("开始修复损坏的重复记录...")
+            
+            # 查找所有 main_card_id 为 null 的记录
+            broken_records = DuplicateBusinessCard.query.filter(
+                DuplicateBusinessCard.main_card_id.is_(None)
+            ).all()
+            
+            if not broken_records:
+                logger.info("没有发现需要修复的损坏记录")
+                return True
+            
+            logger.info(f"发现 {len(broken_records)} 条损坏记录")
+            
+            # 记录要删除的记录信息
+            for i, record in enumerate(broken_records, 1):
+                logger.info(f"损坏记录 {i}:")
+                logger.info(f"  - ID: {record.id}")
+                logger.info(f"  - 重复原因: {record.duplicate_reason}")
+                logger.info(f"  - 处理状态: {record.processing_status}")
+                logger.info(f"  - 创建时间: {record.created_at}")
+                logger.info(f"  - 处理时间: {record.processed_at}")
+            
+            # 询问用户确认
+            print(f"\n发现 {len(broken_records)} 条损坏的重复记录")
+            print("这些记录的 main_card_id 字段为 null,违反了数据库约束")
+            print("是否要删除这些损坏的记录? (y/N): ", end="")
+            
+            confirm = input().strip().lower()
+            if confirm not in ['y', 'yes']:
+                logger.info("用户取消操作")
+                return False
+            
+            # 删除损坏的记录
+            for record in broken_records:
+                db.session.delete(record)
+            
+            # 提交事务
+            db.session.commit()
+            
+            logger.info(f"成功删除了 {len(broken_records)} 条损坏的重复记录")
+            return True
+            
+        except Exception as e:
+            logger.error(f"修复操作失败: {str(e)}")
+            db.session.rollback()
+            return False
+    
+    def main():
+        """主函数"""
+        print("=== 重复记录修复工具 ===")
+        print("此工具用于修复 duplicate_business_cards 表中的损坏记录")
+        print("=" * 50)
+        
+        # 创建应用上下文
+        app = create_app()
+        
+        with app.app_context():
+            success = fix_broken_records()
+            
+            if success:
+                print("\n✅ 修复操作完成")
+            else:
+                print("\n❌ 修复操作失败或被取消")
+                sys.exit(1)
+    
+    if __name__ == "__main__":
+        main()
+        
+except ImportError as e:
+    print(f"导入错误: {e}")
+    print("请确保从项目根目录运行此脚本")
+    sys.exit(1)
+except Exception as e:
+    print(f"执行错误: {e}")
+    sys.exit(1) 

+ 0 - 323
talent_tag_api_documentation.md

@@ -1,323 +0,0 @@
-# 人才标签 API 接口文档
-
-本文档详细说明了人才标签管理的四个 API 接口,包括创建、查询、更新和删除人才标签的操作。
-
-## 目录
-
-- [创建人才标签](#创建人才标签)
-- [获取人才标签列表](#获取人才标签列表)
-- [更新人才标签](#更新人才标签)
-- [删除人才标签](#删除人才标签)
-
-## 创建人才标签
-
-创建新的人才标签节点到 Neo4j 图数据库中。
-
-### 请求信息
-
-- **URL:** `/api/parse/create-talent-tag`
-- **方法:** `POST`
-- **Content-Type:** `application/json`
-
-### 请求参数
-
-| 参数名      | 类型   | 必填 | 描述                               |
-|------------|--------|------|-----------------------------------|
-| name       | String | 是   | 标签名称                           |
-| category   | String | 否   | 标签分类,默认为"未分类"           |
-| description| String | 否   | 标签描述                           |
-| status     | String | 否   | 标签状态,默认为"active"           |
-
-### 请求示例
-
-```json
-{
-  "name": "Java开发",
-  "category": "技术能力/人才",
-  "description": "熟练掌握Java编程语言和相关框架",
-  "status": "active"
-}
-```
-
-### 响应参数
-
-| 参数名      | 类型    | 描述                               |
-|------------|---------|-----------------------------------|
-| success    | Boolean | 操作是否成功                       |
-| message    | String  | 操作结果描述                       |
-| code       | Integer | 状态码                             |
-| data       | Object  | 创建的标签信息                     |
-
-### 响应示例 - 成功
-
-```json
-{
-  "success": true,
-  "message": "人才标签创建成功",
-  "code": 200,
-  "data": {
-    "id": 12345,
-    "name": "Java开发",
-    "en_name": "Java Development",
-    "category": "技术能力/人才",
-    "description": "熟练掌握Java编程语言和相关框架",
-    "status": "active",
-    "time": "2023-07-20 14:30:45"
-  }
-}
-```
-
-### 响应示例 - 失败
-
-```json
-{
-  "success": false,
-  "message": "标签名称不能为空",
-  "code": 400,
-  "data": null
-}
-```
-
-### 状态码
-
-| 状态码 | 描述                 |
-|--------|---------------------|
-| 200    | 请求成功             |
-| 400    | 请求参数错误         |
-| 500    | 服务器内部错误       |
-
----
-
-## 获取人才标签列表
-
-从 Neo4j 图数据库获取人才标签列表,包括所有分类包含"talent"或"人才"的标签。
-
-### 请求信息
-
-- **URL:** `/api/parse/get-talent-tag-list`
-- **方法:** `GET`
-
-### 请求参数
-
-无
-
-### 响应参数
-
-| 参数名      | 类型    | 描述                               |
-|------------|---------|-----------------------------------|
-| success    | Boolean | 操作是否成功                       |
-| message    | String  | 操作结果描述                       |
-| code       | Integer | 状态码                             |
-| data       | Array   | 人才标签列表                       |
-
-### 响应示例 - 成功
-
-```json
-{
-  "success": true,
-  "message": "获取人才标签列表成功",
-  "code": 200,
-  "data": [
-    {
-      "id": 12345,
-      "name": "Java开发",
-      "en_name": "Java Development",
-      "category": "技术能力/人才",
-      "description": "熟练掌握Java编程语言和相关框架",
-      "status": "active",
-      "time": "2023-07-20 14:30:45"
-    },
-    {
-      "id": 12346,
-      "name": "Python开发",
-      "en_name": "Python Development",
-      "category": "技术能力/人才",
-      "description": "熟练掌握Python编程语言和相关框架",
-      "status": "active",
-      "time": "2023-07-19 10:15:22"
-    }
-  ]
-}
-```
-
-### 响应示例 - 失败
-
-```json
-{
-  "success": false,
-  "message": "获取人才标签列表失败: 数据库连接错误",
-  "code": 500,
-  "data": []
-}
-```
-
-### 状态码
-
-| 状态码 | 描述                 |
-|--------|---------------------|
-| 200    | 请求成功             |
-| 500    | 服务器内部错误       |
-
----
-
-## 更新人才标签
-
-更新已有的人才标签节点属性。
-
-### 请求信息
-
-- **URL:** `/api/parse/update-talent-tag/{tag_id}`
-- **方法:** `PUT`
-- **Content-Type:** `application/json`
-
-### 路径参数
-
-| 参数名 | 类型    | 描述           |
-|--------|---------|---------------|
-| tag_id | Integer | 要更新的标签ID |
-
-### 请求参数
-
-| 参数名      | 类型   | 必填 | 描述                               |
-|------------|--------|------|-----------------------------------|
-| name       | String | 否   | 标签名称                           |
-| category   | String | 否   | 标签分类                           |
-| description| String | 否   | 标签描述                           |
-| status     | String | 否   | 标签状态                           |
-
-注意:至少需要提供一个参数进行更新。
-
-### 请求示例
-
-```json
-{
-  "name": "高级Java开发",
-  "description": "精通Java编程语言和相关框架,有丰富的项目经验"
-}
-```
-
-### 响应参数
-
-| 参数名      | 类型    | 描述                               |
-|------------|---------|-----------------------------------|
-| success    | Boolean | 操作是否成功                       |
-| message    | String  | 操作结果描述                       |
-| code       | Integer | 状态码                             |
-| data       | Object  | 更新后的标签信息                   |
-
-### 响应示例 - 成功
-
-```json
-{
-  "success": true,
-  "message": "人才标签更新成功",
-  "code": 200,
-  "data": {
-    "id": 12345,
-    "name": "高级Java开发",
-    "en_name": "Senior Java Development",
-    "category": "技术能力/人才",
-    "description": "精通Java编程语言和相关框架,有丰富的项目经验",
-    "status": "active",
-    "time": "2023-07-21 09:45:30"
-  }
-}
-```
-
-### 响应示例 - 失败
-
-```json
-{
-  "success": false,
-  "message": "未找到ID为12345的标签",
-  "code": 404,
-  "data": null
-}
-```
-
-### 状态码
-
-| 状态码 | 描述                 |
-|--------|---------------------|
-| 200    | 请求成功             |
-| 400    | 请求参数错误         |
-| 404    | 标签不存在           |
-| 500    | 服务器内部错误       |
-
----
-
-## 删除人才标签
-
-删除指定的人才标签节点及其关系。
-
-### 请求信息
-
-- **URL:** `/api/parse/delete-talent-tag/{tag_id}`
-- **方法:** `DELETE`
-
-### 路径参数
-
-| 参数名 | 类型    | 描述           |
-|--------|---------|---------------|
-| tag_id | Integer | 要删除的标签ID |
-
-### 请求参数
-
-无
-
-### 响应参数
-
-| 参数名      | 类型    | 描述                               |
-|------------|---------|-----------------------------------|
-| success    | Boolean | 操作是否成功                       |
-| message    | String  | 操作结果描述                       |
-| code       | Integer | 状态码                             |
-| data       | Object  | 被删除的标签信息                   |
-
-### 响应示例 - 成功
-
-```json
-{
-  "success": true,
-  "message": "人才标签删除成功",
-  "code": 200,
-  "data": {
-    "id": 12345,
-    "name": "高级Java开发",
-    "en_name": "Senior Java Development",
-    "category": "技术能力/人才",
-    "description": "精通Java编程语言和相关框架,有丰富的项目经验",
-    "status": "active",
-    "time": "2023-07-21 09:45:30"
-  }
-}
-```
-
-### 响应示例 - 失败
-
-```json
-{
-  "success": false,
-  "message": "未找到ID为12345的标签",
-  "code": 404,
-  "data": null
-}
-```
-
-### 状态码
-
-| 状态码 | 描述                 |
-|--------|---------------------|
-| 200    | 请求成功             |
-| 404    | 标签不存在           |
-| 500    | 服务器内部错误       |
-
----
-
-## 开发注意事项
-
-1. 所有请求和响应的 Content-Type 均为 `application/json`。
-2. 创建标签时,name 字段为必填,其他字段可选。
-3. 更新标签时,至少需要提供一个要更新的属性。
-4. 删除标签时会同时删除该标签与其他节点之间的所有关系。
-5. 英文名称(en_name)会根据中文名称自动生成,无需手动提供。 

+ 0 - 840
酒店职位和品牌_API使用手册.md

@@ -1,840 +0,0 @@
-# 酒店数据管理系统 API 操作说明书
-
-## 概述
-
-本文档详细描述了酒店数据管理系统中 `hotel_positions`(酒店职位)和 `hotel_group_brands`(酒店集团品牌)两个数据表的完整CRUD操作API接口。
-
-### 基础信息
-- **API基础URL**: `/api/data-parse`
-- **数据格式**: JSON
-- **字符编码**: UTF-8
-- **时间格式**: `YYYY-MM-DD HH:MM:SS`
-
-### 通用返回格式
-所有API接口都遵循统一的返回格式:
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "操作成功信息",
-    "data": "具体数据内容"
-}
-```
-
-### HTTP状态码说明
-| 状态码 | 含义 | 说明 |
-|--------|------|------|
-| 200 | OK | 请求成功 |
-| 201 | Created | 资源创建成功 |
-| 400 | Bad Request | 请求参数错误 |
-| 404 | Not Found | 资源不存在 |
-| 409 | Conflict | 资源冲突(重复) |
-| 500 | Internal Server Error | 服务器内部错误 |
-
----
-
-## 一、酒店职位管理 API (hotel_positions)
-
-### 1.1 获取所有职位记录
-
-#### 基本信息
-- **URL**: `/get-hotel-positions-list`
-- **方法**: `GET`
-- **功能**: 获取酒店职位数据表的全部记录
-
-#### 请求参数
-无需请求参数
-
-#### 响应参数
-| 字段名 | 类型 | 说明 |
-|--------|------|------|
-| code | integer | 响应状态码 |
-| success | boolean | 操作是否成功 |
-| message | string | 响应消息 |
-| data | array | 职位记录数组 |
-| count | integer | 记录总数 |
-
-#### 职位记录字段说明
-| 字段名 | 类型 | 说明 |
-|--------|------|------|
-| id | integer | 主键ID |
-| department_zh | string | 部门中文名称 |
-| department_en | string | 部门英文名称 |
-| position_zh | string | 职位中文名称 |
-| position_en | string | 职位英文名称 |
-| position_abbr | string | 职位英文缩写(可为null) |
-| level_zh | string | 职级中文名称 |
-| level_en | string | 职级英文名称 |
-| created_at | string | 创建时间 |
-| updated_at | string | 更新时间 |
-| created_by | string | 创建者 |
-| updated_by | string | 更新者 |
-| status | string | 状态(active/inactive) |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-GET /api/data-parse/get-hotel-positions-list
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "获取酒店职位列表成功",
-    "data": [
-        {
-            "id": 1,
-            "department_zh": "餐饮部",
-            "department_en": "Food & Beverage Department",
-            "position_zh": "总经理",
-            "position_en": "General Manager",
-            "position_abbr": "GM",
-            "level_zh": "总经理级",
-            "level_en": "General Manager Level",
-            "created_at": "2025-01-19 10:00:00",
-            "updated_at": "2025-01-19 10:00:00",
-            "created_by": "system",
-            "updated_by": "system",
-            "status": "active"
-        }
-    ],
-    "count": 1
-}
-```
-
-### 1.2 新增职位记录
-
-#### 基本信息
-- **URL**: `/add-hotel-positions`
-- **方法**: `POST`
-- **功能**: 新增酒店职位记录
-
-#### 请求参数
-| 字段名 | 类型 | 必填 | 说明 |
-|--------|------|------|------|
-| department_zh | string | 是 | 部门中文名称 |
-| department_en | string | 是 | 部门英文名称 |
-| position_zh | string | 是 | 职位中文名称 |
-| position_en | string | 是 | 职位英文名称 |
-| position_abbr | string | 否 | 职位英文缩写 |
-| level_zh | string | 是 | 职级中文名称 |
-| level_en | string | 是 | 职级英文名称 |
-| created_by | string | 否 | 创建者(默认system) |
-| updated_by | string | 否 | 更新者(默认system) |
-| status | string | 否 | 状态(默认active) |
-
-#### 响应参数
-同职位记录字段说明
-
-#### 测试样例
-
-**请求示例:**
-```bash
-POST /api/data-parse/add-hotel-positions
-Content-Type: application/json
-
-{
-    "department_zh": "餐饮部",
-    "department_en": "Food & Beverage Department",
-    "position_zh": "副总经理",
-    "position_en": "Deputy General Manager",
-    "position_abbr": "DGM",
-    "level_zh": "总监级",
-    "level_en": "Director Level",
-    "created_by": "admin"
-}
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "酒店职位记录创建成功",
-    "data": {
-        "id": 151,
-        "department_zh": "餐饮部",
-        "department_en": "Food & Beverage Department",
-        "position_zh": "副总经理",
-        "position_en": "Deputy General Manager",
-        "position_abbr": "DGM",
-        "level_zh": "总监级",
-        "level_en": "Director Level",
-        "created_at": "2025-01-19 15:30:00",
-        "updated_at": "2025-01-19 15:30:00",
-        "created_by": "admin",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
-**重复记录错误响应:**
-```json
-{
-    "code": 409,
-    "success": false,
-    "message": "职位记录已存在:餐饮部 - 副总经理",
-    "data": {
-        "id": 100,
-        "department_zh": "餐饮部",
-        "position_zh": "副总经理",
-        "..."
-    }
-}
-```
-
-### 1.3 更新职位记录
-
-#### 基本信息
-- **URL**: `/update-hotel-positions/<int:position_id>`
-- **方法**: `PUT`
-- **功能**: 更新指定ID的职位记录
-
-#### 路径参数
-| 参数名 | 类型 | 说明 |
-|--------|------|------|
-| position_id | integer | 职位记录ID |
-
-#### 请求参数
-| 字段名 | 类型 | 必填 | 说明 |
-|--------|------|------|------|
-| department_zh | string | 否 | 部门中文名称 |
-| department_en | string | 否 | 部门英文名称 |
-| position_zh | string | 否 | 职位中文名称 |
-| position_en | string | 否 | 职位英文名称 |
-| position_abbr | string | 否 | 职位英文缩写 |
-| level_zh | string | 否 | 职级中文名称 |
-| level_en | string | 否 | 职级英文名称 |
-| updated_by | string | 否 | 更新者 |
-| status | string | 否 | 状态 |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-PUT /api/data-parse/update-hotel-positions/1
-Content-Type: application/json
-
-{
-    "position_abbr": "AGM",
-    "updated_by": "admin"
-}
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "酒店职位记录更新成功",
-    "data": {
-        "id": 1,
-        "department_zh": "餐饮部",
-        "department_en": "Food & Beverage Department",
-        "position_zh": "总经理",
-        "position_en": "General Manager",
-        "position_abbr": "AGM",
-        "level_zh": "总经理级",
-        "level_en": "General Manager Level",
-        "created_at": "2025-01-19 10:00:00",
-        "updated_at": "2025-01-19 16:00:00",
-        "created_by": "system",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
-### 1.4 查询指定职位记录
-
-#### 基本信息
-- **URL**: `/query-hotel-positions/<int:position_id>`
-- **方法**: `GET`
-- **功能**: 根据ID查询指定职位记录
-
-#### 路径参数
-| 参数名 | 类型 | 说明 |
-|--------|------|------|
-| position_id | integer | 职位记录ID |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-GET /api/data-parse/query-hotel-positions/1
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "查找职位记录成功",
-    "data": {
-        "id": 1,
-        "department_zh": "餐饮部",
-        "department_en": "Food & Beverage Department",
-        "position_zh": "总经理",
-        "position_en": "General Manager",
-        "position_abbr": "GM",
-        "level_zh": "总经理级",
-        "level_en": "General Manager Level",
-        "created_at": "2025-01-19 10:00:00",
-        "updated_at": "2025-01-19 15:45:00",
-        "created_by": "system",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
-**记录不存在响应:**
-```json
-{
-    "code": 404,
-    "success": false,
-    "message": "未找到ID为999的职位记录",
-    "data": null
-}
-```
-
-### 1.5 删除职位记录
-
-#### 基本信息
-- **URL**: `/delete-hotel-positions/<int:position_id>`
-- **方法**: `DELETE`
-- **功能**: 删除指定ID的职位记录
-
-#### 路径参数
-| 参数名 | 类型 | 说明 |
-|--------|------|------|
-| position_id | integer | 职位记录ID |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-DELETE /api/data-parse/delete-hotel-positions/1
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "职位记录删除成功",
-    "data": {
-        "id": 1,
-        "department_zh": "餐饮部",
-        "department_en": "Food & Beverage Department",
-        "position_zh": "总经理",
-        "position_en": "General Manager",
-        "position_abbr": "GM",
-        "level_zh": "总经理级",
-        "level_en": "General Manager Level",
-        "created_at": "2025-01-19 10:00:00",
-        "updated_at": "2025-01-19 15:45:00",
-        "created_by": "system",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
----
-
-## 二、酒店集团品牌管理 API (hotel_group_brands)
-
-### 2.1 获取所有品牌记录
-
-#### 基本信息
-- **URL**: `/get-hotel-group-brands-list`
-- **方法**: `GET`
-- **功能**: 获取酒店集团品牌数据表的全部记录
-
-#### 请求参数
-无需请求参数
-
-#### 响应参数
-| 字段名 | 类型 | 说明 |
-|--------|------|------|
-| code | integer | 响应状态码 |
-| success | boolean | 操作是否成功 |
-| message | string | 响应消息 |
-| data | array | 品牌记录数组 |
-| count | integer | 记录总数 |
-
-#### 品牌记录字段说明
-| 字段名 | 类型 | 说明 |
-|--------|------|------|
-| id | integer | 主键ID |
-| group_name_en | string | 集团英文名称 |
-| group_name_zh | string | 集团中文名称 |
-| brand_name_en | string | 品牌英文名称 |
-| brand_name_zh | string | 品牌中文名称 |
-| positioning_level_en | string | 定位级别英文名称 |
-| positioning_level_zh | string | 定位级别中文名称 |
-| created_at | string | 创建时间 |
-| updated_at | string | 更新时间 |
-| created_by | string | 创建者 |
-| updated_by | string | 更新者 |
-| status | string | 状态(active/inactive) |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-GET /api/data-parse/get-hotel-group-brands-list
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "获取酒店集团品牌列表成功",
-    "data": [
-        {
-            "id": 1,
-            "group_name_en": "IHG Hotels & Resorts",
-            "group_name_zh": "洲际酒店集团",
-            "brand_name_en": "InterContinental",
-            "brand_name_zh": "洲际酒店及度假村",
-            "positioning_level_en": "Upper Upscale",
-            "positioning_level_zh": "超高端",
-            "created_at": "2025-01-19 10:00:00",
-            "updated_at": "2025-01-19 10:00:00",
-            "created_by": "system",
-            "updated_by": "system",
-            "status": "active"
-        }
-    ],
-    "count": 1
-}
-```
-
-### 2.2 新增品牌记录
-
-#### 基本信息
-- **URL**: `/add-hotel-group-brands`
-- **方法**: `POST`
-- **功能**: 新增酒店集团品牌记录
-
-#### 请求参数
-| 字段名 | 类型 | 必填 | 说明 |
-|--------|------|------|------|
-| group_name_en | string | 是 | 集团英文名称 |
-| group_name_zh | string | 是 | 集团中文名称 |
-| brand_name_en | string | 是 | 品牌英文名称 |
-| brand_name_zh | string | 是 | 品牌中文名称 |
-| positioning_level_en | string | 是 | 定位级别英文名称 |
-| positioning_level_zh | string | 是 | 定位级别中文名称 |
-| created_by | string | 否 | 创建者(默认system) |
-| updated_by | string | 否 | 更新者(默认system) |
-| status | string | 否 | 状态(默认active) |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-POST /api/data-parse/add-hotel-group-brands
-Content-Type: application/json
-
-{
-    "group_name_en": "Marriott International",
-    "group_name_zh": "万豪国际",
-    "brand_name_en": "The Ritz-Carlton",
-    "brand_name_zh": "丽思卡尔顿",
-    "positioning_level_en": "Luxury",
-    "positioning_level_zh": "奢华型",
-    "created_by": "admin"
-}
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "酒店集团品牌记录创建成功",
-    "data": {
-        "id": 296,
-        "group_name_en": "Marriott International",
-        "group_name_zh": "万豪国际",
-        "brand_name_en": "The Ritz-Carlton",
-        "brand_name_zh": "丽思卡尔顿",
-        "positioning_level_en": "Luxury",
-        "positioning_level_zh": "奢华型",
-        "created_at": "2025-01-19 16:00:00",
-        "updated_at": "2025-01-19 16:00:00",
-        "created_by": "admin",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
-**重复记录错误响应:**
-```json
-{
-    "code": 409,
-    "success": false,
-    "message": "品牌记录已存在:万豪国际 - 丽思卡尔顿",
-    "data": {
-        "id": 200,
-        "group_name_zh": "万豪国际",
-        "brand_name_zh": "丽思卡尔顿",
-        "..."
-    }
-}
-```
-
-### 2.3 更新品牌记录
-
-#### 基本信息
-- **URL**: `/update-hotel-group-brands/<int:brand_id>`
-- **方法**: `PUT`
-- **功能**: 更新指定ID的品牌记录
-
-#### 路径参数
-| 参数名 | 类型 | 说明 |
-|--------|------|------|
-| brand_id | integer | 品牌记录ID |
-
-#### 请求参数
-| 字段名 | 类型 | 必填 | 说明 |
-|--------|------|------|------|
-| group_name_en | string | 否 | 集团英文名称 |
-| group_name_zh | string | 否 | 集团中文名称 |
-| brand_name_en | string | 否 | 品牌英文名称 |
-| brand_name_zh | string | 否 | 品牌中文名称 |
-| positioning_level_en | string | 否 | 定位级别英文名称 |
-| positioning_level_zh | string | 否 | 定位级别中文名称 |
-| updated_by | string | 否 | 更新者 |
-| status | string | 否 | 状态 |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-PUT /api/data-parse/update-hotel-group-brands/1
-Content-Type: application/json
-
-{
-    "positioning_level_en": "Luxury",
-    "positioning_level_zh": "奢华型",
-    "updated_by": "admin"
-}
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "酒店集团品牌记录更新成功",
-    "data": {
-        "id": 1,
-        "group_name_en": "IHG Hotels & Resorts",
-        "group_name_zh": "洲际酒店集团",
-        "brand_name_en": "InterContinental",
-        "brand_name_zh": "洲际酒店及度假村",
-        "positioning_level_en": "Luxury",
-        "positioning_level_zh": "奢华型",
-        "created_at": "2025-01-19 10:00:00",
-        "updated_at": "2025-01-19 16:30:00",
-        "created_by": "system",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
-### 2.4 查询指定品牌记录
-
-#### 基本信息
-- **URL**: `/query-hotel-group-brands/<int:brand_id>`
-- **方法**: `GET`
-- **功能**: 根据ID查询指定品牌记录
-
-#### 路径参数
-| 参数名 | 类型 | 说明 |
-|--------|------|------|
-| brand_id | integer | 品牌记录ID |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-GET /api/data-parse/query-hotel-group-brands/1
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "查找品牌记录成功",
-    "data": {
-        "id": 1,
-        "group_name_en": "IHG Hotels & Resorts",
-        "group_name_zh": "洲际酒店集团",
-        "brand_name_en": "InterContinental",
-        "brand_name_zh": "洲际酒店及度假村",
-        "positioning_level_en": "Upper Upscale",
-        "positioning_level_zh": "超高端",
-        "created_at": "2025-01-19 10:00:00",
-        "updated_at": "2025-01-19 16:30:00",
-        "created_by": "system",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
-**记录不存在响应:**
-```json
-{
-    "code": 404,
-    "success": false,
-    "message": "未找到ID为999的品牌记录",
-    "data": null
-}
-```
-
-### 2.5 删除品牌记录
-
-#### 基本信息
-- **URL**: `/delete-hotel-group-brands/<int:brand_id>`
-- **方法**: `DELETE`
-- **功能**: 删除指定ID的品牌记录
-
-#### 路径参数
-| 参数名 | 类型 | 说明 |
-|--------|------|------|
-| brand_id | integer | 品牌记录ID |
-
-#### 测试样例
-
-**请求示例:**
-```bash
-DELETE /api/data-parse/delete-hotel-group-brands/1
-```
-
-**成功响应示例:**
-```json
-{
-    "code": 200,
-    "success": true,
-    "message": "品牌记录删除成功",
-    "data": {
-        "id": 1,
-        "group_name_en": "IHG Hotels & Resorts",
-        "group_name_zh": "洲际酒店集团",
-        "brand_name_en": "InterContinental",
-        "brand_name_zh": "洲际酒店及度假村",
-        "positioning_level_en": "Upper Upscale",
-        "positioning_level_zh": "超高端",
-        "created_at": "2025-01-19 10:00:00",
-        "updated_at": "2025-01-19 16:30:00",
-        "created_by": "system",
-        "updated_by": "admin",
-        "status": "active"
-    }
-}
-```
-
----
-
-## 三、错误处理
-
-### 3.1 常见错误场景
-
-#### 缺少必填字段
-```json
-{
-    "code": 400,
-    "success": false,
-    "message": "缺少必填字段: department_zh, position_zh",
-    "data": null
-}
-```
-
-#### 记录不存在
-```json
-{
-    "code": 404,
-    "success": false,
-    "message": "未找到ID为999的职位记录",
-    "data": null
-}
-```
-
-#### 记录重复冲突
-```json
-{
-    "code": 409,
-    "success": false,
-    "message": "职位记录已存在:餐饮部 - 总经理",
-    "data": {
-        "id": 1,
-        "department_zh": "餐饮部",
-        "position_zh": "总经理",
-        "..."
-    }
-}
-```
-
-#### 服务器内部错误
-```json
-{
-    "code": 500,
-    "success": false,
-    "message": "创建酒店职位记录失败: 数据库连接超时",
-    "data": null
-}
-```
-
-### 3.2 错误处理建议
-
-1. **检查HTTP状态码**: 首先检查HTTP响应状态码
-2. **解析响应JSON**: 获取详细的错误信息
-3. **根据code字段处理**: 根据响应中的code字段进行相应处理
-4. **显示用户友好错误信息**: 将技术错误转换为用户可理解的提示
-
----
-
-## 四、最佳实践
-
-### 4.1 API调用建议
-
-1. **设置合适的超时时间**: 建议设置30秒的请求超时
-2. **处理网络异常**: 实现重试机制,最多重试3次
-3. **验证输入参数**: 在发送请求前验证必填字段
-4. **缓存查询结果**: 对于列表查询,可以实现客户端缓存
-
-### 4.2 数据处理建议
-
-1. **字符串去除空格**: 所有字符串字段会自动去除前后空格
-2. **唯一性检查**: 
-   - 职位表:基于部门中文名称+职位中文名称
-   - 品牌表:基于集团中文名称+品牌中文名称
-3. **状态管理**: 记录状态默认为"active",可设置为"inactive"进行软删除
-
-### 4.3 安全建议
-
-1. **输入验证**: 所有输入都会进行服务端验证
-2. **SQL注入防护**: 使用ORM框架防止SQL注入
-3. **日志记录**: 所有操作都会记录详细日志
-4. **权限控制**: 建议在业务层实现用户权限验证
-
----
-
-## 五、测试工具推荐
-
-### 5.1 Postman测试集合
-
-可以导入以下Postman集合来快速测试所有API接口:
-
-```json
-{
-    "info": {
-        "name": "酒店数据管理API",
-        "description": "酒店职位和集团品牌管理API测试集合"
-    },
-    "item": [
-        {
-            "name": "获取所有职位",
-            "request": {
-                "method": "GET",
-                "url": "{{baseUrl}}/api/data-parse/get-hotel-positions-list"
-            }
-        },
-        {
-            "name": "新增职位",
-            "request": {
-                "method": "POST",
-                "url": "{{baseUrl}}/api/data-parse/add-hotel-positions",
-                "header": [
-                    {
-                        "key": "Content-Type",
-                        "value": "application/json"
-                    }
-                ],
-                "body": {
-                    "raw": "{\n    \"department_zh\": \"餐饮部\",\n    \"department_en\": \"Food & Beverage Department\",\n    \"position_zh\": \"副总经理\",\n    \"position_en\": \"Deputy General Manager\",\n    \"position_abbr\": \"DGM\",\n    \"level_zh\": \"总监级\",\n    \"level_en\": \"Director Level\"\n}"
-                }
-            }
-        }
-    ]
-}
-```
-
-### 5.2 cURL命令示例
-
-#### 获取职位列表
-```bash
-curl -X GET "http://localhost:5000/api/data-parse/get-hotel-positions-list" \
-  -H "Content-Type: application/json"
-```
-
-#### 新增职位记录
-```bash
-curl -X POST "http://localhost:5000/api/data-parse/add-hotel-positions" \
-  -H "Content-Type: application/json" \
-  -d '{
-    "department_zh": "餐饮部",
-    "department_en": "Food & Beverage Department",
-    "position_zh": "副总经理",
-    "position_en": "Deputy General Manager",
-    "position_abbr": "DGM",
-    "level_zh": "总监级",
-    "level_en": "Director Level"
-  }'
-```
-
----
-
-## 附录
-
-### A. 数据字典
-
-#### A.1 部门列表(参考)
-- 餐饮部 / Food & Beverage Department
-- 房务部 / Housekeeping Department
-- 市场销售部 / Sales & Marketing Department
-- 人力资源部 / Human Resources Department
-- 财务部 / Finance Department
-- 行政办公室 / Administrative Office
-- 工程部 / Engineering Department
-- 水疗部 / Spa Department
-- 保安部 / Security Department
-
-#### A.2 职级列表(参考)
-- 经理级 / Manager Level
-- 总监级 / Director Level
-- 总经理级 / General Manager Level
-
-#### A.3 定位级别列表(参考)
-- 奢华型 / Luxury
-- 超高端 / Upper Upscale
-- 高端 / Upscale
-- 中高端 / Upper Midscale
-- 中端 / Midscale
-- 经济型 / Economy
-
-### B. 版本历史
-
-| 版本 | 日期 | 修改内容 | 作者 |
-|------|------|----------|------|
-| 1.0 | 2025-01-19 | 初始版本,包含完整CRUD API | 系统 |
-
----
-
-**文档结束**
-
-> 如有疑问或需要技术支持,请联系开发团队。