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.

657 lines
14 KiB

3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 weeks ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
3 months ago
  1. <template>
  2. <div class="pda-container">
  3. <!-- 头部栏 -->
  4. <div class="header-bar">
  5. <div class="header-left" @click="goBack">
  6. <i class="el-icon-arrow-left"></i>
  7. <span>{{ functionTitle }}</span>
  8. </div>
  9. <div class="header-right" @click="$router.push({ path: '/' })">首页</div>
  10. </div>
  11. <!-- 申请单输入 -->
  12. <div class="search-container">
  13. <el-input clearable v-model="requestIssueForm.requestNo" placeholder="请输入SHIPMENTID" prefix-icon="el-icon-search"
  14. @keyup.enter.native="loadIssueRequestMaterials" ref="requestNoInput" />
  15. </div>
  16. <!-- 申请单物料列表 -->
  17. <div class="work-order-list" v-if="issueRequestMaterials.length > 0 ">
  18. <div v-for="material in displayIssueRequestMaterials" :key="`${material.partNo}-${material.itemNo}`"
  19. class="work-order-card" @click="openIssueDetail(material)">
  20. <div class="card-title">
  21. <span class="title-label">shipmentId{{ material.SHIPMENT_ID }} </span>
  22. </div>
  23. <!-- 工单号单独一行 -->
  24. <div class="part-desc-row">
  25. <span class="desc-text">客户名称{{ material.RECEIVER_ADDRESS_NAME }}</span>
  26. </div>
  27. <div class="card-details">
  28. <div class="detail-item">
  29. <div class="detail-label">发料类型</div>
  30. <div class="detail-value">{{ material.SHIPMENT_TYPE }}</div>
  31. </div>
  32. <div class="detail-item">
  33. <div class="detail-label">状态</div>
  34. <div class="detail-value">{{material.STATE}}</div>
  35. </div>
  36. <div class="detail-item">
  37. <div class="detail-label">计划发料日期</div>
  38. <div class="detail-value">{{ material.PLANNED_SHIP_DATE }}</div>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. <!-- 材料列表新增仿 directIssue.vue -->
  44. <div
  45. class="content-area"
  46. v-if="selectedWorkOrder && materialList.length > 0"
  47. >
  48. <div
  49. v-for="(material, index) in materialList"
  50. :key="index"
  51. class="material-card"
  52. @click="openIssueDetail(material)"
  53. >
  54. <div class="card-title">
  55. <span class="title-label"
  56. >物料编码{{ material.INVENTORY_PART_NO }} &nbsp;&nbsp; 行号{{
  57. material.SOURCE_REF2
  58. }}</span
  59. >
  60. </div>
  61. <!-- 物料描述单独一行 -->
  62. <div class="part-desc-row">
  63. <span class="desc-text">客户单号{{ material.SOURCE_REF1 }}</span>
  64. </div>
  65. <div class="card-details">
  66. <div class="detail-item">
  67. <div class="detail-label">销售行号</div>
  68. <div class="detail-value">{{ material.SHIPMENT_LINE_NO }}</div>
  69. </div>
  70. <div class="detail-item">
  71. <div class="detail-label">需求数量</div>
  72. <div class="detail-value">{{ material.INVENTORY_QTY }}</div>
  73. </div>
  74. <div class="detail-item">
  75. <div class="detail-label">单位</div>
  76. <div class="detail-value">{{ material.INVENTORY_UOM }}</div>
  77. </div>
  78. </div>
  79. </div>
  80. </div>
  81. <!-- 空状态 -->
  82. <div
  83. v-if="selectedWorkOrder && materialList.length === 0"
  84. class="empty-state"
  85. >
  86. <i class="el-icon-box"></i>
  87. <p>该申请单暂无材料清单</p>
  88. </div>
  89. <!-- 加载状态 -->
  90. <div v-if="loading" class="loading-state">
  91. <i class="el-icon-loading"></i>
  92. <p>加载中...</p>
  93. </div>
  94. </div>
  95. </template>
  96. <script>
  97. import {
  98. getCustomerIssueNotifyHeaderInfo,
  99. getCustomerIssueNotifyHeaderOrderMaterialList,
  100. } from '@/api/customerIssue/customer-issue'
  101. import { getWorkOrderMaterials } from '@/api/production/production-issue'
  102. export default {
  103. name: 'customerIssuePDA',
  104. data() {
  105. return {
  106. loading: false,
  107. loadingText: '',
  108. message: '',
  109. messageType: 'info',
  110. // 基于申请单发料
  111. requestIssueForm: {
  112. site: localStorage.getItem('site'),
  113. requestNo: '',
  114. operatorName: 'PDA_USER',
  115. issueReason: '',
  116. targetLocation: '',
  117. remark: '',
  118. createLabel: false,
  119. printerName: '',
  120. },
  121. issueRequestMaterials: [],
  122. selectedRequestMaterial: null,
  123. selectedWorkOrder:'',
  124. materialList: [], // 新增:材料清单
  125. showOnlySelected: false,
  126. }
  127. },
  128. computed: {
  129. functionTitle() {
  130. return '客户单发料'
  131. },
  132. displayIssueRequestMaterials() {
  133. if (this.showOnlySelected && this.selectedRequestMaterial) {
  134. return [this.selectedRequestMaterial]
  135. }
  136. return this.issueRequestMaterials
  137. }
  138. },
  139. methods: {
  140. goBack() {
  141. this.$router.back()
  142. },
  143. goBackToMaterials() {
  144. this.selectedRequestMaterial = null
  145. },
  146. resetAll() {
  147. this.issueRequestMaterials = []
  148. this.selectedRequestMaterial = null
  149. this.message = ''
  150. },
  151. // 基于申请单发料相关方法
  152. async loadIssueRequestMaterials() {
  153. if (this.loading) {
  154. console.log("正在加载中,防重复提交");
  155. return;
  156. }
  157. if (!this.requestIssueForm.requestNo) {
  158. this.showMessage('请输入发料申请单号', 'error')
  159. return
  160. }
  161. this.loading = true
  162. this.loadingText = '加载申请单物料...'
  163. this.issueRequestMaterials = []
  164. this.materialList = []
  165. this.selectedRequestMaterial = null
  166. this.showOnlySelected = false
  167. getCustomerIssueNotifyHeaderInfo({
  168. site: localStorage.getItem('site'),
  169. workOrderNo: this.requestIssueForm.requestNo,
  170. }).then(({ data }) => {
  171. if (data.code === 0) {
  172. this.issueRequestMaterials = data.data || []
  173. if (this.issueRequestMaterials.length === 0) {
  174. this.$message.warning('查询申请单不存在')
  175. }
  176. } else {
  177. this.$message.error(data.msg, 'error')
  178. }
  179. })
  180. .finally(() => {
  181. this.loading = false
  182. })
  183. },
  184. isSameRequestMaterial(a, b) {
  185. if (!a || !b) return false
  186. return (
  187. a.notifyNo === b.notifyNo &&
  188. a.itemNo === b.itemNo &&
  189. a.soorderNo === b.soorderNo
  190. )
  191. },
  192. selectRequestMaterial(material) {
  193. if (
  194. this.showOnlySelected &&
  195. this.selectedRequestMaterial
  196. ) {
  197. // 再次点击同一条,恢复显示所有主数据
  198. this.selectedRequestMaterial = null
  199. this.selectedWorkOrder = ''
  200. this.materialList = []
  201. this.showOnlySelected = false
  202. return
  203. }
  204. // 选择并仅显示当前申请单物料
  205. this.selectedRequestMaterial = material
  206. this.selectedWorkOrder = material.SHIPMENT_ID
  207. this.showOnlySelected = true
  208. this.getCustomerIssueNotifyHeaderOrderMaterialList(material)
  209. },
  210. getCustomerIssueNotifyHeaderOrderMaterialList(material){
  211. let params = {
  212. site: localStorage.getItem('site'),
  213. workOrderNo: material.SHIPMENT_ID,
  214. };
  215. getCustomerIssueNotifyHeaderOrderMaterialList(params).then(({ data }) => {
  216. if (data.code === 0) {
  217. console.log(data)
  218. this.materialList = data.data || []
  219. if (this.materialList.length === 0) {
  220. this.$message.warning('该申请单行号暂无材料清单')
  221. }
  222. } else {
  223. this.$message.error(data.msg, 'error')
  224. }
  225. }).catch((error) => {
  226. this.$message.error('获取材料清单失败: ' + error.message, 'error')
  227. });
  228. },
  229. // 打开材料列表页面(仿照 productionReturnPicking.vue 的 openIssueList)
  230. openIssueDetail(material) {
  231. this.$router.push({
  232. name: 'customerIssuePDAIssueList',
  233. query: {
  234. state: material.STATE, // 申请单行号
  235. shipmentId: material.SHIPMENT_ID, // 客户订单号
  236. orderType: material.SHIPMENT_TYPE, // 订单类型
  237. }
  238. })
  239. },
  240. resetRequest() {
  241. this.requestIssueForm.requestNo = ''
  242. this.issueRequestMaterials = []
  243. this.selectedRequestMaterial = null
  244. },
  245. showMessage(text, type = 'info') {
  246. this.message = text
  247. this.messageType = type
  248. setTimeout(() => {
  249. this.message = ''
  250. }, 3000)
  251. },
  252. },
  253. created () {
  254. this.resetRequest()
  255. },
  256. mounted() {
  257. // 聚焦申请单号输入框
  258. this.$nextTick(() => {
  259. if (this.$refs.requestNoInput) {
  260. this.$refs.requestNoInput.focus()
  261. }
  262. })
  263. },
  264. }
  265. </script>
  266. <style scoped>
  267. .pda-container {
  268. width: 100vw;
  269. height: 100vh;
  270. display: flex;
  271. flex-direction: column;
  272. background: #f5f5f5;
  273. }
  274. /* 头部栏 */
  275. .header-bar {
  276. display: flex;
  277. justify-content: space-between;
  278. align-items: center;
  279. padding: 8px 16px;
  280. background: #17b3a3;
  281. color: white;
  282. height: 40px;
  283. min-height: 40px;
  284. }
  285. .header-left {
  286. display: flex;
  287. align-items: center;
  288. cursor: pointer;
  289. font-size: 16px;
  290. font-weight: 500;
  291. }
  292. .header-left i {
  293. margin-right: 8px;
  294. font-size: 18px;
  295. }
  296. .header-right {
  297. cursor: pointer;
  298. font-size: 16px;
  299. font-weight: 500;
  300. }
  301. /* 搜索容器 */
  302. .search-container {
  303. padding: 12px 16px;
  304. background: white;
  305. display: flex;
  306. align-items: center;
  307. gap: 12px;
  308. }
  309. .search-container .el-input {
  310. flex: 1;
  311. }
  312. /* 工单列表 */
  313. .work-order-list {
  314. overflow-y: auto;
  315. padding: 12px 16px;
  316. }
  317. /* 工单卡片 */
  318. .work-order-card {
  319. background: white;
  320. border-radius: 8px;
  321. margin-bottom: 12px;
  322. padding: 16px;
  323. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  324. cursor: pointer;
  325. transition: all 0.2s ease;
  326. border: 2px solid transparent;
  327. }
  328. .work-order-card:hover {
  329. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  330. transform: translateY(-1px);
  331. }
  332. .work-order-card.selected {
  333. border-color: #17b3a3;
  334. background: #f0fffe;
  335. }
  336. .work-order-card:active {
  337. transform: translateY(0);
  338. }
  339. /* 内容区域 */
  340. .content-area {
  341. flex: 1;
  342. overflow-y: auto;
  343. padding: 12px 16px;
  344. }
  345. /* 材料卡片 */
  346. .material-card {
  347. background: white;
  348. border-radius: 8px;
  349. margin-bottom: 12px;
  350. padding: 16px;
  351. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  352. cursor: pointer;
  353. transition: all 0.2s ease;
  354. border: 2px solid transparent;
  355. }
  356. .material-card:hover {
  357. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  358. transform: translateY(-1px);
  359. }
  360. .material-card.selected {
  361. border-color: #17b3a3;
  362. background: #f0fffe;
  363. }
  364. .material-card:active {
  365. transform: translateY(0);
  366. }
  367. /* 卡片标题 */
  368. .card-title {
  369. margin-bottom: 12px;
  370. }
  371. .title-label {
  372. font-size: 12px;
  373. color: #666;
  374. display: block;
  375. margin-bottom: 4px;
  376. }
  377. .title-value {
  378. font-size: 16px;
  379. font-weight: bold;
  380. color: #333;
  381. margin-left: 16px;
  382. }
  383. /* 物料描述行 */
  384. .part-desc-row {
  385. margin-bottom: 12px;
  386. padding: 0 4px;
  387. }
  388. .desc-text {
  389. font-size: 12px;
  390. color: #666;
  391. line-height: 1.3;
  392. word-break: break-all;
  393. }
  394. /* 卡片详情 */
  395. .card-details {
  396. display: flex;
  397. justify-content: space-between;
  398. align-items: flex-start;
  399. gap: 4px;
  400. }
  401. .detail-item {
  402. flex: 1;
  403. text-align: center;
  404. min-width: 50px;
  405. max-width: 70px;
  406. }
  407. .detail-label {
  408. font-size: 11px;
  409. color: #666;
  410. margin-bottom: 4px;
  411. line-height: 1.2;
  412. margin-left: -12px;
  413. }
  414. .detail-value {
  415. font-size: 13px;
  416. color: #333;
  417. line-height: 1.2;
  418. margin-left: -12px;
  419. }
  420. /* 区域头部 */
  421. .section-header {
  422. display: flex;
  423. justify-content: space-between;
  424. align-items: center;
  425. margin-bottom: 12px;
  426. padding: 12px 16px;
  427. background: white;
  428. border-radius: 8px;
  429. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  430. }
  431. .section-header span {
  432. font-size: 14px;
  433. font-weight: 500;
  434. color: #333;
  435. }
  436. .reset-btn {
  437. background: #17b3a3;
  438. color: white;
  439. border: none;
  440. padding: 6px 12px;
  441. border-radius: 4px;
  442. cursor: pointer;
  443. font-size: 12px;
  444. }
  445. .reset-btn:hover {
  446. background: #13998c;
  447. }
  448. /* 输入组 */
  449. .input-group {
  450. margin-bottom: 12px;
  451. }
  452. .input-with-scan {
  453. display: flex;
  454. gap: 8px;
  455. align-items: center;
  456. }
  457. .input-with-scan .el-input {
  458. flex: 1;
  459. }
  460. /* 复选框组 */
  461. .checkbox-group {
  462. margin-bottom: 12px;
  463. }
  464. /* 确认区域 */
  465. .confirm-section {
  466. padding: 16px;
  467. background: white;
  468. border-radius: 8px;
  469. margin-top: 12px;
  470. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  471. }
  472. /* 空状态 */
  473. .empty-state {
  474. display: flex;
  475. flex-direction: column;
  476. align-items: center;
  477. justify-content: center;
  478. padding: 60px 20px;
  479. color: #999;
  480. }
  481. .empty-state i {
  482. font-size: 48px;
  483. margin-bottom: 16px;
  484. }
  485. .empty-state p {
  486. font-size: 14px;
  487. margin: 0;
  488. }
  489. /* 加载状态 */
  490. .loading-state {
  491. display: flex;
  492. flex-direction: column;
  493. align-items: center;
  494. justify-content: center;
  495. padding: 60px 20px;
  496. color: #17b3a3;
  497. }
  498. .loading-state i {
  499. font-size: 24px;
  500. margin-bottom: 12px;
  501. animation: spin 1s linear infinite;
  502. }
  503. @keyframes spin {
  504. from {
  505. transform: rotate(0deg);
  506. }
  507. to {
  508. transform: rotate(360deg);
  509. }
  510. }
  511. .loading-state p {
  512. font-size: 14px;
  513. margin: 0;
  514. }
  515. /* 消息提示 */
  516. .message {
  517. position: fixed;
  518. top: 20px;
  519. left: 50%;
  520. transform: translateX(-50%);
  521. padding: 12px 20px;
  522. border-radius: 6px;
  523. font-weight: bold;
  524. z-index: 1001;
  525. max-width: 90%;
  526. text-align: center;
  527. }
  528. .message.success {
  529. background: #d4edda;
  530. color: #155724;
  531. border: 1px solid #c3e6cb;
  532. }
  533. .message.error {
  534. background: #f8d7da;
  535. color: #721c24;
  536. border: 1px solid #f5c6cb;
  537. }
  538. .message.warning {
  539. background: #fff3cd;
  540. color: #856404;
  541. border: 1px solid #ffeaa7;
  542. }
  543. .message.info {
  544. background: #d1ecf1;
  545. color: #0c5460;
  546. border: 1px solid #bee5eb;
  547. }
  548. /* 响应式设计 */
  549. @media (max-width: 360px) {
  550. .header-bar {
  551. padding: 8px 12px;
  552. }
  553. .search-container {
  554. padding: 8px 12px;
  555. }
  556. .work-order-list {
  557. padding: 8px 12px;
  558. }
  559. .work-order-card {
  560. padding: 12px;
  561. }
  562. .content-area {
  563. padding: 8px 12px;
  564. }
  565. .material-card {
  566. padding: 12px;
  567. }
  568. .card-details {
  569. flex-wrap: wrap;
  570. gap: 6px;
  571. }
  572. .detail-item {
  573. flex: 0 0 48%;
  574. margin-bottom: 6px;
  575. min-width: 50px;
  576. }
  577. }
  578. </style>