feat(wxapp): 实现分享功能并优化用户信息相关操作

- 新增分享功能处理逻辑,包括获取设置、记录分享次数和更新用户积分
- 优化用户信息获取和更新操作,提高代码复用性和可维护性
- 添加错题收藏功能,支持用户对错题进行收藏和取消收藏
- 重构部分代码,提高可读性和性能
This commit is contained in:
Basyc 2025-03-07 21:13:18 +08:00
parent 7ace7db5c5
commit 97a61189ea
3 changed files with 445 additions and 161 deletions

View File

@ -1,10 +1,12 @@
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,
@ -20,20 +22,21 @@ from mooc.models.goouc_fullexam_user import (
)
from mooc.core.config import settings
from mooc.utils.wechat_client import wx_api
from datetime import datetime
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 setting, xueshen
from mooc.crud.crud_goouc_fullexam_user import full_exam_user, user_member
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
@ -53,6 +56,7 @@ class WxappRequest(BaseModel):
return getattr(self, field_name)
return self.data.get(field_name, default)
@wxapp_router.post("/index")
async def handle_wxapp_request(
request: Request,
@ -121,10 +125,18 @@ async def handle_wxapp_request(
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}")
@ -159,6 +171,7 @@ async def handle_update_headimg(data: WxappRequest, db: Session):
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
@ -254,6 +267,8 @@ async def handle_upload_image(data: WxappRequest, db: Session, file: UploadFile
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):
@ -270,6 +285,7 @@ def validate_phone(phone: str) -> bool:
return True
async def handle_set_user_info(data: WxappRequest, db: Session):
"""处理用户信息相关操作"""
logger.info(f"处理用户信息请求: op={data.op}, uid={data.uid},data={data}")
@ -348,6 +364,7 @@ async def handle_set_user_info(data: WxappRequest, db: Session):
message=str(e)
)
# 获取用户信息
async def get_user_info(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]:
"""获取用户详细信息"""
@ -445,6 +462,7 @@ async def get_user_info(uid: str, data: Dict[str, Any], db: Session) -> Dict[str
return {"info": info, "http": http}
# 检查学生信息
async def check_student(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]:
"""检查学生信息是否存在"""
@ -454,13 +472,10 @@ async def check_student(uid: str, data: Dict[str, Any], db: Session) -> Dict[str
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,
@ -481,6 +496,7 @@ async def check_student(uid: str, data: Dict[str, Any], db: Session) -> Dict[str
return {"list": student_info}
# 获取验证码
async def get_verification_code(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]:
"""发送手机验证码"""
@ -490,7 +506,6 @@ async def get_verification_code(uid: str, data: Dict[str, Any], db: Session) ->
if not validate_phone(phone):
raise ValueError("手机号有误")
user = full_exam_user.get(db, int(uid))
if not user:
raise ValueError("用户不存在")
@ -528,6 +543,7 @@ async def get_verification_code(uid: str, data: Dict[str, Any], db: Session) ->
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]:
"""验证手机验证码"""
@ -601,6 +617,7 @@ async def check_verification_code(uid: str, data: Dict[str, Any], db: Session) -
db.rollback()
raise ValueError(f"更新手机号失败: {str(e)}")
# 更新用户信息
async def update_user_info(uid: str, data: Dict[str, Any], db: Session) -> Dict[str, Any]:
"""更新用户基本信息"""
@ -654,6 +671,7 @@ async def update_user_info(uid: str, data: Dict[str, Any], db: Session) -> Dict[
db.rollback()
raise ValueError(f"信息保存失败: {str(e)}")
async def handle_exam_operation(
data: WxappRequest,
db: Session,
@ -687,6 +705,7 @@ async def handle_exam_operation(
"message": str(e)
}
async def handle_collection(
data: WxappRequest,
db: Session,
@ -719,6 +738,7 @@ async def handle_collection(
"message": str(e)
}
async def handle_wrong_question(
data: WxappRequest,
db: Session,
@ -936,3 +956,128 @@ async def handle_login2(data: WxappRequest, db: Session):
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"}

View File

@ -111,6 +111,7 @@ class CRUDPaperTest(CRUDBase[PaperTest, PaperTestCreate, PaperTestUpdate]):
class CRUDPhonecode(CRUDBase[Phonecode, PhoneCodeCreate, PhoneCodeUpdate]):
def get_phonecode(self, db: Session, phonecode_id: int):
return self.get_by_field(db, "id", phonecode_id)
def get_latest_by_phone(self, db: Session, phone: str, weid: int):
"""获取指定手机号的最新验证码记录"""
return db.query(self.model).filter(
@ -118,6 +119,7 @@ class CRUDPhonecode(CRUDBase[Phonecode, PhoneCodeCreate, PhoneCodeUpdate]):
self.model.weid == weid
).order_by(self.model.createtime.desc()).first()
class CRUDQYear(CRUDBase[QYear, QYearCreate, QYearUpdate]):
def get_qyear(self, db: Session, qyear_id: int):
return self.get_by_field(db, "id", qyear_id)
@ -132,11 +134,70 @@ class CRUDSetting(CRUDBase[Setting, SettingCreate, SettingUpdate]):
def get_setting(self, db: Session, setting_id: int):
return self.get_by_field(db, "id", setting_id)
def get_setting_1(self, session: Session, uniacid: int):
# 执行查询并获取第一条结果
result = session.query(
self.model.share_integral,
self.model.share_title,
self.model.shareupper
).filter(
self.model.weid == uniacid
).first()
# 将结果转换为字典格式
if result:
return {
"share_integral": result[0],
"share_title": result[1],
"shareupper": result[2]
}
return {}
class CRUDShareRecord(CRUDBase[ShareRecord, ShareRecordCreate, ShareRecordUpdate]):
def get_share_record(self, db: Session, share_record_id: int):
return self.get_by_field(db, "id", share_record_id)
def get_share_record_1(self, session: Session, uniacid: int, uid: int):
# 生成当天日期字符串
current_day = datetime.now().strftime("%Y-%m-%d")
# 构建查询并获取结果
result = session.query(
self.model.id,
self.model.uid,
self.model.num
).filter(
self.model.weid == uniacid,
self.model.uid == uid,
self.model.day == current_day
).first()
# 转换结果类型
# return result._asdict() if result else {} # 适用于 SQLAlchemy 2.x 的 Row 对象
# 或者手动构建字典(兼容更多版本)
return dict(zip(['id', 'uid', 'num'], result)) if result else {}
def update_share_record(
self,
session: Session,
update_data: dict,
record_id: int,
user_id: int
) -> int:
try:
# 执行更新操作
affected_rows = session.query(self.model).filter(
self.model.id == record_id,
self.model.uid == user_id
).update(update_data)
session.commit()
return affected_rows
except Exception as e:
session.rollback()
print(f"更新失败: {str(e)}")
return 0
class CRUDsonSimple(CRUDBase[SonSimple, SonSimpleCreate, SonSimpleUpdate]):
def get_son_simple(self, db: Session, son_simple_id: int):

View File

@ -98,6 +98,47 @@ class CRUDUserCollectionPraction(
CRUDBase[UserCollectionPraction, UserCollectionPractionCreate, UserCollectionPractionUpdate]):
def get_user_collection_praction(self, db: Session, user_collection_praction_id: int):
return self.get_by_field(db, "id", user_collection_praction_id)
def get_user_collection_praction_1(
self,
session: Session,
uniacid: int,
uid: int,
testid: int
) -> dict:
result = session.query(
self.model
).filter(
self.model.weid == uniacid,
self.model.istatus == 1,
self.model.uid == uid,
self.model.testid == testid
).first()
return result.__dict__ if result else {}
def delete_user_collection_praction(
self,
session: Session,
uniacid: int,
uid: int,
testid: int
) -> int:
try:
# 执行删除操作
affected_rows = session.query(
self.model
).filter(
self.model.weid == uniacid,
self.model.uid == uid,
self.model.testid == testid
).delete()
session.commit()
return affected_rows
except Exception as e:
session.rollback()
print(f"删除失败: {str(e)}")
return 0
class CRUDUserGift(CRUDBase[UserGift, UserGiftCreate, UserGiftUpdate]):
@ -134,10 +175,48 @@ class CRUDUserPool(CRUDBase[UserPool, UserPoolCreate, UserPoolUpdate]):
def get_user_pool(self, db: Session, user_pool_id: int):
return self.get_by_field(db, "id", user_pool_id)
class CRUDFullExamUser(CRUDBase[FullExamUser, FullExamUserCreate, FullExamUserUpdate]):
def get_full_exam_user(self, db: Session, full_exam_user_id: int):
return self.get_by_field(db, "id", full_exam_user_id)
def get_user_info(self, session: Session, uniacid: int, uid: int):
# 构建查询并获取第一条结果
result = session.query(
self.model.id,
self.model.integral,
self.model.status
).filter(
self.model.weid == uniacid,
self.model.id == uid
).first()
# 转换为字典格式
fields = ["id", "integral", "status"]
if result is not None:
return dict(zip(fields, result))
return {}
def update_user_info(
self,
session: Session,
update_data: dict,
user_id: int
) -> int:
try:
# 执行更新操作
affected_rows = session.query(self.model).filter(
self.model.id == user_id
).update(update_data)
session.commit()
return affected_rows
except Exception as e:
session.rollback()
print(f"更新失败: {str(e)}")
return 0
def get_by_openid_and_weid(self, db: Session, openid: str, weid: int, istatus: int = 1):
"""通过openid和weid获取用户"""
return db.query(self.model).filter(
@ -154,6 +233,7 @@ class CRUDFullExamUser(CRUDBase[FullExamUser, FullExamUserCreate, FullExamUserUp
self.model.istatus == istatus
).first()
# 创建实例
user_doexam = CRUDUserDoexam(UserDoexam)
user_doother_exam_answer = CRUDUserDoOtherExamAnswer(UserDoOtherExamAnswer)
@ -170,5 +250,3 @@ user_doother_exam = CRUDUserDoOtherExam(UserDootherExam)
user_wrong_praction = CRUDUserWrongPraction(UserWrongPraction)
user_pool = CRUDUserPool(UserPool)
full_exam_user = CRUDFullExamUser(FullExamUser)