瀏覽代碼

wms操作

haveyou 1 年之前
父節點
當前提交
2f669ab5f4

+ 31 - 0
pages.json

@@ -110,6 +110,7 @@
 			}, {
 				"path": "wms/bad-in",
 				"style": {
+					"navigationStyle": "custom",
 					"navigationBarTitleText": "不良入库"
 				}
 			}, {
@@ -117,6 +118,11 @@
 				"style": {
 					"navigationBarTitleText": "不良出库"
 				}
+			}, {
+				"path": "wms/bad-out-order",
+				"style": {
+					"navigationBarTitleText": "不良出库"
+				}
 			}, {
 				"path": "wms/bad-off",
 				"style": {
@@ -132,9 +138,20 @@
 				"style": {
 					"navigationBarTitleText": "库位订单"
 				}
+			}, {
+				"path": "wms/location-select",
+				"style": {
+					"navigationBarTitleText": "库位选择"
+				}
+			}, {
+				"path": "wms/warehouse-select",
+				"style": {
+					"navigationBarTitleText": "仓库选择"
+				}
 			}, {
 				"path": "wms/speedy-check",
 				"style": {
+					"navigationStyle": "custom",
 					"navigationBarTitleText": "快速盘点"
 				}
 			}, {
@@ -163,6 +180,20 @@
 				"style": {
 					"navigationBarTitleText": "物流详情"
 				}
+			},
+			{
+				"path": "wms/task-detail",
+				"style": {
+					"navigationStyle": "custom",
+					"navigationBarTitleText": "下架任务"
+				}
+			},
+			{
+				"path": "wms/speedy-check-add",
+				"style": {
+					"navigationStyle": "custom",
+					"navigationBarTitleText": "选择商品"
+				}
 			}
 		]
 	}, {

+ 75 - 2
pages/index/entry/book-weight.vue

@@ -1,3 +1,76 @@
 <template>
-	<view>1</view>
-</template>
+	<view class="common-page">
+		<u-form :model="form" :rules="rules" ref="formRef" labelWidth="80px" errorType="toast">
+			<u-form-item label="重量(克)" prop="weight" required>
+				<u-input v-model="form.weight" placeholder="请输入数值" clearable />
+			</u-form-item>
+			<u-form-item label="ISBN" prop="isbn" required>
+				<u-input v-model="form.isbn" placeholder="请输入编码" clearable />
+			</u-form-item>
+		</u-form>
+
+		<view class="fixed-bottom">
+			<u-button size="large" type="warning" text="扫码" @click="handleScan" />
+			<u-button size="large" type="success" text="提交" @click="submitForm" />
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		ref
+	} from 'vue';
+
+	export default {
+		setup() {
+			const form = ref({
+				weight: '',
+				isbn: ''
+			});
+
+			const rules = {
+				weight: [{
+						required: true,
+						message: '请输入重量',
+						trigger: 'blur'
+					},
+					{
+						type: 'number',
+						message: '重量必须是数字',
+						trigger: 'blur'
+					}
+				],
+				isbn: [{
+					required: true,
+					message: '请输入ISBN',
+					trigger: 'blur'
+				}]
+			};
+
+			function handleScan() {
+
+			}
+
+			const formRef = ref(null);
+
+			const submitForm = () => {
+				formRef.value.validate((valid) => {
+					if (valid) {
+						// 提交表单
+						console.log('表单验证成功', form.value);
+					} else {
+						console.log('表单验证失败');
+						return false;
+					}
+				});
+			};
+
+			return {
+				form,
+				rules,
+				formRef,
+				submitForm
+			};
+		}
+	};
+</script>

+ 246 - 2
pages/index/wms/bad-in.vue

@@ -1,3 +1,247 @@
 <template>
-	<view>1</view>
-</template>
+    <view class="common-page" style="padding: 0;">
+        <!-- 顶部导航栏 -->
+        <view class="header">
+            <u-navbar title="不良入库" :border="false" fixed safe-area-inset-top>
+                <template #left>
+                    <u-icon name="arrow-left" color="#333333" size="20" @click="goBack"></u-icon>
+                </template>
+                <template #right>
+                    <u-text type="primary" text="提交" @click="onSubmit"></u-text>
+                </template>
+            </u-navbar>
+        </view>
+
+        <!-- 主要内容区域 -->
+        <view class="content">
+            <!-- 订单基本信息 -->
+            <view class="info-section">
+                <u-form :model="formData" ref="formRef" label-width="70px">
+                    <u-form-item label="订单总数" required>
+                        <u-input v-model="formData.totalOrders" disabled />
+                    </u-form-item>
+                    <u-form-item label="仓库" required>
+                        <u-input v-model="formData.warehouse" @click="selectWarehouse" />
+                    </u-form-item>
+                    <u-form-item label="库位" required>
+                        <u-input v-model="formData.location" @click="selectLocation" />
+                    </u-form-item>
+                </u-form>
+            </view>
+
+            <!-- 订单列表 -->
+            <view class="order-list">
+                <bad-item v-for="(order, index) in orders" :key="index" :data="order" @delete="deleteOrder(index)"
+                    @edit="editOrder(index)"></bad-item>
+            </view>
+
+            <!-- 底部扫码输入框 -->
+            <view class="fixed-bottom pad-20" style="background: #ffffff;">
+                <u-search placeholder="请输入/扫描条码" v-model="scanCode" @confirm="onScanConfirm" :show-action="false"
+                    custom-style="margin-right:10px"></u-search>
+                <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+            </view>
+        </view>
+
+        <!-- 备注弹窗 -->
+        <remark-dialog v-model:visible="remarkVisible" :initial-value="currentRemark"
+            @confirm="handleRemarkConfirm"></remark-dialog>
+    </view>
+</template>
+
+<script setup>
+import {
+    ref,
+    reactive,
+    onMounted,
+    onUnmounted
+} from 'vue';
+import BadItem from './components/BadItem.vue';
+import VolumeTTS from '@/utils/VolumeTTS.js'
+import RemarkDialog from './components/RemarkDialog.vue'
+
+// 表单数据
+const formData = reactive({
+    totalOrders: '3',
+    warehouse: '河南仓',
+    location: 'K001-0111'
+});
+
+// 订单列表
+const orders = ref([{
+    orderNo: '000001',
+    badCount: '5',
+    logisticsNo: 'DPK202444118877',
+    checkDate: '2024-11-14',
+    operator: '李程雪'
+}, {
+    orderNo: '000001',
+    badCount: '5',
+    logisticsNo: 'DPK202444118877',
+    checkDate: '2024-11-14',
+    operator: '李程雪'
+},]);
+
+const scanCode = ref('');
+
+// 备注弹窗相关
+const remarkVisible = ref(false)
+const currentRemark = ref('')
+const currentEditIndex = ref(-1)
+
+// 方法定义
+const goBack = () => {
+    uni.navigateBack();
+};
+
+const onSubmit = () => {
+    uni.showModal({
+        title: '提交确认',
+        content: '是否确认提交本次入库?',
+        success: (res) => {
+            if (res.confirm) {
+                handleSubmitConfirm()
+            }
+        }
+    })
+}
+
+const handleSubmitConfirm = async () => {
+    try {
+        uni.showLoading({
+            title: '提交中...'
+        })
+        
+        // TODO: 这里添加实际的提交逻辑
+        await new Promise(resolve => setTimeout(resolve, 1000)) // 模拟请求
+        
+        uni.hideLoading()
+        uni.showToast({
+            title: '提交成功',
+            icon: 'success'
+        })
+        
+        // 提交成功后返回上一页
+        setTimeout(() => {
+            uni.navigateBack()
+        }, 1500)
+        
+    } catch (error) {
+        uni.hideLoading()
+        uni.showToast({
+            title: '提交失败',
+            icon: 'error'
+        })
+    }
+}
+
+const editOrder = (index) => {
+    // 编辑订单
+    openRemarkDialog(index)
+};
+
+const onScanConfirm = () => {
+    // 扫码确认逻辑
+    // #ifdef APP-PLUS || MP-WEIXIN
+    uni.scanCode({
+        scanType: ['barCode'], // 支持条形码和二维码
+        success: (res) => {
+            scanCode.value = res.result;
+        },
+        fail: (err) => {
+            uni.showToast({
+                title: '扫码失败',
+                icon: 'error'
+            });
+        }
+    });
+    // #endif
+
+    // #ifdef H5
+    uni.showToast({
+        title: 'H5环境不支持扫码,请手动输入',
+        icon: 'none'
+    });
+    // #endif
+};
+
+const openScan = () => {
+    // 打开扫码器
+};
+
+//选择库位
+function selectLocation() {
+    uni.navigateTo({
+        url: "/pages/index/wms/location-select"
+    })
+}
+
+// 删除订单
+const deleteOrder = (index) => {
+    orders.value.splice(index, 1);
+    // 更新总数
+    formData.totalOrders = orders.value.length.toString();
+};
+
+const ttsModule = ref(null);
+onMounted(() => {
+    ttsModule.value = new VolumeTTS();
+
+    // 监听库位选择
+    uni.$on('updateLocation', (locationCode) => {
+        formData.location = locationCode
+    })
+
+    // 监听仓库选择
+    uni.$on('updateWarehouse', (warehouseName) => {
+        formData.warehouse = warehouseName
+    })
+})
+
+// 记得在页面卸载时移除事件监听
+onUnmounted(() => {
+    uni.$off('updateLocation')
+    uni.$off('updateWarehouse')
+})
+
+// 打开备注弹窗
+const openRemarkDialog = (index, remark = '') => {
+    currentEditIndex.value = index
+    currentRemark.value = remark
+    remarkVisible.value = true
+}
+
+// 处理备注确认
+const handleRemarkConfirm = (remark) => {
+    if (currentEditIndex.value >= 0) {
+        orders.value[currentEditIndex.value].remark = remark
+    }
+    currentEditIndex.value = -1
+    currentRemark.value = ''
+}
+
+// 打开仓库选择页面
+const selectWarehouse = () => {
+    uni.navigateTo({
+        url: '/pages/index/wms/warehouse-select'
+    })
+}
+</script>
+
+<style scoped>
+.content {
+    padding-top: 44px;
+    border-radius: 0;
+}
+
+.info-section {
+    background-color: #ffffff;
+    padding: 15px;
+    padding-bottom: 5px;
+    margin-bottom: 12px;
+}
+
+.order-list {
+    margin-bottom: 60px;
+}
+</style>

+ 107 - 2
pages/index/wms/bad-off.vue

@@ -1,3 +1,108 @@
 <template>
-	<view>1</view>
-</template>
+    <view class="container">
+        <!-- 任务列表 -->
+        <view class="task-list">
+            <view v-for="(item, index) in taskList" :key="index" class="task-card" @click="handleTaskClick(item)">
+                <view class="task-header">
+                    <text class="task-no">作业单号:{{ item.taskNo }}</text>
+                </view>
+                <view class="task-content">
+                    <view class="flex-a mb-10">
+                        <text class="label">仓库:</text>
+                        <text class="value">{{ item.warehouse }}</text>
+                    </view>
+                    <view class="flex-a mb-10">
+                        <text class="label">任务数量:</text>
+                        <text class="value">{{ item.quantity }}</text>
+                    </view>
+                    <view class="flex-a">
+                        <text class="label">作业状态:</text>
+                        <text class="value">{{ item.status }}</text>
+                    </view>
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+// 搜索文本
+const searchText = ref('')
+
+// 任务列表数据
+const taskList = ref([
+    {
+        taskNo: 'XJ20245451421',
+        warehouse: '河南仓',
+        quantity: 40,
+        status: '待作业'
+    },
+    {
+        taskNo: 'XJ20245451421',
+        warehouse: '河南仓',
+        quantity: 40,
+        status: '待作业'
+    }
+])
+
+// 搜索处理
+const onSearch = () => {
+    // 实现搜索逻辑
+}
+
+// 打开扫码
+const openScan = () => {
+    // #ifdef APP-PLUS || MP-WEIXIN
+    uni.scanCode({
+        success: (res) => {
+            searchText.value = res.result
+            onSearch()
+        },
+        fail: (err) => {
+            uni.showToast({
+                title: '扫码失败',
+                icon: 'error'
+            })
+        }
+    })
+    // #endif
+
+    // #ifdef H5
+    uni.showToast({
+        title: 'H5环境不支持扫码',
+        icon: 'none'
+    })
+    // #endif
+}
+
+// 点击任务卡片
+const handleTaskClick = (task) => {
+    // 处理任务点击,可以跳转到详情页
+    uni.navigateTo({
+        url: `/pages/index/wms/task-detail?taskNo=${task.taskNo}`
+    })
+}
+</script>
+
+<style scoped>
+.task-card {
+    background-color: #ffffff;
+    padding: 20rpx;
+    margin-top: 16rpx;
+    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+}
+
+.task-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 16rpx;
+}
+
+.task-no {
+    font-size: 28rpx;
+    font-weight: bold;
+}
+</style>

+ 224 - 0
pages/index/wms/bad-out-order.vue

@@ -0,0 +1,224 @@
+<template>
+    <view class="container">
+        <!-- 搜索框 -->
+        <u-sticky>
+            <view class="search-area flex-c mb-20">
+                <u-search v-model="searchText" placeholder="请输入运单号/订单编号" :show-action="false" :clearabled="true"
+                    @change="onSearch" height="40">
+
+                </u-search>
+                <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+            </view>
+        </u-sticky>
+
+        <view class="content">
+            <!-- 基本信息 -->
+            <view class="info-section">
+                <view class="info-item">库位:{{ locationInfo.location }}</view>
+                <view class="info-item">物流单号:{{ locationInfo.logisticsNo }}</view>
+                <view class="info-item">订单编号:{{ locationInfo.orderNo }}</view>
+                <view class="info-item">订单商品:{{ locationInfo.goodsCount }}</view>
+                <view class="info-item">备注信息:{{ locationInfo.remark }}</view>
+            </view>
+
+            <!-- 极差商品列表 -->
+            <view class="bad-list">
+                <view class="list-title mb-6">极差</view>
+                <view v-for="(item, index) in badList" :key="index">
+                    <BadOutCard :item="item" />
+                </view>
+            </view>
+        </view>
+
+        <!-- 底部按钮 -->
+        <view class="fixed-bottom">
+            <u-button size="large" type="warning" text="反馈" @click="openRemarkDialog" />
+            <u-button size="large" type="primary" text="确定出库" @click="onConfirm" />
+        </view>
+
+        <!-- 备注弹窗 -->
+        <remark-dialog v-model:visible="remarkVisible" :initial-value="currentRemark"
+            @confirm="handleRemarkConfirm"></remark-dialog>
+    </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import BadOutCard from './components/BadOutCard.vue'
+import RemarkDialog from './components/RemarkDialog.vue';
+import VolumeTTS from '@/utils/VolumeTTS.js';
+
+const ttsModule = ref(null)
+// 搜索文本
+const searchText = ref('')
+
+// 位置信息
+const locationInfo = ref({
+    location: 'K01-01-1A',
+    logisticsNo: 'DPK20232154221',
+    orderNo: '7516531',
+    goodsCount: '10',
+    remark: ''
+})
+
+// 极差商品列表
+const badList = ref([
+    {
+        image: 'https://img20.360buyimg.com/da/jfs/t1/141592/25/8861/261559/5f68d8c1E33ed78ab/698ad655bfcfbaed.png',
+        title: '公文写作教程',
+        isbn: '978704051555',
+        price: 49.5,
+        discount: 0.85,
+        quantity: 5,
+        set: '不是',
+        estimate: 4.11,
+        review: 0,
+        good: 0,
+        average: 0,
+        bad: 1,
+        reason: '明显泛黄水印/发霉/明显异味'
+    },
+    {
+        image: 'https://img20.360buyimg.com/da/jfs/t1/141592/25/8861/261559/5f68d8c1E33ed78ab/698ad655bfcfbaed.png',
+        title: '公文写作教程',
+        isbn: '978704051555',
+        price: 49.5,
+        discount: 0.85,
+        quantity: 5,
+        set: '不是',
+        estimate: 4.11,
+        review: 0,
+        good: 0,
+        average: 0,
+        bad: 1,
+        reason: '明显泛黄水印/发霉/明显异味'
+    }
+])
+
+onMounted(() => {
+    ttsModule.value = new VolumeTTS()
+})
+
+// 搜索处理
+const onSearch = () => {
+    // 实现搜索逻辑
+}
+
+// 打开扫码
+const openScan = () => {
+    // #ifdef APP-PLUS || MP-WEIXIN
+    uni.scanCode({
+        success: (res) => {
+            searchText.value = res.result
+            onSearch()
+        },
+        fail: (err) => {
+            uni.showToast({
+                title: '扫码失败',
+                icon: 'error'
+            })
+        }
+    })
+    // #endif
+
+    // #ifdef H5
+    uni.showToast({
+        title: 'H5环境不支持扫码',
+        icon: 'none'
+    })
+    // #endif
+}
+
+// 确认出库
+const onConfirm = () => {
+    uni.showModal({
+        title: '确认提示',
+        content: '是否确认出库?',
+        success: (res) => {
+            if (res.confirm) {
+                // 处理确认出库逻辑
+                uni.showToast({
+                    title: '出库成功',
+                    icon: 'success'
+                })
+                ttsModule.value.speak('出库成功')
+            }
+        }
+    })
+}
+
+// 备注弹窗相关
+const remarkVisible = ref(false)
+const currentRemark = ref('')
+const currentEditIndex = ref(-1)
+
+// 打开备注弹窗
+const openRemarkDialog = (index, remark = '') => {
+    currentEditIndex.value = index
+    currentRemark.value = remark
+    remarkVisible.value = true
+}
+
+// 处理备注确认
+const handleRemarkConfirm = (remark) => {
+    if (currentEditIndex.value >= 0) {
+        orders.value[currentEditIndex.value].remark = remark
+    }
+    currentEditIndex.value = -1
+    currentRemark.value = ''
+}
+</script>
+
+<style scoped>
+.container {
+    padding-bottom: 120rpx;
+}
+
+
+.info-section {
+    background-color: #fff;
+    padding: 20rpx;
+    border-radius: 8rpx;
+    margin-bottom: 20rpx;
+}
+
+.info-item {
+    line-height: 1.8;
+}
+
+.list-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    background-color: rgb(222, 134, 143, 0.5);
+    padding: 10rpx 0;
+    padding-left: 30rpx;
+}
+
+.bad-list {
+    margin-bottom: 20rpx;
+}
+
+.footer {
+    position: fixed;
+    bottom: 100rpx;
+    left: 0;
+    right: 0;
+    background-color: #fff;
+    padding: 20rpx;
+}
+
+.btn-group {
+    display: flex;
+    justify-content: space-around;
+}
+
+.search-wrapper {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background-color: #fff;
+    padding: 20rpx;
+    box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
+}
+</style>

+ 56 - 2
pages/index/wms/bad-out.vue

@@ -1,3 +1,57 @@
 <template>
-	<view>1</view>
-</template>
+    <view class="container flex-d h100">
+        <!-- 库位列表 -->
+        <view class="location-list flex-1">
+           <view class="no-data flex-c mt-60">请输入快递单号/订单编号</view>
+        </view>
+
+        <!-- 底部搜索框 -->
+        <view class="pad-20 flex-a" style="background: #ffffff;">
+            <u-search v-model="searchText" placeholder="请输入库位条码" :show-action="false" :clearabled="true"
+                @change="onSearch" height="40"  @click="searchText = ''">
+            </u-search>
+            <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+// 搜索文本
+const searchText = ref('')
+
+
+// 搜索处理
+const onSearch = () => {
+    // 实现搜索逻辑
+    uni.navigateTo({
+        url: `/pages/index/wms/bad-out-order?searchText=${searchText.value}`
+    })
+}
+
+// 打开扫码
+const openScan = () => {
+  // #ifdef APP-PLUS || MP-WEIXIN
+  uni.scanCode({
+    success: (res) => {
+      searchText.value = res.result
+      onSearch()
+    },
+    fail: (err) => {
+      uni.showToast({
+        title: '扫码失败',
+        icon: 'error'
+      })
+    }
+  })
+  // #endif
+
+  // #ifdef H5
+  uni.showToast({
+    title: 'H5环境不支持扫码',
+    icon: 'none'
+  })
+  // #endif
+}
+</script>
+

+ 128 - 0
pages/index/wms/components/BadItem.vue

@@ -0,0 +1,128 @@
+<template>
+  <view class="bad-item">
+    <u-swipe-action>
+      <u-swipe-action-item
+        :options="options"
+        @click="handleAction"
+      >
+        <view class="item-content">
+          <view class="item-row">
+            <text class="label">订单编号:</text>
+            <text class="value">{{ data.orderNo }}</text>
+            <u-icon 
+              name="edit-pen" 
+              color="#4CAF50" 
+              size="20" 
+              class="edit-icon"
+              @click="$emit('edit')"
+            ></u-icon>
+          </view>
+          <view class="item-row">
+            <text class="label">不良数量:</text>
+            <text class="value">{{ data.badCount }}</text>
+          </view>
+          <view class="item-row">
+            <text class="label">物流单号:</text>
+            <text class="value">{{ data.logisticsNo }}</text>
+          </view>
+          <view class="item-row">
+            <text class="label">验货完成日期:</text>
+            <text class="value">{{ data.checkDate }}</text>
+          </view>
+          <view class="item-row">
+            <text class="label">录入人:</text>
+            <text class="value">{{ data.operator }}</text>
+          </view>
+        </view>
+      </u-swipe-action-item>
+    </u-swipe-action>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+const props = defineProps({
+  data: {
+    type: Object,
+    required: true,
+    default: () => ({
+      orderNo: '',
+      badCount: '',
+      logisticsNo: '',
+      checkDate: '',
+      operator: ''
+    })
+  }
+})
+
+const emit = defineEmits(['delete', 'edit'])
+
+// 左滑操作按钮配置
+const options = ref([
+  {
+    text: '删除',
+    style: {
+      backgroundColor: '#ff4444'
+    }
+  }
+])
+
+// 处理左滑操作
+const handleAction = (e) => {
+  if (e.index === 0) {
+    uni.showModal({
+      title: '提示',
+      content: '确定要删除该订单吗?',
+      success: (res) => {
+        if (res.confirm) {
+          emit('delete')
+        }
+      }
+    })
+  }
+}
+</script>
+
+<style scoped>
+.bad-item {
+  margin-bottom: 12px;
+  background-color: #ffffff;
+  border-radius: 8px;
+  overflow: hidden;
+}
+
+.item-content {
+  padding: 12px 15px;
+}
+
+.item-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 8px;
+  position: relative;
+}
+
+.item-row:last-child {
+  margin-bottom: 0;
+}
+
+.label {
+  color: #666;
+  font-size: 14px;
+  width: 100px;
+}
+
+.value {
+  color: #333;
+  font-size: 14px;
+  flex: 1;
+}
+
+.edit-icon {
+  position: absolute;
+  right: 0;
+  top: 50%;
+  transform: translateY(-50%);
+}
+</style>

+ 60 - 0
pages/index/wms/components/BadOutCard.vue

@@ -0,0 +1,60 @@
+<template>
+    <view class="card">
+        <view class="flex w100">
+            <view class="flex-d">
+                <image style="width: 80px;height: 100px;" :src="item.image" mode="aspectFill"></image>
+                <view class="quantity mt-20">数量: {{ item.quantity }}</view>
+            </view>
+            <view class="book-info ml-20 flex-1">
+                <view class="common-title mb-20">{{ item.title }}</view>
+                <view class="flex flex-j-b mb-10">
+                    <view class="isbn">ISBN: {{ item.isbn }}</view>
+                    <view class="set">套装: {{ item.set }}</view>
+
+                </view>
+                <view class="flex flex-j-b mb-10">
+                    <view class="discount">回收折扣: {{ item.discount }}</view>
+                    <view class="review">审核金额: {{ item.review }}</view>
+                </view>
+                <view class="flex flex-j-b mb-10">
+                    <view class="price">定价: {{ item.price }}</view>
+                    <view class="estimate">预估单价: {{ item.estimate }}</view>
+                </view>
+
+                <view class="quality mb-10">
+                    品相: 良好({{ item.good }}) 、 一般({{ item.average }}) 、 极差({{ item.bad }})
+                </view>
+                <view class="reason color-red">原因: {{ item.reason }}</view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import { defineProps } from 'vue'
+
+const props = defineProps({
+    item: Object,
+})
+</script>
+
+<style scoped>
+.card {
+    background-color: rgb(222, 134, 143, 0.5);
+    padding: 12px;
+    display: flex;
+    align-items: center;
+    margin-bottom: 6rpx;
+
+    .card-content {
+        display: flex;
+        width: 100%;
+    }
+    .book-info{
+        font-size: 26rpx;
+    }
+    .color-red {
+        color: #bd3124;
+    }
+}
+</style>

+ 103 - 0
pages/index/wms/components/LocationOrderItem.vue

@@ -0,0 +1,103 @@
+<template>
+    <view class="order-item">
+        <view class="order-header">
+            <view class="order-info">
+                <view class="info-row">
+                    <text class="label">订单编号:</text>
+                    <text class="value">{{ item.orderNo }}</text>
+                </view>
+                <view class="info-row">
+                    <text class="label">不良数量:</text>
+                    <text class="value">{{ item.badCount }}</text>
+                </view>
+                <view class="info-row">
+                    <text class="label">物流单号:</text>
+                    <text class="value">{{ item.logisticsNo }}</text>
+                </view>
+                <view class="info-row">
+                    <text class="label">验货完成日期:</text>
+                    <text class="value">{{ item.inspectionDate }}</text>
+                </view>
+                <view class="info-row">
+                    <text class="label">录入人:</text>
+                    <text class="value">{{ item.operator }}</text>
+                </view>
+            </view>
+
+
+            <view class="check-icon" v-if="isCheck">
+                <u-icon :name="item.checked ? 'checkmark-circle-fill' : 'checkmark-circle'"
+                    :color="item.checked ? '#19be6b' : '#c8c9cc'" size="28" @click="toggleSelect"></u-icon>
+            </view>
+
+            <navigator v-else :url="item.jumpUrl" hover-class="none" class="quick-jump">
+                <u-icon name="arrow-rightward" color="#2979ff" size="20"></u-icon>
+            </navigator>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import { defineProps, defineEmits } from 'vue'
+
+const props = defineProps({
+    item: {
+        type: Object,
+        required: true
+    },
+    isCheck: {
+        type: Boolean,
+        default: false
+    }
+})
+
+const emit = defineEmits(['select'])
+
+const toggleSelect = () => {
+    emit('select', props.item)
+}
+</script>
+
+<style lang="scss" scoped>
+.order-item {
+    background-color: #ffffff;
+    padding: 20rpx;
+    border-bottom: 1px solid #eee;
+}
+
+.order-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+}
+
+.order-info {
+    flex: 1;
+}
+
+.info-row {
+    display: flex;
+    margin-bottom: 12rpx;
+    font-size: 28rpx;
+    line-height: 40rpx;
+
+    &:last-child {
+        margin-bottom: 0;
+    }
+}
+
+.label {
+    color: #666;
+    margin-right: 16rpx;
+    min-width: 160rpx;
+}
+
+.value {
+    color: #333;
+    flex: 1;
+}
+
+.check-icon {
+    padding: 0 10rpx;
+}
+</style>

+ 101 - 0
pages/index/wms/components/RemarkDialog.vue

@@ -0,0 +1,101 @@
+<template>
+    <u-popup :show="visible" @close="onClose" mode="center" round="10" :closeOnClickOverlay="false">
+        <view class="remark-dialog">
+            <view class="dialog-title">编辑备注</view>
+
+            <!-- 备注输入框 -->
+            <view class="dialog-content mb-30">
+                <u-textarea v-model="remarkText" placeholder="请输入" :maxlength="200" height="100" count></u-textarea>
+
+                <!-- 快速输入标签 -->
+                <view class="quick-tags mt-10">
+                    <text class="common-title">快速填入</text>
+                    <view class="tags-container flex-w  mt-20">
+                        <u-tag v-for="(tag, index) in quickTags" :key="index" :text="tag" plain size="mini"
+                            type="primary" @click="appendTag(tag)" class="tag-item"></u-tag>
+                    </view>
+                </view> 
+            </view>
+
+            <!-- 底部按钮 -->
+            <view class="dialog-footer">
+                <u-button plain @click="onClose" class="footer-btn">取消</u-button>
+                <u-button type="primary" @click="onConfirm" class="footer-btn">确定</u-button>
+            </view>
+        </view>
+    </u-popup>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+
+const props = defineProps({
+    visible: {
+        type: Boolean,
+        default: false
+    },
+    initialValue: {
+        type: String,
+        default: ''
+    }
+})
+
+const emit = defineEmits(['update:visible', 'confirm'])
+
+const remarkText = ref('')
+const quickTags = ref(['少书', '多书', '子母件', '书单不符'])
+
+// 监听visible变化,初始化remarkText
+watch(() => props.visible, (newVal) => {
+    if (newVal) {
+        remarkText.value = props.initialValue
+    }
+})
+
+// 追加快速标签
+const appendTag = (tag) => {
+    remarkText.value += remarkText.value ? ' ' + tag : tag
+}
+
+// 关闭弹窗
+const onClose = () => {
+    emit('update:visible', false)
+}
+
+// 确认提交
+const onConfirm = () => {
+    emit('confirm', remarkText.value)
+    onClose()
+}
+</script>
+
+<style scoped>
+.remark-dialog {
+    width: 650rpx;
+    background-color: #fff;
+    border-radius: 10px;
+    padding: 20px;
+}
+
+.dialog-title {
+    text-align: center;
+    font-size: 16px;
+    font-weight: 500;
+    margin-bottom: 20px;
+}
+
+.tag-item {
+    margin-right: 10px;
+    margin-bottom: 10px;
+}
+
+.dialog-footer {
+    display: flex;
+    justify-content: space-between;
+    gap: 15px;
+}
+
+.footer-btn {
+    flex: 1;
+}
+</style>

+ 91 - 2
pages/index/wms/location-order.vue

@@ -1,3 +1,92 @@
 <template>
-	<view>1</view>
-</template>
+    <view class="container">
+        <view class="header">
+            <view class="flex-d">
+                <text>仓库: 河南仓</text>
+                <text class="mt-16">库位编号: {{ location }}</text>
+                <text class="mt-16">订单数量: 3</text>
+            </view>
+        </view>
+
+        <view class="product-details">
+            <LocationOrderItem v-for="(item, index) in products" :key="index" :item="item" />
+        </view>
+
+        <!-- 底部扫码输入框 -->
+        <view class="fixed-bottom pad-20" style="background: #ffffff;">
+            <u-search placeholder="请输入快递单号/订单编号" v-model="searchValue" @confirm="onSearch" :show-action="false"
+                custom-style="margin-right:10px"></u-search>
+            <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import {
+    reactive,
+    ref
+} from 'vue'
+import LocationOrderItem from './components/LocationOrderItem.vue'
+
+const location = 'K01-01-1A'
+const searchValue = ref('')
+
+const products = ref([{
+    orderNo: '978704051555',
+    logisticsNo: "SFUS98218323132131",
+    inspectionDate: "2023-01-01",
+    badCount: 5,
+    operator: '张三',
+},
+{
+    orderNo: '978704051555',
+    logisticsNo: "SFUS98218323132131",
+    inspectionDate: "2023-01-01",
+    badCount: 5,
+    operator: '张三',
+}
+])
+
+const operationLogs = ref([
+    // Example log data
+    {
+        date: '2024-01-12 14:18:01',
+        user: '张张张',
+        action: '提交出库'
+    },
+    {
+        date: '2024-01-12 14:18:01',
+        user: '张张张',
+        action: '提交入库'
+    }
+])
+
+const onSearch = () => {
+    // Implement search logic here
+}
+
+function openScan() {
+
+}
+</script>
+
+<style lang="scss" scoped>
+.header {
+    display: flex;
+    justify-content: space-between;
+    padding: 20rpx 30rpx;
+    background-color: #ffffff;
+}
+
+.status {
+    color: green;
+}
+
+
+.log-item {
+    display: flex;
+    justify-content: space-between;
+    padding: 20rpx 30rpx;
+    border-bottom: 1px solid #e0e0e0;
+}
+</style>

+ 123 - 0
pages/index/wms/location-select.vue

@@ -0,0 +1,123 @@
+<template>
+    <view class="container">
+        <!-- 库位列表 -->
+        <scroll-view scroll-y class="location-list" :style="{ height: scrollHeight + 'px' }">
+            <view v-for="(item, index) in filteredLocations" :key="index" class="location-item"
+                hover-class="location-item-hover" @click="selectLocation(item)">
+                <text>{{ item.code }}</text>
+            </view>
+        </scroll-view>
+
+        <!-- 底部搜索框 -->
+        <view class="fixed-bottom pad-20" style="background: #ffffff;">
+            <u-search v-model="searchText" placeholder="请输入库位条码" :show-action="false" :clearabled="true"
+                @change="onSearch" height="40" :disabled="true" @click="searchText = ''">
+            </u-search>
+            <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from 'vue'
+
+// 搜索文本
+const searchText = ref('')
+
+// 库位列表数据
+const locations = ref([
+    { code: 'k001-0121' },
+    { code: 'k001-0113' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+    { code: 'k001-0111' },
+])
+
+// 滚动区域高度
+const scrollHeight = ref(0)
+
+// 过滤后的库位列表
+const filteredLocations = computed(() => {
+    if (!searchText.value) return locations.value
+    return locations.value.filter(item =>
+        item.code.toLowerCase().includes(searchText.value.toLowerCase())
+    )
+})
+
+// 搜索处理
+const onSearch = () => {
+    // 实现搜索逻辑
+}
+
+// 打开扫码
+const openScan = () => {
+    // #ifdef APP-PLUS || MP-WEIXIN
+    uni.scanCode({
+        success: (res) => {
+            searchText.value = res.result
+            onSearch()
+        },
+        fail: (err) => {
+            uni.showToast({
+                title: '扫码失败',
+                icon: 'error'
+            })
+        }
+    })
+    // #endif
+
+    // #ifdef H5
+    uni.showToast({
+        title: 'H5环境不支持扫码',
+        icon: 'none'
+    })
+    // #endif
+}
+
+// 选择库位
+const selectLocation = (item) => {
+    // 获取页面实例
+    const pages = getCurrentPages()
+    const prevPage = pages[pages.length - 2]
+    
+    // 也可以使用事件总线或页面参数的方式传值
+    uni.$emit('updateLocation', item.code)
+    
+    // 返回上一页
+    uni.navigateBack()
+}
+
+// 计算滚动区域高度
+onMounted(() => {
+    const systemInfo = uni.getSystemInfoSync()
+    // 减去标题栏高度和搜索框高度
+    scrollHeight.value = systemInfo.windowHeight - 44 - 60
+})
+</script>
+
+<style scoped>
+.container {
+    position: relative;
+}
+
+.location-list {
+    padding: 12px 0 60px;
+}
+
+.location-item {
+    background-color: #fff;
+    padding: 15px;
+    margin-bottom: 1px;
+    font-size: 14px;
+}
+</style>

+ 133 - 2
pages/index/wms/order-query.vue

@@ -1,3 +1,134 @@
 <template>
-	<view>1</view>
-</template>
+	<view class="container">
+		<view class="header">
+			<view class="flex-d">
+				<text>订单编号: {{ orderNumber }}</text>
+				<text class="mt-16">库位: {{ location }}</text>
+			</view>
+			<view class="status">
+				<text>已出库</text>
+			</view>
+		</view>
+
+		<view style="background-color: #ffffff" class="pad-5 mt-20">
+			<u-tabs :list="list1" v-model="activeTab" :itemStyle="{height:'44px',width:'48%'}"
+				@change="handleTabChange"></u-tabs>
+		</view>
+
+		<view v-if="activeTab === 0" class="product-details">
+			<bad-out-card v-for="(item, index) in products" :key="index" :item="item" />
+		</view>
+		<view v-else class="operation-logs mt-20">
+			<view v-for="(log, index) in operationLogs" :key="index" class="log-item">
+				<text>{{ log.date }}</text>
+				<text>{{ log.user }}</text>
+				<text>{{ log.action }}</text>
+			</view>
+		</view>
+
+		<!-- 底部扫码输入框 -->
+		<view class="fixed-bottom pad-20" style="background: #ffffff;">
+			<u-search placeholder="请输入快递单号/订单编号" v-model="searchValue" @confirm="onSearch" :show-action="false"
+				custom-style="margin-right:10px"></u-search>
+			<u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref
+	} from 'vue'
+	import BadOutCard from './components/BadOutCard.vue'
+
+	const list1 = reactive([{
+		name: '商品明细'
+	}, {
+		name: "操作记录"
+	}])
+
+	const orderNumber = '4654114'
+	const location = 'K01-01-1A'
+	const activeTab = ref(0)
+	const searchValue = ref('')
+
+	const products = ref([{
+			image: 'https://img20.360buyimg.com/da/jfs/t1/141592/25/8861/261559/5f68d8c1E33ed78ab/698ad655bfcfbaed.png',
+			title: '公文写作教程',
+			isbn: '978704051555',
+			price: 49.5,
+			discount: 0.85,
+			quantity: 5,
+			set: '不是',
+			estimate: 4.11,
+			review: 0,
+			good: 0,
+			average: 0,
+			bad: 1,
+			reason: '明显泛黄水印/发霉/明显异味'
+		},
+		{
+			image: 'https://img20.360buyimg.com/da/jfs/t1/141592/25/8861/261559/5f68d8c1E33ed78ab/698ad655bfcfbaed.png',
+			title: '公文写作教程',
+			isbn: '978704051555',
+			price: 49.5,
+			discount: 0.85,
+			quantity: 5,
+			set: '不是',
+			estimate: 4.11,
+			review: 0,
+			good: 0,
+			average: 0,
+			bad: 1,
+			reason: '明显泛黄水印/发霉/明显异味'
+		}
+	])
+
+	const operationLogs = ref([
+		// Example log data
+		{
+			date: '2024-01-12 14:18:01',
+			user: '张张张',
+			action: '提交出库'
+		},
+		{
+			date: '2024-01-12 14:18:01',
+			user: '张张张',
+			action: '提交入库'
+		}
+	])
+
+	function handleTabChange(tab) {
+		activeTab.value = tab.index
+	}
+
+	const onSearch = () => {
+		// Implement search logic here
+	}
+
+	function openScan() {
+
+	}
+</script>
+
+<style lang="scss" scoped>
+	.header {
+		display: flex;
+		justify-content: space-between;
+		padding: 20rpx 30rpx;
+		background-color: #ffffff;
+	}
+
+	.status {
+		color: green;
+	}
+
+
+	.log-item {
+		display: flex;
+		justify-content: space-between;
+		padding: 20rpx 30rpx;
+		border-bottom: 1px solid #e0e0e0;
+	}
+</style>

+ 138 - 0
pages/index/wms/speedy-check-add.vue

@@ -0,0 +1,138 @@
+<template>
+	<view class="container">
+		<u-navbar title="选择商品" :border="false" fixed safe-area-inset-top>
+			<template #left>
+				<u-icon name="arrow-left" color="#333333" size="20" @click="goBack"></u-icon>
+			</template>
+			<template #right>
+				<u-text type="primary" text="确定" @click="onSubmit"></u-text>
+			</template>
+		</u-navbar>
+
+		<!-- 库位显示 -->
+		<view class="location-info">
+			<text>{{ location }}</text>
+		</view>
+
+		<!-- 订单列表 -->
+		<view class="product-details">
+			<LocationOrderItem isCheck v-for="(item, index) in products" :key="index" :item="item"
+				@select="toggleItemSelect" />
+		</view>
+
+		<!-- 底部全选栏 -->
+		<view class="fixed-bottom">
+			<view class="select-all" @click="toggleSelectAll">
+				<u-icon :name="isAllSelected ? 'checkmark-circle-fill' : 'checkmark-circle'"
+					:color="isAllSelected ? '#19be6b' : '#c8c9cc'" size="28"></u-icon>
+				<text class="select-text">全选</text>
+			</view>
+			<text class="order-count">订单总数: {{ products.length }}</text>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		computed
+	} from 'vue'
+	import LocationOrderItem from './components/LocationOrderItem.vue'
+
+	// 库位相关
+	const location = ref('k01-01-4A')
+
+	// 其他数据
+	const searchValue = ref('')
+	const products = ref([{
+			orderNo: '4846464',
+			logisticsNo: "DPK2023497491611",
+			inspectionDate: "2024-11-14",
+			badCount: 5,
+			operator: '李程雪',
+			checked: false
+		},
+		{
+			orderNo: '4846464',
+			logisticsNo: "DPK2023497491611",
+			inspectionDate: "2024-11-14",
+			badCount: 5,
+			operator: '李程雪',
+			checked: false
+		}
+	])
+
+	// 计算是否全选
+	const isAllSelected = computed(() => {
+		return products.value.length > 0 && products.value.every(item => item.checked)
+	})
+
+	// 切换单个选择
+	const toggleItemSelect = (item) => {
+		item.checked = !item.checked
+	}
+
+	// 切换全选
+	const toggleSelectAll = () => {
+		const newState = !isAllSelected.value
+		products.value.forEach(item => {
+			item.checked = newState
+		})
+	}
+
+	// 确认选择
+	const onSubmit = () => {
+		const selectedItems = products.value.filter(item => item.checked)
+		// 这里可以通过 uni.$emit 传递选中的数据到上一页
+		uni.$emit('selectedProducts', selectedItems)
+		uni.navigateBack()
+	}
+
+	// 返回上一页
+	const goBack = () => {
+		uni.navigateBack()
+	}
+</script>
+
+<style lang="scss" scoped>
+	.location-info {
+		background-color: #fff;
+		padding: 20rpx;
+		text-align: center;
+		font-size: 32rpx;
+		margin-bottom: 16rpx;
+	}
+
+	.product-details {
+		margin-bottom: 100rpx;
+	}
+
+	.fixed-bottom {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		height: 100rpx;
+		background: #ffffff;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 0 30rpx;
+		box-shadow: 0 -2rpx 6rpx rgba(0, 0, 0, 0.1);
+	}
+
+	.select-all {
+		display: flex;
+		align-items: center;
+
+		.select-text {
+			margin-left: 12rpx;
+			font-size: 28rpx;
+		}
+	}
+
+	.order-count {
+		font-size: 28rpx;
+		color: #666;
+	}
+</style>

+ 129 - 2
pages/index/wms/speedy-check.vue

@@ -1,3 +1,130 @@
 <template>
-	<view>1</view>
-</template>
+    <view class="container">
+		<u-navbar title="快速盘点" :border="false" fixed safe-area-inset-top>
+		    <template #left>
+		        <u-icon name="arrow-left" color="#333333" size="20" @click="goBack"></u-icon>
+		    </template>
+		    <template #right>
+		        <u-text type="primary" text="提交" @click="onSubmit"></u-text>
+		    </template>
+		</u-navbar>
+        <!-- 盘点信息选择区域 -->
+        <view class="select-area" style="margin-top: 44px;">
+            <u-cell-group>
+                <u-cell title="盘点方式" :value="checkMethod" @click="showCheckMethodPicker = true" isLink />
+                <u-cell title="目标库位" :value="location" @click="handleLocationSelect" isLink />
+            </u-cell-group>
+        </view>
+
+        <!-- 盘点方式选择器 -->
+        <u-picker :show="showCheckMethodPicker" :columns="[checkMethodOptions]" @confirm="onCheckMethodConfirm"
+            @cancel="showCheckMethodPicker = false" />
+
+        <!-- 订单列表 -->
+        <view class="product-details">
+            <LocationOrderItem v-for="(item, index) in products" :key="index" :item="item" />
+        </view>
+		
+		<view class="add-btn" @click="handleAdd">
+			<u-icon name="plus-circle" size="40" color="#19be6b" @click="openScan"></u-icon>
+		</view>
+
+        <!-- 底部扫码输入框 -->
+        <view class="fixed-bottom pad-20" style="background: #ffffff;">
+            <u-search placeholder="请输入快递单号/订单编号" v-model="searchValue" @confirm="onSearch" :show-action="false"
+                custom-style="margin-right:10px"></u-search>
+            <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import {
+    reactive,
+    ref
+} from 'vue'
+import LocationOrderItem from './components/LocationOrderItem.vue'
+
+// 盘点方式相关
+const showCheckMethodPicker = ref(false)
+const checkMethod = ref('实际数量')
+const checkMethodOptions = ['实际数量', '增加数量', '减少数量']
+
+// 库位相关
+const location = ref('k01-01-4A')
+
+// 其他数据
+const searchValue = ref('')
+const products = ref([{
+    orderNo: '4846464',
+    logisticsNo: "DPK2023497491611",
+    inspectionDate: "2024-11-14",
+    badCount: 5,
+    operator: '李程雪',
+},
+{
+    orderNo: '4846464',
+    logisticsNo: "DPK2023497491611",
+    inspectionDate: "2024-11-14",
+    badCount: 5,
+    operator: '李程雪',
+}
+])
+
+// 方法
+const onCheckMethodConfirm = (e) => {
+    checkMethod.value = e.value[0]
+    showCheckMethodPicker.value = false
+}
+
+const handleLocationSelect = () => {
+    // 跳转到库位选择页面
+    uni.navigateTo({
+        url: '/pages/location-select/index'
+    })
+}
+
+const onSearch = () => {
+    // 实现搜索逻辑
+}
+
+const openScan = () => {
+    // 实现扫描逻辑
+}
+
+function handleAdd(){
+	uni.navigateTo({
+		url:"/pages/index/wms/speedy-check-add"
+	})
+}
+</script>
+
+<style lang="scss" scoped>
+.select-area {
+    background-color: #fff;
+}
+
+.product-details {
+    margin-bottom: 120rpx; // 为底部搜索框留出空间
+}
+
+.fixed-bottom {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    display: flex;
+    align-items: center;
+    padding: 20rpx;
+    background: #ffffff;
+    box-shadow: 0 -2rpx 6rpx rgba(0, 0, 0, 0.1);
+}
+
+.add-btn{
+	position: absolute;
+	right: 0;
+	bottom: 30%;
+	z-index: 99;
+	cursor: pointer;
+}
+</style>

+ 225 - 0
pages/index/wms/task-detail.vue

@@ -0,0 +1,225 @@
+<template>
+    <view class="container">
+        <!-- 顶部导航栏 -->
+        <u-navbar title="下架任务" :border="false" fixed safe-area-inset-top>
+            <template #left>
+                <u-icon name="arrow-left" color="#333333" size="20" @click="goBack"></u-icon>
+            </template>
+            <template #right>
+                <u-text type="primary" text="提交" @click="onSubmit"></u-text>
+            </template>
+        </u-navbar>
+
+        <!-- 任务进度 -->
+        <view class="progress-section">
+            <u-alert title="当前任务" type="info" center></u-alert>
+            <view class="flex flex-j-b pad-10" style="padding-right:40rpx">
+                <view class="next-task" @click="handleNextTask">
+                    <text>上一个</text>
+                </view>
+                <view class="flex-c">
+                    <text>{{ currentTask }}<text class="progress-text font-18 color-green">/{{ totalTasks
+                            }}</text></text>
+                </view>
+                <view class="color-green" @click="handleNextTask">
+                    <text>下一个</text>
+                </view>
+            </view>
+        </view>
+        <!-- 库位信息 -->
+        <view class="flex flex-j-b pad-10 next-location" style="padding-right:40rpx;align-items: center;">
+            <view class="font-14 mb-20">{{ currentIndex }}/{{ totalTasks }}</view>
+            <view class="flex-d">
+                <view class="font-20 text-center">
+                    {{ nextLocation }}
+                </view>
+                <view class="location-detail font-13 mt-10">下一库位 {{ nextLocation }}</view>
+            </view>
+            <u-icon name="attach" size="28"></u-icon>
+        </view>
+
+
+        <!-- 订单信息 -->
+        <view class="order-info">
+            <view class="info-item">订单编号:{{ orderInfo.orderNo }}</view>
+            <view class="info-item">物流单号:{{ orderInfo.logisticsNo }}</view>
+            <view class="info-item">不良数量:{{ orderInfo.badCount }}</view>
+        </view>
+
+        <!-- 极差商品列表 -->
+        <view class="bad-list">
+            <view class="list-title mb-6 mt-20">极差</view>
+            <view v-for="(item, index) in badList" :key="index">
+                <BadOutCard :item="item" />
+            </view>
+        </view>
+
+        <!-- 底部搜索框 -->
+        <view class="fixed-bottom pad-20" style="background: #ffffff;">
+            <u-search v-model="searchText" placeholder="请输入订单编号" :show-action="false" :clearabled="true"
+                @change="onSearch" height="40">
+            </u-search>
+            <u-icon name="scan" size="28" color="#19be6b" @click="openScan"></u-icon>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import {
+    ref,onMounted
+} from 'vue'
+import BadOutCard from '@/pages/index/wms/components/BadOutCard.vue'
+import VolumeTTS from '@/utils/VolumeTTS.js'
+
+// 任务进度
+const currentTask = ref(0)
+const totalTasks = ref(77)
+const currentIndex = ref(1)
+const nextLocation = ref('K01-02-4A')
+
+// 订单信息
+const orderInfo = ref({
+    orderNo: '4571211',
+    logisticsNo: 'DPK203156442584',
+    badCount: 10
+})
+const ttsModule = ref(null)
+onMounted(() => {
+    ttsModule.value = new VolumeTTS()
+})
+
+// 搜索文本
+const searchText = ref('')
+
+// 极差商品列表
+const badList = ref([{
+    image: 'https://img20.360buyimg.com/da/jfs/t1/141592/25/8861/261559/5f68d8c1E33ed78ab/698ad655bfcfbaed.png',
+    title: '公文写作教程',
+    isbn: '978704051555',
+    price: 49.5,
+    discount: 0.85,
+    quantity: 5,
+    set: '不是',
+    good: 0,
+    average: 0,
+    bad: 1,
+    reason: '明显泛黄水印/发霉/明显异味'
+}])
+
+// 处理下一个任务
+const handleNextTask = () => {
+    if (currentTask.value < totalTasks.value) {
+        currentTask.value++
+        VolumeTTS.speak(nextLocation.value)
+    }
+}
+
+// 搜索处理
+const onSearch = () => {
+    // 实现搜索逻辑
+}
+
+// 提交处理
+const onSubmit = () => {
+    uni.showModal({
+        title: '确认提示',
+        content: '是否确认提交本次下架?',
+        success: (res) => {
+            if (res.confirm) {
+                // 处理提交逻辑
+                uni.showToast({
+                    title: '提交成功',
+                    icon: 'success'
+                })
+                ttsModule.value.speak('任务已提交')
+            }
+        }
+    })
+}
+
+function goBack() {
+    uni.showModal({
+        title: '确认提示',
+        content: '是否确认放弃本次下架?',
+        success: (res) => {
+            if (res.confirm) {
+                uni.navigateBack()
+                ttsModule.value.speak('任务已放弃')
+            }
+        }
+    })
+}
+
+// 打开扫码
+const openScan = () => {
+    // #ifdef APP-PLUS || MP-WEIXIN
+    uni.scanCode({
+        success: (res) => {
+            searchText.value = res.result
+            onSearch()
+        },
+        fail: (err) => {
+            uni.showToast({
+                title: '扫码失败',
+                icon: 'error'
+            })
+        }
+    })
+    // #endif
+
+    // #ifdef H5
+    uni.showToast({
+        title: 'H5环境不支持扫码',
+        icon: 'none'
+    })
+    // #endif
+}
+</script>
+
+<style scoped>
+.progress-section {
+    background-color: #fff;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    padding: 10rpx;
+    padding-top: 56px;
+}
+.next-location{
+    background-color: #fff;
+    border-bottom: 1rpx solid #f0f0f0;
+    border-top: 1rpx solid #f0f0f0;
+    padding: 20rpx;
+}
+
+.color-green {
+    color: #4CAF50;
+}
+
+.location-info {
+    background-color: #fff;
+    padding: 20rpx;
+    margin-top: 2rpx;
+}
+
+.location-detail {
+    color: #666;
+}
+
+.order-info {
+    background-color: #fff;
+    padding: 20rpx;
+}
+
+.info-item {
+    line-height: 1.8;
+}
+
+.list-title {
+    font-size: 32rpx;
+    font-weight: bold;
+    background-color: rgb(222, 134, 143, 0.5);
+    padding: 10rpx 0;
+    padding-left: 30rpx;
+}
+</style>

+ 66 - 0
pages/index/wms/warehouse-select.vue

@@ -0,0 +1,66 @@
+<template>
+    <view class="container">
+        <!-- 搜索框 -->
+        <view class="search-area">
+            <u-search v-model="searchText" placeholder="请输入仓库名称" :show-action="false" :clearabled="true"
+                @change="onSearch" height="40"></u-search>
+        </view>
+
+        <!-- 仓库列表 -->
+        <view class="warehouse-list">
+            <view v-for="(item, index) in filteredWarehouses" :key="index" class="warehouse-item"
+                hover-class="warehouse-item-hover" @click="selectWarehouse(item)">
+                <text>{{ index + 1 }}.{{ item.name }}</text>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+
+// 搜索文本
+const searchText = ref('')
+
+// 仓库列表数据
+const warehouses = ref([
+    { id: 1, name: '河南仓' },
+    { id: 2, name: '河北仓' },
+    { id: 3, name: '山东仓' }
+])
+
+// 过滤后的仓库列表
+const filteredWarehouses = computed(() => {
+    if (!searchText.value) return warehouses.value
+    return warehouses.value.filter(item =>
+        item.name.toLowerCase().includes(searchText.value.toLowerCase())
+    )
+})
+
+// 搜索处理
+const onSearch = () => {
+    // 实现搜索逻辑
+}
+
+// 选择仓库
+const selectWarehouse = (item) => {
+    // 使用事件总线传递数据
+    uni.$emit('updateWarehouse', item.name)
+
+    // 返回上一页
+    uni.navigateBack()
+}
+</script>
+
+<style scoped>
+.warehouse-list {
+    margin-top: 12px;
+}
+
+.warehouse-item {
+    background-color: #fff;
+    padding: 15px;
+    margin-bottom: 1px;
+    font-size: 14px;
+}
+</style>

+ 71 - 0
utils/VolumeTTS.js

@@ -0,0 +1,71 @@
+class VolumeTTS {
+    ttsParams = {
+        lang: 'zh-CN',
+        speed: 1, // 将 0-10 转换为 0-1
+        pitch: 1, // 将 0-10 转换为 0-1
+        volume: 1,
+    };
+    TTSModule;
+
+    platform = uni.getSystemInfoSync().platform
+
+    constructor(opts) {
+        if (opts) this.ttsParams = opts;
+
+        // #ifdef APP-PLUS  
+        this.init()
+        // #endif
+    }
+
+    init() {
+        this.TTSModule = uni.requireNativePlugin('nrb-tts-plugin')
+        this.TTSModule && this.TTSModule.init({
+            "lang": "ZH",
+            "country": "CN"
+        }, res => {
+            if (res.success == 0) {
+                console.log('TTS初始化成功')
+            }
+        })
+    }
+
+    speak(text) {
+        // #ifdef H5
+        // H5端使用Web Speech API
+        if ('speechSynthesis' in window) {
+            const utterance = new SpeechSynthesisUtterance(text)
+            utterance.lang = this.ttsParams.lang
+            utterance.rate = this.ttsParams.speed
+            utterance.pitch = this.ttsParams.pitch
+            utterance.volume = this.ttsParams.volume
+            speechSynthesis.speak(utterance)
+        }
+        // #endif
+
+        console.log(this.platform, 'dsad');
+
+        // #ifdef APP-PLUS
+        let opts = this.platform == 'ios' ? {
+            "rate": ttsParams.speed,
+            "lang": "zh-CN",
+            "volume": 1
+        } : {
+            "pitch": ttsParams.pitch,
+            "speechRate": ttsParams.speed,
+            "queueMode": 1,
+        }
+
+        this.TTSModule.speak(text, opts, (e) => {
+            console.log(e, '读取成功')
+        })
+        // #endif   
+    }
+
+    stop() {
+        if (this.TTSModule) {
+            this.TTSModule.stop()
+        }
+    }
+}
+
+export default VolumeTTS