Explorar o código

新增BPM流程实例详情页及相关API接口,优化质检项目任务功能

yusheng hai 10 meses
pai
achega
18b7d79b61

+ 82 - 0
src/api/bpm/index.js

@@ -0,0 +1,82 @@
+import request from '@/utils/request'
+
+export async function getActivityList(query) {
+
+  const res= await request({
+    url: '/bpm/activity/list',
+    method: 'get',
+    params: query
+  })
+
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+export async function getProcessInstance(id) {
+
+  const res= await request({
+    url: '/bpm/process-instance/get?id=' + id,
+    method: 'get',
+  })
+
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+export async function getTaskListByProcessInstanceId(processInstanceId) {
+  const res = await request({
+    url:
+      '/bpm/task/list-by-process-instance-id?processInstanceId=' +
+      processInstanceId,
+    method: 'get'
+  });
+
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+export async function getProcessDefinitionBpmnXML(id) {
+  const res = await request({
+    url: '/bpm/process-definition/get-bpmn-xml?id=' + id,
+    method: 'get'
+  })
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+export async function getTaskAssignRuleList(query) {
+  const res = await request({
+    url: '/bpm/task-assign-rule/list',
+    method: 'get',
+    params: query
+  })
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+export async function processInstanceCreateAPI(data) {
+  const res = await request({
+    url: '/bpm/process-instance/create',
+    method: 'post'
+  },data)
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+export async function getModelPage(query) {
+  const res = await request({
+    url: '/bpm/model/page',
+    method: 'get',
+    params: query
+  })
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 105 - 0
src/api/inspectionProjectTask/index.js

@@ -0,0 +1,105 @@
+import request from '@/utils/request';
+
+// 列表
+
+export async function getList(params) {
+  const res = await request.get(`/qms/taskmonad/page`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//收样
+
+export async function sampleCollection(data) {
+  const res = await request.put(`/qms/taskmonad/sampleCollection`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 派单
+export async function qualityInspectionItemDispatching(data) {
+  const res = await request.post(
+    `/qms/quality_work_order/qualityInspectionItemDispatching`,
+    data
+  );
+  if (res.data.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//请托
+export async function qualityInspectionItemRequest(data) {
+  const res = await request.post(
+    `/qms/quality_work_order/qualityInspectionItemRequest`,
+    data
+  );
+  if (res.data.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 编辑
+export async function update(data) {
+  const res = await request.post(`/qms/inspection_item/update`, data);
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 获取详情
+export async function getById(id) {
+  const res = await request.get(`/qms/taskmonad/getById/${id}`);
+  if (res.data.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 批量导入文件
+export async function importFile(data) {
+  const res = await request.post('/qms/inspection_item/importBatch', data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(res.data); //报错处理
+}
+
+// 删除
+export async function removeItem(data) {
+  const res = await request.delete('/qms/inspection_item/delete', {
+    data
+  });
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 复制
+export async function copyItem(id) {
+  const res = await request.get('/qms/inspection_item/copy/' + id);
+  if (res.data.code == 0) {
+    return res.data.message;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+//下载模板
+export async function downImportTemplate() {
+  const res = await request.post(
+    '/qms/inspection_item/importTemplate',
+    {},
+    {
+      responseType: 'blob'
+    }
+  );
+  console.log(res.data, '***********');
+  download(res.data, '质检项导入模板.xlsx');
+}

+ 25 - 0
src/api/samplingRecords/index.js

@@ -11,3 +11,28 @@ export async function samplingRecordsPage(params) {
   }
   return Promise.reject(new Error(res.data.message));
 }
+
+//取样新建/修改
+export async function samplingrecordSave(data) {
+  const res = await request.post(`/qms/samplingrecord/save`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+//取样新建/修改
+export async function samplingrecordUpdate(data) {
+  const res = await request.put(`/qms/samplingrecord/update`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+//详情
+export async function getById(id) {
+  const res = await request.get(`/qms/samplingrecord/getById/` + id);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 25 - 1
src/enum/dict.js

@@ -19,7 +19,7 @@ export default {
   质检计划状态: 'inspection_plan_status',
   文档类型: 'doc_type',
   工种类型: 'work_type',
-  工作流任务分配自定义脚本: 'bpm_task_assign_script',
+  工作流任务分配自定义脚本: 'bpm_task_assign_script'
 };
 
 export const numberList = [
@@ -43,3 +43,27 @@ export const reviewStatus = {
   2: '已审核',
   3: '审核不通过'
 };
+
+// 质检方案状态
+export const inspectionProjectStatus = [
+  {
+    label: '待检',
+    value: 0
+  },
+  {
+    label: '已检',
+    value: 1
+  },
+  {
+    label: '已派单',
+    value: 2
+  },
+  {
+    label: '已请托',
+    value: 3
+  },
+  {
+    label: '检验中',
+    value: 4
+  }
+];

+ 3 - 1
src/main.js

@@ -26,10 +26,12 @@ import 'bpmn-js/dist/assets/diagram-js.css';
 import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
 import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
 import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
-
+import fileMain from '@/components/addDoc/index.vue';
 // // register globally
 import '@/icons';
 Vue.component('DictSelection', DictSelection);
+Vue.component('fileMain', fileMain);
+
 Vue.config.productionTip = false;
 
 // 公共搜索文件

+ 75 - 0
src/utils/dateUtils.js

@@ -0,0 +1,75 @@
+/**
+ * 将毫秒,转换成时间字符串。例如说,xx 分钟
+ *
+ * @param ms 毫秒
+ * @returns {string} 字符串
+ */
+export function getDate(ms) {
+  const day = Math.floor(ms / (24 * 60 * 60 * 1000));
+  const hour =  Math.floor((ms / (60 * 60 * 1000) - day * 24));
+  const minute =  Math.floor(((ms / (60 * 1000)) - day * 24 * 60 - hour * 60));
+  const second =  Math.floor((ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60));
+  if (day > 0) {
+    return day + "天" + hour + "小时" + minute + "分钟";
+  }
+  if (hour > 0) {
+    return hour + "小时" + minute + "分钟";
+  }
+  if (minute > 0) {
+    return minute + "分钟";
+  }
+  if (second > 0) {
+    return second + "秒";
+  } else {
+    return 0 + "秒";
+  }
+}
+
+export function beginOfDay(date) {
+  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
+}
+
+export function endOfDay(date) {
+  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
+}
+
+export function betweenDay(date1, date2) {
+  date1 = convertDate(date1);
+  date2 = convertDate(date2);
+  // 计算差值
+  return Math.floor((date2.getTime() - date1.getTime()) / (24 * 3600 * 1000));
+}
+
+export function formatDate(date, fmt) {
+  date = convertDate(date);
+  const o = {
+    "M+": date.getMonth() + 1, //月份
+    "d+": date.getDate(), //日
+    "H+": date.getHours(), //小时
+    "m+": date.getMinutes(), //分
+    "s+": date.getSeconds(), //秒
+    "q+": Math.floor((date.getMonth() + 3) / 3), //季度
+    "S": date.getMilliseconds() //毫秒
+  };
+  if (/(y+)/.test(fmt)) { // 年份
+    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
+  }
+  for (const k in o) {
+    if (new RegExp("(" + k + ")").test(fmt)) {
+      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+    }
+  }
+  return fmt;
+}
+
+export function addTime(date, time) {
+  date = convertDate(date);
+  return new Date(date.getTime() + time);
+}
+
+export function convertDate(date) {
+  if (typeof date === 'string') {
+    return new Date(date);
+  }
+  return date;
+}

+ 288 - 0
src/views/bpm/processInstance/detail.vue

@@ -0,0 +1,288 @@
+<template>
+
+    <div class="app-container" style="padding: 15px">
+      <!-- 审批记录 -->
+      <el-card class="box-card" v-loading="tasksLoad">
+        <div slot="header" class="clearfix">
+          <span class="el-icon-picture-outline">审批记录</span>
+        </div>
+        <el-col :span="16" :offset="4">
+          <div class="block">
+            <el-timeline>
+              <el-timeline-item
+                v-for="(item, index) in tasks"
+                :key="index"
+                :icon="getTimelineItemIcon(item)"
+                :type="getTimelineItemType(item)"
+              >
+                <p style="font-weight: 700">任务:{{ item.name }}</p>
+                <el-card :body-style="{ padding: '10px' }">
+                  <label
+                    v-if="item.assigneeUser"
+                    style="font-weight: normal; margin-right: 30px"
+                  >
+                    {{index==0?' 审批人':'发起人' }}:{{ item.assigneeUser.nickname }}
+                    <el-tag type="info" size="mini">{{
+                      item.assigneeUser.deptName
+                    }}</el-tag>
+                  </label>
+                  <label style="font-weight: normal" v-if="item.createTime"
+                    >创建时间:</label
+                  >
+                  <label style="color: #8a909c; font-weight: normal">{{
+                    item.createTime
+                  }}</label>
+                  <label
+                    v-if="item.endTime"
+                    style="margin-left: 30px; font-weight: normal"
+                    >审批时间:</label
+                  >
+                  <label
+                    v-if="item.endTime"
+                    style="color: #8a909c; font-weight: normal"
+                  >
+                    {{ item.endTime }}</label
+                  >
+                  <label
+                    v-if="item.durationInMillis"
+                    style="margin-left: 30px; font-weight: normal"
+                    >耗时:</label
+                  >
+                  <label
+                    v-if="item.durationInMillis"
+                    style="color: #8a909c; font-weight: normal"
+                  >
+                    {{ getDateStar(item.durationInMillis) }}
+                  </label>
+                  <label   v-if="item.result!=1"  style="margin-left: 30px;color: #8a909c; font-weight: normal">
+                    签名:
+                  </label>
+                  <label v-if="item.result!=1">
+                    <el-image
+                      style="width: 50px; height: 50px;position: absolute;transform: translate(0px, 0px);"
+                      :src="item?.assigneeUser?.signature[0]?.url">
+                      <div slot="error" class="image-slot">
+<!--                        <i class="el-icon-picture-outline"></i>-->
+                        <span></span>
+                      </div>
+                    </el-image>
+                  </label>
+
+                  <p v-if="item.reason&&item.result!=4">
+                    <el-tag :type="getTimelineItemType(item)">{{
+                      item.reason
+                    }}</el-tag>
+                  </p>
+                </el-card>
+              </el-timeline-item>
+            </el-timeline>
+          </div>
+        </el-col>
+      </el-card>
+
+      <!-- 高亮流程图 -->
+      <el-card class="box-card" v-loading="processInstanceLoading">
+        <div slot="header" class="clearfix">
+          <span class="el-icon-picture-outline">流程图</span>
+        </div>
+        <my-process-viewer
+
+          key="designer"
+          v-model="bpmnXML"
+          v-bind="bpmnControlForm"
+          :activityData="activityList"
+          :processInstanceData="processInstance"
+          :taskData="tasks"
+        />
+      </el-card>
+    </div>
+
+</template>
+
+<script>
+  import {
+    getProcessDefinitionBpmnXML,
+    getProcessInstance,
+    getTaskListByProcessInstanceId,
+    getActivityList
+  } from '@/api/bpm/index';
+  import store from '@/store';
+  import { getDate } from '@/utils/dateUtils';
+  import dictMixins from '@/mixins/dictMixins';
+  // import Vue from 'vue';
+
+  // 流程实例的详情页,可用于审批
+  export default {
+    name: 'ProcessInstanceDetail',
+    mixins: [dictMixins],
+    props: {
+      id: {
+        default: ''
+      }
+    },
+    components: {},
+    data() {
+      return {
+        // 遮罩层
+        processInstanceLoading: true,
+        dialogVisible: false,
+
+        // 流程实例
+        // id: undefined, // 流程实例的编号
+        processInstance: {},
+
+        // BPMN 数据
+        bpmnXML: null,
+        bpmnControlForm: {
+          prefix: 'flowable'
+        },
+        activityList: [],
+
+        // 审批记录
+        tasksLoad: true,
+        tasks: []
+      };
+    },
+    created() {
+
+      this.getDetail();
+    },
+    methods: {
+
+      /** 获得流程实例 */
+      getDetail() {
+        // 获得流程实例相关
+        this.processInstanceLoading = true;
+        getProcessInstance(this.id).then((response) => {
+          if (!response) {
+            this.$message.error('查询不到流程信息!');
+            return;
+          }
+          // 设置流程信息
+          this.processInstance = response;
+
+          // //将业务表单,注册为动态组件
+          // const path = this.processInstance.processDefinition.formCustomViewPath;
+          // Vue.component("async-biz-form-component", function (resolve) {
+          //   require([`@/views${path}`], resolve);
+          // });
+
+          // 加载流程图
+          getProcessDefinitionBpmnXML(
+            this.processInstance.processDefinition.id
+          ).then((response) => {
+            this.bpmnXML = response;
+          });
+          // 加载活动列表
+          getActivityList({
+            processInstanceId: this.processInstance.id
+          }).then((response) => {
+            this.activityList = response;
+          });
+
+          // 取消加载中
+          this.processInstanceLoading = false;
+        });
+
+        // 获得流程任务列表(审批记录)
+        this.tasksLoad = true;
+        getTaskListByProcessInstanceId(this.id).then((response) => {
+          // 审批记录
+          this.tasks = [];
+          // 移除已取消的审批
+          response.forEach((task) => {
+            // if (task.result !== 4) {
+              this.tasks.push(task);
+            // }
+          });
+          // 排序,将未完成的排在前面,已完成的排在后面;
+          this.tasks.sort((a, b) => {
+            // 有已完成的情况,按照完成时间倒序
+            if (a.endTime && b.endTime) {
+              return b.endTime - a.endTime;
+            } else if (a.endTime) {
+              return 1;
+            } else if (b.endTime) {
+              return -1;
+              // 都是未完成,按照创建时间倒序
+            } else {
+              return b.createTime - a.createTime;
+            }
+          });
+
+          // 需要审核的记录
+          const userId = store.getters.userId;
+          this.tasks.forEach((task) => {
+            if (task.result !== 1 && task.result !== 6) {
+              // 只有待处理才需要
+              return;
+            }
+            if (!task.assigneeUser || task.assigneeUser.id !== userId) {
+              // 自己不是处理人
+              return;
+            }
+          });
+
+          // 取消加载中
+          this.tasksLoad = false;
+        });
+      },
+      getDateStar(ms) {
+        return getDate(ms);
+      },
+      getTimelineItemIcon(item) {
+        if (item.result === 1) {
+          return 'el-icon-time';
+        }
+        if (item.result === 2) {
+          return 'el-icon-check';
+        }
+        if (item.result === 3) {
+          return 'el-icon-close';
+        }
+        if (item.result === 4) {
+          return 'el-icon-remove-outline';
+        }
+        if (item.result === 5) {
+          return 'el-icon-back';
+        }
+        return '';
+      },
+      getTimelineItemType(item) {
+        if (item.result === 1) {
+          return 'primary';
+        }
+        if (item.result === 2) {
+          return 'success';
+        }
+        if (item.result === 3) {
+          return 'danger';
+        }
+        if (item.result === 4) {
+          return 'info';
+        }
+        if (item.result === 5) {
+          return 'warning';
+        }
+        if (item.result === 6) {
+          return 'default';
+        }
+        return '';
+      },
+      handleClose() {
+        this.dialogVisible = false;
+      }
+    }
+  };
+</script>
+
+<style lang="scss">
+  .my-process-designer {
+    height: calc(100vh - 200px);
+  }
+
+  .box-card {
+    width: 100%;
+    margin-bottom: 20px;
+  }
+</style>

+ 2 - 2
src/views/inspectionPoint/index.vue

@@ -63,7 +63,7 @@
   </div>
 </template>
 <script>
-import fileMain from '@/components/addDoc/index.vue';
+
 import search from './components/search.vue';
 import newEdit from './components/newEdit.vue';
 import { getList, removeItem } from '@/api/inspectionPoint';
@@ -76,7 +76,7 @@ export default {
   components: {
     search,
     newEdit,
-    fileMain
+    
   },
   data() {
     return {

+ 73 - 0
src/views/inspectionProjectRequest/components/search.vue

@@ -0,0 +1,73 @@
+<!-- 搜索表单 -->
+<template>
+  <seekPage :seekList="seekList" :formLength="3" @search="search"></seekPage>
+</template>
+
+<script>
+  import { getList } from '@/api/inspectionStandard';
+  export default {
+    data() {
+      return {
+        qualityStandardList: []
+      };
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            label: '任务单号:',
+            value: 'code',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '质检工单编码:',
+            value: 'qualityWorkOrderCode',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '类型:',
+            value: 'qualityType',
+            type: 'DictSelection',
+            dictName: '质检计划类型',
+            placeholder: '请输入'
+          },
+          {
+            label: '批次号:',
+            value: 'batchNo',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '编号:',
+            value: 'productCode',
+            type: 'input',
+            placeholder: '请输入'
+          },
+
+          {
+            label: '状态:',
+            value: 'standardCode',
+            type: 'input',
+            placeholder: '请输入'
+          }
+        ];
+      }
+    },
+    created() {
+      getList({
+        pageNum: 1,
+        size: -1
+      }).then((res) => {
+        this.qualityStandardList = res.list;
+      });
+    },
+    methods: {
+      /* 搜索 */
+      search(e) {
+        this.$emit('search', { ...e });
+      }
+    }
+  };
+</script>

+ 337 - 0
src/views/inspectionProjectRequest/index.vue

@@ -0,0 +1,337 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never">
+      <!-- 搜索表单 -->
+      <search @search="reload" />
+      <!-- 数据表格 -->
+      <ele-pro-table
+        ref="table"
+        :columns="columns"
+        :datasource="datasource"
+        :selection.sync="selection"
+        row-key="code"
+        :page-size="20"
+        @columns-change="handleColumnChange"
+        :cache-key="cacheKeyUrl"
+      >
+        <!-- 表头工具栏 -->
+        <template v-slot:qualityType="{ row }">
+          {{ getDictValue('质检计划类型', row.qualityType) }}
+        </template>
+        <template v-slot:qualityMode="{ row }">
+          {{ getDictValue('取样类型', row.qualityMode) }}
+        </template>
+
+        <!-- 操作列 -->
+        <template v-slot:action="{ row }">
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="sampleCollection(row)"
+            v-if="row.status == 0"
+          >
+            收样
+          </el-link>
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="openEdit(row)"
+            v-if="row.status == 1"
+          >
+            报工
+          </el-link>
+        </template>
+      </ele-pro-table>
+    </el-card>
+    <!-- 编辑弹窗 -->
+    <edit ref="edit" />
+  </div>
+</template>
+
+<script>
+  import search from './components/search.vue';
+  // import edit from './components/inspectionProjectTaskSend.vue';
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  import { getList, sampleCollection } from '@/api/inspectionProjectTask';
+  import dictMixins from '@/mixins/dictMixins';
+  export default {
+    components: {
+      search
+      // edit
+    },
+    mixins: [dictMixins, tabMixins],
+    data() {
+      return {
+        cacheKeyUrl: 'qsm-c2e9664a-inspectionProjectTask',
+        // 表格列配置
+        columns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'code',
+            label: '请托单号',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 130
+          },
+          {
+            prop: 'name',
+            label: '任务名称',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 110
+          },
+
+          {
+            prop: 'executeDeptName',
+            label: '受托部门',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 110
+          },
+
+          {
+            prop: 'executeUserName',
+            minWidth: 110,
+            label: '执行人员',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+
+          {
+            prop: 'requiredCompletionTime',
+            minWidth: 110,
+            label: '完成日期',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'urgent',
+            minWidth: 110,
+            label: '紧急程度',
+            align: 'center',
+            formatter: (row) => {
+              return row.urgent == 1
+                ? '普通'
+                : row.urgent == 2
+                ? '紧急'
+                : '重要';
+            },
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityWorkOrderCode',
+            minWidth: 110,
+            label: '质检工单编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityWorkOrderName',
+            minWidth: 110,
+            label: '质检工单名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sourceCode',
+            minWidth: 110,
+            label: '来源单号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityType',
+            slot: 'qualityType',
+            minWidth: 110,
+            label: '类型',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            slot: 'qualityMode',
+            prop: 'qualityMode',
+            minWidth: 110,
+            label: '质检方式',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productCode',
+            minWidth: 110,
+            label: '编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productName',
+            minWidth: 110,
+            label: '名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'batchNo',
+            minWidth: 110,
+            label: '批次号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'specification',
+            minWidth: 110,
+            label: '规格',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'brandNo',
+            minWidth: 110,
+            label: '牌号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'produceTaskName',
+            minWidth: 110,
+            label: '工序名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'status',
+            minWidth: 110,
+            label: '状态',
+            align: 'center',
+     
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'createUserName',
+            minWidth: 110,
+            label: '创建人',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'createTime',
+            minWidth: 110,
+            label: '创建时间',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sampleReceiverName',
+            minWidth: 110,
+            label: '收样人',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sampleReceiverTime',
+            minWidth: 110,
+            label: '收样时间',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 220,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            fixed: 'right',
+            showOverflowTooltip: true
+          }
+        ]
+      };
+    },
+    created() {
+      this.requestDict('质检计划类型');
+      this.requestDict('取样类型');
+    },
+    methods: {
+      /*回显类型 */
+
+      /* 表格数据源 */
+      datasource({ page, where, limit }) {
+        return getList({
+          ...where,
+          pageNum: page,
+          size: limit
+        });
+      },
+      /* 刷新表格 */
+      reload(where) {
+        this.$refs.table.reload({ page: 1, where: where });
+      },
+
+      uploadFile() {
+        this.$refs.importDialogRef.open();
+      },
+      sampleCollection(row) {
+        sampleCollection({ id: row.id }).then((res) => {
+          this.$message.success('收样成功');
+
+          this.reload();
+        });
+      },
+      /* 打开编辑弹窗 */
+      openEdit(row) {
+        this.current = row;
+        this.showEdit = true;
+        this.$refs.userEdit.$refs.form &&
+          this.$refs.userEdit.$refs.form.clearValidate();
+      },
+
+      /* 删除 */
+      remove(row) {
+        const loading = this.$loading({ lock: true });
+
+        removeItem([row.id])
+          .then((msg) => {
+            loading.close();
+            this.$message.success('删除' + msg);
+            this.reload();
+          })
+          .catch((e) => {
+            loading.close();
+          });
+      },
+
+      /* 批量删除 */
+      removeBatch() {
+        if (!this.selection.length) {
+          this.$message.error('请至少选择一条数据');
+          return;
+        }
+        this.$confirm('确定要删除选中的质检吗?', '提示', {
+          type: 'warning'
+        })
+          .then(() => {
+            const loading = this.$loading({ lock: true });
+            removeItem(this.selection.map((d) => d.id))
+              .then((msg) => {
+                loading.close();
+                this.$message.success('删除' + msg);
+                this.reload();
+              })
+              .catch((e) => {
+                loading.close();
+              });
+          })
+          .catch(() => {});
+      }
+    }
+  };
+</script>

+ 304 - 0
src/views/inspectionProjectTask/components/inspectionProjectTaskSend.vue

@@ -0,0 +1,304 @@
+<template>
+  <ele-modal
+    width="70%"
+    :append-to-body="true"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    :title="type == 1 ? '质检项派单' : '质检项请托'"
+    :visible.sync="visible"
+    :maxable="true"
+    @close="cancel"
+  >
+    <header-title title="质检项信息"></header-title>
+    <ele-pro-table
+      :needPage="false"
+      :columns="tableColumns"
+      :datasource="list"
+      :selection.sync="selection"
+    ></ele-pro-table>
+    <header-title title="派单信息"></header-title>
+    <el-form
+      ref="form"
+      :model="form"
+      :rules="rules"
+      class="el-form-box"
+      label-width="120px"
+    >
+      <el-row>
+        <el-col :span="8">
+          <el-form-item
+            :label="type == 1 ? '任务单号' : '质检项请托单号'"
+            prop="code"
+          >
+            <el-input
+              v-model="form.code"
+              placeholder=" "
+              disabled
+            ></el-input> </el-form-item
+        ></el-col>
+        <el-col :span="8">
+          <el-form-item label="任务名称" prop="name">
+            <el-input
+              v-model="form.name"
+              placeholder="请输入"
+            ></el-input> </el-form-item></el-col
+      ></el-row>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="执行部门" prop="executeDeptId">
+            <deptSelect
+              v-model="form.executeDeptId"
+              @changeGroup="searchDeptNodeClick"
+            /> </el-form-item
+        ></el-col>
+        <el-col :span="8">
+          <el-form-item label="执行人" prop="executeUserId">
+            <el-select
+              v-model="form.executeUserId"
+              @change="changeExecutor"
+              filterable
+              style="width: 100%"
+            >
+              <el-option
+                v-for="item in executorList"
+                :key="item.id"
+                :value="item.id"
+                :label="item.name"
+              ></el-option>
+            </el-select> </el-form-item></el-col
+      ></el-row>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="要求完成时间" prop="requiredCompletionTime">
+            <el-date-picker
+              v-model="form.requiredCompletionTime"
+              style="width: 100%"
+              type="datetime"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              placeholder=" "
+            >
+            </el-date-picker> </el-form-item
+        ></el-col>
+      </el-row>
+    </el-form>
+
+    <template v-slot:footer>
+      <el-button @click="cancel">取消</el-button>
+      <el-button type="primary" :loading="loading" @click="save">
+        确认
+      </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  import {
+    qualityInspectionItemDispatching,
+    qualityInspectionItemRequest
+  } from '@/api/inspectionProjectTask';
+  import { getById } from '@/api/inspectionWork';
+  import { inspectionProjectStatus } from '@/enum/dict.js';
+  import deptSelect from '@/components/CommomSelect/dept-select.vue';
+  import { getUserPage } from '@/api/system/organization';
+  const defaultForm = {
+    id: null,
+    executeDeptId: '',
+    executeDeptName: '',
+    executeUserId: '',
+    executeUserName: '',
+    name: '',
+    code: '',
+    qualityWorkOrderId: '',
+    requiredCompletionTime: '',
+    type: 1
+  };
+  export default {
+    components: { deptSelect },
+
+    data() {
+      return {
+        type: 1,
+        form: { ...defaultForm },
+        executorList: [],
+        selection: [],
+        list: [],
+        tableColumns: [
+          {
+            width: 45,
+            type: 'index',
+            columnKey: 'index',
+            align: 'center',
+            fixed: 'left'
+          },
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center',
+            selectable: (row, index) => {
+              return row.status == 0;
+            }
+          },
+          {
+            minWidth: 150,
+            prop: 'qualitySchemeTemplateCode',
+            align: 'center',
+            label: '质检方案编码',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'qualitySchemeTemplateName',
+            align: 'center',
+            label: '质检方案名称',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'categoryLevelClassName',
+            align: 'center',
+            label: '质检类型',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 130,
+            prop: 'inspectionCode',
+            align: 'center',
+            label: '质检项编码',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'inspectionName',
+            align: 'center',
+            label: '质检项名称',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'defaultValue',
+            align: 'center',
+            label: '工艺参数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'status',
+            align: 'center',
+            formatter: (row) => {
+              return (
+                inspectionProjectStatus.find(
+                  (item) => item.value === row.status
+                )?.label || ''
+              );
+            },
+
+            label: '状态',
+            showOverflowTooltip: true
+          }
+        ],
+        rules: {
+          executeDeptId: [
+            { required: true, message: '请选择部门', trigger: 'blur' }
+          ],
+          name: [
+            { required: true, message: '请输入任务名称', trigger: 'blur' }
+          ],
+          requiredCompletionTime: [
+            { required: true, message: '请输入要求完成日期', trigger: 'blur' }
+          ],
+          executeUserId: [
+            { required: true, message: '请选择人员', trigger: 'blur' }
+          ]
+        },
+
+        loading: false,
+        visible: false
+      };
+    },
+
+    created() {},
+    methods: {
+      open(row, type) {
+        this.type = type;
+        this.visible = true;
+        getById(row.id).then((res) => {
+          let data = res.data;
+          this.form.qualityWorkOrderId = data.id;
+          this.list = data.templateList;
+        });
+      },
+      searchDeptNodeClick(info, row) {
+        if (info) {
+          const params = { groupId: info };
+          this.form.executeDeptId = info;
+          this.form.executeDeptName = row.name;
+          this.getUserList(params);
+        } else {
+          this.form.executeUserId = null;
+          this.form.executeUserName = null;
+          this.executorList = [];
+        }
+      },
+      // 获取人员
+      async getUserList(params) {
+        try {
+          let data = { pageNum: 1, size: -1 };
+
+          if (params) {
+            data = Object.assign(data, params);
+          }
+          const res = await getUserPage(data);
+          this.executorList = res.list;
+          this.form.executeUserId = null;
+          this.form.executeUserName = null;
+        } catch (error) {}
+      },
+      changeExecutor(val) {
+        if (val) {
+          this.form.executeUserId = val;
+          this.form.executeUserName = this.executorList.find(
+            (item) => item.id === val
+          ).name;
+        }
+      },
+      save() {
+        this.$refs.form.validate((valid) => {
+          if (!valid) {
+            return false;
+          }
+          if (this.selection.length == 0) {
+            return this.$message.warning('请至少选择一条数据');
+          }
+          this.loading = true;
+          let api =
+            this.type == 1
+              ? qualityInspectionItemDispatching
+              : qualityInspectionItemRequest;
+          api({
+            ...this.form,
+            detailList: this.selection.map((item) => {
+              return { qualityPlanTemplateId: item.id };
+            })
+          })
+            .then((msg) => {
+              this.loading = false;
+              this.$emit('reload');
+              this.cancel();
+            })
+            .catch((e) => {
+              this.loading = false;
+            });
+        });
+      },
+      cancel() {
+        this.visible = false;
+        this.$refs.form.clearValidate();
+        this.form = { ...defaultForm };
+        this.list = [];
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped></style>

+ 73 - 0
src/views/inspectionProjectTask/components/search.vue

@@ -0,0 +1,73 @@
+<!-- 搜索表单 -->
+<template>
+  <seekPage :seekList="seekList" :formLength="3" @search="search"></seekPage>
+</template>
+
+<script>
+  import { getList } from '@/api/inspectionStandard';
+  export default {
+    data() {
+      return {
+        qualityStandardList: []
+      };
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            label: '任务单号:',
+            value: 'code',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '质检工单编码:',
+            value: 'qualityWorkOrderCode',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '类型:',
+            value: 'qualityType',
+            type: 'DictSelection',
+            dictName: '质检计划类型',
+            placeholder: '请输入'
+          },
+          {
+            label: '批次号:',
+            value: 'batchNo',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '编号:',
+            value: 'productCode',
+            type: 'input',
+            placeholder: '请输入'
+          },
+
+          {
+            label: '状态:',
+            value: 'standardCode',
+            type: 'input',
+            placeholder: '请输入'
+          }
+        ];
+      }
+    },
+    created() {
+      getList({
+        pageNum: 1,
+        size: -1
+      }).then((res) => {
+        this.qualityStandardList = res.list;
+      });
+    },
+    methods: {
+      /* 搜索 */
+      search(e) {
+        this.$emit('search', { ...e });
+      }
+    }
+  };
+</script>

+ 338 - 0
src/views/inspectionProjectTask/index.vue

@@ -0,0 +1,338 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never">
+      <!-- 搜索表单 -->
+      <search @search="reload" />
+      <!-- 数据表格 -->
+      <ele-pro-table
+        ref="table"
+        :columns="columns"
+        :datasource="datasource"
+        :selection.sync="selection"
+        row-key="code"
+        :page-size="20"
+        @columns-change="handleColumnChange"
+        :cache-key="cacheKeyUrl"
+      >
+        <!-- 表头工具栏 -->
+        <template v-slot:qualityType="{ row }">
+          {{ getDictValue('质检计划类型', row.qualityType) }}
+        </template>
+        <template v-slot:qualityMode="{ row }">
+          {{ getDictValue('取样类型', row.qualityMode) }}
+        </template>
+
+        <!-- 操作列 -->
+        <template v-slot:action="{ row }">
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="sampleCollection(row)"
+            v-if="row.status == 0"
+          >
+            收样
+          </el-link>
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="openEdit(row)"
+            v-if="row.status == 1"
+          >
+            报工
+          </el-link>
+        </template>
+      </ele-pro-table>
+    </el-card>
+    <!-- 编辑弹窗 -->
+    <inspectionProjectReport
+      ref="inspectionProjectReportRef"
+      @reload="reload"
+    />
+  </div>
+</template>
+
+<script>
+  import search from './components/search.vue';
+  import inspectionProjectReport from '@/views/inspectionWork/components/inspectionProjectReport.vue';
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  import {
+    getList,
+    sampleCollection,
+    getById
+  } from '@/api/inspectionProjectTask';
+  import dictMixins from '@/mixins/dictMixins';
+import { workOrder } from '@/api/aps';
+import list from '@/i18n/lang/zh_CN/list';
+  export default {
+    components: {
+      search,
+      inspectionProjectReport
+    },
+    mixins: [dictMixins, tabMixins],
+    data() {
+      return {
+        cacheKeyUrl: 'qsm-c2e9664a-inspectionProjectTask',
+        // 表格列配置
+        columns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center',
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'code',
+            label: '质检任务单号',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 130
+          },
+          {
+            prop: 'name',
+            label: '任务名称',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 110
+          },
+
+          {
+            prop: 'executeDeptName',
+            label: '执行部门',
+            showOverflowTooltip: true,
+            align: 'center',
+            minWidth: 110
+          },
+
+          {
+            prop: 'executeUserName',
+            minWidth: 110,
+            label: '执行人员',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+
+          {
+            prop: 'requiredCompletionTime',
+            minWidth: 110,
+            label: '完成日期',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityWorkOrderCode',
+            minWidth: 110,
+            label: '质检工单编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityWorkOrderName',
+            minWidth: 110,
+            label: '质检工单名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sourceCode',
+            minWidth: 110,
+            label: '来源单号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityType',
+            slot: 'qualityType',
+            minWidth: 110,
+            label: '类型',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            slot: 'qualityMode',
+            prop: 'qualityMode',
+            minWidth: 110,
+            label: '质检方式',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productCode',
+            minWidth: 110,
+            label: '编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productName',
+            minWidth: 110,
+            label: '名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'batchNo',
+            minWidth: 110,
+            label: '批次号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'specification',
+            minWidth: 110,
+            label: '规格',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'brandNo',
+            minWidth: 110,
+            label: '牌号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'produceTaskName',
+            minWidth: 110,
+            label: '工序名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'status',
+            minWidth: 110,
+            label: '状态',
+            align: 'center',
+            formatter: (row) => {
+              return row.status == 0
+                ? '待收样'
+                : row.status == 1
+                ? '未报工'
+                : '已报工';
+            },
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'createUserName',
+            minWidth: 110,
+            label: '创建人',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'createTime',
+            minWidth: 110,
+            label: '创建时间',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sampleReceiverName',
+            minWidth: 110,
+            label: '收样人',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sampleReceiverTime',
+            minWidth: 110,
+            label: '收样时间',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 220,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            fixed: 'right',
+            showOverflowTooltip: true
+          }
+        ]
+      };
+    },
+    created() {
+      this.requestDict('质检计划类型');
+      this.requestDict('取样类型');
+    },
+    
+    methods: {
+      /*回显类型 */
+
+      /* 表格数据源 */
+      datasource({ page, where, limit }) {
+        return getList({
+          ...where,
+          pageNum: page,
+          size: limit
+        });
+      },
+      /* 刷新表格 */
+      reload(where) {
+        this.$refs.table.reload({ page: 1, where: where });
+      },
+
+      uploadFile() {
+        this.$refs.importDialogRef.open();
+      },
+      sampleCollection(row) {
+        sampleCollection({ id: row.id }).then((res) => {
+          this.$message.success('收样成功');
+
+          this.reload();
+        });
+      },
+      /* 打开编辑弹窗 */
+      async openEdit(row) {
+        const res = await getById(row.id);
+      
+        this.$refs.inspectionProjectReportRef.open({workData:res.data,list:res.data.templateList}, 'edit');
+      },
+
+      /* 删除 */
+      remove(row) {
+        const loading = this.$loading({ lock: true });
+
+        removeItem([row.id])
+          .then((msg) => {
+            loading.close();
+            this.$message.success('删除' + msg);
+            this.reload();
+          })
+          .catch((e) => {
+            loading.close();
+          });
+      },
+
+      /* 批量删除 */
+      removeBatch() {
+        if (!this.selection.length) {
+          this.$message.error('请至少选择一条数据');
+          return;
+        }
+        this.$confirm('确定要删除选中的质检吗?', '提示', {
+          type: 'warning'
+        })
+          .then(() => {
+            const loading = this.$loading({ lock: true });
+            removeItem(this.selection.map((d) => d.id))
+              .then((msg) => {
+                loading.close();
+                this.$message.success('删除' + msg);
+                this.reload();
+              })
+              .catch((e) => {
+                loading.close();
+              });
+          })
+          .catch(() => {});
+      }
+    }
+  };
+</script>

+ 0 - 2
src/views/inspectionWork/components/Certificate.vue

@@ -77,7 +77,6 @@
     updateCertificateNumber,
     qualityWorkOrderCertificate
   } from '@/api/inspectionWork';
-  import fileMain from '@/components/addDoc/index.vue';
   export default {
     data() {
       return {
@@ -87,7 +86,6 @@
         loading: false
       };
     },
-    components: { fileMain },
     props: {
       addOpen: {
         type: Boolean,

+ 691 - 0
src/views/inspectionWork/components/inspectionProjectReport.vue

@@ -0,0 +1,691 @@
+<!-- 用户编辑弹窗 -->
+<template>
+  <ele-modal
+    title="质检项工单报工"
+    :visible.sync="visible"
+    :before-close="handleClose"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    width="80%"
+    :maxable="true"
+  >
+    <ele-pro-table
+      :needPage="false"
+      :columns="workColumns"
+      :datasource="[form]"
+    >
+      <template v-slot:toolbar>
+        剩余样品总数:{{ form.remainingSampleCount }}
+      </template>
+
+      <template v-slot:qualityType="{ row }">
+        {{ getDictValue('质检计划类型', row.qualityType) }}
+      </template>
+      <template v-slot:qualityMode="{ row }">
+        {{ getDictValue('取样类型', row.qualityMode) }}
+      </template>
+      <template v-slot:hours="{ row }">
+        <el-input v-model="row.hours" placeholder="请输入" type="number">
+        </el-input>
+      </template>
+      <template v-slot:accessory="{ row }">
+        <fileMain v-model="row.accessory" type="view"></fileMain>
+      </template>
+      <template v-slot:sampleQuantity="{ row }">
+        <el-input
+          v-model="row.sampleQuantity"
+          placeholder="请输入"
+          type="number"
+          @input="formSampleQuantityChange"
+        >
+        </el-input>
+      </template>
+      <template v-slot:sampleNoQualifiedNumber="{ row }">
+        <el-input
+          v-model="row.sampleNoQualifiedNumber"
+          @input="formSampleNoQualifiedNumberChange"
+          placeholder="请输入"
+          type="number"
+        >
+        </el-input>
+      </template>
+    </ele-pro-table>
+    <ele-pro-table
+      :needPage="false"
+      :columns="tableColumns"
+      :datasource="tableData"
+    >
+      <template v-slot:toolbar>
+        当前质检剩余样品数:{{ getSampleQuantityCount }}
+      </template>
+      <template v-slot:qualityStandardType="{ row }">
+        {{ getDictValue('质检标准类型', row.qualityStandardType) }}
+      </template>
+      <template v-slot:executionMethod="{ row }">
+        <el-select v-model="row.executionMethod" style="width: 100%">
+          <el-option :value="1" label="常规检验"></el-option>
+          <el-option :value="2" label="实验"></el-option>
+        </el-select>
+      </template>
+      <template v-slot:inspectionTool="{ row }">
+        <toolButtom
+          v-model="row.inspectionTool"
+          :type="type"
+          :sList="row.toolList"
+        />
+      </template>
+      <template v-slot:qualityResultContent="{ row }">
+        <el-input
+          v-model="row.qualityResultContent"
+          placeholder="请输入内容"
+          :disabled="type == 'detail'"
+          @input="handleInput(row, row.qualityResultContent)"
+        >
+          <template slot="append" v-if="row.unitName">
+            {{ row.unitName }}
+          </template>
+        </el-input>
+      </template>
+      <template v-slot:sampleQuantity="{ row, $index }">
+        <el-input
+          v-model="row.sampleQuantity"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('sampleQuantity', row, $index)"
+        >
+        </el-input>
+      </template>
+
+      <template v-slot:qualifiedQuantity="{ row, $index }">
+        <el-input
+          v-model="row.qualifiedQuantity"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('qualifiedQuantity', row, $index)"
+        >
+        </el-input>
+      </template>
+      <template v-slot:noQualifiedQuantity="{ row, $index }">
+        <el-input
+          v-model="row.noQualifiedQuantity"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('noQualifiedQuantity', row, $index)"
+        >
+        </el-input>
+      </template>
+      <template v-slot:lossNumber="{ row, $index }">
+        <el-input
+          v-model="row.lossNumber"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('lossNumber', row, $index)"
+          @click.native="curretNum = row.lossNumber"
+        >
+        </el-input>
+      </template>
+      <template v-slot:lossNumberUnqualified="{ row, $index }">
+        <el-input
+          v-model="row.lossNumberUnqualified"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('lossNumberUnqualified', row, $index)"
+          @click.native="curretNum = row.lossNumberUnqualified"
+        >
+        </el-input>
+      </template>
+      <template v-slot:retainedSampleQuantity="{ row, $index }">
+        <el-input
+          v-model="row.retainedSampleQuantity"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('retainedSampleQuantity', row, $index)"
+          @click.native="curretNum = row.retainedSampleQuantity"
+        >
+        </el-input>
+      </template>
+      <template v-slot:retainedSampleUnqualified="{ row, $index }">
+        <el-input
+          v-model="row.retainedSampleUnqualified"
+          placeholder="请输入"
+          :disabled="type == 'detail'"
+          type="number"
+          @input="inputValue('retainedSampleUnqualified', row, $index)"
+          @click.native="curretNum = row.retainedSampleUnqualified"
+        >
+        </el-input>
+      </template>
+      <template v-slot:qualityResults="{ row, $index }">
+        <el-select
+          v-model="row.qualityResults"
+          placeholder="请选择"
+          style="width: 100%"
+          :disabled="type == 'detail'"
+        >
+          <el-option
+            v-for="item in qualityResultsList"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          >
+          </el-option>
+        </el-select>
+      </template>
+    </ele-pro-table>
+    <template v-slot:footer>
+      <el-button @click="handleClose">取消</el-button>
+      <el-button type="primary" @click="handleConfirm"> 确认 </el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  import dictMixins from '@/mixins/dictMixins';
+  import detailMixins from '../mixins/detailMixins';
+  import toolButtom from './toolButtom.vue';
+  import { handleInput } from './unit.js';
+
+  export default {
+    mixins: [dictMixins, detailMixins],
+
+    components: { toolButtom },
+
+    data() {
+      return {
+        handleInput,
+        type: 'add',
+        title: '',
+        visible: false,
+        form: {},
+        tableData: [],
+        rowIndex: [],
+        curretNum: 0,
+        workColumns: [
+          {
+            minWidth: 150,
+            prop: 'code',
+            align: 'center',
+            label: '质检项工单号',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'qualityWorkOrderCode',
+            align: 'center',
+            label: '质检工单编码',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'qualityWorkOrderName',
+            align: 'center',
+            label: '质检工单名称',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'sourceCode',
+            align: 'center',
+            label: '来源单号',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'qualityType',
+            slot: 'qualityType',
+            align: 'center',
+            label: '类型',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            slot: 'qualityMode',
+            prop: 'qualityMode',
+            align: 'center',
+            label: '质检方式',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'productCode',
+            align: 'center',
+            label: '编码',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'productName',
+            align: 'center',
+            label: '名称',
+            showOverflowTooltip: true
+          },
+
+          {
+            minWidth: 100,
+            prop: 'batchNo',
+            align: 'center',
+            label: '批次号',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'specification',
+            align: 'center',
+            label: '规格',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'brandNo',
+            align: 'center',
+            label: '牌号',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'produceTaskName',
+            align: 'center',
+            label: '工序名称',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'total',
+            align: 'center',
+            label: '总数量',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'sampleQuantity',
+            slot: 'sampleQuantity',
+            align: 'center',
+            label: '样品数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'sampleNoQualifiedNumber',
+            slot: 'sampleNoQualifiedNumber',
+            align: 'center',
+            label: '样品不合格数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'sampleQualifiedNumber',
+            slot: 'sampleQualifiedNumber',
+            align: 'center',
+            label: '样品合格数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'lossNumber',
+            slot: 'lossNumber',
+            align: 'center',
+            label: '损耗数(合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'lossNumberUnqualified',
+            slot: 'lossNumberUnqualified',
+            align: 'center',
+            label: '损耗数(不合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'retainedSampleQuantity',
+            slot: 'retainedSampleQuantity',
+            align: 'center',
+            label: '留样数(合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'retainedSampleUnqualified',
+            slot: 'retainedSampleUnqualified',
+            align: 'center',
+            label: '留样数(不合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'hours',
+            slot: 'hours',
+            align: 'center',
+            label: '工时',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'accessory',
+            slot: 'accessory',
+            align: 'center',
+            label: '附件',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'qualityNames',
+            slot: 'qualityNames',
+            align: 'center',
+            label: '质检人',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'qualityTimeEnd',
+            slot: 'qualityTimeEnd',
+            align: 'center',
+            label: '质检时间',
+            showOverflowTooltip: true
+          }
+        ],
+
+        tableColumns: [
+          {
+            width: 45,
+            type: 'index',
+            columnKey: 'index',
+            align: 'center',
+            fixed: 'left'
+          },
+          {
+            minWidth: 150,
+            prop: 'qualitySchemeTemplateCode',
+            align: 'center',
+            label: '质检方案编码',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'qualitySchemeTemplateName',
+            align: 'center',
+            label: '质检方案名称',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'categoryLevelClassName',
+            align: 'center',
+            label: '质检类型',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 130,
+            prop: 'inspectionCode',
+            align: 'center',
+            label: '质检项编码',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'inspectionName',
+            align: 'center',
+            label: '质检项名称',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'qualityStandardType',
+            slot: 'qualityStandardType',
+            align: 'center',
+            label: '执行标准',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'defaultValue',
+            align: 'center',
+            label: '工艺参数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 130,
+            prop: 'executionMethod',
+            slot: 'executionMethod',
+            align: 'center',
+            label: '执行方法',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'inspectionTool',
+            slot: 'inspectionTool',
+            align: 'center',
+            label: '质检工具',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 200,
+            prop: 'qualityResultContent',
+            align: 'center',
+            slot: 'qualityResultContent',
+            label: '质检内容',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'sampleQuantity',
+            slot: 'sampleQuantity',
+            align: 'center',
+            label: '样品数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'qualifiedQuantity',
+            align: 'center',
+            slot: 'qualifiedQuantity',
+            label: '合格数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 130,
+            prop: 'noQualifiedQuantity',
+            slot: 'noQualifiedQuantity',
+            align: 'center',
+            label: '不合格数',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'lossNumber',
+            slot: 'lossNumber',
+            align: 'center',
+            label: '损耗数(合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'lossNumberUnqualified',
+            slot: 'lossNumberUnqualified',
+            align: 'center',
+            label: '损耗数(不合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 140,
+            prop: 'retainedSampleQuantity',
+            slot: 'retainedSampleQuantity',
+            align: 'center',
+            label: '留样数(合格品)',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'retainedSampleUnqualified',
+            slot: 'retainedSampleUnqualified',
+            align: 'center',
+            label: '留样数(不合格品)',
+            showOverflowTooltip: true
+          },
+
+          {
+            minWidth: 100,
+            prop: 'qualityResults',
+            slot: 'qualityResults',
+            align: 'center',
+            label: '质检结果',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 150,
+            prop: 'experimentCode',
+            align: 'center',
+            label: '实验编号',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 120,
+            prop: 'inspectImage',
+            slot: 'inspectImage',
+            align: 'center',
+            label: '检验图片',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'imgUrl',
+            slot: 'imgUrl',
+            align: 'center',
+            label: '附件',
+            showOverflowTooltip: true
+          },
+          {
+            minWidth: 100,
+            prop: 'action',
+            align: 'center',
+            label: '操作',
+            showOverflowTooltip: true
+          }
+        ],
+        qualityResultsList: [
+          {
+            value: 1,
+            label: '合格'
+          },
+          {
+            value: 2,
+            label: '不合格'
+          },
+          {
+            value: 3,
+            label: '让步接收'
+          }
+        ],
+        sList: [] //质检工具筛选
+      };
+    },
+    computed: {
+      getSampleQuantityCount() {
+        return (
+          this.form.sampleQuantity -
+          this.form.lossNumber -
+          this.form.lossNumberUnqualified -
+          this.form.retainedSampleQuantity -
+          this.form.retainedSampleUnqualified
+        );
+      }
+    },
+
+    created() {
+      this.requestDict('质检计划类型');
+      this.requestDict('取样类型');
+      this.requestDict('质检标准类型');
+    },
+    methods: {
+      async open({ workData, row, list }, type) {
+        this.tableData = [];
+        if (type == 'report') {
+          let data = { ...workData, ...row };
+          data.sampleQuantity = row.sampleQuantity || data.remainingSampleCount;
+          this.$set(this, 'form', JSON.parse(JSON.stringify(data)));
+          this.tableData = JSON.parse(JSON.stringify(list));
+          this.tableData.forEach((item, index) => {
+            item.executionMethod = item.executionMethod || 1;
+          });
+        } else {
+          this.$set(this, 'form', JSON.parse(JSON.stringify(workData)));
+          this.tableData = JSON.parse(JSON.stringify(list));
+        }
+
+        this.visible = true;
+      },
+      formSampleQuantityChange() {
+        if (this.form.sampleQuantity > this.form.remainingSampleCount) {
+          this.form.sampleQuantity = this.form.remainingSampleCount;
+        }
+        if (
+          this.form.sampleQuantity <
+          Math.max(...this.tableData.map((item) => item.sampleQuantity))
+        ) {
+          this.tableData.forEach((item, index) => {
+            this.resetData(item, index, [
+              'qualifiedQuantity',
+              'noQualifiedQuantity',
+              'sampleQuantity'
+            ]);
+          });
+        }
+        this.form.sampleQualifiedNumber = 0;
+        this.form.sampleNoQualifiedNumber = 0;
+      },
+      formSampleNoQualifiedNumberChange() {
+        if (this.form.sampleNoQualifiedNumber > this.form.sampleQuantity) {
+          this.form.sampleNoQualifiedNumber = this.form.sampleQuantity;
+        }
+        this.form.sampleQualifiedNumber =
+          this.form.sampleQuantity - this.form.sampleNoQualifiedNumber;
+      },
+
+      handleClose() {
+        this.visible = false;
+      },
+      handleConfirm() {
+        this.$emit('success', { data: this.form, tableData: this.tableData });
+        this.visible = false;
+      },
+      inputValue(type, item, index) {
+        //样品数
+        if (type == 'sampleQuantity') {
+          this.isSampleQuantity(item, index);
+        }
+        //样品合格数、不合格数
+        if (type == 'qualifiedQuantity' || type == 'noQualifiedQuantity') {
+          this.isQualifiedQuantity(item, index, type);
+        }
+        //损耗数
+        if (type == 'lossNumber' || type == 'lossNumberUnqualified') {
+          this.setNumber(item, index, type, '损耗', 'lossNumber');
+        }
+        //留样数
+        if (
+          type == 'retainedSampleQuantity' ||
+          type == 'retainedSampleUnqualified'
+        ) {
+          this.setNumber(item, index, type, '留样', 'retainedSampleQuantity');
+        }
+      }
+    }
+  };
+</script>
+
+<style scoped lang="scss">
+  ::v-deep .warn {
+    color: red;
+    .el-input__inner {
+      color: red;
+    }
+  }
+</style>

+ 392 - 0
src/views/inspectionWork/components/inspectionWorkDialog.vue

@@ -0,0 +1,392 @@
+<template>
+  <ele-modal
+    title="选择工单"
+    custom-class="ele-dialog-form long-dialog-form"
+    :visible.sync="visible"
+    :before-close="handleClose"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    width="70%"
+    :maxable="true"
+    :resizable="true"
+  >
+    <el-card shadow="never">
+      <seek-page
+        :seekList="seekList"
+        @search="search"
+        ref="search"
+        :keyValue="'qms-inspectionWork-index-search'"
+      ></seek-page>
+      <ele-pro-table
+        ref="table"
+        :columns="columns"
+        :datasource="datasource"
+        :pageSize="20"
+        :pageSizes="[20, 30, 40, 50, 100]"
+        row-key="id"
+        @cell-click="cellClick"
+      >
+        <!-- 表头工具栏 -->
+        <template v-slot:action="{ row }">
+          <el-radio  class="radio" v-model="radio" :label="row.id"
+            ><i></i
+          ></el-radio>
+        </template>
+        <template v-slot:sourceCode="{ row }">
+          <div>{{
+            row.qualityPlanCode ? row.qualityPlanCode : row.workOrderCode
+          }}</div>
+        </template>
+
+        <template v-slot:qualityType="{ row }">{{
+          getDictValue('质检计划类型', row.qualityType)
+        }}</template>
+        <template v-slot:qualityMode="{ row }">{{
+          getDictValue('取样类型', row.qualityMode)
+        }}</template>
+      </ele-pro-table>
+    </el-card>
+
+    <div class="btns" slot="footer">
+      <el-button type="primary" size="small" @click="selected">选择</el-button>
+      <el-button size="small" @click="handleClose">关闭</el-button>
+    </div>
+  </ele-modal>
+</template>
+
+<script>
+  import { getList } from '@/api/inspectionWork';
+  import dictMixins from '@/mixins/dictMixins';
+
+  export default {
+    mixins: [dictMixins],
+
+    components: {},
+    props: {},
+    data() {
+      return {
+        visible: false,
+        radio: null,
+        current: {},
+        columns: [
+          {
+            action: 'action',
+            slot: 'action',
+            align: 'center',
+            label: '选择',
+            minWidth: 100
+          },
+          {
+            type: 'index',
+            columnKey: 'index',
+            align: 'center',
+            label: '序号',
+            width: 55,
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+
+          {
+            prop: 'code',
+            label: '质检工单编码',
+            slot: 'code',
+            align: 'center',
+            width: 180,
+            showOverflowTooltip: true,
+            fixed: 'left'
+          },
+          {
+            prop: 'name',
+            slot: 'name',
+            width: 120,
+            label: '质检工单名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            label: '来源单号',
+            prop: 'sourceCode',
+            slot: 'sourceCode',
+            align: 'center',
+            width: 160,
+            showOverflowTooltip: true
+          },
+          {
+            label: '类型',
+            prop: 'qualityType',
+            slot: 'qualityType',
+            align: 'center',
+            width: 120,
+            showOverflowTooltip: true
+          },
+          {
+            label: '质检方式',
+            prop: 'qualityMode',
+            slot: 'qualityMode',
+            align: 'center',
+            width: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityName',
+            label: '质检人',
+            align: 'center',
+            width: 120,
+            showOverflowTooltip: true,
+            formatter: (row) => {
+              if (row.qualityName) {
+                return row.qualityName;
+              }
+              return row.qualityNames || '';
+            }
+          },
+          {
+            prop: 'qualityTime',
+            label: '质检时间',
+            align: 'center',
+            width: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productCode',
+            width: 120,
+            label: '编码',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productName',
+            width: 120,
+            label: '名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'batchNo',
+            label: '批次号',
+            align: 'center',
+            width: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'specification',
+            label: '规格',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'brandNo',
+            label: '牌号',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'produceTaskName',
+            label: '工序',
+            align: 'center',
+            width: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'total',
+            label: '总数量',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualifiedNumber',
+            label: '合格数',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualificationRate',
+            label: '合格率',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'noQualifiedNumber',
+            label: '不合格数',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'noQualificationRate',
+            label: '不合格率',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'hours',
+            label: '工时',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            label: '附件',
+            prop: 'accessory',
+            align: 'center',
+            slot: 'accessory',
+            showOverflowTooltip: true
+          },
+          {
+            label: '创建时间',
+            prop: 'createTime',
+            align: 'center',
+            width: 160
+          },
+          {
+            prop: 'status',
+            label: '状态',
+            align: 'center',
+            width: 80,
+            formatter: (row, column, cellValue) => {
+              // 状态(0未报工;1已报工;2已关闭;3待取样)
+              switch (cellValue) {
+                case 0:
+                  return '未报工';
+                case 1:
+                  return '已报工';
+                case 2:
+                  return '已关闭';
+                case 3:
+                  return '待取样';
+                default:
+                  return '';
+              }
+            },
+            fixed: 'right'
+          }
+        ]
+      };
+    },
+    created() {
+      this.requestDict('质检计划类型');
+      this.requestDict('不良品处理类型');
+      this.requestDict('取样类型');
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            label: '工单编码:',
+            value: 'code',
+            type: 'input',
+            placeholder: ''
+          },
+          {
+            label: '工单名称:',
+            value: 'name',
+            type: 'input',
+            placeholder: ''
+          },
+          {
+            label: '来源单号:',
+            value: 'sourceCode',
+            type: 'input',
+            placeholder: ''
+          },
+
+          {
+            label: '编码:',
+            value: 'productCode',
+            type: 'input',
+            placeholder: ''
+          },
+          {
+            label: '名称:',
+            value: 'productName',
+            type: 'input',
+            placeholder: ''
+          },
+          {
+            label: '质检人:',
+            value: 'qualityName',
+            type: 'input',
+            placeholder: ''
+          },
+          {
+            label: '状态:',
+            value: 'status',
+            type: 'select',
+            placeholder: '',
+            planList: this.statusList
+          }
+        ];
+      }
+    },
+    methods: {
+      open() {
+        this.visible = true;
+      },
+
+      async datasource({ page, where, limit }) {
+        return getList({
+          ...where,
+          pageNum: page,
+          size: limit,
+          statusList: '0,3'
+        });
+      },
+      search(where) {
+        this.$refs.table.reload({
+          where: where
+          // page: 1
+        });
+      },
+      // 单击获取id
+      cellClick(row) {
+        this.current = row;
+        console.log(row);
+        this.radio = row.id;
+      },
+      handleClose() {
+        this.visible = false;
+        this.current = null;
+        this.radio = '';
+      },
+
+      selected() {
+        if (!this.current) {
+          return this.$message.warning('请至少选择一条数据');
+        }
+        this.$emit('changeParent', this.current);
+        this.handleClose();
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .tree_col {
+    border: 1px solid #eee;
+    padding: 10px 0;
+    box-sizing: border-box;
+    height: 500px;
+    overflow: auto;
+  }
+
+  .table_col {
+    padding-left: 10px;
+
+    ::v-deep .el-table th.el-table__cell {
+      background: #f2f2f2;
+    }
+  }
+
+  .pagination {
+    text-align: right;
+    padding: 10px 0;
+  }
+
+  .btns {
+    text-align: center;
+    padding: 10px 0;
+  }
+
+  .topsearch {
+    margin-bottom: 15px;
+  }
+</style>

+ 59 - 12
src/views/inspectionWork/components/newQualityContentTabs.vue

@@ -36,7 +36,7 @@
           height="500px"
         >
           <!-- :pagination="true" -->
-          <template
+          <!-- <template
             v-slot:toolbar
             v-if="form.qualityMode == 2 && type != 'detail'"
           >
@@ -47,7 +47,7 @@
                 <el-dropdown-item command="2">取小样</el-dropdown-item>
               </el-dropdown-menu>
             </el-dropdown>
-          </template>
+          </template> -->
           <template v-slot:toolkit v-if="form.qualityMode == 2">
             <el-row>
               <el-form
@@ -278,6 +278,7 @@
             align="center"
             fixed="right"
             :show-overflow-tooltip="true"
+            v-if="form.recordingMethod == 2"
           >
             <template slot-scope="scope">
               <span v-if="scope.row.qualityStatus == 0">未检</span>
@@ -292,6 +293,7 @@
             width="180"
             fixed="right"
             :show-overflow-tooltip="true"
+            v-if="form.recordingMethod == 2"
           >
             <template slot-scope="scope">
               <el-select
@@ -317,7 +319,7 @@
             align="center"
             width="120"
             fixed="right"
-            v-if="type != 'detail'"
+            v-if="type != 'detail' && form.recordingMethod == 2"
           >
             <template slot-scope="scope">
               <el-link
@@ -416,14 +418,56 @@
               </div>
             </template>
           </el-table-column>
-
           <el-table-column
-            fixed="right"
-            label="操作"
-            width="80"
-            v-if="type !== 'detail'"
+            label="质检状态"
+            prop="qualityStatus"
+            align="center"
+            :show-overflow-tooltip="true"
+            v-if="form.recordingMethod == 1"
           >
             <template slot-scope="scope">
+              <span v-if="scope.row.qualityStatus == 0">未检</span>
+              <span v-if="scope.row.qualityStatus == 1">已检</span>
+              <span v-if="scope.row.qualityStatus == 2">待检</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            label="质检结果"
+            prop="qualityResults"
+            align="center"
+            width="180"
+            :show-overflow-tooltip="true"
+            v-if="form.recordingMethod == 1"
+          >
+            <template slot-scope="scope">
+              <el-select
+                @change="selectQualityResultsChange"
+                v-model="scope.row.qualityResults"
+                placeholder="请选择"
+                style="width: 100%"
+                :disabled="type == 'detail'"
+                size="mini"
+              >
+                <el-option
+                  v-for="item in qualityResultsList"
+                  :key="item.value"
+                  :label="item.label"
+                  :value="item.value"
+                >
+                </el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="操作" width="150" v-if="type !== 'detail'">
+            <template slot-scope="scope">
+              <!-- <el-link
+                v-if="form.recordingMethod == 1"
+                :type="scope.row.isValid ? 'primary' : 'danger'"
+                :underline="false"
+                @click="inspectionProjectReport(scope.$index, scope.row)"
+              >
+                质检
+              </el-link> -->
               <el-popconfirm
                 class="ele-action"
                 title="确定要删除当前方案吗?"
@@ -614,7 +658,7 @@
             align: 'center',
             showOverflowTooltip: true
           },
-            {
+          {
             label: '型号',
             prop: 'modelType',
             align: 'center',
@@ -898,8 +942,8 @@
           data['qualitySampleTemplateList'] = [];
           data['id'] = '';
           data['weight'] = parseFloat(weight).toFixed(2);
-          let code=await getCodeList('sample_code',{count:1});
-          data['sampleCode'] = code[0]
+          let code = await getCodeList('sample_code', { count: 1 });
+          data['sampleCode'] = code[0];
           arr.push(data);
         }
         this.$set(
@@ -1174,7 +1218,10 @@
       handleSchemeCurrentChange(val) {
         this.schemePagination.currentPage = val;
       },
-
+      //质检项报工
+      inspectionProjectReport(index, row) {
+        this.$emit('inspectionProjectReport', { index, list: [row] });
+      },
       selectQualityResultsChange() {
         this.$emit('countQualityResults');
       },

+ 5 - 157
src/views/inspectionWork/components/sampleListDialog.vue

@@ -127,7 +127,7 @@
                     placeholder="请输入内容"
                     :disabled="type == 'detail'"
                     @input="
-                      handleInput(scope.row, scope.row.qualityResultContent)
+                      handleInput(scope.row, scope.row.qualityResultContent,tableData)
                     "
                   >
                     <template slot="append" v-if="scope.row.unitName">
@@ -147,7 +147,7 @@
                     v-model="scope.row.qualityResults"
                     placeholder="请选择"
                     style="width: 100%"
-                    @change="qualityResultsListChange"
+                    @change="qualityResultsListChange(tableData)"
                     :disabled="type == 'detail'"
                   >
                     <el-option
@@ -212,14 +212,15 @@
 </template>
 
 <script>
-  import index from 'ele-admin/lib/ele-avatar-list';
   import toolButtom from './toolButtom.vue';
+  import {handleInput,qualityResultsListChange} from './unit.js';
   export default {
     components: {
       toolButtom
     },
     data() {
       return {
+        handleInput,qualityResultsListChange,
         title: '',
         visible: false,
         rowIndex: 0,
@@ -341,161 +342,8 @@
 
         this.visible = true;
       },
-      qualityResultsListChange() {
-        this.tableData.forEach((item, index) => {
-          this.$set(
-            this.tableData[index],
-            'qualityResults',
-            this.getQuality(item.qualitySampleTemplateList)
-          );
-        });
-      },
-      getQuality(arr) {
-        let getQualityValue = 1;
-        arr.forEach((item) => {
-          if (item.qualityResults == 2) {
-            getQualityValue = 2;
-          }
-        });
-        return getQualityValue;
-      },
-      inputResultContent(e, row) {
-        console.log(row, 'row row row');
-        if (row.textType == '1') {
-          if (!row.symbol) {
-            if (row.qualityResultContent != row.defaultValue) {
-              this.$set(row, 'qualityResults', 2);
-            } else {
-              this.$set(row, 'qualityResults', 1);
-            }
-            return;
-          }
-          let key = this.mathematicalJudgment(row);
-          this.$set(row, 'qualityResults', key);
-          return;
-        }
-
-        if (row.textType == '3') {
-          let num = Number(row.qualityResultContent);
-          if (num == NaN) {
-            this.$set(row, 'qualityResults', 2);
-            return;
-          }
-          console.log(num, 'num');
-          if (num >= Number(row.minValue) && num <= Number(row.maxValue)) {
-            this.$set(row, 'qualityResults', 1);
-          } else {
-            this.$set(row, 'qualityResults', 2);
-          }
-        }
-      },
-      // 数学判断
-      mathematicalJudgment(row) {
-        console.log('进来没有', row);
-        let symbol = row.symbol?.trim(); // 符号
-        let Ivalue = Number(row.qualityResultContent); // 输入的值
-        let Dvalue = Number(row.defaultValue); // 判断的值
-        if (Ivalue == NaN || Dvalue == NaN) {
-          return 2;
-        }
-        if (symbol == '±') {
-          if (Math.abs(Ivalue) != Math.abs(Dvalue)) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
-
-        if (symbol == '≤' || symbol == '≦') {
-          if (Ivalue <= Dvalue) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
-
-        if (symbol == '≥' || symbol == '≧') {
-          if (Ivalue >= Dvalue) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
 
-        if (symbol == '≈' || symbol == '=') {
-          console.log('进来等于号');
-          if (Ivalue == Dvalue) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
-
-        if (symbol == '≠') {
-          if (Ivalue != Dvalue) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
-
-        if (symbol == '>') {
-          if (Ivalue > Dvalue) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
-        if (symbol == '<') {
-          if (Ivalue < Dvalue) {
-            return 1;
-          } else {
-            return 2;
-          }
-        }
-
-        return 2;
-      },
-
-      handleInput(item, value) {
-        console.log(item,'item')
-        if (value) {
-          if (item.textType == '1') {
-            if (!item.symbol) {
-              if (item.qualityResultContent != item.defaultValue) {
-                this.$set(item, 'qualityResults', 2);
-              } else {
-                this.$set(item, 'qualityResults', 1);
-              }
-              this.qualityResultsListChange();
-              return;
-            }
-            let key = this.mathematicalJudgment(item);
-            this.$set(item, 'qualityResults', key);
-            this.qualityResultsListChange();
-          }
-
-          if (item.textType == '3') {
-            let num = Number(item.qualityResultContent);
-            if (num == NaN) {
-              this.$set(item, 'qualityResults', 2);
-              this.qualityResultsListChange();
-              return;
-            }
-            console.log(num, 'num');
-            if (num >= Number(item.minValue) && num <= Number(item.maxValue)) {
-              this.$set(item, 'qualityResults', 1);
-              this.qualityResultsListChange();
-            } else {
-              this.$set(item, 'qualityResults', 2);
-              this.qualityResultsListChange();
-            }
-          }
-        } else {
-          this.$set(item, 'qualityResults', 1);
-          this.qualityResultsListChange();
-        }
-      },
+  
 
       handleClose() {
         this.visible = false;

+ 132 - 0
src/views/inspectionWork/components/unit.js

@@ -0,0 +1,132 @@
+import Vue from 'vue';
+
+//改变数量
+export function handleInput(item, value, arr) {
+  console.log('进来没有', item, value, arr);
+  if (value) {
+    if (item.textType == '1') {
+      if (!item.symbol) {
+        if (item.qualityResultContent != item.defaultValue) {
+          Vue.set(item, 'qualityResults', 2);
+        } else {
+          Vue.set(item, 'qualityResults', 1);
+        }
+        qualityResultsListChange(arr);
+        return;
+      }
+      let key = mathematicalJudgment(item);
+      Vue.set(item, 'qualityResults', key);
+      qualityResultsListChange(arr);
+    }
+
+    if (item.textType == '3') {
+      let num = Number(item.qualityResultContent);
+      if (num == NaN) {
+        Vue.set(item, 'qualityResults', 2);
+        qualityResultsListChange(arr);
+        return;
+      }
+      if (num >= Number(item.minValue) && num <= Number(item.maxValue)) {
+        Vue.set(item, 'qualityResults', 1);
+        qualityResultsListChange(arr);
+      } else {
+        Vue.set(item, 'qualityResults', 2);
+        qualityResultsListChange(arr);
+      }
+    }
+  } else {
+    Vue.set(item, 'qualityResults', 1);
+    qualityResultsListChange(arr);
+  }
+}
+
+export function qualityResultsListChange(arr) {
+  if (!arr) {
+    return;
+  }
+
+  arr.forEach((item, index) => {
+    Vue.set(
+      arr[index],
+      'qualityResults',
+      getQuality(item.qualitySampleTemplateList)
+    );
+  });
+}
+function getQuality(arr) {
+  let getQualityValue = 1;
+  arr.forEach((item) => {
+    if (item.qualityResults == 2) {
+      getQualityValue = 2;
+    }
+  });
+  return getQualityValue;
+}
+
+// 数学判断
+function mathematicalJudgment(row) {
+  console.log('进来没有', row);
+  let symbol = row.symbol?.trim(); // 符号
+  let Ivalue = Number(row.qualityResultContent); // 输入的值
+  let Dvalue = Number(row.defaultValue); // 判断的值
+  if (Ivalue == NaN || Dvalue == NaN) {
+    return 2;
+  }
+  if (symbol == '±') {
+    if (Math.abs(Ivalue) != Math.abs(Dvalue)) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+
+  if (symbol == '≤' || symbol == '≦') {
+    if (Ivalue <= Dvalue) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+
+  if (symbol == '≥' || symbol == '≧') {
+    if (Ivalue >= Dvalue) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+
+  if (symbol == '≈' || symbol == '=') {
+    console.log('进来等于号');
+    if (Ivalue == Dvalue) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+
+  if (symbol == '≠') {
+    if (Ivalue != Dvalue) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+
+  if (symbol == '>') {
+    if (Ivalue > Dvalue) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+  if (symbol == '<') {
+    if (Ivalue < Dvalue) {
+      return 1;
+    } else {
+      return 2;
+    }
+  }
+
+  return 2;
+}

+ 1 - 2
src/views/inspectionWork/details.vue

@@ -299,12 +299,11 @@
   import detailMixins from './mixins/detailMixins';
   import { parameterGetByCode } from '@/api/main/index';
   import { getUserPage } from '@/api/system/organization';
-  import fileMain from '@/components/addDoc/main.vue';
   import sampleListDialog from './components/sampleListDialog.vue';
 
   export default {
     mixins: [detailMixins],
-    components: { fileMain, sampleListDialog },
+    components: {sampleListDialog },
     data() {
       return {
         activeName: '1',

+ 99 - 16
src/views/inspectionWork/edit.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="ele-body">
-    <div class="switch" v-if="this.qualityType==2">
+    <div class="switch" v-if="this.qualityType == 2">
       <div class="switch_left">
         <ul>
           <li
@@ -47,7 +47,7 @@
       ></base-info>
 
       <header-title title="样品信息"></header-title>
-      <el-form label-width="110px">
+      <el-form label-width="130px">
         <el-row>
           <el-col :span="6">
             <el-form-item label="样品合格数:" prop="sampleQualifiedNumber">
@@ -91,6 +91,14 @@
               <el-input disabled :value="sampletypeVal(form.conditionType)" />
             </el-form-item>
           </el-col>
+          <el-col :span="6">
+            <el-form-item label="记录方法:" prop="samplesType">
+              <el-input
+                disabled
+                :value="form.recordingMethod == 1 ? '批样' : '单样全部'"
+              />
+            </el-form-item>
+          </el-col>
           <el-col :span="6">
             <el-form-item label="样品数量:" prop="sampleQuantity">
               <el-input type="number" disabled v-model="form.sampleQuantity" />
@@ -102,6 +110,34 @@
             </el-form-item>
           </el-col>
         </el-row>
+        <el-row v-if="form.recordingMethod == 1">
+          <el-col :span="6">
+            <el-form-item label="留样数(合格品):" prop="retainedSampleQuantity">
+              <el-input disabled v-model="form.retainedSampleQuantity" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item
+              label="留样数(不合格品):"
+              prop="retainedSampleUnqualified"
+            >
+              <el-input disabled v-model="form.retainedSampleUnqualified" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="损耗数(合格品):" prop="lossNumbe">
+              <el-input disabled v-model="form.lossNumbe" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item
+              label="损耗数(不合格品):"
+              prop="lossNumberUnqualified"
+            >
+              <el-input disabled v-model="form.lossNumberUnqualified" />
+            </el-form-item>
+          </el-col>
+        </el-row>
       </el-form>
       <quality-content-tabs
         v-if="form.id"
@@ -128,6 +164,7 @@
         @countQualityResults="countQualityResults"
         @setSchemeList="setSchemeList"
         @sampleListChange="sampleListChange"
+        @inspectionProjectReport="inspectionProjectReport"
       />
     </el-card>
     <pickOrderList
@@ -148,6 +185,10 @@
       @close="closeDispose"
       @handleDispose="handleDispose"
     ></sampleDisposeDialog>
+    <inspectionProjectReport
+      ref="inspectionProjectReportRef"
+      @success="inspectionProjectReportSuccess"
+    ></inspectionProjectReport>
   </div>
 </template>
 
@@ -173,6 +214,7 @@
   // import term from './term';
   import sampleListDialog from './components/sampleListDialog.vue';
   import sampleDisposeDialog from './components/sampleDisposeDialog.vue';
+  import inspectionProjectReport from './components/inspectionProjectReport.vue';
 
   import { finishPageTab } from '@/utils/page-tab-util';
   export default {
@@ -181,7 +223,8 @@
       QualityContentTabs,
       sampleListDialog,
       sampleDisposeDialog,
-      pickOrderList
+      pickOrderList,
+      inspectionProjectReport
     },
     mixins: [dictMixins],
     computed: {
@@ -233,7 +276,18 @@
           templateList: [],
           qualityIdList: [],
           sampleMeasureUnit: '',
-          conditionType: null
+          conditionType: null,
+          taskMonadInfo: {
+            lossNumber: 0,
+            lossNumberUnqualified: 0,
+            retainedSampleQuantity: 0,
+            retainedSampleUnqualified: 0,
+            sampleNoQualifiedNumber: 0,
+            sampleQualifiedNumber: 0,
+            sampleQuantity: 0,
+            type: 2,
+            qualityWorkOrderId: ''
+          }
         };
       };
       return {
@@ -347,7 +401,6 @@
 
       //
       calculate(list) {
-      
         if (list.length == 0) {
           this.form.sampleQuantity = 0;
           this.form.sampleWeight = 0;
@@ -417,7 +470,6 @@
             this.$set(this.form, 'qualifiedNumber', this.form.total);
             this.$set(this.form, 'noQualifiedNumber', 0);
           } else {
-      
             this.$set(this.form, 'qualificationRate', '0');
             this.$set(this.form, 'noQualificationRate', '100%');
             this.$set(this.form, 'qualityResults', 2);
@@ -679,6 +731,42 @@
         this.calculate(this.sampleList);
         this.sampleNumber = this.sampleList.length;
       },
+      //质检项报工
+      inspectionProjectReport({ index, list }) {
+        this.$nextTick(() => {
+          this.$refs.inspectionProjectReportRef.open({
+            workData: {
+              qualityWorkOrderCode: this.form.code,
+              qualityWorkOrderName: this.form.name,
+              qualityWorkOrderId: this.form.id,
+              sourceCode: this.form.sourceCode,
+              qualityType: this.form.qualityType,
+              qualityMode: this.form.qualityMode,
+              productCode: this.form.productCode,
+              productName: this.form.productName,
+              batchNo: this.form.batchNo,
+              specification: this.form.specification,
+              brandNo: this.form.brandNo,
+              produceTaskName: this.form.produceTaskName,
+              total: this.form.total,
+              hours: this.form.hours,
+              accessory: this.form.accessory,
+              qualityNames: this.form.qualityNames,
+              qualityTimeEnd: this.form.qualityTimeEnd,
+              remainingSampleCount: this.form.remainingSampleCount
+            },
+            row: this.form.taskMonadInfo || {},
+            list
+          },'report');
+        });
+      },
+      //质检项报工回调
+      inspectionProjectReportSuccess({ data, tableData }) {
+        this.schemeList = tableData;
+        data.type = 2;
+        this.form.taskMonadInfo = data;
+        this.form.hours = data.hours;
+      },
       // 切换检验方式为全检后生成样品
       changeGetSampleList(list) {
         this.$message.closeAll();
@@ -1505,20 +1593,14 @@
       },
       // 批量质检
       batchQuality(index, row, type) {
-        // if (this.form.sampleList.qualitySampleTemplateList.length == 0) {
-        //   this.form.sampleList.forEach((item, index) => {
-        //     this.$set(
-        //       this.form.sampleList[index],
-        //       'qualitySampleTemplateList',
-        //       this.form.templateList
-        //     );
-        //   });
-        // }
-
         if (this.sampleList.length == 0) {
           this.$message.error('样品清单不能为空');
           return;
         }
+        if (this.form.recordingMethod == 1) {
+          this.inspectionProjectReport({ index: -1, list: this.schemeList });
+          return;
+        }
 
         if (this.schemeList.length != 0) {
           this.sampleList.forEach((item, index) => {
@@ -1958,6 +2040,7 @@
         );
         this.calculate(this.sampleList);
       },
+
       closeDispose() {
         this.rowData = null;
         this.sampleDisposeVisble = false;

+ 42 - 12
src/views/inspectionWork/index.vue

@@ -80,6 +80,10 @@
             type="primary"
             :underline="false"
             @click="addSampleOpen(row)"
+            v-if="
+              $hasPermission('qms:samplingrecord:save') &&
+              ![1, 2].includes(row.status)
+            "
             >取样</el-link
           >
           <el-link
@@ -97,7 +101,20 @@
             @click="openTransfer(row.id)"
             >转派</el-link
           >
-
+          <el-link
+            type="primary"
+            :underline="false"
+            v-if="row.status == 0 && row.recordingMethod == 1"
+            @click="qualityInspectionSend(row,1)"
+            >质检项派单</el-link
+          >
+          <el-link
+            type="primary"
+            :underline="false"
+            v-if="row.status == 0 && row.recordingMethod == 1"
+            @click="qualityInspectionSend(row,2)"
+            >质检项请托</el-link
+          >
           <el-link type="primary" :underline="false" @click="openNumber(row)"
             >合格证</el-link
           >
@@ -158,16 +175,20 @@
     ></process-submit-dialog>
 
     <addSample ref="addSampleRef" @reload="search"></addSample>
+    <inspectionProjectTaskSend
+      ref="inspectionProjectTaskSendRef"
+      @reload="search"
+    ></inspectionProjectTaskSend>
   </div>
 </template>
 <script>
   import Certificate from './components/Certificate.vue';
   import search from './components/search.vue';
-  import addSample from './components/addSample.vue';
-
+  import addSample from '@/views/sample/sampleRecord/components/addSample.vue';
   import jimureportBrowse from '@/components/jimureport/browseModal.vue';
   import Transfer from './components/transfer.vue';
   import processSubmitDialog from '@/components/processSubmitDialog/processSubmitDialog.vue';
+  import inspectionProjectTaskSend from '@/views/inspectionProjectTask/components/inspectionProjectTaskSend.vue';
   import {
     getList,
     removeItem,
@@ -192,7 +213,8 @@
       Certificate,
       Transfer,
       processSubmitDialog,
-      addSample
+      addSample,
+      inspectionProjectTaskSend
     },
     data() {
       return {
@@ -463,16 +485,16 @@
           {
             label: '类型:',
             value: 'qualityType',
-            type: 'select',
-            placeholder: '',
-            planList: this.typeList
+            type: 'DictSelection',
+            dictName: '质检计划类型',
+            placeholder: ''
           },
           {
             label: '质检方式:',
             value: 'qualityMode',
-            type: 'select',
-            placeholder: '',
-            planList: this.qualityMode
+            type: 'DictSelection',
+            dictName: '取样类型',
+            placeholder: ''
           },
           {
             label: '编码:',
@@ -509,8 +531,12 @@
       selectionChangeHandle(val) {
         this.selection = val;
       },
-      addSampleOpen(row) {
-        this.$refs.addSampleRef.open(row);
+      async addSampleOpen(row) {
+        const code = await verificationQualityInspector(row.id);
+        if (code == '-1') {
+          return;
+        }
+        this.$refs.addSampleRef.open('add', row);
       },
       // 批量关闭
       batchClose() {
@@ -568,6 +594,10 @@
           this.isReportApproval = res.value;
         });
       },
+      //质检项派单
+      qualityInspectionSend(row,type) {
+        this.$refs.inspectionProjectTaskSendRef.open(row,type);
+      },
       async datasource({ page, where, limit }) {
         try {
           await queryTodo({});

+ 82 - 2
src/views/inspectionWork/mixins/detailMixins.js

@@ -3,6 +3,12 @@ const disposalStatustList = { 0: '待处置', 1: '处置中', 2: '处置完成'
 export default {
   data() {
     return {
+      keyArr: [
+        'lossNumber',
+        'lossNumberUnqualified',
+        'retainedSampleQuantity',
+        'retainedSampleUnqualified'
+      ],
       infoList: [
         {
           label: '编码',
@@ -508,7 +514,7 @@ export default {
           width: '120',
           showOverflowTooltip: true
         },
-             {
+        {
           label: '机型',
           prop: 'modelKey',
           align: 'center',
@@ -630,7 +636,7 @@ export default {
           width: '120',
           showOverflowTooltip: true
         },
-             {
+        {
           label: '机型',
           prop: 'modelKey',
           align: 'center',
@@ -714,5 +720,79 @@ export default {
         }
       ]
     };
+  },
+  methods: {
+    //样品数操作
+    isSampleQuantity(item, index) {
+      this.resetData(item, index, ['qualifiedQuantity', 'noQualifiedQuantity']);
+      if (item.sampleQuantity > this.getSampleQuantityCount) {
+        this.$message.error('样品数量不能大于当前质检剩余样品数');
+        this.$set(
+          this.tableData[index],
+          'sampleQuantity',
+          this.getSampleQuantityCount
+        );
+      }
+    },
+    //合格/不合格数操作
+    isQualifiedQuantity(item, index, key) {
+      console.log(item, 'item[key]');
+      if (item[key] > item.sampleQuantity) {
+        this.$message.error(
+          (key == 'qualifiedQuantity' ? '合格' : '不合格') +
+            '数量不能大于样品数'
+        );
+        this.$set(this.tableData[index], key, item.sampleQuantity);
+      }
+      this.$set(
+        this.tableData[index],
+        key == 'qualifiedQuantity'
+          ? 'noQualifiedQuantity'
+          : 'qualifiedQuantity',
+        item.sampleQuantity - item[key]
+      );
+
+      this.resetData(item, index);
+    },
+
+    //留样、损耗逻辑
+    setNumber(item, index, key, title, keyName) {
+      let keyObj = {
+        key: key == keyName ? 'qualifiedQuantity' : 'noQualifiedQuantity',
+        title: key == keyName ? '合格数' : '不合格数'
+      };
+      if (item[key] > item[keyObj.key]) {
+        this.$message.error(
+          title + keyObj.title + '不能大于样品' + keyObj.title
+        );
+        this.$set(this.tableData[index], key, 0);
+      }
+      if (item[key] - (this.curretNum || 0) > this.getSampleQuantityCount) {
+        this.$message.error(
+          title + keyObj.title + '不能大于当前质检剩余样品数'
+        );
+        this.$set(this.tableData[index], key, 0);
+      }
+      this.curretNum = this.tableData[index][key];
+      this.initData();
+    },
+
+    //重置数据
+    resetData(item, index, addResetData = []) {
+      [...this.keyArr, ...addResetData].forEach((key) => {
+        this.$set(this.tableData[index], key, 0);
+      });
+      this.initData();
+    },
+    initData() {
+      this.keyArr.forEach((key) => {
+        this.$set(this.form, key, 0);
+      });
+      this.tableData.forEach((item, index) => {
+        this.keyArr.forEach((key) => {
+          this.form[key] += Number(item[key]) || 0;
+        });
+      });
+    }
   }
 };

+ 396 - 87
src/views/inspectionWork/components/addSample.vue → src/views/sample/sampleRecord/components/addSample.vue

@@ -1,28 +1,55 @@
 <template>
   <ele-modal
     :visible.sync="visible"
-    title="取样"
+    :title="title"
     width="80%"
     append-to-body
     :maxable="true"
+    @close="cancel"
   >
+    <div class="switch" v-if="type == 'view'">
+      <div class="switch_left">
+        <ul>
+          <li
+            v-for="item in tabOptions"
+            :key="item.key"
+            :class="{ active: activeComp == item.key }"
+            @click="activeComp = item.key"
+          >
+            {{ item.name }}
+          </li>
+        </ul>
+      </div>
+    </div>
     <el-form
+      v-show="activeComp === 'main'"
       ref="form"
       :model="form"
       :rules="rules"
       label-width="120px"
       class="el-form-box"
+      :disabled="type == 'view'"
     >
       <header-title title="基本信息"></header-title>
       <el-row>
         <el-col :span="8">
-          <el-form-item label="质检工单编码:" prop="code">
-            <el-input disabled v-model="form.code" placeholder=" " />
+          <el-form-item label="质检工单编码:" prop="qualityWorkOrderCode">
+            <el-input
+              :disabled="!isSampleRecord || (isSampleRecord && type != 'add')"
+              readonly
+              v-model="form.qualityWorkOrderCode"
+              placeholder=" "
+              @click.native="$refs.inspectionWorkDialog.open()"
+            />
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="质检工单名称:" prop="name">
-            <el-input disabled v-model="form.name" placeholder=" " />
+          <el-form-item label="质检工单名称:" prop="qualityWorkOrderName">
+            <el-input
+              disabled
+              v-model="form.qualityWorkOrderName"
+              placeholder=" "
+            />
           </el-form-item>
         </el-col>
 
@@ -70,18 +97,73 @@
             <el-input disabled v-model="form.brandNo" placeholder=" " />
           </el-form-item>
         </el-col>
+        <el-col :span="8">
+          <el-form-item label="总数:" prop="total">
+            <el-input disabled v-model="form.total" placeholder=" ">
+              <template slot="append">
+                {{ form.measureUnit }}
+              </template>
+            </el-input>
+          </el-form-item>
+        </el-col>
+        <!-- <el-col :span="8">
+          <el-form-item label="样品数:" prop="sampleQuantity">
+            <el-input disabled v-model="form.sampleQuantity" placeholder=" ">
+              <template slot="append">
+                {{ form.qualityMode == 1 ? form.measureUnit : form.unit }}
+              </template>
+            </el-input>
+          </el-form-item>
+        </el-col> -->
       </el-row>
       <header-title title="来源清单"></header-title>
       <ele-pro-table
         ref="sourceTable"
         :columns="tableColumns"
-        :datasource="datasource"
+        :datasource="tableList"
         :initLoad="false"
         :needPage="false"
-        height="400px"
+        height="300px"
         full-height="calc(100vh - 120px)"
         :selection.sync="selection"
-      ></ele-pro-table>
+      >
+        <template v-slot:toolbar>
+          累计取样数量:{{ workSampleQuantity }}{{ form.unit }}
+        </template>
+      </ele-pro-table>
+      <header-title title="请样信息"> </header-title>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="请样目的:" prop="pleasePurpose">
+            <el-input
+              v-model="form.pleasePurpose"
+              placeholder="请输入"
+            ></el-input>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row>
+        <el-col :span="8">
+          <el-form-item label="请样数量:" prop="pleaseQuantity">
+            <el-input v-model="form.pleaseQuantity" placeholder="请输入">
+              <template slot="append">
+                {{ form.pleaseUnit }}
+              </template>
+            </el-input>
+          </el-form-item>
+        </el-col>
+        <!-- <el-col :span="4">
+          <el-form-item label="单位:" prop="pleaseUnit">
+            <DictSelection
+              dictName="计量单位"
+              clearable
+              v-model="form.pleaseUnit"
+              filter-placeholder="请输入计量单位搜索"
+              @change="changeSamUnit"
+            ></DictSelection>
+          </el-form-item>
+        </el-col> -->
+      </el-row>
       <header-title title="取样信息"> </header-title>
       <el-row>
         <el-col :span="8">
@@ -89,15 +171,18 @@
             <DictSelection
               dictName="取样类型"
               v-model="form.qualityMode"
+              @change="handleQualityModeChange"
+              :disabled="form.isFirstSampling != '1'"
             ></DictSelection>
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="检验方法:" prop="sampleQuantity">
+          <el-form-item label="记录方法:" prop="recordingMethod">
             <el-select
               style="width: 100%"
-              v-model="form.sampleQuantity"
+              v-model="form.recordingMethod"
               placeholder="请选择"
+              :disabled="form.isFirstSampling != '1'"
             >
               <el-option
                 v-for="item in sampleQuantityList"
@@ -111,11 +196,12 @@
       </el-row>
       <el-row v-if="form.qualityMode == '2'">
         <el-col :span="8">
-          <el-form-item label="取样:" prop="sampleNumber">
+          <el-form-item label="取样:" prop="conditionType">
             <el-select
               style="width: 100%"
               v-model="form.conditionType"
               placeholder="请选择"
+              :disabled="form.isFirstSampling != '1'"
             >
               <el-option
                 v-for="item in sampleNumberList"
@@ -129,21 +215,21 @@
         <el-col :span="16">
           <el-row>
             <el-col :span="6" v-if="form.conditionType == 2">
-              <el-form-item prop="measureQ">
+              <el-form-item prop="quantity">
                 <el-input
-                  v-model="form.measureQ"
+                  v-model="form.quantity"
                   placeholder="请输入"
                 ></el-input>
               </el-form-item>
             </el-col>
             <el-col :span="6" v-if="form.conditionType == 2">
-              <el-form-item prop="sampleUnit" label-width="0">
+              <el-form-item prop="unit" label-width="0">
                 <DictSelection
                   dictName="计量单位"
                   clearable
-                  v-model="form.sampleUnit"
+                  :disabled="form.isFirstSampling != '1'"
+                  v-model="form.unit"
                   filter-placeholder="请输入计量单位搜索"
-                  @change="changeSamUnit"
                 ></DictSelection>
               </el-form-item>
             </el-col>
@@ -164,13 +250,18 @@
               </el-form-item>
             </el-col>
             <el-col :span="10" v-if="form.conditionType == 1">
-              <el-form-item prop="packingUnit" label="单位">
-                <el-select v-model="form.packingUnit" placeholder="请选择">
+              <el-form-item prop="unit" label="单位">
+                <el-select
+                  v-model="form.packingUnit"
+                  placeholder="请选择"
+                  :disabled="form.isFirstSampling != '1'"
+                >
                   <el-option
                     v-for="item in packingSpecificationOption"
                     :key="item.id"
                     :label="item.conversionUnit"
                     :value="item.id"
+                    @click.native="handlePackingUnitChange(item)"
                   >
                   </el-option>
                 </el-select>
@@ -179,7 +270,7 @@
             <el-col
               :span="4"
               style="text-align: right"
-              v-if="form.conditionType == 2"
+              v-if="form.conditionType == 2 && type != 'view'"
             >
               <el-button
                 type="primary"
@@ -192,7 +283,7 @@
             <el-col
               :span="4"
               style="text-align: right"
-              v-if="form.conditionType == 1"
+              v-if="form.conditionType == 1 && type != 'view'"
             >
               <el-button
                 type="primary"
@@ -215,14 +306,25 @@
         full-height="calc(100vh - 120px)"
       ></ele-pro-table>
     </el-form>
-
+    <bpmDetail
+      v-if="activeComp == 'bpm' && form.processInstanceId"
+      :id="form.processInstanceId"
+    ></bpmDetail>
     <template v-slot:footer>
-      <el-button type="primary" @click="save()" v-loading="loading"
+      <el-button
+        type="primary"
+        @click="save()"
+        v-loading="loading"
+        v-if="type != 'view'"
         >确认</el-button
       >
 
-      <el-button @click="cancel">关闭</el-button>
+      <el-button @click="cancel">关闭 {{ form.processInstanceId }}</el-button>
     </template>
+    <inspectionWorkDialog
+      ref="inspectionWorkDialog"
+      @changeParent="changeParent"
+    ></inspectionWorkDialog>
   </ele-modal>
 </template>
 
@@ -231,47 +333,75 @@
     code: '', //编码
     name: '', //名称
     conditionType: '',
-    measureQ: '',
-    sampleUnit: '',
-    portion: ''
+    quantity: '',
+    unit: '',
+    portion: '',
+    qualityMode: '',
+    recordingMethod: 1,
+    pleaseQuantity: '',
+    pleasePurpose: '',
+    pleaseUnit: '',
+    sampleQuantity: '',
+    qualityWorkOrderId: '',
+    qualityWorkOrderCode: '',
+    qualityWorkOrderName: '',
+    isFirstSampling: ''
   };
   import {
     queryQualityInventory,
     queryQualityTempleContent
   } from '@/api/inspectionWork';
-  import { getCodeList } from '@/api/login';
+  import {
+    samplingrecordSave,
+    getById,
+    samplingrecordUpdate,
+    samplingRecordsPage
+  } from '@/api/samplingRecords';
+  import bpmDetail from '@/views/bpm/processInstance/detail.vue';
+  import inspectionWorkDialog from '@/views/inspectionWork/components/inspectionWorkDialog.vue';
+  import { getCodeList, getCode } from '@/api/login';
   export default {
-    components: {},
+    components: { bpmDetail, inspectionWorkDialog },
+    props: {
+      isSampleRecord: {
+        default: false
+      }
+    },
     data() {
       return {
         form: { ...defForm },
+        activeComp: 'main',
+        tabOptions: [
+          { key: 'main', name: '取样详情' },
+          { key: 'bpm', name: '流程详情' }
+        ],
+        workSampleQuantity: 0,
         visible: false,
         loading: false,
         rules: {
-          name: [
-            { required: true, message: '名称不能为空', trigger: 'change' }
-          ],
-          factoriesId: [
-            { required: true, message: '请选择工厂', trigger: 'change' }
+          qualityWorkOrderCode: [
+            { required: true, message: '请选择质检工单', trigger: 'change' }
           ],
-          bomId: [
-            { required: true, message: '请选择BOM版本', trigger: 'change' }
+          qualityMode: [
+            { required: true, message: '请选择质检方式', trigger: 'change' }
           ],
-          bomCategory: [
-            { required: true, message: '请选择BOM类型', trigger: 'change' }
+          recordingMethod: [
+            { required: true, message: '请选择记录方法', trigger: 'change' }
           ],
-          produceRoutingId: [
-            { required: true, message: '请选择工艺路线', trigger: 'change' }
+          conditionType: [
+            { required: true, message: '请选择取样类型', trigger: 'change' }
           ],
-          code: [{ required: true, message: '编码不能为空', trigger: 'change' }]
+          quantity: [{ required: true, message: '请输入', trigger: 'change' }],
+          portion: [{ required: true, message: '请输入', trigger: 'change' }],
+          unit: [{ required: true, message: '请选择', trigger: 'change' }]
         },
         sampleQuantityList: [
-          { label: '依次检验', value: '1' },
-          { label: '分别检验', value: '2' }
+          { label: '批样', value: 1 },
+          { label: '单样全部', value: 2 }
         ],
         sampleNumberList: [
-          { label: '取整样', value: '1' },
-          { label: '取小样', value: '2' }
+          { label: '取整样', value: 1 },
+          { label: '取小样', value: 2 }
         ],
         selection: [],
         tableColumns1: [
@@ -478,49 +608,127 @@
         ],
         packingSpecificationOption: [],
         sampleList: [],
-        schemeList: []
+        schemeList: [],
+        tableList: [],
+        type: 'add',
+        title: ''
       };
     },
 
     computed: {},
     created() {},
     methods: {
-      async open(row) {
+      handlePackingUnitChange(val) {
+        this.$set(this.form, 'unit', val.conversionUnit);
+      },
+      async open(type, row) {
+        this.activeComp = 'main';
         this.visible = true;
-        row.sourceCode = row.qualityPlanCode || row.workOrderCode;
-        this.form = row;
-        this.queryQualityTempleContent();
-        this.$nextTick(() => {
-          this.$refs.sourceTable.reload({
-            page: 1,
-            where: { qualityWorkerId: row.id }
+        this.type = type;
+        this.title =
+          type == 'add' ? '取样' : type == 'edit' ? '修改取样' : '详情';
+        if (type == 'add') {
+          if (row) {
+            this.init(row);
+          }
+        } else {
+          this.getById(row.id);
+        }
+      },
+      async init(row) {
+        let data = await samplingRecordsPage({
+          qualityWorkOrderId: row.id
+        });
+        let list = data.list.filter((item) => item.status === 0);
+        if (list?.length) {
+          this.getById(list[0].id);
+          this.type = 'edit';
+          this.title = '修改取样';
+        } else {
+          row.sourceCode = row.qualityPlanCode || row.workOrderCode;
+          this.form = JSON.parse(JSON.stringify(row));
+          this.form.qualityWorkOrderId = row.id;
+          this.form.qualityWorkOrderCode = row.code;
+          this.form.qualityWorkOrderName = row.name;
+          this.workSampleQuantity = Number(row.sampleQuantity) || 0;
+          this.form.pleaseUnit = this.form.measureUnit;
+          if (!data?.list.length) {
+            this.form.isFirstSampling = 1;
+          } else {
+            this.$set(this.form, 'unit', data?.list[0].unit);
+          }
+          this.datasource(data?.list[0]?.unit);
+          this.queryQualityTempleContent(!data?.list.length&&row.qualityMode==1);
+        }
+      },
+      getById(id) {
+        getById(id).then((res) => {
+          this.workSampleQuantity =
+            Number(res.qualityWorkOrderVO.sampleQuantity) || 0;
+          [
+            'id',
+            'code',
+            'name',
+            'createTime',
+            'createUserId',
+            'status',
+            'approvalStatus',
+            'approvalUserId',
+            'sampleQuantity',
+            'processInstanceId'
+          ].forEach((it) => {
+            delete res.qualityWorkOrderVO[it];
           });
+          this.form = { ...res, ...res.qualityWorkOrderVO };
+          this.datasource(this.form.unit);
+          this.queryQualityTempleContent();
+          if (res.qualityWorkOrderVO.conditionType == 1) {
+            // if (this.form.unit == res.qualityWorkOrderVO.measureUnit) {
+            //   this.$set(this.form, 'packingUnit', '111');
+            // } else {
+            //   this.$set(this.form, 'packingUnit', '222');
+            // }
+            this.$set(this.form, 'portion', res.quantity);
+            this.$set(this.form, 'quantity', 0);
+          } else {
+            this.$set(this.form, 'portion', res.copies);
+          }
+
+          this.sampleList = res.qualitySampleList;
         });
       },
-      async queryQualityTempleContent() {
+      /* 查询质检模板内容 */
+      async queryQualityTempleContent(is) {
         const res = await queryQualityTempleContent({
-          qualityWorkerId: this.form.id,
+          qualityWorkerId: this.form.qualityWorkOrderId,
           page: 1,
           size: 10000
         });
         this.schemeList = res.list;
+        if(is){
+             this.updatePackingList()
+        }
       },
       cancel() {
         this.form = {
           ...defForm
         };
         this.schemeList = [];
+        this.packingSpecificationOption = [];
+        this.sampleList = [];
+        this.tableList = [];
+
         this.visible = false;
       },
-      async datasource({ page, limit, where }) {
+      changeParent(row) {
+        this.init(row);
+      },
+      async datasource(unit) {
         const res = await queryQualityInventory({
-          ...where,
-          pageNum: page,
+          qualityWorkerId: this.form.qualityWorkOrderId,
+          pageNum: 1,
           size: -1
         });
-        if (res.list.length == 0) {
-          return res;
-        }
 
         let o = res.list[0];
         let listArr = [];
@@ -538,7 +746,13 @@
             id: '222'
           });
         }
-
+        if (unit) {
+          this.$set(
+            this.form,
+            'packingUnit',
+            listArr.find((item) => unit == item.conversionUnit)?.id
+          );
+        }
         res.list.map((el) => {
           el.weightProportion = el.weight
             ? (el.weight / el.measureQuantity).toFixed(4)
@@ -546,6 +760,7 @@
           el.weightProportion = el.weightProportion - 0;
         });
         this.packingSpecificationOption = listArr;
+        this.tableList = res.list;
         return res;
       },
 
@@ -554,8 +769,8 @@
         // if (valid) {
         let params = {
           conditionType: this.form.conditionType,
-          measureQ: this.form.measureQ,
-          sampleUnit: this.form.sampleUnit,
+          quantity: this.form.quantity,
+          sampleUnit: this.form.unit,
           portion: this.form.portion
         };
         let specifications = this.packingSpecificationOption.find(
@@ -569,10 +784,10 @@
       async sampleFn(data, specifications) {
         this.sampleList = [];
         if (!this.selection || this.selection.length == 0) {
-          this.$message.warning('请先选择样品!');
+          this.$message.warning('请先选择来源清单!');
           return;
         }
-        const measureQ = data.measureQ || 1;
+        const quantity = data.quantity || 1;
         const unit = data.sampleUnit;
         const sampleCount = Number(data.portion);
         try {
@@ -591,14 +806,14 @@
             }
             // ***
             //抽检计量整样小样或者抽检计重小样
-            if (!this.validateMeasureQuantity(measureQ, unit, sampleCount))
+            if (!this.validateMeasureQuantity(quantity, unit, sampleCount))
               return; //取样数量验证
-            if (unit === 'KG' && !this.validateWeight(measureQ, sampleCount))
+            if (unit === 'KG' && !this.validateWeight(quantity, sampleCount))
               return; // 若计量单位为重量,还需验证总重量是否足够
             await this.getNewFullSampleList(
               Math.ceil(sampleCount),
               // sampleCount,
-              measureQ,
+              quantity,
               unit,
               specifications
             );
@@ -617,10 +832,10 @@
           this.$message.error('取样处理失败');
         }
       },
-      validateWeight(measureQ, sampleCount) {
+      validateWeight(quantity, sampleCount) {
         let totalMaxPossible = 0;
         this.selection.forEach((item) => {
-          totalMaxPossible += item.measureQuantity / measureQ;
+          totalMaxPossible += item.measureQuantity / quantity;
         });
 
         if (totalMaxPossible < sampleCount) {
@@ -636,7 +851,7 @@
         const weightUnit = this.selection[0].weightUnit;
         if (weightUnit === 'G') totalWeight /= 1000;
 
-        if (measureQ * sampleCount > totalWeight) {
+        if (quantity * sampleCount > totalWeight) {
           this.$message.info('取样计量重量不能大于总计量重量');
           return false;
         }
@@ -644,7 +859,7 @@
         const invalidItem = this.selection.find((item) => {
           const weight =
             item.weightUnit === 'G' ? item.weight / 1000 : item.weight;
-          return weight < measureQ;
+          return weight < quantity;
         });
 
         if (invalidItem) {
@@ -655,27 +870,27 @@
         return true;
       },
 
-      validateMeasureQuantity(measureQ, unit, sampleCount) {
-        if (this.form.conditionType == 2 && measureQ <= 0) {
+      validateMeasureQuantity(quantity, unit, sampleCount) {
+        if (this.form.conditionType == 2 && quantity <= 0) {
           this.$message.info('取样计量数量必须大于0');
           return false;
         }
 
-        const totalQuantity = this.selection.reduce(
-          (sum, item) => sum + item.measureQuantity,
-          0
-        );
+        const totalQuantity =
+          this.selection.reduce((sum, item) => sum + item.measureQuantity, 0) -
+          this.workSampleQuantity;
+
         if (
           (this.selection[0].measureUnit === unit ||
             this.form.conditionType == 1) &&
-          measureQ * sampleCount > totalQuantity
+          quantity * sampleCount > totalQuantity
         ) {
           this.$message.info('取样计量数量不能大于总计量数量');
           return false;
         }
 
         const invalidItem = this.selection.find(
-          (item) => item.measureQuantity < measureQ
+          (item) => item.measureQuantity < quantity
         );
         if (invalidItem) {
           this.$message.info('条目计量数量小于取样计量数量');
@@ -696,7 +911,8 @@
         const chooseNumber = this.selection.reduce((acc, pro) => {
           return pro.measureQuantity ? acc + Number(pro.measureQuantity) : acc;
         }, 0);
-        const invalidItem = chooseNumber < sampleCount;
+        const invalidItem =
+          chooseNumber < sampleCount + this.workSampleQuantity;
         // console.log(this.selection, 'this.selection');
         // const invalidItem = this.selection.find(
         //   (item) => item.measureQuantity < sampleCount
@@ -730,7 +946,7 @@
             dataList.push({
               ...item,
               measureQuantity: 1, //作为计量数量
-              sampleCode: await this.getSampleCode(),
+              sampleCode: await getCode('sample_code'),
               qualitySampleTemplateList
             });
           } else {
@@ -738,7 +954,7 @@
               dataList.push({
                 ...item,
                 measureQuantity: currentNum1 > 1 ? 1 : currentNum1, //作为计量数量
-                sampleCode: await this.getSampleCode(),
+                sampleCode: await getCode('sample_code'),
                 qualitySampleTemplateList
               });
               currentNum1 -= 1;
@@ -771,6 +987,7 @@
         }
         // 更改
         this.sampleList = dataList;
+        this.getTotal();
       },
       // 小数点数据判断
       formatNumber(a, b, maxDecimals = 4) {
@@ -905,6 +1122,7 @@
         if (this.sampleList.length > sampleCount) {
           this.sampleList = this.sampleList.splice(0, sampleCount);
         }
+        this.getTotal();
       },
       // 当计量类型 是数量的时候 取整样 校验
       validateSampleQuantity(sampleCount, specifications) {
@@ -916,15 +1134,79 @@
             : 'measureQuantity';
         let labelName = labelKey == 'packingQuantity' ? '包装数量' : '计量数量';
         totalS = this.selection.reduce((total, el) => total + el[labelKey], 0);
-
+        let formTotalS = this.tableList.reduce(
+          (total, el) => total + el[labelKey],
+          0
+        );
         if (sampleCount > totalS) {
           this.$message.info(
             `所填的条目数量不能超过所选${labelName}总和${totalS}`
           );
           return false;
         }
+        if (sampleCount > formTotalS - this.workSampleQuantity) {
+          this.$message.info(
+            `取样数量不能大于${formTotalS - this.workSampleQuantity}`
+          );
+          return false;
+        }
         return true;
       },
+
+      handleQualityModeChange(val) {
+        if (val == 1) {
+          this.updatePackingList();
+        } else {
+          this.sampleList = [];
+          this.getTotal();
+        }
+      },
+      // 全检
+      async updatePackingList() {
+        let list = this.tableList;
+
+        let sampleCount = this.form.total;
+
+        const dataList = [];
+        let count = list ? list.length : 0;
+        console.log(count, 'count');
+        const codeList = await this.batchCodes(count);
+        for (const [index, item] of list.entries()) {
+          const qualitySampleTemplateList = item.qualitySampleTemplateList
+            ?.length
+            ? JSON.parse(JSON.stringify(item.qualitySampleTemplateList))
+            : JSON.parse(
+                JSON.stringify(
+                  this.schemeList.map((item) => {
+                    item['qualityResults'] = 1;
+                    return item;
+                  })
+                )
+              );
+
+          if (sampleCount >= list.length) {
+            dataList.push({
+              ...item,
+              measureQuantity: item.measureQuantity, //作为计量数量
+              sampleCode: codeList[index],
+              qualitySampleTemplateList
+            });
+          }
+        }
+
+        this.sampleList = dataList;
+        this.getTotal();
+      },
+      getTotal() {
+        this.form.sampleQuantity = this.sampleList.reduce(
+          (total, el) => total + Number(el.measureQuantity),
+          0
+        );
+        this.form.sampleWeight = this.sampleList.reduce(
+          (total, el) => total + Number(el.weight),
+          0
+        );
+      },
       async batchCodes(count) {
         if (count <= 0) return;
         let params = { count };
@@ -933,14 +1215,41 @@
       },
       /* 保存编辑 */
       save() {
+        if (this.type == 'add') {
+          [
+            'id',
+            'code',
+            'name',
+            'createTime',
+            'createUserId',
+            'status',
+            'approvalStatus',
+            'approvalUserId'
+          ].forEach((key) => {
+            delete this.form[key];
+          });
+        }
+        if (this.form.conditionType == 1) {
+          this.form.quantity = this.form.portion;
+        }
+        let api =
+          this.type == 'add' ? samplingrecordSave : samplingrecordUpdate;
         this.$refs.form.validate((valid) => {
           if (valid) {
+            if (!this.sampleList.length) {
+              this.$message.error('样品清单不能为空!');
+              return;
+            }
             this.loading = true;
-            saveOrUpdate(this.form)
+
+            api({
+              ...this.form,
+              sampleList: this.sampleList
+            })
               .then((res) => {
                 this.$message.success('操作成功');
                 this.cancel();
-                this.$emit('done');
+                this.$emit('reload');
               })
               .finally(() => {
                 this.loading = false;

+ 258 - 7
src/views/sample/sampleRecord/index.vue

@@ -7,42 +7,85 @@
         row-key="id"
         :columns="columns"
         :datasource="datasource"
-        cache-key="qms-2511141047-sampleRecord-table"
+        @columns-change="handleColumnChange"
+        :cache-key="cacheKeyUrl"
         autoAmendPage
       >
         <template v-slot:toolbar>
-          <el-button type="primary" size="mini">新增</el-button>
+          <el-button type="primary" size="mini" @click="addSampleOpen('add')"
+            v-if="$hasPermission('qms:samplingrecord:save')"
+            >新增</el-button
+          >
+        </template>
+        <template v-slot:code="{ row }">
+          <el-link
+            type="primary"
+            :underline="false"
+            @click="addSampleOpen('view', row)"
+          >
+            {{ row.code }}
+          </el-link>
         </template>
         <template v-slot:action="{ row }">
-          <el-link type="primary" :underline="false" icon="el-icon-edit">
+          <el-link
+            type="primary"
+            :underline="false"
+            icon="el-icon-edit"
+            @click="addSampleOpen('edit', row)"
+            v-if="[0, 3].includes(row.approvalStatus)&&$hasPermission('qms:samplingrecord:update')"
+          >
             编辑
           </el-link>
-          <el-popconfirm
+          <el-link
+            type="primary"
+            :underline="false"
+            v-if="[0, 3].includes(row.approvalStatus)&&$hasPermission('qms:samplingrecord:update')"
+            @click="approvalSubmit(row)"
+            >提交</el-link
+          >
+          <!-- <el-popconfirm
             class="ele-action"
             title="确定要删除此条数据吗?"
             @confirm="deleteRow(row)"
+            v-if="[0, 3].includes(row.approvalStatus)&&$hasPermission('qms:samplingrecord:update')"
           >
             <template v-slot:reference>
               <el-link type="danger" :underline="false" icon="el-icon-delete">
                 删除
               </el-link>
             </template>
-          </el-popconfirm>
+          </el-popconfirm> -->
         </template>
       </ele-pro-table>
     </el-card>
+    <addSample ref="addSampleRef" @reload="search" :isSampleRecord="true"></addSample>
+    <processSubmitDialog
+      :processSubmitDialogFlag.sync="processSubmitDialogFlag"
+      v-if="processSubmitDialogFlag"
+      ref="processSubmitDialogRef"
+      @reload="search"
+    ></processSubmitDialog>
   </div>
 </template>
 
 <script>
   import dictMixins from '@/mixins/dictMixins';
   import tableColumnsMixin from '@/mixins/tableColumnsMixin';
+  import addSample from './components/addSample.vue';
   import { samplingRecordsPage } from '@/api/samplingRecords';
+  import processSubmitDialog from '@/components/processSubmitDialog/processSubmitDialog.vue';
+  import { reviewStatus } from '@/enum/dict';
 
   export default {
     mixins: [dictMixins, tableColumnsMixin],
+    components: {
+      addSample,
+      processSubmitDialog
+    },
     data() {
       return {
+        processSubmitDialogFlag: false,
+        cacheKeyUrl: 'qms-2511141047-sampleRecord-table',
         columns: [
           {
             width: 50,
@@ -53,8 +96,153 @@
           },
           {
             prop: 'code',
+            label: '取样记录编码',
+            slot: 'code',
+            align: 'center',
+            minWidth: 150,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityWorkOrderCode',
             label: '质检工单编码',
             align: 'center',
+            minWidth: 150,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'qualityWorkOrderName',
+            label: '质检工单名称',
+            align: 'center',
+            minWidth: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sourceCode',
+            label: '来源单号',
+            align: 'center',
+            minWidth: 150,
+            showOverflowTooltip: true
+          },
+
+          {
+            prop: 'qualityType',
+            label: '类型',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            formatter: (row) => {}
+          },
+          {
+            prop: 'qualityMode',
+            label: '质检方式',
+            align: 'center',
+            minWidth: 100,
+            formatter: (row) => {
+              return row.qualityMode == 1 ? '全检' : '抽检';
+            },
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productCode',
+            label: '编码',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productName',
+            label: '名称',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'batchNo',
+            label: '批次号',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'specification',
+            label: '规格',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'modelType',
+            label: '型号',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'brandNo',
+            label: '牌号',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'produceTaskName',
+            label: '工序名称',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'pleasePurpose',
+            label: '请样目的',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'pleaseQuantity',
+            label: '请样数量',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'pleaseUnit',
+            label: '单位',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'conditionType',
+            label: '取样',
+            formatter: (row) => {
+              return row.conditionType == 1 ? '整样' : '小样';
+            },
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'recordingMethod',
+            label: '记录方法',
+            align: 'center',
+            formatter: (row) => {
+              return row.recordingMethod == 1 ? '批样' : '单样全部';
+            },
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'quantity',
+            label: '取样数量',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'unit',
+            label: '单位',
+            align: 'center',
             minWidth: 110,
             showOverflowTooltip: true
           },
@@ -62,9 +250,53 @@
             prop: 'status',
             label: '状态',
             align: 'center',
+            minWidth: 110,
             showOverflowTooltip: true,
-            minWidth: 150,
-            formatter: (row) => {}
+            formatter: (_row, _column, cellValue) => {
+              return _row.status == 1
+                ? '审核中'
+                : _row.status == 2
+                ? '已取样'
+                : '未提交';
+            }
+          },
+          {
+            prop: 'approvalStatus',
+            label: '审核状态',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true,
+            formatter: (_row, _column, cellValue) => {
+              return reviewStatus[_row.approvalStatus];
+            }
+          },
+          {
+            prop: 'createUserName',
+            label: '创建人',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'createTime',
+            label: '创建时间',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'approvalUserName',
+            label: '审批人',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'approvalTime',
+            label: '审批时间',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
           },
           {
             columnKey: 'action',
@@ -114,6 +346,25 @@
           where
         });
       },
+      addSampleOpen(type, row) {
+        this.$refs.addSampleRef.open(type, row);
+      },
+      approvalSubmit(res) {
+        this.processSubmitDialogFlag = true;
+        this.$nextTick(() => {
+          let params = {
+            businessId: res.id,
+            businessKey: 'sampling_approval_process',
+            formCreateUserId: res.createUserId,
+            variables: {
+              businessCode: res.code,
+              businessName: res.name,
+              businessType: '取样'
+            }
+          };
+          this.$refs.processSubmitDialogRef.init(params);
+        });
+      },
       /* 表格数据源 */
       datasource({ page, limit, where, order }) {
         // 参数