docs: 备货单/终版列表视图切换实现计划

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
mzl
2026-08-06 11:37:34 +08:00
parent 76baee2fe5
commit aa23d0949b
@@ -0,0 +1,272 @@
# 备货单 / 终版列表「全部 / 我的」视图切换 实现计划
> **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:** 在 `stocking_list.vue` 与 `final_list.vue` 给 `userId === 73` 的特权用户增加「全部 / 我的」视图切换,切换时给列表接口传 `view_scope=all|self`。
**Architecture:** 纯前端 UI + 传参改动。新增本地状态 `viewScope`,工具栏渲染条件 `canViewAll = userStore.getUserInfo.userId === 73`;`getList` 把 `viewScope.value` 作为 `view_scope` 随请求发出;切换时重置页码并重新请求。是否返回全量数据由后端按 token 鉴权决定(后端改造见 spec 第 3.4 节,不在本计划内)。
**Tech Stack:** Vue 3 `<script setup>` + TypeScript、element-plus 2.8、Pinia(`useUserStore`)、`unplugin-auto-import`(`ref/reactive/computed/onMounted/watch` 自动导入,无需手写 import)。
## Global Constraints
- **无前端单元测试框架**:本项目 `package.json` 无 `test` 脚本。验收方式 = `lint` 通过 + 本地 `dev` 手动核对,不写自动化测试。
- **后端是前置依赖**:前端「全部」真正生效需后端 `GET /crm/stock/order/list` 支持 `view_scope` 参数(见 spec 3.4)。前端可先行独立完成 UI 与传参;完整功能联调待后端就绪。
- **安全边界在后端**:前端 `userId === 73` 仅控制按钮显隐,非授权依据。
- **代码风格**:遵循现有写法——`<script setup lang="ts">`、element-plus 组件、snake_case 请求参数。
- **commit 规范**:每任务一次 commit,信息以 `feat:` 开头。
## 文件结构
| 文件 | 责任 | 改动类型 |
|---|---|---|
| `src/views/crmpc/stocking/stocking_list.vue` | 备货单列表,加视图切换 + `view_scope` 传参 | Modify |
| `src/views/crmpc/stocking/final_list.vue` | 终版列表,同构改动 | Modify |
两文件改动完全同构,仅 `is_final`(0 vs 1)不同。不新建文件。
---
## Task 1: stocking_list.vue 增加视图切换
**Files:**
- Modify: `src/views/crmpc/stocking/stocking_list.vue`
- 模板工具栏(约 `line 9-22` 的 `toolbar-right`)
- `getList` 参数(约 `line 339-344`)
- script 状态(约 `line 280-281` `useAuth` 之后)
- script import(约 `line 264-274`)
**Interfaces:**
- Consumes: `useUserStore`(来自 `@/store/modules/user`),其 `getUserInfo: computed => Partial<{ userId: number }>`;`CrmService.getStockList(params)`(已存在)。
- Produces: 列表请求新增参数字段 `view_scope: 'all' | 'self'`。
- [ ] **Step 1: 添加 import**
在 `<script setup lang="ts">` 顶部 import 区(`import { useAuth } from '@/composables/useAuth'` 同处)增加一行:
```ts
import { useUserStore } from '@/store/modules/user'
```
- [ ] **Step 2: 添加状态与切换处理**
在 `const { hasAuth } = useAuth()`(约 line 281)之后插入:
```ts
const userStore = useUserStore()
// 仅 userId=73 的特权用户可切换「全部/我的」
const canViewAll = computed(() => userStore.getUserInfo.userId === 73)
const viewScope = ref<'all' | 'self'>('self')
const onScopeChange = () => {
pagination.currentPage = 1
getList()
}
```
说明:`computed` / `ref` 由 `unplugin-auto-import` 提供,无需 import。`getUserInfo.userId` 类型为 `number | undefined`,`undefined === 73` 为 `false`,判空安全。
- [ ] **Step 3: 修改 `getList` 请求参数**
定位 `getList` 内(约 line 339-344):
```ts
const params = {
current: currentPage,
size: pageSize,
is_final: 0, // 只获取备货单,非终版
keyword: keyword.value
}
```
改为(增加 `view_scope`):
```ts
const params = {
current: currentPage,
size: pageSize,
is_final: 0, // 只获取备货单,非终版
keyword: keyword.value,
view_scope: viewScope.value
}
```
- [ ] **Step 4: 工具栏添加切换控件**
定位模板 `toolbar-right`(约 line 9-21),在 `<el-input>` 之前插入 `el-radio-group`:
原:
```html
<div class="toolbar-right">
<el-input
v-model="keyword"
```
改为:
```html
<div class="toolbar-right">
<el-radio-group
v-if="canViewAll"
v-model="viewScope"
@change="onScopeChange"
style="margin-right: 12px"
>
<el-radio-button value="self">我的</el-radio-button>
<el-radio-button value="all">全部</el-radio-button>
</el-radio-group>
<el-input
v-model="keyword"
```
说明:用 `value`(element-plus 2.6+ 推荐)而非 `label` 作值,避免 2.8 的 label 弃用告警。文字走默认插槽。
- [ ] **Step 5: Lint 校验**
Run: `npm run fix -- src/views/crmpc/stocking/stocking_list.vue`
Expected: 无 error。若有,按提示修复(常见:prettier 格式)。
- [ ] **Step 6: 手动核对(前端独立部分)**
Run: `npm run dev`,浏览器打开备货单列表页。
核对项:
1. 用**非 73 账号**登录:工具栏**不出现**「全部/我的」控件,列表行为同改动前。
2. 打开 DevTools Network,看 `/crm/stock/order/list` 请求 Payload:无论是否 73,都应带上 `view_scope=self`(默认值)。
3. (需 73 登录态)用 73 账号登录:出现「全部/我的」,默认选中「我的」;点「全部」后 Network 请求带 `view_scope=all`,点回「我的」带 `view_scope=self`,且每次切换分页回到第 1 页。
4. 「全部」是否真返回全量数据,取决于后端是否已支持——后端未就绪时,切到「全部」数据可能不变,属预期。
- [ ] **Step 7: Commit**
```bash
git add src/views/crmpc/stocking/stocking_list.vue
git commit -m "feat(stocking): 备货单列表为特权用户增加「全部/我的」视图切换
Co-Authored-By: Claude <noreply@anthropic.com>"
```
---
## Task 2: final_list.vue 增加视图切换(同构)
**Files:**
- Modify: `src/views/crmpc/stocking/final_list.vue`
- 模板工具栏(约 `line 7-19` 的 `toolbar-right`)
- `getList` 参数(约 `line 278-283`)
- script 状态(约 `line 229` `useAuth` 之后)
- script import(约 `line 206-216`)
**Interfaces:**
- Consumes: 同 Task 1(`useUserStore`、`CrmService.getStockList`)。
- Produces: 同 Task 1(`view_scope` 参数)。
- [ ] **Step 1: 添加 import**
在 `<script setup lang="ts">` 顶部 import 区增加:
```ts
import { useUserStore } from '@/store/modules/user'
```
- [ ] **Step 2: 添加状态与切换处理**
在 `const { hasAuth } = useAuth()`(约 line 229)之后插入:
```ts
const userStore = useUserStore()
// 仅 userId=73 的特权用户可切换「全部/我的」
const canViewAll = computed(() => userStore.getUserInfo.userId === 73)
const viewScope = ref<'all' | 'self'>('self')
const onScopeChange = () => {
pagination.currentPage = 1
getList()
}
```
- [ ] **Step 3: 修改 `getList` 请求参数**
定位 `getList` 内(约 line 278-283):
```ts
const params = {
current: currentPage,
size: pageSize,
is_final: 1, // 只获取备货单,非终版
keyword: keyword.value
}
```
改为:
```ts
const params = {
current: currentPage,
size: pageSize,
is_final: 1, // 终版
keyword: keyword.value,
view_scope: viewScope.value
}
```
(注:原代码注释「非终版」是笔误,此处顺手修正为「终版」。)
- [ ] **Step 4: 工具栏添加切换控件**
定位模板 `toolbar-right`(约 line 7-19),在 `<el-input>` 之前插入:
原:
```html
<div class="toolbar-right">
<el-input
v-model="keyword"
```
改为:
```html
<div class="toolbar-right">
<el-radio-group
v-if="canViewAll"
v-model="viewScope"
@change="onScopeChange"
style="margin-right: 12px"
>
<el-radio-button value="self">我的</el-radio-button>
<el-radio-button value="all">全部</el-radio-button>
</el-radio-group>
<el-input
v-model="keyword"
```
- [ ] **Step 5: Lint 校验**
Run: `npm run fix -- src/views/crmpc/stocking/final_list.vue`
Expected: 无 error。
- [ ] **Step 6: 手动核对(前端独立部分)**
Run: `npm run dev`,浏览器打开终版列表页。核对项同 Task 1 Step 6(注意此处是 `is_final=1` 的终版页)。
- [ ] **Step 7: Commit**
```bash
git add src/views/crmpc/stocking/final_list.vue
git commit -m "feat(stocking): 终版列表为特权用户增加「全部/我的」视图切换
Co-Authored-By: Claude <noreply@anthropic.com>"
```
---
## 后端联调清单(交付后端,不在本计划执行范围)
接口 `GET /crm/stock/order/list` 增加可选参数 `view_scope`:
| 请求 | 后端行为 |
|---|---|
| 不传 / `view_scope=self` | 按现状:依 token 用户过滤 |
| `view_scope=all` 且 token 用户 id ∈ {73} | 返回全量 |
| `view_scope=all` 且 token 用户 id ∉ {73} | 降级为 `self`(返回该用户自己的) |
要点:**只信 token,忽略前端任何用户标识**,防 IDOR。