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.

421 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>
<!-- 屏幕适配容器基于1920*1080设计稿防溢出+完整适配 -->
<v-scale-screen width="1920" height="1080" :fullScreen="false">
<div class="app-container home">
<!-- 头部区域标题+看板时间 -->
<div class="head">
<div class="head-content">
<div class="title">产线生产看板</div>
<div class="board-time">{{ currentTime }}</div>
</div>
</div>
<!-- 产线统计概览核心数据总览 -->
<div class="overview-card">
<div class="overview-item">
<span class="overview-label">总产线数</span>
<span class="overview-value">18</span>
</div>
<div class="overview-item">
<span class="overview-label">生产产线</span>
<span class="overview-value success">{{ productionLines.length }}</span>
</div>
<div class="overview-item">
<span class="overview-label">计划总产量</span>
<span class="overview-value">{{ planTotal }}</span>
</div>
<div class="overview-item">
<span class="overview-label">实际完成产量</span>
<span class="overview-value" :class="{ 'overview-warning': completeRate < 80 }">{{ completeTotal }}</span>
</div>
<div class="overview-item">
<span class="overview-label">完成比例</span>
<span class="overview-value" :class="{ 'overview-warning': completeRate < 80 }">{{ completeRate }} %</span>
</div>
</div>
<!-- 产线网格6列3行适配18条产线优化内边距避免挤压 -->
<div class="production-grid" :class="{ 'production-grid-mini': productionLines.length < 13 }">
<div
class="production-card"
v-for="line in productionLines"
:key="line.lineNo"
:class="{ 'line-warning': line.completionRate < 80 }"
>
<div class="line-number"> {{ line.equipmentName }}</div>
<!-- 修复1Vue中title绑定语法错误改为v-bind:title -->
<div class="product-name" >{{ line.productName }}</div>
<div class="data-group">
<div class="data-item">
<span class="label">计划产量:</span>
<span class="value plan-value">{{ line.planTotal }}</span>
</div>
<div class="data-item">
<span class="label">当前产量:</span>
<span class="value current-value" :class="{ 'reach': line.currentOutput >= line.planOutput }">
{{ line.completTotal || 0 }}
</span>
</div>
<div class="data-item efficiency-item">
<div class="efficiency-top">
<span class="label">产量完成率:</span>
<span class="value efficiency-value" :class="{ 'reach': line.completionRate >= 80 }">
{{ line.completionRate }}%
</span>
</div>
<div class="efficiency-progress">
<div
class="progress-bar"
:style="{ width: line.completionRate + '%' }"
:class="{ 'progress-reach': line.completionRate >= 80 }"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</v-scale-screen>
</template>
<script>
import {getProductionLineData} from "@/api/kanban/Packagingline";
export default {
name: 'ProductionBoard',
data() {
return {
productionLines: [],
currentTime: '',
planTotal:0,
completeTotal: 0,
completeRate: 0
}
},
created() {
this.initProductionData();
setInterval(() => {
this.initProductionData();
}, 5000);
setInterval(() => {
this.updateCurrentTime();
}, 1000);
},
methods: {
// 初始化产线数据添加产量完成率保留1位小数
initProductionData() {
getProductionLineData().then(res=>{
let planTotal = 0
let completeTotal = 0
for (const line of res.data){
if (line.planTotal){
planTotal = planTotal + line.planTotal
}
if (line.completTotal){
completeTotal = completeTotal + line.completTotal
line.completionRate = (line.completTotal / line.planTotal * 100).toFixed(1)
}else {
line.completionRate = 0
}
}
let completeRate = ((completeTotal/planTotal) * 100 ).toFixed(1)
this.planTotal = planTotal
this.completeTotal = completeTotal
this.completeRate = completeRate
this.productionLines = res.data
})
},
// 更新看板当前时间格式YYYY-MM-DD HH:mm:ss
updateCurrentTime() {
const now = new Date()
this.currentTime = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
}).replace(/\//g, '-')
},
}
}
</script>
<style scoped>
/* 全局容器修复高度100%继承配合v-scale-screen满屏展示无溢出 */
.app-container {
padding: 0;
width: 100%;
box-sizing: border-box;
overflow: hidden; /* 核心:防止页面整体溢出滚动 */
}
.home {
width: 100%;
background: url("../../../assets/images/bg1.jpg") no-repeat center center;
background-size: cover;
background-color: #050711;
display: flex;
flex-direction: column;
gap: 16px; /* 区域间距,避免内容挤压 */
padding: 16px 24px; /* 全局内边距,防止内容贴边 */
box-sizing: border-box;
}
/* 头部区域:固定高度,避免占用过多空间,内容垂直居中 */
.head {
width: 100%;
height: 74px; /* 降低高度,为下方内容释放空间 */
position: relative;
display: flex;
align-items: center;
flex-shrink: 0; /* 禁止头部压缩,确保高度固定 */
}
/* .head-content 保留原有样式,无需修改 */
.head-content {
width: 100%;
height: 100%;
background: url("../../../assets/images/bg-head.png") no-repeat center center;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
position: relative;
}
/* 标题字体放大28px → 36px醒目且不挤压 */
.title {
position: absolute;
font-size: 36px;
color: #ffffff;
font-weight: 500;
margin: 0;
top: 0;
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
/* 时间字体同步放大16px → 20px与标题比例协调 */
.board-time {
position: absolute;
right: 20px;
top: 70%;
transform: translateY(-50%);
font-size: 20px;
color: #e0e0e0;
margin: 0;
}
/* 概览卡片:降低高度和内边距,紧凑布局,释放垂直空间 */
.overview-card {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
border-radius: 8px;
padding: 20px 0; /* 减少上下内边距 */
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
flex-shrink: 0; /* 禁止概览区压缩 */
height: 120px; /* 固定高度,避免占用过多空间 */
}
.overview-item {
text-align: center;
padding: 0 16px;
}
.overview-label {
display: block;
font-size: 24px;
color: #95a5a6;
margin-bottom: 4px; /* 减少间距,紧凑布局 */
}
.overview-value {
font-size: 26px; /* 降低字体,适配紧凑布局 */
color: #ffffff;
font-weight: 600;
line-height: 1.2;
}
.overview-value.success {
color: #2ecc71;
}
.overview-warning{
color: #f39c12;
}
/* 产线网格:核心修复显示不全,优化间距/高度,确保内容完整展示 */
.production-grid {
display: grid;
grid-template-columns: repeat(6, 1fr); /* 6列3行完美适配18条产线 */
grid-template-rows: repeat(3, 1fr); /* 等分剩余高度,无多余空白 */
gap: 20px; /* 减小网格间距,避免间距占用过多垂直空间 */
flex: 1; /* 填充父容器剩余高度,核心布局属性 */
box-sizing: border-box;
padding: 0; /* 移除多余内边距,释放空间 */
overflow: hidden; /* 防止网格内部内容溢出 */
}
.production-grid-mini{
grid-template-columns: repeat(4, 1fr); /* 5列4行完美适配18条产线 */
grid-template-rows: repeat(4, 1fr); /* 等分剩余高度,无多余空白 */
}
/* 单个产线卡片:彻底修复内容挤压,优化内边距/字体/间距 */
.production-card {
background: rgba(14, 28, 56, 0.9);
border-radius: 6px;
padding: 10px 12px; /* 适中内边距,内容不贴边也不挤压 */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
box-sizing: border-box;
width: 100%;
height: 100%; /* 卡片满网格单元格高度,无空白 */
display: flex;
flex-direction: column;
gap: 6px; /* 减小内部元素间距,紧凑但不拥挤 */
}
/* 卡片悬浮效果:细腻交互,不影响布局 */
.production-card:hover {
box-shadow: 0 6px 16px rgba(0, 183, 255, 0.2);
transform: translateY(-2px);
border-color: rgba(0, 183, 255, 0.4);
}
/* 产量未达标标识:宽度适中,醒目不占空间 */
.line-warning {
border-left: 3px solid #f39c12;
}
/* 产线编号:字体适中,分隔线细腻 */
.line-number {
font-size: 24px;
font-weight: 600;
color: #ffffff;
padding-bottom: 4px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
line-height: 1.2;
white-space: nowrap;
margin: 0;
}
/* 产品名称:强制换行+高度自适应,超长名称自动折行显示 */
.product-name {
font-size: 22px;
color: #a0b4c8;
word-wrap: break-word !important; /* 强制换行,兼容所有浏览器 */
word-break: break-all !important; /* 中英文/数字混合也能正常换行,无截断 */
white-space: normal !important; /* 核心:取消原有不换行限制,覆盖所有冲突样式 */
min-height: 24px; /* 最小高度,避免内容过少时挤压下方 */
overflow: hidden; /* 超出最大高度时隐藏,不影响布局 */
cursor: help;
}
/* 数据组容器:弹性填充卡片剩余高度,内容垂直居中 */
.data-group {
display: flex;
flex-direction: column;
gap: 8px; /* 数据项间距适中,阅读舒适 */
flex: 1; /* 填充卡片剩余高度,无空白 */
justify-content: center; /* 内容垂直居中,避免挤压 */
box-sizing: border-box;
margin: 0;
}
/* 单个数据项:字体缩小,行高优化,紧凑布局 */
.data-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 20px; /* 核心:降低字体大小,适配小卡片,避免内容溢出 */
width: 100%;
line-height: 1.3; /* 行高适中,不重叠 */
margin: 0;
}
/* 标签和数值:颜色适配深色主题,对比度适中 */
.label {
color: #8fa4b8;
font-weight: 400;
}
.value {
color: #e0efff;
font-weight: 600;
}
/* 计划产量颜色:浅蓝色,清晰区分 */
.plan-value {
color: #4fc3f7;
}
/* 达标状态统一绿色,未达标浅橙色,视觉区分明确 */
.current-value.reach,
.completion-rate.reach,
.efficiency-value.reach {
color: #2ecc71;
}
.current-value,
.completion-rate {
color: #ffb74d;
}
/* 效率项:布局紧凑,进度条适配 */
.efficiency-item {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px; /* 减小间距,紧凑布局 */
width: 100%;
margin: 0;
}
.efficiency-top {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
.efficiency-value {
font-size: 20px !important;
color: #ffb74d;
}
/* 效率进度条:高度适中,不占空间,样式细腻 */
.efficiency-progress {
width: 100%;
height: 5px; /* 降低进度条高度,紧凑布局 */
background: rgba(255, 255, 255, 0.1);
border-radius: 2px;
overflow: hidden;
box-sizing: border-box;
}
.progress-bar {
height: 100%;
background: #f39c12;
border-radius: 2px;
transition: width 0.8s ease-in-out;
}
.progress-bar.progress-reach {
background: #2ecc71;
}
</style>