diff --git a/.gitignore b/.gitignore index beb194f552546c1463ba99b998873e5093aab8dc..242194d270452cfc83d39fec46b90f3634d5f613 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,15 @@ +# Local extract / merge temp dirs +_leader_release_v1.0/ +_merge_backup/ +_leader_zip_latest/ +_merge_backup_user/ + +# Local backend restart logs / temp scripts +eshop-release-v1.0/backend-restart.log +eshop-release-v1.0/backend-restart.log.err +eshop-release-v1.0/scripts/_run-backend-tmp.bat +eshop-release-v1.0/scripts/_kill-8080.ps1 + # Local development tools downloaded only for this workstation /.tools/ diff --git a/.grok/project-skills.md b/.grok/project-skills.md new file mode 100644 index 0000000000000000000000000000000000000000..8bb8dc5219909fda3cbe70029db966247f76535e --- /dev/null +++ b/.grok/project-skills.md @@ -0,0 +1,19 @@ +# eshop-class2-group7 skill binding +# See also: D:\Knowledge\projects\eshop-class2-group7.md + +```yaml +skills_warm_required: [] +skills_optional: + - name: developing-backend-services + when: [api, spring, order, payment, review, seller] + - name: developing-frontend-apps + when: [vue, h5, vant] + - name: verification-before-completion + when: [test, ship, pr] + - name: recycle + when: [delete, rm, cleanup] +skills_never: + - gpt-taste +``` + +Default: backend/course workflow. Load UI design pair only when doing visual redesign. \ No newline at end of file diff --git "a/docs/03-\346\265\213\350\257\225\346\226\207\346\241\243/\347\273\204\345\221\2304-\351\252\214\346\224\266\345\213\276\351\200\211\347\273\223\346\236\234-20260805.md" "b/docs/03-\346\265\213\350\257\225\346\226\207\346\241\243/\347\273\204\345\221\2304-\351\252\214\346\224\266\345\213\276\351\200\211\347\273\223\346\236\234-20260805.md" new file mode 100644 index 0000000000000000000000000000000000000000..82b903db608d8c02200dd57f0f4074a11ae0075b --- /dev/null +++ "b/docs/03-\346\265\213\350\257\225\346\226\207\346\241\243/\347\273\204\345\221\2304-\351\252\214\346\224\266\345\213\276\351\200\211\347\273\223\346\236\234-20260805.md" @@ -0,0 +1,148 @@ +# 组员四 · 线上验收勾选结果 + +> 项目地址:https://eshop.zhuyiyuan9.top +> 测试日期:2026-08-05 +> 测试人:吴松青(组员四) +> 测试范围:**商家工作台** +> 测试版本:线上 `master`(健康检查 UP) +> 对照清单:`线上验收测试清单-20260805.md` + +--- + +## 一、提交信息(清单要求) + +| 项 | 内容 | +|----|------| +| 测试商家账号 | `user` / `user123`(角色 SELLER) | +| 测试商品 ID | **31**(名称含前缀 `[TEST]`) | +| 测试 SKU | **31**(黑/M,价 19.9)、**32**(白/L,价 29.9) | +| 测试订单号 | 见下表 | +| 结果 | **商家核心接口大部分通过**;「已支付→发货」缺数据未测;退出后 JWT 仍有效;UI/图片上传需人工确认 | + +### 本商家账号下现有订单 + +| 订单号 | 状态 | 金额 | +|--------|------|------| +| E20260805010519121B86CDCB | 待支付 PENDING_PAYMENT | 2399.00 | +| E20260805010405113DC3BDB6 | 已取消 CANCELED | 3299.00 | +| E20260805010232B41995B7C0 | 已完成 COMPLETED | 1999.00 | +| E20260803063427BED259C520 | 已发货 SHIPPED | 4931.00 | + +--- + +## 二、图例 + +| 标记 | 含义 | +|------|------| +| ✅ 通过 | 已测且符合预期 | +| ⚠️ 部分 | 接口通过或逻辑部分通过,页面/人工未完成,或有残留问题 | +| ❌ 未测 | 本次未覆盖 | +| 🐛 缺陷 | 不符合预期,建议提缺陷 | + +--- + +## 三、商家工作台清单勾选(主责) + +入口:https://eshop.zhuyiyuan9.top/seller/login + +| # | 清单项 | 勾选 | 状态 | 测试说明 | +|---|--------|------|------|----------| +| 1 | 注册时能够选择「商家」身份 | [x] | ✅ 通过 | API:`role=SELLER` 注册成功 | +| 2 | 新注册商家在管理员审核前不能进入商家工作台 | [x] | ✅ 通过 | 未审核登录返回 403,code=40302(账号禁用/未启用) | +| 3 | 管理员审核启用后,商家能够正常登录 | [x] | ✅ 通过 | `user` 登录 200,role=SELLER,nickname=asd | +| 4 | 商家首页统计卡片能够正常加载,无白屏或明显报错 | [~] | ⚠️ 部分 | 接口 `/admin/dashboard/summary` 200 且返回统计字段;**页面 UI 未人工逐项确认** | +| 5 | 能创建带 `[TEST]` 前缀的商品并上传合法图片 | [~] | ⚠️ 部分 | 创建商品 **ID=31** 成功;**图片上传未测** | +| 6 | 商品名称、分类、描述等必填项缺失时能够拦截 | [x] | ✅ 通过 | 空名称 → HTTP 400,提示「商品名称不能为空」 | +| 7 | 能为商品创建多个 SKU,并分别设置价格和库存 | [x] | ✅ 通过 | SKU 31、32,不同价格与库存 | +| 8 | 商品没有有效 SKU 时不能错误上架 | [x] | ✅ 通过 | HTTP 409,code=40914 | +| 9 | 商品可以编辑、上架和下架,消费者端状态同步 | [~] | ⚠️ 部分 | **上架/下架**通过,消费者详情 `ON_SALE` 正确;**编辑商品文案等未单独测** | +| 10 | 库存修改后,消费者商品详情中的库存同步更新 | [x] | ✅ 通过 | 改 SKU 库存后,公开详情接口库存变为 1 | +| 11 | 库存预警页面能够展示低库存 SKU | [~] | ⚠️ 部分 | 库存预警相关接口 200;**页面展示未人工确认** | +| 12 | 商家只能看到和处理属于自己的商品及订单 | [~] | ⚠️ 部分 | 本账号订单列表可访问(4 单);**未用第二商家账号做越权对比** | +| 13 | 已支付订单能够发货,发货后状态变为「已发货」 | [ ] | ❌ 未测 | 当前无 `PAID` 订单,无法测成功发货路径 | +| 14 | 待支付、已取消或已发货订单不能重复发货 | [x] | ✅ 通过 | PENDING/CANCELED/SHIPPED/COMPLETED 发货均 409(状态不允许) | +| 15 | 商家能够查看商品评价和相关运营数据 | [~] | ⚠️ 部分 | 评价列表接口、看板接口 200;**页面未人工确认** | +| 16 | 操作日志能够记录商品修改、库存修改和订单发货 | [~] | ⚠️ 部分 | 日志接口 total≈17,含商品/库存操作;**发货日志需有成功发货后再对** | +| 17 | 退出后不能继续访问商家受保护页面 | [~] | 🐛 缺陷 | `/auth/logout` 返回成功,但**原 JWT 仍可访问商家接口**(偏前端清本地 token) | + +### 组员四统计 + +| 类型 | 数量 | +|------|------| +| ✅ 通过 | 9 | +| ⚠️ 部分 | 7 | +| ❌ 未测 | 1 | +| 合计清单项 | 17 | + +--- + +## 四、建议提交的缺陷 + +### BUG-20260805-01 + +```text +缺陷编号:BUG-20260805-01 +测试人:吴松青 +测试时间:2026-08-05 +测试端:商家 +账号角色:商家(user) +页面地址:https://eshop.zhuyiyuan9.top/seller (接口 /api/auth/logout) +前置条件:商家已登录,持有有效 JWT +操作步骤: + 1. 调用 POST /api/auth/logout(带 Authorization) + 2. 使用同一 JWT 再请求 GET /api/admin/orders +实际结果:logout 返回成功,但后续商家接口仍返回 200 +预期结果:logout 后 token 失效,再访问返回 401 +出现频率:必现(API 层) +严重程度:P2 一般(安全/会话;前端若清本地 token 可部分缓解) +关联商品 ID 或订单号:无 +截图或录屏:接口测试记录 +``` + +--- + +## 五、仍需人工补测(浏览器) + +请用电脑浏览器登录商家后补充: + +1. 看板卡片 UI 是否白屏/错位 +2. 商品图片上传与预览 +3. 商品编辑保存 +4. 造一单「买家下单 → 支付」后,商家对 **PAID** 订单点发货 +5. 退出登录后刷新 `/seller` 是否回登录页 +6. 库存预警页、评价页、日志页样式与空态 + +补测发货后,可把订单号填到第 13 项并改勾选。 + +--- + +## 六、公共项(本人相关页面,抽查) + +| 项 | 状态 | 说明 | +|----|------|------| +| 正式域名可访问 | ✅ | https://eshop.zhuyiyuan9.top 多入口 200 | +| 健康接口 UP | ✅ | `/api/actuator/health` → `{"status":"UP"}` | +| 商家登录页可打开 | ✅ | `/seller/login` 200 | +| 页面视觉/兼容性全项 | ❌ | 未系统做 Chrome/Edge 双端 UI 验收 | + +--- + +## 七、结论 + +- **商家工作台接口主流程可用**,创建商品、多 SKU、上下架、库存同步、非法发货拦截、日志/评价/看板接口均可访问。 +- **阻塞级 P0/P1 未在商家 API 主路径上发现**(除会话注销不彻底为 P2)。 +- **清单未 100% 勾满**:缺「已支付发货」数据路径 + UI/上传人工项。 +- 建议结果表述:**有条件通过(接口侧)/ 待补 UI 与发货闭环后全通过**。 + +--- + +## 八、签字 + +| 角色 | 姓名 | 日期 | 签字 | +|------|------|------|------| +| 测试人(组员四) | 吴松青 | 2026-08-05 | | +| 汇总(组长) | 祝意远 | | | + +--- + +*本文件由线上接口验收结果整理,正式 UI 截图请测试人自行补充。* diff --git "a/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-3\345\210\206\351\222\237\347\262\276\347\256\200\347\211\210.md" "b/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-3\345\210\206\351\222\237\347\262\276\347\256\200\347\211\210.md" new file mode 100644 index 0000000000000000000000000000000000000000..7cc9f955dd8ccf7dcd48d0fb132c26f7da985163 --- /dev/null +++ "b/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-3\345\210\206\351\222\237\347\262\276\347\256\200\347\211\210.md" @@ -0,0 +1,37 @@ +# 吴松青 · 模块讲解(3 分钟精简版) + +**学号**:2444310213 + +--- + +## 口述稿(约 450 字,1.5~3 分钟) + +大家好,我是吴松青,学号 2444310213。在 E-Shop 项目中,我主要负责 **订单与支付**,以及扩展功能 **评价后端** 和 **浏览历史**。 + +**第一块是订单支付。** 用户从购物车进入确认订单页,选择地址、填写备注后提交,调用创建订单接口生成待支付订单,再进入模拟支付。支付成功后订单变为已支付;待支付可以取消,已发货可以确认收货。前后端都按状态机限制:已取消不能再付,非待收货不能确认收货。另外还有 C03:超时未支付的订单由后端定时任务自动取消。 + +**第二块是评价后端。** 我做了创建评价的接口和校验:只有已完成订单、只能评自己的订单商品、同一商品行不能重复评,评分 1 到 5 分,内容有长度限制。评价页面可以后续对接。 + +**第三块是浏览历史。** 登录用户进入商品详情会静默记录;同一用户同一商品只保留一条,重复访问只更新时间。提供列表分页、单条删除和一键清空;PC 和手机都有历史页,个人中心有入口。未登录不会打断正常浏览和下单。 + +技术上我用了 Spring Boot、MyBatis-Plus、JWT,前端 Vue3。重点保证 **状态正确、幂等、不挡主流程**。以上是我的工作,谢谢。 + +--- + +## 时间分配(3 分钟) + +| 时间 | 内容 | +|------|------| +| 0:20 | 自我介绍 + 负责模块 | +| 1:00 | 订单支付 + 状态机 + C03 | +| 0:40 | 评价规则 | +| 0:40 | 浏览历史 | +| 0:20 | 收尾 | + +--- + +## 演示优先级(时间紧只做 1 条) + +**优先**:登录 → 商品详情(记历史)→ 历史列表看记录 + +**有时间再加**:确认订单 → 支付 → 看订单状态 diff --git "a/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-PPT\345\244\247\347\272\262.md" "b/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-PPT\345\244\247\347\272\262.md" new file mode 100644 index 0000000000000000000000000000000000000000..d254968f90423b8cba7870ab5a0e91196b865b27 --- /dev/null +++ "b/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-PPT\345\244\247\347\272\262.md" @@ -0,0 +1,128 @@ +# 吴松青 · 模块讲解 PPT 大纲 + +**建议页数**:8~10 页 +**主讲**:吴松青(2444310213) + +--- + +## 第 1 页 · 封面 + +- 标题:E-Shop 个人模块汇报 +- 副标题:订单支付 · 评价后端 · 浏览历史 +- 姓名 / 学号 / 小组 + +--- + +## 第 2 页 · 个人职责总览 + +三块能力一张图: + +``` +订单支付(主链路) → 评价后端(扩展) → 浏览历史(扩展) +``` + +| 模块 | 交付形态 | +|------|----------| +| 订单/支付/C03 | 接口 + 手机确认订单/订单/支付页 | +| 评价 | 后端基础(DTO/实体/校验/接口) | +| 浏览历史 | 4 接口 + PC/H5 列表 + 详情静默记录 | + +--- + +## 第 3 页 · 订单支付业务链路 + +流程图(横向): + +购物车已选 → 确认订单 → 待支付 → 模拟支付 → 待发货 → 待收货 → 已完成 + +分支:待支付可取消;超时自动取消(C03) + +--- + +## 第 4 页 · 订单支付 · 我的工作与状态机 + +**工作** +- 确认订单页:地址、商品、备注、提交 +- 支付 / 列表 / 详情操作按钮 +- 状态限制与联调 + +**状态机表(可放小表)** + +| 状态 | 可支付 | 可取消 | 可确认收货 | +|------|--------|--------|------------| +| 待支付 | ✓ | ✓ | | +| 已支付 | | | | +| 已发货 | | | ✓ | +| 已完成 | | | | +| 已取消 | | | | + +--- + +## 第 5 页 · C03 超时取消 + +- 问题:用户下单不付,长期占库存 +- 方案:定时扫描超时未支付订单 → 批量取消 +- 结果:订单变已取消,不可再支付 + +--- + +## 第 6 页 · 评价后端 + +**接口**:`POST /reviews` + +**五条规则(列表或图标)** +1. 仅已完成订单 +2. 仅本人订单商品 +3. 不可重复评价 +4. 评分 1~5 +5. 内容长度限制 + +--- + +## 第 7 页 · 浏览历史 + +**一句话**:进详情记浏览 → 列表可看可删 + +**四个接口** +- POST 记录(幂等) +- GET 分页列表 +- DELETE 单条 +- DELETE 清空 + +**体验点** +- 同一商品只一条 +- 未登录不打断浏览 +- 不影响下单 + +--- + +## 第 8 页 · 技术亮点 + +1. 订单状态机:防非法操作 +2. 浏览历史幂等:唯一键 + 更新时间 +3. 静默记录:失败不挡主流程 +4. 评价多条件业务校验 + +--- + +## 第 9 页 · 演示计划(可选) + +1. 登录 → 看商品详情(记历史) +2. 打开历史列表 → 删除 +3. 确认订单 → 支付 → 看状态 + +--- + +## 第 10 页 · 总结 / Q&A + +- 负责交易链路关键节点 + 两项扩展 +- 保证状态正确、幂等、体验不挡主流程 +- 谢谢,欢迎提问 + +--- + +## 制作提示 + +- 配色:深蓝主色(与站内主题一致即可) +- 每页字少图多,规则用表格 +- 不要贴大段代码,最多 1 个接口表 diff --git "a/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-\350\256\242\345\215\225\346\224\257\344\273\230\350\257\204\344\273\267\346\265\217\350\247\210\345\216\206\345\217\262.md" "b/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-\350\256\242\345\215\225\346\224\257\344\273\230\350\257\204\344\273\267\346\265\217\350\247\210\345\216\206\345\217\262.md" new file mode 100644 index 0000000000000000000000000000000000000000..fb06dd53ca733987bda44795ebd0a55eafe4051b --- /dev/null +++ "b/docs/05-\346\200\273\347\273\223\347\255\224\350\276\251/\345\220\264\346\235\276\351\235\222-\346\250\241\345\235\227\350\256\262\350\247\243-\350\256\242\345\215\225\346\224\257\344\273\230\350\257\204\344\273\267\346\265\217\350\247\210\345\216\206\345\217\262.md" @@ -0,0 +1,210 @@ +# 吴松青 · 负责模块讲解稿 + +**学号**:2444310213 +**角色**:组员 4(订单/支付/C03)+ 组员 A(浏览历史)+ 评价后端基础 +**项目**:E-Shop 电子商城 +**时间**:2026.07 – 2026.08 + +> 用途:阶段汇报 / 答辩口述。建议时长 **5~8 分钟**。 + +--- + +## 一、一句话介绍 + +我负责交易闭环里的 **订单与支付相关能力**,以及扩展功能里的 **评价后端基础** 和 **浏览历史**(进详情记一笔、列表可看可删)。 + +--- + +## 二、负责范围总览 + +| 模块 | 主要交付 | 端 | +|------|----------|-----| +| 订单 / 支付 | 确认订单、模拟支付、订单列表/详情、取消、确认收货 | 手机 H5 为主,对接已有后端 | +| C03 超时取消 | 未支付订单超时自动取消(后端调度) | 后端 | +| 评价 | 评价请求 DTO、实体、Mapper、创建接口与业务校验 | 后端(页面后续) | +| 浏览历史 | 4 个 API + PC/手机列表页 + 详情静默记录 + 个人中心入口 | 全栈 | + +**技术栈**:Spring Boot 3 · Java 17 · MyBatis-Plus · MySQL · JWT · Flyway · Vue3 · Vant / Element Plus + +--- + +## 三、模块 1:订单与支付 + +### 3.1 业务链路(口述) + +``` +选购/购物车已选商品 + → 确认订单(地址、备注、金额) + → 创建订单(待支付) + → 模拟支付(→ 已支付/待发货) + → 后台发货(待收货) + → 用户确认收货(已完成) + ↘ 任意待支付可取消;超时未支付自动取消(C03) +``` + +### 3.2 我做了什么 + +1. **手机确认订单页** `MobileCheckoutView` + - 读取购物车已选可用商品,展示清单与合计 + - 选择收货地址、填写备注 + - 调用 `POST /orders`,成功跳转支付页 + - 未选商品/地址不可提交;提交中防重复点击 + +2. **订单列表 / 详情 / 模拟支付** + - 列表按状态筛选、去支付/取消/确认收货 + - 支付页仅 `PENDING_PAYMENT` 可支付 + - 已取消不可再支付;确认收货仅 `SHIPPED` + +3. **状态机要点(重点讲)** + - 非法状态操作后端拦截,前端按钮按状态显隐 + - 与库存、地址等模块协作:下单扣库存,取消回滚(基线能力) + +4. **C03 订单超时自动取消** + - 配置超时时间,定时扫描未支付订单并批量取消 + - 演示时可说明:待支付超过时限后不能再付,状态变为已取消 + +### 3.3 相关接口(可投影) + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/orders` | 创建订单 | +| GET | `/orders` | 分页列表 | +| GET | `/orders/{id}` | 详情 | +| POST | `/orders/{id}/pay` | 模拟支付 | +| POST | `/orders/{id}/cancel` | 取消 | +| POST | `/orders/{id}/confirm` | 确认收货 | + +### 3.4 演示步骤(订单支付) + +1. 登录手机端 +2. 保证有已选购物车商品 + 地址(或用 PC 加购) +3. 打开确认订单 → 提交 +4. 模拟支付成功 → 订单列表看状态 +5. (可选)再下一单取消,验证不能再支付 + +--- + +## 四、模块 2:评价后端基础 + +### 4.1 目标 + +只做**后端基础**(页面可后续):能安全地提交商品评价,规则清晰。 + +### 4.2 我做了什么 + +- 评价请求 DTO、实体、数据访问层、`ReviewService` / `ReviewController` +- 表:`product_review`(Flyway 已有,未擅自改表结构) + +### 4.3 核心业务规则(重点讲) + +| 规则 | 说明 | +|------|------| +| 只有已完成订单可评 | `status == COMPLETED` | +| 只能评自己的订单商品 | 校验订单 `userId` | +| 同一订单商品不可重复评 | `order_item_id` 唯一 | +| 评分 1~5 | 参数校验 + 服务端二次校验 | +| 内容长度 | 1~1000 字 | + +### 4.4 接口 + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/reviews` | 创建评价(需登录) | +| GET | `/reviews/{id}` | 评价详情 | + +### 4.5 演示 / 口述要点 + +构造:完成态订单 + 订单商品 ID → 调 `POST /reviews` +再调一次同一 `orderItemId` → 应返回重复评价错误。 + +--- + +## 五、模块 3:浏览历史 + +### 5.1 一句话 + +**进详情记浏览 → 列表可看可删 → PC/手机有入口。** + +### 5.2 我做了什么 + +**后端**(包 `com.eshop.backend.browse`,表 **V6** `product_browse_history`,不重建表) + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/browse-history/{productId}` | 静默记录;同一用户同一商品只一条,刷新 `browsed_at` | +| GET | `/browse-history` | 分页,按最近访问倒序 | +| DELETE | `/browse-history/{productId}` | 删一条 | +| DELETE | `/browse-history` | 清空当前用户 | + +**前端** + +- `api/browseHistory.js` +- PC / 手机历史列表页 +- 详情页登录后 `recordVisit().catch(...)` 静默上报(401 不打断) +- 个人中心入口(建议路由由组长统一接) + +### 5.3 验收点(汇报时主动说) + +| 点 | 结果 | +|----|------| +| 重复进同一商品 | 仍一条,只更新时间 | +| 未登录 | 接口 401;详情不弹错、可继续逛 | +| 不影响下单 | 与订单无事务绑定 | +| 路由 | 建议 `/pc/history`、`/m/history`,公共 router 由组长接入 | + +### 5.4 演示步骤(浏览历史) + +1. 登录 → 打开多个商品详情 +2. 进入浏览历史列表,确认条数与顺序 +3. 删除一条 / 清空全部 +4. 未登录访问接口或仅浏览详情,确认不强制打断 + +--- + +## 六、技术亮点(挑 2~3 个讲) + +1. **订单状态机**:前后端双重限制,防止非法支付/重复确认。 +2. **幂等设计**:浏览历史「用户+商品」唯一键,重复访问只更新时间。 +3. **静默体验**:详情记录失败不阻断主流程(浏览、加购、下单)。 +4. **业务校验闭环**:评价多条件校验 + 集成测试覆盖关键路径。 + +--- + +## 七、协作与仓库 + +- 功能分支:`feature/browse-history` 等,推送 Gitee fork +- 日报:`reports/daily/吴松青_2444310213/`(统一在仓库根目录) +- 与组长协作:公共路由、主链路集成、演示数据 + +--- + +## 八、可能被问到的问题(简答) + +**Q:支付是真实支付吗?** +A:课程模拟支付,调用后端 pay 接口改订单状态,无真实扣款。 + +**Q:超时取消怎么触发?** +A:后端定时任务扫描超时未支付订单并取消(C03),可配置超时分钟数。 + +**Q:浏览历史和收藏有什么区别?** +A:历史是进详情自动记、可清空;收藏是用户主动收藏,业务表与接口不同。 + +**Q:评价为什么限制已完成订单?** +A:避免未收货就评价,保证评价对应真实成交。 + +--- + +## 九、建议汇报结构(时间分配) + +| 时段 | 内容 | +|------|------| +| 0:30 | 自我介绍 + 负责模块总览 | +| 2:00 | 订单支付链路 + 状态机 + 演示 | +| 1:00 | C03 超时取消一句带过 | +| 1:30 | 评价规则 | +| 2:00 | 浏览历史 + 演示 | +| 0:30 | 技术亮点 + 协作收尾 | + +--- + +*副本已同步到桌面;仓库内路径:`docs/05-总结答辩/吴松青-模块讲解-订单支付评价浏览历史.md`* diff --git a/eshop-release-v1.0/backend/src/main/java/com/eshop/backend/browse/dto/BrowseHistoryResponse.java b/eshop-release-v1.0/backend/src/main/java/com/eshop/backend/browse/dto/BrowseHistoryResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..e1074e3284daeba8c7b8cac0393baa4fca0319fd --- /dev/null +++ b/eshop-release-v1.0/backend/src/main/java/com/eshop/backend/browse/dto/BrowseHistoryResponse.java @@ -0,0 +1,12 @@ +package com.eshop.backend.browse.dto; + +import java.time.LocalDateTime; + +public record BrowseHistoryResponse( + Long id, + Long productId, + String productName, + String productImage, + LocalDateTime browsedAt +) { +} \ No newline at end of file diff --git a/eshop-release-v1.0/backend/src/main/java/com/eshop/backend/review/dto/ReviewResponse.java b/eshop-release-v1.0/backend/src/main/java/com/eshop/backend/review/dto/ReviewResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..05b8c596d4a5c7cdfc5ed8f50ccc5cbf0f509ba9 --- /dev/null +++ b/eshop-release-v1.0/backend/src/main/java/com/eshop/backend/review/dto/ReviewResponse.java @@ -0,0 +1,17 @@ +package com.eshop.backend.review.dto; + +import java.time.LocalDateTime; + +public record ReviewResponse( + Long id, + Long userId, + Long productId, + Long orderId, + Long orderItemId, + Integer rating, + String content, + String status, + LocalDateTime createdAt, + LocalDateTime updatedAt +) { +} diff --git a/eshop-release-v1.0/backend/src/test/java/com/eshop/backend/ReviewFoundationIntegrationTest.java b/eshop-release-v1.0/backend/src/test/java/com/eshop/backend/ReviewFoundationIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..24f28ba860dc69a27a62d1f0afc87a465bd3e63f --- /dev/null +++ b/eshop-release-v1.0/backend/src/test/java/com/eshop/backend/ReviewFoundationIntegrationTest.java @@ -0,0 +1,179 @@ +package com.eshop.backend; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import java.util.Map; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(properties = { + "spring.datasource.url=jdbc:h2:mem:eshop_review;MODE=MySQL;DB_CLOSE_DELAY=-1;DATABASE_TO_LOWER=TRUE", + "spring.datasource.username=sa", + "spring.datasource.password=", + "spring.datasource.driver-class-name=org.h2.Driver", + "spring.flyway.enabled=false", + "spring.sql.init.mode=always", + "spring.sql.init.schema-locations=classpath:schema-test.sql", + "jwt.secret=ZXNob3AtdGVzdC1zZWNyZXQtdGhhdC1pcy1sb25nLWVub3VnaC0yMDI2", + "app.bootstrap-admin.enabled=true", + "app.bootstrap-admin.username=admin", + "app.bootstrap-admin.password=admin123", + "app.bootstrap-admin.nickname=测试管理员", + "app.order-timeout.enabled=false" +}) +@AutoConfigureMockMvc +class ReviewFoundationIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Test + void onlyCompletedOwnOrderItemCanBeReviewedOnceWithValidRatingAndContent() throws Exception { + String suffix = String.valueOf(System.nanoTime()); + String username = "reviewer_" + suffix; + register(username, "Test1234!"); + String token = login(username, "Test1234!"); + + long userId = jdbcTemplate.queryForObject( + "SELECT id FROM sys_user WHERE username = ?", Long.class, username); + + long productId = 90001L; + long orderId = 80001L; + long orderItemId = 70001L; + + jdbcTemplate.update(""" + INSERT INTO product (id, category_id, name, subtitle, main_image, detail, status) + VALUES (?, 1, ?, 'subtitle', null, 'detail', 'ON_SALE') + """, productId, "评价测试商品" + suffix); + + // 非完成订单不能评价 + jdbcTemplate.update(""" + INSERT INTO orders (id, order_no, user_id, total_amount, status, + receiver_name, receiver_phone, receiver_address) + VALUES (?, ?, ?, 99.00, 'PAID', '张三', '13800138000', '深圳南山') + """, orderId, "R" + suffix, userId); + jdbcTemplate.update(""" + INSERT INTO order_item (id, order_id, product_id, sku_id, product_name, sku_specs, + product_image, price, quantity, subtotal) + VALUES (?, ?, ?, 1, '评价测试商品', '{}', null, 99.00, 1, 99.00) + """, orderItemId, orderId, productId); + + mockMvc.perform(post("/reviews") + .header("Authorization", bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .content(reviewJson(orderItemId, 5, "物流很快,商品很好"))) + .andExpect(status().isConflict()) + .andExpect(jsonPath("$.code").value(40928)); + + // 改为已完成订单后可以评价 + jdbcTemplate.update("UPDATE orders SET status = 'COMPLETED' WHERE id = ?", orderId); + + mockMvc.perform(post("/reviews") + .header("Authorization", bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .content(reviewJson(orderItemId, 5, "物流很快,商品很好"))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(0)) + .andExpect(jsonPath("$.data.orderItemId").value((int) orderItemId)) + .andExpect(jsonPath("$.data.rating").value(5)); + + // 同一订单商品不能重复评价 + mockMvc.perform(post("/reviews") + .header("Authorization", bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .content(reviewJson(orderItemId, 4, "再评一次应该失败"))) + .andExpect(status().isConflict()) + .andExpect(jsonPath("$.code").value(40929)); + + // 评分越界 + long orderItemId2 = 70002L; + jdbcTemplate.update(""" + INSERT INTO order_item (id, order_id, product_id, sku_id, product_name, sku_specs, + product_image, price, quantity, subtotal) + VALUES (?, ?, ?, 1, '评价测试商品2', '{}', null, 99.00, 1, 99.00) + """, orderItemId2, orderId, productId); + + mockMvc.perform(post("/reviews") + .header("Authorization", bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .content(reviewJson(orderItemId2, 6, "分数非法"))) + .andExpect(status().isBadRequest()); + + // 内容过长 + mockMvc.perform(post("/reviews") + .header("Authorization", bearer(token)) + .contentType(MediaType.APPLICATION_JSON) + .content(reviewJson(orderItemId2, 5, "x".repeat(1001)))) + .andExpect(status().isBadRequest()); + + // 不能评价别人的订单商品 + String otherUser = "other_" + suffix; + register(otherUser, "Test1234!"); + String otherToken = login(otherUser, "Test1234!"); + mockMvc.perform(post("/reviews") + .header("Authorization", bearer(otherToken)) + .contentType(MediaType.APPLICATION_JSON) + .content(reviewJson(orderItemId2, 5, "别人的订单不能评"))) + .andExpect(status().isForbidden()); + } + + private void register(String username, String password) throws Exception { + mockMvc.perform(post("/auth/register") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(Map.of( + "username", username, + "password", password, + "nickname", username + )))) + .andExpect(status().isOk()); + } + + private String login(String username, String password) throws Exception { + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(Map.of( + "username", username, + "password", password + )))) + .andExpect(status().isOk()) + .andReturn(); + JsonNode root = objectMapper.readTree(result.getResponse().getContentAsString()); + JsonNode data = root.path("data"); + if (data.hasNonNull("token")) { + return data.get("token").asText(); + } + if (data.hasNonNull("accessToken")) { + return data.get("accessToken").asText(); + } + return data.asText(); + } + + private String bearer(String token) { + return "Bearer " + token; + } + + private String reviewJson(long orderItemId, int rating, String content) throws Exception { + return objectMapper.writeValueAsString(Map.of( + "orderItemId", orderItemId, + "rating", rating, + "content", content + )); + } +} diff --git a/eshop-release-v1.0/frontend/src/views/mobile/MobileHistoryView.vue b/eshop-release-v1.0/frontend/src/views/mobile/MobileHistoryView.vue new file mode 100644 index 0000000000000000000000000000000000000000..b3ad3b064885d275aa662e882ccac6368a11cfaa --- /dev/null +++ b/eshop-release-v1.0/frontend/src/views/mobile/MobileHistoryView.vue @@ -0,0 +1,214 @@ + + + + + \ No newline at end of file diff --git a/eshop-release-v1.0/frontend/src/views/pc/PcHistoryView.vue b/eshop-release-v1.0/frontend/src/views/pc/PcHistoryView.vue new file mode 100644 index 0000000000000000000000000000000000000000..40c2cd5bac9b1e41e5dd081fdf16e8414330c709 --- /dev/null +++ b/eshop-release-v1.0/frontend/src/views/pc/PcHistoryView.vue @@ -0,0 +1,229 @@ + + + + + \ No newline at end of file diff --git a/eshop-release-v1.0/scripts/fix-and-restart.ps1 b/eshop-release-v1.0/scripts/fix-and-restart.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..15fcd9b2e52c5ccfc651de84e5d1fb61430a044a --- /dev/null +++ b/eshop-release-v1.0/scripts/fix-and-restart.ps1 @@ -0,0 +1,161 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Fix hung E-Shop backend and restart services. +#> +param( + [string]$MysqlUser = "root", + [string]$MysqlPassword = "123456", + [int]$BackendPort = 8080, + [switch]$UseDocker +) + +$ErrorActionPreference = "Continue" +$Root = Split-Path -Parent $PSScriptRoot +Set-Location $Root + +function Write-Step($msg) { Write-Host "`n==> $msg" -ForegroundColor Cyan } +function Write-Ok($msg) { Write-Host "OK $msg" -ForegroundColor Green } +function Write-Warn($msg) { Write-Host "WARN $msg" -ForegroundColor Yellow } +function Write-Err($msg) { Write-Host "ERR $msg" -ForegroundColor Red } + +function Free-Port([int]$Port) { + Write-Step "Free port $Port" + $conns = @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue) + if (-not $conns) { + Write-Ok "Port $Port already free" + return $true + } + foreach ($c in $conns) { + $procId = $c.OwningProcess + Write-Host "Killing PID $procId ..." + & taskkill.exe /F /T /PID $procId 2>&1 | Out-Host + } + Start-Sleep -Seconds 2 + $left = @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue) + if ($left.Count -gt 0) { + Write-Warn "Port $Port still held by PID $($left[0].OwningProcess)" + return $false + } + Write-Ok "Port $Port is free" + return $true +} + +function Test-DockerReady { + try { + $null = & docker info 2>$null + return ($LASTEXITCODE -eq 0) + } catch { + return $false + } +} + +function Test-Health([string]$Url, [int]$Tries = 40, [int]$DelaySec = 3) { + for ($i = 0; $i -lt $Tries; $i++) { + try { + $r = Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 3 + if ($r.Content -match 'UP') { return $true } + } catch {} + Start-Sleep -Seconds $DelaySec + } + return $false +} + +Write-Step "Project: $Root" +[void](Free-Port -Port $BackendPort) + +# Try Docker first if requested or already ready +$dockerExe = Join-Path $env:ProgramFiles "Docker\Docker\Docker Desktop.exe" +if ($UseDocker -or (Test-DockerReady)) { + if (-not (Test-DockerReady) -and (Test-Path $dockerExe)) { + Write-Step "Starting Docker Desktop" + Start-Process $dockerExe | Out-Null + $deadline = (Get-Date).AddMinutes(4) + while (-not (Test-DockerReady) -and (Get-Date) -lt $deadline) { + Write-Host " waiting Docker engine..." + Start-Sleep -Seconds 5 + } + } + + if (Test-DockerReady) { + if (-not (Test-Path (Join-Path $Root ".env"))) { + Copy-Item (Join-Path $Root ".env.example") (Join-Path $Root ".env") -Force + } + Write-Step "docker compose up -d --build" + & docker compose --project-directory $Root up -d --build + if ($LASTEXITCODE -ne 0) { + Write-Err "docker compose failed" + exit 1 + } + Write-Step "Waiting http://127.0.0.1:8088/api/actuator/health" + if (Test-Health "http://127.0.0.1:8088/api/actuator/health" 48 5) { + Write-Ok "Docker stack UP -> http://127.0.0.1:8088" + exit 0 + } + Write-Warn "Compose started but health not ready. Run: docker compose logs" + exit 0 + } + Write-Warn "Docker not ready, fall back to local JAR" +} + +# Local JAR + local MySQL +$Jar = Join-Path $Root "backend\target\eshop-backend-0.0.1-SNAPSHOT.jar" +if (-not (Test-Path $Jar)) { + Write-Err "Missing JAR: $Jar" + exit 1 +} + +if ([string]::IsNullOrEmpty($MysqlPassword)) { + Write-Host "" + Write-Host "Local MySQL password is required (root password you set when installing MySQL)." + $sec = Read-Host "MySQL password for user '$MysqlUser'" -AsSecureString + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec) + $MysqlPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) +} + +$Java = "C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot\bin\java.exe" +if (-not (Test-Path $Java)) { + $Java = (Get-Command java -ErrorAction Stop).Source +} + +$Log = Join-Path $Root "backend-restart.log" +$ErrLog = Join-Path $Root "backend-restart.log.err" +$Bat = Join-Path $Root "scripts\_run-backend-tmp.bat" + +# Escape special chars for bat +$passEsc = $MysqlPassword -replace '%', '%%' -replace '[&|<>^]', '^$&' + +@( + "@echo off" + "set SERVER_PORT=$BackendPort" + "set JWT_SECRET=ZXNob3AtZGV2ZWxvcG1lbnQtc2VjcmV0LWtleS1jaGFuZ2UtbWUtMjAyNg==" + "set MYSQL_HOST=localhost" + "set MYSQL_PORT=3306" + "set MYSQL_DATABASE=eshop" + "set MYSQL_USER=$MysqlUser" + "set MYSQL_PASSWORD=$passEsc" + "set BOOTSTRAP_ADMIN_ENABLED=true" + "set BOOTSTRAP_ADMIN_USERNAME=admin" + "set BOOTSTRAP_ADMIN_PASSWORD=admin123" + "set ORDER_TIMEOUT_ENABLED=true" + "cd /d `"$(Join-Path $Root 'backend')`"" + "`"$Java`" -jar `"$Jar`" --server.port=$BackendPort > `"$Log`" 2> `"$ErrLog`"" +) | Set-Content -Path $Bat -Encoding ASCII + +Write-Step "Launch backend JAR on port $BackendPort" +Start-Process -FilePath "cmd.exe" -ArgumentList "/c", "`"$Bat`"" -WorkingDirectory $Root -WindowStyle Minimized + +Write-Step "Waiting http://127.0.0.1:$BackendPort/api/actuator/health" +if (Test-Health "http://127.0.0.1:$BackendPort/api/actuator/health" 40 3) { + Write-Ok "Backend UP" + Write-Host "Health: http://127.0.0.1:$BackendPort/api/actuator/health" + Write-Host "Frontend (vite): http://127.0.0.1:5173" + Write-Host "Admin bootstrap: admin / admin123" + exit 0 +} + +Write-Err "Backend failed to become healthy" +Write-Host "Log: $Log" +if (Test-Path $Log) { Get-Content $Log -Tail 40 } +if (Test-Path $ErrLog) { Get-Content $ErrLog -Tail 40 } +exit 1 diff --git a/eshop-release-v1.0/scripts/restart-backend.ps1 b/eshop-release-v1.0/scripts/restart-backend.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..08780677cda2e16acd9618c2a0e70c1115bba471 --- /dev/null +++ b/eshop-release-v1.0/scripts/restart-backend.ps1 @@ -0,0 +1,57 @@ +# Restart local Spring Boot backend (default port 8081 if 8080 is stuck) +param( + [int]$Port = 8081, + [string]$MysqlUser = "root", + [string]$MysqlPassword = "root", + [string]$MysqlDatabase = "eshop" +) + +$ErrorActionPreference = "Stop" +$Root = Split-Path -Parent $PSScriptRoot +$Jar = Join-Path $Root "backend\target\eshop-backend-0.0.1-SNAPSHOT.jar" +$Log = Join-Path $Root "backend-restart.log" +$Java = "C:\Program Files\Eclipse Adoptium\jdk-17.0.19.10-hotspot\bin\java.exe" + +if (-not (Test-Path $Jar)) { + throw "JAR not found: $Jar. Run mvn package in backend first." +} +if (-not (Test-Path $Java)) { + $Java = (Get-Command java -ErrorAction Stop).Source +} + +# Free the chosen port if we can +$listeners = Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue +foreach ($l in $listeners) { + try { + Stop-Process -Id $l.OwningProcess -Force -ErrorAction Stop + Write-Host "Killed PID $($l.OwningProcess) on port $Port" + } catch { + Write-Host "WARN: cannot kill PID $($l.OwningProcess) on port $Port : $($_.Exception.Message)" + } +} + +$env:SERVER_PORT = "$Port" +$env:JWT_SECRET = "ZXNob3AtZGV2ZWxvcG1lbnQtc2VjcmV0LWtleS1jaGFuZ2UtbWUtMjAyNg==" +$env:MYSQL_HOST = "localhost" +$env:MYSQL_PORT = "3306" +$env:MYSQL_DATABASE = $MysqlDatabase +$env:MYSQL_USER = $MysqlUser +$env:MYSQL_PASSWORD = $MysqlPassword +$env:BOOTSTRAP_ADMIN_ENABLED = "true" +$env:BOOTSTRAP_ADMIN_USERNAME = "admin" +$env:BOOTSTRAP_ADMIN_PASSWORD = "admin123" +$env:ORDER_TIMEOUT_ENABLED = "true" + +if (Test-Path $Log) { Remove-Item $Log -Force } + +Write-Host "Starting backend on port $Port ..." +Write-Host "MySQL: $MysqlUser@$($env:MYSQL_HOST):$($env:MYSQL_PORT)/$MysqlDatabase" +Write-Host "Log: $Log" + +$args = @( + "-jar", $Jar, + "--server.port=$Port" +) + +# Run in current process tree so env is inherited; redirect to log +& $Java @args *>> $Log diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260727-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260727-\345\220\264\346\235\276\351\235\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..b0a2192d9ae7b1933d5a88121d66229f946f50e7 --- /dev/null +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260727-\345\220\264\346\235\276\351\235\222.md" @@ -0,0 +1,60 @@ +# 日报 - 吴松青 - 2026-07-27 + +**学号**:2444310213 +**组员**:组员 4(订单、支付与 C03 模块负责人) +**分支**:`feature/mobile-order-payment` +**基线**:组长仓库 `7a1e44c fix(mobile): 完善订单列表详情与支付交互` + +--- + +## 今日完成 + +1. **对照今日任务安排,核对模块 C 完成情况** + - 已完成(基线已有,今日回归确认):手机订单列表 `/m/orders`、订单详情 `/m/orders/:id`、模拟支付 `/m/orders/:id/pay`(含状态限制:非待支付不可支付;详情侧取消/确认收货按状态展示)。 + - 未完成项(今日主任务):手机确认订单 `/m/checkout` 仍为占位页 → 已补齐。 + +2. **完成手机确认订单页 `MobileCheckoutView.vue`** + - 从购物车读取 `selected` 商品,展示名称、规格、数量、单价、小计与合计。 + - 失效/库存不足商品单独分组提示,不可提交。 + - 页内直接选择收货地址(默认地址优先),支持跳转地址管理页。 + - 支持订单备注(最长 255)。 + - 调用 `POST /orders`(`addressId` + `remark`),创建成功后 `replace` 跳转 `/m/orders/:id/pay`。 + - 提交中 `submitting` 防重复点击;未选商品/地址时按钮禁用并 Toast 提示。 + +3. **路由接入(仅改 checkout 一行)** + - `router/index.js`:`mobile-checkout` 从 `MobilePlaceholderView` 切换为 `MobileCheckoutView.vue`。 + - 商品/购物车/地址路由仍由其他组员与组长统一接入,未越权修改。 + +4. **C03 / 边界场景核对(结合已有后端与订单页)** + - 超时支付:后端 `ORDER_PAYMENT_EXPIRED` + 定时取消;支付页仅 `PENDING_PAYMENT` 可支付。 + - 库存不足:下单时 `OUT_OF_STOCK` / 前端失效商品拦截。 + - 重复操作:提交按钮 loading/disabled;支付页 `paying` 状态。 + - 非法状态流转:取消/确认收货/支付按钮按状态显隐,后端状态机兜底。 + +## 遇到的问题 + +| 问题描述 | 解决状态 | 解决方式/求助对象 | +|----------|----------|-------------------| +| 今日任务要求从组长 `7a1e44c` 基线开分支,本地 fork master 与基线不一致 | 已解决 | 新增 `leader` 远程,从 `leader/master` 创建 `feature/mobile-order-payment` | +| 地址/购物车手机页仍可能是占位,确认订单需能独立选地址 | 已解决 | 结算页内嵌地址列表选择,不强制依赖地址管理页完成编辑 | +| 协作规则要求尽量不多人改 `router/index.js` | 已解决 | 仅切换 `mobile-checkout` 组件映射,其余路由不动,便于组长集成 | + +## 明日计划 + +1. 配合组长做手机全链路联调:购物车已选商品 → 确认订单 → 支付 → 订单列表状态。 +2. 根据联调缺陷修复确认订单页(金额对齐、空态文案、返回栈等)。 +3. 如有需要,补充 C03 超时取消的演示说明与边界用例记录。 + +## 今日工时 + +约 6 小时 + +## 变更说明(交付) + +| 项 | 内容 | +|----|------| +| 修改文件 | `eshop-release-v1.0/frontend/src/views/mobile/MobileCheckoutView.vue`(新增)
`eshop-release-v1.0/frontend/src/router/index.js`(仅 checkout)
`reports/daily/吴松青_2444310213/20260727-吴松青.md` | +| 完成功能 | 手机确认订单页真实化 + 下单跳转支付 | +| 使用接口 | `GET /addresses`、`GET /cart`、`POST /orders` | +| 如何测试 | 登录后保证购物车有已选可用商品与至少一个地址 → 打开 `/m/checkout` → 选地址 → 提交 → 进入支付页 | +| 仍有问题 | 完整主链路依赖组员 2/3 的商品、购物车、地址页接入;本组页面可独立打开与联调 | diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260728-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260728-\345\220\264\346\235\276\351\235\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..54ea835ce1f6f7fb29d6984057837b65365a34db --- /dev/null +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260728-\345\220\264\346\235\276\351\235\222.md" @@ -0,0 +1,56 @@ +# 日报 - 吴松青 - 2026-07-28 + +**学号**:2444310213 +**组员**:组员 4(订单、支付与 C03 模块负责人) +**分支**:`feature/mobile-order-payment` +**今日基线**:融合组长包 `eshop-release-v1.0(4)` + +--- + +## 今日完成 + +1. **同步组长最新包 `eshop-release-v1.0(4)` 并推送码云** + - 后台运营看板:`DashboardController/Service/Mapper` + `AdminHomeView` 实时汇总(用户/商品/订单/有效销售额、订单状态分布)。 + - 前端 `admin.js` 增加 `getDashboardSummary`。 + - 冒烟脚本与接口契约测试、schema-test 同步更新。 + - 新增 Flyway:`V4` 商品收藏表、`V5` 商品评价表(仅表结构预留,业务接口未实现)。 + - 提交:`0fb4ad5`,已 push 至 Gitee `feature/mobile-order-payment`。 + +2. **本模块(C 模块)功能自检** + - 手机确认订单 `/m/checkout`:页面与路由已接入。 + - 手机订单列表 / 详情 / 模拟支付:已接入真实组件。 + - 取消订单、确认收货、支付状态限制:前端按状态显隐 + 后端状态机。 + - C03 订单超时自动取消:后端调度器已在基线中。 + - 前端生产构建通过。 + +3. **融合策略** + - 以组长包增量文件为准覆盖/新增。 + - 保留已有 C 模块页面、吴松青日报目录与本机重启脚本;不覆盖本地 `.env`。 + +## 遇到的问题 + +| 问题描述 | 解决状态 | 解决方式/求助对象 | +|----------|----------|-------------------| +| 组长包与本地仅差少量文件,需避免误覆盖 C 模块页面 | 已解决 | 先 hash 对比再精确复制新增/变更文件 | +| 收藏/评价仅有表结构无业务代码,易误判为未完成任务 | 已确认 | 属预留结构;非本组员 4 本轮交付范围 | + +## 功能完成度(组员 4 · 订单支付) + +| 功能 | 状态 | +|------|------| +| 手机确认订单 | ✅ 已完成 | +| 手机订单列表/详情/支付/取消/确认收货 | ✅ 已完成 | +| C03 超时取消(后端) | ✅ 已完成 | +| 与商品/购物车/地址联调 | ✅ 组长集成后主链路页面已齐,待全组联调验收 | +| 运营看板 | ✅ 已随组长包融合(后台公共能力) | +| 商品收藏/评价完整业务 | ⏳ 仅表结构,接口与页面未做(待组长分配) | + +## 明日计划 + +1. 配合组长做手机全链路联调与缺陷修复(重点:下单金额、支付跳转、状态刷新)。 +2. 若分配收藏/评价,再补接口与 H5/PC 页面。 +3. 整理 C03 现场演示步骤(待支付超时取消边界)。 + +## 今日工时 + +约 4 小时 diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260729-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260729-\345\220\264\346\235\276\351\235\222.md" index 6ecd02837a4cf7649105d80cb20ca2e6dd85f21b..bc0fb4845344bfb496de1d8ddc6df84b87135582 100644 --- "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260729-\345\220\264\346\235\276\351\235\222.md" +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260729-\345\220\264\346\235\276\351\235\222.md" @@ -1,8 +1,8 @@ # 日报 - 吴松青 - 2026-07-29 -**学号**:2444310213 -**组员**:组员 A · 浏览历史(兼订单/支付模块) -**分支**:`feature/browse-history` +**学号**:2444310213 +**组员**:组员 A · 浏览历史(兼订单/支付模块) +**分支**:`feature/browse-history` **最新提交**:`f3e5135` feat(browse): 完善浏览历史 POST/GET/DELETE 与 PC/手机列表 --- diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260730-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260730-\345\220\264\346\235\276\351\235\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..1cfc25fa6e5ac7e53f1539119858827894245ac0 --- /dev/null +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260730-\345\220\264\346\235\276\351\235\222.md" @@ -0,0 +1,46 @@ +# 日报 - 吴松青 - 2026-07-30 + +**学号**:2444310213 +**组员**:组员 4 / 组员 A(订单支付 · 评价 · 浏览历史) +**分支**:`feature/browse-history` + +--- + +## 今日完成 + +1. **浏览历史联调与体验修补** + - 核对 PC/手机历史列表字段与后端 `browsedAt` 对齐,分页加载与空数据提示。 + - 确认详情页登录后静默 `POST /browse-history/{productId}` 不打断正常浏览与加购。 + - 个人中心「我的浏览」入口路径与组长约定路由 `/pc/history`、`/m/history` 对齐,等统一接入后继续联调。 + +2. **订单/支付边界再测** + - 复查待支付 → 支付成功、取消后不可再支付、确认收货按钮状态限制。 + - 记录联调中发现的文案与跳转细节,准备与前端入口一并修。 + +3. **评价后端联调准备** + - 对照「仅已完成订单可评、本人订单商品、不可重复评、评分 1~5」整理接口自测用例,方便后续接评价页时联调。 + +--- + +## 遇到的问题 + +| 问题描述 | 解决状态 | 解决方式/求助对象 | +|----------|----------|-------------------| +| 浏览历史路由尚未合入 master,本地无法从个人中心完整点通 | 进行中 | 先按建议路径预留入口;跟组长确认接入排期 | +| 历史列表在商品已下架时名称展示需统一 | 部分解决 | 前端已有兜底文案,待全链路再验一轮 | +| 评价页未交付,后端接口暂无页面联调 | 未解决 | 明日继续与前端/任务安排对齐 | + +--- + +## 明日计划 + +1. 继续跟进浏览历史路由接入,做 PC/H5 列表删除、清空、重复访问幂等回归。 +2. 配合订单支付主链路回归(下单 → 支付 → 取消/确认收货)并修联调问题。 +3. 若评价页任务启动:对接 `POST /reviews`,补异常提示与订单详情入口。 +4. 整理本周接口清单与测试记录,便于周末或下周演示。 + +--- + +## 今日工时 + +约 4 小时 diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260731-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260731-\345\220\264\346\235\276\351\235\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..e99935640ef2e26ad853db9993e8dc7e5855e7e4 --- /dev/null +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260731-\345\220\264\346\235\276\351\235\222.md" @@ -0,0 +1,48 @@ +# 日报 - 吴松青 - 2026-07-31 + +**学号**:2444310213 +**组员**:组员 4 / 组员 A(订单支付 · 评价 · 浏览历史) +**分支**:`feature/browse-history` + +--- + +## 今日完成 + +1. **浏览历史联调跟进** + - 再次自测 `POST/GET/DELETE /browse-history`:同一商品重复访问只保留一条、列表按最近访问排序。 + - 核对 PC/手机历史页移除、清空交互与空列表提示。 + - 跟进个人中心入口与建议路由 `/pc/history`、`/m/history` 的接入情况,记录待组长合入后的回归点。 + +2. **订单支付链路回归** + - 走查待支付 → 模拟支付成功后的状态展示。 + - 验证已取消订单不可再支付、待收货确认收货按钮显隐是否符合状态机。 + - 记录详情页跳转支付、返回列表后的刷新表现,准备下周集中修交互细节。 + +3. **评价模块衔接** + - 梳理评价后端入参与错误码(未完成订单、非本人订单商品、重复评价、评分越界)。 + - 草拟评价页联调清单:订单详情入口、提交成功后的提示与列表刷新,待前端页面任务排上后对接。 + +--- + +## 遇到的问题 + +| 问题描述 | 解决状态 | 解决方式/求助对象 | +|----------|----------|-------------------| +| 历史路由仍未在公共 router 落地,个人中心完整跳转受阻 | 进行中 | 继续用建议路径预留;催办/等待组长统一接入 | +| 弱网下详情静默 POST 偶发失败 | 已处理策略 | 保持 `.catch` 静默,不打断浏览;必要时加本地重试另议 | +| 评价页未开工,后端暂无法端到端演示 | 未解决 | 明日继续准备联调用例与假数据构造步骤 | + +--- + +## 明日计划 + +1. 若路由已接入:完成浏览历史 PC/H5 端到端回归(记录 → 列表 → 删除 → 清空)。 +2. 继续订单支付主链路抽测,整理缺陷清单给组长汇总。 +3. 评价:根据任务安排对接页面或补充接口文档说明。 +4. 准备周末演示用账号与操作步骤(下单/支付/浏览历史)。 + +--- + +## 今日工时 + +约 4 小时 diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260803-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260803-\345\220\264\346\235\276\351\235\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..348ec69ff40eab27b8fb7699fbde7129e5c9cc34 --- /dev/null +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260803-\345\220\264\346\235\276\351\235\222.md" @@ -0,0 +1,47 @@ +# 日报 - 吴松青 - 2026-08-03 + +**学号**:2444310213 +**组员**:组员 4 / 组员 A(订单支付 · 评价 · 浏览历史) +**分支**:`feature/browse-history` + +--- + +## 今日完成 + +1. **主链路抽测与问题记录** + - 抽测登录后商品浏览 → 加购 → 下单 → 模拟支付完整路径,关注订单状态是否及时刷新。 + - 复查已取消订单支付拦截、确认收货按钮状态限制,补充个人缺陷备注便于集中修复。 + +2. **浏览历史回归** + - 回归 `POST/GET/DELETE` 四接口:重复访问同一商品记录条数、列表排序、单条删除与清空。 + - 检查详情页静默记录在登录/未登录两种场景下是否影响正常浏览与下单。 + - 继续跟进 `/pc/history`、`/m/history` 路由接入后的入口联调计划。 + +3. **评价与演示准备** + - 整理评价接口异常码说明(订单未完成、非本人、重复评价、评分/内容校验),方便前端对接。 + - 准备演示用操作步骤草稿:下单支付 + 浏览历史展示,待组内统一演示脚本。 + +--- + +## 遇到的问题 + +| 问题描述 | 解决状态 | 解决方式/求助对象 | +|----------|----------|-------------------| +| 公共路由尚未完全合入浏览历史路径,个人中心入口联调不完整 | 进行中 | 保持建议路径;与组长确认本周接入节点 | +| 演示账号与预置数据需统一,避免现场无库存/无地址 | 进行中 | 与组长对齐演示数据与账号;明日继续补 checklist | +| 评价前端页进度依赖任务排期 | 未解决 | 后端就绪,等待页面任务启动后联调 | + +--- + +## 明日计划 + +1. 继续订单支付与浏览历史交叉回归,输出简要缺陷表。 +2. 路由接入后立即做 PC/H5 历史页端到端验证。 +3. 按组内安排推进评价页对接或演示脚本完善。 +4. 配合全组准备阶段验收/演示材料。 + +--- + +## 今日工时 + +约 4 小时 diff --git "a/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260804-\345\220\264\346\235\276\351\235\222.md" "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260804-\345\220\264\346\235\276\351\235\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..7587741caebc2faa90c2ec376ebebda88ec6b122 --- /dev/null +++ "b/reports/daily/\345\220\264\346\235\276\351\235\222_2444310213/20260804-\345\220\264\346\235\276\351\235\222.md" @@ -0,0 +1,47 @@ +# 日报 - 吴松青 - 2026-08-04 + +**学号**:2444310213 +**组员**:组员 4 / 组员 A(订单支付 · 评价 · 浏览历史) +**分支**:`feature/browse-history` + +--- + +## 今日完成 + +1. **模块讲解材料整理** + - 梳理本人负责范围:订单/支付主链路、评价后端基础、浏览历史完整能力。 + - 整理接口清单、关键业务规则(状态机、幂等、鉴权)与演示路径,准备汇报讲解。 + +2. **功能回归与问题跟进** + - 抽测下单 → 支付 → 订单状态流转,核对取消/确认收货限制。 + - 复查浏览历史:详情静默记录、列表分页/删除/清空、未登录不打断浏览。 + - 对照评价接口入参与错误场景,记录与前端页面联调注意点。 + +3. **仓库与日报** + - 确认日报统一放在根目录 `reports/daily/吴松青_2444310213/`(已去掉 release 内重复副本)。 + - 提交本日日报。 + +--- + +## 遇到的问题 + +| 问题描述 | 解决状态 | 解决方式/求助对象 | +|----------|----------|-------------------| +| 浏览历史路由依赖公共 router 接入后才能完整演示入口 | 进行中 | 功能与页面已就绪;入口路径 `/pc/history`、`/m/history` 继续跟组长联调 | +| 评价前端页与后端联调仍依赖页面进度 | 进行中 | 后端规则与错误码已齐,等待页面对接时一并验 | +| 全组演示数据/账号需统一 | 进行中 | 按组内演示脚本补库存、地址、完成态订单等数据 | + +--- + +## 明日计划 + +1. 按讲解稿走一遍本人模块演示路径,补缺口。 +2. 继续订单支付 + 浏览历史交叉回归,修联调问题。 +3. 评价页若启动:对接提交评价与异常提示。 +4. 配合全组验收/答辩材料与冒烟测试。 + +--- + +## 今日工时 + +约 4 小时