Files
im-uniapp/pages/workbench/wms/out.vue
2025-10-13 17:51:27 +08:00

627 lines
14 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">
<!-- 出库单列表滚动加载区域 -->
<scroll-view
scroll-y
@scrolltolower="loadMore"
:style="{ height: scrollHeight + 'px' }"
class="list-scroll"
>
<!-- 单据列表容器 -->
<view class="documents-container">
<!-- 单据列表 -->
<view v-if="TaskList.length > 0">
<view
class="document-card"
v-for="(item, index) in TaskList"
:key="index"
@click="showDetail(item)"
>
<!-- 单据头部 -->
<view class="doc-header">
<view class="doc-title">出库单</view>
<uni-tag
:type="item.status === 1 ? 'success' : 'warning'"
class="status-tag"
>
{{ item.status === 1 ? "已完成" : "未完成" }}
</uni-tag>
</view>
<!-- 单据编号区域 -->
<view class="doc-number">
<text class="label">编号</text>
<text class="value">{{ item.masterNum }}</text>
</view>
<!-- 单据内容区域 -->
<view class="doc-content">
<view class="doc-row">
<view class="doc-col">
<text class="label">操作时间</text>
<text class="value">{{ parseTime(item.signTime) }}</text>
</view>
</view>
<view class="doc-row">
<view class="doc-col">
<text class="label">操作人</text>
<text class="value">{{ item.signUser }}</text>
</view>
</view>
<view class="doc-row" v-if="item.remark">
<view class="doc-col full-width">
<text class="label">备注</text>
<text class="value remark">{{ item.remark }}</text>
</view>
</view>
</view>
<!-- 单据底部 -->
<view class="doc-footer">
<view class="doc-seal">
<uni-icon type="stamp" size="24" color="#999"></uni-icon>
<text class="seal-text">电子单据</text>
</view>
<uni-icon type="right" size="18" color="#666" class="arrow-icon"></uni-icon>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else-if="!loading && TaskList.length === 0">
<uni-icon type="empty" size="60" color="#ccc"></uni-icon>
<text class="empty-text">暂无出库单数据</text>
</view>
</view>
<!-- 加载更多组件 -->
<uni-load-more
:status="loadMoreStatus"
:content-text="{
more: '上拉加载更多',
loading: '加载中...',
noMore: '没有更多数据了'
}"
class="load-more"
></uni-load-more>
</scroll-view>
<!-- 详情弹窗 -->
<uni-popup
type="bottom"
:duration="300"
ref="popup"
height="700rpx"
>
<view class="popup-container">
<!-- 弹窗标题栏 -->
<!-- <view class="popup-header">
<text class="popup-title">出库单明细</text>
<uni-icon
type="close"
size="24"
class="close-icon"
@click="$refs.popup.close()"
></uni-icon>
</view> -->
<view class="detail-scroll">
<view class="detail-document">
<!-- 明细头部 -->
<!-- <view class="detail-header">
<text class="detail-masterNum">编号{{ currentItem.masterNum || '' }}</text>
<text class="detail-date">{{ currentItem.signTime ? parseTime(currentItem.signTime) : '' }}</text>
</view> -->
<!-- 明细列表 -->
<uni-list v-if="warehouseTaskList.length > 0" border="false">
<uni-list-item class="detail-item" v-for="(item, index) in warehouseTaskList" :key="index">
<view class="detail-content">
<view class="detail-title">
<text class="item-num">{{ index + 1 }}.</text>
<text class="item-name">{{ item.warehouseName }}</text>
</view>
<view class="detail-grid">
<view class="grid-item">
<text class="grid-label">数量</text>
<text class="grid-value">{{ item.taskInventory }}{{ item.unit }}</text>
</view>
<view class="grid-item">
<text class="grid-label">品牌</text>
<text class="grid-value">{{ item.brand || '无' }}</text>
</view>
</view>
<view class="detail-grid">
<view class="grid-item">
<text class="grid-label">型号</text>
<text class="grid-value">{{ item.model || '无' }}</text>
</view>
<view class="grid-item">
<text class="grid-label">规格</text>
<text class="grid-value">{{ item.specifications || '无' }}</text>
</view>
</view>
<view class="detail-remark" v-if="item.remark">
<text class="remark-label">备注</text>
<text class="remark-value">{{ item.remark }}</text>
</view>
</view>
</uni-list-item>
</uni-list>
<view class="empty-state" v-else>
<uni-icon type="empty" size="50" color="#ccc"></uni-icon>
<text class="empty-text">暂无出库单明细</text>
</view>
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { listOaWarehouseMaster } from "@/api/oa/wms/warehouseMaster";
import { getOaWarehouseTaskByMasterId } from "@/api/oa/wms/warehouseTask";
export default {
name: "PurchaseOrderList",
data() {
return {
// 出库单列表数据
TaskList: [],
// 详情数据
warehouseTaskList: [],
// 当前选中项
currentItem: {},
// 加载状态
loading: false,
// 滚动区域高度
scrollHeight: 0,
// 分页参数
page: 1,
pageSize: 10,
// 加载更多状态
loadMoreStatus: 'more',
// 查询参数
queryParams: {
signTime: '',
type: 0,
pageNum: 1,
pageSize: 10
}
};
},
onLoad() {
// 计算滚动区域高度
this.calculateScrollHeight();
// 获取初始数据
this.getList();
},
methods: {
/** 计算滚动区域高度 */
calculateScrollHeight() {
const systemInfo = uni.getSystemInfoSync();
const headerHeight = 20; // 头部筛选区域高度
this.scrollHeight = systemInfo.windowHeight - headerHeight;
},
/** 日期选择变化时触发 */
handleDateChange() {
// 重置分页,重新加载数据
this.page = 1;
this.TaskList = [];
this.getList();
},
/** 查询出库单列表 */
getList() {
// 显示加载状态
this.loading = true;
// 设置分页参数
this.queryParams.pageNum = this.page;
this.queryParams.pageSize = this.pageSize;
listOaWarehouseMaster(this.queryParams)
.then((res) => {
const newData = res.rows || [];
// 如果是第一页,直接替换数据;否则追加数据
if (this.page === 1) {
this.TaskList = newData;
} else {
this.TaskList = [...this.TaskList, ...newData];
}
// 更新加载状态
if (newData.length < this.pageSize) {
this.loadMoreStatus = 'noMore'; // 没有更多数据
} else {
this.loadMoreStatus = 'more'; // 还有更多数据
}
})
.catch(() => {
uni.showToast({
title: '加载失败',
icon: 'none',
duration: 2000
});
})
.finally(() => {
this.loading = false;
});
},
/** 加载更多数据 */
loadMore() {
// 如果正在加载中或没有更多数据,则不执行
if (this.loading || this.loadMoreStatus !== 'more') {
return;
}
// 显示加载中状态
this.loadMoreStatus = 'loading';
// 页码加1
this.page++;
// 获取更多数据
this.getList();
},
/** 查看详情 */
showDetail(item) {
this.currentItem = item;
this.$refs.popup.open();
this.warehouseTaskList = item.warehouseList || [];
},
/** 计算日期差值(天) */
dayDiff(endTime) {
const end = new Date(endTime);
const now = new Date();
end.setHours(0, 0, 0, 0);
now.setHours(0, 0, 0, 0);
return Math.floor((end - now) / (1000 * 60 * 60 * 24));
},
onDateChange(e) {
this.queryParams.signTime = e.detail.value
},
/** 格式化时间 */
parseTime(time, format = '{y}-{m}-{d}') {
if (!time) return '';
const date = new Date(time);
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate()
};
return format.replace(/{(y|m|d)}/g, (match, key) => {
let value = formatObj[key];
if (value < 10) {
value = '0' + value;
}
return value;
});
}
}
};
</script>
<style scoped>
.container {
background-color: #f0f2f5;
min-height: 100vh;
padding: 20rpx;
box-sizing: border-box;
}
/* 滚动区域样式 */
.list-scroll {
width: 100%;
margin: 0 auto;
}
/* 单据容器 */
.documents-container {
/* margin-top: 20rpx; */
display: flex;
flex-direction: column;
gap: 20rpx;
padding-bottom: 30rpx;
}
/* 单据卡片样式 - 核心优化点 */
.document-card {
margin-top: 10rpx;
background-color: #fff;
border-radius: 8rpx;
border: 1px solid #e5e7eb;
padding: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
position: relative;
overflow: hidden;
}
/* 单据头部 */
.doc-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
padding-bottom: 15rpx;
border-bottom: 1px dashed #e5e7eb;
}
.doc-title {
font-size: 32rpx;
font-weight: 600;
color: #1d2129;
display: flex;
align-items: center;
}
.doc-title::before {
content: '';
display: inline-block;
width: 8rpx;
height: 24rpx;
background-color: #1677ff;
margin-right: 10rpx;
border-radius: 2rpx;
}
.status-tag {
transform: scale(0.85);
transform-origin: right center;
}
/* 单据编号 */
.doc-number {
padding: 10rpx 0;
margin-bottom: 10rpx;
border-left: 3rpx solid #e5e7eb;
padding-left: 15rpx;
}
.doc-number .label {
color: #86909c;
font-size: 26rpx;
}
.doc-number .value {
color: #1d2129;
font-size: 28rpx;
font-family: monospace;
letter-spacing: 1rpx;
}
/* 单据内容区域 */
.doc-content {
margin-bottom: 15rpx;
}
.doc-row {
display: flex;
margin-bottom: 12rpx;
}
.doc-col {
flex: 1;
}
.doc-col.full-width {
flex: 100%;
}
.label {
color: #86909c;
font-size: 26rpx;
display: inline-block;
width: 140rpx;
}
.value {
color: #1d2129;
font-size: 26rpx;
}
.remark {
color: #4e5969;
line-height: 1.5;
}
/* 单据底部 */
.doc-footer {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 15rpx;
margin-top: 10rpx;
border-top: 1px dashed #e5e7eb;
}
.doc-seal {
display: flex;
align-items: center;
color: #86909c;
font-size: 22rpx;
}
.seal-text {
margin-left: 8rpx;
}
.arrow-icon {
opacity: 0.7;
}
/* 空状态样式 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 150rpx 0;
}
.empty-text {
font-size: 28rpx;
color: #86909c;
margin-top: 20rpx;
}
/* 加载更多样式 */
.load-more {
padding: 30rpx 0;
}
/* 详情弹窗样式 */
.popup-container {
background-color: #fff;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
max-height: 1000rpx;
display: flex;
flex-direction: column;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 25rpx;
border-bottom: 1px solid #f2f3f5;
}
.popup-title {
font-size: 30rpx;
font-weight: 600;
color: #1d2129;
}
.close-icon {
color: #86909c;
}
.detail-scroll {
flex: 1;
padding: 20rpx;
height: 100%;
overflow-y: scroll;
}
.detail-document {
background-color: #fafafa;
border-radius: 10rpx;
border: 1px solid #f2f3f5;
padding: 15rpx;
}
.detail-header {
display: flex;
justify-content: space-between;
padding: 10rpx 0;
margin-bottom: 15rpx;
border-bottom: 1px dashed #e5e7eb;
}
.detail-masterNum {
font-size: 26rpx;
color: #1d2129;
font-family: monospace;
}
.detail-date {
font-size: 24rpx;
color: #86909c;
}
.detail-item {
margin-bottom: 15rpx;
background-color: #fff;
border-radius: 8rpx;
border: 1px solid #f2f3f5;
overflow: hidden;
}
.detail-content {
padding: 18rpx;
}
.detail-title {
display: flex;
align-items: center;
margin-bottom: 15rpx;
padding-bottom: 10rpx;
border-bottom: 1px solid #f2f3f5;
}
.item-num {
display: inline-block;
width: 36rpx;
height: 36rpx;
line-height: 36rpx;
text-align: center;
background-color: #f0f7ff;
color: #1677ff;
border-radius: 50%;
font-size: 22rpx;
margin-right: 10rpx;
}
.item-name {
font-size: 28rpx;
color: #1d2129;
font-weight: 500;
}
.detail-grid {
display: flex;
justify-content: space-between;
margin-bottom: 12rpx;
}
.grid-item {
flex: 1;
font-size: 24rpx;
}
.grid-item:first-child {
padding-right: 10rpx;
}
.grid-item:last-child {
padding-left: 10rpx;
}
.grid-label {
color: #86909c;
}
.grid-value {
color: #4e5969;
}
.detail-remark {
margin-top: 10rpx;
padding-top: 10rpx;
border-top: 1px dashed #f2f3f5;
font-size: 24rpx;
}
.remark-label {
color: #86909c;
}
.remark-value {
color: #4e5969;
line-height: 1.5;
}
</style>