Skip to content

通讯录管理

通讯录管理模块提供企业联系人信息的查询、搜索、统计等功能,支持公开访问和管理员操作。

接口概览

公开接口(无需认证)

方法路径描述权限要求
GET/api/v1/public/contacts获取公开通讯录列表
GET/api/v1/public/contacts/{id}获取公开通讯录详情
GET/api/v1/public/contacts/search搜索通讯录
GET/api/v1/public/contacts/stats获取通讯录统计
GET/api/v1/public/departments获取部门列表

管理员接口

方法路径描述权限要求
POST/api/v1/admin/contacts创建通讯录记录管理员
PUT/api/v1/admin/contacts/{id}更新通讯录记录管理员
DELETE/api/v1/admin/contacts/{id}删除通讯录记录管理员
POST/api/v1/admin/contacts/sync/{employee_id}同步员工信息到通讯录管理员
POST/api/v1/admin/contacts/batch-sync批量同步员工信息管理员

获取公开通讯录列表

获取公开的企业通讯录列表,支持分页和筛选。

接口信息

  • URL: /api/v1/public/contacts
  • 方法: GET
  • 认证: 无需认证

查询参数

参数类型必填描述默认值
pageint页码1
page_sizeint每页数量20
departmentstring部门筛选-
searchstring搜索关键词(姓名、职位)-
is_publicbool是否公开(默认公开)true

请求示例

bash
GET /api/v1/public/contacts?page=1&page_size=20&department=技术部&search=

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "获取成功",
  "data": {
    "contacts": [
      {
        "id": 1,
        "name": "张三",
        "position": "技术总监",
        "department": "技术部",
        "email": "zhangsan@company.com",
        "phone": "13800138000",
        "mobile": "13900139000",
        "avatar": "https://example.com/avatar.jpg",
        "office": "A座 1001室",
        "is_public": true,
        "created_at": "2024-01-01T12:00:00Z"
      }
    ],
    "pagination": {
      "page": 1,
      "page_size": 20,
      "total": 1,
      "pages": 1
    }
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

获取公开通讯录详情

获取指定联系人的详细信息。

接口信息

  • URL: /api/v1/public/contacts/{id}
  • 方法: GET
  • 认证: 无需认证

路径参数

参数类型必填描述示例
idint联系人ID1

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "获取成功",
  "data": {
    "id": 1,
    "name": "张三",
    "position": "技术总监",
    "department": "技术部",
    "email": "zhangsan@company.com",
    "phone": "13800138000",
    "mobile": "13900139000",
    "fax": "010-12345678",
    "avatar": "https://example.com/avatar.jpg",
    "office": "A座 1001室",
    "address": "北京市朝阳区xxx街道xxx号",
    "is_public": true,
    "employee_id": 10,
    "company": {
      "id": 1,
      "name": "源丰科技有限公司",
      "logo": "https://example.com/company-logo.png"
    },
    "created_at": "2024-01-01T12:00:00Z",
    "updated_at": "2024-01-01T12:00:00Z"
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

搜索通讯录

在通讯录中搜索联系人。

接口信息

  • URL: /api/v1/public/contacts/search
  • 方法: GET
  • 认证: 无需认证

查询参数

参数类型必填描述默认值
qstring搜索关键词-
pageint页码1
page_sizeint每页数量20
departmentstring部门筛选-

请求示例

bash
GET /api/v1/public/contacts/search?q=技术总监&department=技术部

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "搜索成功",
  "data": {
    "contacts": [
      {
        "id": 1,
        "name": "张三",
        "position": "技术总监",
        "department": "技术部",
        "email": "zhangsan@company.com",
        "phone": "13800138000",
        "is_public": true
      }
    ],
    "pagination": {
      "page": 1,
      "page_size": 20,
      "total": 1,
      "pages": 1
    },
    "search_query": "技术总监"
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

获取通讯录统计

获取通讯录的统计信息。

接口信息

  • URL: /api/v1/public/contacts/stats
  • 方法: GET
  • 认证: 无需认证

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "获取成功",
  "data": {
    "total_contacts": 150,
    "public_contacts": 120,
    "private_contacts": 30,
    "by_department": [
      {
        "department": "技术部",
        "count": 45
      },
      {
        "department": "销售部",
        "count": 35
      },
      {
        "department": "市场部",
        "count": 25
      }
    ],
    "by_position": [
      {
        "position": "工程师",
        "count": 60
      },
      {
        "position": "经理",
        "count": 25
      }
    ]
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

获取部门列表

获取所有部门列表。

接口信息

  • URL: /api/v1/public/departments
  • 方法: GET
  • 认证: 无需认证

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "获取成功",
  "data": {
    "departments": [
      {
        "id": 1,
        "name": "技术部",
        "description": "负责技术研发和系统维护",
        "employee_count": 45
      },
      {
        "id": 2,
        "name": "销售部",
        "description": "负责产品销售和客户关系",
        "employee_count": 35
      },
      {
        "id": 3,
        "name": "市场部",
        "description": "负责市场推广和品牌建设",
        "employee_count": 25
      }
    ]
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

创建通讯录记录(管理员)

管理员创建新的通讯录记录。

接口信息

  • URL: /api/v1/admin/contacts
  • 方法: POST
  • 内容类型: application/json
  • 认证: 需要管理员权限

请求参数

字段类型必填描述示例
namestring联系人姓名"张三"
positionstring职位"技术总监"
departmentstring部门"技术部"
emailstring邮箱地址"zhangsan@company.com"
phonestring办公电话"010-12345678"
mobilestring手机号码"13800138000"
faxstring传真号码"010-87654321"
officestring办公室"A座 1001室"
addressstring办公地址"北京市朝阳区xxx街道xxx号"
is_publicbool是否公开true
employee_idint关联员工ID10

请求示例

json
{
  "name": "张三",
  "position": "技术总监",
  "department": "技术部",
  "email": "zhangsan@company.com",
  "phone": "010-12345678",
  "mobile": "13800138000",
  "office": "A座 1001室",
  "is_public": true,
  "employee_id": 10
}

响应示例

成功响应 (201)

json
{
  "code": 201,
  "message": "创建成功",
  "data": {
    "id": 1,
    "name": "张三",
    "position": "技术总监",
    "department": "技术部",
    "email": "zhangsan@company.com",
    "phone": "010-12345678",
    "mobile": "13800138000",
    "office": "A座 1001室",
    "is_public": true,
    "employee_id": 10,
    "created_at": "2024-01-01T12:00:00Z"
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

同步员工信息到通讯录(管理员)

将员工信息同步到通讯录。

接口信息

  • URL: /api/v1/admin/contacts/sync/{employee_id}
  • 方法: POST
  • 认证: 需要管理员权限

路径参数

参数类型必填描述示例
employee_idint员工ID10

请求参数

字段类型必填描述示例
is_publicbool是否公开true
override_existingbool是否覆盖已存在的记录false

请求示例

json
{
  "is_public": true,
  "override_existing": false
}

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "同步成功",
  "data": {
    "contact_id": 1,
    "employee_id": 10,
    "synced_fields": ["name", "position", "department", "email", "phone"],
    "created": true
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

批量同步员工信息(管理员)

批量将多个员工信息同步到通讯录。

接口信息

  • URL: /api/v1/admin/contacts/batch-sync
  • 方法: POST
  • 内容类型: application/json
  • 认证: 需要管理员权限

请求参数

字段类型必填描述示例
employee_idsint[]员工ID列表[10, 11, 12]
is_publicbool是否公开true
override_existingbool是否覆盖已存在的记录false

请求示例

json
{
  "employee_ids": [10, 11, 12],
  "is_public": true,
  "override_existing": false
}

响应示例

成功响应 (200)

json
{
  "code": 200,
  "message": "批量同步完成",
  "data": {
    "total": 3,
    "success": 3,
    "failed": 0,
    "results": [
      {
        "employee_id": 10,
        "contact_id": 1,
        "status": "success",
        "action": "created"
      },
      {
        "employee_id": 11,
        "contact_id": 2,
        "status": "success",
        "action": "created"
      },
      {
        "employee_id": 12,
        "contact_id": 3,
        "status": "success",
        "action": "created"
      }
    ]
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

数据模型

ContactResponse

typescript
interface ContactResponse {
  id: number;                    // 联系人ID
  name: string;                  // 姓名
  position: string;              // 职位
  department: string;            // 部门
  email?: string;                // 邮箱地址
  phone?: string;                // 办公电话
  mobile?: string;               // 手机号码
  fax?: string;                  // 传真号码
  avatar?: string;               // 头像URL
  office?: string;               // 办公室
  address?: string;              // 办公地址
  is_public: boolean;            // 是否公开
  employee_id?: number;          // 关联员工ID
  company?: CompanyInfo;         // 公司信息
  created_at: string;            // 创建时间
  updated_at: string;            // 更新时间
}

DepartmentResponse

typescript
interface DepartmentResponse {
  id: number;                    // 部门ID
  name: string;                  // 部门名称
  description?: string;          // 部门描述
  employee_count: number;        // 员工数量
}

ContactStats

typescript
interface ContactStats {
  total_contacts: number;        // 总联系人数
  public_contacts: number;       // 公开联系人数
  private_contacts: number;      // 私有联系人数
  by_department: Array<{        // 按部门统计
    department: string;
    count: number;
  }>;
  by_position: Array<{          // 按职位统计
    position: string;
    count: number;
  }>;
}

错误代码

错误代码描述解决方案
400请求参数错误检查请求参数格式和必填字段
401未认证检查 JWT token 是否有效
403无权限确认用户具有管理员权限
404联系人不存在检查联系人ID是否正确
409联系人已存在检查是否重复创建
500服务器内部错误联系系统管理员

集成示例

JavaScript 联系人搜索组件

javascript
import React, { useState, useEffect } from 'react';

const ContactSearch = () => {
  const [contacts, setContacts] = useState([]);
  const [loading, setLoading] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [selectedDepartment, setSelectedDepartment] = useState('');

  const searchContacts = async (query = '', department = '') => {
    setLoading(true);
    try {
      const params = new URLSearchParams();
      if (query) params.append('q', query);
      if (department) params.append('department', department);

      const response = await fetch(`/api/v1/public/contacts/search?${params}`);
      const data = await response.json();

      if (data.code === 200) {
        setContacts(data.data.contacts);
      }
    } catch (error) {
      console.error('搜索失败:', error);
    } finally {
      setLoading(false);
    }
  };

  const getDepartments = async () => {
    try {
      const response = await fetch('/api/v1/public/departments');
      const data = await response.json();
      return data.data.departments;
    } catch (error) {
      console.error('获取部门列表失败:', error);
      return [];
    }
  };

  useEffect(() => {
    searchContacts();
  }, []);

  const handleSearch = () => {
    searchContacts(searchQuery, selectedDepartment);
  };

  return (
    <div className="contact-search">
      <h2>通讯录搜索</h2>

      <div className="search-form">
        <input
          type="text"
          placeholder="搜索联系人..."
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
        />

        <select
          value={selectedDepartment}
          onChange={(e) => setSelectedDepartment(e.target.value)}
        >
          <option value="">所有部门</option>
          {/* 部门选项 */}
        </select>

        <button onClick={handleSearch} disabled={loading}>
          {loading ? '搜索中...' : '搜索'}
        </button>
      </div>

      <div className="contact-list">
        {contacts.map(contact => (
          <div key={contact.id} className="contact-item">
            <div className="contact-avatar">
              {contact.avatar ? (
                <img src={contact.avatar} alt={contact.name} />
              ) : (
                <div className="avatar-placeholder">
                  {contact.name.charAt(0)}
                </div>
              )}
            </div>

            <div className="contact-info">
              <h3>{contact.name}</h3>
              <p className="position">{contact.position}</p>
              <p className="department">{contact.department}</p>

              <div className="contact-details">
                {contact.email && (
                  <div className="detail-item">
                    📧 {contact.email}
                  </div>
                )}
                {contact.phone && (
                  <div className="detail-item">
                    📞 {contact.phone}
                  </div>
                )}
                {contact.mobile && (
                  <div className="detail-item">
                    📱 {contact.mobile}
                  </div>
                )}
                {contact.office && (
                  <div className="detail-item">
                    🏢 {contact.office}
                  </div>
                )}
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

export default ContactSearch;

Python 联系人管理脚本

python
import requests
import csv
from typing import List, Optional, Dict, Any

class ContactManager:
    def __init__(self, base_url: str):
        self.base_url = base_url

    def search_contacts(self, query: str, department: Optional[str] = None,
                       page: int = 1, page_size: int = 20) -> Dict[str, Any]:
        """搜索联系人"""
        params = {
            'q': query,
            'page': page,
            'page_size': page_size
        }
        if department:
            params['department'] = department

        response = requests.get(
            f'{self.base_url}/api/v1/public/contacts/search',
            params=params
        )
        response.raise_for_status()
        return response.json()

    def get_contact_stats(self) -> Dict[str, Any]:
        """获取通讯录统计"""
        response = requests.get(f'{self.base_url}/api/v1/public/contacts/stats')
        response.raise_for_status()
        return response.json()

    def get_departments(self) -> List[Dict[str, Any]]:
        """获取部门列表"""
        response = requests.get(f'{self.base_url}/api/v1/public/departments')
        response.raise_for_status()
        return response.json()['data']['departments']

    def export_contacts_to_csv(self, filename: str, department: Optional[str] = None):
        """导出联系人到CSV文件"""
        all_contacts = []
        page = 1

        while True:
            data = self.search_contacts('', department, page, 100)
            contacts = data['data']['contacts']

            if not contacts:
                break

            all_contacts.extend(contacts)
            page += 1

        # 写入CSV文件
        with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
            if not all_contacts:
                print("没有找到联系人数据")
                return

            fieldnames = ['name', 'position', 'department', 'email', 'phone', 'mobile', 'office']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

            writer.writeheader()
            for contact in all_contacts:
                writer.writerow({
                    'name': contact['name'],
                    'position': contact['position'],
                    'department': contact['department'],
                    'email': contact.get('email', ''),
                    'phone': contact.get('phone', ''),
                    'mobile': contact.get('mobile', ''),
                    'office': contact.get('office', '')
                })

        print(f"已导出 {len(all_contacts)} 个联系人到 {filename}")

# 使用示例
def main():
    contact_manager = ContactManager('http://localhost:8080')

    # 获取统计信息
    stats = contact_manager.get_contact_stats()
    print(f"总联系人数: {stats['data']['total_contacts']}")
    print(f"公开联系人: {stats['data']['public_contacts']}")

    # 搜索技术部的联系人
    tech_contacts = contact_manager.search_contacts('', '技术部')
    print(f"技术部联系人: {len(tech_contacts['data']['contacts'])}")

    # 导出联系人到CSV
    contact_manager.export_contacts_to_csv('contacts.csv')

if __name__ == '__main__':
    main()

相关链接

基于 MIT 许可发布