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.

445 lines
14 KiB

1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
1 month ago
1 month ago
​
1 month ago
​
​
​
​
​
​
​
1 month ago
​
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
1 month ago
​
​
​
1 month ago
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month 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>空托盘组盘</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. ref="palletInput"
  26. />
  27. </div>
  28. <!-- 托盘信息显示(扫描托盘后显示)- rqrq -->
  29. <div v-if="palletScanned" class="pallet-info-section">
  30. <!-- 托盘类型选择 - rqrq -->
  31. <div class="input-group">
  32. <label class="input-label">托盘类型</label>
  33. <el-select
  34. v-model="currentPalletType"
  35. placeholder="请选择托盘类型"
  36. style="width: 100%;"
  37. :disabled="palletTypeChangeLoading"
  38. @change="handlePalletTypeChange"
  39. >
  40. <el-option
  41. v-for="type in palletTypeOptions"
  42. :key="type.palletType"
  43. :label="`${type.palletType} - ${type.typeDesc}`"
  44. :value="type.palletType"
  45. />
  46. </el-select>
  47. </div>
  48. <div class="input-group">
  49. <label class="input-label">空托数量</label>
  50. <el-select v-model="count" disabled>
  51. <el-option value=1 label=1></el-option>
  52. <el-option value=2 label=2></el-option>
  53. <el-option value=3 label=3></el-option>
  54. <el-option value=4 label=4></el-option>
  55. <el-option value=5 label=5></el-option>
  56. <el-option value=6 label=6></el-option>
  57. </el-select>
  58. </div>
  59. <!-- 当前站点信息 - rqrq -->
  60. <div class="info-row">
  61. <label class="info-label">当前站点ID:</label>
  62. <span class="info-value">{{ palletInfo.currentStationId || '-' }}</span>
  63. </div>
  64. <div class="info-row">
  65. <label class="info-label">当前站点编码:</label>
  66. <span class="info-value">{{ palletInfo.currentStationCode || '-' }}</span>
  67. </div>
  68. <!-- 操作按钮 - rqrq -->
  69. <div class="button-row" style="display: flex; gap: 8px; margin-top: 16px;">
  70. <button
  71. class="action-btn primary"
  72. @click="handleNotifyInbound"
  73. :disabled="notifyLoading || palletTypeChangeLoading || !currentPalletType"
  74. style="flex: 1;">
  75. {{ notifyLoading ? '处理中...' : '通知入库' }}
  76. </button>
  77. <button
  78. class="action-btn primary"
  79. @click="handleInboundAndTransport"
  80. :disabled="transportLoading || palletTypeChangeLoading || !currentPalletType"
  81. style="flex: 1;">
  82. {{ transportLoading ? '处理中...' : '入库并运输' }}
  83. </button>
  84. </div>
  85. </div>
  86. </div>
  87. </div>
  88. </div>
  89. </div>
  90. </template>
  91. <script>
  92. import {
  93. checkEmptyPallet,
  94. getPalletTypes,
  95. updatePalletTypeAndAutoSort,
  96. notifyEmptyPalletInbound
  97. } from '../../../api/haianAutoWarehouse/emptyPalletAssembly'
  98. export default {
  99. data() {
  100. return {
  101. // 海安PDA前端site唯一来源为store用户对象,兼容旧缓存兜底 - rqrq
  102. site: (this.$store && this.$store.state && this.$store.state.user && this.$store.state.user.site) || localStorage.getItem('site'),
  103. // 托盘信息 - rqrq
  104. palletCode: '',
  105. palletScanned: false,
  106. palletInfo: {
  107. currentStationId: '',
  108. currentStationCode: '',
  109. palletType: '',
  110. area: ''
  111. },
  112. // 托盘类型 - rqrq
  113. currentPalletType: '',
  114. palletTypeOptions: [],
  115. count: 1,
  116. // 加载状态 - rqrq
  117. notifyLoading: false,
  118. transportLoading: false,
  119. palletTypeChangeLoading: false
  120. };
  121. },
  122. methods: {
  123. // 返回上一页并清空页面状态,避免keep-alive导致脏数据残留 - rqrq
  124. handleBack() {
  125. this.resetPage(false);
  126. this.$router.back();
  127. },
  128. // 回首页前清理状态,保证再次进入页面从干净态开始 - rqrq
  129. goHome() {
  130. this.resetPage(false);
  131. this.$router.push({ path: '/' });
  132. },
  133. // 扫描托盘 - rqrq
  134. handlePalletScan() {
  135. if (!this.palletCode.trim()) {
  136. this.$alert('请输入托盘编码', '提示', {
  137. confirmButtonText: '确定'
  138. });
  139. return;
  140. }
  141. checkEmptyPallet({
  142. site: this.site,
  143. palletId: this.palletCode
  144. }).then(({ data }) => {
  145. if (data.code === 0) {
  146. // 后端返回正确的6位栈板码,赋值给输入框 - rqrq
  147. this.palletCode = data.row.palletId;
  148. // 托盘信息 - rqrq
  149. this.palletInfo = data.row;
  150. this.currentPalletType = data.row.palletType || '';
  151. this.palletScanned = true;
  152. // 根据托盘的palletFamily加载托盘类型选项 - rqrq
  153. this.loadPalletTypes(data.row.palletFamily);
  154. } else {
  155. this.$alert(data.msg || '托盘验证失败', '错误', {
  156. confirmButtonText: '确定',
  157. callback: () => {
  158. this.palletCode = '';
  159. this.$nextTick(() => {
  160. if (this.$refs.palletInput) {
  161. this.$refs.palletInput.focus();
  162. }
  163. });
  164. }
  165. });
  166. }
  167. }).catch(error => {
  168. console.error('查询托盘失败:', error);
  169. this.$alert(error.message || '查询托盘失败', '错误', {
  170. confirmButtonText: '确定',
  171. callback: () => {
  172. this.palletCode = '';
  173. this.$nextTick(() => {
  174. if (this.$refs.palletInput) {
  175. this.$refs.palletInput.focus();
  176. }
  177. });
  178. }
  179. });
  180. });
  181. },
  182. // 加载托盘类型选项(根据palletFamily过滤)- rqrq
  183. loadPalletTypes(palletFamily) {
  184. getPalletTypes({
  185. site: this.site,
  186. palletFamily: palletFamily || ''
  187. }).then(({ data }) => {
  188. if (data.code === 0) {
  189. this.palletTypeOptions = data.rows || [];
  190. } else {
  191. this.palletTypeOptions = [];
  192. this.$alert('获取托盘类型失败', '错误', {
  193. confirmButtonText: '确定'
  194. });
  195. }
  196. }).catch(error => {
  197. console.error('获取托盘类型失败:', error);
  198. this.palletTypeOptions = [];
  199. });
  200. },
  201. // 托盘类型变更事件:按小类主数据重置自动分拣和强制整托后落库,禁止残留上一类型勾选 - rqrq
  202. handlePalletTypeChange() {
  203. if (this.palletTypeChangeLoading) {
  204. return;
  205. }
  206. const selectedType = this.palletTypeOptions.find((item) => item.palletType === this.currentPalletType);
  207. const wcsSoreType = selectedType && selectedType.wcsSoreType != null ? Number(selectedType.wcsSoreType) : 0;
  208. const forceFullPalletOut = wcsSoreType === 3
  209. || this.currentPalletType === 'A0103'
  210. || this.currentPalletType === 'A0206';
  211. let autoSort = selectedType && selectedType.wcsAutoSort === 'Y' ? 'Y' : 'N';
  212. if (forceFullPalletOut) {
  213. autoSort = 'N';
  214. }
  215. this.palletTypeChangeLoading = true;
  216. updatePalletTypeAndAutoSort({
  217. site: this.site,
  218. palletId: this.palletCode,
  219. palletType: this.currentPalletType,
  220. autoSort: autoSort,
  221. forceFullPalletOut: forceFullPalletOut
  222. }).then(({ data }) => {
  223. if (data && data.code === 0) {
  224. this.$message.success('更新成功');
  225. } else {
  226. this.$alert((data && data.msg) || '更新失败', '错误', {
  227. confirmButtonText: '确定'
  228. });
  229. }
  230. }).catch(error => {
  231. this.$alert(error.message || '更新失败', '错误', {
  232. confirmButtonText: '确定'
  233. });
  234. }).finally(() => {
  235. this.palletTypeChangeLoading = false;
  236. });
  237. },
  238. // 通知入库前置校验:仅允许“外部回库”空托盘(area和location_code都为空)继续操作 - rqrq
  239. validateNotifyInboundPalletStatus() {
  240. const areaCode = this.palletInfo && this.palletInfo.area ? String(this.palletInfo.area).trim() : ''
  241. const locationCode = this.palletInfo && this.palletInfo.locationCode
  242. ? String(this.palletInfo.locationCode).trim()
  243. : (this.palletInfo && this.palletInfo.currentStationCode ? String(this.palletInfo.currentStationCode).trim() : '')
  244. if (areaCode || locationCode) {
  245. this.$alert('通知入库仅允许未绑定站点的空托盘', '提示', {
  246. confirmButtonText: '确定'
  247. })
  248. return false
  249. }
  250. return true
  251. },
  252. // 通知入库 - rqrq
  253. handleNotifyInbound() {
  254. if (!this.currentPalletType) {
  255. this.$alert('请先选择托盘类型', '提示', {
  256. confirmButtonText: '确定'
  257. });
  258. return;
  259. }
  260. if (!this.validateNotifyInboundPalletStatus()) {
  261. return;
  262. }
  263. // 通知入库:海安只有一个入库口,后端固定下发,页面只做确认 - rqrq
  264. this.$confirm('确定要执行通知入库操作吗?目标点位固定为入库口。', '确认操作', {
  265. confirmButtonText: '确定',
  266. cancelButtonText: '取消',
  267. type: 'warning'
  268. }).then(() => {
  269. this.notifyLoading = true;
  270. notifyEmptyPalletInbound({
  271. site: this.site,
  272. palletId: this.palletCode,
  273. transportFlag: 'N',
  274. count: Number(this.count)
  275. }).then(({ data }) => {
  276. if (data && data.code === 0) {
  277. this.$message.success('通知入库成功');
  278. this.resetPage(true);
  279. } else {
  280. this.$alert(data.msg || '通知入库失败', '错误', {
  281. confirmButtonText: '确定'
  282. });
  283. }
  284. }).catch(error => {
  285. console.error('通知入库失败:', error);
  286. this.$alert(error.message || '通知入库失败', '错误', {
  287. confirmButtonText: '确定'
  288. });
  289. }).finally(() => {
  290. this.notifyLoading = false;
  291. });
  292. }).catch(() => {
  293. // 用户取消操作,不提交通知入库 - rqrq
  294. });
  295. },
  296. // 入库并运输 - rqrq
  297. handleInboundAndTransport() {
  298. if (!this.currentPalletType) {
  299. this.$alert('请先选择托盘类型', '提示', {
  300. confirmButtonText: '确定'
  301. });
  302. return;
  303. }
  304. // 右按钮“入库并运输”前置校验:栈板必须绑定area,否则当前位置禁止空托入库 - rqrq
  305. if (!this.palletInfo.area || !String(this.palletInfo.area).trim()) {
  306. this.$alert('当前位置不允许空托入库', '提示', {
  307. confirmButtonText: '确定'
  308. });
  309. return;
  310. }
  311. this.$confirm('确定要执行入库并运输操作吗?', '确认操作', {
  312. confirmButtonText: '确定',
  313. cancelButtonText: '取消',
  314. type: 'warning'
  315. }).then(() => {
  316. this.transportLoading = true;
  317. notifyEmptyPalletInbound({
  318. site: this.site,
  319. palletId: this.palletCode,
  320. transportFlag: 'Y',
  321. count: Number(this.count),
  322. }).then(({ data }) => {
  323. if (data && data.code === 0) {
  324. this.$message.success('入库并运输成功');
  325. // 清空页面重新扫描 - rqrq
  326. this.resetPage(true);
  327. } else {
  328. this.$alert(data.msg || '入库并运输失败', '错误', {
  329. confirmButtonText: '确定'
  330. });
  331. }
  332. }).catch(error => {
  333. console.error('入库并运输失败:', error);
  334. this.$alert(error.message || '入库并运输失败', '错误', {
  335. confirmButtonText: '确定'
  336. });
  337. }).finally(() => {
  338. this.transportLoading = false;
  339. });
  340. }).catch(() => {
  341. // 用户取消操作
  342. });
  343. },
  344. // 重置页面并按需恢复扫码焦点,统一海安PDA页面生命周期清理行为 - rqrq
  345. resetPage(needFocus) {
  346. this.palletCode = '';
  347. this.palletScanned = false;
  348. this.palletInfo = {
  349. currentStationId: '',
  350. currentStationCode: '',
  351. palletType: '',
  352. area: ''
  353. };
  354. this.currentPalletType = '';
  355. this.palletTypeOptions = [];
  356. this.count = 1;
  357. this.palletTypeChangeLoading = false;
  358. if (needFocus) {
  359. this.$nextTick(() => {
  360. if (this.$refs.palletInput) {
  361. this.$refs.palletInput.focus();
  362. }
  363. });
  364. }
  365. }
  366. },
  367. mounted() {
  368. this.$nextTick(() => {
  369. if (this.$refs.palletInput) {
  370. this.$refs.palletInput.focus();
  371. }
  372. });
  373. },
  374. activated() {
  375. this.resetPage(true);
  376. },
  377. beforeRouteLeave(to, from, next) {
  378. this.resetPage(false);
  379. next();
  380. }
  381. };
  382. </script>
  383. <style scoped>
  384. /* 托盘信息区域 - rqrq */
  385. .pallet-info-section {
  386. margin-top: 16px;
  387. padding: 12px;
  388. background: #f5f7fa;
  389. border-radius: 6px;
  390. }
  391. .info-row {
  392. display: flex;
  393. align-items: center;
  394. padding: 8px 0;
  395. border-bottom: 1px solid #e4e7ed;
  396. }
  397. .info-row:last-child {
  398. border-bottom: none;
  399. }
  400. .info-label {
  401. font-weight: bold;
  402. color: #606266;
  403. width: 120px;
  404. flex-shrink: 0;
  405. }
  406. .info-value {
  407. color: #303133;
  408. font-size: 14px;
  409. }
  410. .button-row {
  411. margin-top: 12px;
  412. }
  413. </style>