## 目标
- 将现有单件发货接口扩展为批量接口，支持一次提交多个资产 ID（如：{"inventory_ids":[52,53,...]}）。
- 复用现有发货能力（默认地址、资产状态迁移、备注标记），保证幂等与错误可追踪。

## 现状
- 单件接口：`POST /api/app/users/{user_id}/inventory/request-shipping`，请求体 `{ inventory_id }`
- 处理器位置：internal/api/user/request_shipping_app.go:30-47
- 服务层：`RequestShipping(ctx, userID, inventoryID)` 设置资产状态为已申请发货并记录备注
  - 代码位置：internal/service/user/address_share.go:120-126（`UPDATE user_inventory SET status=3, ... remark+='|shipping_requested' WHERE status=1`）

## 接口设计
- 新增：`POST /api/app/users/{user_id}/inventory/request-shipping-batch`
- 请求体：
  - `inventory_ids` 数组，必填，长度 1–100，去重后处理
  - `address_id` 可选；若不提供则使用用户默认地址
- 返回体：
  - `address_id` 实际使用的地址 ID
  - `success_ids` 已成功提交的资产 ID 列表
  - `skipped` 数组：[{ id, reason }]（如 not_found、not_owned、invalid_status、already_requested）
  - `failed` 数组：[{ id, reason }]（如 DB 错误等）

## 行为与规则
- 地址选择
  - 若提供 `address_id`：校验属于该用户且有效；否则返回 400
  - 若未提供：读取默认地址；不存在则返回 400（沿用现有单件逻辑）
- 资产校验（逐个）
  - 必须属于该用户
  - `status=1`（可发货）才处理；`status=3`（已申请）则标记为 `already_requested` 并 skip（幂等）
  - 不存在或不属于该用户 → `skipped.not_owned/not_found`
- 幂等性
  - 若 remark 已包含 `shipping_requested` 或状态为 3，则视为已处理；加入 `skipped` 并不报错
- 原子性
  - 批量以“逐条子事务”处理（每条调用服务层更新），确保单条失败不影响其他条目；最终返回成功/跳过/失败三类列表
- 审计
  - 在 `user_points_ledger` 无需记录（该流程与积分无关）；如需审计可在后续增加 `user_operations` 表留痕

## 服务层扩展
- 新增：`RequestShippings(ctx, userID int64, inventoryIDs []int64, addressID *int64) (addrID int64, success []int64, skipped []struct{id int64; reason string}, failed []struct{id int64; reason string}, err error)`
  - 内部：
    - 若 `addressID==nil`，读取默认地址（沿用单件方法）
    - 循环：校验→调用现有 `RequestShipping(ctx, userID, inventoryID)`；捕获错误进行分流
  - 可选优化：对同一用户的多件，合并一次地址校验；对 DB 更新使用独立事务（已在现有方法内处理）

## 处理器实现
- 新增处理器：`RequestShippingBatch()`：
  - 位置：internal/api/user/request_shipping_app.go（或新文件 `request_shipping_batch_app.go`）
  - 解析 `inventory_ids`（去重、长度限制）；解析可选 `address_id`
  - 调用服务层批量方法，组装响应
  - 统一错误码：参数错误 `code.ParamBindError`，无地址 `10021`（沿用或新增），其他子项错误填入 `failed` 字段

## 错误码与返回示例
- 400 参数错误：`{"code":10023,"message":"invalid inventory_ids"}`
- 200 成功+部分跳过：
```
{
  "address_id": 888,
  "success_ids": [52, 53],
  "skipped": [{"id": 54, "reason": "already_requested"}],
  "failed": []
}
```

## 测试用例
- 有默认地址，提交 1、N 个有效资产 → 全成功
- 混合：包含非本用户、已申请、不存在 → 分别进 `skipped`
- 指定 address_id 非本用户 → 400
- 无默认地址且未指定 address → 400
- 幂等：重复提交相同资产 → 均进入 `already_requested`

## 兼容性
- 不改动现有单件接口；前端可增设批量勾选后调用新接口
- DB 无结构变化；仍依赖 `user_inventory.status` 与 `remark` 标记

## 交付内容
- 新增批量处理器与服务方法
- Swagger 注释与接口文档
- 单元测试：服务层批量逻辑、处理器参数校验

请确认按此方案实施，我将立即落地代码、接口与测试。