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.

447 lines
12 KiB

8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
6 months ago
6 months ago
6 months ago
8 months ago
  1. <template>
  2. <div>
  3. <div class="pda-container">
  4. <div class="status-bar">
  5. <div class="goBack" @click="handleBack"><i class="el-icon-arrow-left"></i>上一页</div>
  6. <div class="goBack">检验不合格处理</div>
  7. <div class="network" style="color: #fff" @click="$router.push({ path: '/' })">🏠首页</div>
  8. </div>
  9. <div style="overflow-y: auto">
  10. <!-- Step 1: 扫描或查询检验单据 -->
  11. <div v-if="processFlag === 1">
  12. <div class="scan-box" style="margin: 2px;">
  13. <el-input clearable v-model="scanCode" placeholder="扫描采购单条码"
  14. @keyup.enter.native="handleScan" ref="scanCodeRef" />
  15. </div>
  16. <div class="item-list" v-if="unqualifiedList.length > 0" style="margin: 2px;">
  17. <el-form label-position="top" style="margin: 3px;">
  18. <el-row :gutter="5" @click.native="selectProcessItem(unqualifiedDetail)"
  19. v-for="(unqualifiedDetail, index) in unqualifiedList" :key="index"
  20. :class="index < unqualifiedList.length - 1 ? 'bottom-line-row' : ''">
  21. <el-col :span="6">
  22. <el-form-item label="物料编码"><span>{{ unqualifiedDetail.partNo }}</span></el-form-item>
  23. </el-col>
  24. <el-col :span="8">
  25. <el-form-item label="单据号"><span>{{ unqualifiedDetail.transNo }}</span></el-form-item>
  26. </el-col>
  27. <el-col :span="4">
  28. <el-form-item label="类型">
  29. <span >
  30. {{ getProcessTypeText(unqualifiedDetail.processType) }}
  31. </span>
  32. </el-form-item>
  33. </el-col>
  34. <el-col :span="6">
  35. <el-form-item label="">
  36. <el-button type="text" class="processButton" @click="selectProcessItem(unqualifiedDetail)"
  37. style="margin-top: 10px;margin-left: 20px" size="small">处理</el-button>
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="24">
  41. <el-form-item label="物料描述"><span>{{ unqualifiedDetail.partDesc }}</span></el-form-item>
  42. </el-col>
  43. <el-col :span="6">
  44. <el-form-item :label="getQtyLabel(unqualifiedDetail.processType)">
  45. <span :style="getQtyStyle(unqualifiedDetail.processType)">{{ unqualifiedDetail.unqualifiedQty }}</span>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="6">
  49. <el-form-item label="批次号"><span>{{ unqualifiedDetail.batchNo }}</span></el-form-item>
  50. </el-col>
  51. <el-col :span="6">
  52. <el-form-item label="PO号"><span>{{ unqualifiedDetail.orderRef1 }}</span></el-form-item>
  53. </el-col>
  54. <el-col :span="6">
  55. <el-form-item label="检验日期"><span>{{ formatDate(unqualifiedDetail.inspectionDate) }}</span></el-form-item>
  56. </el-col>
  57. </el-row>
  58. </el-form>
  59. </div>
  60. <!-- 扫描的HandlingUnit明细列表 -->
  61. <div class="scanned-items" v-if="scannedItems.length > 0" style="margin: 2px;">
  62. <div class="section-title">已扫描明细</div>
  63. <div class="item-list">
  64. <el-form label-position="top" style="margin: 3px;">
  65. <el-row :gutter="5" v-for="(item, index) in scannedItems" :key="index"
  66. :class="index < scannedItems.length - 1 ? 'bottom-line-row' : ''">
  67. <el-col :span="8">
  68. <el-form-item label="物料编码"><span>{{ item.partNo }}</span></el-form-item>
  69. </el-col>
  70. <el-col :span="8">
  71. <el-form-item label="HandlingUnit"><span>{{ item.unitId }}</span></el-form-item>
  72. </el-col>
  73. <el-col :span="8">
  74. <el-form-item label="">
  75. <el-button type="text" style="color: #F56C6C;" @click="removeScannedItem(index)"
  76. size="small">移除</el-button>
  77. </el-form-item>
  78. </el-col>
  79. <el-col :span="12">
  80. <el-form-item label="物料描述"><span>{{ item.partDesc }}</span></el-form-item>
  81. </el-col>
  82. <el-col :span="6">
  83. <el-form-item label="数量"><span>{{ item.qty }}</span></el-form-item>
  84. </el-col>
  85. <el-col :span="6">
  86. <el-form-item label="批次号"><span>{{ item.batchNo }}</span></el-form-item>
  87. </el-col>
  88. </el-row>
  89. </el-form>
  90. </div>
  91. </div>
  92. </div>
  93. </div>
  94. </div>
  95. </div>
  96. </template>
  97. <script>
  98. import { getUnqualifiedInspectionList, scanHandlingUnitLabel } from "@/api/po/po.js";
  99. export default {
  100. data() {
  101. return {
  102. processFlag: 1, // 1-不合格列表, 2-处理确认
  103. scanCode: '',
  104. unqualifiedList: [],
  105. scannedItems: [],
  106. selectedItem: {},
  107. site: localStorage.getItem('site')
  108. };
  109. },
  110. methods: {
  111. handleBack() {
  112. if (this.processFlag === 1) {
  113. this.$router.back();
  114. } else if (this.processFlag === 2) {
  115. this.processFlag = 1;
  116. this.scannedItems = [];
  117. } else {
  118. this.processFlag = 1;
  119. }
  120. },
  121. // 处理扫描
  122. handleScan() {
  123. if (!this.scanCode.trim()) {
  124. return;
  125. }
  126. // 判断是否为采购单条码或HandlingUnit条码
  127. if (this.scanCode.startsWith('PO') || this.scanCode.startsWith('REC')) {
  128. // 采购单或接收单条码,查询不合格单据
  129. this.searchUnqualifiedList();
  130. } else {
  131. // HandlingUnit条码,扫描添加明细
  132. this.scanHandlingUnit();
  133. }
  134. },
  135. // 查询检验不合格单据
  136. searchUnqualifiedList() {
  137. const params = {
  138. site: this.site
  139. };
  140. if (this.scanCode && (this.scanCode.startsWith('PO') || this.scanCode.startsWith('REC'))) {
  141. params.transNo = this.scanCode;
  142. }
  143. getUnqualifiedInspectionList(params).then(({ data }) => {
  144. if (data.code === 0) {
  145. this.unqualifiedList = data.rows || [];
  146. if (this.unqualifiedList.length === 0) {
  147. this.$message.success("暂无检验不合格待处理单据");
  148. }
  149. } else {
  150. this.$message.error(data.msg || "查询失败");
  151. }
  152. }).catch(error => {
  153. this.$message.error("查询失败");
  154. console.error(error);
  155. });
  156. this.scanCode = '';
  157. },
  158. // 扫描HandlingUnit条码
  159. scanHandlingUnit() {
  160. const params = {
  161. site: this.site,
  162. unitId: this.scanCode.trim()
  163. };
  164. scanHandlingUnitLabel(params).then(({ data }) => {
  165. if (data.code === 0 && data.data) {
  166. const huInfo = data.data;
  167. // 检查是否已经扫描过
  168. const exists = this.scannedItems.find(item => item.unitId === huInfo.unitId);
  169. if (exists) {
  170. this.$message.warning('该HandlingUnit已扫描,请勿重复扫描');
  171. this.scanCode = '';
  172. return;
  173. }
  174. // 添加到扫描列表
  175. this.scannedItems.push({
  176. unitId: huInfo.unitId,
  177. partNo: huInfo.partNo,
  178. partDesc: huInfo.partDesc,
  179. qty: huInfo.qty,
  180. batchNo: huInfo.batchNo,
  181. locationId: huInfo.locationId
  182. });
  183. this.$message.success('扫描成功');
  184. } else {
  185. this.$message.error(data.msg || 'HandlingUnit不存在或查询失败');
  186. }
  187. }).catch(error => {
  188. this.$message.error("扫描失败");
  189. console.error(error);
  190. });
  191. this.scanCode = '';
  192. },
  193. // 选择处理项目
  194. selectProcessItem(item) {
  195. this.selectedItem = { ...item };
  196. // 跳转到统一的不合格处理页面,通过processType参数区分处理类型
  197. this.$router.push({
  198. path: '/unqualified-process',
  199. query: {
  200. transNo: item.transNo,
  201. itemNo: item.itemNo,
  202. processType: item.processType,
  203. partNo: item.partNo,
  204. unqualifiedQty: item.unqualifiedQty,
  205. scannedItems: JSON.stringify(this.scannedItems)
  206. }
  207. });
  208. },
  209. // 移除扫描的项目
  210. removeScannedItem(index) {
  211. this.scannedItems.splice(index, 1);
  212. this.$message.success('移除成功');
  213. },
  214. // 获取处理类型文本
  215. getProcessTypeText(processType) {
  216. const typeMap = {
  217. 'RETURN': '退货',
  218. 'SCRAP': '报废',
  219. 'EXCHANGE': '换货'
  220. };
  221. return typeMap[processType] || '未知';
  222. },
  223. // 获取数量标签
  224. getQtyLabel(processType) {
  225. const labelMap = {
  226. 'RETURN': '退货数量',
  227. 'SCRAP': '报废数量',
  228. 'EXCHANGE': '换货数量'
  229. };
  230. return labelMap[processType] || '数量';
  231. },
  232. // 获取数量样式
  233. getQtyStyle(processType) {
  234. const styleMap = {
  235. 'RETURN': 'color: #E6A23C; font-weight: 500;', // 橙色
  236. 'SCRAP': 'color: #F56C6C; font-weight: 500;', // 红色
  237. 'EXCHANGE': 'color: #409EFF; font-weight: 500;' // 蓝色
  238. };
  239. return styleMap[processType] || 'color: #666; font-weight: 500;';
  240. },
  241. // 获取当前日期
  242. getCurrentDate() {
  243. const now = new Date();
  244. return now.getFullYear() + '-' +
  245. String(now.getMonth() + 1).padStart(2, '0') + '-' +
  246. String(now.getDate()).padStart(2, '0');
  247. },
  248. // 格式化日期
  249. formatDate(date) {
  250. if (!date) return '';
  251. const d = new Date(date);
  252. return d.getFullYear() + '-' +
  253. String(d.getMonth() + 1).padStart(2, '0') + '-' +
  254. String(d.getDate()).padStart(2, '0');
  255. }
  256. },
  257. mounted() {
  258. this.$nextTick(() => {
  259. if (this.$refs.scanCodeRef) {
  260. this.$refs.scanCodeRef.focus();
  261. }
  262. });
  263. // 默认加载检验不合格列表
  264. this.searchUnqualifiedList();
  265. }
  266. };
  267. </script>
  268. <style scoped>
  269. .goBack {
  270. cursor: pointer;
  271. }
  272. .scan-box input {
  273. width: 100%;
  274. padding: 12px;
  275. font-size: 16px;
  276. }
  277. .filter-box {
  278. text-align: center;
  279. padding: 10px;
  280. }
  281. .item-list {
  282. flex: 1;
  283. overflow-y: auto;
  284. margin: 10px 0;
  285. border: 1px solid rgba(200, 200, 200, 0.8);
  286. background: white;
  287. }
  288. .item-list span {
  289. color: #000;
  290. font-size: 15px;
  291. }
  292. .bottom-line-row {
  293. border-bottom: 1px solid rgba(200, 200, 200, 0.8);
  294. }
  295. .processButton {
  296. font-size: 16px;
  297. border-radius: 3px;
  298. color: #17b3a3;
  299. }
  300. .process-type-selector {
  301. background: white;
  302. padding: 15px;
  303. border-radius: 5px;
  304. border: 1px solid rgba(200, 200, 200, 0.8);
  305. }
  306. .process-type-selector .el-radio-group {
  307. display: flex;
  308. justify-content: space-around;
  309. }
  310. .process-type-selector .el-radio {
  311. margin-right: 0;
  312. }
  313. .section-title {
  314. background: #17b3a3;
  315. color: white;
  316. padding: 8px 15px;
  317. font-size: 14px;
  318. font-weight: 500;
  319. border-radius: 3px 3px 0 0;
  320. }
  321. /* 处理类型样式 */
  322. .process-type-return {
  323. background: #FDF6EC;
  324. color: #E6A23C;
  325. padding: 2px 8px;
  326. border-radius: 12px;
  327. font-size: 12px;
  328. font-weight: 500;
  329. border: 1px solid #F5DAB1;
  330. }
  331. .process-type-scrap {
  332. background: #FEF0F0;
  333. color: #F56C6C;
  334. padding: 2px 8px;
  335. border-radius: 12px;
  336. font-size: 12px;
  337. font-weight: 500;
  338. border: 1px solid #FAB6B6;
  339. }
  340. .process-type-exchange {
  341. background: #ECF5FF;
  342. color: #409EFF;
  343. padding: 2px 8px;
  344. border-radius: 12px;
  345. font-size: 12px;
  346. font-weight: 500;
  347. border: 1px solid #B3D8FF;
  348. }
  349. .process-type-unknown {
  350. background: #F5F7FA;
  351. color: #909399;
  352. padding: 2px 8px;
  353. border-radius: 12px;
  354. font-size: 12px;
  355. font-weight: 500;
  356. border: 1px solid #DCDFE6;
  357. }
  358. .item-list .el-row {
  359. cursor: pointer;
  360. transition: background 0.3s;
  361. padding: 10px;
  362. }
  363. .item-list .el-row:hover {
  364. background: #f5f7fa;
  365. }
  366. .form-section {
  367. background: white;
  368. border-radius: 5px;
  369. }
  370. .form-section >>> .el-col {
  371. margin-bottom: 12px;
  372. }
  373. .bottom-nav {
  374. display: flex;
  375. justify-content: space-around;
  376. padding: 10px;
  377. background: white;
  378. border-top: 1px solid #ddd;
  379. }
  380. .bottom-nav .el-button {
  381. flex: 1;
  382. margin: 0 5px;
  383. }
  384. /* 响应式调整 */
  385. @media (max-width: 768px) {
  386. .status-bar {
  387. font-size: 14px;
  388. padding: 8px 10px;
  389. }
  390. .scan-box input {
  391. padding: 10px;
  392. font-size: 14px;
  393. }
  394. .item-list span {
  395. font-size: 13px;
  396. }
  397. }
  398. </style>