from fastapi import APIRouter, Depends, Request, Form, Body, UploadFile, File from fastapi.responses import PlainTextResponse from typing import Optional, Dict, Any from mooc.models.goouc_fullexam import ShareRecord from pydantic import BaseModel from sqlalchemy.orm import Session from mooc.db.database import get_db from mooc.crud.crud_goouc_fullexam_user import ( CRUDFullExamUser, CRUDUserDoexam, CRUDUserExamAnswer, CRUDUserWrongPraction, CRUDUserCollectionPraction, full_exam_user ) from mooc.models.goouc_fullexam_user import ( UserDoexam, UserExamAnswer, UserWrongPraction, UserCollectionPraction, FullExamUser ) from mooc.core.config import settings from mooc.utils.wechat_client import wx_api from datetime import datetime, time import os from mooc.core.logger import get_logger import httpx from mooc.core.response import ResponseFactory import re from mooc.crud.crud_goouc_fullexam import CRUDSetting, CRUDShareRecord, setting, xueshen from mooc.crud.crud_goouc_fullexam_user import full_exam_user, user_member, user_collection_praction wxapp_router = APIRouter() # 创建模块级别的日志记录器 logger = get_logger(__name__) class WxappRequest(BaseModel): uid: Optional[str] = None op: Optional[str] = None m: Optional[str] = None data: Dict[str, Any] = {} code: Optional[str] = None # 启用额外字段支持 model_config = { "extra": "allow" # 允许存储模型中未定义的字段 } # 添加一个方法便于获取任意字段,带默认值 def get_field(self, field_name: str, default=None): """获取字段值,优先从直接属性获取,然后从data字典获取""" if hasattr(self, field_name): return getattr(self, field_name) return self.data.get(field_name, default) @wxapp_router.post("/index") async def handle_wxapp_request( request: Request, i: str, t: Optional[str] = None, v: Optional[str] = None, c: Optional[str] = "entry", a: Optional[str] = "wxapp", do: Optional[str] = None, db: Session = Depends(get_db), file: UploadFile = None ): # 获取表单数据 try: form_data = await request.form() logger.debug(f"Form data: {form_data}") # 将表单数据转换为字典 data = dict(form_data) # 检查是否包含上传文件 if "upfile" in form_data: file = form_data["upfile"] except Exception as e: logger.error(f"Error reading form data: {e}") # 如果没有表单数据,尝试读取JSON try: data = await request.json() logger.debug(f"JSON data: {data}") except Exception as e: logger.error(f"Error reading JSON: {e}") data = {} logger.debug(f"Final data: {data}") logger.debug(f"Query params: {request.query_params}") # 根据do参数处理不同的业务逻辑 if do == "login2": # 针对login2,直接传递表单数据 if "code" in data: return await handle_login2(WxappRequest(code=data.get("code"), data=data), db) else: # 如果没有code,仍然尝试正常处理 return await handle_login2(WxappRequest(**data), db) elif do == "Setuserinfo": return await handle_set_user_info(WxappRequest(**data), db) elif do == "ExamOperation": return await handle_exam_operation(WxappRequest(**data), db, user_doexam, user_exam_answer) elif do == "Collection": return await handle_collection(WxappRequest(**data), db, user_collection) elif do == "WrongQuestion": return await handle_wrong_question(WxappRequest(**data), db, user_wrong_praction) elif do == "TotalqNum": # 添加新的处理逻辑 return {"code": 0, "data": {"total": 100}, "message": "success"} elif do == "Index": # 添加首页处理逻辑 return {"code": 0, "data": {}, "message": "success"} elif do == "Advert": # 添加广告处理逻辑 return {"code": 0, "data": [], "message": "success"} elif do == "uploadImage": if not file: return ResponseFactory.error(code=400, message="缺少上传文件") return await handle_upload_image(WxappRequest(**data), db, file) elif do == "UpdateHeadimg": return await handle_update_headimg(WxappRequest(**data), db) # part 4编写 elif do == "Share": return await handle_share(WxappRequest(**data), int(i), db) elif do == "AddWrong": return await handle_add_wrong(WxappRequest(**data), db) elif do == "Feedback": return await handle_feedback(WxappRequest(**data), db) return {"code": 404, "message": "接口未找到"} async def handle_update_headimg(data: WxappRequest, db: Session): """处理更新用户头像的请求""" logger.info(f"处理更新头像请求: uid={data.uid},data={data}") try: # 验证必要参数 uid = data.uid # headimg = data.data.get("headimg") # if not uid or not headimg: # logger.error("参数不足: uid或headimg缺失") # return ResponseFactory.error(code=1, message="传递的参数不存在", data="1001") # 获取用户对象,包含weid条件 user = full_exam_user.get_by_id_and_weid(db, int(uid), settings.WECHAT_UNIACID) if not user: logger.error(f"用户不存在: uid={uid}") return ResponseFactory.error(code=1, message="用户不存在", data="error") logger.debug(f"用户信息: {user.headimg}") # 更新用户头像 try: update_data = {"headimg": data.headimg} full_exam_user.update(db, db_obj=user, obj_in=update_data) logger.info(f"头像更新成功: uid={uid}, headimg={data.headimg}") return ResponseFactory.success(data="ok", message="ok") except Exception as e: logger.error(f"头像更新失败: {str(e)}") return ResponseFactory.error(code=1, message="error", data="error") except Exception as e: logger.exception(f"处理更新头像请求过程中发生异常: {str(e)}") return ResponseFactory.error(code=1, message=str(e), data="error") async def handle_upload_image(data: WxappRequest, db: Session, file: UploadFile = File(...)): """处理图片上传功能""" import os import time import random import string import shutil from pathlib import Path logger.info(f"处理图片上传请求: uid={data.uid}, module={data.m}") try: # 定义允许的图片类型 allowed_types = [ "image/jpg", "image/jpeg", "image/png", "image/pjpeg", "image/gif", "image/bmp", "image/x-png" ] # 最大文件大小(2MB) max_file_size = 2000000 # 检查文件是否存在 if not file: logger.error("图片不存在!") return ResponseFactory.error(code=400, message="图片不存在!") # 检查文件内容类型 content_type = file.content_type if content_type not in allowed_types: logger.error(f"文件类型不符: {content_type}") return ResponseFactory.error(code=400, message=f"文件类型不符: {content_type}") # 读取文件内容以检查大小 contents = await file.read() if len(contents) > max_file_size: logger.error(f"文件太大: {len(contents)} bytes") return ResponseFactory.error(code=400, message="文件太大!") # 重置文件位置指针 await file.seek(0) # 获取上传目标文件夹路径 module_name = data.m or "default" # 使用绝对路径并确保目录存在 destination_folder = os.path.join(settings.UPLOAD_IMG_DIR, module_name) logger.debug(f"上传目标文件夹: {destination_folder}") # 确保目标目录存在 Path(destination_folder).mkdir(parents=True, exist_ok=True) # 创建更安全的随机文件名 (时间戳 + 随机数) current_time = int(time.time()) random_string = ''.join(random.choices(string.digits + string.ascii_lowercase, k=8)) file_extension = os.path.splitext(file.filename)[1].lower() # 转为小写以增加一致性 # 验证扩展名安全性 safe_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp'] if file_extension not in safe_extensions: file_extension = '.jpg' # 默认使用安全扩展名 filename = f"{current_time}_{random_string}{file_extension}" # 完整的保存路径 file_path = os.path.join(destination_folder, filename) logger.debug(f"文件将保存至: {file_path}") # 保存文件 with open(file_path, "wb") as buffer: shutil.copyfileobj(file.file, buffer) # 检查文件是否成功保存 if not os.path.exists(file_path): logger.error(f"文件保存失败: {file_path}") return ResponseFactory.error(code=500, message="文件保存失败") # 构建文件URL路径 url_module_path = module_name.replace('\\', '/') # 使用相对路径作为存储路径 relative_path = f"{url_module_path}/{filename}" # 构建完整的外网访问URL # 方法1: 使用BASE_URL配置构建绝对URL absolute_url = f"{settings.BASE_URL}{settings.ATTACH_URL}{relative_path}" logger.info(f"文件上传成功: {absolute_url}") # 直接返回完整URL字符串 return PlainTextResponse(content=absolute_url) except Exception as e: logger.exception(f"文件上传过程中发生异常: {str(e)}") # 直接返回错误消息字符串 return str(e) def validate_phone(phone: str) -> bool: # 基础格式验证 if not re.match(r"^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$", phone): return False # 特殊号段白名单 special_prefix = ["191", "192", "197"] # 根据实际情况更新 if any(phone.startswith(p) for p in special_prefix): return True # 虚拟运营商号段二次验证 if phone.startswith(("170", "171", "172")): return validate_virtual_operator(phone) # 调用专用验证接口 return True async def handle_set_user_info(data: WxappRequest, db: Session): """处理用户信息相关操作""" logger.info(f"处理用户信息请求: op={data.op}, uid={data.uid},data={data}") operations = { "getinfo": get_user_info, "checkStudent": check_student, "update": update_user_info, "getcode": get_verification_code, "checkcode": check_verification_code, } # 如果op为空,则默认执行更新用户信息操作 if not data.op: logger.info(f"未指定操作类型,默认执行更新用户信息: uid={data.uid}") try: # 直接从请求对象中获取数据 update_data = {} if hasattr(data, "name"): update_data["name"] = data.name if hasattr(data, "phone") and data.phone != "null": update_data["phone"] = data.phone # 添加请求中的其他字段 for field in ["student_id", "id_card", "school", "level"]: if hasattr(data, field): update_data["field"] = getattr(data, field) logger.debug(f"更新用户数据: {update_data}") result = await update_user_info(data.uid, update_data, db) return ResponseFactory.success( data=result, message="更新成功" ) except Exception as e: logger.exception(f"更新用户信息时发生异常: {str(e)}") return ResponseFactory.error( code=1, message=str(e) ) # 处理指定操作类型 operation = operations.get(data.op) logger.debug(f"operation: {operation}") if not operation: logger.warning(f"不支持的操作: {data.op}") return ResponseFactory.error( code=1, message=f"不支持的操作: {data.op}" ) try: # 处理特殊情况:getcode操作需要直接获取phone属性 if data.op == "getcode": # 确保将phone从对象属性传递到data字典 data_dict = dict(data.data) if data.data else {} # 复制现有数据 # 从对象中获取phone属性 if hasattr(data, "phone"): data_dict["phone"] = data.phone result = await operation(data.uid, data_dict, db) else: # 其他操作保持原样 result = await operation(data.uid, data.data, db) logger.debug(f"result: {result}") return ResponseFactory.success( data=result, message="success" ) except Exception as e: logger.exception(f"处理用户信息时发生异常: {str(e)}") return ResponseFactory.error( code=1, message=str(e) ) # 获取用户信息 async def get_user_info(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]: """获取用户详细信息""" logger.debug(f"获取用户信息: uid={uid},data={data}") if not uid: raise ValueError("用户ID不存在") # 从请求获取协议和域名 protocol = "https://" # 在实际部署中可能需要根据请求头判断 domain_name = "yourdomain.com" # 这里需要从请求中获取 http = f"{protocol}{domain_name}" # 获取用户基本信息 - 已经使用CRUD方法 user = full_exam_user.get_by_fields(db, {"id": int(uid), "weid": settings.WECHAT_UNIACID, "istatus": 1}) if not user or user.istatus != 1: raise ValueError("用户不存在或已被删除") # 构建用户信息字典 info = { "id": user.id, "nickname": user.nickname, "headimg": user.headimg, "name": user.name, "phone": user.phone, "grade": user.gradeid, "ismember": user.ismember, "member_endtime": None, "nativeplace": user.nativeplace, "integral": user.integral, "student_id": user.student_id, "id_card": user.id_card, "school": user.school, "level": user.level, "openid": user.openid } logger.debug(f"用户信息: {info}") # 检查会员是否过期 current_time = int(datetime.now().timestamp()) if user.ismember == 1 and user.member_endtime and int(user.member_endtime) < current_time: # 更新会员状态为非会员 - 使用CRUD方法 full_exam_user.update(db, db_obj=user, obj_in={"ismember": 2}) info["ismember"] = 2 # 格式化会员到期时间 if user.member_endtime: info["member_endtime"] = datetime.fromtimestamp(int(user.member_endtime)).strftime("%Y-%m-%d") # 获取系统设置 - 使用CRUD替代原始SQL system_setting = setting.get_by_fields(db, {"weid": user.weid}) # 默认用户信息状态为完整 is_ok = 1 # 检查用户信息是否完整 if system_setting and system_setting.info_status == 1: if not user.phone or not user.name: is_ok = 2 # 添加系统设置信息 if system_setting: info["IOS"] = system_setting.IOS info["customer_service"] = system_setting.customer_service # 检查会员系统是否开启 - 使用CRUD替代原始SQL member_setting = user_member.get_by_fields(db, { "weid": user.weid, "istatus": 1 }) info["is_open"] = member_setting.status if member_setting else 0 # 用户信息完整性状态 info["is_ok"] = is_ok # 默认学生信息 info["stu_have"] = 2 info["student_id"] = 0 info["xuesheng_id"] = 0 # 如果用户有姓名和手机号,检查是否是学生 - 使用CRUD替代原始SQL if user.phone and user.name: student = xueshen.get_by_fields(db, { "weid": user.weid, "name": user.name, "phone": user.phone }) if student: info["student_id"] = student.student_name info["xuesheng_id"] = student.xuesheng_id info["stu_have"] = 1 # 检查是否绑定微信 info["is_bind"] = 1 if user.openid else 0 return {"info": info, "http": http} # 检查学生信息 async def check_student(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]: """检查学生信息是否存在""" phone = data.get("phone") name = data.get("name") if not phone or not name: raise ValueError("传递的参数不存在") user = full_exam_user.get(db, int(uid)) if not user: raise ValueError("用户不存在") student = xueshen.get_by_fields(db, { "weid": user.weid, "name": name, "phone": phone }) if not student: raise ValueError("学生信息不存在") # 将结果转换为字典 student_info = { "xuesheng_id": student.xuesheng_id, "name": student.name, "phone": student.phone, "student_name": student.student_name, "sex": student.sex } return {"list": student_info} # 获取验证码 async def get_verification_code(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]: """发送手机验证码""" phone = data.get("phone") # 验证手机号 if not validate_phone(phone): raise ValueError("手机号有误") user = full_exam_user.get(db, int(uid)) if not user: raise ValueError("用户不存在") # 使用CRUD替代SQL查询系统配置 system_config = setting.get_by_fields(db, {"weid": user.weid}) # 生成4位随机验证码 import random code = ''.join(random.choices('0123456789', k=4)) # 发送验证码 - 这里需要替换为实际的短信发送逻辑 try: # 假设这是成功发送 send_result = {"Code": "OK"} if send_result["Code"] == "OK": # 保存验证码记录 from mooc.schemas.goouc_fullexam import PhoneCodeCreate phone_code_data = PhoneCodeCreate( phone=phone, code=int(code), # 确保代码和模型匹配 createtime=int(datetime.now().timestamp()), weid=user.weid ) phone_code.create(db, obj_in=phone_code_data) return {"status": 1} else: raise ValueError(f"发送失败: {send_result.get('Message', '未知错误')}") except Exception as e: logger.error(f"发送验证码失败: {str(e)}") raise ValueError(f"发送验证码失败: {str(e)}") # 检查验证码 async def check_verification_code(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]: """验证手机验证码""" input_code = data.get("code", "").strip() phone = data.get("phone") if not input_code or not phone: raise ValueError("传递的参数不存在") # 获取最新的验证码记录 from sqlalchemy import text code_query = text(""" SELECT * FROM ims_goouc_fullexam_phonecode WHERE weid = :weid AND phone = :phone ORDER BY createtime DESC LIMIT 1 """) user = full_exam_user.get(db, int(uid)) if not user: raise ValueError("用户不存在") code_record = db.execute(code_query, { "weid": user.weid, "phone": phone }).fetchone() if not code_record: raise ValueError("验证码不存在") # 检查验证码是否过期(5分钟有效期) current_time = int(datetime.now().timestamp()) if code_record.createtime + 300 < current_time: raise ValueError("验证码已过期") # 验证码是否正确 if str(code_record.code) != input_code: raise ValueError("验证码错误") # 使用CRUD检查手机号是否已绑定其他账号 other_users = full_exam_user.get_multi_by_fields(db, { "weid": user.weid, "phone": phone }) # 过滤掉当前用户 other_users = [u for u in other_users if u.id != int(uid)] if other_users: raise ValueError("该手机号已绑定其他账号!") # 更新用户手机号 try: # 使用CRUD更新用户手机号 full_exam_user.update(db, db_obj=user, obj_in={"phone": phone}) # 如果用户有姓名,尝试更新学生信息 if user.name: # 查找学生记录 student = xueshen.get_by_fields(db, { "weid": user.weid, "name": user.name }) # 如果找到学生记录,更新其手机号 if student: xueshen.update(db, db_obj=student, obj_in={"phone": phone}) return {"status": "success"} except Exception as e: logger.error(f"更新手机号失败: {str(e)}") db.rollback() raise ValueError(f"更新手机号失败: {str(e)}") # 更新用户信息 async def update_user_info(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]: """更新用户基本信息""" if not uid: raise ValueError("传递的参数不存在") # 获取用户 user = full_exam_user.get_by_id_and_weid(db, int(uid), settings.WECHAT_UNIACID) if not user or user.istatus != 1: raise ValueError("非法用户ID") # 需要更新的字段 update_data = {} # 姓名字段 if "name" in data: update_data["name"] = data.get("name", "").strip() # 处理其他可能需要更新的字段 fields = ["student_id", "id_card", "school", "level", "phone"] for field in fields: if field in data and data.get(field) != "null": update_data[field] = data.get(field) # 如果没有要更新的数据 if not update_data: return {"status": 0, "message": "没有提供要更新的数据"} try: # 更新用户信息 full_exam_user.update(db, db_obj=user, obj_in=update_data) # 如果更新了姓名,并且用户有手机号,则尝试更新学生信息 if "name" in update_data and user.phone: from sqlalchemy import text update_student_query = text(""" UPDATE ims_goouc_fullexam_xuesheng SET name = :name WHERE weid = :weid AND phone = :phone """) db.execute(update_student_query, { "name": update_data["name"], "weid": user.weid, "phone": user.phone }) return {"status": 1, "message": "信息保存成功"} except Exception as e: logger.error(f"更新用户信息失败: {str(e)}") db.rollback() raise ValueError(f"信息保存失败: {str(e)}") async def handle_exam_operation( data: WxappRequest, db: Session, user_doexam: CRUDUserDoexam, user_exam_answer: CRUDUserExamAnswer ): """处理考试相关操作""" operations = { "submit": submit_exam, "get_history": get_exam_history, "get_detail": get_exam_detail, } operation = operations.get(data.op) if not operation: return { "code": 1, "message": f"Unsupported operation: {data.op}" } try: result = await operation(data.uid, data.data, db, user_doexam, user_exam_answer) return { "code": 0, "data": result, "message": "success" } except Exception as e: return { "code": 1, "message": str(e) } async def handle_collection( data: WxappRequest, db: Session, user_collection: CRUDUserCollectionPraction ): """处理收藏相关操作""" operations = { "add": add_collection, "remove": remove_collection, "list": list_collections, } operation = operations.get(data.op) if not operation: return { "code": 1, "message": f"Unsupported operation: {data.op}" } try: result = await operation(data.uid, data.data, db, user_collection) return { "code": 0, "data": result, "message": "success" } except Exception as e: return { "code": 1, "message": str(e) } async def handle_wrong_question( data: WxappRequest, db: Session, user_wrong_praction: CRUDUserWrongPraction ): """处理错题相关操作""" operations = { "add": add_wrong_question, "remove": remove_wrong_question, "list": list_wrong_questions, } operation = operations.get(data.op) if not operation: return { "code": 1, "message": f"Unsupported operation: {data.op}" } try: result = await operation(data.uid, data.data, db, user_wrong_praction) return { "code": 0, "data": result, "message": "success" } except Exception as e: return { "code": 1, "message": str(e) } async def handle_login2(data: WxappRequest, db: Session): """处理微信小程序登录2""" logger.info(f"处理登录请求: {data.uid}") try: # 修改这里,查找code的位置 # 首先检查data.data中是否有code code = data.data.get("code") if isinstance(data.data, dict) else None # 如果在data.data中没有找到code,尝试直接从data对象获取 if not code and hasattr(data, "code"): code = data.code logger.debug(f"登录请求数据: {data}") if not code: logger.warning(f"登录失败: code为空 - UID: {data.uid}") return { "code": 1, "message": "code值获取失败", "data": {"message": "code值获取失败"} } try: # 调用微信API获取openid和session_key logger.debug(f"开始调用微信API: code={code}") wx_info = await wx_api.code2session(code) logger.debug(f"微信API返回结果: {wx_info}") except httpx.ConnectTimeout: # 特别处理连接超时错误 logger.error("连接微信服务器超时,请检查网络连接") return { "code": 1, "message": "连接微信服务器超时,请稍后再试", "data": {"message": "网络连接问题,无法连接到微信服务器"} } except Exception as e: logger.error(f"微信API调用失败: {str(e)}", exc_info=True) return { "code": 1, "message": "获取用户信息失败", "data": {"message": str(e)} } # 检查是否有错误 if wx_info.get("errcode") == 4001: return { "code": 1, "message": "获取用户信息失败", "data": {"message": wx_info.get("errmessage")} } # 确保weid是整数 try: weid = int(settings.WECHAT_UNIACID) except ValueError: # 如果无法转换为整数,使用默认值 logger.warning(f"WECHAT_UNIACID '{settings.WECHAT_UNIACID}' 无法转换为整数,使用默认值1") weid = 1 # 查询用户 - 注意这里是用openid和weid查询 users = full_exam_user.get_by_openid_and_weid( db, wx_info["openid"], weid # 使用整数weid ) info_status = 2 # 默认状态 # 构建用户数据 current_time = int(datetime.now().timestamp()) user_data = { "openid": wx_info["openid"], "nickname": data.data.get("nickName"), "nativeplace": f"{data.data.get('province')},{data.data.get('city')}", "headimg": data.data.get("avatarUrl"), "unionid": wx_info.get("unionid"), "createtime": current_time, "weid": weid, # 现在weid已定义 "last_login_time": current_time, "h5_openid": wx_info["openid"] } if not users: logger.debug(f"用户不存在,创建新用户: {user_data}") # 创建新用户 - 使用CRUD实例 try: logger.debug(f"创建新用户: {user_data}") # 使用UserMemberCreate schema需要导入 from mooc.schemas.goouc_fullexam_user import FullExamUserCreate # 转换为schema对象 user_create_schema = FullExamUserCreate(**user_data) # 使用CRUD实例创建用户 new_user = full_exam_user.create(db, obj_in=user_create_schema) uid = new_user.id except Exception as e: logger.error(f"创建新用户失败: {e}") return { "code": 1, "message": "用户数据插入失败", "data": str(e) } # 处理二维码生成 try: logger.debug(f"开始生成二维码") access_token = await wx_api.get_access_token() # 创建二维码目录 qrcode_path = "../addons/goouc_fullexam/Qrcode/" if not os.path.exists(qrcode_path): os.makedirs(qrcode_path, mode=0o777, exist_ok=True) filename = f"qrcode_{uid}.jpg" # 生成二维码并保存 res = await wx_api.save_unlimited_qrcode( uid, qrcode_path, filename, access_token ) if res: # 更新用户二维码路径 - 使用CRUD实例 from mooc.schemas.goouc_fullexam_user import FullExamUserUpdate update_data = {"qrcode": os.path.join(qrcode_path, filename)} update_schema = FullExamUserUpdate(**update_data) # 使用CRUD实例更新用户 full_exam_user.update(db, db_obj=new_user, obj_in=update_schema) except Exception as e: logger.error(f"生成二维码错误: {e}") return { "code": 1, "message": "生成二维码错误了", "data": str(e) } else: logger.debug(f"用户存在,更新用户信息: {users}") # 检查用户状态 if users.status != 1: return { "code": 1, "message": "您已被禁用,请联系管理员处理~", "data": users } # 更新用户信息 - 使用CRUD实例 try: logger.debug(f"开始更新用户信息: {user_data}") from mooc.schemas.goouc_fullexam_user import FullExamUserUpdate update_schema = FullExamUserUpdate(**user_data) full_exam_user.update(db, db_obj=users, obj_in=update_schema) uid = users.id if users.phone: info_status = 1 except Exception as e: logger.error(f"更新用户信息失败: {e}") return { "code": 1, "message": "更新用户信息失败", "data": str(e) } logger.info(f"登录成功,用户ID: {uid}, 状态: {info_status}") return ResponseFactory.success( data={"uid": uid, "info_status": info_status, "info": {"uid": uid, "info_status": info_status}}, message="登录成功" ) except Exception as e: logger.exception(f"登录过程发生未处理异常: {str(e)}") return ResponseFactory.error( code=1, message=f"登录失败: {str(e)}", data=None ) async def handle_share( data: WxappRequest, uniacid, db: Session, setting_mapper: CRUDSetting, sharing_mapper: CRUDShareRecord, user_mapping: CRUDFullExamUser ): uid = int(data.uid) if not uid: return {"code": 1, "message": "传递的参数不存在", "data": "1001"} user_info = user_mapping.get_user_info(db, uniacid, uid) if not user_info: return {"code": 1, "message": "用户不存在", "data": "1001"} if user_info["status"] != 1: return {"code": 1, "message": "用户被禁用", "data": "1002"} setting = setting_mapper.get_setting_1(db, uniacid) day_num = sharing_mapper.get_share_record_1(db, uniacid, uid) if setting["shareupper"] == 0: data = {} if setting["share_integral"] != 0: if day_num: update = { "num": day_num["num"] + setting["share_integral"], "day": datetime.now().strftime("%Y-%m-%d"), "createtime": int(time.time()) } result = sharing_mapper.update_share_record(db, update, day_num["id"], day_num["uid"]) if result > 0: data["integral"] = user_info["integral"] + setting["share_integral"] res = user_mapping.update_user_info(db, data, user_info["id"]) else: insert = { "uid": uid, "weid": uniacid, "num": setting["share_integral"], "istatus": 1, "day": datetime.now().strftime("%Y-%m-%d"), "createtime": int(time.time()) } result = sharing_mapper.create(db, obj_in=insert) if result > 0: data["integral"] = user_info["integral"] + setting["share_integral"] res = user_mapping.update_user_info(db, data, user_info["id"]) else: if setting["share_integral"] != 0: data = {} if day_num: if day_num["num"] < setting["shareupper"]: can_num = setting["shareupper"] - day_num["num"] if setting["share_integral"] <= can_num: update = { "num": day_num["num"] + setting["share_integral"], "day": datetime.now().strftime("%Y-%m-%d"), "createtime": int(time.time()) } result = sharing_mapper.update_share_record(db, update, day_num["id"], day_num["uid"]) if result: data["integral"] = user_info["integral"] + setting["share_integral"] res = user_mapping.update_user_info(db, data, user_info["id"]) else: insert = { "uid": uid, "weid": uniacid, "num": setting["share_integral"], "istatus": 1, "day": datetime.now().strftime("%Y-%m-%d"), "createtime": int(time.time()) } result = sharing_mapper.create(db, obj_in=insert) if result > 0: data["integral"] = user_info["integral"] + setting["share_integral"] res = user_mapping.update_user_info(db, data, user_info["id"]) if res: return {"status": 0, "message": "分享成功", "data": {"code": 1, "num": setting["share_integral"]}} else: return {"status": 1, "message": "分享失败", "data": {"code": 2}} async def handle_add_wrong( data: WxappRequest, uniacid, db: Session): uid = data.uid tid = data.data["tid"] test_type = data.data.get("test_type") iscollect = data.data.get("wrong_have") if not uid or not tid or not test_type or not iscollect: return {"code": 1, "message": "传递的参数不存在或失效", "data": "1001"} user_info = full_exam_user.get_user_info(db, uniacid, int(uid)) if not user_info: return {"code": 1, "message": "用户不存在", "data": "1002"} if user_info["status"] != 1: return {"code": 1, "message": "用户被禁用", "data": "1003"} have = user_collection_praction.get_user_collection_praction_1(db, uniacid, uid, tid) mess = 0 if not have: insert = { "weid": uniacid, "uid": uid, "testid": tid, "test_type": test_type, "istatus": 1, "createtime": int(time.time()) } res = user_collection_praction.create(db, obj_in=insert) mess = 1 else: res = user_collection_praction.delete_user_collection_praction(db, uniacid, uid, tid) if res: return {"code": 0, "message": "操作成功", "data": mess} else: return {"code": 1, "message": "操作失败", "data": "1005"}