فهرست منبع

修改选择货位键盘
弹出是否立即送货

wangzhengguang 3 ماه پیش
والد
کامیت
96e9026885

+ 180 - 1
src/components/PositionSelector.vue

@@ -7,7 +7,23 @@
         <div style="font-size: 16px; font-weight: 500;">{{ title }}</div>
         <van-icon name="cross" @click="close" />
       </div>
-      <van-search v-model="searchKey" :placeholder="searchPlaceholder" @search="onSearch" @input="onInputChange" />
+      <div style="padding: 8px 12px;">
+        <div style="position: relative;">
+          <input
+            v-model="searchKey"
+            type="text"
+            :placeholder="searchPlaceholder"
+            style="width: 100%; padding: 8px 12px; border: 1px solid #ebedf0; border-radius: 4px; font-size: 14px;"
+            readonly
+            @click="showKeyboard = true"
+          />
+          <van-icon
+            name="search"
+            style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); color: #969799;"
+            @click="onSearch"
+          />
+        </div>
+      </div>
       <div style="flex: 1; overflow-y: auto;">
         <van-radio-group v-model="selectedId">
           <van-cell-group>
@@ -28,6 +44,122 @@
         <van-button type="primary" block @click="confirm">确认</van-button>
       </div>
     </div>
+
+    <!-- 自定义键盘 -->
+    <van-popup v-model:show="showKeyboard" position="top" style="height: 300px;">
+      <div style="display: flex; flex-direction: column; height: 100%;">
+        <div style="display: flex; justify-content: space-between; align-items: center; padding: 10px 16px; border-bottom: 1px solid #ebedf0;">
+          <div style="font-size: 16px; font-weight: 500;">输入货位编号</div>
+          <van-icon name="cross" @click="showKeyboard = false" />
+        </div>
+        <div style="flex: 1; display: flex; flex-direction: column; padding: 10px; overflow: hidden;">
+          <!-- 字母键盘 -->
+          <!-- 标准手机键盘布局 -->
+          <div v-if="keyboardMode === 'letters'" style="display: flex; flex-direction: column; gap: 6px; height: 100%;">
+            <!-- 第1行:10个字母 -->
+            <div style="display: flex; gap: 2px; flex: 1;">
+              <button
+                v-for="char in letters[0]"
+                :key="char"
+                style="flex: 1; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #fff; font-size: 14px; text-align: center; min-width: 0;"
+                @click="addChar(char)"
+              >
+                {{ char }}
+              </button>
+            </div>
+
+            <!-- 第2行:9个字母 -->
+            <div style="display: flex; gap: 2px; flex: 1; padding-left: 5%; padding-right: 5%;">
+              <button
+                v-for="char in letters[1]"
+                :key="char"
+                style="flex: 1; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #fff; font-size: 14px; text-align: center; min-width: 0;"
+                @click="addChar(char)"
+              >
+                {{ char }}
+              </button>
+            </div>
+
+            <!-- 第3行:7个字母 + 删除键 -->
+            <div style="display: flex; gap: 2px; flex: 1;">
+              <button
+                v-for="char in letters[2]"
+                :key="char"
+                style="flex: 1; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #fff; font-size: 14px; text-align: center; min-width: 0;"
+                @click="addChar(char)"
+              >
+                {{ char }}
+              </button>
+              <button
+                style="flex: 2; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #f5f5f5; font-size: 12px; text-align: center;"
+                @click="deleteChar"
+              >
+                删除
+              </button>
+            </div>
+
+            <!-- 功能键区 -->
+            <div style="display: flex; gap: 2px; flex: 1;">
+              <button
+                style="flex: 2; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #f5f5f5; font-size: 12px;"
+                @click="clearInput"
+              >
+                清空
+              </button>
+              <button
+                style="flex: 3; padding: 8px 4px; border: 1px solid #1989fa; border-radius: 4px; background: #1989fa; color: #fff; font-size: 12px;"
+                @click="keyboardMode = 'numbers'"
+              >
+                123
+              </button>
+              <button
+                style="flex: 3; padding: 8px 4px; border: 1px solid #1989fa; border-radius: 4px; background: #1989fa; color: #fff; font-size: 12px;"
+                @click="confirmInput"
+              >
+                确认
+              </button>
+            </div>
+          </div>
+
+          <!-- 数字键盘 -->
+          <div v-else style="display: flex; gap: 6px; height: 100%;">
+            <!-- 数字区域 - 添加 flex: 1 确保与右侧等高 -->
+            <div style="flex: 4 1 0; display: flex; flex-direction: column; gap: 6px;">
+              <!-- 每行数字也需要填满高度 -->
+              <div
+                v-for="(row, rowIndex) in numbers" :key="rowIndex"
+                style="display: flex; gap: 4px; flex: 1;"
+              >
+                <button
+                  v-for="num in row"
+                  :key="num"
+                  style="flex: 1; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #fff; font-size: 14px; text-align: center;"
+                  @click="addChar(num)"
+                >
+                  {{ num }}
+                </button>
+              </div>
+            </div>
+            <!-- 功能键区域 -->
+            <div style="flex: 1; display: flex; flex-direction: column; gap: 6px;">
+              <button
+                v-for="(btn, index) in ['删除', '清空', 'ABC', '确认']"
+                :key="index"
+                style="flex: 1; padding: 8px 4px; border: 1px solid #ebedf0; border-radius: 4px; background: #fff; font-size: 12px; text-align: center;"
+                :style="{
+                  backgroundColor: index >= 2 ? '#1989fa' : '#f5f5f5',
+                  borderColor: index >= 2 ? '#1989fa' : '#ebedf0',
+                  color: index >= 2 ? '#fff' : '#333'
+                }"
+                @click="index === 0 ? deleteChar() : index === 1 ? clearInput() : index === 2 ? keyboardMode = 'letters' : confirmInput()"
+              >
+                {{ btn }}
+              </button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </van-popup>
   </van-popup>
 </template>
 
@@ -97,6 +229,21 @@ const selectedItem = ref(null);
 const defaultApplied = ref(false);
 const route = useRoute();
 const warehouseId = ref(route.query.warehouseId || '');
+const showKeyboard = ref(false);
+
+// 自定义键盘数据
+const keyboardMode = ref('letters'); // 'letters' 或 'numbers'
+const letters = ref([
+  ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
+  ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
+  ['Z', 'X', 'C', 'V', 'B', 'N', 'M'],
+]);
+const numbers = ref([
+  ['1', '2', '3'],
+  ['4', '5', '6'],
+  ['7', '8', '9'],
+  ['-', '0'],
+]);
 
 // 计算属性
 const title = computed(() => {
@@ -266,6 +413,7 @@ const confirm = () => {
 // 关闭弹窗
 const close = () => {
   visible.value = false;
+  showKeyboard.value = false;
   emit('close');
 };
 
@@ -275,6 +423,36 @@ const clearSelected = () => {
   selectedItem.value = null;
 };
 
+// 自定义键盘方法
+let keyboardTimer = null;
+
+const addChar = char => {
+  searchKey.value += char;
+  // 添加防抖自动查询
+  clearTimeout(keyboardTimer);
+  keyboardTimer = setTimeout(() => {
+    onSearch();
+  }, 500);
+};
+
+const deleteChar = () => {
+  searchKey.value = searchKey.value.slice(0, -1);
+  // 添加防抖自动查询
+  clearTimeout(keyboardTimer);
+  keyboardTimer = setTimeout(() => {
+    onSearch();
+  }, 500);
+};
+
+const clearInput = () => {
+  searchKey.value = '';
+};
+
+const confirmInput = () => {
+  showKeyboard.value = false;
+  onSearch();
+};
+
 // 组件挂载时:当 type 为 stockInPhoto 时,直接加载并应用默认逻辑
 onMounted(() => {
   if (props.type === 'stockInPhoto') {
@@ -285,6 +463,7 @@ onMounted(() => {
 // 在组件卸载时清除定时器(避免内存泄漏)
 onUnmounted(() => {
   clearTimeout(timer);
+  clearTimeout(keyboardTimer);
 });
 
 defineExpose({

+ 82 - 1
src/components/StockIn.vue

@@ -81,13 +81,16 @@
 </template>
 
 <script setup>
-import { ref, onMounted } from 'vue';
+import {ref, onMounted, onUnmounted} from 'vue';
 import { useRouter, useRoute } from 'vue-router';
 import PositionSelector from './PositionSelector.vue';
 import { processException } from '../common/Common.js';
 import { ajaxApiGet, ajaxApiPost } from '../common/utils.js';
 import { showFailToast, showSuccessToast, showConfirmDialog } from 'vant';
 
+// WebSocket实例
+const ws = ref(null);
+
 const route = useRoute();
 const router = useRouter();
 
@@ -141,6 +144,48 @@ const goBack = () => {
   router.push('/warehouse-selector?page=stock-in&warehouseId=' + warehouseId.value);
 };
 
+onUnmounted(() => {
+  // 关闭WebSocket连接
+  if (ws.value) {
+    ws.value.close();
+  }
+});
+
+// 初始化WebSocket连接
+const initWebSocket = () => {
+  const wsUrl = 'ws://127.0.0.1:10023';
+  ws.value = new WebSocket(wsUrl);
+
+  ws.value.onopen = () => {
+    console.log('WebSocket连接已建立');
+  };
+
+  ws.value.onmessage = event => {
+    handleWebSocketMessage(event);
+  };
+
+  ws.value.onerror = error => {
+    console.error('WebSocket错误:', error);
+  };
+
+  ws.value.onclose = () => {
+    console.log('WebSocket连接已关闭');
+  };
+};
+
+// 处理WebSocket消息
+const handleWebSocketMessage = event => {
+  try {
+    // 解析接收到的JSON数据
+    const data = JSON.parse(event.data);
+    console.log('接收到WebSocket数据:', data);
+
+  } catch (error) {
+    console.error('解析WebSocket消息失败:', error);
+    showFailToast('解析数据失败,请检查数据格式');
+  }
+};
+
 let timer = null;
 
 // 搜索入库物料
@@ -307,6 +352,23 @@ const submitStockIn = () => {
         clearFormData();
         searchStockInNotDebounce(filter);
         showSuccessToast('入库成功');
+
+        // 处理任务ID,弹出是否立刻运送的对话框
+        if (success.data) {
+          const taskId = success.data;
+          showConfirmDialog({
+            title: '是否立刻运送?',
+            message: '入库成功,是否立即执行运送任务?',
+          })
+            .then(() => {
+              // 点击确认,调用executeTaskById方法
+              executeTaskById(taskId);
+            })
+            .catch(() => {
+              // 点击取消,关闭对话框,任务ID清除
+              console.log('取消运送');
+            });
+        }
       } else {
         showFailToast(success.errorMessage);
       }
@@ -317,6 +379,23 @@ const submitStockIn = () => {
   );
 };
 
+// 执行任务方法
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 
 // 取消入库
 const cancelStockIn = () => {
@@ -358,6 +437,8 @@ onMounted(() => {
   title.value = route.query.warehouseName ? '入库 - ' + route.query.warehouseName : '入库';
   loadStockInList();
   getCarrierTypeList();
+  // 建立WebSocket连接
+  initWebSocket();
 });
 
 </script>

+ 33 - 0
src/components/StockInScan.vue

@@ -291,6 +291,22 @@ const submitStockIn = () => {
       if (success.errorCode === 0) {
         showSuccessToast('入库成功');
         clearFormData();
+        // 处理任务ID,弹出是否立刻运送的对话框
+        if (success.data) {
+          const taskId = success.data;
+          showConfirmDialog({
+            title: '是否立刻运送?',
+            message: '入库成功,是否立即执行运送任务?',
+          })
+            .then(() => {
+              // 点击确认,调用executeTaskById方法
+              executeTaskById(taskId);
+            })
+            .catch(() => {
+              // 点击取消,关闭对话框,任务ID清除
+              console.log('取消运送');
+            });
+        }
       } else {
         showFailToast(success.errorMessage);
       }
@@ -301,6 +317,23 @@ const submitStockIn = () => {
   );
 };
 
+// 执行任务Api
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 const getCarrierTypeList = () => {
   const url = `/api/CarrierTypeResource/queryAllType?warehouseId=${warehouseId.value}`;
   ajaxApiGet(url).then(

+ 33 - 0
src/components/StockOut.vue

@@ -286,6 +286,22 @@ const submitStockOut = () => {
         clearFormData();
         serchStockOutNotDebounce(filter);
         showSuccessToast('出库成功');
+        // 处理任务ID,弹出是否立刻运送的对话框
+        if (success.data) {
+          const taskId = success.data;
+          showConfirmDialog({
+            title: '是否立刻运送?',
+            message: '出库成功,是否立即执行运送任务?',
+          })
+            .then(() => {
+              // 点击确认,调用executeTaskById方法
+              executeTaskById(taskId);
+            })
+            .catch(() => {
+              // 点击取消,关闭对话框,任务ID清除
+              console.log('取消运送');
+            });
+        }
       } else {
         showFailToast(success.errorMessage);
       }
@@ -296,6 +312,23 @@ const submitStockOut = () => {
   );
 };
 
+// 执行任务方法
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 // 根据货位、物料、批号查询库存
 const getStockOutInfo = info => {
   const positionId = info.id;

+ 17 - 0
src/components/StockOutBack.vue

@@ -164,6 +164,23 @@ const submitStockBack = stockOutId => {
   );
 };
 
+// 执行任务方法
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 onMounted(() => {
   warehouseId.value = route.query.warehouseId || '';
   title.value = route.query.warehouseName ? '待返回出库单 - ' + route.query.warehouseName : '待返回出库单';

+ 33 - 0
src/components/StockOutScan.vue

@@ -276,6 +276,22 @@ const submitStockOut = () => {
       if (success.errorCode === 0) {
         showSuccessToast('出库成功');
         clearFormData();
+        // 处理任务ID,弹出是否立刻运送的对话框
+        if (success.data) {
+          const taskId = success.data;
+          showConfirmDialog({
+            title: '是否立刻运送?',
+            message: '出库成功,是否立即执行运送任务?',
+          })
+            .then(() => {
+              // 点击确认,调用executeTaskById方法
+              executeTaskById(taskId);
+            })
+            .catch(() => {
+              // 点击取消,关闭对话框,任务ID清除
+              console.log('取消运送');
+            });
+        }
       } else {
         showFailToast(success.errorMessage);
       }
@@ -286,6 +302,23 @@ const submitStockOut = () => {
   );
 };
 
+// 执行任务方法
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 // 根据货位、物料、批号查询库存
 const getStockOutInfo = info => {
   const positionId = info.id;

+ 33 - 0
src/components/StockTransfer.vue

@@ -260,6 +260,22 @@ const submitTransfer = () => {
         clearFormData();
         searchStockTransferNotDebounce(filter);
         showSuccessToast('调拨成功');
+        // 处理任务ID,弹出是否立刻运送的对话框
+        if (success.data) {
+          const taskId = success.data;
+          showConfirmDialog({
+            title: '是否立刻运送?',
+            message: '调拨成功,是否立即执行运送任务?',
+          })
+            .then(() => {
+              // 点击确认,调用executeTaskById方法
+              executeTaskById(taskId);
+            })
+            .catch(() => {
+              // 点击取消,关闭对话框,任务ID清除
+              console.log('取消运送');
+            });
+        }
       } else {
         showFailToast(success.errorMessage);
       }
@@ -270,6 +286,23 @@ const submitTransfer = () => {
   );
 };
 
+// 执行任务方法
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 // 根据货位、物料、批号查询库存
 const getTransferInfo = info => {
   const positionId = info.id;

+ 33 - 0
src/components/StockTransferScan.vue

@@ -266,6 +266,22 @@ const submitTransfer = () => {
       if (success.errorCode === 0) {
         showSuccessToast('调拨成功');
         clearFormData();
+        // 处理任务ID,弹出是否立刻运送的对话框
+        if (success.data) {
+          const taskId = success.data;
+          showConfirmDialog({
+            title: '是否立刻运送?',
+            message: '调拨成功,是否立即执行运送任务?',
+          })
+            .then(() => {
+              // 点击确认,调用executeTaskById方法
+              executeTaskById(taskId);
+            })
+            .catch(() => {
+              // 点击取消,关闭对话框,任务ID清除
+              console.log('取消运送');
+            });
+        }
       } else {
         showFailToast(success.errorMessage);
       }
@@ -276,6 +292,23 @@ const submitTransfer = () => {
   );
 };
 
+// 执行任务方法
+const executeTaskById = id => {
+  const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
+  return ajaxApiGet(url).then(
+    success => {
+      const { errorCode, errorMessage } = success;
+      if (errorCode !== 0) {
+        return Promise.reject(errorMessage);
+      }
+    },
+    error => {
+      processException(error);
+      return Promise.reject(error);
+    },
+  );
+};
+
 // 根据货位、物料、批号查询库存
 const getTransferInfo = info => {
   const positionId = info.id;