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

# shb-cli task create

工单创建。`task create submit` 是写操作，默认会先检查 VIP 审批和普通审批；若后端要求审批，命令会输出审批信息并停止，不会继续创建。

## 安全规则

- 创建前确认用户明确要求“创建/新建工单”。
- 默认不要使用 `--no-approve`。该标志会跳过审批检查并直接调用创建接口。
- 字段不确定时，先用 `task type list --list-type writeList` 找 `templateId`，再用 `task field list --type-id <templateId>` 查字段。
- 创建前会读取公共字段和工单主表字段；`isNull=0` 的必填字段必须有值，没有值时向用户询问，否则不会继续审批检查或创建。**读字段、判断哪些必填都是后台内部步骤**：缺值时直接用中文向用户要那几项的值（如「请提供客户」「请提供计划开始时间」），**绝不要把 `isNull`、「必填字段清单」、字段配置或「我看到字段配置是…」这类判断过程复述给用户**。
- 客户字段是必填的：执行创建时必须先向用户询问客户，**然后读取 formType 为 customer 的字段**，取其 **setting.customerOption** 对象判断还需要哪些关联字段。下面是它的原始结构（**仅供你内部读取判断，绝不照搬进回复**）：

  ```json
  {
    "product": true,
    "address": true,
    "productIsShow": true,
    "linkman": true,
    "productNotNull": false
  }
  ```

  各 key 的含义（**仅供你内部判断，不要把这些英文 key 名抛给用户**）：

  | key | 含义 |
  |-----|------|
  | `product` | 是否需要「产品」字段 |
  | `address` | 是否需要「客户地址」字段 |
  | `linkman` | 是否需要「客户联系人」字段 |
  | `productIsShow` | 是否显示「产品」字段 |
  | `productNotNull` | 「产品」字段是否必填 |

  读取 `setting.customerOption` 是**纯后台内部步骤**：据此判断需要哪些关联信息后，**直接用中文向用户开口要**（如「请提供客户地址」「请提供联系人」「需要关联哪个产品」），用户只看到你「要什么」。
  **回复里绝不出现 `setting.customerOption` 这个对象、它的字段名（`product`/`address`/`linkman`/`productIsShow` 等）或它的 true/false 值，也不要复述「我读到/看到字段配置是…」这类你的判断过程**——那是你内部怎么判断的，用户不需要、也不该看到。
- **客户、联系人、产品、地址必须是系统内真实存在的数据，严禁捏造**。这些对象的 `id` 及关联字段必须来自查询结果，不能凭空编造或猜测：
  - 客户：**必须当场执行 `customer list`（客户模块没有 `search` 子命令）查找确认，拿到本次查询结果里的 `customer.id`**——**不得**从对话上下文里直接取之前出现过的客户 id（即使本轮聊过该客户），以免张冠李戴或用到过期/错误的客户。此处是「复用已知 ID」规则的例外：创建工单的客户一律重新查。
  - 联系人：`customer linkman search --customer-id <id>` 获取该客户名下真实的联系人（含 id）；地址：`customer address list --customer-id <id>` 获取真实地址（含 id）。主/默认联系人或地址看 `isMain` 字段；
  - 产品：从客户关联的产品查询结果中取 `products` 数组元素（含 `id`、`catalogId` 等）。
  - 若用户口头提供的客户/联系人/产品/地址在系统中查不到，应告知用户并让其确认或先创建对应数据，**不得**用编造的 id 或信息提交。
- 简单字段用快捷 flags 即可；复杂字段、附件、自定义 `task.attribute` 等用 `--data` 内联提供完整 JSON；`--file` 最后（仅本地已有文件时用）。

## 创建前查看字段

创建前先确认该工单类型有哪些字段、哪些必填（见上方安全规则）：

```bash
# 只想看字段时，使用只读字段命令
shb-cli task field list --type-id <templateId>

# 显示字段后继续按当前参数创建
shb-cli task create submit --template-id <templateId> --show-fields --description "测试工单"
```

## 快捷 flag 创建示例

```bash
shb-cli task create submit \
  --template-id "工单类型ID" \
  --template-name "工单类型名称" \
  --description "客户现场设备异常" \
  --customer-id "客户ID" \
  --customer-name "客户名称" \
  --linkman-name "联系人" \
  --linkman-phone "13800000000" \
  --province "上海市" \
  --city "上海市" \
  --district "浦东新区" \
  --detail-address "xx 路 xx 号" \
  --plan-start-time 1782535200000 \
  --plan-end-time 1782542400000
```

不使用 `--data` / `--file` 时，`--template-id` 和 `--template-name` 都必填；`--template-name` 必须与 `--template-id` 对应的工单类型名称一致（来自 `task type list --list-type writeList`），**不要随意捏造**。

> 计划时间用**13 位毫秒**时间戳（与后端一致，如 `1782535200000`）；CLI 原样透传、不做秒↔毫秒换算，传 10 位秒会被后端按毫秒误解。

## 完整 JSON 创建

**使用优先级：`--data` 最优先**——只要传了 `--data`，就以它为准，覆盖快捷 flags 与 `--file`；没有 `--data` 时，常规字段用快捷 flags，`--file` 仅本地已有现成 JSON 文件时用。
使用 `--data` / `--file` 时，JSON 结构**必须严格按照下方示例结构**，顶层包含 `task`、`customer`、`address`、`linkman` 四个 key，不得随意展平或省略顶层结构。`task.templateId` 必须存在，CLI 会据此加载字段元数据并校验必填字段。

> ⚠️ **`task.attribute` 必须存在（可为空对象 `{}`）**。后端在 `task.attribute` 为 `null` 时会返回 `500002 系统错误`。快捷 flags 路径 CLI 已自动补 `"attribute": {}`，但使用 `--data` / `--file` 自行拼 JSON 时必须显式带上。
>
> ⚠️ **`task.templateName` 必须传**，且要与 `templateId` 对应的工单类型名称一致，**请不要随意捏造**（来自 `task type list --list-type writeList` 返回的名称）。

```bash
shb-cli task create submit --template-id <templateId> --show-fields --file ./create-task.json
shb-cli task create submit --template-id <templateId> --show-fields --data '{"task":{"templateId":"xxx","description":"测试工单"}}'
```

示例 创建工单的参数JSON结构：

```json
{
  "task": {
    "templateId": "xxx",
    "templateName": "xxxxx",
    "level": "high",
    "serviceType": "maintenance",
    "serviceContent": "system maintenance",
    "description": "regular maintenance required",
    "planStartTime": 1777132800000,
    "planEndTime": 1777478400000,
    "products": [
        {
          "catalogId": 511205,
          "id": "xxxxx",
          "name": "xxx",
          "serialNumber": "xxxx",
          "type": "xxx类型",
          "customerId": "客户id",
          "qualityEndTime": "",
          "qualityStartTime": "",
          "qualityStatus": ""
        }
      ],
    "attribute": {
      "customField": "custom value"
    }
  },
  "customer": {
    "id": "客户id",
    "name": "客户名称"
  },
  "address": {
    "country": "China",
    "province": "Shanghai",
    "city": "Shanghai",
    "district": "Pudong",
    "detailAddress": "123 Main St"
  },
  "linkman": {
    "name": "Contact A",
    "phone": "13800000000"
  },
  "address": {
    "label": "中国-xx省-xxx市-xxxx县-xxxxxxx",
    "value": "客户地址id",
    "createUser": null,
    "updateUser": null,
    "createTime": 1777271683000,
    "updateTime": 1777271683000,
    "id": "客户地址id",
    "country": "中国",
    "province": "xxx省",
    "city": "xxx市",
    "dist": "xxx县",
    "street": "",
    "address": "1111",
    "longitude": 117.333812,
    "latitude": 27.541061,
    "isMain": 0,
    "attribute": null,
    "addressType": 0,
    "addressNum": null,
    "customerId": "客户id",
    "guideProfessions": [],
    "isGuideData": false,
    "allAddress": null,
    "showAddress": null,
    "guideData": false
  }
}
```

## 支持的快捷 flags

| 分类 | Flags |
|------|-------|
| 工单 | `--template-id`（必填）, `--template-name`（必填，与 template-id 对应的类型名）, `--level`, `--service-type`, `--service-content`, `--description`, `--plan-time`, `--plan-start-time`, `--plan-end-time`, `--engineer-qualification`, `--provider-qualification`, `--estimated-mileage` |
| 客户 | `--customer-id`, `--customer-name` |
| 地址 | `--country`, `--province`, `--city`, `--district`, `--detail-address`, `--latitude`, `--longitude` |
| 联系人 | `--linkman-id`, `--linkman-name`, `--linkman-phone` |
| 关联 | `--flow`, `--event-id`, `--event-no`, `--tick` |
| 自定义字段 | `--custom-fields`（JSON 字符串，合并进 `task.attribute`，如 `'{"field_xxx":"value"}'`） |
| 输入 | `--data`, `--file` |
| 控制 | `--show-fields`, `--no-approve` |

## 审批流程

默认执行顺序：

1. 检查是否需要 VIP 审批。
2. 检查是否需要普通审批。
3. 无需审批时创建工单。

如果返回 “VIP Approval required” 或 “Approval required”，命令会输出后端返回的审批信息并停止。把该信息反馈给用户，不要自动改用 `--no-approve`。

`service task task-mutation` 下的方法标记为 write，非交互执行时通常需要 `--yes` 确认。

## 注意

- `task.attribute`、附件、产品等不在快捷 flags 覆盖范围内，使用 `--file` / `--data`。
- `--show-fields` 需要配合 `--template-id` 才会展示对应类型字段。
- 创建成功后会输出后端返回的 JSON，可从中提取新工单 ID / 编号。
- 在执行工单创建的时候如果有错误，请友好的提示错误信息，不要切换类型。
