qmj 1 месяц назад
Родитель
Сommit
557d7bbcf7

+ 341 - 0
docs/superpowers/plans/2026-05-12-table-qrcode-orders.md

@@ -0,0 +1,341 @@
+# 餐桌码查看关联订单 Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 在商家端餐桌码管理页面增加「订单」按钮,点击后弹窗展示该餐桌关联的所有订单列表。
+
+**Architecture:** 后端在 TableQrcodeController 新增 `getTableOrders` 接口,通过 tableId 查询 pos_order 表;前端在 TableQRCode.vue 操作列新增按钮和订单弹窗。权限复用现有 verifyOwnership 模式。
+
+**Tech Stack:** Java 21 / Spring Boot / MyBatis Plus / Vue 2 + Element UI
+
+---
+
+## File Structure
+
+| File | Action | Responsibility |
+|------|--------|---------------|
+| `ruoyi-admin/src/main/java/com/ruoyi/app/tableqrcode/TableQrcodeController.java` | Modify | 新增 getTableOrders 接口 |
+| `foodie-store/src/api/tableQrcode.js` | Modify | 新增 getTableOrders API 方法 |
+| `foodie-store/src/views/TableQRCode.vue` | Modify | 新增订单按钮和订单弹窗 |
+
+---
+
+### Task 1: 后端 — 新增 getTableOrders 接口
+
+**Files:**
+- Modify: `ruoyi-admin/src/main/java/com/ruoyi/app/tableqrcode/TableQrcodeController.java`
+
+- [ ] **Step 1: 添加新的 import 语句**
+
+在 `TableQrcodeController.java` 文件顶部的 import 区域,添加 PosOrder 和 PosOrderService 相关的 import:
+
+```java
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.system.domain.PosOrder;
+import com.ruoyi.system.service.IPosOrderService;
+```
+
+注意:`IPage` 和 `Page` 需要检查是否与已有 import 冲突。文件中没有这些 import,直接添加即可。
+
+- [ ] **Step 2: 注入 PosOrderService**
+
+在已有的 `@Autowired private IPosStoreService posStoreService;` 之后添加:
+
+```java
+@Autowired
+private IPosOrderService posOrderService;
+```
+
+- [ ] **Step 3: 添加 getTableOrders 方法**
+
+在 `getQrcodeImage` 方法之前(约第 366 行),添加以下方法:
+
+```java
+/**
+ * 查看餐桌关联订单
+ */
+@Anonymous
+@Auth
+@GetMapping("/getTableOrders")
+public AjaxResult getTableOrders(@RequestHeader String token,
+                                  @RequestParam Long id,
+                                  @RequestParam(defaultValue = "1") Integer page,
+                                  @RequestParam(defaultValue = "10") Integer size,
+                                  @RequestParam(required = false) String state)
+{
+    if (!verifyOwnership(token, id))
+    {
+        return error("无权访问");
+    }
+    TableQrcode tableQrcode = tableQrcodeService.selectTableQrcodeById(id);
+    if (tableQrcode == null)
+    {
+        return error("餐桌码不存在");
+    }
+
+    IPage<PosOrder> pageParam = new Page<>(page, size);
+    QueryWrapper<PosOrder> queryWrapper = new QueryWrapper<>();
+    queryWrapper.eq("table_id", id).orderByDesc("cretim");
+    if (state != null && !state.isEmpty())
+    {
+        if (state.equals("z01"))
+        {
+            queryWrapper.apply("((state = 0 AND (collect_payment = 1 OR type = 1)) OR (state = 1))");
+        }
+        else if (state.equals("z234"))
+        {
+            queryWrapper.in("state", 2, 3, 4);
+        }
+        else if (state.equals("z23"))
+        {
+            queryWrapper.in("state", 2, 3);
+        }
+        else if (state.equals("z34"))
+        {
+            queryWrapper.in("state", 3, 4);
+        }
+        else if (state.equals("z678911"))
+        {
+            queryWrapper.in("state", 6, 7, 8, 9, 11);
+        }
+        else
+        {
+            queryWrapper.eq("state", state);
+        }
+    }
+
+    IPage<PosOrder> result = posOrderService.page(pageParam, queryWrapper);
+    return success(result);
+}
+```
+
+还需要在 import 区域添加 `QueryWrapper`(如果还没有的话):
+
+```java
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+```
+
+注意:检查文件顶部是否已有 `LambdaQueryWrapper` 的 import — 如果有,`QueryWrapper` 在同一个包下,只需额外添加这一行。
+
+- [ ] **Step 4: 编译验证**
+
+Run: `cd E:/QtwCode/foodie/foodie_server && mvn compile -pl ruoyi-admin -am -q`
+Expected: BUILD SUCCESS
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add ruoyi-admin/src/main/java/com/ruoyi/app/tableqrcode/TableQrcodeController.java
+git commit -m "feat: 添加餐桌码关联订单查询接口 GET /table-qrcode/getTableOrders"
+```
+
+---
+
+### Task 2: 前端 — API 模块新增 getTableOrders
+
+**Files:**
+- Modify: `foodie-store/src/api/tableQrcode.js`
+
+- [ ] **Step 1: 添加 getTableOrders 方法**
+
+在 `tableQrcode.js` 文件末尾(`getQrcodeImage` 函数之后)添加:
+
+```javascript
+// 查看餐桌关联订单
+export function getTableOrders(params) {
+  return request({
+    url: '/table-qrcode/getTableOrders',
+    method: 'get',
+    headers: { isToken: true },
+    params
+  })
+}
+```
+
+- [ ] **Step 2: Commit**
+
+```bash
+git add foodie-store/src/api/tableQrcode.js
+git commit -m "feat: 前端API模块添加 getTableOrders 方法"
+```
+
+---
+
+### Task 3: 前端 — TableQRCode.vue 新增订单按钮和弹窗
+
+**Files:**
+- Modify: `foodie-store/src/views/TableQRCode.vue`
+
+由于前端文件使用 CRLF 换行符,**必须使用 Python 脚本进行编辑**,不能用 Edit 工具直接替换。
+
+- [ ] **Step 1: 在 import 行添加 getTableOrders**
+
+当前第 134 行:
+```javascript
+import { getTableQrcodeList, addTableQrcode, updateTableQrcode, deleteTableQrcode, changeTableQrcodeStatus, getQrcodeImage } from '@/api/tableQrcode'
+```
+
+改为:
+```javascript
+import { getTableQrcodeList, addTableQrcode, updateTableQrcode, deleteTableQrcode, changeTableQrcodeStatus, getQrcodeImage, getTableOrders } from '@/api/tableQrcode'
+```
+
+- [ ] **Step 2: 在操作列添加「订单」按钮**
+
+在模板第 69 行的「查看二维码」按钮之前,添加订单按钮:
+
+当前代码(第 68-73 行):
+```html
+        <template slot-scope="scope">
+          <el-button @click="handleViewQrcode(scope.row)" type="text" size="small">查看二维码</el-button>
+          <el-button @click="handleEdit(scope.row)" type="text" size="small">编辑</el-button>
+          <el-button @click="handleDelete(scope.row)" type="text" size="small" style="color: red;">删除</el-button>
+        </template>
+```
+
+改为:
+```html
+        <template slot-scope="scope">
+          <el-button @click="handleViewOrders(scope.row)" type="text" size="small">订单</el-button>
+          <el-button @click="handleViewQrcode(scope.row)" type="text" size="small">查看二维码</el-button>
+          <el-button @click="handleEdit(scope.row)" type="text" size="small">编辑</el-button>
+          <el-button @click="handleDelete(scope.row)" type="text" size="small" style="color: red;">删除</el-button>
+        </template>
+```
+
+同时将操作列宽度从 `width="220"` 改为 `width="280"` 以容纳新按钮。
+
+- [ ] **Step 3: 添加订单弹窗模板**
+
+在二维码查看弹窗(第 119-130 行)的 `</el-dialog>` 之后、`</div>` 之前(第 130 行后),添加:
+
+```html
+
+    <!-- 订单查看弹窗 -->
+    <el-dialog :title="'餐桌订单 - ' + orderDialogTableNo" :visible.sync="orderDialogVisible" width="800px" append-to-body>
+      <el-form :inline="true" style="margin-bottom: 15px;">
+        <el-form-item label="订单状态">
+          <el-select v-model="orderQueryState" placeholder="全部" clearable size="small" @change="loadOrders">
+            <el-option label="待处理" value="z01"></el-option>
+            <el-option label="进行中" value="z234"></el-option>
+            <el-option label="已完成" value="z678911"></el-option>
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <el-table v-loading="orderLoading" :data="orderList" :header-cell-style="{ background: '#f0f0f0' }" max-height="400">
+        <el-table-column prop="ddId" label="订单号" width="180"></el-table-column>
+        <el-table-column prop="amount" label="金额" width="100"></el-table-column>
+        <el-table-column prop="state" label="订单状态" width="100">
+          <template slot-scope="scope">
+            <el-tag :type="orderStateTagType(scope.row.state)" size="small">{{ orderStateText(scope.row.state) }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="diningStatus" label="出餐状态" width="100">
+          <template slot-scope="scope">
+            <el-tag :type="scope.row.diningStatus === 1 ? 'success' : 'info'" size="small">
+              {{ scope.row.diningStatus === 1 ? '已出餐' : '未出餐' }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="cretim" label="下单时间" width="180"></el-table-column>
+      </el-table>
+      <el-pagination
+        v-if="orderTotal > 0"
+        :current-page.sync="orderPage"
+        :page-size="10"
+        :total="orderTotal"
+        layout="total, prev, pager, next"
+        @current-change="loadOrders"
+        style="margin-top: 15px; text-align: right;">
+      </el-pagination>
+    </el-dialog>
+```
+
+- [ ] **Step 4: 添加 data 属性**
+
+在 data() 的 `currentRow: {}` 之后添加:
+
+```javascript
+      orderDialogVisible: false,
+      orderDialogTableNo: '',
+      orderDialogTableId: null,
+      orderLoading: false,
+      orderList: [],
+      orderTotal: 0,
+      orderPage: 1,
+      orderQueryState: ''
+```
+
+- [ ] **Step 5: 添加 methods**
+
+在 `downloadQrcode` 方法之后,`methods` 闭合 `}` 之前,添加以下方法:
+
+```javascript
+    handleViewOrders(row) {
+      this.orderDialogTableNo = row.tableNo
+      this.orderDialogTableId = row.id
+      this.orderPage = 1
+      this.orderQueryState = ''
+      this.orderDialogVisible = true
+      this.loadOrders()
+    },
+    loadOrders() {
+      this.orderLoading = true
+      const params = { id: this.orderDialogTableId, page: this.orderPage, size: 10 }
+      if (this.orderQueryState) {
+        params.state = this.orderQueryState
+      }
+      getTableOrders(params).then(res => {
+        if (res.code === 200) {
+          const data = res.data
+          this.orderList = data.records || []
+          this.orderTotal = data.total || 0
+        } else {
+          this.$message.error(res.msg || '获取订单失败')
+        }
+        this.orderLoading = false
+      }).catch(() => {
+        this.$message.error('获取订单失败')
+        this.orderLoading = false
+      })
+    },
+    orderStateText(state) {
+      const map = { 0: '待处理', 1: '已付款', 2: '已接单', 3: '配送中', 4: '已送达', 6: '已取消', 7: '退款中', 8: '已退款', 9: '退款拒绝', 11: '已评价' }
+      return map[state] || '未知'
+    },
+    orderStateTagType(state) {
+      if (state === 0 || state === 1) return 'warning'
+      if (state === 2 || state === 3) return ''
+      if (state === 4) return 'success'
+      if (state === 6 || state === 7 || state === 8) return 'danger'
+      return 'info'
+    }
+```
+
+- [ ] **Step 6: 验证前端编译**
+
+Run: `cd E:/QtwCode/foodie/foodie-store && npm run build`
+Expected: 编译成功无报错
+
+- [ ] **Step 7: Commit**
+
+```bash
+git add foodie-store/src/views/TableQRCode.vue
+git commit -m "feat: 餐桌码管理页面新增查看关联订单功能"
+```
+
+---
+
+## Spec Coverage Check
+
+| Spec 需求 | 对应 Task |
+|-----------|----------|
+| GET /table-qrcode/getTableOrders 接口 | Task 1 |
+| 权限校验(userType 1/3/4) | Task 1(复用 verifyOwnership) |
+| 按 tableId 查询订单,支持分页和状态筛选 | Task 1 |
+| 前端 API 模块 | Task 2 |
+| 操作列「订单」按钮 | Task 3 |
+| 订单弹窗(订单号、金额、状态、出餐状态、时间) | Task 3 |
+| 订单状态筛选下拉 | Task 3 |
+| 分页 | Task 3 |

+ 107 - 0
docs/superpowers/specs/2026-05-12-table-qrcode-orders-design.md

@@ -0,0 +1,107 @@
+# 餐桌码查看关联订单
+
+日期: 2026-05-12
+补充: 2026-04-30-qr-table-ordering-design.md(扫码点餐设计)
+
+## 背景
+
+扫码点餐上线后,商家需要查看某张餐桌的所有关联订单,以便掌握每桌的点餐和出餐情况。当前餐桌码管理页面(TableQRCode.vue)只有 CRUD 和二维码查看,没有订单查看入口。
+
+## 需求
+
+商家在餐桌码管理页面,点击某张餐桌码的「订单」按钮,弹出该餐桌关联的所有订单列表。
+
+### 用户类型与权限
+
+| 用户类型 | userType | 可查看范围 |
+|---------|----------|-----------|
+| 普通商家 | 1 | 自己摊位下的餐桌码关联订单 |
+| 摊主 | 4 | 自己摊位下的餐桌码关联订单 |
+| 夜市管理员 | 3 | 夜市下所有摊位的餐桌码关联订单 |
+
+## 后端
+
+### 新增接口
+
+**GET /table-qrcode/getTableOrders**
+
+请求参数:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| id | long | 是 | 餐桌码 ID |
+| page | int | 否 | 页码,默认 1 |
+| size | int | 否 | 每页条数,默认 10 |
+| state | string | 否 | 订单状态筛选 |
+
+权限校验:
+1. 根据 id 查出餐桌码记录
+2. 普通商家/摊主:验证记录的 storeId 属于当前用户
+3. 夜市管理员:验证记录的 nightMarketId 属于当前用户
+
+查询逻辑:
+1. 从餐桌码记录取 id 作为 tableId
+2. 查询 pos_order 表中 table_id = 该 id 的订单
+3. 按 cretim 降序排列
+4. 支持按 state 筛选
+
+返回格式(复用现有 getstoreorderlist 的字段):
+
+```json
+{
+  "code": 200,
+  "msg": "操作成功",
+  "data": {
+    "total": 5,
+    "records": [
+      {
+        "id": 100,
+        "ddId": "DD20260512001",
+        "amount": 350,
+        "state": 2,
+        "type": 2,
+        "cretim": "2026-05-12 12:30:00",
+        "diningStatus": 0,
+        "food": [...]
+      }
+    ]
+  }
+}
+```
+
+### 实现位置
+
+在 `TableQrcodeController.java` 中新增方法,复用已有的 `PosOrderService` 和 `InfoUserService`。
+
+## 前端
+
+### 改动文件
+
+| 文件 | 改动 |
+|------|------|
+| `src/api/tableQrcode.js` | 新增 getTableOrders API 方法 |
+| `src/views/TableQRCode.vue` | 操作列新增「订单」按钮 + 订单弹窗 |
+
+### TableQRCode.vue 改动
+
+1. **操作列**:在现有按钮(查看二维码、编辑、删除)旁新增「订单」按钮
+2. **订单弹窗**:
+   - el-dialog 展示该餐桌的订单列表
+   - 表格列:订单号、金额、订单状态(tag 标签)、出餐状态、下单时间
+   - 顶部可选:订单状态筛选下拉
+3. **数据加载**:点击按钮时调用 `GET /table-qrcode/{id}/orders`
+
+## 不涉及的范围
+
+- 订单详情页面(复用现有)
+- 餐桌状态联动(下单→使用中,结账→空闲)
+- 多次加餐/拼单
+- 按桌号分组统计
+
+## 影响文件清单
+
+| 文件 | 改动 |
+|------|------|
+| `TableQrcodeController.java` | 新增 getTableOrders 接口(`GET /table-qrcode/getTableOrders?id=xxx`) |
+| `tableQrcode.js` (前端 API) | 新增 getTableOrders 方法 |
+| `TableQRCode.vue` | 新增订单按钮和订单弹窗 |