| | |
| | | <template> |
| | | <view class="page-container"> |
| | | <!-- 订单信息头部 --> |
| | | <view class="order-header" v-if="order"> |
| | | <view |
| | | class="order-header" |
| | | v-if="order" |
| | | > |
| | | <view class="header-content"> |
| | | <view class="header-row"> |
| | | <text class="header-label">单据号</text> |
| | | <text class="header-value">{{order.code}}</text> |
| | | <text class="header-value">{{ order.code }}</text> |
| | | </view> |
| | | <view class="header-row"> |
| | | <text class="header-label">单据类型</text> |
| | | <text class="header-value">{{order.wkType$ || '-'}}</text> |
| | | <text class="header-value">{{ order.wkType$ || '-' }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <!-- 搜索框 --> |
| | | <!-- <view class="search-bar"> |
| | | <uni-search-bar v-model="condition" placeholder=" 扫码 / 输入物料" bgColor="#F5F5F5" @confirm="search" @cancel="onCancelSearch" /> |
| | | </view> --> |
| | | |
| | | |
| | | <!-- 明细列表 --> |
| | | <view class="padding-lr margin-top-sm"> |
| | | <block v-for="(item, index) in filterList" :key="index"> |
| | | <view class="cu-list menu sm-border margin-bottom-sm" @click="chose(item)"> |
| | | <block |
| | | v-for="(item, index) in filterList" |
| | | :key="index" |
| | | > |
| | | <view |
| | | class="cu-list menu sm-border margin-bottom-sm" |
| | | @click="chose(item)" |
| | | > |
| | | <view class="cu-bar bg-white solid-bottom"> |
| | | <view class="action"> |
| | | <view class="index">{{index+1}}</view> |
| | | <view class="index">{{ index + 1 }}</view> |
| | | <view class="text-blue"> |
| | | 编码: {{item.matnrCode}} |
| | | 编码: {{ item.matnrCode }} |
| | | </view> |
| | | </view> |
| | | <view class="action"> |
| | | <text :class="getRemaining(item) > 0 ? 'text-blue' : 'text-green'"> |
| | | {{getRemaining(item) > 0 ? '剩余 ' + getRemaining(item) : '已完成'}} |
| | | <text |
| | | :class=" |
| | | getRemaining(item) > 0 |
| | | ? 'text-blue' |
| | | : 'text-green' |
| | | " |
| | | > |
| | | {{ |
| | | getRemaining(item) > 0 |
| | | ? '剩余 ' + getRemaining(item) |
| | | : '已完成' |
| | | }} |
| | | </text> |
| | | </view> |
| | | </view> |
| | | <view class="cu-item"> |
| | | <view class="content"> |
| | | <text class="text-black">物料名称:</text> |
| | | <text class="text-grey text-sm margin-left-xs">{{item.maktx || '-'}}</text> |
| | | <text class="text-grey text-sm margin-left-xs"> |
| | | {{ item.maktx || '-' }} |
| | | </text> |
| | | </view> |
| | | </view> |
| | | <view class="cu-item"> |
| | | <view class="content"> |
| | | <text class="text-black">规格:</text> |
| | | <text class="text-grey margin-left-xs">{{item.specs || '-'}}</text> |
| | | <text class="text-grey margin-left-xs"> |
| | | {{ item.specs || '-' }} |
| | | </text> |
| | | </view> |
| | | <view class="action"> |
| | | <text class="text-black">批次:</text> |
| | | <text class="text-grey margin-left-xs">{{item.splrBatch || '-'}}</text> |
| | | <text class="text-grey margin-left-xs"> |
| | | {{ item.splrBatch || '-' }} |
| | | </text> |
| | | </view> |
| | | </view> |
| | | <view class="cu-item"> |
| | | <view class="content"> |
| | | <text class="text-black">订单数量:</text> |
| | | <text class="text-blue margin-left-xs">{{item.anfme}}</text> |
| | | <text class="text-blue margin-left-xs"> |
| | | {{ item.anfme }} |
| | | </text> |
| | | </view> |
| | | <view class="action"> |
| | | <text class="text-black">已完成:</text> |
| | | <text class="text-green margin-left-xs">{{item.qty}}</text> |
| | | <text class="text-green margin-left-xs"> |
| | | {{ item.qty }} |
| | | </text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </block> |
| | | </view> |
| | | |
| | | |
| | | <!-- 空状态 --> |
| | | <view class="empty-state" v-if="filterList.length === 0 && !loading"> |
| | | <uni-icons type="info" size="60" color="#CCCCCC"></uni-icons> |
| | | <view |
| | | class="empty-state" |
| | | v-if="filterList.length === 0 && !loading" |
| | | > |
| | | <uni-icons |
| | | type="info" |
| | | size="60" |
| | | color="#CCCCCC" |
| | | ></uni-icons> |
| | | <text class="empty-text">暂无明细数据</text> |
| | | </view> |
| | | |
| | | |
| | | <!-- 统计信息 --> |
| | | <view class="stats-bar" v-if="menuList.length > 0"> |
| | | <view |
| | | class="stats-bar" |
| | | v-if="menuList.length > 0" |
| | | > |
| | | <view class="stats-item"> |
| | | <text class="stats-value">{{menuList.length}}</text> |
| | | <text class="stats-value">{{ menuList.length }}</text> |
| | | <text class="stats-label">总明细</text> |
| | | </view> |
| | | <view class="stats-divider"></view> |
| | | <view class="stats-item"> |
| | | <text class="stats-value">{{pendingCount}}</text> |
| | | <text class="stats-value">{{ pendingCount }}</text> |
| | | <text class="stats-label">待处理</text> |
| | | </view> |
| | | <view class="stats-divider"></view> |
| | | <view class="stats-item"> |
| | | <text class="stats-value">{{completedCount}}</text> |
| | | <text class="stats-value">{{ completedCount }}</text> |
| | | <text class="stats-label">已完成</text> |
| | | </view> |
| | | </view> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { request } from '@/common/request.js' |
| | | export default { |
| | | data() { |
| | | return { |
| | | data: '', |
| | | condition: '', |
| | | menuList: [], |
| | | order: '', |
| | | loading: false, |
| | | import { request } from '@/common/request.js' |
| | | export default { |
| | | data() { |
| | | return { |
| | | data: '', |
| | | condition: '', |
| | | menuList: [], |
| | | order: '', |
| | | loading: false |
| | | } |
| | | }, |
| | | computed: { |
| | | // 过滤后的列表(优先显示有剩余数量的) |
| | | filterList() { |
| | | if (!this.condition.trim()) { |
| | | // 排序:有剩余数量的排前面 |
| | | return [...this.menuList].sort((a, b) => { |
| | | if (a.ableQty > 0 && b.ableQty <= 0) return -1 |
| | | if (a.ableQty <= 0 && b.ableQty > 0) return 1 |
| | | return 0 |
| | | }) |
| | | } |
| | | const keyword = this.condition.toLowerCase() |
| | | return this.menuList.filter((item) => { |
| | | return ( |
| | | (item.matnr && |
| | | item.matnr.toLowerCase().includes(keyword)) || |
| | | (item.maktx && |
| | | item.maktx.toLowerCase().includes(keyword)) || |
| | | (item.batch && item.batch.toLowerCase().includes(keyword)) |
| | | ) |
| | | }) |
| | | }, |
| | | computed: { |
| | | // 过滤后的列表(优先显示有剩余数量的) |
| | | filterList() { |
| | | if (!this.condition.trim()) { |
| | | // 排序:有剩余数量的排前面 |
| | | return [...this.menuList].sort((a, b) => { |
| | | if (a.ableQty > 0 && b.ableQty <= 0) return -1; |
| | | if (a.ableQty <= 0 && b.ableQty > 0) return 1; |
| | | return 0; |
| | | }); |
| | | } |
| | | const keyword = this.condition.toLowerCase(); |
| | | return this.menuList.filter(item => { |
| | | return (item.matnr && item.matnr.toLowerCase().includes(keyword)) || |
| | | (item.maktx && item.maktx.toLowerCase().includes(keyword)) || |
| | | (item.batch && item.batch.toLowerCase().includes(keyword)); |
| | | }); |
| | | }, |
| | | // 待处理数量 |
| | | pendingCount() { |
| | | return this.menuList.filter(item => item.enableQty > 0).length; |
| | | }, |
| | | // 已完成数量 |
| | | completedCount() { |
| | | return this.menuList.filter(item => item.enableQty <= 0).length; |
| | | // 待处理数量 |
| | | pendingCount() { |
| | | return this.menuList.filter((item) => item.enableQty > 0).length |
| | | }, |
| | | // 已完成数量 |
| | | completedCount() { |
| | | return this.menuList.filter((item) => item.enableQty <= 0).length |
| | | } |
| | | }, |
| | | onLoad() { |
| | | let that = this |
| | | const eventChannel = this.getOpenerEventChannel() |
| | | if (eventChannel) { |
| | | eventChannel.on('data', function (data) { |
| | | that.order = data.data |
| | | that.getOrderNoList(that.order) |
| | | }) |
| | | } |
| | | }, |
| | | onShow() { |
| | | if (this.order) { |
| | | this.getOrderNoList(this.order) |
| | | } |
| | | }, |
| | | methods: { |
| | | // 获取剩余数量 |
| | | getRemaining(item) { |
| | | if (item.ableQty !== undefined && item.ableQty !== null) { |
| | | return Number(item.ableQty) |
| | | } |
| | | // 降级逻辑:订单数量 - 已完成数量 |
| | | return Number(item.anfme || 0) - Number(item.qty || 0) |
| | | }, |
| | | onLoad() { |
| | | let that = this; |
| | | const eventChannel = this.getOpenerEventChannel(); |
| | | if (eventChannel) { |
| | | eventChannel.on('data', function(data) { |
| | | that.order = data.data; |
| | | that.getOrderNoList(that.order); |
| | | }); |
| | | // 搜索 |
| | | async search() { |
| | | if (!this.condition.trim()) { |
| | | this.getOrderNoList(this.order) |
| | | return |
| | | } |
| | | }, |
| | | onShow() { |
| | | if (this.order) { |
| | | this.getOrderNoList(this.order); |
| | | } |
| | | }, |
| | | methods: { |
| | | // 获取剩余数量 |
| | | getRemaining(item) { |
| | | if (item.ableQty !== undefined && item.ableQty !== null) { |
| | | return Number(item.ableQty); |
| | | } |
| | | // 降级逻辑:订单数量 - 已完成数量 |
| | | return Number(item.anfme || 0) - Number(item.qty || 0); |
| | | }, |
| | | // 搜索 |
| | | async search() { |
| | | if (!this.condition.trim()) { |
| | | this.getOrderNoList(this.order); |
| | | return; |
| | | } |
| | | this.loading = true; |
| | | try { |
| | | const res = await request('/orderDetl/search/pda/auth', { |
| | | this.loading = true |
| | | try { |
| | | const res = await request( |
| | | '/orderDetl/search/pda/auth', |
| | | { |
| | | condition: this.condition, |
| | | order: this.order.code |
| | | }, 'POST', true); |
| | | |
| | | if (res.code === 200) { |
| | | let list = res.data || []; |
| | | list.forEach(item => { |
| | | if (item.enableQty === undefined || item.enableQty === null) { |
| | | item.enableQty = Number(item.anfme || 0) - Number(item.qty || 0); |
| | | } |
| | | }); |
| | | this.menuList = list; |
| | | } else if (res.code === 403) { |
| | | uni.showToast({ title: res.msg, icon: "none", position: 'top' }); |
| | | setTimeout(() => { |
| | | uni.reLaunch({ url: '../login/login' }); |
| | | }, 1000); |
| | | } else { |
| | | uni.showToast({ title: res.msg, icon: "none", position: 'top' }); |
| | | } |
| | | } catch (err) { |
| | | // request.js 已经处理了错误提示 |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | // 取消搜索 |
| | | onCancelSearch() { |
| | | this.condition = ''; |
| | | this.getOrderNoList(this.order); |
| | | }, |
| | | // 获取订单明细列表 |
| | | async getOrderNoList(order) { |
| | | if (!order || !order.code) return; |
| | | this.loading = true; |
| | | try { |
| | | const res = await request('/orderOut/detlList', { |
| | | orderNo: order.code |
| | | }, 'GET', true); |
| | | |
| | | if (res.code === 200) { |
| | | let list = res.data || []; |
| | | list.forEach(item => { |
| | | if (item.enableQty === undefined || item.enableQty === null) { |
| | | item.enableQty = Number(item.anfme || 0) - Number(item.qty || 0); |
| | | } |
| | | }); |
| | | this.menuList = list; |
| | | } else { |
| | | this.menuList = res.data || []; |
| | | } |
| | | } catch (err) { |
| | | // request.js 已经处理了错误提示 |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | // 选择明细进行出库 |
| | | chose(item) { |
| | | if (item.enableQty <= 0) { |
| | | uni.showToast({ title: '该明细已完成', icon: "none", position: 'top' }); |
| | | return; |
| | | } |
| | | let that = this; |
| | | uni.navigateTo({ |
| | | url: "./outLocView", |
| | | success: function(res) { |
| | | res.eventChannel.emit('orderItem', { |
| | | item: item |
| | | }); |
| | | }, |
| | | events: { |
| | | acceptDataFromOpenedPage: function(data) { |
| | | // 返回后刷新数据 |
| | | }, |
| | | }, |
| | | }); |
| | | 'POST', |
| | | true |
| | | ) |
| | | |
| | | if (res.code === 200) { |
| | | let list = res.data || [] |
| | | list.forEach((item) => { |
| | | if ( |
| | | item.ableQty === undefined || |
| | | item.ableQty === null |
| | | ) { |
| | | item.ableQty = |
| | | Number(item.anfme || 0) - Number(item.qty || 0) |
| | | } |
| | | }) |
| | | this.menuList = list |
| | | } else if (res.code === 403) { |
| | | uni.showToast({ |
| | | title: res.msg, |
| | | icon: 'none', |
| | | position: 'top' |
| | | }) |
| | | setTimeout(() => { |
| | | uni.reLaunch({ url: '../login/login' }) |
| | | }, 1000) |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.msg, |
| | | icon: 'none', |
| | | position: 'top' |
| | | }) |
| | | } |
| | | } catch (err) { |
| | | // request.js 已经处理了错误提示 |
| | | } finally { |
| | | this.loading = false |
| | | } |
| | | }, |
| | | // 取消搜索 |
| | | onCancelSearch() { |
| | | this.condition = '' |
| | | this.getOrderNoList(this.order) |
| | | }, |
| | | // 获取订单明细列表 |
| | | async getOrderNoList(order) { |
| | | if (!order || !order.code) return |
| | | this.loading = true |
| | | try { |
| | | const res = await request( |
| | | '/orderOut/detlList', |
| | | { |
| | | orderNo: order.code |
| | | }, |
| | | 'GET', |
| | | true |
| | | ) |
| | | |
| | | if (res.code === 200) { |
| | | let list = res.data || [] |
| | | list.forEach((item) => { |
| | | if ( |
| | | item.enableQty === undefined || |
| | | item.enableQty === null |
| | | ) { |
| | | item.enableQty = |
| | | Number(item.anfme || 0) - Number(item.qty || 0) |
| | | } |
| | | }) |
| | | this.menuList = list |
| | | } else { |
| | | this.menuList = res.data || [] |
| | | } |
| | | } catch (err) { |
| | | // request.js 已经处理了错误提示 |
| | | } finally { |
| | | this.loading = false |
| | | } |
| | | }, |
| | | // 选择明细进行出库 |
| | | chose(item) { |
| | | if (item.ableQty <= 0) { |
| | | uni.showToast({ |
| | | title: '该明细已完成', |
| | | icon: 'none', |
| | | position: 'top' |
| | | }) |
| | | return |
| | | } |
| | | let that = this |
| | | uni.navigateTo({ |
| | | url: './outLocView', |
| | | success: function (res) { |
| | | res.eventChannel.emit('orderItem', { |
| | | item: item |
| | | }) |
| | | }, |
| | | events: { |
| | | acceptDataFromOpenedPage: function (data) { |
| | | // 返回后刷新数据 |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | /* 引入公共样式 */ |
| | | @import url('@/static/css/common.scss'); |
| | | /* 引入公共样式 */ |
| | | @import url('@/static/css/common.scss'); |
| | | |
| | | .page-container { |
| | | padding-bottom: 120rpx; |
| | | } |
| | | |
| | | /* 订单头部 */ |
| | | .order-header { |
| | | background: linear-gradient(135deg, #0081ff 0%, #1890ff 100%); |
| | | padding: 16rpx 20rpx; |
| | | } |
| | | |
| | | .header-content { |
| | | background: rgba(255, 255, 255, 0.15); |
| | | border-radius: 10rpx; |
| | | padding: 12rpx 16rpx; |
| | | } |
| | | |
| | | .header-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 4rpx 0; |
| | | } |
| | | |
| | | .header-label { |
| | | font-size: 24rpx; |
| | | color: rgba(255, 255, 255, 0.7); |
| | | } |
| | | |
| | | .header-value { |
| | | font-size: 26rpx; |
| | | color: #ffffff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | /* 搜索栏 */ |
| | | .search-bar { |
| | | padding: 0rpx 8rpx; |
| | | background: #ffffff; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 129, 255, 0.08); |
| | | } |
| | | .page-container { |
| | | padding-bottom: 120rpx; |
| | | } |
| | | |
| | | /* 列表样式迁移 from rece/other.vue */ |
| | | .index { |
| | | border: 1px solid #e54d42; |
| | | color: #e54d42; |
| | | border-radius: 50%; |
| | | display: block; |
| | | width: 50rpx; |
| | | height: 50rpx; |
| | | line-height: 48rpx; |
| | | text-align: center; |
| | | margin-right: 20rpx; |
| | | font-size: 30rpx; |
| | | } |
| | | /* 订单头部 */ |
| | | .order-header { |
| | | background: linear-gradient(135deg, #0081ff 0%, #1890ff 100%); |
| | | padding: 16rpx 20rpx; |
| | | } |
| | | |
| | | .act { |
| | | border: 1px solid #e54d42; |
| | | } |
| | | .header-content { |
| | | background: rgba(255, 255, 255, 0.15); |
| | | border-radius: 10rpx; |
| | | padding: 12rpx 16rpx; |
| | | } |
| | | |
| | | .text-blue { |
| | | color: #0081ff !important; |
| | | } |
| | | |
| | | .text-green { |
| | | color: #39b54a !important; |
| | | } |
| | | |
| | | /* 空状态 */ |
| | | .empty-state { |
| | | padding: 60rpx 0; |
| | | } |
| | | |
| | | .empty-text { |
| | | margin-top: 20rpx; |
| | | } |
| | | |
| | | /* 统计栏 */ |
| | | .stats-bar { |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-around; |
| | | background: #ffffff; |
| | | padding: 16rpx 0; |
| | | box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06); |
| | | } |
| | | |
| | | .stats-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | flex: 1; |
| | | } |
| | | |
| | | .stats-value { |
| | | font-size: 32rpx; |
| | | color: #303133; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .stats-label { |
| | | font-size: 20rpx; |
| | | color: #909399; |
| | | margin-top: 4rpx; |
| | | } |
| | | |
| | | .stats-divider { |
| | | width: 1rpx; |
| | | height: 50rpx; |
| | | background: #e8e8e8; |
| | | } |
| | | .header-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 4rpx 0; |
| | | } |
| | | |
| | | .header-label { |
| | | font-size: 24rpx; |
| | | color: rgba(255, 255, 255, 0.7); |
| | | } |
| | | |
| | | .header-value { |
| | | font-size: 26rpx; |
| | | color: #ffffff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | /* 搜索栏 */ |
| | | .search-bar { |
| | | padding: 0rpx 8rpx; |
| | | background: #ffffff; |
| | | box-shadow: 0 2rpx 8rpx rgba(0, 129, 255, 0.08); |
| | | } |
| | | |
| | | /* 列表样式迁移 from rece/other.vue */ |
| | | .index { |
| | | border: 1px solid #e54d42; |
| | | color: #e54d42; |
| | | border-radius: 50%; |
| | | display: block; |
| | | width: 50rpx; |
| | | height: 50rpx; |
| | | line-height: 48rpx; |
| | | text-align: center; |
| | | margin-right: 20rpx; |
| | | font-size: 30rpx; |
| | | } |
| | | |
| | | .act { |
| | | border: 1px solid #e54d42; |
| | | } |
| | | |
| | | .text-blue { |
| | | color: #0081ff !important; |
| | | } |
| | | |
| | | .text-green { |
| | | color: #39b54a !important; |
| | | } |
| | | |
| | | /* 空状态 */ |
| | | .empty-state { |
| | | padding: 60rpx 0; |
| | | } |
| | | |
| | | .empty-text { |
| | | margin-top: 20rpx; |
| | | } |
| | | |
| | | /* 统计栏 */ |
| | | .stats-bar { |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-around; |
| | | background: #ffffff; |
| | | padding: 16rpx 0; |
| | | box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06); |
| | | } |
| | | |
| | | .stats-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | flex: 1; |
| | | } |
| | | |
| | | .stats-value { |
| | | font-size: 32rpx; |
| | | color: #303133; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .stats-label { |
| | | font-size: 20rpx; |
| | | color: #909399; |
| | | margin-top: 4rpx; |
| | | } |
| | | |
| | | .stats-divider { |
| | | width: 1rpx; |
| | | height: 50rpx; |
| | | background: #e8e8e8; |
| | | } |
| | | </style> |