第二天项目
苍穹外卖项目 - 第2天冲刺日志
日期:2025-11-27
冲刺周期:第2天/共7天
参与人员:李靖华 温尚熙 谢斯越 郑哲磊
二、会议内容记录
郑哲磊(后端负责人)
昨天已完成的工作:
- ✅ [WI-001] 搭建Spring Boot项目基础架构
- ✅ [WI-002] 配置MySQL数据库连接
- ✅ [WI-003] 配置Redis缓存
- ✅ [WI-004] 完成员工登录接口开发
今天计划完成的工作:
- [WI-017] 完成员工管理CRUD接口
- [WI-018] 实现JWT token认证机制
- [WI-019] 完成菜品分类管理接口
- [WI-020] 编写接口文档(Swagger)
工作中遇到的困难:
- JWT token刷新机制设计需要与前端协商
- Redis连接池配置需要优化
谢斯越(前端负责人)
昨天已完成的工作:
- ✅ [WI-005] 搭建管理端前端项目框架
- ✅ [WI-006] 完成登录页面UI设计
- ✅ [WI-007] 实现登录功能前端逻辑
- ✅ [WI-008] 配置axios请求拦截器
今天计划完成的工作:
- [WI-021] 完成主页布局和导航菜单
- [WI-022] 实现员工管理页面
- [WI-023] 完成分类管理页面
- [WI-024] 实现token自动刷新机制
工作中遇到的困难:
- Element Plus表格组件的分页功能需要深入学习
- 路由权限控制逻辑较复杂
温尚熙(小程序开发)
昨天已完成的工作:
- ✅ [WI-009] 初始化微信小程序项目
- ✅ [WI-010] 设计小程序首页布局
- ✅ [WI-011] 完成菜品分类展示页面
- ✅ [WI-012] 配置小程序网络请求
今天计划完成的工作:
- [WI-025] 实现菜品列表页面
- [WI-026] 完成菜品详情页面
- [WI-027] 实现购物车功能
- [WI-028] 完成用户授权登录
工作中遇到的困难:
- 微信授权登录需要后端配合,等待接口开发
- 购物车数据持久化方案需要确定
李靖华(测试与文档)
昨天已完成的工作:
- ✅ [WI-013] 编写项目需求文档
- ✅ [WI-014] 设计数据库表结构
- ✅ [WI-015] 编写接口测试用例
- ✅ [WI-016] 搭建测试环境
今天计划完成的工作:
- [WI-029] 执行登录接口测试
- [WI-030] 编写员工管理测试用例
- [WI-031] 更新API文档
- [WI-032] 进行代码质量检查
工作中遇到的困难:
- 部分接口返回格式不统一,需要规范化
- 测试数据准备工作量较大
三、燃尽图
剩余工作量(小时)
120 |●
| \
100 | ●
| \\
80 | \
| \
60 | \
| \
40 | \
| \
20 | \
| ●
0 |__________________________
1 2 3 4 5 6 7 (天数)
图例:
● —— 实际进度(实线)
- - - 理想进度(虚线)
四、代码/文档签入记录
郑哲磊 - 员工管理与JWT认证模块
- 模块名称:sky-server 员工管理模块
- 提交内容:
- 完成员工增删改查接口
- 实现JWT token生成和验证
- 添加全局异常处理器
代码示例:
// EmployeeController.java - 员工管理控制器
@RestController
@RequestMapping("/admin/employee")
@Slf4j
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping("/login")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO dto) {
Employee employee = employeeService.login(dto);
// 生成JWT token
Map<String, Object> claims = new HashMap<>();
claims.put("empId", employee.getId());
String token = JwtUtil.createJWT(jwtProperties.getSecretKey(),
jwtProperties.getTtl(), claims);
EmployeeLoginVO vo = EmployeeLoginVO.builder()
.id(employee.getId())
.userName(employee.getUsername())
.name(employee.getName())
.token(token)
.build();
return Result.success(vo);
}
@PostMapping
public Result save(@RequestBody EmployeeDTO dto) {
employeeService.save(dto);
return Result.success();
}
}
// JwtUtil.java - JWT工具类
public class JwtUtil {
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long expMillis = System.currentTimeMillis() + ttlMillis;
Date exp = new Date(expMillis);
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))
.setExpiration(exp);
return builder.compact();
}
}
谢斯越 - 管理端员工管理页面模块
- 模块名称:sky-admin 员工管理页面
- 提交内容:
- 完成主页布局和侧边栏导航
- 实现员工管理页面CRUD功能
- 添加表单验证和错误提示
代码示例:
<!-- EmployeeList.vue - 员工列表页面 -->
<template>
<div class="employee-container">
<el-button type="primary" @click="handleAdd">新增员工</el-button>
<el-table :data="employeeList" style="margin-top: 20px">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="phone" label="手机号" />
<el-table-column label="状态">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? '启用' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="page"
v-model:page-size="pageSize"
:total="total"
@current-change="getEmployeeList"
/>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getEmployeeListApi, deleteEmployeeApi } from '@/api/employee'
import { ElMessage } from 'element-plus'
const employeeList = ref([])
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const getEmployeeList = async () => {
const { data } = await getEmployeeListApi({ page: page.value, pageSize: pageSize.value })
employeeList.value = data.records
total.value = data.total
}
const handleDelete = async (id) => {
await deleteEmployeeApi(id)
ElMessage.success('删除成功')
getEmployeeList()
}
onMounted(() => {
getEmployeeList()
})
</script>
温尚熙 - 小程序菜品展示模块
- 模块名称:sky-user 菜品展示模块
- 提交内容:
- 完成菜品列表页面
- 实现分类切换功能
- 添加菜品搜索功能
代码示例:
// pages/index/index.js - 菜品列表页面
Page({
data: {
categoryList: [],
dishList: [],
currentCategory: 0,
searchKey: ''
},
onLoad() {
this.getCategoryList()
this.getDishList()
},
// 获取分类列表
getCategoryList() {
wx.request({
url: getApp().globalData.baseUrl + '/user/category/list',
method: 'GET',
success: (res) => {
this.setData({
categoryList: res.data.data
})
}
})
},
// 获取菜品列表
getDishList() {
wx.request({
url: getApp().globalData.baseUrl + '/user/dish/list',
method: 'GET',
data: {
categoryId: this.data.currentCategory,
name: this.data.searchKey
},
success: (res) => {
this.setData({
dishList: res.data.data
})
}
})
},
// 切换分类
onCategoryChange(e) {
this.setData({
currentCategory: e.currentTarget.dataset.id
})
this.getDishList()
},
// 搜索菜品
onSearch(e) {
this.setData({
searchKey: e.detail.value
})
this.getDishList()
}
})
<!-- pages/index/index.wxml - 菜品列表页面结构 -->
<view class="container">
<!-- 搜索框 -->
<view class="search-box">
<input placeholder="搜索菜品" bindinput="onSearch" />
</view>
<!-- 分类列表 -->
<scroll-view class="category-list" scroll-x>
<view wx:for="{{categoryList}}" wx:key="id"
class="category-item {{currentCategory === item.id ? 'active' : ''}}"
data-id="{{item.id}}"
bindtap="onCategoryChange">
{{item.name}}
</view>
</scroll-view>
<!-- 菜品列表 -->
<view class="dish-list">
<view wx:for="{{dishList}}" wx:key="id" class="dish-item">
<image src="{{item.image}}" class="dish-image" />
<view class="dish-info">
<text class="dish-name">{{item.name}}</text>
<text class="dish-price">¥{{item.price}}</text>
</view>
</view>
</view>
</view>
李靖华 - 接口测试与文档模块
- 模块名称:测试用例与API文档
- 提交内容:
- 完成登录接口测试用例
- 编写员工管理接口测试脚本
- 更新API文档v2.0
测试用例示例:
// employee.test.js - 员工管理接口测试
const request = require('supertest');
const app = require('../app');
describe('员工管理接口测试', () => {
let token = '';
// 测试登录接口
test('POST /admin/employee/login - 登录成功', async () => {
const response = await request(app)
.post('/admin/employee/login')
.send({
username: 'admin',
password: '123456'
});
expect(response.status).toBe(200);
expect(response.body.code).toBe(1);
expect(response.body.data).toHaveProperty('token');
token = response.body.data.token;
});
// 测试获取员工列表
test('GET /admin/employee/page - 获取员工列表', async () => {
const response = await request(app)
.get('/admin/employee/page')
.set('token', token)
.query({ page: 1, pageSize: 10 });
expect(response.status).toBe(200);
expect(response.body.code).toBe(1);
expect(response.body.data).toHaveProperty('records');
});
// 测试新增员工
test('POST /admin/employee - 新增员工', async () => {
const response = await request(app)
.post('/admin/employee')
.set('token', token)
.send({
name: '测试员工',
username: 'test001',
phone: '13800138000',
sex: '1',
idNumber: '110101199001011234'
});
expect(response.status).toBe(200);
expect(response.body.code).toBe(1);
});
});
API文档示例:
## 员工管理接口
### 1. 员工登录
- 接口路径:POST /admin/employee/login
- 请求参数:
```json
{
"username": "admin",
"password": "123456"
}
浙公网安备 33010602011771号