Files
klp-mono/apps/hand-factory/pages/fahuo/fahuo.vue
砂糖 b93d636c8a feat: 更新应用版本至1.3.30并优化报餐统计功能
新增系统配置API模块
移除列表加载时的多余条件判断
优化报餐统计页面样式和逻辑
2026-04-14 11:18:33 +08:00

792 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 筛选栏 -->
<view class="filter-bar">
<!-- 左侧发货计划选择 -->
<view class="plan-select" @click="openPlanPopup">
<uni-icons type="shop" size="20" color="#666"></uni-icons>
<text class="plan-text">{{ currentPlan.planNo || '选择发货单据' }}</text>
<uni-icons type="arrowright" size="16" color="#999"></uni-icons>
</view>
</view>
<!-- 发货计划选择悬浮窗 -->
<uni-popup ref="planPopup" type="bottom" :mask-click="true" height="70%">
<view class="popup-container">
<!-- 弹窗头部 -->
<view class="popup-header">
<text class="popup-title">选择发货单据</text>
<uni-icons type="close" size="20" @click="closePlanPopup"></uni-icons>
</view>
<!-- 计划筛选输入框 -->
<view class="plan-search">
<input v-model="planKeyword" placeholder="请输入发货单号筛选" clearable class="plan-search-input"
@confirm="fetchDeliveryPlan"></input>
<uni-icons type="search" size="18" color="#666" @click="fetchDeliveryPlan(true)"></uni-icons>
</view>
<!-- 发货计划列表 -->
<scroll-view class="detail-scroll" scroll-y>
<view class="form-card">
<uni-list v-if="planList.length">
<uni-list-item v-for="(item, index) in planList" :key="index"
:title="item.waybillName + '-' + item.consigneeUnit"
:note="item.licensePlate + '(' + item.principal + ')'"
clickable
@click="selectPlan(item)"></uni-list-item>
</uni-list>
<view class="empty-tip" v-else>暂无发货计划数据</view>
</view>
<!-- 加载更多 -->
<uni-load-more :status="planHasMore ? 'more' : 'noMore'" @clickLoadMore="fetchDeliveryPlan(false)"
v-if="planList.length"></uni-load-more>
</scroll-view>
</view>
</uni-popup>
<uni-popup ref='viewPopup' type="bottom" :mask-click="true" height="70%">
<view class="popup-container">
<!-- 弹窗头部标题+关闭按钮 -->
<view class="popup-header">
<text class="popup-title">钢卷详情信息</text>
<uni-icons type="close" size="20" @click="closeViewPopup"></uni-icons>
</view>
<!-- 详情内容区域滚动布局适配多内容 -->
<scroll-view class="detail-scroll" scroll-y>
<view class="form-card" v-if="form.coilId">
<!-- 基础信息网格 -->
<view class="info-grid">
<view class="info-item">
<text class="item-label">入场钢卷号</text>
<text class="item-value">{{ form.enterCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">钢卷号</text>
<text class="item-value">{{ form.currentCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">班组</text>
<text class="item-value">{{ form.team || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">数据类型</text>
<text
class="item-value">{{ form.dataType === 0 ? '默认数据' : form.dataType === 10 ? '待发货数据' : '-' }}</text>
</view>
<view class="info-item full-width">
<text class="item-label">逻辑库位</text>
<text class="item-value">{{ form.warehouseName || '-' }}</text>
</view>
<view class="info-item full-width">
<text class="item-label">实际库位</text>
<text class="item-value">{{ form.actualWarehouseName || '-' }}</text>
</view>
</view>
<!-- 物料信息 -->
<view class="card-title" style="margin-top: 30rpx;">
<text class="title-dot"></text>
<text class="title-text">物料信息</text>
</view>
<view class="info-grid">
<view class="info-item">
<text class="item-label">物品名称</text>
<text class="item-value">{{ form.itemName || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">规格</text>
<text class="item-value">{{ form.specification || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">材质</text>
<text class="item-value">{{ form.material || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">厂家</text>
<text class="item-value">{{ form.manufacturer || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">表面处理</text>
<text class="item-value">{{ form.surfaceTreatmentDesc || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">镀层质量</text>
<text class="item-value">{{ form.zincLayer || '-' }}</text>
</view>
</view>
<!-- 重量信息 -->
<view class="card-title" style="margin-top: 30rpx;">
<text class="title-dot"></text>
<text class="title-text">数据信息</text>
</view>
<view class="info-grid">
<view class="info-item">
<text class="item-label">毛重</text>
<text class="item-value">{{ form.grossWeight || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">净重</text>
<text class="item-value">{{ form.netWeight || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">长度m</text>
<text class="item-value">{{ form.length || '-' }}</text>
</view>
</view>
<!-- 操作信息 -->
<view class="card-title" style="margin-top: 30rpx;">
<text class="title-dot"></text>
<text class="title-text">操作信息</text>
</view>
<view class="info-grid">
<view class="info-item">
<text class="item-label">操作人</text>
<text class="item-value">{{ operatorName }}</text>
</view>
<view class="info-item">
<text class="item-label">更新时间</text>
<text class="item-value">{{ currentAction.updateTime || '-' }}</text>
</view>
<view class="info-item full-width">
<text class="item-label">操作状态</text>
<text
class="item-value">{{ currentAction.actionStatus === 0 ? '未开始' : currentAction.actionStatus === 2 ? '已完成' : '-' }}</text>
</view>
</view>
</view>
<!-- 空数据提示 -->
<view class="empty-tip" v-else>
暂无钢卷详情数据
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 主列表区域 -->
<view class="main-list">
<scroll-view class="list-scroll" scroll-y>
<uni-list v-if="list.length">
<uni-list-item v-for="(item, index) in list" :key="index" @click=""
:title="`钢卷号:${item.coilNo || '-'}`" :note="`操作时间:${item.updateTime || '-'}`">
<template v-slot:footer>
<button style="margin-right: 10rpx;" size="mini" type="primary" plain="true" @click="openViewPopup(item)">查看</button>
</template>
</uni-list-item>
</uni-list>
<view class="empty-tip" v-else>暂无待操作数据</view>
<!-- 加载更多 -->
<uni-load-more :status="hasMore ? 'more' : 'noMore'" @clickLoadMore="fetchList(false)"
v-if="list.length"></uni-load-more>
</scroll-view>
</view>
</view>
</template>
<script>
import {
listDeliveryWaybill
} from '@/api/wms/deliveryWaybill.js'
import {
listDeliveryPlan
} from '@/api/wms/deliveryPlan.js';
import {
listDeliveryWaybillDetail
} from '@/api/wms/deliveryWaybillDetail.js'
import {
updateMaterialCoilSimple,
getMaterialCoil
} from '@/api/wms/coil.js'
// 入库操作编码
const ACTION_TYPE = 401;
// 发货计划类型编码
const RECEIVE_PLAN_TYPE = 2;
// 未开始操作状态
const ACTION_STATUS = 0;
export default {
data() {
return {
// 主列表数据
list: [],
currentPlan: {}, // 当前选中的发货计划
currentCoilNo: undefined, // 当前输入的钢卷号
hasMore: true, // 是否有更多主列表数据
pageNum: 1, // 主列表页码
pageSize: 10, // 每页条数
refreshing: false, // 下拉刷新状态
// 发货计划弹窗相关
planKeyword: '', // 计划筛选关键词
planList: [], // 发货计划列表
planHasMore: true, // 计划列表是否有更多
planPageNum: 1, // 计划列表页码
popupShow: false, // 弹窗显示状态
form: {},
loading: false,
currentAction: {},
loadingDetail: false,
};
},
computed: {
// 获取当前操作者昵称
operatorName() {
return this.$store.state.user.nickName || this.$store.state.user.name || '未知'
}
},
onShow() {
// 页面显示时初始化加载数据
this.fetchList(true);
},
methods: {
/**
* 获取待操作列表数据
* @param {Boolean} isRefresh 是否刷新(重置页码)
*/
async fetchList(isRefresh = false) {
try {
// 刷新时重置页码和加载状态
if (isRefresh) {
this.pageNum = 1;
this.refreshing = true;
}
// 构造请求参数
const params = {
pageNum: this.pageNum,
waybillId: this.currentPlan.waybillId,
pageSize: this.pageSize
};
// 请求接口
const res = await listDeliveryWaybillDetail(params);
if (res.code === 200) {
const list = res.rows || [];
// 刷新时替换数据,加载更多时追加数据
this.list = isRefresh ? list : [...this.list, ...list];
// 判断是否有更多数据
this.hasMore = this.pageNum * this.pageSize < res.total;
}
console.log(this.list, '需要渲染的数据')
} catch (err) {
console.error('获取待操作列表失败:', err);
uni.showToast({
title: '数据加载失败',
icon: 'none'
});
} finally {
// 结束下拉刷新状态
this.refreshing = false;
// 加载更多时页码+1
if (!isRefresh) this.pageNum++;
}
},
/**
* 获取发货计划列表
* @param {Boolean} isRefresh 是否刷新(重置页码)
*/
async fetchDeliveryPlan(isRefresh = false) {
try {
if (isRefresh) {
this.planPageNum = 1;
}
// 构造请求参数
const params = {
waybillName: this.planKeyword || '', // 计划编号筛选
pageNum: this.planPageNum,
pageSize: this.pageSize,
};
const res = await listDeliveryWaybill(params);
if (res.code === 200) {
const list = res.rows || [];
this.planList = isRefresh ? list : [...this.planList, ...list];
this.planHasMore = this.planPageNum * this.pageSize < res.total;
}
} catch (err) {
console.error('获取发货单据失败:', err);
uni.showToast({
title: '计划加载失败',
icon: 'none'
});
} finally {
if (!isRefresh) this.planPageNum++;
}
},
/**
* 打开发货计划弹窗
*/
openPlanPopup() {
this.$refs.planPopup.open();
// 打开弹窗时加载计划数据
this.fetchDeliveryPlan(true);
},
/**
* 关闭发货计划弹窗
*/
closePlanPopup() {
this.$refs.planPopup.close();
},
/**
* 打开发货弹窗
*/
openReceivePopup(row) {
this.$refs.receivePopup.open('bottom')
// this.loadingDetail = false;
uni.showLoading({
title: '正在加载发货详情'
})
getMaterialCoil(row.coilId).then(res => {
this.form = res.data;
this.currentAction = row;
// this.loadingDetail = true
uni.hideLoading()
})
},
openViewPopup(row) {
this.$refs.viewPopup.open('bottom')
// this.loadingDetail = false;
uni.showLoading({
title: '正在加载发货详情'
})
getMaterialCoil(row.coilId).then(res => {
console.log(res.data)
this.form = res.data;
this.currentAction = row;
uni.hideLoading()
// this.loadingDetail = true
})
},
/**
* 关闭钢卷详情弹窗
*/
closeViewPopup() {
this.$refs.viewPopup.close();
// 可选:清空表单临时数据(根据业务需求决定是否保留)
this.form = {};
this.currentAction = {};
},
/**
* 确认发货
*/
confirmReceive(row) {
const currentAction = this.currentAction;
const form = this.form;
const that = this;
uni.showModal({
title: '确定要发货吗?',
success() {
// console.log(currentAction, form)
that.loading = true;
Promise.all([
updatePendingAction({
...currentAction,
actionStatus: 2
}),
updateMaterialCoilSimple({
...form,
dataType: 1
})
]).then(_ => {
uni.showToast({
title: '钢卷已发货'
});
that.fetchList(true);
that.loading = false;
that.$refs.receivePopup.close()
})
}
})
},
/**
* 选择发货计划
* @param {Object} plan 选中的计划对象
*/
selectPlan(plan) {
this.currentPlan = plan;
this.closePlanPopup();
// 选择计划后重新加载主列表
this.fetchList(true);
},
/**
* 下拉刷新触发(修正后事件可正常绑定)
*/
onPullDownRefresh() {
this.fetchList(true);
},
/**
* 页面上拉加载(可选:补充页面级上拉加载)
*/
onReachBottom() {
if (this.hasMore) {
this.fetchList(false);
}
}
},
// 补充页面级上拉加载钩子(可选,增强体验)
onReachBottom() {
this.onReachBottom();
}
};
</script>
<style scoped lang="scss">
.container {
width: 100%;
height: 100vh;
background-color: #f5f5f5;
display: flex;
flex-direction: column;
}
/* 筛选栏样式 */
.filter-bar {
display: flex;
align-items: center;
padding: 10rpx 20rpx;
background-color: #fff;
border-bottom: 1px solid #eee;
}
.plan-select {
display: flex;
align-items: center;
gap: 8rpx;
padding: 10rpx 15rpx;
background-color: #f8f8f8;
border-radius: 6rpx;
margin-right: 20rpx;
min-width: 200rpx;
}
.plan-text {
font-size: 28rpx;
color: #333;
flex: 1;
}
.coil-filter {
display: flex;
align-items: center;
flex: 1;
background-color: #f8f8f8;
border-radius: 6rpx;
padding: 0 15rpx;
}
.coil-input {
flex: 1;
font-size: 28rpx;
}
/* 弹窗样式 */
.popup-container {
width: 100%;
height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
}
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx;
border-bottom: 1px solid #eee;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.plan-search {
display: flex;
align-items: center;
gap: 10rpx;
padding: 15rpx 20rpx;
border-bottom: 1px solid #eee;
}
.plan-search-input {
flex: 1;
font-size: 28rpx;
}
// .plan-list {
// flex: 1;
// overflow-y: auto;
// padding: 10rpx;
// }
/* 列表样式 */
.main-list {
flex: 1;
overflow: hidden;
}
.list-scroll {
width: 100%;
height: 100%;
}
.uni-list {
background-color: #fff;
margin: 10rpx;
border-radius: 8rpx;
}
.uni-list-item {
font-size: 28rpx;
}
/* 空数据提示 */
.empty-tip {
text-align: center;
padding: 50rpx 0;
font-size: 28rpx;
color: #999;
}
/* 加载更多样式 */
.uni-load-more {
margin: 20rpx 0;
}
.form-card {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
overflow: scroll;
height: 70vh;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.card-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 25rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
.title-dot {
width: 8rpx;
height: 28rpx;
background: #007aff;
border-radius: 4rpx;
margin-right: 12rpx;
}
.title-text {
flex: 1;
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.status-badge {
font-size: 22rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
margin-right: 10rpx;
&.status-1 {
background: #d1f2eb;
color: #0c6957;
}
&.status-0 {
background: #f8d7da;
color: #721c24;
}
}
.more-btn {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 16rpx;
background: #f0f7ff;
border-radius: 20rpx;
border: 1rpx solid #007aff;
.icon-more {
font-size: 24rpx;
color: #007aff;
}
.more-text {
font-size: 24rpx;
color: #007aff;
}
}
}
/* 信息网格 */
.info-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
.info-item {
flex: 1;
min-width: 45%;
background: #f8f9fa;
padding: 20rpx;
border-radius: 12rpx;
&.full-width {
flex: 0 0 100%;
}
.item-label {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 10rpx;
}
.item-value {
display: block;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
}
/* 表单项 */
.form-item {
margin-bottom: 30rpx;
&:last-of-type {
margin-bottom: 0;
}
.form-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
&::before {
content: '*';
color: #ff4d4f;
margin-right: 6rpx;
}
}
.form-label-optional {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
}
.form-input {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
transition: all 0.3s;
&:focus {
background: #fff;
border-color: #007aff;
}
&.form-input-disabled {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
}
}
/* 操作者信息 */
.operator-info {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0;
margin-top: 20rpx;
.operator-label {
font-size: 26rpx;
color: #999;
}
.operator-name {
font-size: 26rpx;
color: #007aff;
font-weight: 500;
}
}
/* 操作按钮 */
.action-buttons {
display: flex;
gap: 20rpx;
margin-top: 30rpx;
.btn {
flex: 1;
height: 88rpx;
border-radius: 12rpx;
font-size: 30rpx;
font-weight: 500;
border: none;
transition: all 0.2s;
&:active {
transform: scale(0.98);
}
&[disabled] {
opacity: 0.6;
}
}
.btn-secondary {
background: #f5f5f5;
color: #666;
}
.btn-primary {
background: linear-gradient(135deg, #007aff 0%, #0051d5 100%);
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(0, 122, 255, 0.3);
}
}
</style>