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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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