from app.core.crud import CRUDBase from app.schemas.weixin import ( WeixinUserCreate, WeixinUserUpdate, ) from app.models.weixin import WeixinUser from app.schemas.weixin import WeixinUserBindInfo from some_sdk.services.binder import feishu_client, xy_client from some_sdk.feishu_sdk.biz.doc import search_file_record from some_sdk.xingyun_sdk.apis.channel import list_channel_group, list_channel_group_user_list, set_online_staff import logging logger = logging.getLogger(__name__) from datetime import datetime def split_generator(iterable, chunk_size=50): """ 将可迭代对象拆分为多个子列表 """ chunk = [] for item in iterable: chunk.append(item) if len(chunk) == chunk_size: yield chunk chunk = [] if chunk: yield chunk class WeixinUserController(CRUDBase[WeixinUser, WeixinUserCreate, WeixinUserUpdate]): def __init__(self): super().__init__(model=WeixinUser) async def update_from_group(self, internal_members: list[dict]): # 同步更新数据库 member_dict = {} for member in internal_members: member = member.copy() userid = member.get('userid', None) member['alias'] = member.pop('name', None) member_dict[userid] = member member_list = await self.model.filter(userid__in=member_dict.keys()) update_list = [] update_fileds = ['alias', 'role', 'erp_id', 'erp_name'] history = {} for member in member_list: member_info = member_dict.pop(member.userid, history.get(member.userid, {})) if member.role in ['owner', 'admin', 'follower']: continue if not member_info: continue history[member.userid] = member_info updated = {} for field in update_fileds: old_value = getattr(member, field) if field not in member_info: continue value = member_info.get(field) if old_value != value: setattr(member, field, value) updated[f'{field}:{str(old_value)}'] = value if updated: logger.info(f'用户 {member.userid} 更新关系为 {updated}') update_list.append(member) if update_list: await self.model.bulk_update(update_list, fields=update_fileds) # 新增用户 create_list = [] for userid, member_info in member_dict.items(): create_list.append(WeixinUser( **member_info, name=member_info.get('alias'), )) if create_list: await self.model.bulk_create(create_list) return { 'update_count': len(update_list), 'create_count': len(create_list), } async def bind_user(self, user_in: WeixinUserBindInfo): if not user_in.userid: raise ValueError("用户ID不能为空") if user_in.erp_id == 0: del user_in.erp_id user = await self.model.filter(userid=user_in.userid).first() if not user: await self.create({**user_in.model_dump(exclude_unset=True), 'name': user_in.username}) return {} await self.model.filter(userid=user_in.userid).update(**user_in.model_dump(exclude_unset=True)) async def set_user_online(self, class_type: str, date: datetime): daysTimestamp = lambda nowStamp, days: nowStamp + days * 24 * 60 * 60 * 1000 formatDate = lambda ts: datetime.fromtimestamp(ts / 1000).strftime('%Y-%m-%d') today = int(date.timestamp() * 1000) logger.info(f'设置 {formatDate(today)} 班次为 {class_type} 的员工为在线状态') yestoday = daysTimestamp(today, -1) tomorrow = daysTimestamp(today, 1) # 查询日期为 yestoday 到 后天 之间的所有记录 resp = search_file_record( feishu_client, app_token="V4qebMG2kamCWMslJmdcQMbtngW", table_id="tblKgjc3F2jZ2inC", filter={ "conjunction": "and", "conditions": [{ "field_name": "日期", "operator": "isGreater", "value": ["ExactDate", yestoday] },{ "field_name": "日期", "operator": "isLess", "value": ["ExactDate", daysTimestamp(today, 2)] }] }, ) set_result = {} current_class = (class_type, today) next_class = ('早班', tomorrow) if class_type == '晚班' else ('晚班', today) current_class_mapping = {} next_class_mapping = {} async for data in resp: user = data.get('data', {}) user_online = ((user.get('班次') or '')[:2], user.get('日期', '')) # logger.info(f'用户{user.get("接量成员", "")} 在线时间为{user_online} 当前班次为{current_class} 下一班次为{next_class}') class_group = user.get('组别', '') class_mapping = None # 当前班次 if user_online == current_class: class_mapping = current_class_mapping set_result[class_group] = {"接量成员": user.get('接量成员', '')} # 下一班次 elif user_online == next_class: class_mapping = next_class_mapping if class_mapping is None: continue if user.get('id', ''): class_mapping.setdefault(class_group, []) class_mapping[class_group].append(user.get('id', '')) assert current_class_mapping, f"根据日期{current_class[1]} {formatDate(current_class[1])}没有找到班次为{class_type}的员工" logger.info(f'根据日期{current_class[1]} {formatDate(current_class[1])} 找到班次为{class_type}的员工: {current_class_mapping} {set_result}') if next_class_mapping: logger.info(f'根据日期{next_class[1]} {formatDate(next_class[1])} 找到班次为{next_class[0]}的员工: {next_class_mapping}') group_list = list_channel_group(xy_client) async for group in group_list: title = group.get("title", "") if title not in current_class_mapping: continue set_result[title] = set_result.get(title) or {} try: user_list = list_channel_group_user_list(xy_client, groupId=group.get("id", "")) huomaList = [] async for user in user_list: huomaList.append(user.get('id')) if not huomaList: logger.error(f'组 {title} {group.get("id", "")} 中没有员工') continue is_faild, is_success = [], [] # 按照50个一组设置在线状态 for i in range(0, len(huomaList), 50): result = await set_online_staff(xy_client, allDayUserIds=','.join(current_class_mapping[title]), huomaList=huomaList[i:i+50]) is_faild += list(filter(lambda x: x.get('errorMsg', ''), result.get('data', []))) is_success += list(filter(lambda x: x.get('success', True), result.get('data', []))) is_faild = set(is_faild) if is_faild: logger.error(f'设置失败的员工: {is_faild}') else: logger.info(f'全部员工设置成功') set_result[title] = { 'success': len(is_success), 'fail': len(is_faild), **set_result[title] } except Exception as e: logger.exception(f'设置群 {group.get("id", "")} 中员工 {huomaList} 为在线状态失败: {e}') return set_result, next_class_mapping weixin_user_controller = WeixinUserController()