feat:车间看板公共模板初版
This commit is contained in:
parent
1693b9d3da
commit
390e05f999
|
|
@ -0,0 +1,894 @@
|
||||||
|
<template>
|
||||||
|
<el-container class="dashboard">
|
||||||
|
<!-- Header -->
|
||||||
|
<el-header class="dash-header">
|
||||||
|
<div class="dash-header-side dash-header-left">
|
||||||
|
<span class="header-tag">PHOTON · {{ mgroupName }}</span>
|
||||||
|
<span class="header-status"><i class="led-dot"></i>实时数据</span>
|
||||||
|
</div>
|
||||||
|
<div class="dash-header-center">
|
||||||
|
<div class="dash-title">{{ mgroupName }}工段生产数据看板</div>
|
||||||
|
<div class="dash-title-deco"><span></span><i></i><span></span></div>
|
||||||
|
</div>
|
||||||
|
<div class="dash-header-side dash-header-right">
|
||||||
|
<div class="dash-day">{{ currentDay }}</div>
|
||||||
|
<div class="dash-time">{{ currentTime }}</div>
|
||||||
|
</div>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
|
<el-main class="dash-main">
|
||||||
|
<!-- KPI Cards -->
|
||||||
|
<div class="kpi-row">
|
||||||
|
<div class="kpi-card kpi-c1">
|
||||||
|
<div class="kpi-meta">
|
||||||
|
<div class="kpi-label">日投产量</div>
|
||||||
|
<div class="kpi-sub">DAILY INPUT</div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-value">{{ sctj.rtcs }}</div>
|
||||||
|
<div class="kpi-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-card kpi-c2">
|
||||||
|
<div class="kpi-meta">
|
||||||
|
<div class="kpi-label">日加工数</div>
|
||||||
|
<div class="kpi-sub">PROCESSED</div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-value">{{ sctj.rjgs }}</div>
|
||||||
|
<div class="kpi-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-card kpi-c3">
|
||||||
|
<div class="kpi-meta">
|
||||||
|
<div class="kpi-label">加工前不良</div>
|
||||||
|
<div class="kpi-sub">PRE-DEFECT</div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-value">{{ sctj.rjgqbls }}</div>
|
||||||
|
<div class="kpi-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-card kpi-c4">
|
||||||
|
<div class="kpi-meta">
|
||||||
|
<div class="kpi-label">日合格数</div>
|
||||||
|
<div class="kpi-sub">QUALIFIED</div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-value">{{ sctj.rhgs }}</div>
|
||||||
|
<div class="kpi-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-card kpi-c5">
|
||||||
|
<div class="kpi-meta">
|
||||||
|
<div class="kpi-label">日不合格数</div>
|
||||||
|
<div class="kpi-sub">REJECTED</div>
|
||||||
|
</div>
|
||||||
|
<div class="kpi-value">{{ sctj.rbhgs }}</div>
|
||||||
|
<div class="kpi-bar"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Top row: 2 panels -->
|
||||||
|
<el-row :gutter="12" type="flex" class="row-top">
|
||||||
|
<el-col :span="12" class="col-full">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span class="panel-title">设备状态</span>
|
||||||
|
<div class="panel-states">
|
||||||
|
<span class="state-chip s-run"><i></i>运行<em>{{ hh.yx }}</em></span>
|
||||||
|
<span class="state-chip s-idle"><i></i>未运行<em>{{ hh.wyx }}</em></span>
|
||||||
|
<span class="state-chip s-err"><i></i>故障<em>{{ hh.gz }}</em></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body" id="scrollContainer">
|
||||||
|
<dv-scroll-board :config="configDataEq" class="board" />
|
||||||
|
</div>
|
||||||
|
<i class="corner tl"></i><i class="corner tr"></i>
|
||||||
|
<i class="corner bl"></i><i class="corner br"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="col-full">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span class="panel-title">昨日损耗分析</span>
|
||||||
|
<span class="panel-sub">LOSS ANALYSIS</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body chart-body" id="chart2"></div>
|
||||||
|
<i class="corner tl"></i><i class="corner tr"></i>
|
||||||
|
<i class="corner bl"></i><i class="corner br"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- Bottom row: 2 panels -->
|
||||||
|
<el-row :gutter="12" type="flex" class="row-bottom">
|
||||||
|
<el-col :span="12" class="col-full">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span class="panel-title">生产统计</span>
|
||||||
|
<span class="panel-sub">DAILY STATISTICS</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<dv-scroll-board :config="configDatas" class="board" />
|
||||||
|
</div>
|
||||||
|
<i class="corner tl"></i><i class="corner tr"></i>
|
||||||
|
<i class="corner bl"></i><i class="corner br"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" class="col-full">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span class="panel-title">车间库存</span>
|
||||||
|
<span class="panel-sub">INVENTORY</span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<dv-scroll-board :config="configDataInm" class="board" />
|
||||||
|
</div>
|
||||||
|
<i class="corner tl"></i><i class="corner tr"></i>
|
||||||
|
<i class="corner bl"></i><i class="corner br"></i>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as echarts from "echarts";
|
||||||
|
import scScrollTavle from "@/components/scScrollTable.vue";
|
||||||
|
function deepCopy(obj) {
|
||||||
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
components: { scScrollTavle },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pieOption: {
|
||||||
|
backgroundColor: "",
|
||||||
|
tooltip: { trigger: 'item' },
|
||||||
|
legend: {
|
||||||
|
icon: "stack",
|
||||||
|
right: 10,
|
||||||
|
orient: 'vertical',
|
||||||
|
itemWidth: 10,
|
||||||
|
itemHeight: 10,
|
||||||
|
textStyle: { color: '#c8f2ff', fontSize: 11 },
|
||||||
|
},
|
||||||
|
series: {
|
||||||
|
name: '不合格占比',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['35%', '65%'],
|
||||||
|
center: ['38%', '52%'],
|
||||||
|
itemStyle: {
|
||||||
|
borderColor: 'rgba(3, 22, 26, 0.8)',
|
||||||
|
borderWidth: 2,
|
||||||
|
},
|
||||||
|
label: { show: false },
|
||||||
|
labelLine: { show: false },
|
||||||
|
data: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tableHeight: 100,
|
||||||
|
speed: 2000,
|
||||||
|
time: null,
|
||||||
|
hh: {
|
||||||
|
yx: 0,
|
||||||
|
wyx: 0,
|
||||||
|
gz: 0,
|
||||||
|
},
|
||||||
|
sctj: {
|
||||||
|
rtcs: 0,
|
||||||
|
rjgs: 0,
|
||||||
|
rjgqbls: 0,
|
||||||
|
rhgs: 0,
|
||||||
|
rbhgs: 0,
|
||||||
|
},
|
||||||
|
dayInterval: null,
|
||||||
|
chartInterval2: null,
|
||||||
|
//库存
|
||||||
|
configDataInm: {
|
||||||
|
header: ['物料名称', '批次号', '数量', '生产中'],
|
||||||
|
headerBGC: 'rgba(0, 229, 255, 0.16)',
|
||||||
|
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
|
||||||
|
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
|
||||||
|
headerHeight: 38,
|
||||||
|
rowNum: 8,
|
||||||
|
align: 'center',
|
||||||
|
data: [],
|
||||||
|
waitTime: 1500,
|
||||||
|
},
|
||||||
|
//设备
|
||||||
|
configDataEq: {
|
||||||
|
headerBGC: 'rgba(0, 229, 255, 0.16)',
|
||||||
|
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
|
||||||
|
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
|
||||||
|
header: ['设备名称', '设备编号', '设备状态', '物料数量'],
|
||||||
|
headerHeight: 38,
|
||||||
|
rowNum: 8,
|
||||||
|
align: 'center',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
//生产统计
|
||||||
|
configDatas: {
|
||||||
|
headerBGC: 'rgba(0, 229, 255, 0.16)',
|
||||||
|
oddRowBGC: 'rgba(0, 229, 255, 0.04)',
|
||||||
|
evenRowBGC: 'rgba(0, 229, 255, 0.10)',
|
||||||
|
header: ['日期', '加工数', '合格数', '不合格数'],
|
||||||
|
headerHeight: 38,
|
||||||
|
rowNum: 7,
|
||||||
|
align: 'center',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
page: 1,
|
||||||
|
currentTime: "",
|
||||||
|
currentDay: "",
|
||||||
|
mgroupName: "",
|
||||||
|
mgroupId: "",
|
||||||
|
today: "",
|
||||||
|
end_time: '',
|
||||||
|
start_time: '',
|
||||||
|
daysList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
let that = this;
|
||||||
|
let arr = this.$route.path.split("/");
|
||||||
|
that.mgroup_code = arr[2];
|
||||||
|
that.page = 1;
|
||||||
|
that.getMgroups(this.mgroup_code);
|
||||||
|
that.configDataInm.data = [];
|
||||||
|
//表格table的高度
|
||||||
|
this.tableHeight = document.getElementById("scrollContainer").clientHeight;
|
||||||
|
this.showTime();
|
||||||
|
this.dayInterval = setInterval(() => {
|
||||||
|
this.showTime();
|
||||||
|
}, 1000);
|
||||||
|
//近七天的日期数组
|
||||||
|
let daysArr = this.getMondayOfCurrentWeek();
|
||||||
|
this.daysArr = daysArr;
|
||||||
|
let xAxisData = [];
|
||||||
|
daysArr.forEach((item) => {
|
||||||
|
let dates = item.split('-');
|
||||||
|
let obj = dates[1] + '-' + dates[2];
|
||||||
|
xAxisData.push(obj);
|
||||||
|
let dayitem = Number(dates[2]);
|
||||||
|
that.daysList.push(dayitem);
|
||||||
|
})
|
||||||
|
that.today = new Date().toISOString().split('T')[0];
|
||||||
|
that.yesterday = new Date(new Date().getTime() - 24 * 60 * 60 * 1000).toISOString().split('T')[0];
|
||||||
|
this.xAxisData = xAxisData;
|
||||||
|
let startDate = new Date(daysArr[0]).getTime() - (1000 * 60 * 60 * 24);
|
||||||
|
let endDate = new Date(daysArr[6]).getTime() + (1000 * 60 * 60 * 24);
|
||||||
|
let start_time = this.$TOOL.dateFormat(new Date(startDate), "yyyy-MM-dd");
|
||||||
|
let end_time = this.$TOOL.dateFormat(new Date(endDate), "yyyy-MM-dd");
|
||||||
|
this.start_time = start_time;
|
||||||
|
this.end_time = end_time;
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.dayInterval) clearInterval(this.dayInterval);
|
||||||
|
if (this.chartInterval2) clearInterval(this.chartInterval2);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMgroups(code){
|
||||||
|
let that = this;
|
||||||
|
that.$API.mtm.mgroup.list.req({page:0,code}).then((res) => {
|
||||||
|
that.mgroupName = res[0].name;
|
||||||
|
that.mgroupId = res[0].id;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
that.getEqState(that.mgroupId);
|
||||||
|
this.getMaterials(that.page);
|
||||||
|
this.getProductLine();
|
||||||
|
this.getCountnotok();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getMondayOfCurrentWeek() {
|
||||||
|
let today = new Date();
|
||||||
|
let days = [];
|
||||||
|
for (let i = 6; i >= 0; i--) {
|
||||||
|
let date = new Date(today);
|
||||||
|
date.setDate(today.getDate() - i);
|
||||||
|
days.push(date.toISOString().split('T')[0]);
|
||||||
|
}
|
||||||
|
return days;
|
||||||
|
},
|
||||||
|
//时间
|
||||||
|
showTime() {
|
||||||
|
this.currentTime = this.$TOOL.dateFormat(new Date(), "hh:mm:ss");
|
||||||
|
this.currentDay = this.$TOOL.dateFormat(
|
||||||
|
new Date(),
|
||||||
|
"yyyy年MM月dd日"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setChart(name, option = null) {
|
||||||
|
let dom = document.getElementById(name);
|
||||||
|
if (!dom) return null;
|
||||||
|
var myChart = echarts.getInstanceByDom(dom);
|
||||||
|
if (myChart == undefined) {
|
||||||
|
myChart = echarts.init(dom, "dark", {
|
||||||
|
renderer: "svg",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (option == null) {
|
||||||
|
option = Object.assign({}, this.barOption);
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
myChart.setOption(option);
|
||||||
|
} catch (error) { }
|
||||||
|
}, 500);
|
||||||
|
return myChart;
|
||||||
|
},
|
||||||
|
//生产统计
|
||||||
|
getProductLine() {
|
||||||
|
let that = this;
|
||||||
|
let obj = {
|
||||||
|
query: { start_date: that.start_time, end_date: that.end_time, mgroup_name: that.mgroupName },
|
||||||
|
};
|
||||||
|
that.$API.bi.dataset.exec.req("lineDay", obj).then((res) => {
|
||||||
|
let list = res.data2.ds0;
|
||||||
|
if (list.length > 0) {
|
||||||
|
list.forEach((item) => {
|
||||||
|
let dateNow = new Date().getDate();
|
||||||
|
if (item.日 == dateNow) {
|
||||||
|
that.sctj.rtcs = item.总重量;
|
||||||
|
that.sctj.rjgs = item.生产数;
|
||||||
|
that.sctj.rjgqbls = item.生产数 - item.不合格数 - item.合格数;
|
||||||
|
that.sctj.rhgs = item.合格数;
|
||||||
|
that.sctj.rbhgs = item.不合格数;
|
||||||
|
}
|
||||||
|
let arr = [];
|
||||||
|
arr[0] = item.年 + '-' + item.月 + '-' + item.日;
|
||||||
|
arr[1] = item.生产数;
|
||||||
|
arr[2] = item.合格数;
|
||||||
|
arr[3] = item.不合格数;
|
||||||
|
that.configDatas.data.push(arr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//不合格分布
|
||||||
|
getCountnotok() {
|
||||||
|
let that = this;
|
||||||
|
let obj = {
|
||||||
|
query: { start_date: that.yesterday, end_date: that.yesterday,mgroup_name:that.mgroupName }
|
||||||
|
};
|
||||||
|
that.$API.bi.dataset.exec.req('notok_dis', obj).then((res) => {
|
||||||
|
let seriesData = [];
|
||||||
|
if (res.data2.ds0) {
|
||||||
|
res.data2.ds0.forEach((item) => {
|
||||||
|
let obj = {};
|
||||||
|
obj.name = item.不合格项;
|
||||||
|
obj.value = item.数量;
|
||||||
|
seriesData.push(obj);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
that.pieOption.series.data = seriesData;
|
||||||
|
let index2 = 0;
|
||||||
|
let chart2 = this.setChart("chart2", that.pieOption);
|
||||||
|
if (!chart2) return;
|
||||||
|
this.chartInterval2 = setInterval(function () {
|
||||||
|
if (index2 < seriesData.length) {
|
||||||
|
chart2.dispatchAction({ type: "downplay", seriesIndex: 0 });
|
||||||
|
chart2.dispatchAction({ type: "highlight", seriesIndex: 0, dataIndex: index2 });
|
||||||
|
chart2.dispatchAction({ type: "showTip", seriesIndex: 0, dataIndex: index2 });
|
||||||
|
index2++;
|
||||||
|
} else {
|
||||||
|
index2 = 0;
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
//设备状态
|
||||||
|
getEqState(id) {
|
||||||
|
let that = this;
|
||||||
|
that.$API.wpm.ana.equipLastMlog.req({ mgroup: id }).then((res) => {
|
||||||
|
that.hh.yx += res.运行;
|
||||||
|
that.hh.wyx += res.未运行;
|
||||||
|
that.hh.gz += res.故障;
|
||||||
|
if (res.rows.length > 0) {
|
||||||
|
res.rows.forEach((item) => {
|
||||||
|
let arr = [];
|
||||||
|
arr[0] = item.name;
|
||||||
|
arr[1] = item.number;
|
||||||
|
if (item.mstate == '运行') {
|
||||||
|
arr[2] = '<span style="color:#00e5ff">● 运行中</span>';
|
||||||
|
} else if (item.mstate == '未运行') {
|
||||||
|
arr[2] = '<span style="color:#45b076">● 未运行</span>';
|
||||||
|
} else if (item.mstate == '故障') {
|
||||||
|
arr[2] = '<span style="color:#de3c36">● 故障</span>';
|
||||||
|
}
|
||||||
|
arr[3] = item.t_count_use ? item.t_count_use : 0;
|
||||||
|
that.configDataEq.data.push(arr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//库存统计列表
|
||||||
|
getMaterials(page) {
|
||||||
|
let that = this;
|
||||||
|
let query = '{ material_name, batch, count, count_working }';
|
||||||
|
that.$API.wpm.wmaterial.list.req({ page: page, page_size: 500, mgroup: that.mgroupId, query: query }).then((res) => {
|
||||||
|
if (res.results.length > 0) {
|
||||||
|
res.results.forEach((item) => {
|
||||||
|
let arr = [];
|
||||||
|
arr[0] = item.material_name;
|
||||||
|
arr[1] = item.batch;
|
||||||
|
arr[2] = item.count;
|
||||||
|
arr[3] = item.count_working;
|
||||||
|
that.configDataInm.data.push(arr);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@font-face {
|
||||||
|
font-family: "myfont";
|
||||||
|
src: url("../../../utils/youShe.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard,
|
||||||
|
.dashboard * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #00181c url("/public/img/photon_bg.png") center / cover no-repeat;
|
||||||
|
color: #fff;
|
||||||
|
font-family: "Microsoft Yahei" !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse at 20% 0%, rgba(0, 229, 255, 0.10), transparent 55%),
|
||||||
|
radial-gradient(ellipse at 80% 100%, rgba(0, 122, 153, 0.18), transparent 55%);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= Header ============= */
|
||||||
|
.dash-header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 0 0 72px !important;
|
||||||
|
height: 72px !important;
|
||||||
|
padding: 0 24px !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: url("/public/img/photon_header.png") center / 100% 100% no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-header-side {
|
||||||
|
flex: 0 0 280px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-header-right {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-header-center {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-title {
|
||||||
|
font-family: "myfont", "Microsoft Yahei";
|
||||||
|
font-size: 30px;
|
||||||
|
font-weight: bold;
|
||||||
|
letter-spacing: 8px;
|
||||||
|
background: linear-gradient(180deg, #ffffff 0%, #b9fbff 55%, #00d4ff 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
text-shadow: 0 0 22px rgba(0, 212, 255, 0.45);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-title-deco {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-title-deco span {
|
||||||
|
display: inline-block;
|
||||||
|
width: 90px;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(0, 229, 255, 0.7), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-title-deco i {
|
||||||
|
display: inline-block;
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: #00e5ff;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
box-shadow: 0 0 8px #00e5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border: 1px solid rgba(0, 229, 255, 0.45);
|
||||||
|
color: #95ffff;
|
||||||
|
background: rgba(0, 229, 255, 0.06);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-status {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #95ffff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.led-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #18f1a4;
|
||||||
|
box-shadow: 0 0 8px #18f1a4;
|
||||||
|
animation: led-pulse 1.4s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes led-pulse {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
opacity: 0.35;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-day {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #c8f2ff;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash-time {
|
||||||
|
font-family: "myfont", "Microsoft Yahei";
|
||||||
|
font-size: 22px;
|
||||||
|
color: #fff;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
text-shadow: 0 0 12px rgba(0, 229, 255, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= Main ============= */
|
||||||
|
.dash-main {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 1 1 0 !important;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 10px !important;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= KPI Strip ============= */
|
||||||
|
.kpi-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
flex: 0 0 92px;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-card {
|
||||||
|
position: relative;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: linear-gradient(135deg, rgba(0, 60, 80, 0.55) 0%, rgba(3, 22, 26, 0.7) 100%);
|
||||||
|
border: 1px solid rgba(0, 229, 255, 0.22);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-card::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: radial-gradient(circle at 100% 0%, rgba(0, 229, 255, 0.16), transparent 60%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-card::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 3px;
|
||||||
|
height: 100%;
|
||||||
|
background: #00e5ff;
|
||||||
|
box-shadow: 0 0 10px #00e5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-meta {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-label {
|
||||||
|
font-size: 15px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: #d8f6ff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-sub {
|
||||||
|
font-size: 10px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: rgba(149, 255, 255, 0.45);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-value {
|
||||||
|
font-family: "myfont", "Microsoft Yahei";
|
||||||
|
font-size: 34px;
|
||||||
|
font-weight: bold;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
z-index: 1;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-bar {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 2px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c1 .kpi-value {
|
||||||
|
color: #95ffff;
|
||||||
|
text-shadow: 0 0 14px rgba(0, 229, 255, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c1::after {
|
||||||
|
background: #00e5ff;
|
||||||
|
box-shadow: 0 0 10px #00e5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c1 .kpi-bar {
|
||||||
|
background: linear-gradient(90deg, #00e5ff, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c2 .kpi-value {
|
||||||
|
color: #c5ff7a;
|
||||||
|
text-shadow: 0 0 14px rgba(170, 255, 102, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c2::after {
|
||||||
|
background: #aaff66;
|
||||||
|
box-shadow: 0 0 10px #aaff66;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c2 .kpi-bar {
|
||||||
|
background: linear-gradient(90deg, #aaff66, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c3 .kpi-value {
|
||||||
|
color: #ffd87a;
|
||||||
|
text-shadow: 0 0 14px rgba(255, 200, 80, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c3::after {
|
||||||
|
background: #ffb74d;
|
||||||
|
box-shadow: 0 0 10px #ffb74d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c3 .kpi-bar {
|
||||||
|
background: linear-gradient(90deg, #ffb74d, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c4 .kpi-value {
|
||||||
|
color: #7af0a8;
|
||||||
|
text-shadow: 0 0 14px rgba(45, 210, 140, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c4::after {
|
||||||
|
background: #2dd28c;
|
||||||
|
box-shadow: 0 0 10px #2dd28c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c4 .kpi-bar {
|
||||||
|
background: linear-gradient(90deg, #2dd28c, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c5 .kpi-value {
|
||||||
|
color: #ff8a8a;
|
||||||
|
text-shadow: 0 0 14px rgba(255, 107, 107, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c5::after {
|
||||||
|
background: #ff6b6b;
|
||||||
|
box-shadow: 0 0 10px #ff6b6b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kpi-c5 .kpi-bar {
|
||||||
|
background: linear-gradient(90deg, #ff6b6b, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= Content Rows ============= */
|
||||||
|
.row-top,
|
||||||
|
.row-bottom {
|
||||||
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-top {
|
||||||
|
flex: 1.15 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-bottom {
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-full {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= Panel ============= */
|
||||||
|
.panel {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(180deg, rgba(10, 63, 68, 0.45) 0%, rgba(3, 22, 26, 0.65) 100%);
|
||||||
|
border: 1px solid rgba(0, 229, 255, 0.18);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-head {
|
||||||
|
position: relative;
|
||||||
|
height: 36px;
|
||||||
|
flex: 0 0 36px;
|
||||||
|
padding: 0 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
background: linear-gradient(90deg, rgba(0, 229, 255, 0.16) 0%, rgba(0, 229, 255, 0.02) 60%, rgba(0, 229, 255, 0.08) 100%);
|
||||||
|
border-bottom: 1px solid rgba(0, 229, 255, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-head::before {
|
||||||
|
content: "";
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
background: linear-gradient(180deg, #00e5ff, #007a99);
|
||||||
|
box-shadow: 0 0 6px rgba(0, 229, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-sub {
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
color: rgba(149, 255, 255, 0.5);
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-states {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-chip {
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
background: rgba(255, 255, 255, 0.04);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
color: #d8f6ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-chip i {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-chip em {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-run i {
|
||||||
|
background: #00a3f5;
|
||||||
|
box-shadow: 0 0 6px #00a3f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-idle i {
|
||||||
|
background: #45b076;
|
||||||
|
box-shadow: 0 0 6px #45b076;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-err i {
|
||||||
|
background: #de3c36;
|
||||||
|
box-shadow: 0 0 6px #de3c36;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-body {
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 8px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-body {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============= Corner brackets ============= */
|
||||||
|
.corner {
|
||||||
|
position: absolute;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-color: #00e5ff;
|
||||||
|
border-style: solid;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.corner.tl {
|
||||||
|
top: -1px;
|
||||||
|
left: -1px;
|
||||||
|
border-width: 2px 0 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.corner.tr {
|
||||||
|
top: -1px;
|
||||||
|
right: -1px;
|
||||||
|
border-width: 2px 2px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.corner.bl {
|
||||||
|
bottom: -1px;
|
||||||
|
left: -1px;
|
||||||
|
border-width: 0 0 2px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.corner.br {
|
||||||
|
bottom: -1px;
|
||||||
|
right: -1px;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue