From ba8aa925e7901381ceb394adb53eca8723d1c4c5 Mon Sep 17 00:00:00 2001
From: leiqunqing <zhengqifeng@hnkhzn.com>
Date: 星期一, 19 一月 2026 11:05:49 +0800
Subject: [PATCH] 完善工位界面
---
代码管理/WIDESEAWCS_Client/src/views/Home.vue | 1094 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1,082 insertions(+), 12 deletions(-)
diff --git "a/\344\273\243\347\240\201\347\256\241\347\220\206/WIDESEAWCS_Client/src/views/Home.vue" "b/\344\273\243\347\240\201\347\256\241\347\220\206/WIDESEAWCS_Client/src/views/Home.vue"
index 820437a..b82d2f2 100644
--- "a/\344\273\243\347\240\201\347\256\241\347\220\206/WIDESEAWCS_Client/src/views/Home.vue"
+++ "b/\344\273\243\347\240\201\347\256\241\347\220\206/WIDESEAWCS_Client/src/views/Home.vue"
@@ -1,24 +1,1094 @@
<template>
- <div class="title"></div>
+ <div class="container">
+ <!-- 宸︿晶鍖哄煙 - 鏃犱换浣曟爣棰樻爣娉� -->
+ <div class="left-area">
+ <div class="left-top">
+ <!-- 鎸夐挳+淇″彿 妯悜鎺掑垪瀹瑰櫒 -->
+ <div class="btn-signal-group">
+ <!-- 鎸夐挳缁� - 淇敼涓轰笂涓嬫帓鍒� -->
+ <div class="btn-group">
+ <button
+ class="btn"
+ :class="isPLCStarted ? 'stop-btn' : 'start-btn'"
+ @click="handleToggle"
+ >
+ <i class="icon" :class="isPLCStarted ? 'icon-stop' : 'icon-start'"></i>
+ {{ isPLCStarted ? "鍏抽棴" : "鍚姩" }}
+ </button>
+ <button
+ class="btn"
+ :class="isPLCPaused ? 'resume-btn' : 'pause-btn'"
+ @click="handlePauseToggle"
+ :disabled="!isPLCStarted"
+ >
+ <i class="icon" :class="isPLCPaused ? 'icon-resume' : 'icon-pause'"></i>
+ {{ isPLCPaused ? "鎭㈠" : "鏆傚仠" }}
+ </button>
+ </div>
+
+ <!-- 淇″彿鐏粍 鍗犱袱涓寜閽搴� + 鏁翠綋鏀惧ぇ -->
+ <div class="signal-status">
+ <div class="signal-item" v-for="(signal, index) in signalStates" :key="index">
+ <div
+ class="signal-light"
+ :class="signal ? 'signal-active' : 'signal-inactive'"
+ >
+ <div class="signal-light-inner"></div>
+ </div>
+ <span class="signal-label">{{ signalLabels[index] }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="left-bottom">
+ <div class="form-row finished-product-row">
+ <span class="label">鎴愬搧缂栧彿锛�</span>
+ <input type="text" class="input-box" v-model="finishedProduct" disabled />
+ </div>
+ <div class="parts-list">
+ <div
+ class="form-row part-item"
+ v-for="(item, index) in leftPartCodes"
+ :key="index"
+ >
+ <span class="label">闆朵欢{{ index + 1 }}锛�</span>
+ <input
+ type="text"
+ class="input-box"
+ v-model="leftPartCodes[index]"
+ disabled
+ />
+ <label class="checkbox-container">
+ <input
+ type="checkbox"
+ class="part-checkbox"
+ v-model="leftPartChecked[index]"
+ @change="handlePartCheck(index)"
+ />
+ <span class="checkmark"></span>
+ <span class="checkbox-label">{{
+ leftPartChecked[index] ? "鎵爜" : "涓嶆壂"
+ }}</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- 鍙充晶鍖哄煙 - 鏃犱换浣曟爣棰樻爣娉� 銆愬凡鍒犻櫎娓呯┖+淇濆瓨鎸夐挳銆� -->
+ <div class="right-area">
+ <div class="right-top">
+ <div class="form-row">
+ <span class="label">褰曞叆妗嗭細</span>
+ <!-- 鉁� 鍙繚鐣欑函褰曞叆妗嗭紝娓呯┖/淇濆瓨鎸夐挳宸插垹闄� -->
+ <input type="text" class="input-box" v-model="rightTopInput" />
+ </div>
+ </div>
+
+ <div class="right-bottom">
+ <div class="form-row tooling-board-row">
+ <span class="short-label">宸ヨ鏉跨紪鍙凤細</span>
+ <input
+ type="text"
+ class="input-box short-input"
+ v-model="toolingBoardNo"
+ placeholder="璇疯緭鍏ュ伐瑁呮澘缂栧彿"
+ />
+ <button class="btn clear-btn" @click="clearToolingBoardNo">
+ <i class="icon icon-clear"></i>娓呴櫎
+ </button>
+ <button class="btn save-btn" @click="saveToolingBoardNo">
+ <i class="icon icon-submit"></i>鎻愪氦
+ </button>
+ </div>
+ <div class="parts-list">
+ <div class="form-row part-item finished-product-row">
+ <span class="label">鎴愬搧缂栧彿锛�</span>
+ <input
+ type="text"
+ class="input-box"
+ v-model="finishedProductCode"
+ placeholder="璇疯緭鍏ユ垚鍝佺紪鍙�"
+ />
+ <button class="btn clear-btn" @click="clearFinishedProductCode">
+ <i class="icon icon-clear"></i>娓呴櫎
+ </button>
+ </div>
+ <div
+ class="form-row part-item"
+ v-for="(item, index) in rightPartCodes"
+ :key="index"
+ >
+ <span class="label">闆朵欢{{ index + 1 }}锛�</span>
+ <input
+ type="text"
+ class="input-box"
+ v-model="rightPartCodes[index]"
+ placeholder="璇疯緭鍏ラ浂浠剁紪鍙�"
+ />
+ <button class="btn clear-btn" @click="clearRightPart(index)">
+ <i class="icon icon-clear"></i>娓呴櫎
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
</template>
<script>
-import { ref, reactive } from 'vue'
+import { ref, onMounted, onUnmounted, watch, computed } from "vue";
+import axios from "axios";
export default {
setup() {
- return {
+ // 鍩虹鏁版嵁瀹氫箟 - 1:1绮惧噯瀵规帴鍚庣 鎴愬搧缂栧彿+闆朵欢缂栧彿 鏃犲啑浣欏吋瀹�
+ const finishedProduct = ref(""); // 宸︿晶鎴愬搧缂栧彿锛圙etLeftInitialData鎺ュ彛杩斿洖锛�
+ const finishedProductId = ref("");
+ const rightTopInput = ref("");
+ const leftPartCodes = ref(Array(10).fill("")); // 宸︿晶闆朵欢缂栧彿鏁扮粍
+ const rightPartCodes = ref(Array(10).fill("")); // 鍙充晶闆朵欢缂栧彿鏁扮粍
+ const leftPartChecked = ref(Array(10).fill(false));
+ const toolingBoardNo = ref("");
+ const fillIndex = ref(-1);
+ const leftPartIds = ref(Array(10).fill(""));
+ const finishedProductCode = ref(""); // 鍙充晶鎴愬搧缂栧彿锛堝伐瑁呮澘鎺ュ彛杩斿洖锛�
- }
- }
-}
+ // PLC鐘舵��
+ const isPLCStarted = ref(false);
+ const isPLCPaused = ref(false);
+
+ // 淇″彿鐩稿叧
+ const signalStates = ref([false, false, false, false, false]);
+ const signalLabels = ref([
+ "蹇冭烦淇″彿",
+ "鎬ュ仠淇″彿",
+ "鑷姩杩愯淇″彿",
+ "鍦ㄧ嚎妯″紡淇″彿",
+ "鏁呴殰淇″彿",
+ ]);
+
+ // 瀹氭椂杞鏍稿績閰嶇疆
+ let pollingTimer = null;
+ const pollingInterval = 5000;
+ let checkDebounceTimer = null;
+ let destroyDelayTimer = null;
+ const destroyDelayTime = 500; // 鉁� 鏍稿績锛氬~鍏�+娓呯┖ 閮藉欢杩�500姣
+ let boardCodeDebounceTimer = null;
+ // 鉁� 鏂板锛氳嚜鍔ㄦ彁浜ら槻鎶栧畾鏃跺櫒锛岄槻姝㈤噸澶嶆彁浜�
+ let autoSubmitDebounceTimer = null;
+ // 鉁� 鏂板锛氭彁浜ら攣锛岄槻姝㈡棤鍕鹃�夋椂閲嶅瑙﹀彂鎻愪氦
+ let submitLock = ref(false);
+
+ // 鉁� 鉁� 鉁� 鏍稿績鏂板1锛氳绠楀睘鎬� - 瀹炴椂缁熻宸︿晶鍕鹃�夌殑澶嶉�夋鏁伴噺 (鑷姩鏇存柊)
+ const checkedCount = computed(() => {
+ // 缁熻leftPartChecked鏁扮粍涓负true鐨勬暟閲�
+ return leftPartChecked.value.filter((checked) => checked === true).length;
+ });
+
+ // 鉁� 鉁� 鉁� 鏍稿績鏂板2锛氳绠楀睘鎬� - 瀹炴椂缁熻鍙充晶宸插~鍏呯殑闆朵欢鏁伴噺 (鑷姩鏇存柊)
+ const filledPartCount = computed(() => {
+ // 缁熻rightPartCodes鏁扮粍涓湁鍊�(闈炵┖)鐨勯浂浠舵暟閲�
+ return rightPartCodes.value.filter((code) => code.trim() !== "").length;
+ });
+
+ // 鉁� 鑾峰彇宸︿晶鍒濆鏁版嵁 - 瀵规帴 /api/scanStation/GetLeftInitialData
+ const fetchLeftInitialData = async () => {
+ try {
+ console.log("姝e湪鑾峰彇宸︿晶鍒濆鏁版嵁锛堟垚鍝佺紪鍙�+闆朵欢缂栧彿+鍕鹃�夌姸鎬�+闆朵欢ID锛�...");
+ const response = await axios.get("/api/scanStation/GetLeftInitialData", {
+ timeout: 5000,
+ });
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ if (isSuccess) {
+ const data = resData.Data || resData.data || {};
+ if (data.finishedProductId) finishedProductId.value = data.finishedProductId;
+ if (data.finishedProduct) finishedProduct.value = data.finishedProduct;
+ // 璧嬪�煎乏渚ч浂浠剁紪鍙�
+ if (Array.isArray(data.leftPartCodes) && data.leftPartCodes.length >= 10) {
+ for (let i = 0; i < 10; i++) {
+ leftPartCodes.value[i] = data.leftPartCodes[i] || "";
+ leftPartIds.value[i] = data.leftPartIds?.[i] || "";
+ }
+ }
+ // 璧嬪�煎嬀閫夌姸鎬�
+ if (Array.isArray(data.leftPartChecked) && data.leftPartChecked.length >= 10) {
+ for (let i = 0; i < 10; i++) {
+ leftPartChecked.value[i] = !!data.leftPartChecked[i];
+ }
+ }
+ }
+ } catch (error) {
+ console.error("鑾峰彇宸︿晶鍒濆鏁版嵁澶辫触锛�", error);
+ }
+ };
+
+ // 鉁� 鑾峰彇淇″彿+PLC鐘舵��
+ const fetchSignalAndPLCStates = async () => {
+ try {
+ const response = await axios.get("/api/scanStation/GetSignalStates", {
+ timeout: 5000,
+ });
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ if (isSuccess) {
+ const data = resData.Data || resData.data || {};
+ const newSignalStates = data.signalStates || [];
+ for (let i = 0; i < 5; i++) signalStates.value[i] = newSignalStates[i] ?? false;
+ const plcStatus = data.plcStatus || data.plc_status || {};
+ isPLCStarted.value = plcStatus.isStarted ?? isPLCStarted.value;
+ // 鉁� 淇BUG锛氬師浠g爜鏄� isPLCStarted.value 瀵艰嚧鏆傚仠鐘舵�佽祴鍊奸敊璇�
+ isPLCPaused.value = plcStatus.isPaused ?? isPLCPaused.value;
+ }
+ } catch (error) {
+ console.error("鑾峰彇淇″彿鍜孭LC鐘舵�佸け璐ワ細", error);
+ }
+ };
+
+ // 鉁� 銆愭牳蹇冧慨鏀广�戝伐瑁呮澘鏌ヨ鎺ュ彛 - 鏈夋暟鎹氨濉厖锛屾棤鏁版嵁/澶辫触 瀹屽叏淇濈暀鍘熸湁鍐呭锛屼笉鍋氫换浣曟竻绌烘搷浣�
+ const fetchProductAndPartsByBoardCode = async (boardCode) => {
+ if (!boardCode.trim()) return;
+ try {
+ console.log(`宸ヨ鏉跨紪鍙峰彉鏇达紝璇锋眰鏁版嵁锛�${boardCode}`);
+ const response = await axios.get(
+ "/api/boxingDetail/GetProductAndPartsByBoardNo",
+ {
+ params: { palletCode: boardCode.trim() },
+ timeout: 5000,
+ }
+ );
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ // 鉁� 鍙湁銆愭帴鍙f垚鍔�+鏈夎繑鍥炴暟鎹�戠殑鏃跺�欙紝鎵嶆墽琛岃祴鍊艰鐩�
+ if (isSuccess) {
+ const data = resData.Data || resData.data || {};
+ // 鏈夋垚鍝佺紪鍙峰氨璧嬪�硷紝娌℃湁灏变笉鎿嶄綔
+ if (data.finishedProductCode) {
+ finishedProductCode.value = data.finishedProductCode;
+ }
+ // 鏈夐浂浠跺垪琛ㄥ氨濉厖锛屾病鏈夊氨涓嶆搷浣�
+ const partsList = Array.isArray(data.partsList) ? data.partsList : [];
+ if (partsList.length > 0) {
+ for (let i = 0; i < 10; i++) {
+ if (partsList[i]) {
+ rightPartCodes.value[i] = partsList[i];
+ }
+ }
+ }
+ console.log("鉁� 宸ヨ鏉挎煡璇㈡垚鍔燂紝鎴愬搧缂栧彿+闆朵欢缂栧彿濉厖瀹屾垚");
+ } else {
+ // 鉁� 鏃犲搴旀暟鎹細鍙脊鎻愮ず锛屼笉娓呯┖浠讳綍鍐呭
+ alert(
+ "鑾峰彇鏁版嵁澶辫触锛�" + (resData.Message || resData.message || "鏃犲搴斿伐瑁呮澘鏁版嵁")
+ );
+ }
+ } catch (error) {
+ // 鉁� 璇锋眰澶辫触锛氬彧寮规彁绀猴紝涓嶆竻绌轰换浣曞唴瀹�
+ alert("宸ヨ鏉挎暟鎹姹傚け璐ワ紝璇锋鏌ョ綉缁滄垨鎺ュ彛锛�");
+ console.error("宸ヨ鏉挎帴鍙h姹傚け璐ワ細", error);
+ } finally {
+ boardCodeDebounceTimer = null;
+ }
+ };
+
+ // 鍚姩/鍋滄瀹氭椂杞
+ const startPolling = () => {
+ if (pollingTimer) clearInterval(pollingTimer);
+ fetchSignalAndPLCStates();
+ pollingTimer = setInterval(fetchSignalAndPLCStates, pollingInterval);
+ };
+ const stopPolling = () => {
+ if (pollingTimer) clearInterval(pollingTimer);
+ pollingTimer = null;
+ };
+
+ // PLC鍚姩/鍏抽棴閫昏緫
+ const handleToggle = async () => {
+ try {
+ const response = await axios.get("/api/scanStation/StartPLC", {
+ params: { isStop: isPLCStarted.value },
+ timeout: 5000,
+ });
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ if (isSuccess) {
+ isPLCStarted.value = !isPLCStarted.value;
+ isPLCPaused.value = false;
+ fetchSignalAndPLCStates();
+ } else {
+ alert(
+ resData.Message ||
+ resData.message ||
+ (isPLCStarted.value ? "鍏抽棴澶辫触" : "鍚姩澶辫触")
+ );
+ }
+ } catch (error) {
+ alert(isPLCStarted.value ? "鍏抽棴PLC澶辫触" : "鍚姩PLC澶辫触");
+ console.error("PLC鍚仠澶辫触锛�", error);
+ }
+ };
+
+ // PLC鏆傚仠/鎭㈠閫昏緫
+ const handlePauseToggle = async () => {
+ try {
+ const response = await axios.get("/api/scanStation/PausePLC", {
+ params: { isPause: !isPLCPaused.value },
+ timeout: 5000,
+ });
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ if (isSuccess) {
+ isPLCPaused.value = !isPLCPaused.value;
+ fetchSignalAndPLCStates();
+ } else {
+ alert(
+ resData.Message ||
+ resData.message ||
+ (isPLCPaused.value ? "鎭㈠澶辫触" : "鏆傚仠澶辫触")
+ );
+ }
+ } catch (error) {
+ alert(isPLCPaused.value ? "鎭㈠PLC澶辫触" : "鏆傚仠PLC澶辫触");
+ console.error("PLC鏆傚仠鎭㈠澶辫触锛�", error);
+ }
+ };
+
+ // 闆朵欢鍕鹃�夌姸鎬佸彉鏇村鐞�
+ const handlePartCheck = async (index) => {
+ const isChecked = leftPartChecked.value[index];
+ const partCode = leftPartCodes.value[index];
+ const partId = leftPartIds.value[index];
+
+ if (!finishedProductId.value) {
+ alert("鎴愬搧ID涓嶅瓨鍦紝鏃犳硶鏇存柊闆朵欢鎵爜鐘舵�侊紒");
+ leftPartChecked.value[index] = !isChecked;
+ return;
+ }
+ if (!partId) {
+ alert(`闆朵欢${index + 1}鏁版嵁搴揑D涓嶅瓨鍦紝鏃犳硶鏇存柊鎵爜鐘舵�侊紒`);
+ leftPartChecked.value[index] = !isChecked;
+ return;
+ }
+ if (!partCode.trim()) {
+ alert(`闆朵欢${index + 1}缂栧彿涓虹┖锛屾棤娉曟洿鏂版壂鐮佺姸鎬侊紒`);
+ leftPartChecked.value[index] = !isChecked;
+ return;
+ }
+
+ if (checkDebounceTimer) clearTimeout(checkDebounceTimer);
+ checkDebounceTimer = setTimeout(async () => {
+ try {
+ const response = await axios.post(
+ "/api/scanStation/UpdatePartScannedStatus",
+ { Id: partId, IsScanned: isChecked ? 1 : 0 },
+ { timeout: 5000 }
+ );
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ if (isSuccess) {
+ console.log(`闆朵欢${index + 1}鎵爜鐘舵�佹洿鏂版垚鍔焋);
+ // 鉁� 鍕鹃�夌姸鎬佸彉鍖栨椂锛岄噸缃彁浜ら攣
+ submitLock.value = false;
+ } else {
+ leftPartChecked.value[index] = !isChecked;
+ alert(
+ `闆朵欢${index + 1}鐘舵�佹洿鏂板け璐ワ細${
+ resData.Message || resData.message || "鏈煡閿欒"
+ }`
+ );
+ }
+ } catch (error) {
+ leftPartChecked.value[index] = !isChecked;
+ alert(`闆朵欢${index + 1}鐘舵�佹洿鏂拌姹傚け璐ワ紝璇锋鏌ョ綉缁滄垨鎺ュ彛锛乣);
+ console.error(`鏇存柊闆朵欢${index + 1}鎵爜鐘舵�佸け璐ワ細`, error);
+ } finally {
+ checkDebounceTimer = null;
+ }
+ }, 500);
+ };
+
+ // 鉁� 鏍稿績淇敼锛氬欢杩�0.5绉掑~鍏� + 寤惰繜0.5绉掓竻绌� 鍚屾鎵ц 鏃犻渶鎵嬪姩鎸夐挳
+ const fillContent = () => {
+ if (!rightTopInput.value.trim()) return;
+ const inputValue = rightTopInput.value.trim();
+
+ // 娓呴櫎鏃у畾鏃跺櫒锛岄槻姝㈤噸澶嶆墽琛�
+ if (destroyDelayTimer) clearTimeout(destroyDelayTimer);
+ // 缁熶竴寤惰繜500ms鎵ц銆愬~鍏�+娓呯┖銆�
+ destroyDelayTimer = setTimeout(() => {
+ if (!toolingBoardNo.value.trim()) {
+ toolingBoardNo.value = inputValue;
+ } else if (!finishedProductCode.value.trim()) {
+ finishedProductCode.value = inputValue;
+ } else if (fillIndex.value < 10) {
+ rightPartCodes.value[fillIndex.value] = inputValue;
+ fillIndex.value++;
+ } else {
+ alert("宸ヨ鏉跨紪鍙枫�佹垚鍝佺紪鍙峰拰闆朵欢1-10宸插叏閮ㄥ~鍏呭畬鎴�,鏃犳硶缁х画褰曞叆!");
+ rightTopInput.value = "";
+ destroyDelayTimer = null;
+ return;
+ }
+ // 濉厖瀹屾垚鍚� 鑷姩娓呯┖褰曞叆妗�
+ rightTopInput.value = "";
+ destroyDelayTimer = null;
+ }, destroyDelayTime);
+ };
+
+ // 鉁� 鐩戝惉褰曞叆妗嗗唴瀹瑰彉鍖栬嚜鍔ㄨЕ鍙戝~鍏呴�昏緫
+ watch(
+ rightTopInput,
+ (newVal) => {
+ if (newVal.trim()) fillContent();
+ },
+ { immediate: false }
+ );
+
+ // 鐩戝惉宸ヨ鏉跨紪鍙峰彉鍖栨煡璇㈡暟鎹�
+ watch(
+ toolingBoardNo,
+ (newVal) => {
+ const boardCode = newVal.trim();
+ if (boardCode) {
+ if (boardCodeDebounceTimer) clearTimeout(boardCodeDebounceTimer);
+ boardCodeDebounceTimer = setTimeout(
+ () => fetchProductAndPartsByBoardCode(boardCode),
+ 300
+ );
+ } else {
+ if (boardCodeDebounceTimer) clearTimeout(boardCodeDebounceTimer);
+ }
+ },
+ { immediate: false }
+ );
+
+ // 鍙充晶椤甸潰鎿嶄綔鏂规硶 (宸插垹闄ゆ竻绌�/淇濆瓨褰曞叆妗嗙殑鏂规硶锛屾棤鍐椾綑)
+ const clearToolingBoardNo = () => (toolingBoardNo.value = "");
+ const clearRightPart = (index) => (rightPartCodes.value[index] = "");
+ const clearFinishedProductCode = () => (finishedProductCode.value = "");
+
+ // 鎻愪氦宸ヨ鏉挎暟鎹埌鍚庣
+ const saveToolingBoardNo = async () => {
+ if (!toolingBoardNo.value.trim()) {
+ alert("宸ヨ鏉跨紪鍙蜂笉鑳戒负绌猴紝璇疯緭鍏ュ悗鍐嶆彁浜わ紒");
+ return;
+ }
+ if (!finishedProductCode.value.trim()) {
+ alert("鎴愬搧缂栧彿涓嶈兘涓虹┖锛岃杈撳叆鍚庡啀鎻愪氦锛�");
+ return;
+ }
+ try {
+ const submitData = {
+ toolingBoardNo: toolingBoardNo.value.trim(),
+ finishedProductCode: finishedProductCode.value.trim(),
+ partsList: rightPartCodes.value.map((item) => item.trim()),
+ };
+ console.log("鉁� 鎻愪氦宸ヨ鏉挎暟鎹細", submitData);
+ const response = await axios.post(
+ "/api/boxingDetail/SaveToolingBoardNo",
+ submitData,
+ { timeout: 5000 }
+ );
+ const resData = response.data;
+ const isSuccess = resData.Status === true || resData.status === true;
+ if (isSuccess) {
+ alert("鉁� 鎻愪氦鎴愬姛锛�");
+ toolingBoardNo.value = "";
+ finishedProductCode.value = "";
+ rightPartCodes.value = Array(10).fill("");
+ rightTopInput.value = "";
+ fillIndex.value = -1;
+ // 鉁� 鎻愪氦鎴愬姛鍚庯紝閲嶇疆鎻愪氦閿�
+ submitLock.value = false;
+ } else {
+ alert("鎻愪氦澶辫触锛�" + (resData.Message || resData.message || "鏈煡閿欒"));
+ }
+ } catch (error) {
+ alert("鎻愪氦璇锋眰澶辫触锛岃妫�鏌ョ綉缁滄垨鎺ュ彛锛�");
+ console.error("鎻愪氦鎺ュ彛澶辫触锛�", error);
+ // 鉁� 璇锋眰澶辫触涔熼噸缃攣
+ submitLock.value = false;
+ }
+ };
+
+ // 鉁� 鉁� 鉁� 鏍稿績鍗囩骇锛氳嚜鍔ㄦ彁浜ゅ垽鏂�昏緫 - 鏂板鏃犲嬀閫夋椂鎴愬搧缂栧彿濉厖鍗虫彁浜�
+ const checkAutoSubmit = () => {
+ // 闃叉姈锛氶槻姝㈢煭鏃堕棿鍐呭娆¤Е鍙戞彁浜�
+ if (autoSubmitDebounceTimer) clearTimeout(autoSubmitDebounceTimer);
+ autoSubmitDebounceTimer = setTimeout(() => {
+ const needCheckNum = checkedCount.value; // 宸︿晶鍕鹃�夌殑鏁伴噺
+ const filledNum = filledPartCount.value; // 鍙充晶濉厖鐨勯浂浠舵暟閲�
+ const hasBoardNo = toolingBoardNo.value.trim() !== ""; // 宸ヨ鏉挎湁鍊�
+ const hasProductCode = finishedProductCode.value.trim() !== ""; // 鎴愬搧鏈夊��
+
+ console.log(`鉁� 鑷姩鎻愪氦鏍¢獙锛氬乏渚у嬀閫�${needCheckNum}涓紝鍙充晶濉厖${filledNum}涓猔);
+
+ // 鍒嗘敮1锛氬乏渚ф湁鍕鹃�� 鈫� 鍘熸湁閫昏緫锛氶浂浠跺~鍏呮暟鈮ュ嬀閫夋暟 鎵嶆彁浜�
+ if (needCheckNum > 0) {
+ if (hasBoardNo && hasProductCode && filledNum >= needCheckNum) {
+ console.log("鉁� 婊¤冻鍕鹃�夋暟閲忔潯浠讹紝鎵ц鑷姩鎻愪氦锛�");
+ saveToolingBoardNo();
+ }
+ }
+ // 鍒嗘敮2锛氬乏渚ф棤鍕鹃�� 鈫� 鏂板閫昏緫锛氬伐瑁呮澘+鎴愬搧閮芥湁鍊� 灏辨彁浜� (鍔犻攣闃查噸澶�)
+ else {
+ if (hasBoardNo && hasProductCode && !submitLock.value) {
+ console.log("鉁� 宸︿晶鏃犲嬀閫夛紝鎴愬搧缂栧彿濉厖瀹屾垚锛屾墽琛岃嚜鍔ㄦ彁浜わ紒");
+ submitLock.value = true; // 鍔犻攣闃叉閲嶅鎻愪氦
+ saveToolingBoardNo();
+ }
+ }
+ autoSubmitDebounceTimer = null;
+ }, 300);
+ };
+
+ // 鉁� 鉁� 鉁� 鏍稿績鏂板4锛氱洃鍚叧閿暟鎹彉鍖栵紝瑙﹀彂鑷姩鎻愪氦鏍¢獙
+ watch(
+ [checkedCount, filledPartCount, toolingBoardNo, finishedProductCode],
+ () => {
+ checkAutoSubmit();
+ },
+ { deep: true, immediate: false }
+ );
+
+ // 鑷姩妫�娴嬪~鍏呯储寮曢�昏緫
+ const detectFillIndex = () => {
+ if (!toolingBoardNo.value.trim() || !finishedProductCode.value.trim()) {
+ fillIndex.value = -1;
+ return;
+ }
+ for (let i = 0; i < 10; i++) {
+ if (!rightPartCodes.value[i].trim()) {
+ fillIndex.value = i;
+ return;
+ }
+ }
+ fillIndex.value = 10;
+ };
+
+ watch(
+ [toolingBoardNo, finishedProductCode, () => [...rightPartCodes.value]],
+ detectFillIndex,
+ {
+ immediate: true,
+ deep: true,
+ }
+ );
+
+ // 椤甸潰鎸傝浇/鍗歌浇鐢熷懡鍛ㄦ湡
+ onMounted(async () => {
+ await fetchLeftInitialData();
+ startPolling();
+ detectFillIndex();
+ });
+
+ onUnmounted(() => {
+ stopPolling();
+ if (checkDebounceTimer) clearTimeout(checkDebounceTimer);
+ if (destroyDelayTimer) clearTimeout(destroyDelayTimer);
+ if (boardCodeDebounceTimer) clearTimeout(boardCodeDebounceTimer);
+ if (autoSubmitDebounceTimer) clearTimeout(autoSubmitDebounceTimer);
+ });
+
+ return {
+ finishedProduct,
+ finishedProductId,
+ rightTopInput,
+ leftPartCodes,
+ rightPartCodes,
+ leftPartChecked,
+ leftPartIds,
+ toolingBoardNo,
+ isPLCStarted,
+ isPLCPaused,
+ signalStates,
+ signalLabels,
+ finishedProductCode,
+ handleToggle,
+ handlePauseToggle,
+ handlePartCheck,
+ clearToolingBoardNo,
+ saveToolingBoardNo,
+ clearRightPart,
+ clearFinishedProductCode,
+ };
+ },
+};
</script>
<style scoped>
-.title {
- line-height: 70vh;
- text-align: center;
- font-size: 28px;
- color: orange;
+/* 鍩虹鏍峰紡閲嶇疆涓庡叏灞�鏍峰紡 */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ font-family: "Microsoft Yahei", "PingFang SC", "Inter", sans-serif;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
}
-</style>
\ No newline at end of file
+*::-webkit-scrollbar {
+ display: none;
+}
+
+body {
+ background: linear-gradient(135deg, #f0f4f8 0%, #e9ecef 100%);
+ min-height: 100vh;
+ overflow: hidden;
+ font-size: 14px;
+}
+
+/* 瀹瑰櫒鏍峰紡 - 鏀惧ぇ 闂磋窛鍔犲 */
+.container {
+ display: flex;
+ width: 100%;
+ height: 100vh;
+ margin: 0;
+ gap: 15px;
+ padding: 15px;
+ overflow: hidden;
+}
+
+/* 闈㈡澘閫氱敤鏍峰紡 - 缁熶竴鍐呰竟璺� 纭繚宸﹀彸瀵归綈 */
+.left-area,
+.right-area {
+ flex: 1;
+ width: 50%;
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ padding: 18px;
+ background: #ffffff;
+ border: 1px solid #e2e8f0;
+ border-radius: 15px;
+ box-shadow: 0 6px 16px rgba(149, 157, 165, 0.15);
+ transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+}
+
+/* 鎸夐挳+淇″彿 妯悜鎺掑垪瀹瑰櫒 - 鏍稿績甯冨眬 */
+.btn-signal-group {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ width: 100%;
+}
+.btn-group {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ flex-shrink: 0;
+}
+.signal-status {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ gap: 18px;
+ flex-shrink: 0;
+ padding: 0;
+}
+
+.left-top {
+ background: #f8fafc;
+ padding: 15px;
+ border-radius: 12px;
+ flex-shrink: 0;
+ width: 100%;
+}
+
+.left-bottom,
+.right-bottom {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ flex: 1;
+ overflow: hidden !important;
+}
+
+.right-top {
+ padding: 15px;
+ background: #f8fafc;
+ border-radius: 12px;
+ flex-shrink: 0;
+}
+
+/* 琛ㄥ崟琛屾牱寮� - 缁熶竴楂樺害鍜岄棿璺� 纭繚宸﹀彸瀵归綈 */
+.form-row {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-wrap: nowrap;
+ padding: 6px 10px;
+ border-radius: 8px;
+ transition: all 0.2s ease;
+ height: 48px;
+ line-height: 48px;
+ flex-shrink: 0;
+ width: 100%;
+}
+
+.form-row:hover {
+ background: #f8fafc;
+}
+
+.finished-product-row {
+ background: #eff6ff;
+ border-left: 4px solid #3b82f6;
+}
+
+.tooling-board-row {
+ background: #f0fdf4;
+ border-left: 4px solid #22c55e;
+}
+
+.part-item {
+ border-bottom: 1px solid #f1f5f9;
+ margin-bottom: 3px;
+}
+
+.part-item:last-child {
+ border-bottom: none;
+}
+
+/* 鏍囩鏍峰紡 - 缁熶竴瀹藉害 纭繚宸﹀彸瀵归綈 */
+.label {
+ width: 90px;
+ text-align: right;
+ color: #334155;
+ font-size: 15px;
+ font-weight: 600;
+ flex-shrink: 0;
+}
+
+.short-label {
+ width: 110px;
+ text-align: right;
+ color: #334155;
+ font-size: 15px;
+ font-weight: 600;
+ flex-shrink: 0;
+}
+
+/* 杈撳叆妗嗘牱寮� - 缁熶竴灏哄 纭繚宸﹀彸瀵归綈 */
+.input-box {
+ flex: 1;
+ min-width: 100px;
+ height: 42px;
+ padding: 0 15px;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ outline: none;
+ font-size: 15px;
+ transition: all 0.2s ease;
+ background-color: #ffffff;
+}
+
+.short-input {
+ width: 150px !important;
+ flex: none !important;
+}
+
+.input-box:focus {
+ border-color: #3b82f6;
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.12);
+}
+
+.input-box:disabled {
+ background-color: #f1f5f9;
+ color: #64748b;
+ cursor: not-allowed;
+}
+
+.input-box::placeholder {
+ color: #94a3b8;
+ font-size: 14px;
+}
+
+/* 鎸夐挳鏍峰紡 - 鍥哄畾瀹藉害 涓嶅彉 */
+.btn {
+ width: 120px;
+ height: 42px;
+ padding: 0 16px;
+ border: none;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 600;
+ transition: all 0.2s ease;
+ flex-shrink: 0;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ position: relative;
+ overflow: hidden;
+}
+
+.btn:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ transform: none !important;
+ box-shadow: none !important;
+}
+
+.btn::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
+ transition: all 0.5s ease;
+}
+
+.btn:hover::after {
+ left: 100%;
+}
+
+/* 鍥炬爣鏍峰紡 - 鍥炬爣鏀惧ぇ */
+.icon {
+ display: inline-block;
+ width: 18px;
+ height: 18px;
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+.icon-start {
+ 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='M8 5v14l11-7z'/%3E%3C/svg%3E");
+}
+
+.icon-stop {
+ 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 6h12v12H6z'/%3E%3C/svg%3E");
+}
+
+.icon-pause {
+ 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 19h4V5H6v14zm8-14v14h4V5h-4z'/%3E%3C/svg%3E");
+}
+
+.icon-resume {
+ 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='M11 5L6 9H2v6h4l5 4V5zm7 0v14c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2z'/%3E%3C/svg%3E");
+}
+
+.icon-clear {
+ 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='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E");
+}
+
+.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");
+}
+
+/* 鎸夐挳绫诲瀷鏍峰紡 - 涓嶅彉 */
+.start-btn {
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
+ color: #fff;
+}
+.start-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(16, 185, 129, 0.2);
+}
+
+.stop-btn {
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
+ color: #fff;
+}
+.stop-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(239, 68, 68, 0.2);
+}
+
+.pause-btn {
+ background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
+ color: #fff;
+}
+.pause-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(245, 158, 11, 0.2);
+}
+
+.resume-btn {
+ background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
+ color: #fff;
+}
+.resume-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(139, 92, 246, 0.2);
+}
+
+.clear-btn {
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
+ color: #fff;
+ padding: 0 12px;
+}
+.clear-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(239, 68, 68, 0.15);
+}
+
+.save-btn {
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
+ color: #fff;
+ padding: 0 12px;
+}
+.save-btn:hover:not(:disabled) {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(59, 130, 246, 0.15);
+}
+
+/* 淇″彿鐏牱寮� 閱掔洰鏀惧ぇ */
+.signal-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 5px;
+ min-width: 60px;
+}
+.signal-label {
+ font-size: 14px;
+ color: #334155;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 100%;
+ text-align: center;
+ font-weight: 600;
+}
+.signal-light {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
+ transition: all 0.3s ease;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.signal-light-inner {
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: white;
+ opacity: 0.9;
+ transition: all 0.3s ease;
+}
+.signal-active {
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
+ box-shadow: 0 0 18px rgba(16, 185, 129, 0.7);
+ animation: pulse 2s infinite;
+}
+.signal-inactive {
+ background: linear-gradient(135deg, #94a3b8 0%, #64748b 100%);
+}
+@keyframes pulse {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.8);
+ }
+ 70% {
+ box-shadow: 0 0 0 15px rgba(16, 185, 129, 0);
+ }
+ 100% {
+ box-shadow: 0 0 0 0 rgba(16, 185, 129, 0);
+ }
+}
+
+/* 鑷畾涔夊閫夋鏍峰紡 - 鏀惧ぇ 鐐瑰嚮鍖哄煙鏇村ぇ */
+.checkbox-container {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ color: #334155;
+ flex-shrink: 0;
+}
+.part-checkbox {
+ display: none;
+}
+.checkmark {
+ width: 22px;
+ height: 22px;
+ background-color: #f1f5f9;
+ border: 1px solid #cbd5e1;
+ border-radius: 4px;
+ transition: all 0.2s ease;
+ position: relative;
+}
+.part-checkbox:checked ~ .checkmark {
+ background-color: #3b82f6;
+ border-color: #3b82f6;
+}
+.checkmark:after {
+ content: "";
+ position: absolute;
+ display: none;
+ left: 7px;
+ top: 2px;
+ width: 6px;
+ height: 12px;
+ border: solid white;
+ border-width: 0 3px 3px 0;
+ transform: rotate(45deg);
+}
+.part-checkbox:checked ~ .checkmark:after {
+ display: block;
+}
+.checkbox-label {
+ font-size: 13px;
+ color: #475569;
+ width: 50px;
+}
+
+/* 鍝嶅簲寮忛�傞厤 */
+@media (max-width: 1200px) {
+ .container {
+ flex-direction: column;
+ height: auto;
+ }
+ .left-area,
+ .right-area {
+ width: 100%;
+ flex: none;
+ }
+ .btn-signal-group {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+ .signal-status {
+ width: 100%;
+ justify-content: flex-start;
+ }
+}
+
+@media (max-width: 768px) {
+ .form-row {
+ flex-direction: column;
+ align-items: flex-start;
+ height: auto;
+ line-height: normal;
+ }
+ .label,
+ .short-label {
+ width: 100%;
+ text-align: left;
+ margin-bottom: 6px;
+ }
+ .input-box {
+ width: 100%;
+ }
+ .short-input {
+ width: 100% !important;
+ }
+ .btn {
+ width: 100%;
+ margin-top: 6px;
+ }
+ .btn-group {
+ flex-direction: column;
+ gap: 10px;
+ width: 100%;
+ }
+}
+</style>
--
Gitblit v1.9.3