qualityWorkOrderTable.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. <template>
  2. <div>
  3. <seek-page :seekList="seekList" @search="search"></seek-page>
  4. <ele-pro-table
  5. ref="table"
  6. row-key="id"
  7. :columns="columns"
  8. :datasource="datasource"
  9. :cache-key="cacheKeyUrl"
  10. :selection.sync="selection"
  11. autoAmendPage
  12. height="var(--batch-record-table-height)"
  13. >
  14. <template v-slot:action="{ row }">
  15. <el-link type="primary" :underline="false" @click="goToDetail(row)">
  16. 详情
  17. </el-link>
  18. </template>
  19. <template v-slot:code="{ row }">
  20. <el-link type="primary" @click="goToDetail(row)">{{
  21. row.code
  22. }}</el-link>
  23. </template>
  24. <template v-slot:toolbar>
  25. <exportButton
  26. fileName="质检工单"
  27. apiUrl="/qms/quality_work_order/exportBatchRecordPage"
  28. :params="params"
  29. ></exportButton>
  30. <print-selector :options="printOptions" @select="handlePrint" />
  31. </template>
  32. </ele-pro-table>
  33. <product-inspection-report ref="productInspectionReport" />
  34. <sampling-form ref="samplingForm" />
  35. <finished-product-original-record ref="finishedProductOriginalRecord" />
  36. </div>
  37. </template>
  38. <script>
  39. import dictMixins from '@/mixins/dictMixins';
  40. import tableColumnsMixin from '@/mixins/tableColumnsMixin';
  41. import { batchRecordPage, queryPrint } from '@/api/qualityWorkOrder/index.js';
  42. import exportButton from '@/components/upload/exportButton.vue';
  43. import printSelector from '../printSelector.vue';
  44. import productInspectionReport from '../../print/electrodeBatchRecord/productInspectionReport.vue';
  45. import samplingForm from '../../print/electrodeBatchRecord/samplingForm.vue';
  46. import finishedProductOriginalRecord from '../../print/electrodeBatchRecord/finishedProductOriginalRecord.vue';
  47. export default {
  48. mixins: [dictMixins, tableColumnsMixin],
  49. components: {
  50. exportButton,
  51. printSelector,
  52. productInspectionReport,
  53. samplingForm,
  54. finishedProductOriginalRecord
  55. },
  56. props: {
  57. tableQuery: {
  58. type: Object,
  59. default: () => {
  60. return {};
  61. }
  62. }
  63. },
  64. data() {
  65. return {
  66. columns: [
  67. {
  68. width: 45,
  69. type: 'selection',
  70. columnKey: 'selection',
  71. align: 'center',
  72. fixed: 'left'
  73. },
  74. {
  75. width: 50,
  76. type: 'index',
  77. columnKey: 'index',
  78. align: 'center',
  79. label: '序号'
  80. },
  81. {
  82. prop: 'code',
  83. label: '质检工单编码',
  84. align: 'center',
  85. minWidth: 110,
  86. showOverflowTooltip: true,
  87. slot: 'code'
  88. },
  89. {
  90. prop: 'name',
  91. label: '质检工单名称',
  92. align: 'center',
  93. showOverflowTooltip: true,
  94. minWidth: 150
  95. },
  96. {
  97. prop: 'sourceCode',
  98. label: '来源单号',
  99. align: 'center',
  100. showOverflowTooltip: true,
  101. minWidth: 150,
  102. formatter: (row) => {
  103. return row.qualityPlanCode
  104. ? row.qualityPlanCode
  105. : row.workOrderCode;
  106. }
  107. },
  108. {
  109. prop: 'qualityType',
  110. label: '类型',
  111. align: 'center',
  112. showOverflowTooltip: true,
  113. minWidth: 150,
  114. formatter: (row) => {
  115. return this.getDictValue('质检计划类型', row.qualityType);
  116. }
  117. },
  118. {
  119. prop: 'qualityMode',
  120. label: '质检方式',
  121. align: 'center',
  122. showOverflowTooltip: true,
  123. minWidth: 150,
  124. formatter: (row) => {
  125. return this.getDictValue('取样类型', `0${row.qualityMode}`);
  126. }
  127. },
  128. {
  129. prop: 'qualityName',
  130. label: '报工人',
  131. align: 'center',
  132. showOverflowTooltip: true,
  133. minWidth: 150
  134. },
  135. {
  136. prop: 'qualityTime',
  137. label: '质检时间',
  138. align: 'center',
  139. showOverflowTooltip: true,
  140. minWidth: 150
  141. },
  142. {
  143. prop: 'status',
  144. label: '状态',
  145. align: 'center',
  146. showOverflowTooltip: true,
  147. minWidth: 150,
  148. formatter: (row) => {
  149. switch (row.status) {
  150. case 0:
  151. return '未报工';
  152. case 1:
  153. return '已报工';
  154. default:
  155. return '已关闭';
  156. }
  157. }
  158. },
  159. {
  160. label: '操作',
  161. columnKey: 'action',
  162. slot: 'action',
  163. showOverflowTooltip: true,
  164. minWidth: 110,
  165. align: 'center',
  166. fixed: 'right'
  167. }
  168. ],
  169. cacheKeyUrl: 'mes-9221130-quality-work-order-table',
  170. params: {},
  171. tableData: [],
  172. selection: [],
  173. printTypeMap: {
  174. productInspectionReport: 'PRODUCT_INSPECTION_REPORT',
  175. samplingForm: 'SAMPLING_SLIP',
  176. finishedProductOriginalRecord: 'FINISHED_PRODUCT_INSPECTION_RECORD'
  177. },
  178. printOptions: [
  179. {
  180. key: 'productInspectionReport',
  181. label: '产品报检单',
  182. code: 'CG-038'
  183. },
  184. { key: 'samplingForm', label: '取样单', code: 'ZL-041' }
  185. // {
  186. // key: 'finishedProductOriginalRecord',
  187. // label: '成品检验原始记录',
  188. // code: '054-7'
  189. // }
  190. ]
  191. };
  192. },
  193. computed: {
  194. seekList() {
  195. return [
  196. {
  197. label: '生产工单编码',
  198. value: 'workOrderCode',
  199. type: 'input',
  200. placeholder: '请输入',
  201. labelWidth: 110
  202. },
  203. {
  204. label: '质检工单编码',
  205. value: 'code',
  206. type: 'input',
  207. placeholder: '请输入',
  208. labelWidth: 110
  209. },
  210. {
  211. label: '质检工单名称',
  212. value: 'name',
  213. type: 'input',
  214. placeholder: '请输入',
  215. labelWidth: 110
  216. }
  217. ];
  218. }
  219. },
  220. created() {
  221. this.requestDict('质检计划类型');
  222. this.requestDict('不良品处理类型');
  223. this.requestDict('取样类型');
  224. },
  225. methods: {
  226. // 刷新表格
  227. reload(where = {}) {
  228. this.$refs.table.reload({
  229. where,
  230. ...this.tableQuery
  231. });
  232. },
  233. /* 表格数据源 */
  234. datasource({ page, limit, where, order }) {
  235. // 参数
  236. const body = {
  237. ...where,
  238. ...order,
  239. pageNum: page,
  240. size: limit,
  241. ...this.tableQuery
  242. };
  243. this.params = body;
  244. const res = batchRecordPage(body);
  245. Promise.resolve(res).then((data) => {
  246. this.tableData = data?.list || data?.records || [];
  247. });
  248. return res;
  249. },
  250. search(where) {
  251. this.reload(where);
  252. },
  253. goToDetail(row) {
  254. const path = `/page-qms/inspectionWork/details?id=${row.id}&path=&name=工单`;
  255. window.history.pushState(null, '', path);
  256. },
  257. async handlePrint(key) {
  258. const printType = this.printTypeMap[key];
  259. if (!printType) {
  260. this.$message.warning('暂不支持该打印单据');
  261. return;
  262. }
  263. try {
  264. const ids = this.getPrintIds();
  265. if (!ids.length) {
  266. this.$message.warning('未获取到可打印数据的ID');
  267. return;
  268. }
  269. const res = await queryPrint({ ids, printType });
  270. const data = this.buildPrintData(res, key);
  271. if (!data) {
  272. this.$message.warning('未查询到可打印的质检工单数据');
  273. return;
  274. }
  275. if (this.$refs[key]) {
  276. this.$refs[key].open(data);
  277. }
  278. } catch (error) {
  279. this.$message.error(error.message || '查询打印数据失败');
  280. }
  281. },
  282. buildPrintData(res, key) {
  283. const list = this.getPrintList(res, key);
  284. if (!list.length) {
  285. return null;
  286. }
  287. if (key == 'productInspectionReport') {
  288. const first = list[0];
  289. const selected = this.getSelectedItem(first, 0);
  290. const base = this.buildPrintItem(first, selected);
  291. return {
  292. ...base,
  293. code: selected.code || first.workOrderCode || '',
  294. date: this.formatPrintDate(
  295. this.getValue(
  296. first.createTime,
  297. selected.qualityTime,
  298. selected.createTime
  299. )
  300. ),
  301. reporter: selected.qualityName || selected.createUserName || '',
  302. receiver: selected.reviewerName || selected.checkerName || '',
  303. department: selected.departmentName || selected.workshopName || '',
  304. items: list.map((item, index) =>
  305. this.buildPrintItem(
  306. item,
  307. this.getSelectedItem(item, index),
  308. index
  309. )
  310. )
  311. };
  312. }
  313. const data = list.map((item, index) => {
  314. const selected = this.getSelectedItem(item.basicInfo || item, index);
  315. return key == 'samplingForm'
  316. ? this.buildSamplingFormData(item, selected)
  317. : this.buildFinishedProductRecordData(item, selected);
  318. });
  319. return data.length == 1 ? data[0] : data;
  320. },
  321. getPrintList(res, key) {
  322. const listMap = {
  323. productInspectionReport: 'productInspectionReportList',
  324. samplingForm: 'samplingSlipList',
  325. finishedProductOriginalRecord: 'finishedProductInspectionRecordList'
  326. };
  327. const listKey = listMap[key];
  328. if (Array.isArray(res?.[listKey])) {
  329. return res[listKey];
  330. }
  331. if (Array.isArray(res)) {
  332. return res;
  333. }
  334. return [];
  335. },
  336. getPrintRows() {
  337. return this.selection.length ? this.selection : this.tableData;
  338. },
  339. getPrintIds() {
  340. return [
  341. ...new Set(
  342. this.getPrintRows()
  343. .map((item) => item.id)
  344. .filter((id) => this.hasValue(id))
  345. )
  346. ];
  347. },
  348. getSelectedItem(item = {}, index = 0) {
  349. const printRows = this.getPrintRows();
  350. return (
  351. printRows.find(
  352. (row) =>
  353. (this.hasValue(item.id) && row.id == item.id) ||
  354. (this.hasValue(item.workOrderCode) &&
  355. row.workOrderCode == item.workOrderCode) ||
  356. (this.hasValue(item.produceBatch) &&
  357. row.batchNo == item.produceBatch)
  358. ) ||
  359. printRows[index] ||
  360. printRows[0] ||
  361. {}
  362. );
  363. },
  364. buildSamplingFormData(item, selected) {
  365. return {
  366. ...selected,
  367. ...item,
  368. productName: this.getValue(
  369. item.materialName,
  370. selected.productName,
  371. selected.materialName,
  372. selected.name
  373. ),
  374. specification: this.getValue(
  375. item.specModel,
  376. selected.specification,
  377. selected.productModel
  378. ),
  379. batchNo: this.getValue(
  380. item.produceBatch,
  381. item.batch,
  382. selected.batchNo
  383. ),
  384. sampleSource: this.getValue(
  385. selected.sampleSource,
  386. selected.sourceTypeDesc,
  387. selected.sourceCode,
  388. selected.workOrderCode
  389. ),
  390. sampleLocation: this.getValue(
  391. selected.samplePlace,
  392. selected.sampleLocation
  393. ),
  394. sampleDate: this.formatPrintDate(
  395. this.getValue(
  396. item.createTime,
  397. selected.qualityTime,
  398. selected.createTime
  399. )
  400. ),
  401. batchQuantity: this.hasValue(item.batch)
  402. ? item.batch
  403. : this.buildQuantityText(item.quantityVerified, item.unit),
  404. sampleQuantity: this.buildQuantityText(
  405. this.getValue(item.quantity, selected.sampleQuantity),
  406. item.unit
  407. ),
  408. sampler: this.getValue(
  409. selected.sampleUserName,
  410. selected.qualityName,
  411. selected.createUserName
  412. ),
  413. checker: this.getValue(
  414. selected.checkerName,
  415. selected.reviewerName,
  416. selected.approvalUserName
  417. ),
  418. remark: this.getValue(item.remark, selected.remark)
  419. };
  420. },
  421. buildFinishedProductRecordData(item, selected) {
  422. const basicInfo = item.basicInfo || {};
  423. const detailList = Array.isArray(item.detailList)
  424. ? item.detailList
  425. : [];
  426. const inspectionItems = detailList.map((detail) => ({
  427. ...detail,
  428. name: detail.inspectionItem || '',
  429. standard: detail.standardRequirement || '',
  430. result: detail.inspectionResult || '',
  431. conclusion: ''
  432. }));
  433. return {
  434. ...selected,
  435. ...basicInfo,
  436. productName: this.getValue(
  437. basicInfo.productName,
  438. selected.productName,
  439. selected.name
  440. ),
  441. productCode: this.getValue(
  442. selected.productCode,
  443. selected.materialCode
  444. ),
  445. specification: this.getValue(
  446. basicInfo.specModel,
  447. selected.specification,
  448. selected.productModel
  449. ),
  450. packageSpec: basicInfo.packageSpec || '',
  451. batchNo: this.getValue(basicInfo.produceBatch, selected.batchNo),
  452. sterilizationBatchNo: basicInfo.sterilizationBatch || '',
  453. submitQuantity: this.getValue(
  454. basicInfo.productQuantity,
  455. selected.submitQuantity
  456. ),
  457. sampleQuantity: this.getValue(
  458. basicInfo.samplingQuantity,
  459. selected.sampleQuantity
  460. ),
  461. inspectionBasis: this.getValue(
  462. basicInfo.inspectionBasis,
  463. selected.inspectionBasis
  464. ),
  465. inspectionDate: this.formatPrintDate(
  466. this.getValue(
  467. basicInfo.reportDate,
  468. basicInfo.productionDate,
  469. basicInfo.createTime,
  470. selected.qualityTime
  471. )
  472. ),
  473. appearanceItems: inspectionItems,
  474. performanceItems: [],
  475. packagingItems: [],
  476. conclusion: this.getValue(
  477. selected.conclusion,
  478. selected.inspectionResult
  479. ),
  480. inspector: this.getValue(
  481. selected.qualityName,
  482. selected.createUserName
  483. ),
  484. checker: this.getValue(selected.checkerName, selected.reviewerName),
  485. remark: selected.remark || ''
  486. };
  487. },
  488. buildPrintItem(item, selected = {}, index = 0) {
  489. return {
  490. ...item,
  491. seq: index + 1,
  492. productCode: item.materialCode || selected.productCode || '',
  493. productName:
  494. item.productName ||
  495. item.materialName ||
  496. selected.productName ||
  497. selected.name ||
  498. '',
  499. materialCode: item.materialCode || '',
  500. materialName: item.materialName || '',
  501. specification:
  502. [item.specification, item.modelType].filter(Boolean).join('/') ||
  503. item.specModel ||
  504. selected.specification ||
  505. '',
  506. sterilizationBatchNo:
  507. item.sterilizationBatch || selected.sterilizationBatchNo || '',
  508. productionBatchNo: item.produceBatch || selected.batchNo || '',
  509. batchNo: item.produceBatch || item.batch || selected.batchNo || '',
  510. unit: item.unit || selected.unit || '',
  511. quantity: this.getValue(item.quantity, selected.quantity),
  512. processOrderCode:
  513. item.workOrderCode ||
  514. selected.workOrderCode ||
  515. selected.sourceCode ||
  516. '',
  517. inspectionCode: selected.code || ''
  518. };
  519. },
  520. buildQuantityText(quantity, unit) {
  521. if (!this.hasValue(quantity)) {
  522. return '';
  523. }
  524. return `${quantity}${unit || ''}`;
  525. },
  526. hasValue(value) {
  527. return value !== undefined && value !== null && value !== '';
  528. },
  529. getValue(...values) {
  530. const value = values.find((item) => this.hasValue(item));
  531. return value === undefined ? '' : value;
  532. },
  533. formatPrintDate(value) {
  534. if (!this.hasValue(value)) {
  535. return '';
  536. }
  537. const source = value;
  538. if (typeof source == 'string') {
  539. return source.slice(0, 10);
  540. }
  541. if (this.$util?.toDateString) {
  542. return this.$util.toDateString(source, 'yyyy-MM-dd');
  543. }
  544. return new Date(source).toISOString().slice(0, 10);
  545. }
  546. }
  547. };
  548. </script>
  549. <style></style>