4 天以前 741918a903e17b2ec7522556d2c043b8d35dd8a1
docs/quality_unqualified_order.md
@@ -1,34 +1,49 @@
# 不合格品处理单 — 前端联调文档
# 不合格品处理单模块(QualityUnqualifiedOrder)
## 概述
不合格品处理单是正式的不合格品处置流程模块,替代旧的不合格管理(`/quality/qualityUnqualified`)中的处置功能。旧模块的不合格品发现(新增/列表/详情)继续使用,但**处置操作统一使用本模块**。
### 自动创建机制
当检验单(原材料/过程/出厂检验)提交时,如果**不合格数量 > 0**,系统在创建 `QualityUnqualified` 记录的同时,**自动创建一条不合格品处理单**,`unqualifiedProcess`(不合格工序)根据检验类别自动映射:
| 检验类别 | inspectType | unqualifiedProcess |
|----------|-------------|-------------------|
| 原材料检验 | 0 | 1(来料) |
| 过程检验 | 0 | 2(制程) |
| 出厂检验 | 0 | 3(成品) |
处理单初始状态为 `0`(草稿),后续可编辑处置方式并提交审批。
### 与旧模块的关系
| | 旧:不合格管理 | 新:不合格品处理单 |
|---|---|---|
| 路径 | `/quality/qualityUnqualified` | `/qualityUnqualifiedOrder` |
| 用途 | 不合格品首次记录、查看 | 正式处置流程(含审批) |
| 处置方式 | `dealResult` 自由文本 | `disposalMethod` 结构化枚举 |
| 创建方式 | 检验单提交自动创建 / 手动新增 | 检验单提交自动创建 / 手动新增 |
## 涉及页面
- **不合格品处理单列表/详情** — 新增页面
## 变更说明
新增 `quality_unqualified_order` 不合格品处理单模块,支持对不合格品进行正式的处置记录,包含审批状态机(草稿→待审批→审批中→已完成/已驳回)。附件使用系统统一的 `storage_attachment` 表。
- 不合格品处理单列表页
- 不合格品处理单新增/编辑页
- 不合格品处理单详情页
## API
### 不合格品处理单
### 1. 新增处理单
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/qualityUnqualifiedOrder/save` | 新增处理单(编号自动生成) |
| PUT | `/qualityUnqualifiedOrder/update` | 修改处理单 |
| DELETE | `/qualityUnqualifiedOrder/delete` | 批量删除(逻辑删除) |
| GET | `/qualityUnqualifiedOrder/listPage` | 分页查询 |
| GET | `/qualityUnqualifiedOrder/{id}` | 查看详情 |
| POST | /qualityUnqualifiedOrder/save | 新增不合格品处理单 |
### 请求/响应参数
**QualityUnqualifiedOrder 对象:**
**请求参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| id | Long | 否 | 主键(修改时必填) |
| orderNo | String | 否 | 处理单编号,自动生成,前缀 BHG+日期+序号 |
| unqualifiedId | Long | 否 | 关联不合格品ID |
| unqualifiedId | Long | 是 | 关联不合格品ID |
| projectName | String | 否 | 项目名称 |
| projectNo | String | 否 | 项目编号 |
| equipmentId | Long | 否 | 关联设备ID |
@@ -41,7 +56,7 @@
| materialQuality | String | 否 | 材质 |
| quantity | BigDecimal | 否 | 总数量 |
| unqualifiedQuantity | BigDecimal | 否 | 不合格数量 |
| unqualifiedProcess | Integer | 否 | 不合格工序:1=来料,2=制程,3=成品 |
| unqualifiedProcess | Integer | 否 | 不合格工序:1=来料, 2=制程, 3=成品 |
| supplierName | String | 否 | 供应商名称 |
| inspectorName | String | 否 | 检验员 |
| inspectDate | Date | 否 | 检验日期 (yyyy-MM-dd) |
@@ -50,233 +65,501 @@
| problemDescription | String | 否 | 问题描述 |
| reasonAnalysis | String | 否 | 原因分析及建议 |
| correctionAction | String | 否 | 纠正措施 |
| disposalMethod | Integer | 否 | 处置方式:1=让步接收,2=厂内维修,3=返厂维修,4=换货,5=退货,6=报废 |
| **disposalMethod** | **Integer** | **是** | **处置方式:1=让步接收, 2=厂内维修, 3=返厂维修, 4=换货, 5=退货, 6=报废** |
| repairEvaluation | String | 否 | 厂内/返厂维修评估 |
| preventiveAction | String | 否 | 预防措施 |
| status | Integer | 否 | 状态:0=草稿,1=待审批,2=审批中,3=已完成,4=已驳回 |
| remark | String | 否 | 备注 |
| storageBlobDTOs | List\<StorageBlobDTO\> | 否 | 附件上传列表 |
| storageBlobVOs | List\<StorageBlobVO\> | 否 | 附件回显列表(查询时返回) |
| deptOpinion | String | 否 | 责任部门主管意见 |
| companyDecision | String | 否 | 公司处理决定 |
| generalManagerOpinion | String | 否 | 总经理意见 |
| storageBlobDTOs | List | 否 | 附件列表 |
### 分页查询参数
**自动行为:**
- 自动生成处理单编号(`BHGyyMMdd+流水号`)
- **手动新增时**:选了处置方式 → 状态自动为 `3`(已完成);没选 → 状态为 `0`(草稿)
- **质检自动创建时**:状态初始为 `0`(草稿),需通过处理接口补充处置方式
- **当 `disposalMethod` 选择 2(厂内维修)或 3(返厂维修)时,自动创建返修生产订单**
**响应:** `{ "code": 200, "msg": "操作成功", "data": true }`
### 2. 修改处理单
| 方法 | 路径 | 说明 |
|------|------|------|
| PUT | /qualityUnqualifiedOrder/update | 修改不合格品处理单 |
**请求参数:** 与新增相同,额外需要 `id` 字段。
### 3. 删除处理单
| 方法 | 路径 | 说明 |
|------|------|------|
| DELETE | /qualityUnqualifiedOrder/delete | 删除不合格品处理单 |
**请求参数:** `[id1, id2, ...]` — ID 数组
### 4. 分页查询
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /qualityUnqualifiedOrder/listPage | 分页查询 |
**查询参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| pageNum | Integer | 否 | 页码,默认1 |
| pageSize | Integer | 否 | 每页条数,默认10 |
| status | Integer | 否 | 状态筛选 |
| projectName | String | 否 | 项目名称模糊搜索 |
| orderNo | String | 否 | 编号模糊搜索 |
| entryDateStart | String | 否 | 创建时间起始 |
| entryDateEnd | String | 否 | 创建时间结束 |
| page | int | 否 | 页码(默认1) |
| size | int | 否 | 每页条数(默认10) |
| status | Integer | 否 | 状态:0=草稿, 1=待审批, 2=审批中, 3=已完成, 4=已驳回 |
| projectName | String | 否 | 项目名称(模糊匹配) |
| orderNo | String | 否 | 处理单编号(模糊匹配) |
| entryDateStart | String | 否 | 创建时间起 (yyyy-MM-dd) |
| entryDateEnd | String | 否 | 创建时间止 (yyyy-MM-dd) |
### 删除请求体
**响应字段:** 返回 `QualityUnqualifiedOrder` 全部字段,含 `storageBlobVOs`(附件列表)。
```json
[1, 2, 3]
```
### 5. 详情查询
## 数据结构
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /qualityUnqualifiedOrder/{id} | 处理单详情 |
### StorageBlobDTO(上传时传入)
**响应:** 返回单条 `QualityUnqualifiedOrder` 全部字段,含附件。
```json
{
  "id": "临时文件ID(字符串)",
  "name": "文件名",
  "url": "文件路径",
  "fileSize": 1024
}
```
### 6. 处理(处置)
### StorageBlobVO(查询时返回)
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /qualityUnqualifiedOrder/deal | 对草稿状态的处理单补充处置方式并完成 |
```json
{
  "id": 1,
  "name": "检验报告.pdf",
  "url": "/upload/20260613/xxx.pdf",
  "fileSize": 102400,
  "application": "FILE"
**请求参数:**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| **id** | **Long** | **是** | 处理单ID |
| **disposalMethod** | **Integer** | **是** | **处置方式:1=让步接收, 2=厂内维修, 3=返厂维修, 4=换货, 5=退货, 6=报废** |
| repairEvaluation | String | 否 | 厂内/返厂维修评估 |
| reasonAnalysis | String | 否 | 原因分析及建议 |
| correctionAction | String | 否 | 纠正措施 |
| preventiveAction | String | 否 | 预防措施 |
| remark | String | 否 | 备注 |
| deptOpinion | String | 否 | 责任部门主管意见 |
| companyDecision | String | 否 | 公司处理决定 |
| generalManagerOpinion | String | 否 | 总经理意见 |
**自动行为:**
- 状态更新为 `3`(已完成)
- 处置方式为 2(厂内维修)或 3(返厂维修)时,自动创建返修生产订单
**响应:** `{ "code": 200, "msg": "操作成功", "data": true }`
### 7. 导出处理单
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /qualityUnqualifiedOrder/export/{id} | 导出不合格品处理单为 Excel |
**请求参数:** `id` — 处理单ID(路径参数)
**响应:** 文件流,`Content-Type: application/vnd.ms-excel`,文件名 `不合格品处理单_{编号}.xls`
**模板字段映射:**
| 模板位置 | 字段 |
|----------|------|
| 项目名称 | projectName |
| 项目编号 | projectNo |
| 设备名称 | equipmentName |
| 设备图号 | equipmentDrawingNo |
| 物料名称 | materialName |
| 物料图号 | materialDrawingNo |
| 型号规格 | specificationModel |
| 材质 | materialQuality |
| 总数量 | quantity |
| 不合格数 | unqualifiedQuantity |
| 不合格工序 | unqualifiedProcess(勾选来料/制程/成品) |
| 供货商名称 | supplierName |
| 检验员 | inspectorName |
| 检验日期 | inspectDate |
| 责任人 | responsiblePerson |
| 责任部门 | responsibleDept |
| 问题描述 | problemDescription |
| 原因分析及建议 | reasonAnalysis |
| 纠正措施 | correctionAction |
| 处置方式 | disposalMethod(勾选对应选项) |
| 厂内/返厂维修评估 | repairEvaluation |
| 预防措施 | preventiveAction |
| 责任部门主管意见 | deptOpinion |
| 公司处理决定 | companyDecision |
| 总经理意见 | generalManagerOpinion |
**前端调用示例:**
```js
// 列表页操作列增加导出按钮
<el-button text type="primary" @click="handleExport(row.id)">导出</el-button>
// 详情页增加导出按钮
<el-button type="primary" @click="handleExport">导出</el-button>
methods: {
  handleExport(id) {
    window.open(`/api/qualityUnqualifiedOrder/export/${id}`);
  },
}
```
## 前端修改点
### 1. 不合格品处理单 — 新增/编辑表单
### 1. 处理单列表页
```html
<el-form :model="form" :rules="rules" ref="formRef">
  <el-form-item label="项目名称" prop="projectName">
    <el-input v-model="form.projectName" />
  </el-form-item>
  <el-form-item label="项目编号" prop="projectNo">
    <el-input v-model="form.projectNo" />
  </el-form-item>
  <el-form-item label="设备名称" prop="equipmentName">
    <el-input v-model="form.equipmentName" />
  </el-form-item>
  <el-form-item label="物料/部件名称" prop="materialName">
    <el-input v-model="form.materialName" />
  </el-form-item>
  <el-form-item label="型号规格" prop="specificationModel">
    <el-input v-model="form.specificationModel" />
  </el-form-item>
  <el-form-item label="材质" prop="materialQuality">
    <el-input v-model="form.materialQuality" />
  </el-form-item>
  <el-form-item label="总数量" prop="quantity">
    <el-input-number v-model="form.quantity" />
  </el-form-item>
  <el-form-item label="不合格数量" prop="unqualifiedQuantity">
    <el-input-number v-model="form.unqualifiedQuantity" />
  </el-form-item>
  <el-form-item label="不合格工序" prop="unqualifiedProcess">
    <el-select v-model="form.unqualifiedProcess">
      <el-option label="来料" :value="1" />
      <el-option label="制程" :value="2" />
      <el-option label="成品" :value="3" />
    </el-select>
  </el-form-item>
  <el-form-item label="供应商名称" prop="supplierName">
    <el-input v-model="form.supplierName" />
  </el-form-item>
  <el-form-item label="检验员" prop="inspectorName">
    <el-input v-model="form.inspectorName" />
  </el-form-item>
  <el-form-item label="检验日期" prop="inspectDate">
    <el-date-picker v-model="form.inspectDate" type="date" value-format="yyyy-MM-dd" />
  </el-form-item>
  <el-form-item label="责任人" prop="responsiblePerson">
    <el-input v-model="form.responsiblePerson" />
  </el-form-item>
  <el-form-item label="责任部门" prop="responsibleDept">
    <el-input v-model="form.responsibleDept" />
  </el-form-item>
  <el-form-item label="问题描述" prop="problemDescription">
    <el-input type="textarea" v-model="form.problemDescription" />
  </el-form-item>
  <el-form-item label="原因分析" prop="reasonAnalysis">
    <el-input type="textarea" v-model="form.reasonAnalysis" />
  </el-form-item>
  <el-form-item label="纠正措施" prop="correctionAction">
    <el-input type="textarea" v-model="form.correctionAction" />
  </el-form-item>
  <el-form-item label="处置方式" prop="disposalMethod">
    <el-select v-model="form.disposalMethod">
      <el-option label="让步接收" :value="1" />
      <el-option label="厂内维修" :value="2" />
      <el-option label="返厂维修" :value="3" />
      <el-option label="换货" :value="4" />
      <el-option label="退货" :value="5" />
      <el-option label="报废" :value="6" />
    </el-select>
  </el-form-item>
  <el-form-item label="维修评估" prop="repairEvaluation">
    <el-input type="textarea" v-model="form.repairEvaluation" />
  </el-form-item>
  <el-form-item label="预防措施" prop="preventiveAction">
    <el-input type="textarea" v-model="form.preventiveAction" />
  </el-form-item>
  <el-form-item label="备注" prop="remark">
    <el-input type="textarea" v-model="form.remark" />
  </el-form-item>
  <el-form-item label="附件">
    <file-upload
      v-model="form.storageBlobDTOs"
      :file-list="form.storageBlobVOs"
    />
  </el-form-item>
</el-form>
<template>
  <div class="app-container">
    <!-- 搜索栏 -->
    <el-form :model="queryParams" :inline="true">
      <el-form-item label="处理单编号">
        <el-input v-model="queryParams.orderNo" placeholder="输入编号" />
      </el-form-item>
      <el-form-item label="项目名称">
        <el-input v-model="queryParams.projectName" placeholder="输入项目" />
      </el-form-item>
      <el-form-item label="状态">
        <el-select v-model="queryParams.status" placeholder="全部" clearable>
          <el-option label="草稿" :value="0" />
          <el-option label="待审批" :value="1" />
          <el-option label="审批中" :value="2" />
          <el-option label="已完成" :value="3" />
          <el-option label="已驳回" :value="4" />
        </el-select>
      </el-form-item>
      <el-form-item label="创建时间">
        <el-date-picker v-model="dateRange" type="daterange" value-format="yyyy-MM-dd"
          start-placeholder="开始" end-placeholder="结束" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleQuery">查询</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <!-- 操作按钮 -->
    <el-row :gutter="10" class="mb8">
      <el-button type="primary" @click="handleAdd">新增处理单</el-button>
      <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete">删除</el-button>
    </el-row>
    <!-- 表格 -->
    <el-table :data="list" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" />
      <el-table-column label="处理单编号" prop="orderNo" width="160" />
      <el-table-column label="项目名称" prop="projectName" />
      <el-table-column label="型号规格" prop="specificationModel" width="120" />
      <el-table-column label="不合格数量" prop="unqualifiedQuantity" width="100" />
      <el-table-column label="处置方式" width="110">
        <template #default="{ row }">
          {{ disposalMethodMap[row.disposalMethod] }}
        </template>
      </el-table-column>
      <el-table-column label="状态" width="80">
        <template #default="{ row }">
          <el-tag :type="statusTagType(row.status)">{{ statusMap[row.status] }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="检验员" prop="inspectorName" width="100" />
      <el-table-column label="检验日期" prop="inspectDate" width="110" />
      <el-table-column label="创建时间" prop="createTime" width="160" />
      <el-table-column label="操作" width="120" fixed="right">
        <template #default="{ row }">
          <el-button text type="primary" @click="handleDetail(row.id)">详情</el-button>
          <el-button text type="primary" @click="handleEdit(row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination :total="total" v-model:page="page" v-model:limit="size"
      @pagination="loadList" />
  </div>
</template>
```
### 2. 不合格品处理单 — 列表页
```js
data() {
  return {
    list: [],
    total: 0,
    page: 1,
    size: 10,
    selectedIds: [],
    dateRange: [],
    queryParams: {
      orderNo: '',
      projectName: '',
      status: null,
    },
    disposalMethodMap: { 1: '让步接收', 2: '厂内维修', 3: '返厂维修', 4: '换货', 5: '退货', 6: '报废' },
    statusMap: { 0: '草稿', 1: '待审批', 2: '审批中', 3: '已完成', 4: '已驳回' },
  }
},
methods: {
  statusTagType(status) {
    const map = { 0: 'info', 1: 'warning', 2: '', 3: 'success', 4: 'danger' };
    return map[status] || 'info';
  },
  loadList() {
    const params = { ...this.queryParams, page: this.page, size: this.size };
    if (this.dateRange && this.dateRange.length === 2) {
      params.entryDateStart = this.dateRange[0];
      params.entryDateEnd = this.dateRange[1];
    }
    listPage(params).then(res => {
      this.list = res.rows;
      this.total = res.total;
    });
  },
  handleQuery() { this.page = 1; this.loadList(); },
  resetQuery() {
    this.queryParams = { orderNo: '', projectName: '', status: null };
    this.dateRange = [];
    this.handleQuery();
  },
  handleSelectionChange(selection) { this.selectedIds = selection.map(i => i.id); },
  handleAdd() { this.$router.push('/quality/unqualified-order/add'); },
  handleEdit(row) { this.$router.push({ path: '/quality/unqualified-order/edit', query: { id: row.id } }); },
  handleDetail(id) { this.$router.push({ path: '/quality/unqualified-order/detail', query: { id } }); },
  handleDelete() {
    this.$confirm('确认删除选中的处理单?').then(() => {
      deleteOrders(this.selectedIds).then(() => {
        this.$message.success('删除成功');
        this.loadList();
      });
    });
  },
}
```
### 2. 新增/编辑处理单页
```html
<el-table :data="tableData" border>
  <el-table-column prop="orderNo" label="处理单编号" />
  <el-table-column prop="projectName" label="项目名称" />
  <el-table-column prop="materialName" label="物料名称" />
  <el-table-column prop="specificationModel" label="型号规格" />
  <el-table-column prop="unqualifiedQuantity" label="不合格数量" />
  <el-table-column prop="disposalMethod" label="处置方式">
    <template #default="{ row }">
      {{ disposalMethodMap[row.disposalMethod] }}
    </template>
  </el-table-column>
  <el-table-column prop="status" label="状态">
    <template #default="{ row }">
      <el-tag :type="statusTagType(row.status)">{{ statusMap[row.status] }}</el-tag>
    </template>
  </el-table-column>
  <el-table-column label="操作">
    <template #default="{ row }">
      <el-button type="text" @click="handleDetail(row.id)">详情</el-button>
      <el-button type="text" @click="handleEdit(row)">编辑</el-button>
      <el-button type="text" @click="handleDelete(row.id)">删除</el-button>
    </template>
  </el-table-column>
</el-table>
```
<template>
  <div class="app-container">
    <el-form ref="form" :model="form" :rules="rules" label-width="120px">
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="关联不合格品" prop="unqualifiedId">
            <el-select v-model="form.unqualifiedId" placeholder="选择不合格品" filterable>
              <el-option v-for="item in unqualifiedList" :key="item.id"
                :label="item.productName + ' ' + item.model + ' (' + item.quantity + ')'"
                :value="item.id" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="不合格工序" prop="unqualifiedProcess">
            <el-select v-model="form.unqualifiedProcess">
              <el-option label="来料" :value="1" />
              <el-option label="制程" :value="2" />
              <el-option label="成品" :value="3" />
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
### 3. data 数据
      <el-divider>基本信息</el-divider>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="项目名称" prop="projectName">
            <el-input v-model="form.projectName" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="项目编号" prop="projectNo">
            <el-input v-model="form.projectNo" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="物料/部件名称" prop="materialName">
            <el-input v-model="form.materialName" />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="物料图号" prop="materialDrawingNo">
            <el-input v-model="form.materialDrawingNo" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="8">
          <el-form-item label="型号规格" prop="specificationModel">
            <el-input v-model="form.specificationModel" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="材质" prop="materialQuality">
            <el-input v-model="form.materialQuality" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="供应商" prop="supplierName">
            <el-input v-model="form.supplierName" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-divider>不合格信息</el-divider>
      <el-row :gutter="20">
        <el-col :span="8">
          <el-form-item label="总数量" prop="quantity">
            <el-input-number v-model="form.quantity" :min="0" :precision="2" style="width:100%" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="不合格数量" prop="unqualifiedQuantity">
            <el-input-number v-model="form.unqualifiedQuantity" :min="0" :precision="2" style="width:100%" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="检验日期" prop="inspectDate">
            <el-date-picker v-model="form.inspectDate" type="date" value-format="yyyy-MM-dd" style="width:100%" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="20">
        <el-col :span="8">
          <el-form-item label="检验员" prop="inspectorName">
            <el-input v-model="form.inspectorName" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="责任人" prop="responsiblePerson">
            <el-input v-model="form.responsiblePerson" />
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item label="责任部门" prop="responsibleDept">
            <el-input v-model="form.responsibleDept" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-form-item label="问题描述" prop="problemDescription">
        <el-input v-model="form.problemDescription" type="textarea" :rows="2" />
      </el-form-item>
      <el-divider>处置决策</el-divider>
      <el-form-item label="处置方式" prop="disposalMethod">
        <el-radio-group v-model="form.disposalMethod">
          <el-radio :value="1">让步接收</el-radio>
          <el-radio :value="2">厂内维修</el-radio>
          <el-radio :value="3">返厂维修</el-radio>
          <el-radio :value="4">换货</el-radio>
          <el-radio :value="5">退货</el-radio>
          <el-radio :value="6">报废</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item v-if="form.disposalMethod === 2 || form.disposalMethod === 3" label="维修评估" prop="repairEvaluation">
        <el-input v-model="form.repairEvaluation" type="textarea" :rows="3"
          placeholder="评估维修可行性、所需工时、物料等" />
      </el-form-item>
      <el-form-item label="原因分析及建议" prop="reasonAnalysis">
        <el-input v-model="form.reasonAnalysis" type="textarea" :rows="3" />
      </el-form-item>
      <el-form-item label="纠正措施" prop="correctionAction">
        <el-input v-model="form.correctionAction" type="textarea" :rows="3" />
      </el-form-item>
      <el-form-item label="预防措施" prop="preventiveAction">
        <el-input v-model="form.preventiveAction" type="textarea" :rows="3" />
      </el-form-item>
      <el-divider>审批意见</el-divider>
      <el-form-item label="责任部门主管意见" prop="deptOpinion">
        <el-input v-model="form.deptOpinion" type="textarea" :rows="2" />
      </el-form-item>
      <el-form-item label="公司处理决定" prop="companyDecision">
        <el-input v-model="form.companyDecision" type="textarea" :rows="2" />
      </el-form-item>
      <el-form-item label="总经理意见" prop="generalManagerOpinion">
        <el-input v-model="form.generalManagerOpinion" type="textarea" :rows="2" />
      </el-form-item>
      <el-divider>附件</el-divider>
      <el-form-item label="附件">
        <file-upload v-model="form.storageBlobDTOs" />
      </el-form-item>
    </el-form>
    <div class="text-center">
      <el-button type="primary" @click="handleSubmit">提交</el-button>
      <el-button @click="handleCancel">取消</el-button>
    </div>
  </div>
</template>
```
```js
data() {
  return {
    form: {
      storageBlobDTOs: [],
      storageBlobVOs: [],
      unqualifiedId: null,
      disposalMethod: null,
    },
    query: {
      pageNum: 1,
      pageSize: 10,
      status: null,
      projectName: '',
      orderNo: '',
    rules: {
      unqualifiedId: [{ required: true, message: '请选择关联不合格品', trigger: 'change' }],
      disposalMethod: [{ required: true, message: '请选择处置方式', trigger: 'change' }],
    },
    statusMap: { 0: '草稿', 1: '待审批', 2: '审批中', 3: '已完成', 4: '已驳回' },
    disposalMethodMap: { 1: '让步接收', 2: '厂内维修', 3: '返厂维修', 4: '换货', 5: '退货', 6: '报废' },
    unqualifiedProcessMap: { 1: '来料', 2: '制程', 3: '成品' },
    unqualifiedList: [],
  }
},
mounted() {
  // 加载待处理的不合格品列表
  loadUnqualifiedList({ inspectState: 0 }).then(res => this.unqualifiedList = res.rows);
  if (this.$route.query.id) {
    getDetail(this.$route.query.id).then(res => this.form = res.data);
  }
},
methods: {
  handleSubmit() {
    this.$refs.form.validate(valid => {
      if (!valid) return;
      const api = this.form.id ? updateOrder : saveOrder;
      api(this.form).then(() => {
        this.$message.success(this.form.id ? '修改成功' : '新增成功');
        this.$router.back();
      });
    });
  },
  handleCancel() { this.$router.back(); },
}
```
### 4. API 调用
## 处置方式说明
```js
import request from '@/utils/request'
| 值 | 含义 | 系统自动行为 |
|----|------|------------|
| 1 | 让步接收 | 无自动操作,需人工后续处理 |
| 2 | 厂内维修 | **自动创建返修生产订单**(FG 开头 NPS 编号),克隆原工序路线 |
| 3 | 返厂维修 | **自动创建返修生产订单**(FG 开头 NPS 编号),克隆原工序路线 |
| 4 | 换货 | 无自动操作 |
| 5 | 退货 | 无自动操作 |
| 6 | 报废 | 无自动操作(库存扣减由旧模块 `/quality/qualityUnqualified/deal` 处理) |
// 分页查询
export function listPage(query) {
  return request({ url: '/qualityUnqualifiedOrder/listPage', method: 'get', params: query })
}
## 状态流转
// 详情
export function getDetail(id) {
  return request({ url: `/qualityUnqualifiedOrder/${id}`, method: 'get' })
}
// 新增
export function save(data) {
  return request({ url: '/qualityUnqualifiedOrder/save', method: 'post', data })
}
// 修改
export function update(data) {
  return request({ url: '/qualityUnqualifiedOrder/update', method: 'put', data })
}
// 删除
export function remove(ids) {
  return request({ url: '/qualityUnqualifiedOrder/delete', method: 'delete', data: ids })
}
```
质检自动创建 ──> 0(草稿) ──> 调用 /deal 选择处置方式 ──> 3(已完成)
手动新增(没选处置方式) ──> 0(草稿) ──> 调用 /deal ──> 3(已完成)
手动新增(选了处置方式) ──> 3(已完成)
```
## 注意事项
- 处理单编号 `orderNo` 由后端自动生成(前缀 "BHG" + 日期 + 3位自增序号),前端无需传入
- 新增时 `status` 默认为 0(草稿),无需前端设置
- 删除为逻辑删除,通过 `deleted` 字段标记
- 附件上传使用系统已有的文件上传组件,将返回的临时文件ID通过 `storageBlobDTOs` 传入
- 不合格品处理单可关联 `quality_unqualified` 表的记录(通过 `unqualifiedId` 字段)
- 检验单提交时,不合格数量 > 0 会自动创建处理单(状态为草稿),**无需手动新增**
- 手动新增处理单时,选了处置方式直接完成,没选则保持草稿
- 草稿状态的处理单通过 `/qualityUnqualifiedOrder/deal` 接口补充处置方式
- 旧的不合格管理(`/quality/qualityUnqualified`)继续用于不合格品首次记录和列表查看
- 处置操作统一使用本模块(`/qualityUnqualifiedOrder`)
- 选择"厂内维修"或"返厂维修"时,系统自动创建返修生产订单,无需手动操作
- 返修生产订单的 `disposalMethod` 字段标记了处置方式,可在生产订单列表区分普通订单和返修订单
- 处理单编号自动生成,前缀为 `BHG`
- 附件通过 `storageBlobDTOs` 字段上传,查询时返回 `storageBlobVOs`