- 新增 dingtalk_service.py 调用钉钉开放API - 支持获取 Access Token、部门列表、员工列表 - employee_sync_service 改为从钉钉API获取员工 - 前端配置界面支持配置 CorpId、ClientId、ClientSecret - 移除外部数据库表依赖
This commit is contained in:
@@ -41,13 +41,10 @@ class DingtalkConfigResponse(BaseModel):
|
||||
|
||||
|
||||
class EmployeeSyncConfigUpdate(BaseModel):
|
||||
"""员工同步配置更新请求"""
|
||||
db_host: Optional[str] = Field(None, description="数据库主机")
|
||||
db_port: Optional[int] = Field(None, description="数据库端口")
|
||||
db_name: Optional[str] = Field(None, description="数据库名")
|
||||
db_user: Optional[str] = Field(None, description="数据库用户名")
|
||||
db_password: Optional[str] = Field(None, description="数据库密码")
|
||||
table_name: Optional[str] = Field(None, description="员工表/视图名称")
|
||||
"""员工同步配置更新请求(钉钉 API 方式)"""
|
||||
corp_id: Optional[str] = Field(None, description="钉钉企业 CorpId")
|
||||
client_id: Optional[str] = Field(None, description="应用 ClientId (AppKey)")
|
||||
client_secret: Optional[str] = Field(None, description="应用 ClientSecret (AppSecret)")
|
||||
enabled: Optional[bool] = Field(None, description="是否启用自动同步")
|
||||
|
||||
|
||||
@@ -294,30 +291,39 @@ async def get_employee_sync_config(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> ResponseModel:
|
||||
"""
|
||||
获取员工同步配置
|
||||
获取员工同步配置(钉钉 API 方式)
|
||||
|
||||
仅限管理员访问
|
||||
数据库连接从环境变量读取,前端只能配置表名和开关
|
||||
"""
|
||||
check_admin_permission(current_user)
|
||||
|
||||
import os
|
||||
tenant_id = await get_or_create_tenant_id(db)
|
||||
|
||||
# 从数据库获取表名和开关配置
|
||||
table_name = await get_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME')
|
||||
# 从数据库获取钉钉 API 配置
|
||||
corp_id = await get_system_config(db, tenant_id, 'employee_sync', 'CORP_ID')
|
||||
client_id = await get_system_config(db, tenant_id, 'employee_sync', 'CLIENT_ID')
|
||||
client_secret = await get_system_config(db, tenant_id, 'employee_sync', 'CLIENT_SECRET')
|
||||
enabled = await get_feature_switch(db, tenant_id, 'employee_sync')
|
||||
|
||||
# 从环境变量检查数据源是否已配置
|
||||
sync_db_url = os.environ.get('EMPLOYEE_SYNC_DB_URL', '')
|
||||
configured = bool(sync_db_url)
|
||||
# 脱敏处理 client_secret
|
||||
client_secret_masked = None
|
||||
if client_secret:
|
||||
if len(client_secret) > 8:
|
||||
client_secret_masked = client_secret[:4] + '****' + client_secret[-4:]
|
||||
else:
|
||||
client_secret_masked = '****'
|
||||
|
||||
# 检查配置是否完整
|
||||
configured = bool(corp_id and client_id and client_secret)
|
||||
|
||||
return ResponseModel(
|
||||
message="获取成功",
|
||||
data={
|
||||
"table_name": table_name or "v_钉钉员工表",
|
||||
"corp_id": corp_id,
|
||||
"client_id": client_id,
|
||||
"client_secret_masked": client_secret_masked,
|
||||
"enabled": enabled,
|
||||
"configured": configured, # 数据源是否已在环境变量配置
|
||||
"configured": configured,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -329,18 +335,23 @@ async def update_employee_sync_config(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> ResponseModel:
|
||||
"""
|
||||
更新员工同步配置
|
||||
更新员工同步配置(钉钉 API 方式)
|
||||
|
||||
仅限管理员访问
|
||||
只能配置表名和开关,数据库连接从环境变量读取
|
||||
"""
|
||||
check_admin_permission(current_user)
|
||||
|
||||
tenant_id = await get_or_create_tenant_id(db)
|
||||
|
||||
try:
|
||||
if config.table_name is not None:
|
||||
await set_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME', config.table_name)
|
||||
if config.corp_id is not None:
|
||||
await set_system_config(db, tenant_id, 'employee_sync', 'CORP_ID', config.corp_id)
|
||||
|
||||
if config.client_id is not None:
|
||||
await set_system_config(db, tenant_id, 'employee_sync', 'CLIENT_ID', config.client_id)
|
||||
|
||||
if config.client_secret is not None:
|
||||
await set_system_config(db, tenant_id, 'employee_sync', 'CLIENT_SECRET', config.client_secret)
|
||||
|
||||
if config.enabled is not None:
|
||||
await set_feature_switch(db, tenant_id, 'employee_sync', config.enabled)
|
||||
@@ -370,44 +381,46 @@ async def test_employee_sync_connection(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> ResponseModel:
|
||||
"""
|
||||
测试员工同步数据库连接
|
||||
测试钉钉 API 连接
|
||||
|
||||
仅限管理员访问
|
||||
使用环境变量中的数据库连接配置
|
||||
"""
|
||||
check_admin_permission(current_user)
|
||||
|
||||
import os
|
||||
tenant_id = await get_or_create_tenant_id(db)
|
||||
|
||||
# 从环境变量获取数据库连接
|
||||
sync_db_url = os.environ.get('EMPLOYEE_SYNC_DB_URL', '')
|
||||
# 获取钉钉配置
|
||||
corp_id = await get_system_config(db, tenant_id, 'employee_sync', 'CORP_ID')
|
||||
client_id = await get_system_config(db, tenant_id, 'employee_sync', 'CLIENT_ID')
|
||||
client_secret = await get_system_config(db, tenant_id, 'employee_sync', 'CLIENT_SECRET')
|
||||
|
||||
if not sync_db_url:
|
||||
if not all([corp_id, client_id, client_secret]):
|
||||
return ResponseModel(
|
||||
code=400,
|
||||
message="数据源未配置,请联系系统管理员配置 EMPLOYEE_SYNC_DB_URL 环境变量"
|
||||
message="钉钉 API 配置不完整,请先填写 CorpId、ClientId、ClientSecret"
|
||||
)
|
||||
|
||||
# 获取表名配置
|
||||
table_name = await get_system_config(db, tenant_id, 'employee_sync', 'TABLE_NAME') or "v_钉钉员工表"
|
||||
|
||||
try:
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from app.services.dingtalk_service import DingTalkService
|
||||
|
||||
engine = create_async_engine(sync_db_url, echo=False, pool_pre_ping=True)
|
||||
|
||||
async with engine.connect() as conn:
|
||||
# 测试查询员工表
|
||||
result = await conn.execute(text(f"SELECT COUNT(*) FROM {table_name}"))
|
||||
count = result.scalar()
|
||||
|
||||
await engine.dispose()
|
||||
|
||||
return ResponseModel(
|
||||
message=f"连接成功!员工表共有 {count} 条在职员工",
|
||||
data={"employee_count": count}
|
||||
dingtalk = DingTalkService(
|
||||
corp_id=corp_id,
|
||||
client_id=client_id,
|
||||
client_secret=client_secret
|
||||
)
|
||||
|
||||
result = await dingtalk.test_connection()
|
||||
|
||||
if result["success"]:
|
||||
return ResponseModel(
|
||||
message=f"连接成功!已获取到组织架构",
|
||||
data=result
|
||||
)
|
||||
else:
|
||||
return ResponseModel(
|
||||
code=500,
|
||||
message=result["message"]
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"测试连接失败: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user