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.

516 lines
14 KiB

1 day ago
  1. <template>
  2. <div>
  3. <div class="pda-container">
  4. <!-- 头部栏 - rqrq -->
  5. <div class="header-bar">
  6. <div class="header-left" @click="handleBack">
  7. <i class="el-icon-arrow-left"></i>
  8. <span>取消WCS组盘任务</span>
  9. </div>
  10. <div class="header-right" @click="goHome">
  11. 首页
  12. </div>
  13. </div>
  14. <div class="table-body" style="max-height: 600px; overflow-y: auto;">
  15. <div class="main-content form-section">
  16. <!-- 栈板扫描 - rqrq -->
  17. <div class="input-group">
  18. <label class="input-label">栈板编码</label>
  19. <el-input
  20. v-model="palletCode"
  21. placeholder="请扫描栈板编码"
  22. class="form-input"
  23. clearable
  24. @keyup.enter.native="handlePalletScan"
  25. inputmode="none"
  26. autocomplete="off"
  27. autocorrect="off"
  28. spellcheck="false"
  29. ref="palletInput"
  30. />
  31. </div>
  32. <!-- 栈板信息显示扫描栈板后显示- rqrq -->
  33. <div v-if="palletScanned" class="pallet-info-section">
  34. <div class="info-row">
  35. <label class="info-label">是否被调用:</label>
  36. <span class="info-value" :style="{color: palletInfo.callingFlag === 'Y' ? '#F56C6C' : '#67C23A'}">
  37. {{ palletInfo.callingFlag === 'Y' ? '是' : '否' }}
  38. </span>
  39. </div>
  40. <!-- 是否发送组盘任务 - rqrq -->
  41. <div class="info-row">
  42. <label class="info-label">是否已组盘:</label>
  43. <span class="info-value" :style="{color: hasSentWcsTask ? '#F56C6C' : '#67C23A'}">
  44. {{ hasSentWcsTask ? '是' : '否' }}
  45. </span>
  46. </div>
  47. <!-- 浏览明细按钮 - rqrq -->
  48. <div class="button-row">
  49. <button class="action-btn primary" @click="showDetailModal" style="width: 100%;">
  50. 浏览明细 ({{ detailList.length }})
  51. </button>
  52. </div>
  53. <!-- 取消组盘按钮只有发送了组盘任务才显示- rqrq -->
  54. <div class="button-row">
  55. <button
  56. class="action-btn primary"
  57. @click="handleCancelWcsPallet"
  58. style="width: 100%;">
  59. {{ cancelLoading ? '取消中...' : '取消组盘' }}
  60. </button>
  61. </div>
  62. <!-- 移出全部物料按钮只有未发送组盘任务且未被调用且有明细才显示- rqrq -->
  63. <div v-if="showRemoveAllButton" class="button-row">
  64. <button
  65. class="action-btn warning"
  66. @click="handleRemoveAllMaterials"
  67. :disabled="removeAllLoading"
  68. style="width: 100%;">
  69. {{ removeAllLoading ? '移出中...' : '移出全部物料' }}
  70. </button>
  71. </div>
  72. </div>
  73. </div>
  74. </div>
  75. </div>
  76. <!-- 浏览明细弹窗 - rqrq -->
  77. <el-dialog
  78. :title="'栈板明细 (共'+detailList.length+'条)'"
  79. :visible.sync="detailModalVisible"
  80. width="90%"
  81. :close-on-click-modal="false"
  82. :show-close="false"
  83. :modal="true"
  84. :modal-append-to-body="true"
  85. :append-to-body="true"
  86. >
  87. <div class="table-body" style="max-height: 400px; overflow-y: auto;">
  88. <div class="detail-table">
  89. <div class="table-header">
  90. <div class="col-position">位置</div>
  91. <div class="col-layer">层数</div>
  92. <div class="col-serial">标签号</div>
  93. </div>
  94. <div
  95. v-for="(detail, index) in detailList"
  96. :key="index"
  97. class="table-row"
  98. >
  99. <div class="col-position">{{ detail.position }}</div>
  100. <div class="col-layer">{{ detail.layer }}</div>
  101. <div class="col-serial">{{ detail.serialNo }}</div>
  102. </div>
  103. <!-- 暂无数据提示 -->
  104. <div v-if="detailList.length === 0" class="table-row empty-row">
  105. <div class="empty-hint">暂无栈板明细数据</div>
  106. </div>
  107. </div>
  108. </div>
  109. <div slot="footer" class="dialog-footer">
  110. <button class="action-btn secondary" @click="detailModalVisible=false">关闭</button>
  111. </div>
  112. </el-dialog>
  113. </div>
  114. </template>
  115. <script>
  116. import {
  117. getPalletDetails
  118. } from '../../../api/haianAutoWarehouse/palletPacking'
  119. import {
  120. checkPalletWcsStatus,
  121. cancelWcsPallet,
  122. removeAllPalletDetails
  123. } from '../../../api/haianAutoWarehouse/cancelWcsPallet'
  124. export default {
  125. data() {
  126. return {
  127. // 海安PDA前端site唯一来源为store用户对象,兼容旧缓存兜底 - rqrq
  128. site: (this.$store && this.$store.state && this.$store.state.user && this.$store.state.user.site) || localStorage.getItem('site'),
  129. // 栈板信息 - rqrq
  130. palletCode: '',
  131. palletScanned: false,
  132. palletInfo: {
  133. callingFlag: '',
  134. canOperate: '',
  135. isEmpty: ''
  136. },
  137. // 按钮显示控制 - rqrq
  138. hasSentWcsTask: false,
  139. showCancelButton: false,
  140. showRemoveAllButton: false,
  141. // 栈板明细 - rqrq
  142. detailList: [],
  143. detailModalVisible: false,
  144. // 加载状态 - rqrq
  145. cancelLoading: false,
  146. removeAllLoading: false
  147. };
  148. },
  149. methods: {
  150. // 返回上一页并清空页面状态,避免keep-alive导致脏数据残留 - rqrq
  151. handleBack() {
  152. this.resetPage(false);
  153. this.$router.back();
  154. },
  155. // 回首页前清理状态,保证再次进入页面从干净态开始 - rqrq
  156. goHome() {
  157. this.resetPage(false);
  158. this.$router.push({ path: '/' });
  159. },
  160. // 扫描栈板 - rqrq
  161. handlePalletScan() {
  162. if (!this.palletCode.trim()) {
  163. this.$alert('请输入栈板编码', '提示', {
  164. confirmButtonText: '确定'
  165. });
  166. return;
  167. }
  168. checkPalletWcsStatus({
  169. site: this.site,
  170. palletId: this.palletCode
  171. }).then(({ data }) => {
  172. if (data.code === 0) {
  173. // 后端返回正确的6位栈板码,赋值给输入框 - rqrq
  174. this.palletCode = data.row.palletId;
  175. // 保存栈板信息 - rqrq
  176. this.palletInfo = data.row;
  177. this.palletScanned = true;
  178. // 解析按钮显示逻辑 - rqrq
  179. // canOperate字段存储showCancelButton(是否显示取消组盘按钮)- rqrq
  180. this.showCancelButton = data.row.canOperate === 'Y';
  181. // isEmpty字段存储showRemoveAllButton(是否显示移出全部物料按钮)- rqrq
  182. this.showRemoveAllButton = data.row.isEmpty === 'Y';
  183. // 计算hasSentWcsTask(是否发送组盘任务)用于显示 - rqrq
  184. this.hasSentWcsTask = this.showCancelButton;
  185. // 加载栈板明细 - rqrq
  186. this.loadPalletDetails();
  187. } else {
  188. this.$alert(data.msg || '栈板不存在', '错误', {
  189. confirmButtonText: '确定',
  190. callback: () => {
  191. this.palletCode = '';
  192. this.$nextTick(() => {
  193. if (this.$refs.palletInput) {
  194. this.$refs.palletInput.focus();
  195. }
  196. });
  197. }
  198. });
  199. }
  200. }).catch(error => {
  201. console.error('查询栈板失败:', error);
  202. this.$alert(error.message || '查询栈板失败', '错误', {
  203. confirmButtonText: '确定',
  204. callback: () => {
  205. this.palletCode = '';
  206. this.$nextTick(() => {
  207. if (this.$refs.palletInput) {
  208. this.$refs.palletInput.focus();
  209. }
  210. });
  211. }
  212. });
  213. });
  214. },
  215. // 加载栈板明细 - rqrq
  216. loadPalletDetails() {
  217. getPalletDetails({
  218. site: this.site,
  219. palletId: this.palletCode,
  220. position: '',
  221. layer: ''
  222. }).then(({ data }) => {
  223. if (data.code === 0) {
  224. this.detailList = data.details || [];
  225. } else {
  226. this.detailList = [];
  227. }
  228. }).catch(error => {
  229. console.error('获取栈板明细失败:', error);
  230. this.detailList = [];
  231. });
  232. },
  233. // 显示明细弹窗 - rqrq
  234. showDetailModal() {
  235. this.detailModalVisible = true;
  236. },
  237. // 取消组盘 - rqrq
  238. handleCancelWcsPallet() {
  239. this.$confirm('确定要取消组盘吗?取消后需要重新组盘才能推送到WCS。', '确认操作', {
  240. confirmButtonText: '确定',
  241. cancelButtonText: '取消',
  242. type: 'warning'
  243. }).then(() => {
  244. this.cancelLoading = true;
  245. cancelWcsPallet({
  246. site: this.site,
  247. palletId: this.palletCode
  248. }).then(({ data }) => {
  249. if (data && data.code === 0) {
  250. this.$message.success('取消组盘成功');
  251. // 重新扫描刷新信息 - rqrq
  252. this.handlePalletScan();
  253. } else {
  254. this.$alert(data.msg || '取消组盘失败', '错误', {
  255. confirmButtonText: '确定'
  256. });
  257. }
  258. }).catch(error => {
  259. console.error('取消组盘失败:', error);
  260. // 网络错误也弹出提示框 - rqrq
  261. this.$alert(error.message || '取消组盘失败', '错误', {
  262. confirmButtonText: '确定'
  263. });
  264. }).finally(() => {
  265. this.cancelLoading = false;
  266. });
  267. }).catch(() => {
  268. // 用户取消操作
  269. });
  270. },
  271. // 移出全部物料 - rqrq
  272. handleRemoveAllMaterials() {
  273. this.$confirm('确定要移出栈板上的全部物料吗?此操作不可恢复!', '确认操作', {
  274. confirmButtonText: '确定',
  275. cancelButtonText: '取消',
  276. type: 'warning'
  277. }).then(() => {
  278. this.removeAllLoading = true;
  279. removeAllPalletDetails({
  280. site: this.site,
  281. palletId: this.palletCode
  282. }).then(({ data }) => {
  283. if (data && data.code === 0) {
  284. this.$message.success('移出全部物料成功');
  285. // 重新扫描刷新信息 - rqrq
  286. this.handlePalletScan();
  287. } else {
  288. this.$alert(data.msg || '移出全部物料失败', '错误', {
  289. confirmButtonText: '确定'
  290. });
  291. }
  292. }).catch(error => {
  293. console.error('移出全部物料失败:', error);
  294. // 网络错误也弹出提示框 - rqrq
  295. this.$alert(error.message || '移出全部物料失败', '错误', {
  296. confirmButtonText: '确定'
  297. });
  298. }).finally(() => {
  299. this.removeAllLoading = false;
  300. });
  301. }).catch(() => {
  302. // 用户取消操作
  303. });
  304. },
  305. // 重置页面并按需恢复扫码焦点,统一海安PDA页面生命周期清理行为 - rqrq
  306. resetPage(needFocus) {
  307. this.palletCode = '';
  308. this.palletScanned = false;
  309. this.palletInfo = {
  310. callingFlag: '',
  311. canOperate: '',
  312. isEmpty: ''
  313. };
  314. this.hasSentWcsTask = false;
  315. this.showCancelButton = false;
  316. this.showRemoveAllButton = false;
  317. this.detailList = [];
  318. this.detailModalVisible = false;
  319. if (needFocus) {
  320. this.$nextTick(() => {
  321. if (this.$refs.palletInput) {
  322. this.$refs.palletInput.focus();
  323. }
  324. });
  325. }
  326. }
  327. },
  328. mounted() {
  329. this.$nextTick(() => {
  330. if (this.$refs.palletInput) {
  331. this.$refs.palletInput.focus();
  332. }
  333. });
  334. },
  335. activated() {
  336. this.resetPage(true);
  337. },
  338. beforeRouteLeave(to, from, next) {
  339. this.resetPage(false);
  340. next();
  341. }
  342. };
  343. </script>
  344. <style scoped>
  345. /* 栈板信息区域 - rqrq */
  346. .pallet-info-section {
  347. margin-top: 16px;
  348. padding: 12px;
  349. background: #f5f7fa;
  350. border-radius: 6px;
  351. }
  352. .info-row {
  353. display: flex;
  354. align-items: center;
  355. padding: 8px 0;
  356. border-bottom: 1px solid #e4e7ed;
  357. }
  358. .info-row:last-child {
  359. border-bottom: none;
  360. }
  361. .info-label {
  362. font-weight: bold;
  363. color: #606266;
  364. width: 140px;
  365. flex-shrink: 0;
  366. }
  367. .info-value {
  368. color: #303133;
  369. font-size: 14px;
  370. font-weight: bold;
  371. }
  372. .button-row {
  373. margin-top: 12px;
  374. }
  375. /* 警告按钮 - rqrq */
  376. .action-btn.warning {
  377. background-color: #E6A23C;
  378. color: white;
  379. border: none;
  380. padding: 10px 20px;
  381. border-radius: 4px;
  382. cursor: pointer;
  383. font-size: 14px;
  384. }
  385. .action-btn.warning:hover {
  386. background-color: #d99525;
  387. }
  388. .action-btn.warning:disabled {
  389. background-color: #f5dab1;
  390. cursor: not-allowed;
  391. }
  392. /* 表格样式 - rqrq */
  393. .detail-table {
  394. background: white;
  395. border-radius: 6px;
  396. overflow: hidden;
  397. border: 1px solid #e0e0e0;
  398. }
  399. .table-header,
  400. .table-row {
  401. display: flex;
  402. align-items: center;
  403. padding: 8px;
  404. border-bottom: 1px solid #e0e0e0;
  405. }
  406. .table-header {
  407. background: #f5f5f5;
  408. font-weight: bold;
  409. font-size: 14px;
  410. }
  411. .table-row {
  412. font-size: 13px;
  413. }
  414. .table-row:last-child {
  415. border-bottom: none;
  416. }
  417. .col-position {
  418. flex: 1;
  419. text-align: center;
  420. }
  421. .col-layer {
  422. flex: 1;
  423. text-align: center;
  424. }
  425. .col-serial {
  426. flex: 4;
  427. text-align: center;
  428. word-break: break-all;
  429. }
  430. /* 空数据提示 - rqrq */
  431. .empty-hint {
  432. text-align: center;
  433. color: #999;
  434. padding: 20px;
  435. background: white;
  436. border-radius: 6px;
  437. }
  438. /* 空数据行样式 - rqrq */
  439. .empty-row {
  440. justify-content: center;
  441. align-items: center;
  442. padding: 20px;
  443. border-bottom: none;
  444. }
  445. .empty-row .empty-hint {
  446. text-align: center;
  447. color: #999;
  448. width: 100%;
  449. }
  450. .dialog-footer {
  451. display: flex;
  452. gap: 8px;
  453. text-align: center;
  454. }
  455. /* 修复模态框层级问题 - rqrq */
  456. ::v-deep .el-dialog__wrapper {
  457. z-index: 2000 !important;
  458. }
  459. ::v-deep .el-overlay {
  460. z-index: 2000 !important;
  461. }
  462. </style>