Files
ljwx-health/ljwx-bigscreen/app/services/org.py
T
2025-12-19 19:29:14 +08:00

887 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import logging
from flask import jsonify, session, request, abort, json
from werkzeug.exceptions import NotFound
from app.models import db, OrgInfo, UserOrg, UserInfo, Position, UserPosition, DeviceInfo
# tenant_context removed - customerId now passed as parameter
from collections import defaultdict
from sqlalchemy import text, and_, or_
# 导入组织架构优化查询服务
from .org_optimized import get_org_service
from .org_service import get_unified_org_service
# Configure logging
logging.basicConfig(filename='org.log', level=logging.INFO,
format='%(asctime)s %(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
def fetch_departments_by_orgId(org_id, customer_id=None):
"""递归获取组织下的所有部门信息,包括当前组织,支持多租户隔离"""
try:
# 如果没有提供customer_id,尝试从请求获取
if customer_id is None:
try:
customer_id = request.args.get('customerId', None, type=int)
except RuntimeError:
# 在没有Flask上下文时,不设置默认customer_id,让查询逻辑根据org_id自动处理
customer_id = None
logger.info("无Flask上下文,不设置默认customer_id,将根据org_id查询")
logger.info(f"查询组织部门: org_id={org_id}, customer_id={customer_id}")
def get_child_departments(parent_id, customer_id=None):
query = db.session.query(OrgInfo)\
.filter(OrgInfo.parent_id == parent_id)\
.filter(OrgInfo.is_deleted.is_(False))
# 🔧 修复:简化子部门查询逻辑
if customer_id is not None:
# 如果提供了customer_id,先尝试严格匹配
strict_departments = query.filter(OrgInfo.customer_id == customer_id).all()
if strict_departments:
departments = strict_departments
else:
# 如果严格匹配没有结果,可能是组织结构层次问题,获取所有子部门但验证有效性
all_departments = query.all()
departments = []
for dept in all_departments:
# 检查该部门是否属于指定客户(通过ID或customer_id字段)
if (str(dept.id) == str(customer_id) or
(dept.customer_id and str(dept.customer_id) == str(customer_id)) or
str(parent_id) == str(customer_id)):
departments.append(dept)
# 如果仍然没有结果,为了兼容性,返回所有子部门
if not departments:
departments = all_departments
else:
# customer_id为None时,直接查询所有子部门,不做customer_id过滤
departments = query.all()
departments_data = []
for dept in departments:
dept_data = {
'id': str(dept.id),
'name': dept.name,
'parent_id': str(dept.parent_id),
'create_time': dept.create_time.strftime('%Y-%m-%d %H:%M:%S') if dept.create_time else None
}
# 递归获取子部门
child_departments = get_child_departments(dept.id, customer_id)
if child_departments:
dept_data['children'] = child_departments
departments_data.append(dept_data)
return departments_data
# 先获取当前组织的信息,支持租户隔离
query = db.session.query(OrgInfo)\
.filter(OrgInfo.id == org_id)\
.filter(OrgInfo.is_deleted.is_(False))
logger.info(f"🔍 查询组织: org_id={org_id}, customer_id={customer_id}")
# 🔧 修复:简化查询逻辑,优先根据org_id查询
if customer_id is not None:
# 尝试多种查询策略
# 策略1:直接customer_id匹配
current_org = query.filter(OrgInfo.customer_id == customer_id).first()
# 策略2:如果没找到,可能该组织本身就是客户根组织
if not current_org:
current_org = query.first()
# 验证是否为该客户的根组织或子组织
if current_org and str(current_org.id) == str(customer_id):
# 该组织ID就是客户ID,这是有效的
pass
elif current_org:
# 检查是否为该客户下的子组织(通过parent_id链条)
temp_org = current_org
is_valid_org = False
depth = 0
while temp_org and depth < 10: # 防止死循环
if str(temp_org.id) == str(customer_id) or (temp_org.customer_id and str(temp_org.customer_id) == str(customer_id)):
is_valid_org = True
break
if temp_org.parent_id:
temp_org = db.session.query(OrgInfo).filter(OrgInfo.id == temp_org.parent_id, OrgInfo.is_deleted.is_(False)).first()
else:
break
depth += 1
if not is_valid_org:
current_org = None
else:
# customer_id为None时,直接根据org_id查询,不做customer_id过滤
current_org = query.first()
logger.info(f"🔍 customer_id为None,直接根据org_id查询: org_id={org_id}, found_org={current_org.name if current_org else 'None'}")
if not current_org:
logger.warning(f"❌ Organization not found: {org_id}, customer_id: {customer_id}")
# 添加更详细的调试信息
all_orgs = db.session.query(OrgInfo).filter(OrgInfo.id == org_id).all()
logger.info(f"🔍 所有匹配ID的组织(包括已删除): {len(all_orgs)}")
for org in all_orgs:
logger.info(f" - ID: {org.id}, Name: {org.name}, is_deleted: {org.is_deleted}, customer_id: {getattr(org, 'customer_id', 'N/A')}")
return {
'success': False,
'error': f'Organization not found: {org_id}'
}
# 构建包含当前组织的树结构
root_data = {
'id': str(current_org.id),
'name': current_org.name,
'parent_id': str(current_org.parent_id) if current_org.parent_id else None,
'create_time': current_org.create_time.strftime('%Y-%m-%d %H:%M:%S') if current_org.create_time else None,
'children': get_child_departments(org_id, customer_id)
}
return {
'success': True,
'data': [root_data] # 返回包含根节点的数组
}
except Exception as e:
logger.error(f"Error in fetch_departments_by_orgId: {str(e)}")
return {
'success': False,
'error': str(e)
}
def fetch_users_by_orgId(org_id, customer_id=None):
"""获取组织及其所有子部门下的用户信息,支持多租户隔离 - 增强回退版本"""
try:
# 🔧 修复:增加多重查询策略
# 方法1:使用统一服务查询部门
org_response = fetch_departments_by_orgId(org_id, customer_id)
if not org_response.get('success'):
logger.warning(f"统一服务查询部门失败,尝试直接数据库查询用户")
return fetch_users_by_orgId_direct(org_id, customer_id)
# 方法2:基于部门结果查询用户
users = _fetch_users_from_departments(org_response, org_id, customer_id)
if users and len(users) > 0:
logger.info(f"基于部门树查询成功: 组织{org_id}找到{len(users)}个用户")
return users
# 方法3:直接数据库查询(绕过统一服务)
logger.warning(f"部门树查询无用户结果,尝试直接数据库查询")
users_direct = fetch_users_by_orgId_direct(org_id, customer_id)
if users_direct and len(users_direct) > 0:
logger.info(f"直接数据库查询成功: 组织{org_id}找到{len(users_direct)}个用户")
return users_direct
# 方法4:扩大查询范围(包含子组织)
logger.warning(f"直接查询也无结果,尝试查询子组织")
users_expanded = fetch_users_with_descendants(org_id, customer_id)
logger.info(f"扩展查询结果: 组织{org_id}及子组织找到{len(users_expanded)}个用户")
return users_expanded
except Exception as e:
logger.error(f"所有用户查询方法均失败: {str(e)}")
return []
def _fetch_users_from_departments(org_response, org_id, customer_id):
"""基于部门树结果查询用户"""
try:
# 获取组织及其所有子部门
#logger.info(f"fetch_users_by_orgId:org_response: {org_response}")
#print("fetch_users_by_orgId:org_response:", org_response)
# 收集所有部门ID(包括子部门)
department_ids = set()
def collect_dept_ids(dept_data):
department_ids.add(dept_data['id'])
for child in dept_data.get('children', []):
collect_dept_ids(child)
# 处理根组织
department_ids.add(str(org_id))
# 处理所有子部门
for dept in org_response.get('data', []):
collect_dept_ids(dept)
#print(f"Found departments: {department_ids}")
# 查询所有部门下的用户,直接在SQL中过滤掉管理员
users = db.session.query(
UserInfo, UserOrg, OrgInfo
).join(
UserOrg, UserInfo.id == UserOrg.user_id
).join(
OrgInfo, UserOrg.org_id == OrgInfo.id
).filter(
UserOrg.org_id.in_(department_ids),
UserInfo.is_deleted.is_(False),
UserInfo.status == '1',
db.or_(UserInfo.user_type.is_(None), UserInfo.user_type == 0) # 只查询非管理员用户
).all()
# 使用字典来存储唯一的用户信息,以用户ID为键
user_dict = {}
for user_info, user_org, org_info in users:
user_id = str(user_info.id)
if user_id not in user_dict:
# 获取职位信息
position_info = db.session.query(Position.name).join(
UserPosition, Position.id == UserPosition.position_id
).filter(UserPosition.user_id == user_info.id).first()
position_name = position_info.name if position_info else None
user_dict[user_id] = {
'id': user_id,
'user_name': user_info.user_name,
'nick_name': user_info.nick_name,
'real_name': user_info.real_name,
'email': user_info.email,
'phone': user_info.phone,
'avatar': user_info.avatar,
'user_card_number': user_info.user_card_number,
'device_sn': user_info.device_sn,
'customer_id': user_info.customer_id,
'status': user_info.status,
'department_id': org_info.id,
'department_name': org_info.name,
'create_time': user_info.create_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.create_time else None,
'update_time': user_info.update_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.update_time else None,
'working_years': user_info.working_years,
'position': position_name
}
# 将字典转换为列表
user_list = list(user_dict.values())
print(f"Found {len(user_list)} employee users (admin users already filtered in SQL) for org {org_id} and its subdepartments")
return user_list
except Exception as e:
logger.error(f"Error in _fetch_users_from_departments: {str(e)}")
return []
def fetch_users_by_orgId_direct(org_id, customer_id=None):
"""直接数据库查询用户(绕过服务层)"""
try:
# 直接查询,不依赖组织服务,在SQL中直接过滤掉管理员
users = db.session.query(
UserInfo, UserOrg, OrgInfo
).join(
UserOrg, UserInfo.id == UserOrg.user_id
).join(
OrgInfo, UserOrg.org_id == OrgInfo.id
).filter(
UserOrg.org_id == org_id,
UserInfo.is_deleted.is_(False),
UserInfo.status == '1',
db.or_(UserInfo.user_type.is_(None), UserInfo.user_type == 0) # 只查询非管理员用户
)
if customer_id is not None:
users = users.filter(UserInfo.customer_id == customer_id)
users_result = users.all()
# 格式化返回结果
user_list = []
for user_info, user_org, org_info in users_result:
# 获取职位信息
position_info = db.session.query(Position.name).join(
UserPosition, Position.id == UserPosition.position_id
).filter(UserPosition.user_id == user_info.id).first()
position_name = position_info.name if position_info else None
user_list.append({
'id': str(user_info.id),
'user_name': user_info.user_name,
'nick_name': user_info.nick_name,
'real_name': user_info.real_name,
'email': user_info.email,
'phone': user_info.phone,
'avatar': user_info.avatar,
'user_card_number': user_info.user_card_number,
'device_sn': user_info.device_sn,
'customer_id': user_info.customer_id,
'status': user_info.status,
'department_id': org_info.id,
'department_name': org_info.name,
'create_time': user_info.create_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.create_time else None,
'update_time': user_info.update_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.update_time else None,
'working_years': user_info.working_years,
'position': position_name
})
logger.info(f"直接数据库查询: 组织{org_id}找到{len(user_list)}个员工用户(管理员已在SQL中过滤)")
return user_list
except Exception as e:
logger.error(f"直接数据库查询用户失败: {str(e)}")
return []
def fetch_users_with_descendants(org_id, customer_id=None):
"""查询组织及其所有子组织的用户(扩展查询)"""
try:
# 查询所有可能的子组织
descendant_orgs = db.session.query(OrgInfo.id).filter(
OrgInfo.is_deleted.is_(False),
db.or_(
OrgInfo.id == org_id,
OrgInfo.parent_id == org_id,
OrgInfo.ancestors.like(f'%,{org_id},%') if hasattr(OrgInfo, 'ancestors') else True
)
).all()
org_ids = [org.id for org in descendant_orgs]
if not org_ids:
# 如果没有找到子组织,至少查询当前组织
org_ids = [org_id]
# 查询这些组织下的所有用户
users = db.session.query(
UserInfo, UserOrg, OrgInfo
).join(
UserOrg, UserInfo.id == UserOrg.user_id
).join(
OrgInfo, UserOrg.org_id == OrgInfo.id
).filter(
UserOrg.org_id.in_(org_ids),
UserInfo.is_deleted.is_(False),
UserInfo.status == '1',
db.or_(UserInfo.user_type.is_(None), UserInfo.user_type == 0) # 只查询非管理员用户
)
if customer_id is not None:
users = users.filter(UserInfo.customer_id == customer_id)
users_result = users.all()
# 使用字典来存储唯一的用户信息
user_dict = {}
for user_info, user_org, org_info in users_result:
user_id = str(user_info.id)
if user_id not in user_dict:
# 获取职位信息
position_info = db.session.query(Position.name).join(
UserPosition, Position.id == UserPosition.position_id
).filter(UserPosition.user_id == user_info.id).first()
position_name = position_info.name if position_info else None
user_dict[user_id] = {
'id': user_id,
'user_name': user_info.user_name,
'nick_name': user_info.nick_name,
'real_name': user_info.real_name,
'email': user_info.email,
'phone': user_info.phone,
'avatar': user_info.avatar,
'user_card_number': user_info.user_card_number,
'device_sn': user_info.device_sn,
'customer_id': user_info.customer_id,
'status': user_info.status,
'department_id': org_info.id,
'department_name': org_info.name,
'create_time': user_info.create_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.create_time else None,
'update_time': user_info.update_time.strftime('%Y-%m-%d %H:%M:%S') if user_info.update_time else None,
'working_years': user_info.working_years,
'position': position_name
}
# 将字典转换为列表
user_list = list(user_dict.values())
logger.info(f"扩展查询: 组织{org_id}及子组织找到{len(user_list)}个员工用户(管理员已在SQL中过滤)")
return user_list
except Exception as e:
logger.error(f"扩展查询用户失败: {str(e)}")
return []
def getCustomers():
"""获取所有顶级组织(客户)"""
try:
customers = db.session.query(OrgInfo)\
.filter(OrgInfo.parent_id == 0)\
.filter(OrgInfo.is_deleted.is_(False))\
.all()
customer_list = []
for customer in customers:
customer_list.append({
'id': customer.id,
'name': customer.name,
'code': customer.code,
'status': customer.status,
'create_time': customer.create_time.strftime('%Y-%m-%d %H:%M:%S') if customer.create_time else None,
'update_time': customer.update_time.strftime('%Y-%m-%d %H:%M:%S') if customer.update_time else None
})
logger.info(f"Found {len(customer_list)} customers")
return customer_list
except Exception as e:
logger.error(f"Error in getCustomers: {str(e)}")
return []
def fetch_departments(orgId, customerId=None):
try:
logger.info(f"🔍 fetch_departments调用: orgId={orgId}, customerId={customerId}")
# 🔧 修复:处理多种情况
# 情况1: orgId为None但有customerId,查找该客户的根组织
if orgId is None and customerId:
root_orgs = db.session.query(OrgInfo)\
.filter(OrgInfo.customer_id == customerId)\
.filter(OrgInfo.is_deleted.is_(False))\
.filter(db.or_(OrgInfo.parent_id.is_(None), OrgInfo.parent_id == 0))\
.all()
if root_orgs:
orgId = root_orgs[0].id # 使用第一个根组织
logger.info(f"自动找到customerId {customerId} 的根组织ID: {orgId}")
else:
return {
'success': False,
'error': f'No root organization found for customer: {customerId}'
}
# 情况2: 有orgId但没有customerId,需要检查orgId的真实含义
elif orgId and not customerId:
# 先尝试作为orgId直接查询
org_exists = db.session.query(OrgInfo).filter(
OrgInfo.id == orgId,
OrgInfo.is_deleted.is_(False)
).first()
if org_exists:
# 找到了组织,但需要设置正确的customerId
customerId = org_exists.customer_id
logger.info(f"✅ 直接找到组织: {orgId}, 设置customerId={customerId}")
else:
logger.info(f"🔍 orgId {orgId} 不存在,尝试多种映射策略")
# 策略1: 尝试将orgId作为customerId查找根组织
root_orgs = db.session.query(OrgInfo)\
.filter(OrgInfo.customer_id == orgId)\
.filter(OrgInfo.is_deleted.is_(False))\
.filter(db.or_(OrgInfo.parent_id.is_(None), OrgInfo.parent_id == 0))\
.all()
if root_orgs:
customerId = orgId # 原来的orgId实际上是customerId
orgId = root_orgs[0].id # 使用根组织的ID
logger.info(f"✅ 策略1成功: 将 {customerId} 作为customerId,找到根组织ID: {orgId}")
else:
# 策略2: 检查是否存在某个租户组织,其ID本身就是租户ID(可能是租户顶级组织)
tenant_org = db.session.query(OrgInfo).filter(
OrgInfo.id == orgId
).first() # 不加is_deleted过滤,因为可能状态字段不同
if tenant_org:
logger.info(f"✅ 策略2成功: {orgId} 是有效的组织ID,name={tenant_org.name}, is_deleted={tenant_org.is_deleted}")
customerId = tenant_org.customer_id if hasattr(tenant_org, 'customer_id') else orgId
# 如果找到的是租户本身,直接使用它
if tenant_org.is_deleted is False or tenant_org.is_deleted == 0:
# 组织可用,直接使用
pass
else:
logger.info(f"⚠️ 组织{orgId}已被删除,但仍然尝试使用")
else:
# 策略3: 查找是否有组织的customer_id字段等于这个ID(反向查找)
orgs_with_customer = db.session.query(OrgInfo)\
.filter(OrgInfo.customer_id == orgId)\
.filter(OrgInfo.is_deleted.is_(False))\
.all()
if orgs_with_customer:
# 找到第一个根组织(parent_id为0或None)
root_org = None
for org in orgs_with_customer:
if not org.parent_id or org.parent_id == 0:
root_org = org
break
if not root_org:
root_org = orgs_with_customer[0] # 如果没有根组织,使用第一个
customerId = orgId
orgId = root_org.id
logger.info(f"✅ 策略3成功: 找到customer_id={customerId}的组织,使用orgId={orgId}")
else:
logger.warning(f"❌ 所有策略都失败: {orgId} 既不是有效的orgId也不是有效的customerId")
return {
'success': False,
'error': f'Organization not found for ID: {orgId}. Please check if this ID exists in sys_org_units table.'
}
# 直接使用递归获取的部门数据
response = fetch_departments_by_orgId(orgId, customerId)
if not response['success']:
return response
return {
'success': True,
'data': response['data']
}
except Exception as e:
print(f"Error in fetch_departments: {str(e)}")
return {
'success': False,
'error': str(e)
}
def fetch_users_stats_by_orgId(org_id):
"""获取用户统计信息"""
try:
users = fetch_users_by_orgId(org_id)
if not users:
return {
'success': False,
'error': 'No users found'
}
# 部门统计
department_stats = {}
for user in users:
dept_id = user['department_id']
dept_name = user['department_name']
if dept_id not in department_stats:
department_stats[dept_id] = {
'name': dept_name,
'total': 0,
'with_device': 0,
'without_device': 0
}
stats = department_stats[dept_id]
stats['total'] += 1
if user['device_sn'] and user['device_sn'].strip() not in ['', '-']:
stats['with_device'] += 1
else:
stats['without_device'] += 1
# 用户增长趋势(按月统计)
monthly_stats = defaultdict(lambda: {'total': 0, 'with_device': 0})
for user in users:
if user['create_time']:
month = user['create_time'][:7] # 获取年月 (YYYY-MM)
monthly_stats[month]['total'] += 1
if user['device_sn'] and user['device_sn'].strip() not in ['', '-']:
monthly_stats[month]['with_device'] += 1
# 整体设备佩戴统计
total_users = len(users)
users_with_device = sum(1 for user in users
if user['device_sn'] and user['device_sn'].strip() not in ['', '-'])
return {
'success': True,
'data': {
'department_stats': [
{
'name': stats['name'],
'total': stats['total'],
'with_device': stats['with_device'],
'without_device': stats['without_device']
}
for stats in department_stats.values()
],
'monthly_stats': [
{
'month': month,
'total': stats['total'],
'with_device': stats['with_device']
}
for month, stats in sorted(monthly_stats.items())
],
'overall_stats': {
'total_users': total_users,
'users_with_device': users_with_device,
'users_without_device': total_users - users_with_device
}
}
}
except Exception as e:
logger.error(f"Error in fetch_users_stats_by_orgId: {str(e)}")
return {
'success': False,
'error': str(e)
}
def fetch_root_departments():
"""获取根部门 - 移除ancestors字段依赖"""
try:
org_service = get_unified_org_service()
departments = org_service.get_root_departments()
return jsonify({
'success': True,
'data': departments
})
except Exception as e:
logger.error(f"Error in fetch_root_departments: {str(e)}")
return jsonify({
'success': False,
'error': str(e)
})
def get_org_descendants(org_id, customer_id=None):
"""获取组织及其所有子组织的ID列表 - 使用统一服务"""
try:
org_service = get_unified_org_service()
return org_service.get_org_descendants_ids(int(org_id), customer_id)
except Exception as e:
logger.error(f"Error in get_org_descendants: {e}")
return [int(org_id)] # 发生错误时至少返回当前组织ID
def get_top_level_org_id(org_id):
"""根据org_id获取顶级组织(租户)ID - 通过ancestors字段解析"""
# 不需要获取租户ID,直接返回org_id
return org_id
# ==================== 健康分析系统所需的组织架构函数 ====================
def findTopLevelOrganizations():
"""
获取所有顶级组织(租户)列表
利用 sys_org_closure 表来查找没有上级的组织
"""
try:
logger.info("开始查询顶级组织(租户)")
# 方法1: 直接查找 parent_id 为 0 或 None 的组织
top_level_orgs = db.session.query(OrgInfo).filter(
and_(
or_(OrgInfo.parent_id == 0, OrgInfo.parent_id.is_(None)),
OrgInfo.is_deleted == 0
)
).all()
# 如果没有找到,尝试查找 sys_org_closure 表
if not top_level_orgs:
# 使用原生SQL查询 sys_org_closure 表
sql = text("""
SELECT DISTINCT o.id, o.name, o.code, o.customer_id, o.create_time
FROM sys_org_units o
WHERE o.id NOT IN (
SELECT DISTINCT descendant_id
FROM sys_org_closure
WHERE ancestor_id != descendant_id
)
AND o.is_deleted = 0
ORDER BY o.id
""")
result = db.session.execute(sql)
top_level_orgs = []
for row in result:
top_level_orgs.append({
'id': row.id,
'name': row.name,
'code': row.code,
'customer_id': row.customer_id,
'create_time': row.create_time.strftime('%Y-%m-%d %H:%M:%S') if row.create_time else None
})
else:
# 转换为字典格式
top_level_orgs = [
{
'id': org.id,
'name': org.name,
'code': org.code,
'customer_id': getattr(org, 'customer_id', org.id),
'create_time': org.create_time.strftime('%Y-%m-%d %H:%M:%S') if org.create_time else None
}
for org in top_level_orgs
]
logger.info(f"找到 {len(top_level_orgs)} 个顶级组织")
return top_level_orgs
except Exception as e:
logger.error(f"查询顶级组织失败: {str(e)}")
# 回退方案:直接查询所有 parent_id 为 0 的组织
try:
fallback_orgs = db.session.query(OrgInfo).filter(
OrgInfo.parent_id == 0,
OrgInfo.is_deleted == 0
).all()
return [
{
'id': org.id,
'name': org.name,
'code': org.code,
'customer_id': getattr(org, 'customer_id', org.id),
'create_time': org.create_time.strftime('%Y-%m-%d %H:%M:%S') if org.create_time else None
}
for org in fallback_orgs
]
except Exception as fallback_e:
logger.error(f"回退查询也失败: {str(fallback_e)}")
return []
def findAllDescendants(customer_id):
"""
获取客户下的所有部门 org_id 列表
利用 sys_org_closure 表来查找所有子孙组织
Args:
customer_id: 客户(顶级组织)的ID
Returns:
list: 包含所有部门 org_id 的列表
"""
try:
logger.info(f"开始查询客户 {customer_id} 下的所有部门")
# 方法1: 使用 sys_org_closure 表查询
try:
sql = text("""
SELECT DISTINCT descendant_id as org_id
FROM sys_org_closure
WHERE ancestor_id = :customer_id
AND ancestor_id != descendant_id
UNION
SELECT :customer_id as org_id
ORDER BY org_id
""")
result = db.session.execute(sql, {'customer_id': customer_id})
org_ids = [row.org_id for row in result]
if org_ids:
logger.info(f"通过 sys_org_closure 表找到 {len(org_ids)} 个部门")
return org_ids
except Exception as closure_e:
logger.warning(f"sys_org_closure 表查询失败: {str(closure_e)}")
# 方法2: 回退到递归查询 sys_org_units 表
def get_descendants_recursive(parent_id, visited=None):
if visited is None:
visited = set()
if parent_id in visited:
return []
visited.add(parent_id)
descendants = [parent_id]
# 查找直接子组织
children = db.session.query(OrgInfo.id).filter(
OrgInfo.parent_id == parent_id,
OrgInfo.is_deleted == 0
).all()
for child in children:
child_id = child.id
descendants.extend(get_descendants_recursive(child_id, visited))
return descendants
org_ids = get_descendants_recursive(customer_id)
logger.info(f"通过递归查询找到 {len(org_ids)} 个部门")
return org_ids
except Exception as e:
logger.error(f"查询客户 {customer_id} 的部门失败: {str(e)}")
# 最小回退:至少返回客户自己的ID
return [customer_id]
def getUserIdsByOrgId(org_id):
"""
根据 org_id 从 sys_user 表查询该组织下的所有 user_id
Args:
org_id: 组织ID
Returns:
list: 用户ID列表
"""
try:
logger.info(f"开始查询组织 {org_id} 下的用户")
# 查询该组织下的所有用户
users = db.session.query(UserInfo.id).join(
UserOrg, UserInfo.id == UserOrg.user_id
).filter(
UserOrg.org_id == org_id,
UserInfo.is_deleted == 0,
UserInfo.status == '1' # 只查询激活状态的用户
).all()
user_ids = [user.id for user in users]
logger.info(f"组织 {org_id} 下找到 {len(user_ids)} 个用户")
return user_ids
except Exception as e:
logger.error(f"查询组织 {org_id} 的用户失败: {str(e)}")
return []
def getAllUserIdsByCustomer(customer_id):
"""
获取客户下所有部门的所有用户ID
Args:
customer_id: 客户ID
Returns:
dict: {org_id: [user_ids]} 的映射字典
"""
try:
logger.info(f"开始获取客户 {customer_id} 下所有用户")
# 1. 获取客户下所有部门
org_ids = findAllDescendants(customer_id)
# 2. 获取每个部门下的用户
customer_users = {}
total_users = 0
for org_id in org_ids:
user_ids = getUserIdsByOrgId(org_id)
if user_ids:
customer_users[org_id] = user_ids
total_users += len(user_ids)
logger.info(f"客户 {customer_id} 下共有 {len(org_ids)} 个部门,{total_users} 个用户")
return customer_users
except Exception as e:
logger.error(f"获取客户 {customer_id} 用户失败: {str(e)}")
return {}