- 全量同步 (sync_employees) 现在会检测并软删除离职员工 - 增量同步改为软删除而非物理删除,更安全 - 离职处理:设置 is_active=False, is_deleted=True - 前端显示离职处理数量统计
This commit is contained in:
@@ -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}秒")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user