You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
udiwms-vue-frame/src/views/collect/IosplitFifoStock.vue

458 lines
12 KiB
Vue

<template>
<div class="dashboard-container">
<!-- 搜索区域 -->
<div class="search-section">
<div class="search-wrapper">
<el-input
placeholder="请输入产品名称搜索"
prefix-icon="el-icon-search"
v-model="filterQuery.cpmctymc"
@keyup.enter.native="handleSearch"
clearable
>
<el-button slot="append" icon="el-icon-refresh" @click="onReset"></el-button>
<el-button slot="append" icon="el-icon-search" @click="handleSearch" >查询</el-button>
</el-input>
</div>
</div>
<!--展示区域-->
<div class="card-container" ref="scrollContainer">
<el-row :gutter="20">
<el-col :span="8" v-for="(item, index) in displayedData" :key="index">
<el-card class="product-card" :body-style="{ padding: '0px' }">
<div class="card-header">
<h3 class="product-name" :title="item.productName">{{ item.productName }}</h3>
<div class="product-info">
<span class="batch-no">{{ item.prepnSpec }}</span>
<span class="expire-date">{{ item.ggxh }}</span>
</div>
</div>
<div class="card-body">
<div class="progress-item">
<div class="progress-label">
<span>工位存量</span>
<span class="progress-value">{{ item.workplaceStock }}/{{ item.workplaceTotal }}</span>
</div>
<el-progress
:text-inside="true"
:percentage="calculatePercentage(item.workplaceStock, item.workplaceTotal)"
:color="getProgressColor(item.workplaceStock, item.workplaceTotal)"
:stroke-width="20"
></el-progress>
</div>
<div class="progress-item">
<div class="progress-label">
<span>拆零存量</span>
<span class="progress-value">{{ item.splitStock }}/{{ item.splitTotal }}</span>
</div>
<el-progress
:text-inside="true"
:percentage="calculatePercentage(item.splitStock, item.splitTotal)"
:color="getProgressColor(item.splitStock, item.splitTotal)"
:stroke-width="20"
></el-progress>
</div>
</div>
</el-card>
</el-col>
</el-row>
<div v-if="dataLoading" class="loading-more">...</div>
<div v-if="!dataLoading && displayedData.length >= displayData.length" class="no-more-data"></div>
</div>
</div>
</template>
<script>
import { getStockList } from '@/api/inout/splitInv'
export default {
name: "IosplitFifoStock",
data() {
return {
filterQuery: {
page: 1,
limit: 1000,
cpmctymc:""
},
total: 0,
limit: 6,
loadLimit:3,
page: 1, // 当前页码
displayData: [],
displayedData:[],
loading: false,
dataLoading: false,
colorRanges: [
{ min: 0, max: 20, color: '#F56C6C' }, // 红色 - 危险
{ min: 20, max: 50, color: '#E6A23C' }, // 橙色 - 警告
{ min: 50, max: 80, color: '#409EFF' }, // 蓝色 - 正常
{ min: 80, max: 101, color: '#67C23A' } // 绿色 - 良好
],
delay:1500,
timer: null,
fast: false,
}
},
mounted() {
// this.loadInitialData();
const scrollContainer = this.$refs.scrollContainer;
scrollContainer.addEventListener("scroll", this.handleScroll);
this.startTimer()
},
beforeDestroy(){
const scrollContainer = this.$refs.scrollContainer;
scrollContainer.removeEventListener("scroll", this.handleScroll);
this.clearTimer()
},
methods: {
loadInitialData() {
this.displayedData = this.displayData.slice(0, this.limit);
},
handleScroll() {
// alert("jajajjaja")
const { scrollTop, clientHeight, scrollHeight } = this.$refs.scrollContainer;
const threshold = 10; // 阈值距离底部10px时触发
if (scrollTop + clientHeight >= scrollHeight - threshold) {
this.loadMoreData();
}
// 检测是否滚动到底部
// if (
// window.innerHeight + document.documentElement.scrollTop >=
// document.documentElement.offsetHeight - 10
// ) {
// this.loadMoreData();
// }
},
loadMoreData() {
if (this.dataLoading) return; // 如果正在加载,直接返回
this.dataLoading = true;
setTimeout(() => {
// 计算下一页的数据范围
const start = this.displayedData.length;
const end = start + this.loadLimit; // 每次加载3条数据
// 加载更多数据
const moreData = this.displayData.slice(start, end);
if (moreData.length > 0) {
this.displayedData = [...this.displayedData, ...moreData];
}
this.dataLoading = false; // 关闭加载状态
}, this.delay); // 延迟3秒后加载数据
},
onReset() {
this.filterQuery = {
page: 1,
limit: 1000,
cpmctymc:""
}
this.getList();
},
handleSearch() {
this.filterQuery.page = 1;
this.getList();
},
handleSizeChange(val) {
this.filterQuery.limit = val;
this.getList();
},
handleCurrentChange(val) {
this.filterQuery.page = val;
this.getList();
},
getList() {
this.loading = true;
// // 调用API获取数据
getStockList(this.filterQuery)
.then(response => {
if (response.code === 20000) {
// 处理返回的数据
this.total = response.data.total || 0;
// 转换数据格式以适应展示需求
this.displayData = (response.data.list || []).map(item => {
return {
productName: item.cpmctymc || '未知产品',
prepnSpec: item.prepnSpec ,
ggxh: item.ggxh ,
workplaceStock: item.remCount || 0,
workplaceTotal: item.maxDrugCount || 100,
splitStock: item.splitRemCount || 0,
splitTotal: item.maxDrugCount || 100
};
});
this.loadInitialData()
} else {
this.$message.error(response.message || '获取数据失败');
this.displayData = [];
this.total = 0;
}
this.loading = false;
})
.catch(error => {
console.error('获取数据失败:', error);
this.$message.error('获取数据失败,请稍后重试');
this.displayData = [];
this.total = 0;
this.loading = false;
});
},
calculatePercentage(current, total) {
if (!total || total === 0) return 0;
// const percentage = (current / total) * 100;
// return Math.min(100, Math.max(0, percentage));
const percentage = Math.round((current * 100) / total);
return Math.min(100, Math.max(0, percentage));
},
getProgressColor(current, total) {
if (!total || total === 0) return this.colorRanges[0].color;
const percentage = this.calculatePercentage(current, total);
// 根据百分比返回对应的颜色
for (const range of this.colorRanges) {
if (percentage >= range.min && percentage < range.max) {
return range.color;
}
}
return this.colorRanges[0].color;
},
timeGetList() {
this.loading = true;
// // 调用API获取数据
getStockList(this.filterQuery)
.then(response => {
if (response.code === 20000) {
// 处理返回的数据
this.total = response.data.total || 0;
// 转换数据格式以适应展示需求
this.displayData = (response.data.list || []).map(item => {
return {
productName: item.cpmctymc || '未知产品',
prepnSpec: item.prepnSpec ,
ggxh: item.ggxh ,
workplaceStock: item.remCount || 0,
workplaceTotal: item.maxDrugCount || 100,
splitStock: item.splitRemCount || 0,
splitTotal: item.maxDrugCount || 100
};
});
} else {
this.$message.error(response.message || '获取数据失败');
this.displayData = [];
this.total = 0;
}
this.loading = false;
})
.catch(error => {
console.error('获取数据失败:', error);
this.$message.error('获取数据失败,请稍后重试');
this.displayData = [];
this.total = 0;
this.loading = false;
});
},
startTimer() {
// 使用箭头函数保持正确的 this 指向
this.timer = setInterval(() => {
this.timeGetList()
}, 5000) // 2分钟 = 120秒 * 1000毫秒
},
clearTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
},
computed: {
noMore () {
return this.count >= 21
},
disabled () {
return this.loading || this.noMore
}
},
created() {
this.getList()
},
};
</script>
<style scoped>
.dashboard-container {
height: 85vh; /* 使用视口高度单位,确保铺满整个屏幕 */
width: 100%;
background-color: #f5f7fa;
padding: 20px;
display: flex;
flex-direction: column;
box-sizing: border-box; /* 确保padding不会增加总高度 */
overflow: hidden; /* 防止内容溢出 */
}
.search-section {
margin-top: 20px;
margin-bottom: 10px;
}
.search-wrapper {
max-width: 600px;
margin: 0 0; /* 修改为左对齐 */
}
.display-section {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden; /* 防止内容溢出 */
}
.card-container {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 20px; /* 为分页腾出空间 */
}
.product-card {
height: 220px; /* 增加卡片高度 */
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
overflow: hidden;
display: flex;
flex-direction: column;
}
.product-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
.card-header {
background-color: #409EFF;
color: white;
padding: 15px;
}
.product-name {
margin: 0;
font-size: 18px;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.product-info {
display: flex;
justify-content: space-between;
margin-top: 5px;
font-size: 12px;
opacity: 0.9;
}
.card-body {
padding: 20px; /* 增加内边距 */
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-around; /* 均匀分布进度条 */
}
.progress-item {
margin-bottom: 20px; /* 增加进度条之间的间距 */
}
.progress-item:last-child {
margin-bottom: 0;
}
.progress-label {
display: flex;
justify-content: space-between;
margin-bottom: 8px; /* 增加标签和进度条之间的间距 */
font-size: 14px;
color: #606266;
}
.progress-value {
font-weight: 600;
}
.pagination-container {
margin-top: 20px;
text-align: center;
padding: 10px 0;
}
/* 响应式调整 */
@media screen and (max-width: 1200px) {
.el-col {
width: 100% !important;
}
.product-card {
height: 200px; /* 在小屏幕上稍微减小高度 */
}
}
/* 自定义进度条样式 */
:deep(.el-progress-bar__outer) {
border-radius: 6px;
background-color: #ebeef5;
height: 12px !important; /* 确保进度条高度 */
}
:deep(.el-progress-bar__inner) {
border-radius: 6px;
transition: width 0.6s ease, background-color 0.6s ease;
}
/* 大屏模式下的额外样式 */
@media screen and (min-width: 1920px) {
.dashboard-container {
padding: 10px;
}
.product-card {
height: 240px; /* 在大屏幕上增加高度 */
}
.product-name {
font-size: 22px;
}
.progress-label {
font-size: 16px;
}
.progress-item {
margin-bottom: 25px;
}
}
.loading-more,
.no-more-data {
text-align: center;
margin-top: 10px;
font-size: 14px;
color: #999;
}
</style>