heli-mes/mes-ui/mini-app/src/pages/receivingGoods/receivingGoods.vue
2025-10-23 18:38:30 +08:00

763 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.

<script setup lang="ts">
import { onMounted, ref, } from "vue";
import {
getReceivingGoods, postOperateAPI, receiveGoods, verification,
} from "@/services/productionReport";
import { useLoginStore } from "@/stores/modules/login";
const userStore = useLoginStore();
const userId = userStore.userInfo.userId;
const popup = ref<UniHelper.UniPopupInstance>()
const showPop = ref<UniHelper.UniPopupInstance>()
// 是否分页结束
const isFinish = ref(false);
// 是否触发下拉刷新
const isTriggered = ref(false);
const noticeMsg = ref("");
const purchaseRemAmounts = ref("")
const estimatedPrice = ref("")
// 是否加载中标记,用于防止滚动触底触发多次请求
const isLoading = ref(false);
// 请求参
const queryParams : Required<any> = {
pageNo: 1,
pageSize: 5,
subOrDetailName: "",
projectName: "",
projectSubName: "",
supplierName: "",
boomName: "",
procedureName: "",
blueprintNo: "",
};
const dataList = ref([]);
const list = ref([]);
const getListData = async () => {
// 如果数据出于加载中,退出函数
if (isLoading.value) return;
if (isFinish.value === true) {
return uni.showToast({ icon: "none", title: "没有更多数据~" });
}
isLoading.value = true;
// 发送请求
const data = await getReceivingGoods(queryParams);
isLoading.value = false;
dataList.value.push(...data.list);
// 分页条件
if (queryParams.pageNo < data.totalPages) {
// 页码累加
queryParams.pageNo++;
} else {
// 分页已结束
isFinish.value = true;
}
};
const isScanning = ref(false)
const todayStr = ref("");
const searchVal = ref("");
onMounted(async () => {
isFinish.value = false;
isLoading.value = false;
queryParams.pageNo = 1;
await getListData();
});
// 自定义下拉刷新被触发
const onRefresherrefresh = async () => {
// 开始动画
isTriggered.value = true;
// 重置数据
queryParams.pageNo = 1;
dataList.value = [];
isFinish.value = false;
// 加载数据
await getListData();
// 关闭动画
isTriggered.value = false;
};
const handleScan = async () => {
if (isScanning.value) return;
isScanning.value = true;
try {
console.log('触发扫码')
const res = await uni.scanCode();
console.log(res.result)
searchVal.value = res.result;
// 使用 setTimeout 确保 UI 更新
await new Promise(resolve => setTimeout(resolve, 0));
await handleSearch({ inputValue: res.result });
} catch (error) {
uni.showToast({ title: '扫码失败', icon: 'none' });
} finally {
isScanning.value = false;
}
};
const handleSearch = async (e) => {
// 重置状态
queryParams.pageNo = 1;
isFinish.value = false;
dataList.value = [];
// 设置搜索词
queryParams.subOrDetailName = e.inputValue;
searchVal.value = e.inputValue; // 同步输入框值
try {
await getListData();
} catch (error) {
console.error('搜索请求失败:', error);
}
};
const popUp = async (data) => {
estimatedPrice.value = data.estimatedPrice
purchaseRemAmounts.value = data.purchaseRemAmounts
list.value.push(data)
popup.value?.open()
}
const handleOk = async () => {
if (estimatedPrice.value == null || estimatedPrice.value == "" || estimatedPrice.value == undefined || estimatedPrice.value == '' || estimatedPrice.value <= 0) {
uni.showToast({
title: '预估总价不能为空',
icon: 'none',
duration: 2000
});
return
}
if (purchaseRemAmounts.value == null || purchaseRemAmounts.value == "" || purchaseRemAmounts.value == undefined || purchaseRemAmounts.value <= 0 || purchaseRemAmounts.value == '') {
uni.showToast({
title: '入库数量不能为空或为0',
icon: 'none',
duration: 2000
});
return
}
list.value[0].estimatedPrice = estimatedPrice.value
list.value[0].purchaseRemAmounts = purchaseRemAmounts.value
await verification(list.value[0])
const res = await Promise.race([
receiveGoods(list.value[0]),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("请求超时")), 30000)
)
]);
uni.showToast({
title: '收货成功',
icon: 'none',
duration: 2000
});
list.value = []
estimatedPrice.value = ""
purchaseRemAmounts.value = ""
popup.value?.close()
queryParams.pageNo = 1;
isFinish.value = false;
dataList.value = [];
await getListData()
}
const cancel = () => {
list.value = []
estimatedPrice.value = ""
purchaseRemAmounts.value = ""
popup.value?.close()
queryParams.pageNo = 1;
isFinish.value = false;
dataList.value = [];
getListData()
}
const filterData : Required<any> = ({
projectName: '',
subProjectName: '',
supplier: '',
partName: '',
process: '',
drawingNo: ''
})
// 切换下拉框显示状态
const toggleDropdown = () => {
showPop.value?.open()
}
// 取消过滤
const cancelFilter = () => {
showPop.value?.close()
}
// 确认过滤
const confirmFilter = () => {
// 清空搜索框内容
searchVal.value = '';
queryParams.subOrDetailName=""
// 这里可以添加过滤逻辑
// 收起下拉区域
showPop.value?.close();
queryParams.pageNo = 1;
isFinish.value = false;
dataList.value = [];
getListData()
}
</script>
<template>
<view class="cont">
<view class="search" style="display: flex; align-items: center;">
<view style="
width: 90%;
display: flex;
align-items: center;
background: #e2f3ff;
border-radius: 20rpx;
padding: 0 8rpx;
height: 50px;
">
<input class="uni-input" v-model="searchVal" placeholder="请输入物料名称、图号、工序"
:placeholder-style="'color:#28A0F8;'" style="
flex: 1;
background: transparent;
border: none;
outline: none;
font-size: 25rpx;
color: #28a0f8;
height: 50px;
line-height: 50px;
" @input="handleSearch({ inputValue: searchVal })" clearable />
<view
style="
background: none;
border: none;
padding: 0 10rpx;
height: 50px;
display: flex;
align-items: center;
"
@click="handleScan"
>
<uni-icons type="scan" size="28" color="#28A0F8"></uni-icons>
</view>
</view>
<view class="filter-btn" @click="toggleDropdown" style="margin-left: 10px;">
<image src="/static/images/shalou.jpeg" mode="aspectFit" class="filter-icon"></image>
</view>
</view>
<scroll-view enable-back-to-top scroll-y class="data-list" refresher-enabled :refresher-triggered="isTriggered"
@refresherrefresh="onRefresherrefresh" @scrolltolower="getListData">
<view class="item" v-for="item in dataList" :key="item.id">
<view class="hd">
<view class="num">图号:</view>
<view class="num">{{
item.blueprintNo
}}</view>
<view class="statusText1" @click="popUp(item)">
收货
</view>
</view>
<view class="md">
<view class="product-row">
<view class="row-item">
<view class="label">零件名称: <span style="font-weight: bold;">{{ item.boomName }}</span></view>
</view>
<view class="row-item">
<view class="label">派工工序: <span style="font-weight: bold;">{{ item.procedureName }}</span></view>
</view>
</view>
<view class="product-row">
<view class="row-item">
<view class="label">采购数量: {{ item.purchaseAmount }}</view>
</view>
<view class="row-item">
<view class="label">剩余数量: {{ item.purchaseRemAmount }}</view>
</view>
</view>
<view class="product-row">
<view class="row-item">
<view class="label">收货状态: {{ item.receivingStatus==1?"未收货":"收货中" }}</view>
</view>
<view class="row-item">
<view class="label">物料类型: {{ item.goodsType==1?"物料":"加工件" }}</view>
</view>
</view>
<view class="product-row">
<view class="row-item">
<view class="label">完成日期: {{ item.requireTimes }}</view>
</view>
<view class="row-item">
<view class="label">&emsp;供应商: {{ item.supplierName }}</view>
</view>
</view>
<view class="product-row">
<view class="row-item">
<view class="label">预估总价: {{ item.estimatedPrice }}</view>
</view>
<view class="row-item">
<view class="label">&emsp;&emsp;材质: {{ item.boomSpec }}</view>
</view>
</view>
<view class="product-row">
<view>
<view class="label">子项目编码: {{ item.projectSubCode }}</view>
</view>
</view>
</view>
</view>
<!-- 底部提示文字 -->
<view class="loading-text" :style="{ paddingBottom: safeAreaInsets?.bottom + 'px' }">
{{ isFinish ? "没有更多数据~" : "正在加载..." }}
</view>
</scroll-view>
<uni-popup class="popup" ref="popup" :mask-click="false" type="bottom" background-color="#fff">
<view class="title">
<view class="text">填写信息</view>
</view>
<view class="cont">
<view class="item">
<view class="label"><span class="star">*</span>入库数量:</view>
<uni-easyinput class="val" type="number" v-model="purchaseRemAmounts"
placeholder="请输入本次入库数量"></uni-easyinput>
</view>
<view class="item">
<view class="label"><span class="star">*</span>预估总价:</view>
<uni-easyinput class="val" type="number" v-model="estimatedPrice"
placeholder="请输入本次预估总价"></uni-easyinput>
</view>
</view>
<view class="button-group">
<view class="ok" @click="handleOk">确定</view>
<view class="cancel" @click="cancel">取消</view>
</view>
</uni-popup>
<uni-popup class="popup" ref="showPop" :mask-click="false" type="top" background-color="#fff">
<view style="margin-top: 6%;">
<uni-forms :modelValue="queryParams" label-align="right" label-width="90px">
<uni-forms-item label="项目名称" name="projectName">
<uni-easyinput type="text" v-model="queryParams.projectName" placeholder="请输入项目名称" />
</uni-forms-item>
<uni-forms-item label="子项目名称" name="projectSubName">
<uni-easyinput type="text" v-model="queryParams.projectSubName" placeholder="请输入子项目名称" />
</uni-forms-item>
<uni-forms-item name="supplierName" label="供应商">
<uni-easyinput type="text" v-model="queryParams.supplierName" placeholder="请输入供应商" />
</uni-forms-item>
<uni-forms-item label="零件名称" name="boomName">
<uni-easyinput type="text" v-model="queryParams.boomName" placeholder="请输入零件名称" />
</uni-forms-item>
<uni-forms-item label="工序" name="procedureName">
<uni-easyinput type="text" v-model="queryParams.procedureName" placeholder="请输入工序" />
</uni-forms-item>
<uni-forms-item name="blueprintNo" label="图号">
<uni-easyinput type="text" v-model="queryParams.blueprintNo" placeholder="请输入图号" />
</uni-forms-item>
</uni-forms>
</view>
<view class="button-group">
<view class="ok" @click="confirmFilter">查询</view>
<view class="cancel" @click="cancelFilter">取消</view>
</view>
</uni-popup>
</view>
</template>
<style lang="scss">
.fixed-bottom-modal {
position: fixed !important; /* 覆盖框架默认定位 */
bottom: 0; /* 紧贴屏幕底部 */
left: 0;
right: 0;
z-index: 9999 !important; /* 确保最高层级 */
}
.filter-buttons {
display: flex;
width: 100%;
justify-content: space-between;
}
.filter-btn {
padding: 10rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto; /* Push the filter button to the right */
.filter-icon {
width: 40rpx;
height: 40rpx;
}
}
.filter-buttons .cancel {
background-color: white;
color: #333;
flex: 1;
text-align: center;
padding: 10px;
border: 1px solid #ddd;
}
.filter-buttons .ok {
background-color: #007aff;
color: white;
flex: 1;
text-align: center;
padding: 10px;
}
// 订单列表
.search {
padding: 0rpx;
width: 90%;
margin: auto;
margin-top: 20rpx;
position: relative;
.uni-input {
border: 1px solid #d1d6db;
height: 60rpx;
line-height: 60rpx;
padding: 4rpx 10rpx;
font-size: 32rpx;
border-radius: 10rpx;
flex: 1; /* Make the input take the remaining space */
}
.icons {
width: 30rpx;
position: absolute;
right: 40rpx;
top: 0rpx;
}
}
.data-list {
height: 90vh;
.item {
position: relative;
padding: 20rpx 0;
margin: 20rpx 20rpx;
border-radius: 10rpx;
background-color: #fff;
box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.05);
.hd {
padding: 10rpx;
font-size: 28rpx;
display: flex;
.statusLabel {
font-size: 24rpx;
color: #737d88;
}
}
.md {
position: relative;
padding: 10rpx;
min-height: 100rpx;
font-size: 28rpx;
border-top: 2rpx solid #f2f2f2;
.product-item {
margin: 20rpx 0;
display: flex;
align-items: center;
color: #737d88;
}
.product-row {
margin: 20rpx 0;
display: flex;
flex-direction: row;
justify-content: space-between;
color: #737d88;
.row-item {
flex: 1;
.label {
margin-bottom: 10rpx;
}
.val {
color: #1d2129;
&.high-color {
color: #00b42a;
}
}
}
}
}
.statusText1 {
font-size: 24rpx;
position: absolute;
right: 30rpx;
top: 15rpx;
border-radius: 10rpx;
font-size: 24rpx;
padding: 10rpx 30rpx;
border-radius: 10rpx;
font-size: 24rpx;
background: linear-gradient(149deg, #4CAF50 4%, #388E3C 98%);
color: #fff;
}
&:last-child {
padding-bottom: 40rpx;
}
}
.status {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
color: #999;
margin-bottom: 15rpx;
.date {
color: #666;
flex: 1;
}
.primary {
color: #ff9240;
}
.icon-delete {
line-height: 1;
margin-left: 10rpx;
padding-left: 10rpx;
border-left: 1rpx solid #e3e3e3;
}
}
.goods {
display: flex;
margin-bottom: 20rpx;
.cover {
width: 170rpx;
height: 170rpx;
margin-right: 20rpx;
border-radius: 10rpx;
overflow: hidden;
position: relative;
.image {
width: 170rpx;
height: 170rpx;
}
}
.quantity {
position: absolute;
bottom: 0;
right: 0;
line-height: 1;
padding: 6rpx 4rpx 6rpx 8rpx;
font-size: 24rpx;
color: #fff;
border-radius: 10rpx 0 0 0;
background-color: rgba(0, 0, 0, 0.6);
}
.meta {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.name {
height: 80rpx;
font-size: 26rpx;
color: #444;
}
.type {
line-height: 1.8;
padding: 0 15rpx;
margin-top: 10rpx;
font-size: 24rpx;
align-self: flex-start;
border-radius: 4rpx;
color: #888;
background-color: #f7f7f8;
}
.more {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
color: #333;
}
}
.payment {
display: flex;
justify-content: flex-end;
align-items: center;
line-height: 1;
padding: 20rpx 0;
text-align: right;
color: #999;
font-size: 28rpx;
border-bottom: 1rpx solid #eee;
.quantity {
font-size: 24rpx;
margin-right: 16rpx;
}
.amount {
color: #444;
margin-left: 6rpx;
}
.symbol {
font-size: 20rpx;
}
}
.action {
display: flex;
justify-content: flex-end;
align-items: center;
padding-top: 20rpx;
.button {
width: 180rpx;
height: 60rpx;
display: flex;
justify-content: center;
align-items: center;
margin-left: 20rpx;
border-radius: 60rpx;
border: 1rpx solid #ccc;
font-size: 26rpx;
color: #444;
}
.secondary {
color: #3775f6;
border-color: #3775f6;
}
.primary {
color: #fff;
background-color: #3775f6;
border-color: #3775f6;
}
}
.loading-text {
text-align: center;
font-size: 28rpx;
color: #666;
padding: 20rpx 0;
}
}
.popup {
.title {
line-height: 1;
padding: 40rpx;
font-size: 32rpx;
font-weight: normal;
border-bottom: 1rpx solid #ddd;
color: #444;
.close {
position: absolute;
right: 24rpx;
top: 40rpx;
height: 60rpx;
width: 60rpx;
text-align: center;
}
}
.cont {
display: flex;
flex-direction: column;
align-items: center;
margin: 40rpx;
height: 50vh;
.item {
display: flex;
align-items: center;
margin: 100rpx 20rpx 0 0;
color: #737D88;
width: 94%;
.label {
font-size: 32rpx;
width: 260rpx;
.star {
color: red
}
}
.val {
flex: 1;
font-size: 32rpx;
}
.unit {
width: 100rpx;
margin-left: 4rpx;
text-align: center;
}
}
}
/* 新增按钮组容器样式 */
.button-group {
display: flex;
/* 开启弹性布局 */
justify-content: center;
/* 水平居中对齐 */
gap: 20rpx;
/* 按钮间距 */
}
/* 修正原有 .ok 样式 */
.ok,
.cancel {
font-size: 40rpx;
text-align: center;
width: 250rpx;
border-radius: 24rpx;
padding: 10rpx 0;
background-color: #3C8AF7;
color: #fff;
line-height:40px;
margin: 20rpx auto 80rpx;
/* 移除原有的 margin: 20rpx auto 80rpx; */
}
/* 可选为取消按钮添加不同样式 */
.cancel {
background: linear-gradient(157deg, #A9A9A9 -3%, #A9A9A9 90%);
}
}
</style>