第一组 - U-Linker - 第二篇冲刺博客
| Fifth Assignment | U-Linker |
|---|---|
| 课程 | EE308FZ - 软件工程 |
| 要求 | Fifth Assignment——Alpha Sprint |
| 目标 | 记录冲刺阶段第3-4天的项目进展、团队协作与问题解决 |
目录
- 第一组 - U-Linker - 第二篇冲刺博客
- I. 项目燃起图
- II. 模块运行展示
- III. 重点代码
- 1. 个人中心(“我的”)
- 2. 编辑个人信息
- 3. 积分明细
- IV. 成员分工 & 提交记录
I. 项目燃起图
截至目前(第4天),项目的整体进度如下:
项目目前剩余工作量为 68%。相比于理想状态下的剩余工作量(约 66.7%),我们的实际进度曲线(红线)略微浮于理想曲线(蓝线)上方。这意味着我们存在极小幅度的任务积压(约 1-2% 的偏差),但整体处于完全可控的范围内。
II. 模块运行展示
我们的UI设计与前端开发组完成了个人中心页面的深度交互,实现了用户头像、昵称及积分数据的实时响应式展示。同时,重点攻克了积分明细的可视化列表渲染,通过动态样式逻辑自动区分“收入”与“支出”的视觉反馈。
我们的后端开发组完成了项目最核心的交易模块开发,实现了“购买服务”与“悬赏任务申请/选人”的复杂业务逻辑,确立了订单状态流转与积分扣除机制。此外,新增了即时通讯模块的API接口,支持创建会话与发送消息,并升级了用户信息接口,实现了头像文件的上传、重命名与存储逻辑,打通了从用户交互到数据库持久化的完整链路。
我们的测试与体验优化组完成了对新上线的交易接口与聊天接口的边界测试,重点验证了积分不足、重复申请任务等异常场景下的系统稳定性。同时,对个人中心进行了前后端联调测试,确保前端修改的信息能准确无误地同步至数据库,且页面加载时的状态回显迅速、准确。
- 编辑个人信息
- 积分明细
III. 重点代码
1. 个人中心(“我的”)
前端
响应式数据绑定与用户交互
个人中心页面的模板设计充分体现了Vue的数据驱动特性。我们使用多种绑定语法将JavaScript数据与HTML元素无缝连接,当数据变化时,视图会自动更新,无需手动操作DOM。这种设计模式既提升了开发效率,也保证了用户体验的一致性。
<template><!-- 数据绑定 --><h2class="text-xl font-bold text-gray-900 truncate">{{ userInfo.name }}</h2><!-- 条件渲染 --><spanv-if="unreadMessages > 0"class="bg-red-500 text-white text-[10px] px-1.5 rounded-full">{{ unreadMessages }}</span><!-- 事件绑定 --><button@click="handleEditProfile">编辑</button><!-- 动态属性绑定 -->< img :src="userInfo.avatar" alt="用户头像"><!-- 响应式积分显示 --><divclass="text-3xl font-bold font-mono tracking-wider">{{ userInfo.points }}</div></template>后端
通过 models.py 定义用户结构,并提供 /auth/profile 接口供前端获取当前用户的核心数据(如头像、积分、姓名)。
classUser(db.Model):__tablename__='user'id=db.Column(db.Integer,primary_key=True)username=db.Column(db.String(50),unique=True,nullable=False)name=db.Column(db.String(50))points=db.Column(db.Integer,default=100)# 对应前端显示的积分avatar=db.Column(db.String(200))# 对应前端绑定的 :src# ...defto_dict(self):return{'id':self.id,'username':self.username,'name':self.name,'points':self.points,'avatar':self.avatar}@auth_bp.route('/profile',methods=['GET'])defget_profile():# 获取 URL 参数 user_iduser_id=request.args.get('user_id')# ...# 在数据库中查找user=db.session.get(User,user_id)ifuser:returnsuccess(data=user.to_dict())# 返回包含 points, avatar 的字典else:returnerror(message="用户不存在")2. 编辑个人信息
前端
(1)这是Vue最核心的功能,建立了表单输入框和JavaScript数据之间的双向连接。用户输入 → 自动更新数据;数据变化 → 自动更新界面显示。
<!-- 模板部分 --><inputtype="text"v-model="formData.username"<!--核心:双向数据绑定-->@input="validateUsername" ><!-- 数据部分 --><scriptsetup>constformData=reactive({username:'李晓明'// 与v-model建立双向连接})</script>(2)实现了边输入边验证的体验,用户不需要点击提交按钮就能立即得到反馈。
<inputtype="text"v-model="formData.username"@input="validateUsername"<!--核心:输入时实时触发验证-->><scriptsetup>// 核心验证函数constvalidateUsername=()=>{constusername=formData.username.trim()if(username===''){validationErrors.username='用户名不能为空'}elseif(username.length<2){validationErrors.username='用户名至少2个字符'}else{validationErrors.username=''checkUsernameUnique(username)// 触发异步验证}}</script>(3)自动计算表单是否有效,并智能控制保存按钮状态,用户界面状态完全由数据驱动。
<scriptsetup>// 核心:计算表单验证状态constisFormValid=computed(()=>{returnformData.username.trim()!==''&&!validationErrors.username})</script><!-- 使用计算属性 --><button :disabled="!isFormValid"<!-- 核心:自动启用/禁用按钮 -->@click="handleSave" > 保存修改</button>后端
(1)数据接收与处理 (auth.py):对应前端的双向绑定,后端在 update_profile 接口接收表单数据。虽然前端做了验证,后端依然需要验证用户是否存在。
@auth_bp.route('/update_profile',methods=['POST'])defupdate_profile():# 1. 获取当前用户user_id=request.form.get('user_id')# ...user=db.session.get(User,user_id)ifnotuser:returnerror(message="用户不存在")# 2. 修改普通资料 (对应前端 v-model 绑定的数据)new_name=request.form.get('name')ifnew_name:user.name=new_name# ...(2)实时验证支持:虽然代码中未展示专门的“检查用户名唯一性”的独立接口,但在注册接口中存在类似的逻辑,可被复用或封装以支持前端的 checkUsernameUnique。
# 逻辑参考:检查重复 (auth.py 中的 register 函数)existing_user=User.query.filter(or_(User.username==username,User.student_id==student_id)).first()ifexisting_user:# 返回错误信息供前端展示ifexisting_user.username==username:returnerror(message="该用户名已经被注册")(3)保存修改与头像上传 (auth.py):对应前端“保存修改”按钮的点击事件。后端处理文件上传、重命名(防止冲突)以及更新数据库路径。
# ...接 update_profile 函数try:# 3. 处理头像上传 (对应前端文件输入)if'avatar'inrequest.files:file=request.files['avatar']# 检查文件是否存在且格式合法iffileandallowed_file(file.filename):# 为了防止文件名冲突,重命名为: user_id_时间戳.jpgext=file.filename.rsplit('.',1)[1].lower()filename=secure_filename(f"user_{user.id}_{int(datetime.now().timestamp())}.{ext}")# ...保存文件逻辑 (省略路径拼接代码)...file.save(file_path)# 4. 更新数据库里的路径user.avatar=url_for('static',filename=f'avatars/{filename}')db.session.commit()# 提交事务,完成保存returnsuccess(message="个人资料修改成功",data=user.to_dict())# ...3. 积分明细
前端
(1)通过ref和reactive建立集中式数据源,积分总额与明细记录完全响应式,一处更新处处同步。
<scriptsetup>import{ref,reactive,computed}from'vue'// 核心:积分总额响应式管理consttotalPoints=ref(350)// 核心:积分明细列表响应式数据constpointsRecords=reactive([{id:1,title:'完成任务:数据标注',amount:90,type:'income',icon:'mdi:check-circle-outline',color:'green',date:'2025-11-05 14:30',status:'任务完成'},// ...更多记录])</script>(2)利用动态CSS类绑定实现收入/支出自动颜色区分,图标、背景、文字颜色完全由数据类型驱动。
<template><!-- 积分记录列表 --><divv-for="record in pointsRecords":key="record.id"class="bg-white p-4 rounded-xl shadow-sm border border-gray-100 flex justify-between items-center"><!-- 图标区域:动态样式绑定 --><divclass="flex items-center gap-3"><div:class="['w-10 h-10 rounded-full flex items-center justify-center', record.type ==='income'?'bg-green-50 text-green-600':'bg-red-50 text-red-500']"><spanclass="iconify w-6 h-6":data-icon="record.icon"></span></div><div><divclass="text-sm font-bold text-gray-800">{{ record.title }}</div><divclass="text-xs text-gray-400 mt-0.5">{{ record.date }}</div></div></div><!-- 金额区域:动态样式绑定 --><divclass="text-right"><div:class="['text-lg font-bold', record.type ==='income'?'text-green-600':'text-red-500']">{{ record.type === 'income' ? '+' : '-' }}{{ record.amount }}</div><divclass="text-[10px] text-gray-400">{{ record.status }}</div></div></div></template>(3)通过computed属性实现智能数据筛选与实时统计,时间筛选、收入支出分类统计完全自动化计算。
<scriptsetup>// 核心:筛选条件响应式管理constfilterPeriod=ref('month')// 核心:计算属性实现智能筛选constfilteredRecords=computed(()=>{constnow=newDate()constthirtyDaysAgo=newDate(now.setDate(now.getDate()-30))returnpointsRecords.filter(record=>{constrecordDate=newDate(record.date)if(filterPeriod.value==='month'){// 筛选本月记录returnrecordDate.getMonth()===newDate().getMonth()}elseif(filterPeriod.value==='week'){// 筛选本周记录constweekAgo=newDate(now.setDate(now.getDate()-7))returnrecordDate>=weekAgo}returntrue})})// 核心:统计计算consttotalIncome=computed(()=>{returnfilteredRecords.value.filter(record=>record.type==='income').reduce((sum,record)=>sum+record.amount,0)})consttotalExpense=computed(()=>{returnfilteredRecords.value.filter(record=>record.type==='expense').reduce((sum,record)=>sum+record.amount,0)})</script>后端
(1)数据源定义 (models.py):后端没有独立的积分流水表,而是通过 Order(订单)表来记录交易。前端的“积分记录”对应后端的订单记录。
classOrder(db.Model):__tablename__='orders'# ...buyer_id=db.Column(db.Integer,db.ForeignKey('user.id'),nullable=False)# 买家 (支出方)seller_id=db.Column(db.Integer,db.ForeignKey('user.id'),nullable=False)# 卖家 (收入方)# ...price=db.Column(db.Integer,default=0)# 对应积分金额created_at=db.Column(db.DateTime,default=datetime.now)# 对应时间(2)获取交易记录 (transaction.py):对应前端的列表渲染。后端查询我参与的所有订单(我是买家或我是卖家),前端根据 buyer_id 或 seller_id 是否为当前用户来判断是 income(收入/绿色)还是 expense(支出/红色)。
@transaction_bp.route('/my_involved',methods=['GET'])defget_my_involved():user_id=request.args.get('user_id')# ...# 核心逻辑: 只要 buyer_id 是我,或者 seller_id 是我,都算我参与的query=Order.query.filter(or_(Order.buyer_id==user_id,Order.seller_id==user_id)).order_by(Order.created_at.desc())# 按时间倒序,对应前端的时间排序# 分页返回,支持前端的滚动加载或分页pagination=query.paginate(page=page,per_page=per_page,error_out=False)returnsuccess(data={'total':pagination.total,# ...'items':[o.to_dict()foroinpagination.items]# 返回数据列表供前端 v-for})IV. 成员分工 & 提交记录
| Student ID | Name (姓名) | Work (工作) | Contribution (贡献) |
|---|---|---|---|
| 832301330 | 颜一顺 | Backend Development | 8.5% |
| 832302227 | 程一鸣 | Backend Development | 8.5% |
| 832301320 | 陶炯 | Backend Development | 8.5% |
| 832301326 | 曾渝 | Backend Development | 8.5% |
| 832302213 | 林语婧 | Front-end development | 8.5% |
| 832302230 | 薛易明 | Front-end development | 8.5% |
| 832302209 | 陈舒薇 | Front-end development | 8.5% |
| 832301123 | 杨璐 | Front-end development | 8.5% |
| 832301315 | 高子言 | Front-end development | 8.5% |
| 832302225 | 黄祉睿 | Testing and Optimization | 8.5% |
| 832302202 | 张健涛 | UI Design | 7.5% |
| 832302205 | 陈乐晗 | UI Design | 7.5% |
提交记录:
GitHub链接