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.

429 lines
13 KiB

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