瀏覽代碼

货位选择优化

liuyanpeng 6 月之前
父節點
當前提交
e49a9fe298

+ 58 - 16
src/components/PositionSelector.vue

@@ -21,9 +21,7 @@
         <div v-if="loading" style="text-align: center; color: #969799; padding: 10px 0;">加载中...</div>
         <van-empty v-if="columns.length === 0 && !loading" description="暂无数据" />
       </div>
-      <div
-        style="padding: 10px 16px; border-top: 1px solid #ebedf0; display: flex; flex-direction: column; gap: 8px;"
-      >
+      <div style="padding: 10px 16px; border-top: 1px solid #ebedf0; display: flex; flex-direction: column; gap: 8px;">
         <van-button type="default" block :disabled="noMore || loading" @click="loadMore">
           {{ noMore ? '没有更多数据' : '加载更多' }}
         </van-button>
@@ -34,10 +32,11 @@
 </template>
 
 <script setup>
-import { showFailToast } from 'vant';
+import { showFailToast, showToast } from 'vant';
 import { ajaxApiGet } from '../common/utils';
 import { processException } from '../common/Common.js';
 import { ref, watch, computed, onMounted, defineProps, defineEmits, defineExpose } from 'vue';
+import { useRoute } from 'vue-router';
 
 const props = defineProps({
   show: {
@@ -65,6 +64,19 @@ const props = defineProps({
     type: Boolean,
     default: true,
   },
+  isDefault: {
+    type: Boolean,
+    default: false,
+  },
+  // 父组件 van-dialog 显示状态,用于控制何时执行默认选择逻辑
+  dialogShow: {
+    type: Boolean,
+    default: false,
+  },
+  type: {
+    type: String,
+    default: '',
+  },
 });
 
 const emit = defineEmits([
@@ -82,9 +94,12 @@ const loading = ref(false);
 const noMore = ref(false);
 const selectedId = ref(props.defaultSelectedId);
 const selectedItem = ref(null);
+const defaultApplied = ref(false);
+const route = useRoute();
+const warehouseId = ref(route.query.warehouseId || '');
 
 // 计算属性
-const title = computed(() =>{
+const title = computed(() => {
   const titleMap = {
     stockIn: {
       transfer: '选择中转区货位',
@@ -123,8 +138,10 @@ const apiUrl = computed(() => {
 // 监听props变化
 watch(() => props.show, newVal => {
   visible.value = newVal;
-  if (newVal && columns.value.length === 0) {
-    getPositionData();
+  if (newVal) {
+    if (columns.value.length === 0) {
+      getPositionData();
+    }
   }
 });
 
@@ -138,6 +155,13 @@ watch(() => props.defaultSelectedId, newVal => {
   selectedId.value = newVal;
 });
 
+// 当父级对话框显示时触发加载并应用默认选择逻辑(仅在 type 为 stockIn 时)
+watch(() => props.dialogShow, (newVal, oldVal) => {
+  if (props.type === 'stockIn' && newVal && newVal !== oldVal) {
+    getPositionData(true);
+  }
+});
+
 // 搜索
 const onSearch = () => {
   getPositionData(true);
@@ -156,14 +180,16 @@ const getPositionData = (isReset = true) => {
     currentPage.value = 1;
     columns.value = [];
     noMore.value = false;
+    // 重置默认选择已应用标记
+    defaultApplied.value = false;
   }
 
   loading.value = true;
   const start = (currentPage.value - 1) * props.pageSize;
   const length = props.pageSize;
   const filter = searchKey.value;
-
-  ajaxApiGet(`${apiUrl.value}?start=${start}&length=${length}&filter=${filter}`).then(
+  let url = apiUrl.value + '?start=' + start + '&length=' + length + '&filter=' + filter + '&warehouseId=' + warehouseId.value;
+  ajaxApiGet(url).then(
     success => {
       loading.value = false;
       const { errorCode, errorMessage, datas, total } = success;
@@ -179,8 +205,24 @@ const getPositionData = (isReset = true) => {
 
           columns.value = [...columns.value, ...newColumns];
           noMore.value = columns.value.length >= total;
+
+          // 如果需要默认加载且尚未应用默认值,则选中第一项并通知父组件
+          if (isReset && props.isDefault && !defaultApplied.value) {
+            const first = columns.value[0];
+            if (first) {
+              selectedId.value = first.value;
+              selectedItem.value = first;
+              emit('confirm', first);
+              defaultApplied.value = true;
+            }
+          }
         } else {
           noMore.value = true;
+          // 当需要默认选择但没有可用数据时,提示无空闲货位
+          if (isReset && props.isDefault && !defaultApplied.value) {
+            showToast('当前仓库暂无空闲货位');
+            defaultApplied.value = true;
+          }
         }
       } else {
         noMore.value = true;
@@ -223,10 +265,10 @@ const clearSelected = () => {
   selectedItem.value = null;
 };
 
-// 组件挂载时,如果show为true则加载数据
+// 组件挂载时:当 type 为 stockInPhoto 时,直接加载并应用默认逻辑
 onMounted(() => {
-  if (props.show) {
-    getPositionData();
+  if (props.type === 'stockInPhoto') {
+    getPositionData(true);
   }
 });
 
@@ -238,18 +280,18 @@ defineExpose({
 <style scoped>
 /* 使用深度选择器确保 van-search 样式不受影响 */
 :deep(.van-search) {
-    padding: 8px 12px;
+  padding: 8px 12px;
 }
 
 :deep(.van-cell) {
-    align-items: center;
+  align-items: center;
 }
 
 :deep(.van-radio) {
-    margin-right: 0;
+  margin-right: 0;
 }
 
 :deep(.van-button) {
-    margin-bottom: 8px;
+  margin-bottom: 8px;
 }
 </style>

+ 13 - 6
src/components/StockIn.vue

@@ -1,6 +1,6 @@
 <template>
   <van-nav-bar
-    title="入库" left-arrow left-text="返回" right-text="拍照" fixed placeholder @click-left="goBack()"
+    :title="title" left-arrow left-text="返回" right-text="拍照" fixed placeholder @click-left="goBack()"
     @click-right="goTakePhoto"
   />
   <van-search v-model="stockInSearch" placeholder="请输入搜索关键词" @search="searchStockIn" />
@@ -58,19 +58,20 @@
     :default-selected-id="formData.transferId" @confirm="onTransferPositionSelected"
   />
   <position-selector
-    ref="idlePositionSelector" v-model:show="isShowIdle" position-type="idle"
-    :default-selected-id="formData.idleId" @confirm="onIdlePositionSelected"
+    ref="idlePositionSelector" v-model:show="isShowIdle" position-type="idle" :is-default="true"
+    type="stockIn" :dialog-show="isShowStockIn" :default-selected-id="formData.idleId" @confirm="onIdlePositionSelected"
   />
 </template>
 
 <script setup>
 import { ref, onMounted } from 'vue';
-import { useRouter } from 'vue-router';
+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';
 
+const route = useRoute();
 const router = useRouter();
 
 const stockInSearch = ref('');
@@ -103,9 +104,12 @@ const formData = ref({
 const isShowStockIn = ref(false);
 const isShowTransfer = ref(false);
 const isShowIdle = ref(false);
+const warehouseId = ref(null);
+const warehouseName = ref(null);
+const title  = ref('');
 
 const goBack = () => {
-  router.push('/app-menus');
+  router.push('/warehouse-selector?page=stock-in&warehouseId=' + warehouseId.value);
 };
 
 // 搜索入库物料
@@ -275,9 +279,12 @@ const clearFormData = () => {
 
 // 拍照
 const goTakePhoto = () => {
-  router.push('/stock-in-photo');
+  router.push('/stock-in-photo?warehouseId=' + warehouseId.value + '&warehouseName=' + warehouseName.value);
 };
 onMounted(() => {
+  warehouseId.value = route.query.warehouseId || '';
+  warehouseName.value = route.query.warehouseName || '';
+  title.value = route.query.warehouseName ? '入库 - ' + route.query.warehouseName : '入库';
   loadStockInList();
 });
 

+ 27 - 6
src/components/StockInPhoto.vue

@@ -1,5 +1,8 @@
 <template>
-  <van-nav-bar title="拍照入库" left-arrow left-text="返回" fixed placeholder @click-left="goBack()" />
+  <van-nav-bar
+    :title="title" left-arrow left-text="返回" fixed placeholder right-text="返回菜单" @click-left="goBack()"
+    @click-right="goMenu"
+  />
   <van-image v-if="imageUrl" width="100%" height="100%" :src="imageUrl" />
   <div class="content">
     <div class="scan-btn">
@@ -41,21 +44,27 @@
     </van-form>
   </div>
   <div>
-    <position-selector ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="transfer" @confirm="onTransferPositionSelected" />
-    <position-selector ref="idlePositionSelector" v-model:show="isShowIdle" position-type="idle" @confirm="onIdlePositionSelected" />
+    <position-selector
+      ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="transfer"
+      @confirm="onTransferPositionSelected"
+    />
+    <position-selector
+      ref="idlePositionSelector" v-model:show="isShowIdle" position-type="idle" type="stockInPhoto"
+      :is-default="true" @confirm="onIdlePositionSelected"
+    />
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
-import { useRouter } from 'vue-router';
+import { ref, onMounted } 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';
 import { showSuccessToast, showFailToast, showConfirmDialog } from 'vant';
 import { showFullscreenLoading, hideFullscreenLoading } from '../common/loading';
 
-
+const route = useRoute();
 const router = useRouter();
 
 const imageUrl = ref('');
@@ -82,10 +91,22 @@ const stockData = ref({
   idleNo: '',
 });
 
+const warehouseId = ref('');
+const title  = ref('');
+
+onMounted(() => {
+  warehouseId.value = route.query.warehouseId || '';
+  title.value = route.query.warehouseName ? '入库拍照 - ' + route.query.warehouseName : '入库拍照';
+});
+
 const goBack = () => {
   router.back();
 };
 
+const goMenu = () => {
+  router.push('/app-menus');
+};
+
 const takePhoto = () => {
   fileInput.value.click();
 };

+ 18 - 7
src/components/StockOut.vue

@@ -1,6 +1,6 @@
 <template>
   <van-nav-bar
-    title="出库" left-arrow left-text="返回" right-text="拍照" fixed placeholder @click-left="goBack()"
+    :title="title" left-arrow left-text="返回" right-text="拍照" fixed placeholder @click-left="goBack()"
     @click-right="goTakePhoto"
   />
   <van-search v-model="stockOutSearch" placeholder="请输入搜索关键词" @search="searchStockOut" />
@@ -64,24 +64,25 @@
     </template>
   </van-dialog>
   <position-selector
-    ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="transfer"
+    ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="transfer" :warehouse-id="warehouseId"
     is-user="stockOut" :default-selected-id="formData.transferId" @confirm="onTransferPositionSelected"
   />
   <position-selector
     ref="usingPositionSelector" v-model:show="isShowUsing" position-type="using" is-user="stockOut"
-    :default-selected-id="formData.positionId"
+    :warehouse-id="warehouseId" :default-selected-id="formData.positionId"
     @confirm="onUsingPositionSelected"
   />
 </template>
 
 <script setup>
 import { ref, onMounted } from 'vue';
-import { useRouter } from 'vue-router';
+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';
 
+const route = useRoute();
 const router = useRouter();
 
 const stockOutSearch = ref('');
@@ -113,12 +114,22 @@ const formData = ref({
   outAll: true,
 });
 
+const warehouseId = ref('');
+const title  = ref('');
+const warehouseName = ref('');
+
+onMounted(() => { 
+  warehouseId.value = route.query.warehouseId || '';
+  warehouseName.value = route.query.warehouseName || '';
+  title.value = route.query.warehouseName ? '出库 - ' + route.query.warehouseName : '出库';
+});
+
 const isShowStockOut = ref(false);
 const isShowTransfer = ref(false);
 const isShowUsing = ref(false);
 
 const goBack = () => {
-  router.push('/app-menus');
+  router.push('/warehouse-selector?page=stock-out&warehouseId=' + warehouseId.value);
 };
 
 // 搜索出库物料
@@ -218,7 +229,7 @@ const getList = (page, pageSize) => {
   const start = (page - 1) * pageSize;
   const length = pageSize;
   const filter = stockOutSearch.value;
-  const url = `/api/StockOutResource/queryCurrentStockStockOut?start=${start}&length=${length}&filter=${filter}`;
+  const url = `/api/StockOutResource/queryCurrentStockStockOut?start=${start}&length=${length}&filter=${filter}&warehouseId=${warehouseId.value}`;
   return new Promise((resolve, reject) => {
     ajaxApiGet(url).then(
       success => {
@@ -318,7 +329,7 @@ const clearFormData = () => {
 
 // 拍照
 const goTakePhoto = () => {
-  router.push('/stock-out-photo');
+  router.push('/stock-out-photo?warehouseId=' + warehouseId.value + '&warehouseName=' + warehouseName.value);
 };
 onMounted(() => {
   loadStockOutList();

+ 23 - 12
src/components/StockOutBack.vue

@@ -1,13 +1,11 @@
 <template>
-  <van-nav-bar
-    title="待返回出库单" left-arrow left-text="返回" fixed placeholder @click-left="goBack()"
-  />
+  <van-nav-bar :title="title" left-arrow left-text="返回" fixed placeholder @click-left="goBack()" />
   <van-search v-model="stockBackSearch" placeholder="请输入搜索关键词" @search="searchStockBack" />
   <div class="content">
     <div>
       <van-list
-        v-model:loading="loading" :finished="finished" finished-text=""
-        :immediate-check="false" @load="loadStockOutBackList"
+        v-model:loading="loading" :finished="finished" finished-text="" :immediate-check="false"
+        @load="loadStockOutBackList"
       >
         <div v-for="(item, index) in stockBackList" :key="item.id" class="list-container">
           <van-form :scroll-to-error="true">
@@ -20,7 +18,7 @@
             <van-field v-model="item.inventoryType" name="inventoryType" label="规格型号:" readonly />
             <van-field v-model="item.quantity" name="quantity" label="数量:" readonly />
             <van-field v-model="item.batchNo" name="batchNo" label="批号:" readonly />
-            <van-field v-model="item.positionName" name="positionName" label="货位:" readonly />
+            <van-field v-model="item.positionName" name="positionName" label="货位:" readonly class="red-field" />
           </van-form>
         </div>
       </van-list>
@@ -31,11 +29,12 @@
 
 <script setup>
 import { ref, onMounted } from 'vue';
-import { useRouter } from 'vue-router';
+import { ajaxApiGet } from '../common/utils.js';
+import { useRouter, useRoute } from 'vue-router';
 import { processException } from '../common/Common.js';
-import { ajaxApiGet, ajaxApiPost } from '../common/utils.js';
 import { showFailToast, showSuccessToast, showConfirmDialog } from 'vant';
 
+const route = useRoute();
 const router = useRouter();
 
 const stockBackSearch = ref('');
@@ -48,8 +47,11 @@ const page = ref(1);
 const total = ref(0);
 const pageSize = ref(10);
 
+const warehouseId = ref(null);
+const title = ref('');
+
 const goBack = () => {
-  router.push('/app-menus');
+  router.push('/warehouse-selector?page=stock-out-back&warehouseId=' + warehouseId.value);
 };
 
 // 搜索返回物料
@@ -96,7 +98,7 @@ const loadStockOutBackList = async () => {
     }
   } catch (error) {
     finished.value = true;
-    if(error.responseText === '未查询出部分出库的出库单') return;
+    if (error.responseText === '未查询出部分出库的出库单') return;
     processException(error);
   } finally {
     loading.value = false;
@@ -108,7 +110,7 @@ const getList = (page, pageSize) => {
   const start = (page - 1) * pageSize;
   const length = pageSize;
   const filter = stockBackSearch.value;
-  const url = `/api/StockOutResource/queryReturnStockOut?start=${start}&length=${length}&filter=${filter}`;
+  const url = `/api/StockOutResource/queryReturnStockOut?start=${start}&length=${length}&filter=${filter}&warehouseId=${warehouseId.value}`;
   return new Promise((resolve, reject) => {
     ajaxApiGet(url).then(
       success => {
@@ -150,6 +152,8 @@ const submitStockBack = stockOutId => {
 };
 
 onMounted(() => {
+  warehouseId.value = route.query.warehouseId || '';
+  title.value = route.query.warehouseName ? '待返回出库单 - ' + route.query.warehouseName : '待返回出库单';
   loadStockOutBackList();
 });
 
@@ -181,4 +185,11 @@ onMounted(() => {
   align-items: center;
   margin-bottom: 10px;
 }
-</style>
+
+/* 货位字段值显示为红色 */
+.red-field :deep(.van-field__control) {
+  color: red;
+  font-weight: bold;
+  font-size: 22px;
+}
+</style>

+ 36 - 8
src/components/StockOutPhoto.vue

@@ -1,5 +1,5 @@
 <template>
-  <van-nav-bar title="拍照出库" left-arrow left-text="返回" fixed placeholder @click-left="goBack()" />
+  <van-nav-bar :title="title" left-arrow left-text="返回" fixed placeholder right-text="返回菜单" @click-left="goBack()" @click-right="goMenu" />
   <van-image v-if="imageUrl" width="100%" height="100%" :src="imageUrl" />
   <div class="content">
     <div class="scan-btn">
@@ -36,11 +36,11 @@
 
       <van-field
         v-model="stockData.transferName" is-link readonly name="transfer" label="中转区货位:"
-        placeholder="点击选择中转区货位" @click="isShowTransfer = true"
+        placeholder="点击选择中转区货位" @click="showTransferClick"
       />
       <van-field
         v-model="stockData.positionName" is-link readonly name="warehouse" label="出库货位:" placeholder="点击选择出库货位"
-        @click="isShowUsing = true"
+        @click="showUsingClick"
       />
       <div style="margin: 16px">
         <van-button round block type="primary" @click="submit">
@@ -51,26 +51,26 @@
   </div>
   <div>
     <position-selector
-      ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="transfer"
+      ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="transfer" :warehouse-id="warehouseId"
       is-user="stockOut" :default-selected-id="stockData.transferId" @confirm="onTransferPositionSelected"
     />
     <position-selector
       ref="usingPositionSelector" v-model:show="isShowUsing" position-type="using" is-user="stockOut"
-      :default-selected-id="stockData.positionId" @confirm="onUsingPositionSelected"
+      :warehouse-id="warehouseId" :default-selected-id="stockData.positionId" @confirm="onUsingPositionSelected"
     />
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
-import { useRouter } from 'vue-router';
+import { ref, onMounted } 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';
 import { showSuccessToast, showFailToast, showConfirmDialog } from 'vant';
 import { showFullscreenLoading, hideFullscreenLoading } from '../common/loading';
 
-
+const route = useRoute();
 const router = useRouter();
 
 const imageUrl = ref('');
@@ -101,10 +101,22 @@ const stockData = ref({
   outAll: true,
 });
 
+const warehouseId = ref('');
+const title  = ref('');
+
+onMounted(() => { 
+  warehouseId.value = route.query.warehouseId || '';
+  title.value = route.query.warehouseName ? '出库拍照 - ' + route.query.warehouseName : '出库拍照';
+});
+
 const goBack = () => {
   router.back();
 };
 
+const goMenu = () => {
+  router.push('/app-menus');
+};
+
 const takePhoto = () => {
   fileInput.value.click();
 };
@@ -119,6 +131,22 @@ const onFileChange = event => {
   photoFile.value = file;
 
 };
+
+const showTransferClick = () => {
+  if (!stockData.value.inventoryNo) {
+    showFailToast({ duration: 3000, message: '请先拍摄并识别图片' });
+    return;
+  }
+  isShowTransfer.value = true;
+};
+const showUsingClick = () => {
+  if (!stockData.value.inventoryNo) {
+    showFailToast({ duration: 3000, message: '请先拍摄并识别图片' });
+    return;
+  }
+  isShowUsing.value = true;
+};
+
 // 处理中转区货位选择结果
 const onTransferPositionSelected = item => {
   stockData.value.transferId = item.id;

+ 15 - 7
src/components/StockTransfer.vue

@@ -1,6 +1,6 @@
 <template>
   <van-nav-bar
-    title="调拨" left-arrow left-text="返回" right-text="拍照" fixed placeholder @click-left="goBack()"
+    :title="title" left-arrow left-text="返回" right-text="拍照" fixed placeholder @click-left="goBack()"
     @click-right="goTakePhoto"
   />
   <van-search v-model="stockTransferSearch" placeholder="请输入搜索关键词" @search="searchStockTransfer" />
@@ -56,23 +56,24 @@
     </template>
   </van-dialog>
   <position-selector
-    ref="currentPositionSelector" v-model:show="isShowCurrent" position-type="current"
+    ref="currentPositionSelector" v-model:show="isShowCurrent" position-type="current" :warehouse-id="warehouseId"
     is-user="transfer" :default-selected-id="formData.positionBeforeId" @confirm="currentPositionSelected"
   />
   <position-selector
-    ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="idle"
+    ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="idle" :warehouse-id="warehouseId"
     is-user="transfer" @confirm="onTransferPositionSelected"
   />
 </template>
 
 <script setup>
 import { ref, onMounted } from 'vue';
-import { useRouter } from 'vue-router';
+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';
 
+const route = useRoute();
 const router = useRouter();
 
 const stockTransferSearch = ref('');
@@ -103,12 +104,16 @@ const formData = ref({
   positionAfterName: '',
 });
 
+const warehouseId = ref(null);
+const title  = ref('');
+const warehouseName = ref('');
+
 const isShowStockTransfer = ref(false);
 const isShowCurrent = ref(false);
 const isShowTransfer = ref(false);
 
 const goBack = () => {
-  router.push('/app-menus');
+  router.push('/warehouse-selector?page=stock-transfer&warehouseId=' + warehouseId.value);
 };
 
 // 搜索调拨物料
@@ -203,7 +208,7 @@ const getList = (page, pageSize) => {
   const start = (page - 1) * pageSize;
   const length = pageSize;
   const filter = stockTransferSearch.value;
-  const url = `/api/StockOutResource/queryCurrentStockStockOut?start=${start}&length=${length}&filter=${filter}`;
+  const url = `/api/StockOutResource/queryCurrentStockStockOut?start=${start}&length=${length}&filter=${filter}&warehouseId=${warehouseId.value}`;
   return new Promise((resolve, reject) => {
     ajaxApiGet(url).then(
       success => {
@@ -301,9 +306,12 @@ const clearFormData = () => {
 
 // 拍照
 const goTakePhoto = () => {
-  router.push('/stock-transfer-photo');
+  router.push('/stock-transfer-photo?warehouseId=' + warehouseId.value + '&warehouseName=' + warehouseName.value);
 };
 onMounted(() => {
+  warehouseId.value = route.query.warehouseId || '';
+  warehouseName.value = route.query.warehouseName || '';
+  title.value = route.query.warehouseName ? '调拨 - ' + route.query.warehouseName : '调拨';
   loadTransferList();
 });
 

+ 35 - 7
src/components/StockTransferPhoto.vue

@@ -1,5 +1,5 @@
 <template>
-  <van-nav-bar title="拍照调拨" left-arrow left-text="返回" fixed placeholder @click-left="goBack()" />
+  <van-nav-bar :title="title" left-arrow left-text="返回" fixed placeholder right-text="返回菜单" @click-left="goBack()" @click-right="goMenu" />
   <van-image v-if="imageUrl" width="100%" height="100%" :src="imageUrl" />
   <div class="content">
     <div class="scan-btn">
@@ -27,11 +27,11 @@
 
       <van-field
         v-model="stockData.positionBeforeName" is-link readonly name="warehouse" label="调拨前货位:"
-        placeholder="点击选择调拨前货位" :default-selected-id="stockData.positionBeforeId" @click="isShowCurrent = true"
+        placeholder="点击选择调拨前货位" :default-selected-id="stockData.positionBeforeId" @click="showCurrentClick"
       />
       <van-field
         v-model="stockData.positionAfterName" is-link readonly name="warehouse" label="调拨后货位:"
-        placeholder="点击选择调拨后货位" @click="isShowTransfer = true"
+        placeholder="点击选择调拨后货位" @click="showTransferClick"
       />
 
       <div style="margin: 16px">
@@ -43,19 +43,19 @@
   </div>
   <div>
     <position-selector
-      ref="currentPositionSelector" v-model:show="isShowCurrent" position-type="current"
+      ref="currentPositionSelector" v-model:show="isShowCurrent" position-type="current" :warehouse-id="warehouseId"
       is-user="transfer" :default-selected-id="stockData.positionBeforeId" @confirm="currentPositionSelected"
     />
     <position-selector
-      ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="idle"
+      ref="transferPositionSelector" v-model:show="isShowTransfer" position-type="idle" :warehouse-id="warehouseId"
       is-user="transfer" @confirm="onTransferPositionSelected"
     />
   </div>
 </template>
 
 <script setup>
-import { ref } from 'vue';
-import { useRouter } from 'vue-router';
+import { ref, onMounted } 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';
@@ -63,6 +63,7 @@ import { showSuccessToast, showFailToast, showConfirmDialog } from 'vant';
 import { showFullscreenLoading, hideFullscreenLoading } from '../common/loading';
 
 
+const route = useRoute();
 const router = useRouter();
 
 const imageUrl = ref('');
@@ -92,10 +93,22 @@ const stockData = ref({
   positionAfterName: '',
 });
 
+const warehouseId = ref(null);
+const title = ref('');
+
+onMounted(() => {
+  warehouseId.value = route.query.warehouseId || '';
+  title.value = route.query.warehouseName ? '调拨拍照 - ' + route.query.warehouseName : '调拨拍照';
+});
+
 const goBack = () => {
   router.back();
 };
 
+const goMenu = () => {
+  router.push('/app-menus');
+};
+
 const takePhoto = () => {
   fileInput.value.click();
 };
@@ -111,6 +124,21 @@ const onFileChange = event => {
 
 };
 
+const showCurrentClick = () => {
+  if (!stockData.value.inventoryNo) {
+    showFailToast({ duration: 3000, message: '请先拍摄并识别图片' });
+    return;
+  }
+  isShowCurrent.value = true;
+};
+const showTransferClick = () => {
+  if (!stockData.value.inventoryNo) {
+    showFailToast({ duration: 3000, message: '请先拍摄并识别图片' });
+    return;
+  }
+  isShowTransfer.value = true;
+};
+
 // 处理调拨前货位选择结果
 const currentPositionSelected = item => {
   getTransferInfo(item);

+ 171 - 0
src/components/WarehouseSelector.vue

@@ -0,0 +1,171 @@
+<template>
+  <van-nav-bar :title="title" left-arrow fixed placeholder left-text="返回" @click-left="goBack" />
+
+  <div class="warehouse-selector">
+    <van-search 
+      v-model="searchValue" 
+      placeholder="请输入仓库名称" 
+      shape="round" 
+      @search="onSearch" 
+      @clear="onSearch"
+    />
+    
+    <div class="warehouse-cards">
+      <div 
+        v-for="warehouse in columns" 
+        :key="warehouse.id"
+        class="warehouse-card"
+        :class="{ selected: isSelected(warehouse.id) }"
+        @click="selectWarehouse(warehouse)"
+      >
+        <div class="warehouse-name">{{ warehouse.name }}</div>
+        <div class="warehouse-no">{{ warehouse.no }}</div>
+      </div>
+      
+      <div v-if="columns.length === 0" class="no-data">
+        暂无仓库数据
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { showFailToast } from 'vant';
+import { ajaxApiGet } from '../common/utils.js';
+import { processException } from '../common/Common.js';
+
+export default {
+  name: 'SelectWarehouse',
+  data() {
+    return {
+      columns: [],
+      searchValue: '',
+      selectedWarehouse: null,
+      page: '',
+      title: '',
+      warehouseId: '',
+    };
+  },
+
+  mounted() {
+    this.getAllWarehouse();
+    this.page = this.$route.query.page;
+    this.warehouseId = this.$route.query.warehouseId;
+    if(this.page === 'stock-in') {
+      this.title = '入库-仓库选择';
+    } else if(this.page === 'stock-out') {
+      this.title = '出库-仓库选择';
+    } else if(this.page === 'stock-transfer') {
+      this.title = '调拨-仓库选择';
+    } else if(this.page === 'stock-out-back') {
+      this.title = '待返回出库-仓库选择';
+    }
+  },
+  
+  methods: {
+    goBack() {
+      this.$router.push('/app-menus');
+    },
+    selectWarehouse(warehouse) {
+      this.selectedWarehouse = warehouse;
+      console.log(warehouse);
+ 
+      this.$router.push({
+        path: this.page,
+        query: {
+          warehouseId: warehouse.id,
+          warehouseName: warehouse.name,
+        },
+      });
+    },
+    
+    isSelected(id) {
+      return this.warehouseId && this.warehouseId == id;
+    },
+
+    // 搜索处理函数
+    onSearch() {
+      this.getAllWarehouse(this.searchValue);
+    },
+
+    getAllWarehouse(name = '') {
+      const url = `/api/WarehouseResource/queryByCondition?name=${name}`;
+      ajaxApiGet(url).then(res => {
+        if (res.errorCode === 0) {
+          this.columns = res.datas.map(item => ({
+            id: item.id,
+            name: item.name,
+            no: item.no,
+          }));
+        } else {
+          showFailToast(res.errorMessage);
+        }
+      }).catch(error => {
+        processException(error);
+      });
+    },
+
+    // 提供给父组件调用的方法,用于清空选择
+    clearSelected() {
+      this.selectedWarehouse = null;
+    },
+    
+    // 获取当前选中的仓库ID
+    getSelectedValue() {
+      return this.selectedWarehouse ? this.selectedWarehouse.id : null;
+    },
+  },
+};
+</script>
+
+<style scoped>
+.warehouse-selector {
+  width: 100%;
+}
+
+.warehouse-cards {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
+  gap: 10px;
+  padding: 10px;
+}
+
+.warehouse-card {
+  border: 1px solid #ebedf0;
+  border-radius: 8px;
+  padding: 24px 8px;
+  text-align: center;
+  cursor: pointer;
+  transition: all 0.3s;
+  background-color: #fff;
+}
+
+.warehouse-card:hover {
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.warehouse-card.selected {
+  background-color: #1989fa;
+  color: white;
+}
+
+.warehouse-name {
+  font-size: 14px;
+  font-weight: bold;
+  margin-bottom: 5px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.warehouse-no {
+  font-size: 12px;
+  opacity: 0.8;
+}
+
+.no-data {
+  text-align: center;
+  padding: 20px;
+  color: #969799;
+  grid-column: 1 / -1;
+}
+</style>

+ 8 - 4
src/menu/AppMenus.vue

@@ -3,7 +3,7 @@
 
   <div class="menu-page">
     <van-grid :column-num="2" :border="false" clickable>
-      <van-grid-item to="/stock-in" class="menu-item">
+      <van-grid-item class="menu-item" @click="toPage('stock-in')">
         <template #icon>
           <van-icon name="home-o" class="menu-icon" />
         </template>
@@ -13,7 +13,7 @@
         </template>
       </van-grid-item>
 
-      <van-grid-item to="/stock-out" class="menu-item">
+      <van-grid-item class="menu-item" @click="toPage('stock-out')">
         <template #icon>
           <van-icon name="logistics" class="menu-icon" />
         </template>
@@ -23,7 +23,7 @@
         </template>
       </van-grid-item>
 
-      <van-grid-item to="/stock-transfer" class="menu-item">
+      <van-grid-item class="menu-item" @click="toPage('stock-transfer')">
         <template #icon>
           <van-icon name="exchange" class="menu-icon" />
         </template>
@@ -33,7 +33,7 @@
         </template>
       </van-grid-item>
 
-      <van-grid-item to="/stock-out-back" class="menu-item">
+      <van-grid-item class="menu-item" @click="toPage('stock-out-back')">
         <template #icon>
           <van-icon name="revoke" class="menu-icon" />
         </template>
@@ -56,6 +56,10 @@ const logout = () => {
   router.push('/');
 };
 
+const toPage = page => {
+  router.push('/warehouse-selector?page=' + page);
+};
+
 </script>
 
 <style scoped>

+ 4 - 0
src/router/router.js

@@ -6,6 +6,9 @@ const Login = () => import('../menu/UserNameLogin.vue')
 // 菜单
 const AppMenus = () => import('../menu/AppMenus.vue')
 
+// 仓库选择
+const WarehouseSelector = () => import('../components/WarehouseSelector.vue')
+
 // 入库
 const StockIn = () => import('../components/StockIn.vue')
 
@@ -32,6 +35,7 @@ export default [
   { path: '/', redirect: '/login', meta: { requiresAuth: false }, },
   { path: '/login', component: Login, meta: { requiresAuth: false }, },
   { path: '/app-menus', component: AppMenus, meta: { requiresAuth: true }, },
+  { path: '/warehouse-selector', component: WarehouseSelector, meta: { requiresAuth: true }, },
   { path: '/stock-in', component: StockIn, meta: { requiresAuth: true }, },
   { path: '/stock-in-photo', component: StockInPhoto, meta: { requiresAuth: true }, },
   { path: '/stock-out', component: StockOut, meta: { requiresAuth: true }, },