feat: 员工同步增加离职处理功能
Some checks failed
continuous-integration/drone/push Build is failing

- 全量同步 (sync_employees) 现在会检测并软删除离职员工
- 增量同步改为软删除而非物理删除,更安全
- 离职处理:设置 is_active=False, is_deleted=True
- 前端显示离职处理数量统计
This commit is contained in:
yuliang_guo
2026-01-31 18:10:45 +08:00
parent e5dd6f3acb
commit 506e9ea2e2
2 changed files with 53 additions and 44 deletions

View File

@@ -333,6 +333,7 @@ class EmployeeSyncService:
'users_created': 0,
'users_existing': 0,
'users_restored': 0,
'users_departed': 0,
'users_skipped': 0,
'teams_created': 0,
'positions_created': 0,
@@ -408,7 +409,29 @@ class EmployeeSyncService:
stats['errors'].append(error_msg)
continue
# 3. 提交所有更改
# 3. 处理离职员工(软删除)
dingtalk_phones = {emp.get('phone') for emp in employees if emp.get('phone')}
# 获取系统中所有活跃用户(排除 admin
stmt = select(User).where(
User.is_deleted == False,
User.is_active == True,
User.username != 'admin',
User.role != 'admin'
)
result = await self.db.execute(stmt)
system_users = result.scalars().all()
# 找出离职员工(系统有但钉钉没有)
for user in system_users:
if user.phone and user.phone not in dingtalk_phones:
# 软删除:标记为离职
user.is_active = False
user.is_deleted = True
stats['users_departed'] += 1
logger.info(f"🚪 标记离职员工: {user.full_name} ({user.phone})")
# 4. 提交所有更改
await self.db.commit()
logger.info("✅ 数据库事务已提交")
@@ -422,14 +445,15 @@ class EmployeeSyncService:
stats['end_time'] = datetime.now()
stats['duration'] = (stats['end_time'] - stats['start_time']).total_seconds()
# 4. 输出统计信息
# 5. 输出统计信息
logger.info("=" * 60)
logger.info("同步完成统计")
logger.info("=" * 60)
logger.info(f"员工: {stats['total_employees']}")
logger.info(f"钉钉在职员工: {stats['total_employees']}")
logger.info(f"新增用户: {stats['users_created']}")
logger.info(f"已存在用户: {stats['users_existing']}")
logger.info(f"恢复用户: {stats['users_restored']}")
logger.info(f"离职处理: {stats['users_departed']}")
logger.info(f"跳过用户: {stats['users_skipped']}")
logger.info(f"耗时: {stats['duration']:.2f}")
@@ -696,50 +720,33 @@ class EmployeeSyncService:
stats['errors'].append(error_msg)
continue
# 5. 删除离职员工(物理删除)
# 先flush之前的新增操作,避免与删除操作冲突
# 5. 处理离职员工(删除)
# 先flush之前的新增操作
await self.db.flush()
# 收集需要删除的用户ID
users_to_delete = []
# 标记离职员工
for user in system_users:
if user.phone and user.phone in phones_to_delete:
# 双重保护确保不删除admin
if user.username == 'admin' or user.role == 'admin':
logger.warning(f"⚠️ 跳过删除管理员账户: {user.username}")
logger.warning(f"⚠️ 跳过处理管理员账户: {user.username}")
continue
users_to_delete.append({
'id': user.id,
try:
# 软删除:标记为离职
user.is_active = False
user.is_deleted = True
stats['deleted_users'].append({
'full_name': user.full_name,
'phone': user.phone,
'username': user.username
})
# 批量删除用户及其关联数据
for user_info in users_to_delete:
try:
user_id = user_info['id']
# 先清理关联数据(外键约束)
await self._cleanup_user_related_data(user_id)
# 用SQL直接删除用户避免ORM的级联操作冲突
await self.db.execute(
text("DELETE FROM users WHERE id = :user_id"),
{"user_id": user_id}
)
stats['deleted_users'].append({
'full_name': user_info['full_name'],
'phone': user_info['phone'],
'username': user_info['username']
})
stats['deleted_count'] += 1
logger.info(f"🗑️ 删除离职员工: {user_info['full_name']} ({user_info['phone']})")
logger.info(f"🚪 标记离职员工: {user.full_name} ({user.phone})")
except Exception as e:
error_msg = f"删除员工 {user_info['full_name']} 失败: {str(e)}"
error_msg = f"处理离职员工 {user.full_name} 失败: {str(e)}"
logger.error(error_msg)
stats['errors'].append(error_msg)
continue
@@ -763,7 +770,7 @@ class EmployeeSyncService:
logger.info("增量同步完成统计")
logger.info("=" * 60)
logger.info(f"新增员工: {stats['added_count']}")
logger.info(f"删除员工: {stats['deleted_count']}")
logger.info(f"离职处理: {stats['deleted_count']}")
logger.info(f"跳过员工: {stats['skipped_count']}")
logger.info(f"耗时: {stats['duration']:.2f}")

View File

@@ -348,12 +348,14 @@ const triggerSync = async () => {
const created = data.users_created || 0
const existing = data.users_existing || 0
const restored = data.users_restored || 0
const departed = data.users_departed || 0
const skipped = data.users_skipped || 0
let msg = `同步完成!共处理 ${data.total_employees || 0} 名员工`
let msg = `同步完成!钉钉在职 ${data.total_employees || 0} `
if (created > 0) msg += `,新增 ${created}`
if (existing > 0) msg += `,已存在 ${existing}`
if (restored > 0) msg += `,恢复 ${restored}`
if (departed > 0) msg += `,离职 ${departed}`
if (skipped > 0) msg += `,跳过 ${skipped}`
ElMessage.success(msg)