pjb
2 天以前 9d4fab12199b4011fd26367233141a9ec105cc03
组托和订单组托功能完善,新增领料出
2个文件已添加
1582 ■■■■■ 已修改文件
pages/order/callOutboundDetl/callOutboundDetl.vue 680 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/order/callReqOutbound.vue 902 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/order/callOutboundDetl/callOutboundDetl.vue
New file
@@ -0,0 +1,680 @@
<template>
    <view class="container">
        <!-- 搜索筛选卡片 -->
        <view class="filter-card">
            <!-- 订单选择 -->
            <view class="filter-item">
                <view class="filter-label">
                    <uni-icons type="document" size="18" color="#409EFF"></uni-icons>
                    <text>订单号</text>
                </view>
                <view class="filter-input">
                    <uni-combox :candidates="orderNoList" placeholder="请选择订单" v-model="orderNo" @input="getOrderDet"></uni-combox>
                </view>
            </view>
            <!-- 物料编号过滤 -->
            <view class="filter-item">
                <view class="filter-label">
                    <uni-icons type="scan" size="18" color="#409EFF"></uni-icons>
                    <text>物料编号</text>
                </view>
                <view class="filter-input">
                    <input
                        type="text"
                        v-model="filterMatnr"
                        placeholder="输入物料编号过滤"
                        @input="onFilterInput"
                        class="filter-input-field"
                        placeholder-class="placeholder-style"
                    />
                </view>
                <view v-if="filterMatnr" class="filter-clear" @click="clearFilter">
                    <uni-icons type="close" size="18" color="#909399"></uni-icons>
                </view>
            </view>
            <!-- 统计和全选栏 -->
            <view class="filter-footer">
                <view class="stat-info">
                    <uni-icons type="list" size="16" color="#909399"></uni-icons>
                    <text>{{filterMatnr ? '过滤结果' : '全部物料'}}:{{filteredList.length}} 条</text>
                </view>
                <view class="select-all-btn" @click="allSelect">
                    <text class="select-all-text">{{seltitle}}</text>
                </view>
            </view>
        </view>
        <!-- 物料列表 -->
        <scroll-view class="scroll-area" scroll-y :show-scrollbar="false">
            <view class="material-list">
                <view class="material-card" v-for="(orderDetl,index) in filteredList" :key="index" @click="toggleSelect(orderDetl)">
                    <view class="card-content">
                        <view class="card-info">
                            <view class="info-row">
                                <view class="info-label">序号:</view>
                                <view class="info-value">
                                    <text class="serial-number">{{index + 1}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">订单号:</view>
                                <view class="info-value">
                                    <text class="tag tag-info">{{orderDetl.orderNo || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">料号:</view>
                                <view class="info-value">
                                    <text class="tag tag-primary">{{orderDetl.matnr || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">批号:</view>
                                <view class="info-value">
                                    <text class="tag tag-warning">{{orderDetl.batch || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">库位号:</view>
                                <view class="info-value">
                                    <text class="tag tag-warning">{{orderDetl.locNo || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">可用数量:</view>
                                <view class="info-value">
                                    <text class="quantity-text">{{orderDetl.anfme}}</text>
                                    <text class="unit-text">个</text>
                                </view>
                            </view>
                        </view>
                        <view v-if="orderDetl.frozen === 0" class="card-checkbox">
                            <view class="checkbox-wrapper" :class="{ 'checked': orderDetl.checked }">
                                <uni-icons v-if="orderDetl.checked" type="checkmarkempty" size="20" color="#ffffff"></uni-icons>
                            </view>
                        </view>
                        <view v-else>
                            <view>库存不足</view>
                        </view>
                    </view>
                </view>
                <!-- 空状态 -->
                <view v-if="filteredList.length === 0 && dataList.length > 0" class="empty-state">
                    <uni-icons type="search" size="80" color="#e4e7ed"></uni-icons>
                    <text class="empty-text">没有匹配 "{{filterMatnr}}" 的物料</text>
                </view>
                <view v-else-if="dataList.length === 0" class="empty-state">
                    <uni-icons type="document" size="80" color="#e4e7ed"></uni-icons>
                    <text class="empty-text">请先选择订单</text>
                </view>
                <!-- 底部提示 -->
                <view class="bottom-tip" v-if="filteredList.length > 0">
                    <text>- 已经到底了 -</text>
                </view>
            </view>
        </scroll-view>
        <!-- 底部操作按钮 -->
        <view class="bottom-bar">
            <button class="btn-submit" size="default" type="primary" @click="addItems()">
                <uni-icons type="checkmarkempty" size="18" color="#ffffff"></uni-icons>
                <text>提取选中物料</text>
            </button>
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                baseUrl: '',
                token: '',
                storeId: 0,
                store: '',
                total: 0,
                searchType: '订单',
                searchValue: '',
                dataList: [],
                filteredList: [],
                selectedList: [],
                matnr: '',
                orderNo: '',
                orderNoList: [],
                seltitle: '全选',
                filterMatnr: '',
                idList: [],
            }
        },
        onShow() {
            let _this = this
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            this.storeId = uni.getStorageSync('store')
            if (this.storeId == 1) {
                this.store = '宁波仓'
            }
            if (this.storeId == 2) {
                this.store = '新昌仓'
            }
            const eventChannel = this.getOpenerEventChannel();
            eventChannel.on('item', function(data) {
                _this.matnr = data.item.matnr
                _this.getMatList()
            })
            this.getOrderNoList()
        },
        methods: {
            onFilterInput() {
                this.applyFilter()
            },
            applyFilter() {
                if (!this.filterMatnr || this.filterMatnr.trim() === '') {
                    this.filteredList = [...this.dataList]
                } else {
                    const keyword = this.filterMatnr.trim().toLowerCase()
                    this.filteredList = this.dataList.filter(item => {
                        return item.matnr && item.matnr.toLowerCase().includes(keyword)
                    })
                }
                this.updateSelectAllTitle()
            },
            clearFilter() {
                this.filterMatnr = ''
                this.applyFilter()
            },
            updateSelectAllTitle() {
                if (this.filteredList.length === 0) {
                    this.seltitle = '全选'
                    return
                }
                const allChecked = this.filteredList.every(item => item.checked === true)
                this.seltitle = allChecked ? '取消全选' : '全选'
            },
            toggleSelect(item) {
                this.checkboxChange(item)
            },
            addItems() {
                let pickList = []
                for (let k of this.dataList) {
                    if (k.checked) {
                        pickList.push(k)
                    }
                }
                if (pickList.length === 0) {
                    uni.showToast({
                        title: '请至少选择一个物料',
                        icon: "none",
                        position: 'center'
                    })
                    return
                }
                this.getOpenerEventChannel().emit('pickList', {data: pickList});
                uni.navigateBack({})
            },
            checkboxChange(e) {
                if (e.checked) {
                    this.$set(e, 'checked', false)
                } else {
                    this.$set(e, 'checked', true)
                }
                this.updateSelectAllTitle()
            },
            allSelect() {
                const targetList = this.filteredList
                if (this.seltitle == '全选') {
                    for (let k of targetList) {
                        k.checked = true
                    }
                    this.seltitle = '取消全选'
                } else {
                    for (let k of targetList) {
                        k.checked = false
                    }
                    this.seltitle = '全选'
                }
            },
            getOrderDet() {
                let that = this
                that.idList = []
                uni.request({
                    url: that.baseUrl + '/orderDetlPakout/list/auth',
                    data: {orderNo: that.orderNo},
                    method: 'GET',
                    success(res) {
                        res = res.data;
                        if (res.code === 200) {
                            for (var i = 0; i < res.data.length; i++) {
                                if (res.data[i].id) {  // 确保 id 存在
                                    that.idList.push(res.data[i].id)
                                }
                            }
                            console.info(that.idList)
                            // 在第一个请求成功后,再发起第二个请求
                            that.previewPakout()
                        }
                    }
                })
            },
            previewPakout(){
                let that = this
                uni.request({
                    url:that.baseUrl + '/out/pakout/preview/auth',
                    data:that.idList,
                    method:'POST',
                    header: {
                        'Content-Type': 'application/json',  // 关键:添加这行
                        'token': that.token                   // 添加 token 认证
                    },
                    success(res) {
                        console.info('原始 res:', res)
                        console.info('res.data 类型:', typeof res.data)
                        console.info('res.data 内容:', res.data)
                        // 关键:如果 res.data 是字符串,需要解析
                        let result = res.data
                        if (typeof result === 'string') {
                            result = JSON.parse(result)
                            console.info('解析后的 result:', result)
                        }
                        if (result.code === 200) {
                            // 直接赋值,不要做其他操作
                            that.dataList = result.data
                            console.info('赋值后的 dataList:', JSON.parse(JSON.stringify(that.dataList)))
                            // 添加 checked 属性
                            if (that.dataList && that.dataList.length > 0) {
                                for (var i = 0; i < that.dataList.length; i++) {
                                    that.$set(that.dataList[i], 'checked', false)
                                }
                                that.applyFilter()
                            }
                        }
                    }
                })
            },
            getOrderNoList() {
                let that = this
                uni.request({
                    url: this.baseUrl + '/order/pakout/order/nav/list/auth',
                    header: {
                        'token': uni.getStorageSync('token')
                    },
                    method: 'POST',
                    success(res) {
                        res = res.data
                        console.log(res)
                        if (res.code == 403) {
                            uni.showToast({ title: res.msg, icon: "error", position: 'center' })
                            setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1000);
                        }
                        for (var i = 0; i < res.data.length; i++) {
                            that.orderNoList.push(res.data[i].orderNo)
                        }
                    }
                })
            },
            clear() {
                this.searchValue = ''
                this.getOrderNoList(this.locNo)
            },
            back() {
                uni.navigateBack({})
            },
            set(e) {
                var ck = this.dataList[e].checked
                this.dataList[e].checked = ck ? false : true
                this.updateSelectAllTitle()
            },
            getMatList() {
                let that = this
                let searchParam = {
                    orderNo: that.searchValue,
                    matnr: that.matnr,
                }
                console.log(searchParam);
                uni.request({
                    url: that.baseUrl + '/mobile/outBound/mat/list',
                    header: {
                        'token': uni.getStorageSync('token')
                    },
                    data: searchParam,
                    method: 'GET',
                    success(res) {
                        res = res.data;
                        if (res.code === 200) {
                            that.total = res.data.length
                            const result1 = res.data.filter(obj1 =>
                                !that.selectedList.some(obj2 => obj1.matnr === obj2.matnr && obj1.orderNo === obj2.orderNo)
                            );
                            that.dataList = result1
                            that.total = result1.length
                            that.applyFilter()
                        } else if (res.code == 403) {
                            uni.showToast({ title: res.msg, icon: "error", position: 'center' })
                            setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1000);
                        } else {
                            uni.showToast({ title: res.msg, icon: "error", position: 'center' })
                        }
                    }
                })
            },
            addItem(mat) {
                this.getOpenerEventChannel().emit('sMat', {data: mat});
                uni.navigateBack({})
            }
        },
        watch: {
            filterMatnr() {
                this.applyFilter()
            }
        }
    }
</script>
<style scoped>
/* 全局样式 */
.container {
    min-height: 100vh;
    background-color: #f5f7fa;
}
.status_bar {
    height: var(--status-bar-height);
    width: 100%;
    background-color: #ffffff;
}
/* 筛选卡片 */
.filter-card {
    background: #ffffff;
    margin: 24rpx;
    border-radius: 24rpx;
    overflow: hidden;
    box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.filter-item {
    display: flex;
    align-items: center;
    padding: 24rpx 32rpx;
    border-bottom: 1px solid #f0f0f0;
}
.filter-item:last-child {
    border-bottom: none;
}
.filter-label {
    width: 140rpx;
    display: flex;
    align-items: center;
    gap: 12rpx;
    font-size: 28rpx;
    color: #303133;
    font-weight: 500;
}
.filter-input {
    flex: 1;
}
.filter-input-field {
    background: #f5f7fa;
    padding: 16rpx 20rpx;
    border-radius: 12rpx;
    font-size: 28rpx;
    color: #303133;
    width: 100%;
}
.filter-input-field:focus {
    background: #ffffff;
    box-shadow: 0 0 0 2rpx #409EFF;
}
.filter-clear {
    padding: 0 16rpx;
    display: flex;
    align-items: center;
    justify-content: center;
}
.placeholder-style {
    color: #c0c4cc;
    font-size: 26rpx;
}
.filter-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20rpx 32rpx;
    background: #f8f9fa;
    border-top: 1px solid #f0f0f0;
}
.stat-info {
    display: flex;
    align-items: center;
    gap: 8rpx;
    font-size: 26rpx;
    color: #606266;
}
.select-all-btn {
    padding: 8rpx 24rpx;
    background: #ecf5ff;
    border-radius: 32rpx;
}
.select-all-text {
    font-size: 26rpx;
    color: #409EFF;
    font-weight: 500;
}
/* 滚动区域 */
.scroll-area {
    height: calc(100vh - 420rpx);
    padding: 0 24rpx;
}
/* 物料列表 */
.material-list {
    padding-bottom: 40rpx;
}
.material-card {
    background: #ffffff;
    border-radius: 24rpx;
    margin-bottom: 20rpx;
    overflow: hidden;
    box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
    transition: all 0.3s ease;
}
.material-card:active {
    transform: scale(0.98);
}
.card-content {
    display: flex;
    padding: 24rpx;
}
.card-info {
    flex: 1;
}
.info-row {
    display: flex;
    align-items: center;
    margin-bottom: 16rpx;
    font-size: 28rpx;
}
.info-row:last-child {
    margin-bottom: 0;
}
.info-label {
    width: 140rpx;
    color: #909399;
    font-size: 26rpx;
}
.info-value {
    flex: 1;
    color: #606266;
    font-size: 28rpx;
    word-break: break-all;
}
.serial-number {
    color: #409EFF;
    font-weight: 600;
}
/* 标签样式 */
.tag {
    display: inline-block;
    padding: 6rpx 16rpx;
    border-radius: 8rpx;
    font-size: 24rpx;
    font-weight: 500;
}
.tag-primary {
    background: #ecf5ff;
    color: #409EFF;
}
.tag-info {
    background: #f0f9ff;
    color: #67C23A;
}
.tag-warning {
    background: #fdf6ec;
    color: #E6A23C;
}
.quantity-text {
    font-size: 32rpx;
    font-weight: 600;
    color: #F56C6C;
}
.unit-text {
    font-size: 24rpx;
    color: #909399;
    margin-left: 8rpx;
}
/* 复选框样式 */
.card-checkbox {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-left: 20rpx;
    margin-left: 20rpx;
    border-left: 2rpx solid #f0f0f0;
}
.checkbox-wrapper {
    width: 44rpx;
    height: 44rpx;
    border-radius: 50%;
    border: 2rpx solid #dcdfe6;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
    background: #ffffff;
}
.checkbox-wrapper.checked {
    background: #409EFF;
    border-color: #409EFF;
}
/* 空状态 */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 120rpx 0;
}
.empty-text {
    font-size: 28rpx;
    color: #c0c4cc;
    margin-top: 24rpx;
}
/* 底部提示 */
.bottom-tip {
    text-align: center;
    padding: 40rpx 0;
    color: #c0c4cc;
    font-size: 24rpx;
}
/* 底部按钮栏 */
.bottom-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 20rpx 32rpx;
    padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
    background: #ffffff;
    box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
    z-index: 20;
}
.btn-submit {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12rpx;
    height: 88rpx;
    border-radius: 48rpx;
    font-size: 30rpx;
    font-weight: 500;
    background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
    color: #ffffff;
    border: none;
    box-shadow: 0 8rpx 20rpx rgba(64, 158, 255, 0.3);
    transition: all 0.3s ease;
}
.btn-submit:active {
    transform: scale(0.98);
    box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
}
</style>
pages/order/callReqOutbound.vue
New file
@@ -0,0 +1,902 @@
<template>
    <view class="container">
        <!-- 搜索筛选卡片 -->
        <view class="filter-card">
            <!-- 订单选择 -->
            <view class="filter-item">
                <view class="filter-label">
                    <uni-icons type="document" size="18" color="#409EFF"></uni-icons>
                    <text>订单号</text>
                </view>
                <view class="filter-input">
                    <uni-combox :candidates="orderNoList" placeholder="请选择订单" v-model="orderNo" @input="getOrderDet"></uni-combox>
                </view>
            </view>
            <!-- 物料编号过滤 -->
            <view class="filter-item">
                <view class="filter-label">
                    <uni-icons type="scan" size="18" color="#409EFF"></uni-icons>
                    <text>物料编号</text>
                </view>
                <view class="filter-input">
                    <input
                        type="text"
                        v-model="filterMatnr"
                        placeholder="输入物料编号过滤"
                        @input="onFilterInput"
                        class="filter-input-field"
                        placeholder-class="placeholder-style"
                    />
                </view>
                <view v-if="filterMatnr" class="filter-clear" @click="clearFilter">
                    <uni-icons type="close" size="18" color="#909399"></uni-icons>
                </view>
            </view>
            <!-- 统计和全选栏 -->
            <view class="filter-footer">
                <view class="stat-info">
                    <uni-icons type="list" size="16" color="#909399"></uni-icons>
                    <text>{{filterMatnr ? '过滤结果' : '全部物料'}}:{{filteredList.length}} 条</text>
                </view>
                <view class="select-all-btn" @click="allSelect">
                    <text class="select-all-text">{{seltitle}}</text>
                </view>
            </view>
        </view>
        <!-- 物料列表 -->
        <scroll-view class="scroll-area" scroll-y :show-scrollbar="false">
            <view class="material-list">
                <view class="material-card" v-for="(orderDetl,index) in filteredList" :key="index" @click="toggleSelect(orderDetl)">
                    <view class="card-content">
                        <view class="card-info">
                            <view class="info-row">
                                <view class="info-label">序号:</view>
                                <view class="info-value">
                                    <text class="serial-number">{{index + 1}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">出库口:</view>
                                <view class="info-value">
                                    <uni-combox :candidates="orderDetl.staNos || []" placeholder="请选择出库口" v-model="orderDetl.selectedStaNo" @click.stop></uni-combox>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">订单号:</view>
                                <view class="info-value">
                                    <text class="tag tag-info">{{orderDetl.orderNo || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">料号:</view>
                                <view class="info-value">
                                    <text class="tag tag-primary">{{orderDetl.matnr || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">批号:</view>
                                <view class="info-value">
                                    <text class="tag tag-warning">{{orderDetl.batch || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">库位号:</view>
                                <view class="info-value">
                                    <text class="tag tag-warning">{{orderDetl.locNo || '-'}}</text>
                                </view>
                            </view>
                            <view class="info-row">
                                <view class="info-label">可用数量:</view>
                                <view class="info-value">
                                    <text class="quantity-text">{{orderDetl.anfme || 0}}</text>
                                    <text class="unit-text">个</text>
                                </view>
                            </view>
                        </view>
                        <view v-if="orderDetl.frozen === 0" class="card-checkbox" @click.stop>
                            <view class="checkbox-wrapper" :class="{ 'checked': orderDetl.checked }">
                                <uni-icons v-if="orderDetl.checked" type="checkmarkempty" size="20" color="#ffffff"></uni-icons>
                            </view>
                        </view>
                        <view v-else class="disabled-wrapper" @click.stop>
                            <view class="disabled-tag">
                                <text>库存不足</text>
                            </view>
                        </view>
                    </view>
                </view>
                <!-- 空状态 -->
                <view v-if="filteredList.length === 0 && dataList.length > 0" class="empty-state">
                    <uni-icons type="search" size="80" color="#e4e7ed"></uni-icons>
                    <text class="empty-text">没有匹配 "{{filterMatnr}}" 的物料</text>
                </view>
                <view v-else-if="dataList.length === 0 && !loading" class="empty-state">
                    <uni-icons type="document" size="80" color="#e4e7ed"></uni-icons>
                    <text class="empty-text">请先选择订单</text>
                </view>
                <!-- 加载状态 -->
                <view v-if="loading" class="loading-state">
                    <uni-load-more status="loading"></uni-load-more>
                </view>
                <!-- 底部提示 -->
                <view class="bottom-tip" v-if="filteredList.length > 0 && !loading">
                    <text>- 已经到底了 -</text>
                </view>
            </view>
        </scroll-view>
        <!-- 底部操作按钮 -->
        <view class="bottom-bar">
            <button class="btn-submit" size="default" type="primary" @click="reset()">
                <text>重置</text>
            </button>
            <button class="btn-submit" size="default" type="primary" @click="addItems()">
                <uni-icons type="checkmarkempty" size="18" color="#ffffff"></uni-icons>
                <text>出库选中物料</text>
            </button>
        </view>
    </view>
</template>
<script>
    export default {
        data() {
            return {
                baseUrl: '',
                token: '',
                storeId: 0,
                store: '',
                total: 0,
                searchType: '订单',
                searchValue: '',
                dataList: [],
                filteredList: [],
                selectedList: [],
                matnr: '',
                orderNo: '',
                orderNoList: [],
                seltitle: '全选',
                filterMatnr: '',
                idList: [],
                loading: false,
            }
        },
        computed: {
            selectedCount() {
                return this.dataList.filter(item => item.checked).length
            }
        },
        onShow() {
            let _this = this
            this.baseUrl = uni.getStorageSync('baseUrl');
            this.token = uni.getStorageSync('token');
            this.storeId = uni.getStorageSync('store')
            if (this.storeId == 1) {
                this.store = '宁波仓'
            }
            if (this.storeId == 2) {
                this.store = '新昌仓'
            }
            const eventChannel = this.getOpenerEventChannel();
            eventChannel.on('item', function(data) {
                _this.matnr = data.item.matnr
                _this.getMatList()
            })
            this.getOrderNoList()
        },
        methods: {
            // 重置选中状态
            reset() {
                for (let k of this.dataList) {
                    this.$set(k, 'checked', false)
                }
                this.orderNo = ''
                this.updateSelectAllTitle()
            },
            onFilterInput() {
                this.applyFilter()
            },
            applyFilter() {
                if (!this.filterMatnr || this.filterMatnr.trim() === '') {
                    this.filteredList = [...this.dataList]
                } else {
                    const keyword = this.filterMatnr.trim().toLowerCase()
                    this.filteredList = this.dataList.filter(item => {
                        return item.matnr && item.matnr.toLowerCase().includes(keyword)
                    })
                }
                this.updateSelectAllTitle()
            },
            clearFilter() {
                this.filterMatnr = ''
                this.applyFilter()
            },
            updateSelectAllTitle() {
                if (this.filteredList.length === 0) {
                    this.seltitle = '全选'
                    return
                }
                const allChecked = this.filteredList.every(item => item.checked === true)
                this.seltitle = allChecked ? '取消全选' : '全选'
            },
            toggleSelect(item) {
                if (item.frozen !== 0) return
                this.checkboxChange(item)
            },
            addItems() {
                    // 收集所有选中的物料
                    let pickList = []
                    for (let k of this.dataList) {
                        if (k.checked) {
                            pickList.push(k)
                        }
                    }
                    if (pickList.length === 0) {
                        uni.showToast({
                            title: '请至少选择一个物料',
                            icon: "none",
                            position: 'center'
                        })
                        return
                    }
                    // 检查是否所有选中的物料都选择了出库口
                    const missingStaNo = pickList.filter(item => {
                        return item.staNos && item.staNos.length > 0 && !item.selectedStaNo
                    })
                    if (missingStaNo.length > 0) {
                        uni.showModal({
                            title: '提示',
                            content: `有 ${missingStaNo.length} 个物料未选择出库口,是否继续?`,
                            confirmText: '继续',
                            cancelText: '取消',
                            success: (res) => {
                                if (res.confirm) {
                                    this.submitPickList(pickList)
                                }
                            }
                        })
                        return
                    }
                    this.submitPickList(pickList)
            },
            // 提交选中的物料列表
            submitPickList(pickList) {
                // 准备提交的数据格式
                const submitData = pickList.map(item => {
                    return {
                        frozen: item.frozen,
                        matnr: item.matnr,              // 物料编号
                        maktx: item.maktx,
                        batch: item.batch,              // 批号
                        locNo: item.locNo,              // 库位号
                        anfme: item.anfme,              // 可用数量
                        orderNo: item.orderNo,          // 订单号
                        staNo: item.selectedStaNo, // 选中的出库口
                        // 添加其他需要的字段
                    }
                })
                console.log('准备出库的物料:', submitData)
                this.outboundRequest(submitData)
            },
            // 直接调用出库接口的方法
            outboundRequest(submitData) {
                uni.showLoading({ title: '出库中...', mask: true })
                uni.request({
                    url: this.baseUrl + '/out/pakout/auth',  // 替换成你的出库接口地址
                    method: 'POST',
                    header: {
                        'Content-Type': 'application/json',
                        'token': this.token
                    },
                    data: {
                        list: submitData      // 选中的物料列表
                    },
                    success(res) {
                        let result = res.data
                        if (typeof result === 'string') {
                            try {
                                result = JSON.parse(result)
                            } catch(e) {
                                console.error('JSON解析失败:', e)
                            }
                        }
                        if (result.code === 200) {
                            uni.showToast({
                                title: `成功出库 ${submitData.length} 个物料`,
                                icon: "success"
                            })
                            // 出库成功后,刷新列表或返回上一页
                            setTimeout(() => {
                                // 刷新当前列表
                                this.getOrderDet()
                                // 或者返回上一页
                                // uni.navigateBack({})
                            }, 1500)
                        } else if (result.code === 403) {
                            uni.showToast({ title: result.msg || '登录已过期', icon: "error" })
                            setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1500);
                        } else {
                            uni.showToast({ title: result.msg || '出库失败', icon: "error" })
                        }
                    },
                    fail(err) {
                        console.error('出库请求失败:', err)
                        uni.showToast({ title: '网络请求失败', icon: "error" })
                    },
                    complete() {
                        uni.hideLoading()
                    }
                })
            },
            checkboxChange(e) {
                if (e.checked) {
                    this.$set(e, 'checked', false)
                } else {
                    this.$set(e, 'checked', true)
                }
                this.updateSelectAllTitle()
            },
            allSelect() {
                const targetList = this.filteredList
                if (this.seltitle == '全选') {
                    for (let k of targetList) {
                        if (k.frozen === 0) {
                            k.checked = true
                        }
                    }
                    this.seltitle = '取消全选'
                } else {
                    for (let k of targetList) {
                        k.checked = false
                    }
                    this.seltitle = '全选'
                }
            },
            getOrderDet() {
                if (!this.orderNo) {
                    uni.showToast({
                        title: '请选择订单号',
                        icon: "none"
                    })
                    return
                }
                let that = this
                that.idList = []
                that.loading = true
                uni.showLoading({ title: '加载中...', mask: true })
                uni.request({
                    url: that.baseUrl + '/orderDetlPakout/list/auth',
                    data: {orderNo: that.orderNo},
                    method: 'GET',
                    success(res) {
                        res = res.data;
                        if (res.code === 200) {
                            for (var i = 0; i < res.data.length; i++) {
                                if (res.data[i].id) {
                                    that.idList.push(res.data[i].id)
                                }
                            }
                            that.previewPakout()
                        } else {
                            uni.hideLoading()
                            that.loading = false
                            uni.showToast({
                                title: res.msg || '加载失败',
                                icon: "error"
                            })
                        }
                    },
                    fail() {
                        uni.hideLoading()
                        that.loading = false
                        uni.showToast({
                            title: '网络请求失败',
                            icon: "error"
                        })
                    }
                })
            },
            previewPakout() {
                let that = this
                uni.request({
                    url: that.baseUrl + '/out/pakout/preview/auth',
                    data: that.idList,
                    method: 'POST',
                    header: {
                        'Content-Type': 'application/json',
                        'token': that.token
                    },
                    success(res) {
                        let result = res.data
                        if (typeof result === 'string') {
                            try {
                                result = JSON.parse(result)
                            } catch(e) {
                                console.error('JSON解析失败:', e)
                            }
                        }
                        if (result.code === 200) {
                            that.dataList = result.data || []
                            if (that.dataList.length > 0) {
                                for (var i = 0; i < that.dataList.length; i++) {
                                    that.$set(that.dataList[i], 'checked', false)
                                    that.$set(that.dataList[i], 'selectedStaNo', '')
                                    if (!that.dataList[i].staNos) {
                                        that.$set(that.dataList[i], 'staNos', [])
                                    }
                                }
                                that.applyFilter()
                            }
                            uni.showToast({
                                title: `加载成功,共${that.dataList.length}个物料`,
                                icon: "success",
                                duration: 1500
                            })
                        } else if (result.code == 403) {
                            uni.showToast({ title: result.msg || '登录已过期', icon: "error" })
                            setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1500);
                        } else {
                            uni.showToast({ title: result.msg || '预览失败', icon: "error" })
                        }
                    },
                    fail(err) {
                        console.error('预览请求失败:', err)
                        uni.showToast({ title: '网络请求失败', icon: "error" })
                    },
                    complete() {
                        uni.hideLoading()
                        that.loading = false
                    }
                })
            },
            getOrderNoList() {
                let that = this
                uni.request({
                    url: this.baseUrl + '/order/pakout/order/nav/list/auth',
                    header: {
                        'token': uni.getStorageSync('token')
                    },
                    method: 'POST',
                    success(res) {
                        res = res.data
                        if (res.code == 403) {
                            uni.showToast({ title: res.msg, icon: "error", position: 'center' })
                            setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1000);
                        }
                        if (res.data && res.data.length) {
                            for (var i = 0; i < res.data.length; i++) {
                                that.orderNoList.push(res.data[i].orderNo)
                            }
                        }
                    }
                })
            },
            clear() {
                this.searchValue = ''
                this.getOrderNoList(this.locNo)
            },
            back() {
                uni.navigateBack({})
            },
            set(e) {
                var ck = this.dataList[e].checked
                this.dataList[e].checked = ck ? false : true
                this.updateSelectAllTitle()
            },
            getMatList() {
                let that = this
                let searchParam = {
                    orderNo: that.searchValue,
                    matnr: that.matnr,
                }
                that.loading = true
                uni.showLoading({ title: '加载中...', mask: true })
                uni.request({
                    url: that.baseUrl + '/mobile/outBound/mat/list',
                    header: {
                        'token': uni.getStorageSync('token')
                    },
                    data: searchParam,
                    method: 'GET',
                    success(res) {
                        res = res.data;
                        if (res.code === 200) {
                            that.total = res.data.length
                            const result1 = res.data.filter(obj1 =>
                                !that.selectedList.some(obj2 => obj1.matnr === obj2.matnr && obj1.orderNo === obj2.orderNo)
                            );
                            that.dataList = result1
                            that.total = result1.length
                            that.applyFilter()
                        } else if (res.code == 403) {
                            uni.showToast({ title: res.msg, icon: "error", position: 'center' })
                            setTimeout(() => { uni.reLaunch({ url: '../login/login' }); }, 1000);
                        } else {
                            uni.showToast({ title: res.msg, icon: "error", position: 'center' })
                        }
                    },
                    fail() {
                        uni.showToast({ title: '网络请求失败', icon: "error" })
                    },
                    complete() {
                        uni.hideLoading()
                        that.loading = false
                    }
                })
            },
            addItem(mat) {
                this.getOpenerEventChannel().emit('sMat', {data: mat});
                uni.navigateBack({})
            }
        },
        watch: {
            filterMatnr() {
                this.applyFilter()
            }
        }
    }
</script>
<style scoped>
/* 全局样式 */
.container {
    min-height: 100vh;
    background-color: #f5f7fa;
}
.status_bar {
    height: var(--status-bar-height);
    width: 100%;
    background-color: #ffffff;
}
/* 筛选卡片 */
.filter-card {
    background: #ffffff;
    margin: 24rpx;
    border-radius: 24rpx;
    overflow: hidden;
    box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
.filter-item {
    display: flex;
    align-items: center;
    padding: 24rpx 32rpx;
    border-bottom: 1px solid #f0f0f0;
}
.filter-item:last-child {
    border-bottom: none;
}
.filter-label {
    width: 140rpx;
    display: flex;
    align-items: center;
    gap: 12rpx;
    font-size: 28rpx;
    color: #303133;
    font-weight: 500;
}
.filter-input {
    flex: 1;
}
.filter-input-field {
    background: #f5f7fa;
    padding: 16rpx 20rpx;
    border-radius: 12rpx;
    font-size: 28rpx;
    color: #303133;
    width: 100%;
}
.filter-input-field:focus {
    background: #ffffff;
    box-shadow: 0 0 0 2rpx #409EFF;
}
.filter-clear {
    padding: 0 16rpx;
    display: flex;
    align-items: center;
    justify-content: center;
}
.placeholder-style {
    color: #c0c4cc;
    font-size: 26rpx;
}
.filter-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 20rpx 32rpx;
    background: #f8f9fa;
    border-top: 1px solid #f0f0f0;
}
.stat-info {
    display: flex;
    align-items: center;
    gap: 8rpx;
    font-size: 26rpx;
    color: #606266;
}
.select-all-btn {
    padding: 8rpx 24rpx;
    background: #ecf5ff;
    border-radius: 32rpx;
}
.select-all-text {
    font-size: 26rpx;
    color: #409EFF;
    font-weight: 500;
}
/* 滚动区域 */
.scroll-area {
    height: calc(100vh - 420rpx);
    padding: 0 24rpx;
}
/* 物料列表 */
.material-list {
    padding-bottom: 40rpx;
}
.material-card {
    background: #ffffff;
    border-radius: 24rpx;
    margin-bottom: 20rpx;
    overflow: hidden;
    box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
    transition: all 0.3s ease;
}
.material-card:active {
    transform: scale(0.98);
}
.card-content {
    display: flex;
    padding: 24rpx;
}
.card-info {
    flex: 1;
}
.info-row {
    display: flex;
    align-items: center;
    margin-bottom: 16rpx;
    font-size: 28rpx;
}
.info-row:last-child {
    margin-bottom: 0;
}
.info-label {
    width: 140rpx;
    color: #909399;
    font-size: 26rpx;
}
.info-value {
    flex: 1;
    color: #606266;
    font-size: 28rpx;
    word-break: break-all;
}
.serial-number {
    color: #409EFF;
    font-weight: 600;
}
/* 标签样式 */
.tag {
    display: inline-block;
    padding: 6rpx 16rpx;
    border-radius: 8rpx;
    font-size: 24rpx;
    font-weight: 500;
}
.tag-primary {
    background: #ecf5ff;
    color: #409EFF;
}
.tag-info {
    background: #f0f9ff;
    color: #67C23A;
}
.tag-warning {
    background: #fdf6ec;
    color: #E6A23C;
}
.quantity-text {
    font-size: 32rpx;
    font-weight: 600;
    color: #F56C6C;
}
.unit-text {
    font-size: 24rpx;
    color: #909399;
    margin-left: 8rpx;
}
/* 复选框样式 */
.card-checkbox {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-left: 20rpx;
    margin-left: 20rpx;
    border-left: 2rpx solid #f0f0f0;
}
.checkbox-wrapper {
    width: 44rpx;
    height: 44rpx;
    border-radius: 50%;
    border: 2rpx solid #dcdfe6;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s ease;
    background: #ffffff;
}
.checkbox-wrapper.checked {
    background: #409EFF;
    border-color: #409EFF;
}
/* 库存不足样式 */
.disabled-wrapper {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-left: 20rpx;
    margin-left: 20rpx;
    border-left: 2rpx solid #f0f0f0;
}
.disabled-tag {
    padding: 8rpx 16rpx;
    background: #fef0f0;
    border-radius: 8rpx;
}
.disabled-tag text {
    font-size: 24rpx;
    color: #F56C6C;
}
/* 空状态 */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 120rpx 0;
}
.empty-text {
    font-size: 28rpx;
    color: #c0c4cc;
    margin-top: 24rpx;
}
/* 加载状态 */
.loading-state {
    padding: 60rpx 0;
}
/* 底部提示 */
.bottom-tip {
    text-align: center;
    padding: 40rpx 0;
    color: #c0c4cc;
    font-size: 24rpx;
}
/* 底部按钮栏 */
.bottom-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 20rpx 32rpx;
    display: flex;
    flex-direction: row;
    padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
    background: #ffffff;
    box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
    z-index: 20;
}
.btn-submit {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12rpx;
    height: 88rpx;
    border-radius: 48rpx;
    font-size: 30rpx;
    font-weight: 500;
    background: linear-gradient(135deg, #409EFF 0%, #66b1ff 100%);
    color: #ffffff;
    border: none;
    box-shadow: 0 8rpx 20rpx rgba(64, 158, 255, 0.3);
    transition: all 0.3s ease;
    position: relative;
}
.btn-submit:active {
    transform: scale(0.98);
    box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
}
.selected-badge {
    position: absolute;
    top: -12rpx;
    right: -12rpx;
    background: #F56C6C;
    color: #ffffff;
    font-size: 22rpx;
    padding: 4rpx 12rpx;
    border-radius: 32rpx;
    min-width: 40rpx;
    text-align: center;
}
</style>