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.

1121 lines
35 KiB

  1. <template>
  2. <div class="mod-config">
  3. <!-- 条件查询 -->
  4. <el-card :class="['search-card', { 'collapsed': !searchExpanded }]" shadow="hover">
  5. <div slot="header" class="search-header">
  6. <div class="header-left">
  7. <i class="el-icon-search"></i>
  8. <span class="header-title">工单材料上机记录</span>
  9. </div>
  10. <div class="header-right">
  11. <el-button
  12. type="text"
  13. size="small"
  14. @click="toggleSearchExpand"
  15. class="collapse-btn">
  16. <i :class="searchExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
  17. {{ searchExpanded ? '收起' : '展开' }}
  18. </el-button>
  19. </div>
  20. </div>
  21. <el-form
  22. :inline="true"
  23. label-position="top"
  24. :model="searchData"
  25. class="search-form"
  26. @keyup.enter.native="getData">
  27. <!-- 所有查询条件 -->
  28. <template v-if="searchExpanded">
  29. <!-- 第一行 -->
  30. <el-row :gutter="16">
  31. <el-col :span="4">
  32. <el-form-item label="工厂编码">
  33. <el-select v-model="searchData.site" placeholder="请选择工厂" clearable filterable style="width: 100%">
  34. <el-option v-for="item in siteList" :key="item" :label="item" :value="item"></el-option>
  35. </el-select>
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="4">
  39. <el-form-item label="工单号">
  40. <el-input v-model="searchData.orderNo" placeholder="请输入工单号" clearable></el-input>
  41. </el-form-item>
  42. </el-col>
  43. <el-col :span="4">
  44. <el-form-item label="派工单号">
  45. <el-input v-model="searchData.seqNo" placeholder="请输入派工单号" clearable></el-input>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="4">
  49. <el-form-item label="材料卷号">
  50. <el-input v-model="searchData.rmRollNo" placeholder="请输入材料卷号" clearable></el-input>
  51. </el-form-item>
  52. </el-col>
  53. <el-col :span="4">
  54. <el-form-item label="材料编码">
  55. <el-input v-model="searchData.partNo" placeholder="请输入材料编码" clearable></el-input>
  56. </el-form-item>
  57. </el-col>
  58. <el-col :span="4">
  59. <el-form-item label="材料名称">
  60. <el-input v-model="searchData.partDesc" placeholder="请输入材料名称" clearable></el-input>
  61. </el-form-item>
  62. </el-col>
  63. </el-row>
  64. <!-- 第二行 -->
  65. <el-row :gutter="16">
  66. <el-col :span="4">
  67. <el-form-item label="产品编码">
  68. <el-input v-model="searchData.productPartNo" placeholder="请输入产品编码" clearable></el-input>
  69. </el-form-item>
  70. </el-col>
  71. <el-col :span="4">
  72. <el-form-item label="加工中心">
  73. <el-input v-model="searchData.workCenterNo" placeholder="请输入加工中心" clearable></el-input>
  74. </el-form-item>
  75. </el-col>
  76. <el-col :span="4">
  77. <el-form-item label="机台">
  78. <el-input v-model="searchData.resourceId" placeholder="请输入机台" clearable></el-input>
  79. </el-form-item>
  80. </el-col>
  81. <el-col :span="4">
  82. <el-form-item label="操作类型">
  83. <el-select v-model="searchData.histType" placeholder="请选择" clearable style="width: 100%">
  84. <el-option label="全部" value=""></el-option>
  85. <el-option label="发料" value="发料"></el-option>
  86. <el-option label="换料" value="换料"></el-option>
  87. <el-option label="退料" value="退料"></el-option>
  88. </el-select>
  89. </el-form-item>
  90. </el-col>
  91. <el-col :span="4">
  92. <el-form-item label="是否结束">
  93. <el-select v-model="searchData.finishedFlag" placeholder="请选择" clearable style="width: 100%">
  94. <el-option label="全部" value=""></el-option>
  95. <el-option label="是" value="Y"></el-option>
  96. <el-option label="否" value="N"></el-option>
  97. </el-select>
  98. </el-form-item>
  99. </el-col>
  100. <el-col :span="4">
  101. <el-form-item label="是否退料">
  102. <el-select v-model="searchData.unissueFlag" placeholder="请选择" clearable style="width: 100%">
  103. <el-option label="全部" value=""></el-option>
  104. <el-option label="是" value="Y"></el-option>
  105. <el-option label="否" value="N"></el-option>
  106. </el-select>
  107. </el-form-item>
  108. </el-col>
  109. </el-row>
  110. <!-- 第三行 -->
  111. <el-row :gutter="16">
  112. <el-col :span="4">
  113. <el-form-item label="是否关键料">
  114. <el-select v-model="searchData.keyRMFlag" placeholder="请选择" clearable style="width: 100%">
  115. <el-option label="全部" value=""></el-option>
  116. <el-option label="是" value="Y"></el-option>
  117. <el-option label="否" value="N"></el-option>
  118. </el-select>
  119. </el-form-item>
  120. </el-col>
  121. <el-col :span="8">
  122. <el-form-item label="上机时间">
  123. <el-date-picker
  124. v-model="searchData.startDate1"
  125. type="date"
  126. value-format="yyyy-MM-dd"
  127. placeholder="开始日期"
  128. style="width: 45%">
  129. </el-date-picker>
  130. <span style="margin: 0 6px; color: #DCDFE6;">~</span>
  131. <el-date-picker
  132. v-model="searchData.startDate2"
  133. type="date"
  134. value-format="yyyy-MM-dd"
  135. placeholder="结束日期"
  136. style="width: 45%">
  137. </el-date-picker>
  138. </el-form-item>
  139. </el-col>
  140. </el-row>
  141. </template>
  142. <!-- 操作按钮区域 -->
  143. <el-row :gutter="16">
  144. <el-col :span="24">
  145. <div class="search-actions">
  146. <div class="action-left">
  147. <el-button
  148. type="primary"
  149. icon="el-icon-search"
  150. :loading="searchLoading"
  151. @click="getData">
  152. 查询
  153. </el-button>
  154. <el-button
  155. icon="el-icon-refresh-left"
  156. @click="resetSearch">
  157. 重置
  158. </el-button>
  159. </div>
  160. </div>
  161. </el-col>
  162. </el-row>
  163. </el-form>
  164. </el-card>
  165. <!-- 主信息列表 -->
  166. <div class="section-title-bar">
  167. <i class="el-icon-document"></i>
  168. <span>材料上机记录</span>
  169. <span class="total-count"> {{ totalCount }} </span>
  170. </div>
  171. <el-table
  172. ref="mainTable"
  173. :height="tableHeight"
  174. :data="dataList"
  175. border
  176. v-loading="dataListLoading"
  177. style="width: 100%;">
  178. <el-table-column
  179. type="index"
  180. header-align="center"
  181. align="center"
  182. width="60"
  183. label="序号">
  184. </el-table-column>
  185. <el-table-column
  186. header-align="center"
  187. align="center"
  188. width="120"
  189. fixed="left"
  190. label="操作">
  191. <template slot-scope="scope">
  192. <el-link style="cursor: pointer; margin-right: 8px" @click="printMaterialLabel(scope.row)">打印</el-link>
  193. <el-link style="cursor: pointer" v-if="scope.row.finishedFlag == 'N' && scope.row.histType == '发料'" @click="showReturnMaterialDialog(scope.row)">异常退料</el-link>
  194. </template>
  195. </el-table-column>
  196. <el-table-column
  197. v-for="(item, index) in columnList"
  198. :key="index"
  199. :prop="item.columnProp"
  200. :header-align="item.headerAlign"
  201. :show-overflow-tooltip="true"
  202. :align="item.align"
  203. :min-width="item.columnWidth"
  204. :label="item.columnLabel">
  205. <template slot-scope="scope">
  206. <span
  207. :class="{
  208. 'status-yes': (item.columnProp === 'finishedFlagDesc' || item.columnProp === 'unissueFlagDesc' || item.columnProp === 'keyRMFlagDesc') && scope.row[item.columnProp] === '是',
  209. 'status-no': (item.columnProp === 'finishedFlagDesc' || item.columnProp === 'unissueFlagDesc' || item.columnProp === 'keyRMFlagDesc') && scope.row[item.columnProp] === '否'
  210. }">
  211. {{ scope.row[item.columnProp] }}
  212. </span>
  213. </template>
  214. </el-table-column>
  215. </el-table>
  216. <el-pagination
  217. style="margin-top: 0px"
  218. @size-change="sizeChangeHandle"
  219. @current-change="currentChangeHandle"
  220. :current-page="pageIndex"
  221. :page-sizes="[20, 50, 100, 200, 500]"
  222. :page-size="pageSize"
  223. :total="totalCount"
  224. layout="total, sizes, prev, pager, next, jumper">
  225. </el-pagination>
  226. <!-- 异常退料对话框 -->
  227. <el-dialog
  228. title="异常退料"
  229. :visible.sync="returnMaterialVisible"
  230. width="600px"
  231. class="material-dialog"
  232. v-drag>
  233. <div class="material-content">
  234. <el-form :model="returnData" label-position="top" label-width="100px">
  235. <!-- 材料信息卡片 -->
  236. <div class="material-info-card">
  237. <div class="info-header">
  238. <i class="el-icon-document"></i>
  239. <span>材料信息</span>
  240. </div>
  241. <div class="info-content">
  242. <el-row :gutter="15">
  243. <el-col :span="12">
  244. <div class="info-row">
  245. <label class="info-label">工单号</label>
  246. <span class="info-value">{{ returnData.orderNo || '-' }}</span>
  247. </div>
  248. </el-col>
  249. <el-col :span="12">
  250. <div class="info-row">
  251. <label class="info-label">派工单号</label>
  252. <span class="info-value">{{ returnData.seqNo || '-' }}</span>
  253. </div>
  254. </el-col>
  255. </el-row>
  256. <el-row :gutter="15">
  257. <el-col :span="12">
  258. <div class="info-row">
  259. <label class="info-label">材料卷号</label>
  260. <span class="info-value">{{ returnData.rmRollNo || '-' }}</span>
  261. </div>
  262. </el-col>
  263. <el-col :span="12">
  264. <div class="info-row">
  265. <label class="info-label">材料编码</label>
  266. <span class="info-value">{{ returnData.partNo || '-' }}</span>
  267. </div>
  268. </el-col>
  269. </el-row>
  270. <el-row :gutter="15">
  271. <el-col :span="24">
  272. <div class="info-row">
  273. <label class="info-label">材料名称</label>
  274. <span class="info-value">{{ returnData.partDesc || '-' }}</span>
  275. </div>
  276. </el-col>
  277. </el-row>
  278. <el-row :gutter="15">
  279. <el-col :span="12">
  280. <div class="info-row">
  281. <label class="info-label">规格型号</label>
  282. <span class="info-value">{{ returnData.spec || '-' }}</span>
  283. </div>
  284. </el-col>
  285. </el-row>
  286. </div>
  287. </div>
  288. <!-- 退料设置区域 -->
  289. <div class="return-settings">
  290. <el-row :gutter="15">
  291. <el-col :span="8">
  292. <el-form-item label="上机数量" class="form-item-enhanced">
  293. <el-input
  294. v-model="displayOnMachineQty"
  295. disabled
  296. size="large"
  297. style="width: 100%">
  298. </el-input>
  299. </el-form-item>
  300. </el-col>
  301. <el-col :span="8">
  302. <el-form-item label="退料数量" class="form-item-enhanced">
  303. <el-input class="inlineNumber numInput"
  304. v-model="returnData.returnQty"
  305. type="number"
  306. placeholder="请输入退料数量"
  307. size="large"
  308. @input="calculateRemainQty"
  309. style="width: 100%">
  310. </el-input>
  311. </el-form-item>
  312. </el-col>
  313. <el-col :span="8">
  314. <el-form-item label="剩余数量" class="form-item-enhanced">
  315. <el-input
  316. v-model="displayRemainQty"
  317. disabled
  318. size="large"
  319. :class="{'remain-negative': returnData.remainQty < 0}"
  320. style="width: 100%">
  321. </el-input>
  322. </el-form-item>
  323. </el-col>
  324. </el-row>
  325. <!-- 备注 -->
  326. <el-row style="margin-bottom: 30px">
  327. <el-col :span="24">
  328. <el-form-item label="备注">
  329. <el-input
  330. v-model="returnData.remark"
  331. type="textarea"
  332. :rows="3"
  333. placeholder="请输入备注"
  334. show-word-limit>
  335. </el-input>
  336. </el-form-item>
  337. </el-col>
  338. </el-row>
  339. </div>
  340. </el-form>
  341. </div>
  342. <span slot="footer" class="dialog-footer">
  343. <el-button type="primary" :loading="returnLoading" @click="submitReturnMaterial">确定</el-button>
  344. <el-button @click="returnMaterialVisible = false">取消</el-button>
  345. </span>
  346. </el-dialog>
  347. </div>
  348. </template>
  349. <script>
  350. import {
  351. listMaterialOnMachineRecord,
  352. materialReturnDuringProduction
  353. } from '@/api/schedule/materialOnMachineRecord.js';
  354. import {getSiteList } from "@/api/report/partTemplateStatus.js";
  355. import { callUspPartLabelTemplate } from '@/api/wms/wms';
  356. import getLodop from '@/utils/LodopFuncs.js';
  357. import labelPrintTemplates from '@/mixins/labelPrintTemplates.js';
  358. export default {
  359. mixins: [labelPrintTemplates],
  360. data() {
  361. return {
  362. searchExpanded: true,
  363. searchLoading: false,
  364. dataListLoading: false,
  365. searchData: {
  366. site: '',
  367. orderNo: '',
  368. seqNo: '',
  369. partNo: '',
  370. partDesc: '',
  371. rmRollNo: '',
  372. histType: '',
  373. finishedFlag: '',
  374. unissueFlag: '',
  375. keyRMFlag: '',
  376. productPartNo: '',
  377. workCenterNo: '',
  378. resourceId: '',
  379. startDate1: '',
  380. startDate2: ''
  381. },
  382. siteList: [],
  383. dataList: [],
  384. pageIndex: 1,
  385. pageSize: 50,
  386. totalCount: 0,
  387. tableHeight: 400,
  388. columnList: [
  389. { columnProp: 'orderNo', columnLabel: '工单号', columnWidth: '120', headerAlign: 'center', align: 'left' },
  390. { columnProp: 'seqNo', columnLabel: '派工单号', columnWidth: '150', headerAlign: 'center', align: 'left' },
  391. { columnProp: 'itemNo', columnLabel: '工序号', columnWidth: '70', headerAlign: 'center', align: 'center' },
  392. { columnProp: 'operationDesc', columnLabel: '工序描述', columnWidth: '100', headerAlign: 'center', align: 'left' },
  393. { columnProp: 'workCenterNo', columnLabel: '加工中心', columnWidth: '100', headerAlign: 'center', align: 'left' },
  394. { columnProp: 'resourceId', columnLabel: '机台', columnWidth: '100', headerAlign: 'center', align: 'left' },
  395. { columnProp: 'rmRollNo', columnLabel: '材料卷号', columnWidth: '150', headerAlign: 'center', align: 'left' },
  396. { columnProp: 'partNo', columnLabel: '材料编码', columnWidth: '120', headerAlign: 'center', align: 'left' },
  397. { columnProp: 'partDesc', columnLabel: '材料名称', columnWidth: '150', headerAlign: 'center', align: 'left' },
  398. { columnProp: 'spec', columnLabel: '规格型号', columnWidth: '120', headerAlign: 'center', align: 'left' },
  399. { columnProp: 'transQty', columnLabel: '上机数量', columnWidth: '100', headerAlign: 'center', align: 'right' },
  400. { columnProp: 'netIssueQty', columnLabel: '净发料数量', columnWidth: '100', headerAlign: 'center', align: 'right' },
  401. { columnProp: 'histType', columnLabel: '操作类型', columnWidth: '80', headerAlign: 'center', align: 'center' },
  402. { columnProp: 'startDate', columnLabel: '上机时间', columnWidth: '150', headerAlign: 'center', align: 'center' },
  403. { columnProp: 'finishedFlagDesc', columnLabel: '是否结束', columnWidth: '80', headerAlign: 'center', align: 'center' },
  404. { columnProp: 'finishedDate', columnLabel: '结束时间', columnWidth: '150', headerAlign: 'center', align: 'center' },
  405. { columnProp: 'unissueFlagDesc', columnLabel: '是否退料', columnWidth: '80', headerAlign: 'center', align: 'center' },
  406. { columnProp: 'keyRMFlagDesc', columnLabel: '是否关键料', columnWidth: '90', headerAlign: 'center', align: 'center' },
  407. { columnProp: 'reportedBy', columnLabel: '操作人', columnWidth: '100', headerAlign: 'center', align: 'left' },
  408. { columnProp: 'productPartNo', columnLabel: '产品编码', columnWidth: '120', headerAlign: 'center', align: 'left' },
  409. { columnProp: 'productPartDesc', columnLabel: '产品名称', columnWidth: '150', headerAlign: 'center', align: 'left' },
  410. { columnProp: 'orderStatus', columnLabel: '工单状态', columnWidth: '80', headerAlign: 'center', align: 'center' },
  411. { columnProp: 'customerId', columnLabel: '客户编码', columnWidth: '100', headerAlign: 'center', align: 'left' },
  412. { columnProp: 'customerName', columnLabel: '客户名称', columnWidth: '120', headerAlign: 'center', align: 'left' },
  413. { columnProp: 'remark', columnLabel: '备注', columnWidth: '150', headerAlign: 'center', align: 'left' }
  414. ],
  415. // 异常退料对话框
  416. returnMaterialVisible: false,
  417. returnLoading: false,
  418. returnData: {
  419. site: '',
  420. orderNo: '',
  421. itemNo: '',
  422. seqNo: '',
  423. rollNo: '',
  424. rmRollNo: '',
  425. partNo: '',
  426. partDesc: '',
  427. spec: '',
  428. histSeqNo: '',
  429. operatorId: '',
  430. onMachineQty: 0,
  431. returnQty: 0,
  432. remainQty: 0,
  433. remark: ''
  434. }
  435. }
  436. },
  437. computed: {
  438. displayOnMachineQty() {
  439. return this.returnData.onMachineQty || this.returnData.onMachineQty === 0 ? String(this.returnData.onMachineQty) : '';
  440. },
  441. displayRemainQty() {
  442. return this.returnData.remainQty || this.returnData.remainQty === 0 ? String(this.returnData.remainQty) : '';
  443. }
  444. },
  445. created() {
  446. this.setDefaultDates();
  447. this.getSiteList();
  448. this.calculateTableHeight();
  449. window.addEventListener('resize', this.calculateTableHeight);
  450. },
  451. beforeDestroy() {
  452. window.removeEventListener('resize', this.calculateTableHeight);
  453. },
  454. methods: {
  455. // 设置默认日期(本月)
  456. setDefaultDates() {
  457. const now = new Date();
  458. const firstDay = new Date(now.getFullYear(), now.getMonth(), 1);
  459. const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0);
  460. this.searchData.startDate1 = this.formatDate(firstDay);
  461. this.searchData.startDate2 = this.formatDate(lastDay);
  462. },
  463. formatDate(date) {
  464. const year = date.getFullYear();
  465. const month = String(date.getMonth() + 1).padStart(2, '0');
  466. const day = String(date.getDate()).padStart(2, '0');
  467. return `${year}-${month}-${day}`;
  468. },
  469. // 获取Site列表
  470. getSiteList() {
  471. getSiteList().then(({ data }) => {
  472. if (data && data.code === 0) {
  473. this.siteList = data.siteList || [];
  474. // 如果有权限的site,默认选择第一个
  475. if (this.siteList.length > 0) {
  476. this.searchData.site = this.siteList[0];
  477. }
  478. }
  479. }).catch(err => {
  480. console.error('获取Site列表失败:', err);
  481. });
  482. },
  483. // 计算表格高度
  484. calculateTableHeight() {
  485. this.$nextTick(() => {
  486. const windowHeight = window.innerHeight;
  487. const headerHeight = this.searchExpanded ? 360 : 186;
  488. this.tableHeight = windowHeight - headerHeight - 105;
  489. });
  490. },
  491. // 切换查询条件展开/收起
  492. toggleSearchExpand() {
  493. this.searchExpanded = !this.searchExpanded;
  494. this.calculateTableHeight();
  495. },
  496. // 查询数据
  497. getData() {
  498. this.searchLoading = true;
  499. this.dataListLoading = true;
  500. const params = {
  501. ...this.searchData,
  502. username: this.$store.state.user.name,
  503. page: this.pageIndex,
  504. limit: this.pageSize
  505. };
  506. listMaterialOnMachineRecord(params).then(({ data }) => {
  507. if (data && data.code === 0) {
  508. this.dataList = data.page.list || [];
  509. this.totalCount = data.page.totalCount || 0;
  510. } else {
  511. this.dataList = [];
  512. this.totalCount = 0;
  513. this.$message.error(data.msg || '查询失败');
  514. }
  515. }).catch(error => {
  516. this.dataList = [];
  517. this.totalCount = 0;
  518. this.$message.error('查询失败: ' + (error.message || '未知错误'));
  519. }).finally(() => {
  520. this.searchLoading = false;
  521. this.dataListLoading = false;
  522. });
  523. },
  524. // 重置查询条件
  525. resetSearch() {
  526. this.searchData = {
  527. site: this.siteList.length > 0 ? (this.$store.state.user.site || this.siteList[0]) : '',
  528. orderNo: '',
  529. seqNo: '',
  530. partNo: '',
  531. partDesc: '',
  532. rmRollNo: '',
  533. histType: '',
  534. finishedFlag: '',
  535. unissueFlag: '',
  536. keyRMFlag: '',
  537. productPartNo: '',
  538. workCenterNo: '',
  539. resourceId: '',
  540. startDate1: '',
  541. startDate2: ''
  542. };
  543. this.setDefaultDates();
  544. this.pageIndex = 1;
  545. },
  546. // 每页数变化
  547. sizeChangeHandle(val) {
  548. this.pageSize = val;
  549. this.pageIndex = 1;
  550. this.getData();
  551. },
  552. // 当前页变化
  553. currentChangeHandle(val) {
  554. this.pageIndex = val;
  555. this.getData();
  556. },
  557. // 显示异常退料对话框
  558. showReturnMaterialDialog(row) {
  559. this.returnData = {
  560. site: row.site,
  561. orderNo: row.orderNo,
  562. itemNo: row.itemNo,
  563. seqNo: row.seqNo,
  564. rollNo: row.rmRollNo,
  565. rmRollNo: row.rmRollNo,
  566. partNo: row.partNo,
  567. partDesc: row.partDesc,
  568. spec: row.spec,
  569. histSeqNo: row.histSeqNo,
  570. operatorId: this.$store.state.user.name,
  571. onMachineQty: parseFloat(row.transQty) || 0,
  572. returnQty: 0,
  573. remainQty: parseFloat(row.transQty) || 0,
  574. remark: ''
  575. };
  576. this.returnMaterialVisible = true;
  577. },
  578. // 计算剩余数量
  579. calculateRemainQty() {
  580. const onMachineQty = parseFloat(this.returnData.onMachineQty) || 0;
  581. const returnQty = parseFloat(this.returnData.returnQty) || 0;
  582. this.returnData.remainQty = onMachineQty - returnQty;
  583. },
  584. // 提交异常退料
  585. submitReturnMaterial() {
  586. if (!this.returnData.returnQty || this.returnData.returnQty === '' || this.returnData.returnQty < 0) {
  587. this.returnData.returnQty = 0;
  588. }
  589. this.calculateRemainQty();
  590. if (this.returnData.remainQty < 0) {
  591. this.$message.warning('退料数量不能大于上机数量!');
  592. return;
  593. }
  594. this.returnLoading = true;
  595. const submitData = {
  596. site: this.returnData.site,
  597. orderNo: this.returnData.orderNo,
  598. itemNo: this.returnData.itemNo,
  599. seqNo: this.returnData.seqNo,
  600. rollNo: this.returnData.rmRollNo,
  601. returnQty: this.returnData.returnQty,
  602. histSeqNo: this.returnData.histSeqNo,
  603. operatorId: this.returnData.operatorId,
  604. remark: this.returnData.remark || ''
  605. };
  606. materialReturnDuringProduction(submitData).then(({ data }) => {
  607. if (data.code == 500 || data.code == 400) {
  608. this.$message.error(data.msg || data.message);
  609. } else if (data.code == 201) {
  610. this.$message.success(data.msg || '操作成功');
  611. // 处理打印
  612. if (data.printData) {
  613. this.executePrint([data.printData]);
  614. }
  615. this.returnMaterialVisible = false;
  616. this.getData();
  617. } else {
  618. this.$message.success(data.msg || data.message || '操作成功');
  619. this.returnMaterialVisible = false;
  620. this.getData();
  621. }
  622. }).catch(error => {
  623. this.$message.error('操作失败:' + (error.message || '未知错误'));
  624. }).finally(() => {
  625. this.returnLoading = false;
  626. });
  627. },
  628. // 打印材料清单中的卷标签
  629. async printMaterialLabel(row) {
  630. try {
  631. // 1. 获取 LODOP 打印控件
  632. const LODOP = getLodop();
  633. if (!LODOP) {
  634. this.$message.error('无法连接到打印控件,请确保已安装并启动 CLodop!');
  635. return;
  636. }
  637. // 2. 获取默认打印机
  638. const printerCount = LODOP.GET_PRINTER_COUNT();
  639. if (printerCount <= 0) {
  640. this.$message.error('未检测到打印机,请确保已安装并连接打印机!');
  641. return;
  642. }
  643. // 3. 调用存储过程获取打印参数
  644. const params = {
  645. site: row.site,
  646. buNo: '',
  647. menuID: '104003006',
  648. relatedOrderNo: row.orderNo,
  649. relatedOrderLineNo: row.seqNo,
  650. documentNo: '',
  651. partNo: row.partNo,
  652. labelNo: '',
  653. rollNo: row.rmRollNo
  654. };
  655. const {data: printData} = await callUspPartLabelTemplate(params);
  656. if (printData && printData.code === 0 && printData.row) {
  657. const labelData = printData.row;
  658. // 初始化打印任务
  659. LODOP.PRINT_INIT('材料卷标签打印_' + row.rmRollNo);
  660. LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", true);
  661. // 根据 labelNo 调用不同的打印方法
  662. if (labelData.labelNo === 'A001') {
  663. await this.printLabelA001(LODOP, labelData, false);
  664. } else if (labelData.labelNo === 'A002') {
  665. this.printLabelA002(LODOP, labelData, false);
  666. } else if (labelData.labelNo === 'A003') {
  667. this.printLabelA003(LODOP, labelData, false);
  668. } else if (labelData.labelNo === 'A004') {
  669. this.printLabelA004(LODOP, labelData, false);
  670. } else {
  671. this.$message.warning(`未知的标签模板:${labelData.labelNo}`);
  672. return;
  673. }
  674. // 执行打印
  675. LODOP.PRINT();
  676. this.$message.success('打印任务已发送!');
  677. } else {
  678. this.$message.error(printData.msg || '获取打印参数失败');
  679. }
  680. } catch (error) {
  681. console.error('打印材料标签失败:', error);
  682. this.$message.error('打印失败: ' + (error.message || '请重试'));
  683. }
  684. },
  685. // 执行打印
  686. executePrint(printDataList) {
  687. try {
  688. const LODOP = getLodop();
  689. if (!LODOP) {
  690. this.$message.warning('无法连接到打印控件,跳过打印');
  691. return;
  692. }
  693. const printerCount = LODOP.GET_PRINTER_COUNT();
  694. if (printerCount === 0) {
  695. this.$message.warning('未检测到打印机,跳过打印');
  696. return;
  697. }
  698. if (!printDataList || printDataList.length === 0) {
  699. return;
  700. }
  701. const labelNo = printDataList[0].labelNo;
  702. if (!labelNo) {
  703. return;
  704. }
  705. for (let i = 0; i < printDataList.length; i++) {
  706. const printData = printDataList[i];
  707. LODOP.PRINT_INIT('异常退料标签打印_' + (i + 1));
  708. LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", true);
  709. if (labelNo === 'A001') {
  710. this.printLabelA001(LODOP, printData, false);
  711. } else if (labelNo === 'A002') {
  712. this.printLabelA002(LODOP, printData, false);
  713. } else if (labelNo === 'A003') {
  714. this.printLabelA003(LODOP, printData, false);
  715. } else if (labelNo === 'A004') {
  716. this.printLabelA004(LODOP, printData, false);
  717. }
  718. LODOP.PRINT();
  719. }
  720. this.$message.success('标签打印任务已发送!');
  721. } catch (error) {
  722. console.error('打印失败:', error);
  723. }
  724. }
  725. }
  726. }
  727. </script>
  728. <style scoped>
  729. /* 搜索卡片样式 */
  730. .search-card {
  731. margin-bottom: 16px;
  732. border-radius: 8px;
  733. overflow: hidden;
  734. transition: all 0.3s ease;
  735. }
  736. .search-card:hover {
  737. box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  738. }
  739. .search-card /deep/ .el-card__header {
  740. padding: 5px 20px;
  741. background: linear-gradient(135deg, #9ac3d0 20%, #b6c7dd 80%);
  742. border-bottom: none;
  743. }
  744. .search-header {
  745. display: flex;
  746. justify-content: space-between;
  747. align-items: center;
  748. }
  749. .header-left {
  750. display: flex;
  751. align-items: center;
  752. color: #fff;
  753. }
  754. .header-left i {
  755. font-size: 16px;
  756. margin-right: 8px;
  757. }
  758. .header-title {
  759. font-size: 14px;
  760. font-weight: 600;
  761. letter-spacing: 0.5px;
  762. }
  763. .header-right {
  764. color: #fff;
  765. }
  766. .collapse-btn {
  767. color: #fff;
  768. font-weight: 500;
  769. transition: all 0.3s ease;
  770. }
  771. .collapse-btn:hover {
  772. color: #f0f0f0;
  773. transform: translateY(-1px);
  774. }
  775. .collapse-btn i {
  776. transition: transform 0.3s ease;
  777. }
  778. /* 搜索表单样式 */
  779. .search-form {
  780. padding: 6px 0;
  781. min-height: 0;
  782. }
  783. /* 卡片主体样式 */
  784. .search-card /deep/ .el-card__body {
  785. padding: 10px;
  786. transition: all 0.3s ease;
  787. }
  788. /* 收起时的样式 */
  789. .search-card.collapsed /deep/ .el-card__body {
  790. padding: 10px 20px;
  791. }
  792. .search-form /deep/ .el-form-item {
  793. margin-bottom: 12px;
  794. }
  795. .search-form /deep/ .el-form-item__label {
  796. font-weight: 500;
  797. color: #606266;
  798. padding-bottom: 4px;
  799. }
  800. .search-form /deep/ .el-input__inner,
  801. .search-form /deep/ .el-textarea__inner {
  802. border-radius: 6px;
  803. border: 1px solid #DCDFE6;
  804. transition: all 0.3s ease;
  805. }
  806. .search-form /deep/ .el-input__inner:focus,
  807. .search-form /deep/ .el-textarea__inner:focus {
  808. border-color: #9ac3d0;
  809. box-shadow: 0 0 0 2px rgba(154, 195, 208, 0.1);
  810. }
  811. .search-form /deep/ .el-select {
  812. width: 100%;
  813. }
  814. /* 操作按钮区域 */
  815. .search-actions {
  816. display: flex;
  817. justify-content: space-between;
  818. align-items: center;
  819. padding: 8px 0 2px 0;
  820. }
  821. /* 展开时显示上边框 */
  822. .search-card:not(.collapsed) .search-actions {
  823. border-top: 1px solid #f0f0f0;
  824. margin-top: 6px;
  825. }
  826. /* 收起时不显示上边框和上边距 */
  827. .search-card.collapsed .search-actions {
  828. border-top: none;
  829. margin-top: 0;
  830. padding-top: 0;
  831. }
  832. .action-left {
  833. display: flex;
  834. gap: 8px;
  835. align-items: center;
  836. }
  837. .search-actions .el-button {
  838. border-radius: 4px;
  839. padding: 5px 10px;
  840. font-size: 12px;
  841. font-weight: 500;
  842. transition: all 0.3s ease;
  843. }
  844. .search-actions .el-button:hover {
  845. transform: translateY(-2px);
  846. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  847. }
  848. .search-actions .el-button--primary {
  849. background: #60aeff;
  850. border-color: #60aeff;
  851. }
  852. .search-actions .el-button--primary:hover {
  853. background: #7dbdff;
  854. border-color: #7dbdff;
  855. }
  856. /* 区域标题栏样式 */
  857. .section-title-bar {
  858. display: flex;
  859. align-items: center;
  860. padding: 8px 12px;
  861. background: linear-gradient(135deg, #f5f7fa 0%, #e4e7eb 100%);
  862. border-radius: 4px;
  863. margin-bottom: 8px;
  864. font-size: 14px;
  865. font-weight: 600;
  866. color: #303133;
  867. }
  868. .section-title-bar i {
  869. font-size: 16px;
  870. margin-right: 8px;
  871. color: #409eff;
  872. }
  873. .section-title-bar .total-count {
  874. margin-left: 10px;
  875. font-size: 12px;
  876. font-weight: normal;
  877. color: #909399;
  878. }
  879. /* 状态样式 */
  880. .status-yes {
  881. color: #67C23A;
  882. font-weight: 600;
  883. }
  884. .status-no {
  885. color: #F56C6C;
  886. font-weight: 600;
  887. }
  888. /* 表格样式 */
  889. /deep/ .el-table th {
  890. background-color: #f5f7fa;
  891. color: #303133;
  892. font-weight: 600;
  893. }
  894. /deep/ .el-table tr:hover > td {
  895. background-color: #f5f7fa !important;
  896. }
  897. /* 异常退料对话框样式 */
  898. .material-dialog /deep/ .el-dialog {
  899. border-radius: 8px;
  900. overflow: hidden;
  901. }
  902. .material-dialog /deep/ .el-dialog__header {
  903. background: linear-gradient(135deg, #9ac3d0 20%, #b6c7dd 80%);
  904. padding: 15px 20px;
  905. }
  906. .material-dialog /deep/ .el-dialog__title {
  907. color: #fff;
  908. font-size: 16px;
  909. font-weight: 600;
  910. }
  911. .material-dialog /deep/ .el-dialog__headerbtn .el-dialog__close {
  912. color: #fff;
  913. font-size: 18px;
  914. }
  915. .material-dialog /deep/ .el-dialog__headerbtn .el-dialog__close:hover {
  916. color: #f0f0f0;
  917. }
  918. .material-dialog /deep/ .el-dialog__body {
  919. padding: 20px;
  920. background-color: #f8f9fa;
  921. }
  922. .material-dialog /deep/ .el-dialog__footer {
  923. padding: 12px 20px;
  924. background-color: #fff;
  925. border-top: 1px solid #e9ecef;
  926. }
  927. .material-info-card {
  928. background: linear-gradient(135deg, rgba(154, 195, 208, 0.15) 0%, rgba(182, 199, 221, 0.15) 100%);
  929. border-radius: 8px;
  930. padding: 16px;
  931. margin-bottom: 20px;
  932. border: 1px solid #e3e8f0;
  933. box-shadow: 0 2px 8px rgba(154, 195, 208, 0.08);
  934. }
  935. .material-info-card .info-header {
  936. display: flex;
  937. align-items: center;
  938. margin-bottom: 12px;
  939. padding-bottom: 10px;
  940. border-bottom: 1px solid #dee2e6;
  941. }
  942. .material-info-card .info-header i {
  943. font-size: 18px;
  944. color: #9ac3d0;
  945. margin-right: 8px;
  946. }
  947. .material-info-card .info-header span {
  948. font-size: 14px;
  949. font-weight: 600;
  950. color: #495057;
  951. }
  952. .material-info-card .info-content {
  953. background-color: rgba(255, 255, 255, 0.8);
  954. border-radius: 4px;
  955. padding: 12px;
  956. }
  957. .material-info-card .info-row {
  958. display: flex;
  959. align-items: center;
  960. padding: 4px 0;
  961. }
  962. .material-info-card .info-label {
  963. font-size: 13px;
  964. color: #6c757d;
  965. min-width: 90px;
  966. font-weight: 500;
  967. }
  968. .material-info-card .info-value {
  969. font-size: 13px;
  970. color: #212529;
  971. font-weight: 600;
  972. flex: 1;
  973. }
  974. .return-settings {
  975. background: #fff;
  976. border-radius: 8px;
  977. padding: 16px;
  978. border: 1px solid #e3e8f0;
  979. box-shadow: 0 2px 8px rgba(154, 195, 208, 0.05);
  980. }
  981. .form-item-enhanced {
  982. margin-bottom: 10px;
  983. }
  984. .form-item-enhanced /deep/ .el-form-item__label {
  985. color: #495057;
  986. font-weight: 500;
  987. font-size: 14px;
  988. margin-bottom: 8px;
  989. }
  990. .form-item-enhanced /deep/ .el-input .el-input__inner {
  991. border-radius: 6px;
  992. border: 1px solid #dee2e6;
  993. height: 42px;
  994. line-height: 42px;
  995. font-size: 15px;
  996. }
  997. .form-item-enhanced /deep/ .el-input .el-input__inner:focus {
  998. border-color: #9ac3d0;
  999. box-shadow: 0 0 0 3px rgba(154, 195, 208, 0.1);
  1000. }
  1001. .form-item-enhanced /deep/ .remain-negative .el-input__inner {
  1002. color: #f56c6c;
  1003. font-weight: 600;
  1004. border-color: #f56c6c;
  1005. background-color: #fef0f0;
  1006. }
  1007. .numInput /deep/ .el-input__inner {
  1008. text-align: right;
  1009. }
  1010. /deep/ .inlineNumber input::-webkit-outer-spin-button,
  1011. /deep/ .inlineNumber input::-webkit-inner-spin-button {
  1012. -webkit-appearance: none;
  1013. }
  1014. /deep/ .inlineNumber input[type="number"] {
  1015. -moz-appearance: textfield;
  1016. padding-right: 5px !important;
  1017. }
  1018. /* 响应式设计 */
  1019. @media (max-width: 1200px) {
  1020. .search-actions {
  1021. flex-direction: column;
  1022. gap: 10px;
  1023. }
  1024. .action-left {
  1025. width: 100%;
  1026. justify-content: center;
  1027. }
  1028. }
  1029. </style>