You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1175 lines
38 KiB

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
  1. <template>
  2. <div class="customer-css">
  3. <el-dialog :title="titleCon" v-drag v-bind="$attrs" v-on="$listeners" width="700px" style="height: 680px;" class="customer-dialog">
  4. <el-form :inline="true" label-position="top" style="height: auto;">
  5. <!-- 时间和固定载具 -->
  6. <el-row style="margin-top: -10px;">
  7. <el-col :span="11">
  8. <el-form-item :label=labels.currentTime>
  9. <el-date-picker style="width: 110px;"
  10. v-model="pageData.reportDate"
  11. format="yyyy-MM-dd"
  12. value-format="yyyy-MM-dd"
  13. placeholder="">
  14. </el-date-picker>
  15. </el-form-item>
  16. <el-form-item :label="''" style="margin-top: 23px">
  17. <el-time-picker style="width: 100px;"
  18. v-model="pageData.reportTime"
  19. format="HH:mm:ss"
  20. value-format="HH:mm:ss"
  21. placeholder="">
  22. </el-time-picker>
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="6">
  26. <el-form-item>
  27. <span style="cursor: pointer" slot="label" @click="queryFixedCarrierList"><a>固定载具</a></span>
  28. <el-input v-model="pageData.fixture" readonly style="width: 120px;" placeholder="固定载具"></el-input>
  29. </el-form-item>
  30. </el-col>
  31. <el-col :span="3">
  32. <el-form-item label="排数">
  33. <el-input-number :controls="false" :step="0" v-model="pageData.rowCount" @change="handleRowCountChange" style="width: 60px;"></el-input-number>
  34. </el-form-item>
  35. </el-col>
  36. <el-col :span="3">
  37. <el-form-item label="分切卷数">
  38. <el-input-number :controls="false" :step="0" v-model="pageData.rollCount" style="width: 60px;"></el-input-number>
  39. </el-form-item>
  40. </el-col>
  41. </el-row>
  42. <!-- 排数据表格 -->
  43. <div class="rq">
  44. <el-table
  45. :data="rowDataList"
  46. border
  47. style="width: 100%; margin-top: 10px;"
  48. max-height="350"
  49. :span-method="objectSpanMethod">
  50. <el-table-column prop="rowNumber" label="NO." width="50" align="center">
  51. </el-table-column>
  52. <el-table-column label="良品数" width="80" align="center">
  53. <template slot-scope="scope">
  54. <el-input-number
  55. :controls="false" :step="0"
  56. v-model="scope.row.goodQty"
  57. @change="handleQtyChange(scope.row)"
  58. style="width: 100%"
  59. class="good-qty-input"
  60. :style="{'color': '#67c23a', 'font-weight': 'bold'}">
  61. </el-input-number>
  62. </template>
  63. </el-table-column>
  64. <el-table-column label="面损" width="80" align="center">
  65. <template slot-scope="scope">
  66. <el-input-number
  67. :controls="false" :step="0"
  68. v-model="scope.row.surfaceLossQty"
  69. @change="handleQtyChange(scope.row)"
  70. style="width: 100%">
  71. </el-input-number>
  72. </template>
  73. </el-table-column>
  74. <el-table-column label="性能不良" width="80" align="center">
  75. <template slot-scope="scope">
  76. <el-input-number
  77. :controls="false" :step="0"
  78. v-model="scope.row.poorPerformanceQty"
  79. @change="handleQtyChange(scope.row)"
  80. style="width: 100%">
  81. </el-input-number>
  82. </template>
  83. </el-table-column>
  84. <el-table-column label="不良数" width="80" align="right">
  85. <template slot-scope="scope">
  86. <div class="defect-display" :style="{'color': '#f56c6c', 'font-weight': 'bold', 'text-align': 'right', 'padding-right': '10px'}">
  87. {{ scope.row.defectQty }}
  88. </div>
  89. </template>
  90. </el-table-column>
  91. <el-table-column label="良率" width="80" align="center">
  92. <template slot-scope="scope">
  93. <div class="yield-display" :style="{'color': '#409eff', 'font-weight': 'bold'}">
  94. {{ scope.row.yieldRate }}
  95. </div>
  96. </template>
  97. </el-table-column>
  98. <el-table-column label="总数" width="80" align="right">
  99. <template slot-scope="scope">
  100. <div class="total-display" :style="{'text-align': 'right', 'padding-right': '10px'}">
  101. {{ scope.row.totalQty }}
  102. </div>
  103. </template>
  104. </el-table-column>
  105. <el-table-column label="备注" align="center" class-name="remark-column">
  106. <template slot-scope="scope">
  107. <div class="remark-wrapper">
  108. <el-input
  109. type="textarea"
  110. v-model="scope.row.remark"
  111. resize="none"
  112. :autosize="false"
  113. class="remark-textarea">
  114. </el-input>
  115. </div>
  116. </template>
  117. </el-table-column>
  118. </el-table>
  119. </div>
  120. </el-form>
  121. <span slot="footer" class="dialog-footer">
  122. <el-button type="primary" @click="checkCreateSeparateRolllBun">保存</el-button>
  123. <el-button @click="closeDialog">{{ buttons.closeButton }}</el-button>
  124. </span>
  125. </el-dialog>
  126. <!-- 固定载具选择对话框 -->
  127. <el-dialog title="固定载具清单" :close-on-click-modal="false" v-drag :visible.sync="carrierModelFlag" width="950px">
  128. <div class="rq">
  129. <el-form :inline="true" label-position="top" :model="carrierSearchData">
  130. <el-form-item label="标签条码">
  131. <el-input v-model="carrierSearchData.carrierNo" clearable style="width: 150px"></el-input>
  132. </el-form-item>
  133. <el-form-item label="载具类型名称">
  134. <el-input v-model="carrierSearchData.carrierTypeName" clearable style="width: 150px"></el-input>
  135. </el-form-item>
  136. <el-form-item label="规格描述">
  137. <el-input v-model="carrierSearchData.specification" clearable style="width: 150px"></el-input>
  138. </el-form-item>
  139. <el-form-item label=" ">
  140. <el-button type="primary" @click="queryFixedCarrierList">查询</el-button>
  141. <el-button v-if="!editBatchVisible" @click="editBatchModel" type="success" icon="el-icon-edit">批量编辑</el-button>
  142. <el-button v-if="editBatchVisible" @click="batchSaveCarrier" type="primary" icon="el-icon-check" :loading="saveLoading">批量保存</el-button>
  143. </el-form-item>
  144. </el-form>
  145. <el-table
  146. :height="400"
  147. :data="carrierList"
  148. @row-dblclick="selectCarrier"
  149. border
  150. style="width: 100%;">
  151. <el-table-column
  152. prop="carrierNo"
  153. label="标签条码"
  154. header-align="center"
  155. align="left"
  156. min-width="120">
  157. </el-table-column>
  158. <el-table-column
  159. prop="carrierTypeName"
  160. label="载具类型名称"
  161. header-align="center"
  162. align="left"
  163. min-width="150">
  164. </el-table-column>
  165. <el-table-column
  166. prop="specification"
  167. label="规格描述"
  168. header-align="center"
  169. align="left"
  170. min-width="150">
  171. </el-table-column>
  172. <el-table-column
  173. prop="dimensions"
  174. label="尺寸"
  175. header-align="center"
  176. align="left"
  177. min-width="100">
  178. </el-table-column>
  179. <el-table-column
  180. label="可用数量"
  181. header-align="center"
  182. align="right"
  183. min-width="120">
  184. <template slot-scope="scope">
  185. <el-input-number
  186. v-if="editBatchVisible"
  187. v-model="scope.row.availableQty"
  188. :controls="false"
  189. :min="0"
  190. :precision="0"
  191. style="width: 100%">
  192. </el-input-number>
  193. <span v-else>{{ scope.row.availableQty || 0 }}</span>
  194. </template>
  195. </el-table-column>
  196. <el-table-column
  197. label="操作"
  198. header-align="center"
  199. align="center"
  200. width="80"
  201. fixed="right">
  202. <template slot-scope="scope">
  203. <el-button
  204. type="text"
  205. icon="el-icon-printer"
  206. @click="printCarrier(scope.row)"
  207. style="color: #409eff;">
  208. 打印
  209. </el-button>
  210. </template>
  211. </el-table-column>
  212. </el-table>
  213. </div>
  214. <el-footer style="height:40px;margin-top: 20px;text-align:center">
  215. <el-button type="primary" @click="carrierModelFlag=false">关闭</el-button>
  216. </el-footer>
  217. </el-dialog>
  218. </div>
  219. </template>
  220. <script>
  221. import {
  222. checkCreateSplitSfdcRoll,/*校验是否可以创建分卷*/
  223. createSplitSfdcRoll,/*执行创建分卷的操作*/
  224. getFixedCarrierList,/*获取固定载具列表*/
  225. } from '@/api/yieldReport/com_separate_roll.js';
  226. /*打印标签专用的js*/
  227. import {
  228. printSfdcLabel,
  229. } from "@/views/modules/yieldReport/print_roll_label.js";
  230. import {
  231. searchSysLanguagePackList,
  232. searchSysLanguageParam,
  233. searchFunctionButtonList,
  234. saveButtonList,
  235. searchSysLanguage,
  236. searchLanguageListByLanguageCode,
  237. saveSysLanguageOne,
  238. searchPageLanguageData,
  239. removerLanguage,
  240. saveSysLanguageList
  241. } from "@/api/sysLanguage.js";
  242. var functionId = 'C10000004';
  243. export default {
  244. name: "com_separate_roll",
  245. data() {
  246. return {
  247. titleCon: '创建分卷',
  248. showDefault: false,
  249. scheduleData: {
  250. site: this.$store.state.user.site,
  251. username: this.$store.state.user.name,
  252. seqNo: '',
  253. orderNo: '',
  254. itemNo: 0,
  255. resourceId: '',
  256. scheduledDate: '',
  257. shiftNo: '',
  258. partNo: '',
  259. workCenterNo: '',
  260. workCenterDesc: '',
  261. resourceDesc: '',
  262. rollNo: '',
  263. partDesc: '',
  264. planStartTime: '',
  265. planFinishTime: '',
  266. qtyRequiredOriginal: 0,
  267. preItemDesc: '',
  268. nextItemDesc: '',
  269. nextItemNo: 0,
  270. operatorId: '',
  271. functionName: '',
  272. currentRollFlag: false
  273. },
  274. pageData: {
  275. site: this.$store.state.user.site,
  276. username: this.$store.state.user.name,
  277. orderNo: '',
  278. itemNo: '',
  279. seqNo: '',
  280. rollNo: '',
  281. reportDate: '',
  282. reportTime: '',
  283. operatorId: '',
  284. rollQty: 0,
  285. rollNums: 1,
  286. // 新增字段
  287. fixture: '', // 固定载具
  288. rowCount: 0, // 排数
  289. rollCount: 0, // 卷数
  290. carrierNo: ''
  291. },
  292. rowDataList: [], // 排数据列表
  293. operatorData: {
  294. site: this.$store.state.user.site,
  295. username: this.$store.state.user.name,
  296. operatorId: '',
  297. operatorName: '',
  298. status: '',
  299. seqNo: '',
  300. showFlag: false
  301. },
  302. carrierModelFlag: false, // 固定载具对话框标记
  303. carrierList: [], // 固定载具列表
  304. carrierSearchData: { // 固定载具查询条件
  305. carrierNo: '',
  306. carrierTypeName: '',
  307. specification: ''
  308. },
  309. editBatchVisible: false, // 批量编辑状态
  310. saveLoading: false, // 保存loading状态
  311. buttons: {
  312. confirmButton: '确定',
  313. closeButton: '关闭',
  314. },
  315. buttonList: [
  316. {
  317. functionId: functionId,
  318. languageValue: '确定',
  319. objectId: 'confirmButton',
  320. objectType: 'button',
  321. tableId: '*'
  322. }, {
  323. functionId: functionId,
  324. languageValue: '关闭',
  325. objectId: 'closeButton',
  326. objectType: 'button',
  327. tableId: '*'
  328. },
  329. ],
  330. queryButton: {
  331. functionId: functionId,
  332. table_id: '*',
  333. languageCode: this.$i18n.locale,
  334. objectType: 'button'
  335. },
  336. labels: {
  337. componentTitle: '创建分卷',
  338. currentTime: '当前时间:',
  339. rollQty: '良品数量:',
  340. rollNums: '卷数:',
  341. approvedQtyMustBeInteger: '良品数量必须是正整数!',
  342. rollQtyMustBeInteger: '卷数必须是正整数!',
  343. pleaseSwitchOperator: '请先切换人员!',
  344. approvedQtyMustMoreTanZeroAndBeInteger: '良品数量必须大于零且是整数!',
  345. rollQtyMustMoreTanZeroAndBeInteger: '卷数必须是正整数!',
  346. confirmLabel: '确认',
  347. cancelLabel: '取消',
  348. },
  349. labelsList: [
  350. {
  351. functionId: functionId,
  352. languageValue: '创建分卷',
  353. objectId: 'componentTitle',
  354. objectType: 'label',
  355. tableId: '*'
  356. }, {
  357. functionId: functionId,
  358. languageValue: '当前时间:',
  359. objectId: 'currentTime',
  360. objectType: 'label',
  361. tableId: '*'
  362. }, {
  363. functionId: functionId,
  364. languageValue: '良品数量:',
  365. objectId: 'rollQty',
  366. objectType: 'label',
  367. tableId: '*'
  368. }, {
  369. functionId: functionId,
  370. languageValue: '卷数:',
  371. objectId: 'rollNums',
  372. objectType: 'label',
  373. tableId: '*'
  374. }, {
  375. functionId: functionId,
  376. languageValue: '良品数量必须是正整数!',
  377. objectId: 'approvedQtyMustBeInteger',
  378. objectType: 'label',
  379. tableId: '*'
  380. }, {
  381. functionId: functionId,
  382. languageValue: '卷数必须是正整数!',
  383. objectId: 'rollQtyMustBeInteger',
  384. objectType: 'label',
  385. tableId: '*'
  386. }, {
  387. functionId: functionId,
  388. languageValue: '良品数量必须大于零且是整数!',
  389. objectId: 'approvedQtyMustMoreTanZeroAndBeInteger',
  390. objectType: 'label',
  391. tableId: '*'
  392. }, {
  393. functionId: functionId,
  394. languageValue: '卷数必须大于零且是整数!',
  395. objectId: 'rollQtyMustMoreTanZeroAndBeInteger',
  396. objectType: 'label',
  397. tableId: '*'
  398. }, {
  399. functionId: functionId,
  400. languageValue: '请先切换人员!',
  401. objectId: 'pleaseSwitchOperator',
  402. objectType: 'label',
  403. tableId: '*'
  404. }, {
  405. functionId: functionId,
  406. languageValue: '确认',
  407. objectId: 'confirmLabel',
  408. objectType: 'label',
  409. tableId: '*'
  410. }, {
  411. functionId: functionId,
  412. languageValue: '取消',
  413. objectId: 'cancelLabel',
  414. objectType: 'label',
  415. tableId: '*'
  416. },
  417. ],
  418. queryLabel: {
  419. functionId: functionId,
  420. table_id: '*',
  421. languageCode: this.$i18n.locale,
  422. objectType: 'label'
  423. },
  424. }
  425. },
  426. methods: {
  427. //页面初始化是的方法
  428. init(scheduleData, operatorData) {
  429. //初始化参数
  430. this.scheduleData = scheduleData;
  431. //初始化操作员对象
  432. this.operatorData = JSON.parse(JSON.stringify(operatorData));
  433. //重置时间
  434. this.pageData.reportDate = this.dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss');
  435. this.pageData.reportTime = this.dayjs(new Date()).format('HH:mm:ss');
  436. //设置参数
  437. this.pageData.orderNo = scheduleData.orderNo;
  438. this.pageData.itemNo = scheduleData.itemNo;
  439. this.pageData.seqNo = scheduleData.seqNo;
  440. this.pageData.rollNo = scheduleData.rollNo;
  441. this.pageData.operatorId = operatorData.operatorId;
  442. //清空参数
  443. this.pageData.rollQty = 0;
  444. this.pageData.rollNums = 1;
  445. // 初始化新增字段
  446. this.pageData.rowCount = scheduleData.rowCount;
  447. this.pageData.rollCount = scheduleData.rollCount;
  448. this.pageData.fixture = scheduleData.carrierNo;
  449. //判断是否启用多语言
  450. // this.getMultiLanguageList(); //刷新多语言的信息
  451. //获取焦点
  452. this.$nextTick(() => {
  453. this.$refs.rollQty && this.$refs.rollQty.focus();
  454. });
  455. this.titleCon = this.labels.componentTitle;//重置标题
  456. // 初始化排数据列表
  457. this.initRowDataList();
  458. },
  459. // ===================== 新增分卷优化方法 =====================
  460. // 初始化排数据列表
  461. initRowDataList() {
  462. this.rowDataList = []
  463. for (let i = 0; i < this.pageData.rowCount; i++) {
  464. this.rowDataList.push({
  465. rowNumber: i,
  466. goodQty: 0,
  467. surfaceLossQty: 0,
  468. poorPerformanceQty: 0,
  469. defectQty: 0,
  470. yieldRate: '0.00%',
  471. totalQty: 0,
  472. remark: ''
  473. })
  474. }
  475. },
  476. // 排数变化时重新初始化
  477. handleRowCountChange() {
  478. if (this.pageData.rollCount > this.pageData.rowCount) {
  479. this.pageData.rollCount = this.pageData.rowCount
  480. }
  481. this.initRowDataList()
  482. },
  483. // 数量变化时自动计算不良数、良率和总数
  484. handleQtyChange(row) {
  485. // 计算不良数 = 面损 + 性能不良
  486. row.defectQty = (row.surfaceLossQty || 0) + (row.poorPerformanceQty || 0)
  487. // 计算总数 = 良品数 + 不良数
  488. row.totalQty = (row.goodQty || 0) + row.defectQty
  489. // 计算良率 = 良品数 / 总数 * 100%
  490. if (row.totalQty > 0) {
  491. const yieldValue = ((row.goodQty || 0) / row.totalQty * 100).toFixed(2)
  492. row.yieldRate = yieldValue + '%'
  493. } else {
  494. row.yieldRate = '0.00%'
  495. }
  496. },
  497. // 验证排数据
  498. validateRowData() {
  499. if (this.pageData.rowCount <= 0) {
  500. this.$message.warning('请输入有效的排数')
  501. return false
  502. }
  503. if (this.pageData.rollCount <= 0) {
  504. this.$message.warning('请输入有效的卷数')
  505. return false
  506. }
  507. if (this.pageData.rollCount > this.pageData.rowCount) {
  508. this.$message.warning('卷数不能大于排数')
  509. return false
  510. }
  511. // 检查是否有数据
  512. const hasData = this.rowDataList.some(row => (row.goodQty > 0 || row.defectQty > 0))
  513. if (!hasData) {
  514. this.$message.warning('请至少输入一行数据')
  515. return false
  516. }
  517. // 检查每一行的良品数必须大于0
  518. for (let i = 0; i < this.rowDataList.length; i++) {
  519. const row = this.rowDataList[i]
  520. if (row.goodQty === null || row.goodQty === undefined || row.goodQty <= 0) {
  521. this.$message.error(`${i + 1} 排的良品数必须大于0`)
  522. return false
  523. }
  524. }
  525. return true
  526. },
  527. // 表格合并行方法(备注列根据卷数合并)
  528. objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  529. // 只对备注列进行合并(最后一列)
  530. if (column.label === '备注') {
  531. // 计算每卷的排数
  532. const rowsPerRoll = Math.floor(this.pageData.rowCount / this.pageData.rollCount)
  533. const remainingRows = this.pageData.rowCount % this.pageData.rollCount
  534. // 计算当前行属于第几卷
  535. let currentRollIndex = 0
  536. let accumulatedRows = 0
  537. for (let i = 0; i < this.pageData.rollCount; i++) {
  538. const currentRollRows = rowsPerRoll + (i < remainingRows ? 1 : 0)
  539. if (rowIndex < accumulatedRows + currentRollRows) {
  540. currentRollIndex = i
  541. break
  542. }
  543. accumulatedRows += currentRollRows
  544. }
  545. // 计算当前卷的排数
  546. const currentRollRows = rowsPerRoll + (currentRollIndex < remainingRows ? 1 : 0)
  547. // 如果是当前卷的第一行,显示合并的单元格
  548. if (rowIndex === accumulatedRows) {
  549. return {
  550. rowspan: currentRollRows,
  551. colspan: 1
  552. }
  553. } else {
  554. // 其他行不显示
  555. return {
  556. rowspan: 0,
  557. colspan: 0
  558. }
  559. }
  560. }
  561. },
  562. // 计算备注wrapper的样式(使用padding-top实现垂直居中)
  563. getRemarkWrapperStyle(rowIndex) {
  564. if (this.pageData.rowCount <= 0 || this.pageData.rollCount <= 0) {
  565. return {}
  566. }
  567. // 计算每卷的排数
  568. const rowsPerRoll = Math.floor(this.pageData.rowCount / this.pageData.rollCount)
  569. const remainingRows = this.pageData.rowCount % this.pageData.rollCount
  570. // 计算当前行属于第几卷
  571. let currentRollIndex = 0
  572. let accumulatedRows = 0
  573. for (let i = 0; i < this.pageData.rollCount; i++) {
  574. const currentRollRows = rowsPerRoll + (i < remainingRows ? 1 : 0)
  575. if (rowIndex < accumulatedRows + currentRollRows) {
  576. currentRollIndex = i
  577. break
  578. }
  579. accumulatedRows += currentRollRows
  580. }
  581. // 计算当前卷的排数
  582. const currentRollRows = rowsPerRoll + (currentRollIndex < remainingRows ? 1 : 0)
  583. // 每行高度约为32px
  584. const rowHeight = 32
  585. const totalHeight = currentRollRows * rowHeight
  586. // textarea的实际高度约为24px(单行)
  587. const textareaHeight = 24
  588. // 计算需要的padding-top来实现垂直居中
  589. const paddingTop = (totalHeight - textareaHeight) / 2
  590. // 返回样式对象
  591. return {
  592. paddingTop: paddingTop + 'px'
  593. }
  594. },
  595. // ===================== 分卷优化方法结束 =====================
  596. // 查询固定载具列表
  597. queryFixedCarrierList() {
  598. const params = {
  599. site: this.scheduleData.site,
  600. carrierNo: this.carrierSearchData.carrierNo,
  601. carrierTypeName: this.carrierSearchData.carrierTypeName,
  602. specification: this.carrierSearchData.specification
  603. }
  604. getFixedCarrierList(params).then(({data}) => {
  605. if (data && data.code === 0) {
  606. this.carrierList = data.data
  607. this.carrierModelFlag = true
  608. } else {
  609. this.$message.error(data.msg || '获取固定载具列表失败')
  610. }
  611. }).catch(error => {
  612. this.$message.error('获取固定载具列表失败: ' + error.message)
  613. })
  614. },
  615. // 选中固定载具
  616. selectCarrier(row) {
  617. this.pageData.fixture = row.carrierNo
  618. this.carrierModelFlag = false
  619. },
  620. // 批量编辑模态框
  621. editBatchModel() {
  622. if (this.editBatchVisible) {
  623. this.editBatchVisible = false
  624. } else {
  625. this.editBatchVisible = true
  626. }
  627. },
  628. // 批量保存固定载具可用数量
  629. batchSaveCarrier() {
  630. this.saveLoading = true
  631. // 调用API保存
  632. import('@/api/yieldReport/com_separate_roll.js').then(module => {
  633. const { updateFixedCarrierBatch } = module
  634. updateFixedCarrierBatch(this.carrierList).then(({data}) => {
  635. if (data && data.code === 0) {
  636. this.$message.success('批量保存成功')
  637. this.editBatchVisible = false
  638. this.queryFixedCarrierList()
  639. } else {
  640. this.$message.error(data.msg || '批量保存失败')
  641. }
  642. }).catch(error => {
  643. this.$message.error('批量保存失败: ' + error.message)
  644. }).finally(() => {
  645. this.saveLoading = false
  646. })
  647. })
  648. },
  649. // 打印固定载具
  650. printCarrier(row) {
  651. // 构造打印数据
  652. const printData = {
  653. carrierNo: row.carrierNo,
  654. carrierTypeName: row.carrierTypeName,
  655. specification: row.specification,
  656. dimensions: row.dimensions,
  657. availableQty: row.availableQty || 0,
  658. site: this.scheduleData.site
  659. }
  660. // 调用打印功能
  661. this.printCarrierLabel(printData)
  662. },
  663. // 打印载具标签
  664. printCarrierLabel(data) {
  665. try {
  666. // 生成二维码(使用 QRCode.js 或者使用在线二维码API)
  667. const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=${encodeURIComponent(data.carrierNo)}`
  668. // 打印HTML模板
  669. const printContent = `
  670. <div style="width: 100mm; font-family: Arial, sans-serif; padding: 10px; position: relative;">
  671. <!-- 左上角二维码 -->
  672. <div style="position: absolute; top: 10px; left: 10px;">
  673. <img src="${qrCodeUrl}" style="width: 80px; height: 80px; border: 1px solid #ddd;" alt="QR Code"/>
  674. </div>
  675. <!-- 标题 -->
  676. <div style="text-align: center; font-size: 20px; font-weight: bold; margin-bottom: 15px; padding-top: 5px;">
  677. 固定载具标签
  678. </div>
  679. <!-- 信息表格 -->
  680. <table style="width: 100%; border-collapse: collapse; font-size: 14px; margin-top: 10px;">
  681. <tr>
  682. <td style="padding: 8px; border: 1px solid #333; font-weight: bold; width: 35%; background-color: #f5f5f5;">标签条码:</td>
  683. <td style="padding: 8px; border: 1px solid #333; font-size: 15px; font-weight: bold;">${data.carrierNo || ''}</td>
  684. </tr>
  685. <tr>
  686. <td style="padding: 8px; border: 1px solid #333; font-weight: bold; background-color: #f5f5f5;">载具类型:</td>
  687. <td style="padding: 8px; border: 1px solid #333;">${data.carrierTypeName || ''}</td>
  688. </tr>
  689. <tr>
  690. <td style="padding: 8px; border: 1px solid #333; font-weight: bold; background-color: #f5f5f5;">规格描述:</td>
  691. <td style="padding: 8px; border: 1px solid #333;">${data.specification || ''}</td>
  692. </tr>
  693. <tr>
  694. <td style="padding: 8px; border: 1px solid #333; font-weight: bold; background-color: #f5f5f5;">尺寸:</td>
  695. <td style="padding: 8px; border: 1px solid #333;">${data.dimensions || ''}</td>
  696. </tr>
  697. <tr>
  698. <td style="padding: 8px; border: 1px solid #333; font-weight: bold; background-color: #f5f5f5;">可用数量:</td>
  699. <td style="padding: 8px; border: 1px solid #333; font-size: 18px; font-weight: bold; color: #e74c3c;">${data.availableQty}</td>
  700. </tr>
  701. </table>
  702. <!-- 打印时间 -->
  703. <div style="text-align: center; margin-top: 15px; font-size: 11px; color: #999; border-top: 1px dashed #ccc; padding-top: 10px;">
  704. 打印时间: ${this.dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')}
  705. </div>
  706. </div>
  707. `
  708. // 创建打印窗口
  709. const printWindow = window.open('', '_blank')
  710. printWindow.document.write(`
  711. <html>
  712. <head>
  713. <title>打印固定载具标签</title>
  714. <meta charset="UTF-8">
  715. <style>
  716. @page { size: auto; margin: 5mm; }
  717. body { margin: 0; padding: 0; }
  718. @media print {
  719. body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  720. }
  721. </style>
  722. </head>
  723. <body>
  724. ${printContent}
  725. </body>
  726. </html>
  727. `)
  728. printWindow.document.close()
  729. // 延迟打印,确保二维码图片加载完成
  730. setTimeout(() => {
  731. printWindow.print()
  732. printWindow.close()
  733. }, 500)
  734. this.$message.success('正在打印载具标签...')
  735. } catch (error) {
  736. this.$message.error('打印失败: ' + error.message)
  737. }
  738. },
  739. /*关闭modal*/
  740. closeDialog(){
  741. //刷新报工的页面
  742. this.$emit('refreshPageData');
  743. //关闭当前的页面
  744. this.$emit('update:visible', false);
  745. },
  746. /*检查材料卷号的数据*/
  747. checkValidQty() {
  748. //获取当前是的数量
  749. let rollQty = parseFloat(this.pageData.rollQty);
  750. //判断是否可以修改
  751. if (rollQty <= 0 || !Number.isInteger(rollQty)){
  752. this.$message.error(this.labels.approvedQtyMustBeInteger);
  753. return false;
  754. }
  755. },
  756. /*检查材料卷号的数据*/
  757. checkRollNums() {
  758. //获取当前是的数量
  759. let rollNums = parseFloat(this.pageData.rollNums);
  760. //判断是否是正整数
  761. if (rollNums <= 0 || !Number.isInteger(rollNums)){
  762. this.$message.error(this.labels.rollQtyMustBeInteger);
  763. return false;
  764. }
  765. },
  766. checkCreateSeparateRolllBun() {
  767. //人员判断
  768. if (this.pageData.operatorId === '' || this.pageData.operatorId == null) {
  769. this.$message.error(this.labels.pleaseSwitchOperator);
  770. return false;
  771. }
  772. // //获取当前是的数量
  773. // let rollQty = parseFloat(this.pageData.rollQty);
  774. // //判断是否可以修改
  775. // if (rollQty <= 0 || !Number.isInteger(rollQty)){
  776. // this.$message.error(this.labels.approvedQtyMustMoreTanZeroAndBeInteger);
  777. // return false;
  778. // }
  779. // //获取当前是的数量
  780. // let rollNums = parseFloat(this.pageData.rollNums);
  781. // //判断是否是正整数
  782. // if (rollNums <= 0 || !Number.isInteger(rollNums)){
  783. // this.$message.error(this.labels.rollQtyMustMoreTanZeroAndBeInteger);
  784. // return false;
  785. // }
  786. //校验是否继续
  787. checkCreateSplitSfdcRoll(this.pageData)
  788. .then(({data}) => {
  789. //判断是否成功
  790. if (data.code == 500) {
  791. this.$message.error(data.msg);
  792. } else if (data.resultMap.resultCode == '201') {
  793. //打开异常原因录入的界面
  794. this.$confirm(data.resultMap.resultMsg, '提示', {
  795. confirmButtonText: this.labels.confirmLabel,
  796. celButtonText: this.labels.cancelLabel,
  797. type: 'warning'
  798. }).then(() => {
  799. //执行切换卷的操作
  800. this.createSeparateRolllOperation();
  801. });
  802. } else { //执行切换卷的操作
  803. this.createSeparateRolllOperation();
  804. }
  805. });
  806. },
  807. /*执行创建分卷的操作*/
  808. async createSeparateRolllOperation() {
  809. // 验证排数据
  810. if (!this.validateRowData()) {
  811. return false
  812. }
  813. try {
  814. // 计算分卷
  815. const rowsPerRoll = Math.floor(this.pageData.rowCount / this.pageData.rollCount)
  816. const remainingRows = this.pageData.rowCount % this.pageData.rollCount
  817. let currentRowIndex = 0
  818. const allPrintList = []
  819. // 循环创建每一卷
  820. for (let rollIndex = 0; rollIndex < this.pageData.rollCount; rollIndex++) {
  821. // 计算当前卷的排数
  822. const currentRollRows = rowsPerRoll + (rollIndex < remainingRows ? 1 : 0)
  823. // 计算当前卷的良品和不良总数
  824. let totalGoodQty = 0
  825. let totalDefectQty = 0
  826. const rollRows = []
  827. // 获取当前卷的备注(第一排的备注)
  828. let rollRemark = ''
  829. for (let i = 0; i < currentRollRows; i++) {
  830. const row = this.rowDataList[currentRowIndex + i]
  831. totalGoodQty += row.goodQty || 0
  832. totalDefectQty += row.defectQty || 0
  833. // 第一排的备注作为整卷的备注
  834. if (i === 0) {
  835. rollRemark = row.remark || ''
  836. }
  837. rollRows.push({
  838. rowNumber: row.rowNumber,
  839. goodQty: row.goodQty || 0,
  840. surfaceLossQty: row.surfaceLossQty || 0,
  841. poorPerformanceQty: row.poorPerformanceQty || 0,
  842. defectQty: row.defectQty || 0,
  843. totalQty: row.totalQty || 0,
  844. remark: row.remark || ''
  845. })
  846. }
  847. // 构建请求数据(每次调用rollNums固定为1)
  848. const requestData = {
  849. ...this.pageData,
  850. rollQty: totalGoodQty, // 该卷的良品总数
  851. rollNums: 1, // 固定为1
  852. totalDefectQty: totalDefectQty, // 该卷的不良总数
  853. rollRows: rollRows, // 该卷包含的排数据
  854. remark: rollRemark // 该卷的备注
  855. }
  856. // 调用后端创建单个卷
  857. const {data} = await createSplitSfdcRoll(requestData)
  858. if (data.code === 500) {
  859. throw new Error(data.msg)
  860. }
  861. // 收集打印数据
  862. if (data.printList && data.printList.length > 0) {
  863. allPrintList.push(...data.printList)
  864. }
  865. // 进度提示
  866. this.$message.success(`${rollIndex + 1}/${this.pageData.rollCount}卷创建成功`)
  867. currentRowIndex += currentRollRows
  868. }
  869. // 所有卷创建完成
  870. this.$message.success('创建分卷完成!')
  871. // 处理打印的数据
  872. if (allPrintList.length > 0) {
  873. printSfdcLabel(allPrintList)
  874. }
  875. // 延时关闭弹窗
  876. setTimeout(() =>{
  877. //关闭当前的页面
  878. this.closeDialog()
  879. }, 1000)
  880. } catch (error) {
  881. this.$message.error('创建分卷失败: ' + error.message)
  882. }
  883. },
  884. // 保存 默认配置 列
  885. async saveMultiLanguage() {
  886. // 保存页面 button label title 属性
  887. let buttons = this.buttonList;
  888. let labels = this.labelsList;
  889. await saveButtonList(buttons)
  890. await saveButtonList(labels)
  891. },
  892. getMultiLanguageList() {
  893. //首先查询当前按钮的多语言
  894. searchFunctionButtonList(this.queryButton).then(({data}) => {
  895. if (data && data.code == 0 ) {
  896. this.buttons = data.data
  897. } else {
  898. // saveButtonList(this.buttonList).then(({data}) => {
  899. // })
  900. }
  901. });
  902. //其次查询当前标签的多语言
  903. searchFunctionButtonList(this.queryLabel).then(({data}) => {
  904. if (data && data.code == 0 ) {
  905. this.labels = data.data
  906. } else {
  907. // saveButtonList(this.buttonList).then(({data}) => {
  908. // })
  909. }
  910. });
  911. },
  912. },
  913. created() {
  914. // this.factoryList()
  915. // this.getLanguageList()
  916. }
  917. }
  918. </script>
  919. <style scoped lang="scss">
  920. /*调节页面button和input的上下间距*/
  921. .customer-css .customer-button{
  922. margin-top: 25px;
  923. }
  924. /*调节fieldset下的样式*/
  925. .customer-fieldset .customer-item{
  926. margin-top: -15px;
  927. }
  928. /*fieldset下table的样式*/
  929. .customer-fieldset /deep/ .el-table__header th.is-leaf{
  930. line-height: 16px;
  931. }
  932. /deep/ .customer-tab .el-tabs__content{
  933. padding: 0px !important;
  934. }
  935. /* 良品数输入框样式 - 绿色加粗 */
  936. .good-qty-input >>> .el-input__inner {
  937. font-weight: bold !important;
  938. color: #67c23a !important;
  939. font-size: 12px !important;
  940. }
  941. ::v-deep .good-qty-input .el-input__inner {
  942. font-weight: bold !important;
  943. color: #67c23a !important;
  944. font-size: 12px !important;
  945. }
  946. /deep/ .good-qty-input .el-input__inner {
  947. font-weight: bold !important;
  948. color: #67c23a !important;
  949. font-size: 12px !important;
  950. }
  951. /* 不良数输入框样式 - 红色加粗 */
  952. .defect-qty-input >>> .el-input__inner {
  953. font-weight: bold !important;
  954. color: #f56c6c !important;
  955. font-size: 12px !important;
  956. }
  957. ::v-deep .defect-qty-input .el-input__inner {
  958. font-weight: bold !important;
  959. color: #f56c6c !important;
  960. font-size: 12px !important;
  961. }
  962. /deep/ .defect-qty-input .el-input__inner {
  963. font-weight: bold !important;
  964. color: #f56c6c !important;
  965. font-size: 12px !important;
  966. }
  967. /* 总数显示样式 */
  968. .total-display {
  969. font-weight: bold;
  970. color: #303133;
  971. font-size: 12px;
  972. }
  973. /* 备注列单元格样式 - 使用绝对定位填满 */
  974. .customer-dialog >>> .el-table td:last-child {
  975. padding: 0 !important;
  976. position: relative !important;
  977. }
  978. .customer-dialog /deep/ .el-table td:last-child {
  979. padding: 0 !important;
  980. position: relative !important;
  981. }
  982. /* 备注包装器 - 绝对定位填满单元格 */
  983. .customer-dialog >>> .remark-wrapper {
  984. position: absolute !important;
  985. top: 0 !important;
  986. left: 0 !important;
  987. right: 0 !important;
  988. bottom: 0 !important;
  989. width: 100% !important;
  990. height: 100% !important;
  991. }
  992. .customer-dialog /deep/ .remark-wrapper {
  993. position: absolute !important;
  994. top: 0 !important;
  995. left: 0 !important;
  996. right: 0 !important;
  997. bottom: 0 !important;
  998. width: 100% !important;
  999. height: 100% !important;
  1000. }
  1001. /* 备注textarea */
  1002. .customer-dialog >>> .remark-textarea {
  1003. width: 100% !important;
  1004. height: 100% !important;
  1005. }
  1006. .customer-dialog >>> .remark-textarea .el-textarea__inner {
  1007. border: none !important;
  1008. padding: 8px 10px !important;
  1009. border-radius: 0 !important;
  1010. resize: none !important;
  1011. width: 100% !important;
  1012. height: 100% !important;
  1013. box-sizing: border-box !important;
  1014. overflow-y: auto !important;
  1015. }
  1016. .customer-dialog /deep/ .remark-textarea {
  1017. width: 100% !important;
  1018. height: 100% !important;
  1019. }
  1020. .customer-dialog /deep/ .remark-textarea .el-textarea__inner {
  1021. border: none !important;
  1022. padding: 8px 10px !important;
  1023. border-radius: 0 !important;
  1024. resize: none !important;
  1025. width: 100% !important;
  1026. height: 100% !important;
  1027. box-sizing: border-box !important;
  1028. overflow-y: auto !important;
  1029. }
  1030. </style>
  1031. <style lang="scss">
  1032. /* 全局样式 - 良品数和不良数输入框颜色 */
  1033. .good-qty-input .el-input__inner {
  1034. font-weight: bold !important;
  1035. color: #67c23a !important;
  1036. font-size: 16px !important;
  1037. }
  1038. .defect-qty-input .el-input__inner {
  1039. font-weight: bold !important;
  1040. color: #f56c6c !important;
  1041. font-size: 16px !important;
  1042. }
  1043. /* 备注列样式 - 只针对创建分卷对话框 */
  1044. .customer-css .el-table td:last-child {
  1045. padding: 0 !important;
  1046. position: relative !important;
  1047. }
  1048. /* 备注包装器 - 填满整个单元格 */
  1049. .customer-css .remark-wrapper {
  1050. position: absolute !important;
  1051. top: 0 !important;
  1052. left: 0 !important;
  1053. right: 0 !important;
  1054. bottom: 0 !important;
  1055. width: 100% !important;
  1056. height: 100% !important;
  1057. }
  1058. /* 备注textarea容器 */
  1059. .customer-css .remark-textarea {
  1060. width: 100% !important;
  1061. height: 100% !important;
  1062. }
  1063. .customer-css .remark-textarea .el-textarea__inner {
  1064. border: none !important;
  1065. padding: 8px 10px !important;
  1066. border-radius: 0 !important;
  1067. resize: none !important;
  1068. width: 100% !important;
  1069. height: 100% !important;
  1070. box-sizing: border-box !important;
  1071. overflow-y: auto !important;
  1072. }
  1073. </style>