| | |
| | | v-model="leftPartCodes[index]" |
| | | disabled |
| | | /> |
| | | <!-- æ°å¢ï¼ä¾æ¹ä»£ç è¾å
¥æ¡ --> |
| | | <input |
| | | type="text" |
| | | class="input-box supplier-code-input" |
| | | v-model="leftPartSupplierCodes[index]" |
| | | disabled |
| | | placeholder="便¹ä»£ç " |
| | | /> |
| | | <label class="checkbox-container"> |
| | | <input |
| | | type="checkbox" |
| | |
| | | <div class="right-top"> |
| | | <div class="form-row input-submit-row"> |
| | | <span class="label">å½å
¥æ¡ï¼</span> |
| | | <input type="text" class="input-box" v-model="rightTopInput" /> |
| | | <!-- å
³é®ä¿®æ¹1ï¼æ·»å refæ è¯ --> |
| | | <input |
| | | ref="inputBoxRef" |
| | | type="text" |
| | | class="input-box" |
| | | v-model="rightTopInput" |
| | | @blur="handleInputBlur" |
| | | /> |
| | | <button class="btn save-btn submit-input-btn" @click="saveData"> |
| | | <i class="icon icon-submit"></i>æäº¤ |
| | | </button> |
| | |
| | | /> |
| | | <button class="btn clear-btn" @click="clearFinishedProductCode"> |
| | | <i class="icon icon-clear"></i>æ¸
é¤ |
| | | </button> |
| | | <!-- æ°å¢ï¼å é¤å½åæçæé® --> |
| | | <button |
| | | class="btn delete-tray-btn" |
| | | @click="deleteCurrentTray" |
| | | :disabled="deleteLoading" |
| | | > |
| | | <i class="icon icon-delete"></i>å é¤å½åæç |
| | | </button> |
| | | </div> |
| | | <div |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { ref, onMounted, onUnmounted, watch, computed } from "vue"; |
| | | import { ref, onMounted, onUnmounted, watch, computed, nextTick } from "vue"; |
| | | import axios from "axios"; |
| | | |
| | | export default { |
| | |
| | | const finishedProductId = ref(""); // 左侧æåIDï¼æ¥å£è¿åï¼ |
| | | const rightTopInput = ref(""); // å³ä¾§æ ¸å¿å½å
¥æ¡ |
| | | const leftPartCodes = ref(Array(10).fill("")); // 左侧é¶ä»¶ç¼å·æ°ç» |
| | | // æ°å¢ï¼å·¦ä¾§ä¾æ¹ä»£ç æ°ç» |
| | | const leftPartSupplierCodes = ref(Array(10).fill("")); |
| | | const rightPartCodes = ref(Array(10).fill("")); // å³ä¾§é¶ä»¶ç¼å·æ°ç» |
| | | const leftPartChecked = ref(Array(10).fill(false)); // 左侧é¶ä»¶å¾éç¶æ |
| | | const leftPartIds = ref(Array(10).fill("")); // 左侧é¶ä»¶IDï¼æ¥å£è¿åï¼ |
| | | const finishedProductCode = ref(""); // å³ä¾§æåç¼å·è¾å
¥æ¡ |
| | | const fillIndex = ref(-1); // å½å
¥æ¡èªå¨å¡«å
ç´¢å¼ |
| | | const checkLoading = ref(Array(10).fill(false)); // é¶ä»¶å¾éå è½½é |
| | | // æ°å¢ï¼å 餿çå è½½ç¶æ |
| | | const deleteLoading = ref(false); |
| | | |
| | | // å
³é®ä¿®æ¹2ï¼å®ä¹å½å
¥æ¡ref |
| | | const inputBoxRef = ref(null); |
| | | |
| | | // ä¿¡å·ç¯ç¸å
³ |
| | | const signalStates = ref([false, false, false, false, false]); |
| | |
| | | const destroyDelayTime = 500; // å½å
¥æ¡å¡«å
å»¶è¿500ms |
| | | let autoSubmitDebounceTimer = null; |
| | | let submitLock = ref(false); // æäº¤éï¼é²æ¢éå¤æäº¤ |
| | | |
| | | // å
³é®ä¿®æ¹3ï¼å°è£
èç¦æ¹æ³ |
| | | const focusInputBox = () => { |
| | | nextTick(() => { |
| | | if (inputBoxRef.value) { |
| | | inputBoxRef.value.focus(); |
| | | // å¯éï¼éä¸è¾å
¥æ¡å
å®¹ï¼æ¹ä¾¿ç´æ¥è¦çè¾å
¥ |
| | | // inputBoxRef.value.select(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 计ç®å±æ§ - ç»è®¡ææå¾é/å¡«å
æ°éï¼è¿æ»¤ç©ºå¼ï¼ |
| | | const checkedCount = computed(() => { |
| | |
| | | for (let i = 0; i < 10; i++) { |
| | | leftPartCodes.value[i] = data.leftPartCodes[i] || ""; |
| | | leftPartIds.value[i] = data.leftPartIds?.[i] || ""; |
| | | // æ°å¢ï¼èµå¼ä¾æ¹ä»£ç |
| | | leftPartSupplierCodes.value[i] = data.leftPartSupplierCodes?.[i] || ""; |
| | | } |
| | | } |
| | | if (Array.isArray(data.leftPartChecked) && data.leftPartChecked.length >= 10) { |
| | |
| | | } |
| | | } catch (error) { |
| | | console.error("è·å左侧åå§æ°æ®å¤±è´¥ï¼", error); |
| | | } finally { |
| | | // æ°æ®å è½½å®æåèç¦ |
| | | focusInputBox(); |
| | | } |
| | | }; |
| | | |
| | |
| | | if (!finishedProductId.value) { |
| | | alert("æåIDä¸åå¨ï¼æ æ³æ´æ°é¶ä»¶æ«ç ç¶æï¼"); |
| | | leftPartChecked.value[index] = !isChecked; |
| | | focusInputBox(); // æç¤ºåèç¦ |
| | | return; |
| | | } |
| | | if (!partId) { |
| | | alert(`é¶ä»¶${index + 1}æ°æ®åºIDä¸åå¨ï¼æ æ³æ´æ°æ«ç ç¶æï¼`); |
| | | leftPartChecked.value[index] = !isChecked; |
| | | focusInputBox(); // æç¤ºåèç¦ |
| | | return; |
| | | } |
| | | if (!partCode.trim()) { |
| | | alert(`é¶ä»¶${index + 1}ç¼å·ä¸ºç©ºï¼æ æ³æ´æ°æ«ç ç¶æï¼`); |
| | | leftPartChecked.value[index] = !isChecked; |
| | | focusInputBox(); // æç¤ºåèç¦ |
| | | return; |
| | | } |
| | | |
| | |
| | | checkLoading.value[index] = false; |
| | | if (checkDebounceTimer) clearTimeout(checkDebounceTimer); |
| | | checkDebounceTimer = null; |
| | | focusInputBox(); // æä½å®æåèç¦ |
| | | } |
| | | }; |
| | | |
| | |
| | | fillIndex.value++; |
| | | } else { |
| | | alert("æåç¼å·åé¶ä»¶1-10å·²å
¨é¨å¡«å
宿,æ æ³ç»§ç»å½å
¥!"); |
| | | rightTopInput.value = ""; |
| | | destroyDelayTimer = null; |
| | | return; |
| | | } |
| | | rightTopInput.value = ""; |
| | | destroyDelayTimer = null; |
| | | focusInputBox(); // å¡«å
宿åèç¦ |
| | | }, destroyDelayTime); |
| | | }; |
| | | |
| | |
| | | { immediate: false } |
| | | ); |
| | | |
| | | // å
³é®ä¿®æ¹4ï¼å¤±å»ç¦ç¹æ¶éæ°èç¦ |
| | | const handleInputBlur = () => { |
| | | // å»¶è¿ä¸ç¹æ§è¡ï¼é¿å
åå
¶ä»æä½å²çª |
| | | setTimeout(() => { |
| | | focusInputBox(); |
| | | }, 50); |
| | | }; |
| | | |
| | | // å³ä¾§è¾å
¥æ¡æ¸
餿¹æ³ |
| | | const clearRightPart = (index) => (rightPartCodes.value[index] = ""); |
| | | const clearFinishedProductCode = () => (finishedProductCode.value = ""); |
| | | const clearRightPart = (index) => { |
| | | rightPartCodes.value[index] = ""; |
| | | focusInputBox(); // æ¸
é¤åèç¦ |
| | | }; |
| | | const clearFinishedProductCode = () => { |
| | | finishedProductCode.value = ""; |
| | | focusInputBox(); // æ¸
é¤åèç¦ |
| | | }; |
| | | |
| | | // æ ¸å¿ä¿®æ¹ï¼æ¢å¤æåç¼å·å¿
å¡«æ ¡éªï¼æªå¡«åç´æ¥æç¤ºå¹¶ç»æ¢æäº¤ |
| | | const saveData = async () => { |
| | |
| | | const productCode = finishedProductCode.value.trim(); |
| | | if (!productCode) { |
| | | alert("请å
å¡«åæåç¼å·ï¼æåç¼å·ä¸ºå¿
填项ï¼"); |
| | | focusInputBox(); // æç¤ºåèç¦ |
| | | return; |
| | | } |
| | | // 2. æäº¤éï¼é²æ¢éå¤ç¹å» |
| | |
| | | rightPartCodes.value = Array(10).fill(""); |
| | | rightTopInput.value = ""; |
| | | fillIndex.value = -1; |
| | | const msg = resData.message; |
| | | |
| | | // æ ¸å¿ä¿®æ¹ï¼ä»
å½ msg 䏿¯ null æ¶æå¼¹åºæç¤º |
| | | if (msg !== null) { |
| | | alert(msg); |
| | | } |
| | | } else { |
| | | // ä¸å¡é误ï¼ç´æ¥å±ç¤ºå端è¿åçmessageï¼å¦ç©æéè¯¯ãæ é
æ¹ï¼ |
| | | const errorMsg = resData.message || "æäº¤å¤±è´¥ï¼æªç¥ä¸å¡é误"; |
| | | alert(`æäº¤å¤±è´¥ï¼${errorMsg}`); |
| | | alert(`${resData.message || "æªç¥é误"}`); |
| | | } |
| | | } catch (error) { |
| | | // 6. å¼å¸¸æè·ï¼å
¼å®¹åç«¯æªæè·å¼å¸¸ï¼å¦PLCé讯å¼å¸¸ãæ°ç»è¶çã500éè¯¯ï¼ |
| | |
| | | } finally { |
| | | // 7. éæ¾æäº¤éï¼æ 论æå/失败é½è¦éæ¾ |
| | | submitLock.value = false; |
| | | focusInputBox(); // æäº¤å®æåèç¦ |
| | | } |
| | | }; |
| | | |
| | |
| | | if (!hasProductCode) { |
| | | console.log("â ï¸ æåç¼å·æªå¡«åï¼è·³è¿èªå¨æäº¤"); |
| | | autoSubmitDebounceTimer = null; |
| | | focusInputBox(); // æ ¡éªåèç¦ |
| | | return; |
| | | } |
| | | |
| | |
| | | }, 300); // 300ms鲿ï¼é¿å
è¾å
¥é¢ç¹è§¦å |
| | | }; |
| | | |
| | | // æ°å¢ï¼å é¤å½åæçæ¹æ³ |
| | | const deleteCurrentTray = async () => { |
| | | // 确认æä½ï¼é²æ¢è¯¯å |
| | | if (!confirm("确认è¦å é¤å½åæçæ°æ®åï¼æ¤æä½ä¸å¯æ¢å¤ï¼")) { |
| | | focusInputBox(); |
| | | return; |
| | | } |
| | | |
| | | // 设置å è½½ç¶æï¼é²æ¢éå¤ç¹å» |
| | | deleteLoading.value = true; |
| | | try { |
| | | console.log("ð¤ è°ç¨å é¤å½åæçæ¥å£ï¼/api/boxing/DeleteCurrentTray"); |
| | | // è°ç¨å 餿¥å£ï¼æ ¹æ®å®é
鿱鿩GET/POSTï¼è¿éé»è®¤ç¨POSTï¼è¥å端æ¯GET坿¹ä¸ºgetï¼ |
| | | const response = await axios.post( |
| | | "/api/boxing/DeleteCurrentTray", |
| | | {}, // è¥æ åæ°ä¼ ç©ºå¯¹è±¡ |
| | | { timeout: 8000 } |
| | | ); |
| | | const resData = response.data; |
| | | console.log("ð¥ å é¤å½åæçæ¥å£è¿åï¼", resData); |
| | | |
| | | // éé
å端è¿åæ ¼å¼ |
| | | const isSuccess = resData.status === true || resData.Status === true; |
| | | if (isSuccess) { |
| | | // å 餿å忏
空å³ä¾§è¾å
¥æ¡ |
| | | finishedProductCode.value = ""; |
| | | rightPartCodes.value = Array(10).fill(""); |
| | | rightTopInput.value = ""; |
| | | fillIndex.value = -1; |
| | | alert(resData.message || "å½åæçå 餿åï¼"); |
| | | } else { |
| | | alert(`å é¤å¤±è´¥ï¼${resData.message || "æªç¥é误"}`); |
| | | } |
| | | } catch (error) { |
| | | // å¼å¸¸å¤ç |
| | | let errorMsg = "å 餿ç请æ±å¼å¸¸ï¼"; |
| | | if (error.code === "ECONNABORTED") { |
| | | errorMsg = "å é¤è¯·æ±è¶
æ¶ï¼è¯·ç¨åéè¯"; |
| | | } else if (error.response) { |
| | | errorMsg = `æå¡å¨é误ï¼${error.response.status} - ${error.response.statusText}`; |
| | | console.error("â å 餿çæå¡å¨é误详æ
ï¼", error.response.data); |
| | | } else if (error.request) { |
| | | errorMsg = "ç½ç»å¼å¸¸ï¼æªæ¶å°å端ååºï¼è¯·æ£æ¥æ¥å£å°ååç½ç»"; |
| | | } else { |
| | | errorMsg = `请æ±é误ï¼${error.message}`; |
| | | } |
| | | alert(errorMsg); |
| | | console.error("â å é¤æçæ¥å£å¼å¸¸è¯¦æ
ï¼", error); |
| | | } finally { |
| | | // éæ¾å è½½ç¶æ |
| | | deleteLoading.value = false; |
| | | focusInputBox(); // æä½å®æåèç¦å½å
¥æ¡ |
| | | } |
| | | }; |
| | | |
| | | // çå¬èªå¨æäº¤ç¸å
³æ°æ®ååï¼è§¦åæ ¡éª |
| | | watch([checkedCount, filledPartCount, finishedProductCode], () => checkAutoSubmit(), { |
| | | deep: true, |
| | |
| | | const detectFillIndex = () => { |
| | | if (!finishedProductCode.value.trim()) { |
| | | fillIndex.value = -1; |
| | | return; |
| | | } |
| | | for (let i = 0; i < 10; i++) { |
| | | if (!rightPartCodes.value[i].trim()) { |
| | | fillIndex.value = i; |
| | | return; |
| | | } else { |
| | | for (let i = 0; i < 10; i++) { |
| | | if (!rightPartCodes.value[i].trim()) { |
| | | fillIndex.value = i; |
| | | return; |
| | | } |
| | | } |
| | | fillIndex.value = 10; |
| | | } |
| | | fillIndex.value = 10; |
| | | }; |
| | | |
| | | // ç嬿å/é¶ä»¶è¾å
¥ï¼æ´æ°å¡«å
ç´¢å¼ |
| | |
| | | await fetchLeftInitialData(); |
| | | startPolling(); |
| | | detectFillIndex(); |
| | | focusInputBox(); // é¡µé¢æè½½åç«å³èç¦ |
| | | }); |
| | | |
| | | // çå½å¨æï¼å¸è½½æ¶æ¸
餿æå®æ¶å¨/鲿ï¼é²æ¢å
åæ³æ¼ |
| | |
| | | finishedProduct, |
| | | rightTopInput, |
| | | leftPartCodes, |
| | | // æ°å¢ï¼æ´é²ä¾æ¹ä»£ç æ°ç» |
| | | leftPartSupplierCodes, |
| | | rightPartCodes, |
| | | leftPartChecked, |
| | | signalStates, |
| | | signalLabels, |
| | | finishedProductCode, |
| | | checkLoading, |
| | | deleteLoading, // æ´é²å é¤å è½½ç¶æ |
| | | handlePartCheck, |
| | | saveData, |
| | | deleteCurrentTray, // æ´é²å é¤æçæ¹æ³ |
| | | clearRightPart, |
| | | clearFinishedProductCode, |
| | | inputBoxRef, // æ´é²ref |
| | | handleInputBlur, // æ´é²æ¹æ³ |
| | | }; |
| | | }, |
| | | }; |
| | |
| | | transition: all 0.2s ease; |
| | | background-color: #ffffff; |
| | | } |
| | | /* æ°å¢ï¼ä¾æ¹ä»£ç è¾å
¥æ¡æ ·å¼ï¼å®½åº¦ç¨çªï¼ */ |
| | | .supplier-code-input { |
| | | flex: 0 0 150px; |
| | | min-width: 120px; |
| | | } |
| | | .input-box:focus { |
| | | border-color: #3b82f6; |
| | | box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.12); |
| | |
| | | gap: 8px; |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | /* æ°å¢ï¼å 餿çæé®å®½åº¦éé
*/ |
| | | .delete-tray-btn { |
| | | width: 140px !important; |
| | | } |
| | | .submit-input-btn { |
| | | width: 110px !important; |
| | |
| | | .icon-submit { |
| | | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M2.01 21L15 13.4 23 21V5H2.01V21zM17 15l-5-5-5 5V7h10v8z'/%3E%3C/svg%3E"); |
| | | } |
| | | /* æ°å¢ï¼å é¤å¾æ */ |
| | | .icon-delete { |
| | | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z'/%3E%3C/svg%3E"); |
| | | } |
| | | |
| | | /* æé®ä¸»é¢æ ·å¼ */ |
| | | .clear-btn { |
| | |
| | | .save-btn:hover:not(:disabled) { |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 8px rgba(59, 130, 246, 0.15); |
| | | } |
| | | /* æ°å¢ï¼å 餿çæé®æ ·å¼ */ |
| | | .delete-tray-btn { |
| | | background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); |
| | | color: #fff; |
| | | padding: 0 12px; |
| | | } |
| | | .delete-tray-btn:hover:not(:disabled) { |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 8px rgba(245, 158, 11, 0.15); |
| | | } |
| | | |
| | | /* ä¿¡å·ç¯æ ·å¼ */ |
| | |
| | | .input-box { |
| | | width: 100%; |
| | | } |
| | | /* éé
ç§»å¨ç«¯ä¾æ¹ä»£ç è¾å
¥æ¡ */ |
| | | .supplier-code-input { |
| | | flex: 1; |
| | | min-width: 100%; |
| | | margin-top: 6px; |
| | | } |
| | | /* ç§»å¨ç«¯æé®å®½åº¦éé
*/ |
| | | .btn, |
| | | .submit-input-btn { |
| | | .submit-input-btn, |
| | | .delete-tray-btn { |
| | | width: 100% !important; |
| | | margin-top: 6px; |
| | | } |