Files
vue-fastapi-admin/app/controllers/weixin/user.py
T
2026-06-25 17:41:06 +08:00

202 lines
7.9 KiB
Python

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()