# 餐桌码查看关联订单 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 |
