Compare commits
2 Commits
cf71fabef0
...
8024c38c32
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8024c38c32 | ||
|
|
8bfd5aa3de |
@@ -103,7 +103,7 @@ class DashboardService:
|
|||||||
try:
|
try:
|
||||||
result = await self.db.execute(
|
result = await self.db.execute(
|
||||||
select(func.coalesce(func.sum(TrainingSession.duration_seconds), 0))
|
select(func.coalesce(func.sum(TrainingSession.duration_seconds), 0))
|
||||||
.where(TrainingSession.status == 'COMPLETED')
|
.where(TrainingSession.status == 'completed') # 修复: 使用小写
|
||||||
)
|
)
|
||||||
training_hours = (result.scalar() or 0) / 3600
|
training_hours = (result.scalar() or 0) / 3600
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -611,7 +611,7 @@ class EmployeeSyncService:
|
|||||||
"""
|
"""
|
||||||
增量同步员工数据
|
增量同步员工数据
|
||||||
- 新增钉钉有但系统没有的员工
|
- 新增钉钉有但系统没有的员工
|
||||||
- 删除系统有但钉钉没有的员工(物理删除)
|
- 删除系统有但钉钉没有的员工(软删除)
|
||||||
- 跳过两边都存在的员工(不做任何修改)
|
- 跳过两边都存在的员工(不做任何修改)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -634,8 +634,22 @@ class EmployeeSyncService:
|
|||||||
try:
|
try:
|
||||||
# 1. 获取钉钉在职员工数据
|
# 1. 获取钉钉在职员工数据
|
||||||
dingtalk_employees = await self.fetch_employees_from_dingtalk()
|
dingtalk_employees = await self.fetch_employees_from_dingtalk()
|
||||||
|
|
||||||
|
# 使用手机号和钉钉ID双重匹配
|
||||||
dingtalk_phones = {emp.get('phone') for emp in dingtalk_employees if emp.get('phone')}
|
dingtalk_phones = {emp.get('phone') for emp in dingtalk_employees if emp.get('phone')}
|
||||||
logger.info(f"钉钉在职员工数量: {len(dingtalk_phones)}")
|
dingtalk_ids = {emp.get('dingtalk_id') for emp in dingtalk_employees if emp.get('dingtalk_id')}
|
||||||
|
|
||||||
|
logger.info(f"钉钉在职员工数量: {len(dingtalk_employees)}")
|
||||||
|
logger.info(f"有手机号的员工: {len(dingtalk_phones)}")
|
||||||
|
logger.info(f"有钉钉ID的员工: {len(dingtalk_ids)}")
|
||||||
|
|
||||||
|
# 安全检查:如果钉钉返回了员工但手机号全为空,可能是权限问题,跳过删除操作
|
||||||
|
skip_delete = False
|
||||||
|
if len(dingtalk_employees) > 0 and len(dingtalk_phones) == 0:
|
||||||
|
logger.warning("⚠️ 钉钉返回员工数据但手机号全为空,可能是钉钉应用缺少手机号读取权限!")
|
||||||
|
logger.warning("⚠️ 跳过离职员工处理,避免误删")
|
||||||
|
skip_delete = True
|
||||||
|
stats['errors'].append("钉钉应用可能缺少手机号读取权限,跳过删除操作")
|
||||||
|
|
||||||
# 2. 获取系统现有用户(排除admin和已软删除的)
|
# 2. 获取系统现有用户(排除admin和已软删除的)
|
||||||
stmt = select(User).where(
|
stmt = select(User).where(
|
||||||
@@ -645,16 +659,26 @@ class EmployeeSyncService:
|
|||||||
result = await self.db.execute(stmt)
|
result = await self.db.execute(stmt)
|
||||||
system_users = result.scalars().all()
|
system_users = result.scalars().all()
|
||||||
system_phones = {user.phone for user in system_users if user.phone}
|
system_phones = {user.phone for user in system_users if user.phone}
|
||||||
logger.info(f"系统现有员工数量(排除admin): {len(system_phones)}")
|
system_dingtalk_ids = {user.dingtalk_id for user in system_users if user.dingtalk_id}
|
||||||
|
logger.info(f"系统现有员工数量(排除admin): {len(system_users)}")
|
||||||
|
logger.info(f"系统有手机号的员工: {len(system_phones)}")
|
||||||
|
logger.info(f"系统有钉钉ID的员工: {len(system_dingtalk_ids)}")
|
||||||
|
|
||||||
# 3. 计算需要新增、删除、跳过的员工
|
# 3. 计算需要新增、删除、跳过的员工(同时考虑手机号和钉钉ID)
|
||||||
|
# 新增: 钉钉有但系统没有(手机号或钉钉ID都不存在)
|
||||||
phones_to_add = dingtalk_phones - system_phones
|
phones_to_add = dingtalk_phones - system_phones
|
||||||
phones_to_delete = system_phones - dingtalk_phones
|
ids_to_add = dingtalk_ids - system_dingtalk_ids
|
||||||
|
|
||||||
|
# 删除: 系统有但钉钉没有(手机号和钉钉ID都不在钉钉列表中)
|
||||||
|
phones_to_delete = system_phones - dingtalk_phones if not skip_delete else set()
|
||||||
|
|
||||||
|
# 跳过: 两边都存在
|
||||||
phones_to_skip = dingtalk_phones & system_phones
|
phones_to_skip = dingtalk_phones & system_phones
|
||||||
|
ids_to_skip = dingtalk_ids & system_dingtalk_ids
|
||||||
|
|
||||||
logger.info(f"待新增: {len(phones_to_add)}, 待删除: {len(phones_to_delete)}, 跳过: {len(phones_to_skip)}")
|
logger.info(f"待新增(手机号): {len(phones_to_add)}, 待删除(手机号): {len(phones_to_delete)}, 跳过(手机号): {len(phones_to_skip)}")
|
||||||
|
|
||||||
stats['skipped_count'] = len(phones_to_skip)
|
stats['skipped_count'] = len(phones_to_skip) + len(ids_to_skip)
|
||||||
|
|
||||||
# 4. 新增员工
|
# 4. 新增员工
|
||||||
for employee in dingtalk_employees:
|
for employee in dingtalk_employees:
|
||||||
@@ -724,12 +748,29 @@ class EmployeeSyncService:
|
|||||||
# 先flush之前的新增操作
|
# 先flush之前的新增操作
|
||||||
await self.db.flush()
|
await self.db.flush()
|
||||||
|
|
||||||
# 标记离职员工
|
# 如果跳过删除,则不处理
|
||||||
for user in system_users:
|
if skip_delete:
|
||||||
if user.phone and user.phone in phones_to_delete:
|
logger.info("⚠️ 由于安全检查未通过,跳过离职员工处理")
|
||||||
|
else:
|
||||||
|
# 标记离职员工(需要手机号和钉钉ID都不在钉钉列表中才删除)
|
||||||
|
for user in system_users:
|
||||||
# 双重保护:确保不删除admin
|
# 双重保护:确保不删除admin
|
||||||
if user.username == 'admin' or user.role == 'admin':
|
if user.username == 'admin' or user.role == 'admin':
|
||||||
logger.warning(f"⚠️ 跳过处理管理员账户: {user.username}")
|
continue
|
||||||
|
|
||||||
|
# 检查用户是否在钉钉列表中(手机号或钉钉ID匹配任一即视为在职)
|
||||||
|
in_dingtalk = False
|
||||||
|
if user.phone and user.phone in dingtalk_phones:
|
||||||
|
in_dingtalk = True
|
||||||
|
if user.dingtalk_id and user.dingtalk_id in dingtalk_ids:
|
||||||
|
in_dingtalk = True
|
||||||
|
|
||||||
|
if in_dingtalk:
|
||||||
|
continue # 在钉钉中,跳过
|
||||||
|
|
||||||
|
# 额外安全检查:如果钉钉没有返回有效数据,不删除
|
||||||
|
if len(dingtalk_phones) == 0 and len(dingtalk_ids) == 0:
|
||||||
|
logger.warning(f"⚠️ 钉钉数据为空,跳过删除用户: {user.full_name}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user