吴羡
5 天以前 28c36a0fa33955174d87510353ff06cbecaa7a89
成品下单支持批量下单,检验委托单按批次合并展示/编辑/删除/导出
已修改3个文件
842 ■■■■■ 文件已修改
src/api/business/add.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CNAS/process/demand/index.vue 645 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/business/productOrder/components/addOrder.vue 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/business/add.js
@@ -40,6 +40,14 @@
    data: query
  })
}
// 批量添加新聚检验下单数据
export function addBatchNewJuInsOrder(query) {
  return request({
    url: '/insOrder/addBatchNewJuInsOrder',
    method: 'post',
    data: query
  })
}
// 审核检验单机进行状态修改
export function upInsOrderOfState(query) {
  return request({
src/views/CNAS/process/demand/index.vue
@@ -28,10 +28,13 @@
      <el-table v-loading="tableListLoading" :data="tableList"
                height="630" border>
        <el-table-column align="center" label="序号" type="index"></el-table-column>
        <el-table-column label="试样名称" prop="sampleName" show-overflow-tooltip></el-table-column>
        <el-table-column label="试样名称" prop="sampleName" show-overflow-tooltip>
          <template #default="scope">
            <span>{{ scope.row.sampleName }}<template v-if="scope.row.detailCount > 1"> 等{{ scope.row.detailCount }}只</template></span>
          </template>
        </el-table-column>
        <el-table-column label="委托编号" prop="entrustCode" show-overflow-tooltip></el-table-column>
        <el-table-column label="委托时间" prop="commissionDate" show-overflow-tooltip></el-table-column>
        <el-table-column label="型号" prop="modelNo" show-overflow-tooltip></el-table-column>
        <el-table-column label="委托单位" prop="commissionUnit" show-overflow-tooltip></el-table-column>
        <el-table-column label="生产单位" prop="production" show-overflow-tooltip></el-table-column>
        <el-table-column label="委托人" prop="commissionUser"></el-table-column>
@@ -40,7 +43,7 @@
        <el-table-column label="是否留样" prop="isLeave">
          <template #default="scope">
            <span v-if="scope.row.isLeave === 1">是</span>
            <span v-if="scope.row.isLeave === 0">否</span>
            <span v-else-if="scope.row.isLeave != null">否</span>
          </template>
        </el-table-column>
        <el-table-column label="样品处理方式" prop="processing" width="150">
@@ -70,292 +73,255 @@
      </el-pagination>
    </div>
    <el-dialog :class="{ downPdf: title == '下载' }" :close-on-click-modal="false" :close-on-press-escape="false"
      :modal="title != '下载'" :title="title" v-model="detailDialogVisible" top="20px" width="1200px">
      <div style="max-height: 75vh;overflow-y: auto;">
      :modal="title != '下载'" :title="title" v-model="detailDialogVisible" top="20px" width="1080px">
      <div style="max-height: 78vh;overflow-y: auto;">
        <div id="dialogBody">
          <table border="1" cellpadding="10" class="tables heads" style="border: 1px dashed black;width: 100%">
            <tr>
              <td rowspan="2">
              </td>
              <td>
                <p>记录名称:检验委托单</p>
              </td>
              <td>
                <p>保存期限:6年</p>
              </td>
            </tr>
            <tr>
              <td>
                <p>记录编号:</p>
              </td>
              <td>
                <p>归档部门:综合室</p>
              </td>
            </tr>
          </table>
          <h4 style="display: flex;align-items: center;flex-direction: column;justify-content: center;">
            <span style="font-size: 28px;">检 验 委 托 单</span>
            <span style="font-size: 28px;">客 户 检 测 委 托 书</span>
          </h4>
          <p v-if="operationType !== 'view'" style="margin-left: 560px;display: flex;align-items: center">
            <span style="width: 100px">委托编号:</span>
            <el-input v-model="currentInfo.entrustCode" clearable size="small"></el-input>
          </p>
          <p v-if="operationType === 'view'" style="margin-top: 16px;margin-left: 600px;">委托编号:{{
            currentInfo.entrustCode }}
          </p>
          <table border="1" cellpadding="10" class="tables" style="width: 100%">
          <p style="margin: 0 0 8px 0;text-align: right;" v-if="operationType === 'view'">委托编号:{{ entrustCodeText }}</p>
          <div style="margin-bottom: 8px;text-align: right;" v-if="operationType !== 'view'">
            <el-button size="small" type="primary" @click="addOrderDetailList">添加样品行</el-button>
          </div>
          <div style="overflow-x: auto;">
          <table border="1" class="tables">
            <colgroup>
              <col style="width: 6%" />
              <col style="width: 9%" />
              <col style="width: 9%" />
              <col style="width: 10%" />
              <col style="width: 6%" />
              <col style="width: 7%" />
              <col style="width: 4%" />
              <col style="width: 4%" />
              <col style="width: 7%" />
              <col style="width: 21%" />
              <col style="width: 17%" />
            </colgroup>
            <tr>
              <td colspan="2">
                <p>试样名称</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.sampleName" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.sampleName }}</td>
              <td>
                <p>委托时间</p>
              </td>
              <td v-if="operationType !== 'view'">
                <el-date-picker v-model="currentInfo.commissionDate" clearable format="YYYY-MM-DD" placeholder="选择日期"
                  size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD">
                </el-date-picker>
              </td>
              <td v-if="operationType === 'view'">{{ currentInfo.commissionDate }}</td>
            </tr>
            <tr>
              <td colspan="2">
                <p>型 号</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.modelNo" clearable
              <td rowspan="5">委托方</td>
              <td>委托方单位</td>
              <td colspan="6">
                <el-input v-if="operationType !== 'view'" v-model="currentInfo.commissionUnit" clearable
                  size="small"></el-input>
                <span v-else>{{ currentInfo.commissionUnit }}</span>
              </td>
              <td v-if="operationType === 'view'">{{ currentInfo.modelNo }}</td>
              <td>
                <p>委托单位</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.commissionUnit" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.commissionUnit }}</td>
              <td>委托编号</td>
              <td colspan="2">详见样品信息表</td>
            </tr>
            <tr>
              <td>生产单位</td>
              <td colspan="6">
                <el-input v-if="operationType !== 'view'" v-model="currentInfo.production" clearable
                  size="small"></el-input>
                <span v-else>{{ currentInfo.production }}</span>
              </td>
              <td>是否留样</td>
              <td colspan="2">
                <p>生产单位</p>
                <el-radio-group v-if="operationType !== 'view'" v-model="currentInfo.isLeave">
                  <el-radio :value="1">是</el-radio>
                  <el-radio :value="2">否</el-radio>
                </el-radio-group>
                <span v-else>{{ currentInfo.isLeave == null ? '' : (currentInfo.isLeave === 1 ? '是' : '否') }}</span>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.production" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.production }}</td>
              <td>
                <p>委托人</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.commissionUser" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.commissionUser }}</td>
            </tr>
            <tr>
              <td colspan="2">
                <p>样品数量</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.quantity" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.quantity }}</td>
              <td>
                <p>样品状态</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.sampleStatus" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{
                insStateList.find(m => m.value == currentInfo.sampleStatus) ? insStateList.find(m => m.value == currentInfo.sampleStatus).label:'/'
                }}</td>
              <td>项目名称</td>
              <td colspan="9" style="text-align: center;">{{ projectName }}</td>
            </tr>
            <tr>
              <td>样品类别</td>
              <td colspan="6">详见样品信息表</td>
              <td>检测来源</td>
              <td colspan="2">
                <p>是否留样</p>
                <el-radio-group v-if="operationType !== 'view'" v-model="currentInfo.sampleSource">
                  <el-radio :value="1">送样</el-radio>
                  <el-radio :value="2">采样</el-radio>
                </el-radio-group>
                <span v-else>{{ sampleSourceText }}</span>
              </td>
              <td v-if="operationType !== 'view'">
                <el-radio-group v-model="currentInfo.isLeave">
            </tr>
            <tr>
              <td>送样时间</td>
              <td colspan="6">
                <el-date-picker v-if="operationType !== 'view'" v-model="currentInfo.commissionDate" clearable
                  format="YYYY-MM-DD" placeholder="选择日期" size="small" style="width: 100%" type="date"
                  value-format="YYYY-MM-DD">
                </el-date-picker>
                <span v-else>{{ currentInfo.commissionDate }}</span>
              </td>
              <td>送样人</td>
              <td colspan="2">
                <el-input v-if="operationType !== 'view'" v-model="currentInfo.commissionUser" clearable
                  size="small"></el-input>
                <span v-else>{{ currentInfo.commissionUser }}</span>
              </td>
            </tr>
            <tr>
              <td :rowspan="2 + detailCount">样品信息</td>
              <td colspan="10">样品和检测信息</td>
            </tr>
            <tr>
              <td>样品名称</td>
              <td>样品编号</td>
              <td>检测项目</td>
              <td>样品数量</td>
              <td>样品状态</td>
              <td colspan="3">检测依据</td>
              <td>备注信息(详细信息见证明附件)</td>
              <td>委托编号</td>
            </tr>
            <tr v-for="(item, index) in (currentInfo.orderDetailList || [])" :key="index">
              <td>
                <el-input v-if="operationType !== 'view'" v-model="item.sampleName" clearable
                  size="small"></el-input>
                <span v-else>{{ item.sampleName }}</span>
              </td>
              <td>
                <el-input v-if="operationType !== 'view'" v-model="item.sampleNumber" clearable
                  size="small"></el-input>
                <span v-else>{{ item.sampleNumber }}</span>
              </td>
              <td>
                <el-input v-if="operationType !== 'view'" v-model="item.testItem" clearable size="small"></el-input>
                <span v-else>{{ item.testItem }}</span>
              </td>
              <td>
                <el-input v-if="operationType !== 'view'" v-model="item.quantity" clearable
                  size="small"></el-input>
                <span v-else>{{ item.quantity }}</span>
              </td>
              <td>
                <el-input v-if="operationType !== 'view'" v-model="item.sampleStatus" clearable
                  size="small"></el-input>
                <span v-else>{{ item.sampleStatus }}</span>
              </td>
              <td colspan="3">
                <el-input v-if="operationType !== 'view'" v-model="item.testStandard" clearable
                  size="small"></el-input>
                <span v-else>{{ item.testStandard }}</span>
              </td>
              <td>
                <el-input v-if="operationType !== 'view'" v-model="item.remark" clearable size="small"></el-input>
                <span v-else>{{ item.remark }}</span>
              </td>
              <td>
                <div>{{ detailEntrustCodes[index] }}</div>
                <el-button v-if="operationType !== 'view'" link type="danger" size="small"
                  @click="removeOrderDetailList(index)">删除本行</el-button>
              </td>
            </tr>
            <tr>
              <td rowspan="4">委托要求</td>
              <td>分包内容</td>
              <td colspan="9">
                <template v-if="operationType !== 'view'">
                  <el-radio-group v-model="currentInfo.subcontractType">
                    <el-radio :value="1">有</el-radio>
                    <el-radio :value="0">无</el-radio>
                  </el-radio-group>
                  <span v-if="currentInfo.subcontractType === 1" style="margin-left: 8px;">
                    分包单位信息:
                    <el-input v-model="currentInfo.subcontractCompany" clearable size="small"
                      style="width: 260px;"></el-input>
                  </span>
                </template>
                <span v-else>{{ subcontractText }}</span>
              </td>
            </tr>
            <tr>
              <td>样品处置</td>
              <td colspan="3">
                <el-radio-group v-if="operationType !== 'view'" v-model="currentInfo.sampleDisposal">
                  <el-radio :value="1">委托方取回</el-radio>
                  <el-radio :value="2">检测方处置</el-radio>
                </el-radio-group>
                <span v-else>{{ sampleDisposalText }}</span>
              </td>
              <td colspan="2">对结果评价</td>
              <td colspan="4">
                <el-radio-group v-if="operationType !== 'view'" v-model="currentInfo.resultEvaluation">
                  <el-radio :value="1">是</el-radio>
                  <el-radio :value="0">否</el-radio>
                </el-radio-group>
                <span v-else>{{ resultEvaluationText }}</span>
              </td>
              <td v-if="operationType === 'view'">
                <span v-if="currentInfo.isLeave == 1">是</span>
                <span v-else>否</span>
            </tr>
            <tr>
              <td>报告交付方式</td>
              <td colspan="9">
                <template v-if="operationType !== 'view'">
                  <el-radio-group v-model="currentInfo.reportDelivery">
                    <el-radio :value="1">自取</el-radio>
                    <el-radio :value="2">快递</el-radio>
                    <el-radio :value="3">电子传送</el-radio>
                  </el-radio-group>
                  <template v-if="currentInfo.reportDelivery === 2">
                    <div style="margin-top: 6px;">
                      报告寄送地址:
                      <el-input v-model="currentInfo.reportAddress" clearable size="small"
                        style="width: 360px;"></el-input>
                    </div>
                    <div style="margin-top: 6px;">
                      收件人及电话:
                      <el-input v-model="currentInfo.reportReceiver" clearable size="small"
                        style="width: 260px;"></el-input>
                    </div>
                  </template>
                </template>
                <span v-else>{{ reportDeliveryText }}</span>
              </td>
              <td>
                <p>样品处理方式</p>
            </tr>
            <tr>
              <td>委托方承诺</td>
              <td colspan="9" style="line-height: 1.8;">
                <div>我方保证对所提供的一切资料、实物真实性负责,并提供必要的合作,按规定支付检验费。</div>
                <div style="display: flex;align-items: center;flex-wrap: wrap;gap: 8px 28px;margin-top: 4px;">
                  <span>委托人:________</span>
                  <span>日期:________</span>
                  <span>联系电话:________</span>
                </div>
              </td>
              <td v-if="operationType !== 'view'">
                <el-radio-group v-model="currentInfo.processing">
                  <el-radio :value="0">委托单位取回</el-radio>
                  <el-radio :value="1">实验室处理</el-radio>
            </tr>
            <tr>
              <td rowspan="3">委托接收</td>
              <td>样品状态</td>
              <td colspan="9">
                <el-radio-group v-if="operationType !== 'view'" v-model="currentInfo.receiveStatus">
                  <el-radio :value="1">符合要求</el-radio>
                  <el-radio :value="2">有缺陷,但不影响检测</el-radio>
                  <el-radio :value="3">不符合检测要求</el-radio>
                </el-radio-group>
              </td>
              <td v-if="operationType === 'view'">
                <span v-if="currentInfo.processing == 0">委托单位取回</span>
                <span v-else>实验室处理</span>
                <span v-else>{{ receiveStatusText }}</span>
              </td>
            </tr>
            <tr>
              <td colspan="2">
                <p>约定完成时间(报告日期)</p>
              </td>
              <td v-if="operationType !== 'view'">
                <el-date-picker v-model="currentInfo.appointed" clearable format="YYYY-MM-DD" placeholder="选择日期"
                  size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD">
                </el-date-picker>
              </td>
              <td v-if="operationType === 'view'">{{ currentInfo.appointed }}</td>
              <td>
                <p>报告发送方式</p>
              </td>
              <td v-if="operationType !== 'view'">
                <el-radio-group v-model="currentInfo.send">
                  <el-radio :value="1">自取</el-radio>
                  <el-radio :value="0">其他</el-radio>
              <td>检测费</td>
              <td colspan="9">
                <el-radio-group v-if="operationType !== 'view'" v-model="currentInfo.feeStatus">
                  <el-radio :value="1">已收</el-radio>
                  <el-radio :value="2">未收</el-radio>
                  <el-radio :value="3">预收</el-radio>
                </el-radio-group>
              </td>
              <td v-if="operationType === 'view'">
                <span v-if="currentInfo.send == 1">自取</span>
                <span v-else>其他</span>
              </td>
            </tr>
            <el-button size="small" type="primary" @click="addOrderDetailList"
              v-if="operationType !== 'view'">添加</el-button>
            <tr>
              <td>
                <p>序号</p>
              </td>
              <td>
                <p>样品编号</p>
              </td>
              <td>
                <p>试验项目</p>
              </td>
              <td>
                <p>检验依据</p>
              </td>
              <td>
                <p>备注</p>
              </td>
            </tr>
            <tr v-for="(item, index) in currentInfo.orderDetailList" :key="index">
              <td>{{ index + 1 }}</td>
              <td v-if="operationType !== 'view'"><el-input v-model="item.sampleNumber" clearable
                  size="small"></el-input>
              </td>
              <td v-if="operationType === 'view'">{{ item.sampleNumber }}</td>
              <td v-if="operationType !== 'view'"><el-input v-model="item.testItem" clearable size="small"></el-input>
              </td>
              <td v-if="operationType === 'view'">{{ item.testItem }}</td>
              <td v-if="operationType !== 'view'"><el-input v-model="item.testStandard" clearable
                  size="small"></el-input>
              </td>
              <td v-if="operationType === 'view'">{{ item.testStandard }}</td>
              <td v-if="operationType !== 'view'"><el-input v-model="item.remark" clearable size="small"></el-input>
              </td>
              <td v-if="operationType === 'view'">{{ item.remark }}</td>
            </tr>
            <tr>
              <td colspan="2">
                <p>判定规则</p>
              </td>
              <td v-if="operationType !== 'view'" colspan="3">
                <el-radio-group v-model="currentInfo.criterionRule">
                  <el-radio :value="0">不考虑不确定度</el-radio>
                  <el-radio :value="1">考虑不确定度</el-radio>
                </el-radio-group>
                <span v-if="currentInfo.criterionRule === 1"><el-input v-model="currentInfo.criterionRuleRemark"
                    clearable size="small" style="width: 60px"></el-input>%</span>
              </td>
              <td v-if="operationType === 'view'" colspan="3">
                <span v-if="currentInfo.criterionRule === 0">不考虑不确定度</span>
                <span v-if="currentInfo.criterionRule === 1">考虑不确定度</span>
                <span v-if="currentInfo.criterionRule === 1">{{ currentInfo.criterionRuleRemark + '%' }}</span>
                <span v-else>{{ feeStatusText }}</span>
              </td>
            </tr>
            <tr>
              <td colspan="2">
                <p>委托人签名</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.commissionUser" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">
                {{ currentInfo.commissionUser }}
              </td>
              <td>
                <p>委托日期</p>
              </td>
              <td v-if="operationType !== 'view'">
                <el-date-picker v-model="currentInfo.commissionDate" clearable format="YYYY-MM-DD" placeholder="选择日期"
                  size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD">
                </el-date-picker>
              </td>
              <td v-if="operationType === 'view'">{{ currentInfo.commissionDate }}</td>
            </tr>
            <tr>
              <td colspan="2">
                <p>委托人联系电话</p>
              </td>
              <td v-if="operationType !== 'view'" colspan="3"><el-input v-model="currentInfo.commissionPhone" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'" colspan="3">{{ currentInfo.commissionPhone }}</td>
            </tr>
            <tr>
              <td colspan="2">
                <p>综合室签名</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.generalOfficeUser" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.generalOfficeUser }}</td>
              <td>
                <p>接收日期</p>
              </td>
              <td v-if="operationType !== 'view'">
                <el-date-picker v-model="currentInfo.receiptData" clearable format="YYYY-MM-DD" placeholder="选择日期"
                  size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD">
                </el-date-picker>
              </td>
              <td v-if="operationType === 'view'">{{ currentInfo.receiptData }}</td>
            </tr>
            <tr>
              <td colspan="2">
                <p>领样员签名</p>
              </td>
              <td v-if="operationType !== 'view'"><el-input v-model="currentInfo.sampleTakerUser" clearable
                  size="small"></el-input></td>
              <td v-if="operationType === 'view'">{{ currentInfo.sampleTakerUser }}</td>
              <td>
                <p>领样日期</p>
              </td>
              <td v-if="operationType !== 'view'">
                <el-date-picker v-model="currentInfo.sampleData" clearable format="YYYY-MM-DD" placeholder="选择日期"
                  size="small" style="width: 100%" type="date" value-format="YYYY-MM-DD">
                </el-date-picker>
              </td>
              <td v-if="operationType === 'view'">{{ currentInfo.sampleData }}</td>
            </tr>
            <tr>
              <td colspan="2" rowspan="3">
                <p>检测机构信息</p>
              </td>
              <td colspan="3">
                <p>新聚</p>
              <td>检测方承诺</td>
              <td colspan="9" style="line-height: 1.8;">
                <div>本公司保证检测工作的公正性,对检测数据负责,并对委托方提供的技术资料和样品保密。</div>
                <div style="margin-top: 4px;">业务受理:________&nbsp;&nbsp;&nbsp;&nbsp;日期:________&nbsp;&nbsp;&nbsp;&nbsp;联系电话:________</div>
              </td>
            </tr>
            <tr>
              <td colspan="3">
                <p>地址:江苏省南通市经济技术开发区新开南路 19 号</p>
              </td>
            </tr>
            <tr>
              <td colspan="3">
                <p>电话:0513-89059043</p>
              </td>
              <td colspan="2">委托说明</td>
              <td colspan="9">委托单为双方检测业务契约,请委托单位认真填写,要求内容完整,字迹清晰,委托单位和检测单位各持一份。本次检测仅对所提供的样品负责。</td>
            </tr>
          </table>
          <p style="margin-top: 10px;margin-left: 20px;">注:本检验委托单一式二份,一份综合室归档,一份委托单位留存。</p>
          </div>
        </div>
      </div>
      <template #footer><span v-if="operationType !== 'view'"  class="dialog-footer">
      <template #footer><span v-if="operationType !== 'view'" class="dialog-footer">
        <el-button @click="detailDialogVisible = false">取 消</el-button>
        <el-button v-if="operationType === 'edit'" :loading="buttonLoading" type="primary" @click="handleEdit">确
          定</el-button>
@@ -366,7 +332,7 @@
        <el-button :loading="outLoading" plain type="primary" @click="orderReportDown">下载委托单</el-button>
        <el-button :loading="outLoading" plain type="primary" @click="orderFormDown">下载委托报告</el-button>
      </span>
      <template #footer><span  class="dialog-footer">
      <template #footer><span class="dialog-footer">
        <el-button @click="downloadDialog = false">取 消</el-button>
      </span></template>
    </el-dialog>
@@ -453,6 +419,75 @@
  computed: {
    action() {
      return this.javaApi + '/inspectionOrder/uploadInspectionOrderFile'
    },
    detailCount() {
      return (this.currentInfo.orderDetailList || []).length
    },
    detailEntrustCodes() {
      const rows = this.currentInfo.orderDetailList || []
      const code = this.currentInfo.entrustCode || ''
      const dash = code.lastIndexOf('-')
      const prefix = !code ? '' : (dash < 0 ? code + '-' : code.slice(0, dash + 1))
      const bases = rows.map(item => item.entrustCode || this.rowEntrustCode(item))
      const counts = {}
      bases.forEach(base => { counts[base] = (counts[base] || 0) + 1 })
      const used = new Set()
      return bases.map((base, index) => {
        let candidate = base
        if (!base || counts[base] > 1 || used.has(candidate)) {
          let seq = index + 1
          candidate = prefix + String(seq).padStart(2, '0')
          while (used.has(candidate)) {
            seq += rows.length
            candidate = prefix + String(seq).padStart(2, '0')
          }
        }
        used.add(candidate)
        return candidate
      })
    },
    entrustCodeText() {
      const codes = this.detailEntrustCodes.filter(Boolean)
      if (codes.length > 1) {
        return `${codes[0]} ~ ${codes[codes.length - 1]}`
      }
      return this.currentInfo.entrustCode
    },
    projectName() {
      return this.detailCount + '个样品'
    },
    subcontractText() {
      const has = this.currentInfo.subcontractType === 1
      const company = this.currentInfo.subcontractCompany || ''
      return `${has ? '☑有' : '□有'}(分包单位信息:${company})  ${has ? '□无' : '☑无'}`
    },
    sampleDisposalText() {
      const value = this.currentInfo.sampleDisposal
      return `${value === 1 ? '☑委托方取回' : '□委托方取回'}、${value === 2 ? '☑检测方处置' : '□检测方处置'}`
    },
    resultEvaluationText() {
      const value = this.currentInfo.resultEvaluation
      return `${value === 1 ? '☑是' : '□是'}  ${value === 0 ? '☑否' : '□否'}`
    },
    reportDeliveryText() {
      const value = this.currentInfo.reportDelivery
      let text = `${value === 1 ? '☑自取' : '□自取'};${value === 2 ? '☑快递' : '□快递'};${value === 3 ? '☑电子传送' : '□电子传送'}`
      if (value === 2) {
        text += `;报告寄送地址:${this.currentInfo.reportAddress || ''} 收件人及电话:${this.currentInfo.reportReceiver || ''}`
      }
      return text
    },
    sampleSourceText() {
      const value = this.currentInfo.sampleSource
      return `${value === 1 ? '☑送样' : '□送样'};${value === 2 ? '☑采样' : '□采样'}`
    },
    receiveStatusText() {
      const value = this.currentInfo.receiveStatus
      return `${value === 1 ? '☑符合要求' : '□符合要求'};${value === 2 ? '☑有缺陷,但不影响检测' : '□有缺陷,但不影响检测'};${value === 3 ? '☑不符合检测要求' : '□不符合检测要求'}`
    },
    feeStatusText() {
      const value = this.currentInfo.feeStatus
      return `${value === 1 ? '☑已收' : '□已收'};${value === 2 ? '☑未收' : '□未收'};${value === 3 ? '☑预收' : '□预收'}`
    }
  },
  methods: {
@@ -460,13 +495,32 @@
      if (this.currentInfo.orderDetailList == null) {
        this.currentInfo.orderDetailList = []
      }
      this.currentInfo.orderDetailList.push({
      const rows = this.currentInfo.orderDetailList
      const last = rows.length ? rows[rows.length - 1] : {}
      rows.push({
        sampleName: last.sampleName || this.currentInfo.sampleName || '',
        sampleNumber: '',
        testItem: '',
        quantity: last.quantity || this.currentInfo.quantity || '',
        sampleStatus: last.sampleStatus || this.currentInfo.sampleStatus || '',
        testStandard: '',
        standardMethodList: '',
        remark: '',
      })
    },
    removeOrderDetailList(index) {
      this.currentInfo.orderDetailList.splice(index, 1)
    },
    // 委托编号按样品编号后两位生成,与导出 Word 规则一致
    rowEntrustCode(item) {
      const code = this.currentInfo.entrustCode || ''
      const sampleNumber = (item.sampleNumber || '').trim()
      if (!code || !sampleNumber) {
        return code
      }
      const suffix = sampleNumber.length >= 2 ? sampleNumber.slice(-2) : sampleNumber
      const index = code.lastIndexOf('-')
      return index < 0 ? code : code.slice(0, index + 1) + suffix
    },
    // 查询列表
    refreshTable() {
@@ -507,10 +561,19 @@
    },
    // 提交修改
    handleEdit() {
      if (!this.currentInfo.orderDetailList || this.currentInfo.orderDetailList.length === 0) {
        this.$message.warning('请至少添加一个样品行')
        return
      }
      const blankRow = this.currentInfo.orderDetailList.findIndex(item => !(item.sampleNumber || '').trim())
      if (blankRow >= 0) {
        this.$message.warning(`第${blankRow + 1}行样品编号不能为空`)
        return
      }
      this.buttonLoading = true
      updateInspectionOrder(this.currentInfo).then(res => {
        this.buttonLoading = false
        this.$message.success('新增成功')
        this.$message.success('保存成功')
        this.detailDialogVisible = false
        this.refreshTable()
      }).catch(err => {
@@ -520,9 +583,15 @@
    // 打开编辑弹框
    goUpdate(row) {
      this.operationType = 'edit'
      getInspectionOrderOne({ inspectionOrderId: row.inspectionOrderId }).then(res => {
      getInspectionOrderOne({
        inspectionOrderId: row.inspectionOrderId,
        batchNo: row.batchNo || undefined
      }).then(res => {
        this.currentInfo = res.data
        this.title = '编辑检验委托单';
        if (!this.currentInfo.orderDetailList || this.currentInfo.orderDetailList.length === 0) {
          this.addOrderDetailList()
        }
        this.title = '编辑客户检测委托书';
        this.detailDialogVisible = true
      }).catch(err => {
        console.log('err----', err)
@@ -531,9 +600,12 @@
    // 查看
    handleLook(row) {
      this.operationType = 'view'
      getInspectionOrderOne({ inspectionOrderId: row.inspectionOrderId }).then(res => {
      getInspectionOrderOne({
        inspectionOrderId: row.inspectionOrderId,
        batchNo: row.batchNo || undefined
      }).then(res => {
        this.currentInfo = res.data
        this.title = '查看检验委托单';
        this.title = '查看客户检测委托书';
        this.detailDialogVisible = true
      }).catch(err => {
        console.log('err----', err)
@@ -541,12 +613,18 @@
    },
    // 删除
    deleteOrder(row) {
      this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
      const isBatch = row.memberCount > 1
      this.$confirm(isBatch
        ? `该委托单为批量委托,共${row.memberCount}个样品,删除将整批删除,是否继续?`
        : '此操作将永久删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delInspectionOrder({ inspectionOrderId: row.inspectionOrderId }).then(res => {
        delInspectionOrder({
          inspectionOrderId: row.inspectionOrderId,
          batchNo: row.batchNo || undefined
        }).then(res => {
          this.$message.success('删除成功!');
          this.refreshTable();
        });
@@ -565,6 +643,10 @@
    // 委托单下载
    orderFormDown() {
      let url = this.download.fileUrl;
      if (!url) {
        this.$message.warning('该委托单暂无委托报告文件,请先上传');
        return;
      }
      const link = document.createElement('a');
      link.href = this.javaApi + url;
      link.target = '_blank';
@@ -574,10 +656,13 @@
    // 委托报告下载
    orderReportDown() {
      this.outLoading = true;
      exportInspectionOrder({ inspectionOrderId: this.download.inspectionOrderId }).then(res => {
      exportInspectionOrder({
        inspectionOrderId: this.download.inspectionOrderId,
        batchNo: this.download.batchNo || undefined
      }).then(res => {
        this.outLoading = false;
        const blob = new Blob([res], { type: 'application/octet-stream' });
        this.$download.saveAs(blob, '检验委托单.docx')
        this.$download.saveAs(blob, '客户检测委托书.docx')
      }).catch(err => {
        this.outLoading = false;
@@ -621,4 +706,36 @@
}
</script>
<style scoped></style>
<style scoped>
.tables {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: 14px;
  color: #303133;
}
.tables td {
  padding: 6px 8px;
  vertical-align: middle;
  word-break: break-all;
  line-height: 1.6;
}
.tables :deep(.el-input),
.tables :deep(.el-date-editor) {
  width: 100%;
}
.tables :deep(.el-input__inner) {
  font-size: 14px;
}
.tables :deep(.el-radio-group) {
  flex-wrap: wrap;
}
.tables :deep(.el-radio) {
  margin-right: 12px;
}
</style>
src/views/business/productOrder/components/addOrder.vue
@@ -225,6 +225,34 @@
            </el-col>
          </el-row>
        </el-form>
        <div v-if="batchOrderMode" class="batch-sample">
          <div class="batch-sample__header">
            <div>
              <div class="batch-sample__title">批量样品</div>
              <div class="batch-sample__tip">先在上方填写一个样品的检测依据、样品名称、样品编号、样品数量、样品外观,点击“添加样品”加入列表;提交后每个样品生成一张委托单,检验委托单中合并为一张委托书。</div>
            </div>
            <el-button type="primary" plain size="small" @click="addBatchSample">添加样品</el-button>
          </div>
          <el-table :data="batchSampleList" size="small" border class="batch-sample__table"
                    empty-text="暂未添加样品。未添加时按上方单个样品信息下单">
            <el-table-column type="index" label="序号" width="60" align="center"/>
            <el-table-column prop="sampleView" label="样品名称" min-width="120" show-overflow-tooltip/>
            <el-table-column prop="sampleCode" label="样品编号" min-width="120" show-overflow-tooltip/>
            <el-table-column label="检测依据" min-width="160" show-overflow-tooltip>
              <template #default="scope">{{ scope.row.sample }}</template>
            </el-table-column>
            <el-table-column prop="testQuantity" label="样品数量" width="110" align="center"/>
            <el-table-column prop="sampleStatus" label="样品外观" min-width="110" show-overflow-tooltip/>
            <el-table-column label="原始记录模板" min-width="180" show-overflow-tooltip>
              <template #default="scope">{{ batchTemplateNames(scope.row) }}</template>
            </el-table-column>
            <el-table-column label="操作" width="80" align="center">
              <template #default="scope">
                <el-button link type="danger" size="small" @click="removeBatchSample(scope.$index)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
        <el-form v-if="false" ref="addObj" :inline="true" :model="addObj" :rules="addObjRules" label-width="108px"
                 label-position="right">
          <el-row>
@@ -837,6 +865,7 @@
  selectStandardTreeList2, getFileList, delFile
} from "@/api/business/rawMaterialOrder";
import {
  addBatchNewJuInsOrder,
  addInsOrder, addInsOrderTemplate, delInsOrderTemplate,
  getQuarterOnOrder, judgeNotSpotCheckOrder, selectInsOrderTemplateById,
  updateInsOrder,
@@ -876,6 +905,10 @@
    newJuLaboratoryList() {
      return (this.dict.type.sys_sub_lab || []).filter(item => item.label === '新聚')
    },
    // 仅新增委托单时支持批量样品,编辑/查看历史单仍按单样品处理
    batchOrderMode() {
      return this.active == 1 && !this.isEdit
    },
  },
  dicts: ['check_type1', 'urgency_level', 'form_type', 'sample_status_list', 'sys_sub_lab'],
  data() {
@@ -890,6 +923,7 @@
      fileList: [],
      deleteFileIds: [],
      boundTemplateList: [],
      batchSampleList: [],
      templateBindingLoading: false,
      sampleSelectionList: [],//样品表格选中数据
      editTable: [],
@@ -1152,7 +1186,7 @@
      this.orderLoadVersion++
      const defaults = this.$options.data.call(this)
      const fields = ['addObj', 'sample', 'sampleCode', 'fileList', 'deleteFileIds',
        'boundTemplateList', 'sampleSelectionList', 'editTable', 'sampleList',
        'boundTemplateList', 'batchSampleList', 'sampleSelectionList', 'editTable', 'sampleList',
        'productList', 'productList0', 'productIds', 'sampleIds', 'selectTree',
        'selectTreeNode', 'selectiveEcho', 'specialStandardMethod', 'model',
        'standardMethodListId', 'template', 'templates', 'addObj1', 'totalArr',
@@ -1470,6 +1504,10 @@
        this.$refs.newJuOrder.validateField('sampleDate');
        return;
      }
      if (this.batchOrderMode && this.batchSampleList.length > 0) {
        this.saveBatchOrder()
        return
      }
      if (this.addObj.standardTreeId) {
        if (!this.addObj.sample || !this.addObj.company || !this.addObj.orderType || !this.addObj.testQuantity) {
          this.$message.error('请填写检测依据、委托单位、检验类别和样品数量');
@@ -1767,6 +1805,123 @@
          this.saveLoad = false
        })
      }
    },
    addBatchSample() {
      if (!this.addObj.standardTreeId) {
        this.$message.error('请选择检测依据')
        return
      }
      if (this.templateBindingLoading) {
        this.$message.warning('原始记录模板加载中,请稍候')
        return
      }
      if (this.boundTemplateList.length === 0) {
        this.$message.error('所选检测依据未绑定原始记录模板')
        return
      }
      const sampleCode = (this.sampleCode || '').trim()
      if (sampleCode.length < 2) {
        this.$message.error('请填写样品编号(至少2位)')
        return
      }
      if (!this.addObj.testQuantity) {
        this.$message.error('请填写样品数量')
        return
      }
      if (this.batchSampleList.some(item => item.sampleCode === sampleCode)) {
        this.$message.error('该样品编号已在批量列表中')
        return
      }
      this.batchSampleList.push({
        sampleCode,
        sampleView: this.addObj.sampleView || this.addObj.sample || '',
        testQuantity: this.addObj.testQuantity,
        sampleStatus: this.addObj.sampleStatus,
        sample: this.addObj.sample,
        standardTreeId: this.addObj.standardTreeId,
        templateList: this.boundTemplateList.map((item, index) => ({
          templateId: item.templateId,
          name: item.name,
          sort: index
        }))
      })
      // 清空当前样品信息,方便继续录入下一个样品
      this.sampleCode = ''
      this.addObj.sample = null
      this.addObj.sampleView = ''
      this.addObj.standardTreeId = null
      this.addObj.testQuantity = ''
      this.addObj.sampleStatus = ''
      this.boundTemplateList = []
      this.selectTreeNode = null
      this.selectTree = null
    },
    removeBatchSample(index) {
      this.batchSampleList.splice(index, 1)
    },
    batchTemplateNames(row) {
      return (row.templateList || []).map(item => item.name).join('、')
    },
    saveBatchOrder() {
      if (this.addObj.standardTreeId || (this.sampleCode || '').trim()) {
        this.$message.error('上方还有未加入列表的样品,请先点击“添加样品”或清空后再提交')
        return
      }
      if (!this.addObj.company || !this.addObj.orderType) {
        this.$message.error('请填写委托单位和检验类别')
        return
      }
      if (this.addObj.subcontractType == null || this.addObj.sampleDisposal == null
        || this.addObj.resultEvaluation == null || this.addObj.reportDelivery == null) {
        this.$message.error('请选择分包内容、样品处置、对结果评价和报告交付方式')
        return
      }
      if (this.addObj.subcontractType === 1 && !this.addObj.subcontractCompany) {
        this.$message.error('分包内容为有时,请填写分包单位信息')
        return
      }
      if (this.addObj.reportDelivery === 2 && (!this.addObj.reportAddress || !this.addObj.reportReceiver)) {
        this.$message.error('报告交付方式为快递时,请填写报告寄送地址和收件人及电话')
        return
      }
      const emptyTemplateRow = this.batchSampleList.find(item => !item.templateList || item.templateList.length === 0)
      if (emptyTemplateRow) {
        this.$message.error(`样品 ${emptyTemplateRow.sampleCode} 没有原始记录模板,请删除后重新添加`)
        return
      }
      this.saveLoad = true
      const insOrder = {
        ...this.addObj,
        productionDate: this.addObj.productionDate === '/' || !this.addObj.productionDate
          ? null : this.addObj.productionDate,
        typeSource: -1,
      }
      delete insOrder.createTime
      delete insOrder.temperature
      delete insOrder.humidity
      const payload = {
        insOrder,
        sampleList: this.batchSampleList.map(item => ({
          sampleCode: item.sampleCode,
          sampleView: item.sampleView,
          testQuantity: item.testQuantity,
          sampleStatus: item.sampleStatus,
          standardTreeId: item.standardTreeId,
          templateList: item.templateList.map((tpl, index) => ({templateId: tpl.templateId, sort: index}))
        }))
      }
      addBatchNewJuInsOrder(payload).then(async res => {
        const fileSuccess = await this.saveOrderFiles(res.data)
        this.saveLoad = false
        if (!fileSuccess) {
          this.$message.warning('订单已保存,部分附件处理失败,请到委托单详情重新上传')
        } else {
          this.$message.success('已提交')
        }
        this.closeOpenPage()
      }).catch(e => {
        this.saveLoad = false
      })
    },
    handleFileChange(file, fileList) {
      if (file.size > 200 * 1024 * 1024) {
@@ -2808,6 +2963,38 @@
  color: var(--lims-text-3);
}
/* 批量样品:表单下方的待提交样品列表 */
.batch-sample {
  margin-top: 4px;
  padding-top: 16px;
  border-top: 1px dashed var(--el-border-color);
}
.batch-sample__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}
.batch-sample__title {
  font-size: 14px;
  font-weight: bold;
  color: var(--lims-text);
}
.batch-sample__tip {
  margin-top: 4px;
  font-size: 12px;
  color: var(--lims-text-3);
  line-height: 1.5;
}
.batch-sample__table {
  margin-bottom: 16px;
}
/* 委托单信息:顶部操作栏 */
.order-header {
  display: flex;