> **前置条件** — 执行以下任何命令前，请先确认已完成认证。如未认证，参见 [`../../shb-shared/SKILL.md`](../../shb-shared/SKILL.md)。

# shb-cli part personal

个人备件库查询：`personal search`（持有列表）、`personal stock-record`（库存变化记录）、`personal use-record`（工单领用/退回记录）、`personal users`（人员搜索）、`personal holding`（指定人对指定备件的持有数量）。

> **本文档出现的命令、子命令、flag、参数名、接口/JSON 字段名，以及取数过程（分页、数量判断、全量拉取、字段裁剪）都只供你后台执行，绝不出现在给用户的回复里**——不解释、不转述、不当理由说。回复只给业务结果与真实数量（如「天驰手上共持有 9 种备件，共 672 件」）。

## 个人库 ≠ 仓库库存

**个人库记录 = 备件 × 人**，与仓库库存（`part stock search`，备件 × 仓库）是两个不同维度。用户问"某人手上有多少备件"用本文档的命令；问"某仓库还有多少库存"用 `part stock`；问"这个备件本身的信息"用 `part search`/`part detail`。三者都不要混用。

## userId 语义：不传 ≠ 查自己（CRITICAL）

`personal search`/`stock-record`/`use-record` **不传 `--user-id` 不代表"查询我自己"**，而是按当前登录人的数据权限查团队/全部可见成员的合计数据。要查某个具体人：

```bash
# 1. 先按姓名搜人，拿到 userId
shb-cli part personal users --keyword <姓名>

# 2. 再显式传 --user-id
shb-cli part personal search --user-id <userId>
```

**绝不要凭空猜测或省略 `--user-id` 来代表"当前用户"**——CLI 没有登录人上下文注入机制，省略就是"查团队/全部"，不是"查自己"。

## 搜索个人持有列表

### 快捷 flag 方式（推荐）

```bash
# 按人查（先用 users 拿 userId）
shb-cli part personal search --user-id <userId>

# 关键字搜索
shb-cli part personal search --user-id <userId> --keyword <关键字>

# 按团队查
shb-cli part personal search --team-id <teamId>

# 查某个备件被谁持有（配合 --sparepart-id）
shb-cli part personal search --sparepart-id <备件id>

# 按类型筛选，逗号分隔
shb-cli part personal search --user-id <userId> --type "耗材,工具"

# 只看启用中的备件
shb-cli part personal search --user-id <userId> --enabled-only

# 格式化数据输出
shb-cli part personal search --user-id <userId> --format-data --fields serialNumber,name,quantity,unavailableNum,userName

# 获取全量数据
shb-cli part personal search --user-id <userId> --all --format-data --fields serialNumber,name,quantity,userName
```

### 完整 JSON body 方式

```bash
shb-cli part personal search --data '{"pageNum":1,"pageSize":10,"userId":"<userId>","enable":1}'
shb-cli part personal search --file ./personal-search.json
```

**使用优先级：快捷 flags ＞ `--data` ＞ `--file`**——常规筛选直接用快捷 flags；需要完整或复杂 JSON（如 `productTypeList`、`sortBy`）时用 `--data`；`--file` 仅在本地已有现成 JSON 文件时用。

### 支持的搜索字段（JSON body，字段名为 SparepartUserSearchModelDTO）

| 字段 | 类型 | 说明 |
|------|------|------|
| `userId` | string | 指定用户（**不传≠查自己**，见上方 CRITICAL 说明） |
| `teamId` | string | 指定团队 |
| `sparepartId` | string | 指定备件 |
| `keyWord` | string | 关键字模糊搜索（**注意大写 W**，写成 `keyword` 会被静默忽略） |
| `typeList` | string[] | 备件类型过滤 |
| `standard` | string | 规格，模糊匹配 |
| `description` | string | 说明，模糊匹配 |
| `enable` | string | `"1"` 仅启用备件 |
| `productTypeList` | string[] | 关联产品目录类型 ID 数组 |
| `pageNum` | int | 页码，**从 1 开始**（默认 1） |
| `pageSize` | int | 每页条数，0 表示查全量 |
| `sortBy` | object | 排序，`{字段名: true\|false}`，`true` 为升序 |

> **flag 名与 JSON 字段名的对应**：`--keyword`↔`keyWord`（注意大写 W）、`--type`（逗号分隔字符串）↔`typeList`（数组）、`--enabled-only`（bool flag）↔`enable`（传 `"1"` 才带这个字段，不传默认查全部启用/停用）、`--user-id`↔`userId`、`--team-id`↔`teamId`、`--sparepart-id`↔`sparepartId`。

## --format-data 输出结构速查（personal search）

```json
{
  "page":                {"page": 1, "pageSize": 10, "totalElements": 9, "totalPages": 1},
  "columns":             [{"field": "serialNumber", "label": "编号"}, ...],
  "rows":                [{"serialNumber": "SP-001", "name": "刹车片", "quantity": "20", "unavailableNum": "1", "userName": "天驰", ...}, ...],
  "sparepartCountTotal": "672",
  "sparepartNumTotal":   "9"
}
```

**字段命名容易读反，务必按这个来（已真机确认）**：
- `sparepartCountTotal` = 持有备件的**总数量**（所有记录 `quantity` 求和）
- `sparepartNumTotal` = 持有的**备件品类数**（等于 `page.totalElements`）

不加 `--fields` 时默认输出字段：`serialNumber`（编号）、`name`（名称）、`type`（类型）、`standard`（规格）、`quantity`（数量，派生列）、`unavailableNum`（不可用数量）、`userName`（领用人）。

其余可选字段：`id`（记录内部 ID）、`sparepartId`、`userId`、`staffId`、`unit`（单位）、`description`（说明）、`occupyNum`（占用数量）、`applyBacking`（退回中数量）、`productTypeList`（关联产品类型）。

`quantity`（数量）= `repertoryCount`（在手）+ `applyBacking`（退回中）——退回中的备件仍算此人持有。**这个数字通常比 `part stock distribution` 里同一人"个人库"条目显示的 `repertoryCount` 大**，两处对不上是正常现象，不是数据错误。

## 库存变化记录（stock-record）与使用记录（use-record）

两者字段家族几乎相同（都嵌套 `sparepart{...}`），差异是记录性质：`stock-record` 是备件在个人库里的进出（申领到个人/分配到个人/备件退回/工单备件返还等），`use-record` 专指工单领用/退回（含工单号、客户信息）。

```bash
# 库存变化记录
shb-cli part personal stock-record --user-id <userId>

# 只看某种记录类型，逗号分隔（值来自服务端，常见如 申领到个人/分配到个人/备件退回/工单备件返还）
shb-cli part personal stock-record --user-id <userId> --item "备件退回,分配到个人"

# 按时间范围
shb-cli part personal stock-record --user-id <userId> --time-start "2026-01-01 00:00:00" --time-end "2026-12-31 23:59:59"

# 格式化输出
shb-cli part personal stock-record --user-id <userId> --format-data --fields serialNumber,name,item,variation,number,sourceName,userName,recordNo,createTime

# 使用记录（工单领用/退回，值常见 工单使用/工单退回）
shb-cli part personal use-record --user-id <userId> --item "工单使用"
shb-cli part personal use-record --user-id <userId> --format-data --fields serialNumber,name,item,number,taskNo,customerName,userName,createTime

# 使用记录也支持完整 JSON body（stock-record 是 GET，不支持 --data/--file；use-record 是 POST，支持）
shb-cli part personal use-record --data '{"pageNum":1,"pageSize":10,"userId":"<userId>"}'
```

**时间参数名踩坑警示（已真机确认）**：两个记录接口的创建时间范围参数是 **`timeStart`/`timeEnd`**，**不是** `createTimeStart`/`createTimeEnd`（虽然后端 DTO 字段名容易让人以为是后者）——传 `createTimeStart` 会被后端静默忽略、不生效。CLI 的 `--time-start`/`--time-end` 已经用对了参数名，直接用即可，不要自己拼 `--data` 时写错。时间值支持 `"yyyy-MM-dd HH:mm:ss"` 或 epoch 毫秒两种格式。

### --format-data 默认字段

- `stock-record` 默认：`serialNumber`（编号）、`name`（名称）、`type`（类型）、`item`（记录类型）、`variation`（变化数）、`number`（结余）、`sourceName`（来源）、`userName`（领用人）、`propserName`（发起人）、`executorName`（审批人）、`recordNo`（记录编号）、`createTime`（创建时间）。
- `use-record` 默认：`serialNumber`（编号）、`name`（名称）、`item`（记录类型）、`variation`（变化数）、`number`（结余）、`taskNo`（工单号）、`customerName`（客户）、`userName`（领用人）、`createTime`（创建时间）。
- 两者共享的可选字段：`standard`/`unit`/`description`（嵌套自 sparepart）、`remark`（备注）、`targetName`（目标仓库）、`customerNumber`（客户编号，use-record）、`productTypeList`。

原始响应是嵌套结构（`sparepart{...}` 子对象），`--format-data` 已自动展平，无需自己拼路径。

### 获取全量数据

同其他 part 子命令：**能判断数据量不大（≤500）直接 `--all`**（配 `--format-data --fields` 收窄列）；不确定先用 `--page-size 1` 探 `total`，`≤500` 用 `--all`，`>500` 改分页叠加。

## 人员搜索（users）

```bash
shb-cli part personal users --keyword <姓名>
shb-cli part personal users --keyword <姓名> --team-id <teamId>
```

- 参数是**小写 `keyword`**，与备件搜索家族的 `keyWord`（大写 W）不同，**不要弄反**。
- 返回一个**裸数组** `[{userId, staffId, displayName, head}]`（服务端已按当前登录人的数据权限过滤，不需要也不能自己传权限参数）。
- 本命令**不支持** `--format-data`（原始字段已是扁平结构，直接读取即可）。
- `--page-size` 默认 50，本接口不支持 `pageNum` 翻页。

## 持有数量查询（holding）

```bash
shb-cli part personal holding --user-id <userId> --sparepart-ids <备件id1,备件id2>
```

- `--user-id`、`--sparepart-ids` **均必填**，缺一即报错（后端返回"缺少参数"业务错误）。
- `--sparepart-ids` 逗号分隔，支持一次查多个备件。
- 返回 `[{sparepartId, sparepartNumber}]`，`sparepartNumber` 即该人持有该备件的数量（口径同 `personal search` 的 `quantity`：含退回中）。
- 本模块唯一带 `{status,succ,message,data}` 信封的接口，CLI 已自动解包出 `data` 数组，无需关心信封细节。
- 本命令**不支持** `--format-data`（结构已经很简单）。

## 典型组合场景

### 场景一：查某人手上有哪些备件

```bash
# 1. 按姓名找到 userId
shb-cli part personal users --keyword "天驰"

# 2. 查其持有列表
shb-cli part personal search --user-id <userId> --all --format-data --fields serialNumber,name,quantity,userName
```

### 场景二：查某人对某个备件的持有数量（已知备件 id）

```bash
shb-cli part personal holding --user-id <userId> --sparepart-ids <sparepartId>
```

### 场景三：查某人某段时间的领用/退回流水

```bash
shb-cli part personal use-record --user-id <userId> \
  --time-start "2026-01-01 00:00:00" --time-end "2026-01-31 23:59:59" \
  --format-data --fields serialNumber,item,number,taskNo,customerName,createTime
```

## 注意

- `personal search`/`stock-record`/`use-record` 默认输出原始响应（裸 PageInfo，`personal search` 额外带 `sparepartCountTotal`/`sparepartNumTotal`；**没有** status/data 信封）；需要字段文案、展平字段和值格式化时显式传 `--format-data`。
- 搜索结果异常偏多，先检查是否漏传了 `--user-id`（不传就是查团队/全部，见上方 CRITICAL 说明）。
- **统计需求优先用计数查询**：只需要总数时用 `--page-size 1` 取 `page.totalElements`（品类数）或响应里的 `sparepartCountTotal`（总数量），不要为了数数把全量明细拉进来。
