add 导航 & update chart样式

This commit is contained in:
DESKTOP-FUDKNA8\znjsz 2024-03-18 17:13:41 +08:00
parent 85cc0c4c43
commit bb7f77e3ac
10 changed files with 745 additions and 55 deletions

View File

@ -134,6 +134,12 @@ function handleResolutionChange(width, height) {
</div> </div>
<!-- <button @click="handleIgnore" class="alert-btn">忽略</button> --> <!-- <button @click="handleIgnore" class="alert-btn">忽略</button> -->
</Container> </Container>
<ul class="main-screen-navigator alert-screen-navigator">
<li><a href="/main-screen">主屏页面</a></li>
<li class="active">报警列表</li>
<li><a href="/1-1">分屏页面</a></li>
</ul>
</div> </div>
</div> </div>
</template> </template>

View File

@ -75,10 +75,68 @@ function handleResolutionChange(width, height) {
<TodayRate class=" " /> <TodayRate class=" " />
<SumRate class=" " /> <SumRate class=" " />
</div> </div>
<ul class="main-screen-navigator alert-screen-navigator">
<li class="active">主屏页面</li>
<li><a href="/alert-list">报警列表</a></li>
<li><a href="/1-1">分屏页面</a></li>
</ul>
</div> </div>
</template> </template>
<style> <style>
ul,
li {
margin: 0;
padding: 0;
list-style: none;
}
.alert-screen-navigator a,
.main-screen-navigator a {
color: #fff;
text-decoration: none;
}
.alert-screen-navigator,
.main-screen-navigator {
position: absolute;
z-index: 1000;
bottom: 32px;
left: 0;
right: 0;
margin: 0 auto;
width: 460px;
display: flex;
justify-content: space-around;
align-items: center;
background: rgba(46, 175, 214, 0.1);
color: #fff;
font-size: 16px;
letter-spacing: 1px;
user-select: none;
padding: 12px;
border-radius: 32px;
}
.alert-screen-navigator > li,
.main-screen-navigator > li {
cursor: pointer;
transition: all 0.2s ease-out;
border-radius: 20px;
padding: 12px 24px;
font-size: 20px;
}
.alert-screen-navigator > li:hover,
.main-screen-navigator > li:hover {
background: rgba(5, 106, 246, 0.168);
}
.alert-screen-navigator > li.active,
.main-screen-navigator > li.active {
background: rgba(5, 106, 246, 0.668);
}
.dark-table { .dark-table {
height: 100%; height: 100%;
background: transparent; background: transparent;

View File

@ -0,0 +1,147 @@
<script setup>
import { computed, onMounted, ref, watch } from "vue";
import * as echarts from "echarts";
import option from "./rateOption";
const props = defineProps({
isOnlyChild: {
type: Boolean,
default: false,
},
rawData: {
type: Object,
default: () => {
return {
targetProduction: 0,
nowProduction: 0,
targetYield: 0,
nowYield: 0,
};
},
},
});
watch(
() => props.isOnlyChild,
(newVal) => {
reInitChart();
}
);
const rate = computed(() => {
const _rate = ((props.rawData.nowYield / props.rawData.targetYield) * 100)
.toFixed(2)
.toString();
return [parseInt(_rate), _rate.split(".")[1]];
});
const chart = ref(null);
const rateChartRef = ref(null);
function reInitChart() {
if (chart.value) chart.value.dispose();
const _chart = echarts.init(rateChartRef.value);
_chart.setOption(option);
chart.value = _chart;
}
onMounted(() => {
reInitChart();
});
</script>
<template>
<div class="chart rate-chart">
<div ref="rateChartRef" class="chart-container"></div>
<div :class="['fake-chart-title', isOnlyChild ? 'is-only-child' : '']">
<span class="integer-part">{{ rate[0] }}.</span>
<span class="decimal-part">{{ rate[1] }}%</span>
</div>
<div class="text-intro">
<div class="text-intro__item">
<span class="legend-box green"></span>
<span>当前成品率: 32.73%</span>
</div>
<div class="text-intro__item">
<span class="legend-box blue"></span>
<span>目标成品率: 90.72%</span>
</div>
</div>
</div>
</template>
<style scoped>
.rate-chart {
height: 240px;
flex-grow: 1;
position: relative;
}
.chart-container {
margin: auto;
width: 320px;
height: 100%;
background: "#0f01";
position: relative;
}
.fake-chart-title {
user-select: none;
position: absolute;
top: 30%;
left: 32%;
}
.fake-chart-title.is-only-child {
left: 42%;
}
.fake-chart-title > .integer-part {
font-size: 48px;
color: #fff;
}
.fake-chart-title > .decimal-part {
font-size: 32px;
color: #fff;
}
.text-intro {
position: absolute;
height: auto;
width: 240px;
bottom: 18px;
left: 0;
right: 0;
margin: 0 auto;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
align-items: center;
user-select: none;
}
.text-intro__item {
font-size: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.legend-box {
width: 16px;
height: 16px;
border-radius: 4px;
}
.green {
background: #4cf0e8;
}
.blue {
background: #1065ff;
}
</style>

View File

@ -0,0 +1,93 @@
<script setup>
import { onMounted, ref } from "vue";
import * as echarts from "echarts";
import getOptions from "./yieldOption";
const props = defineProps({
rawData: {
type: Object,
default: () => {
return {
targetProduction: 0,
nowProduction: 0,
targetYield: 0,
nowYield: 0,
};
},
},
});
const chart = ref(null);
const yieldChartRef = ref(null);
function reInitChart() {
if (chart.value) chart.value.dispose();
const _chart = echarts.init(yieldChartRef.value);
_chart.setOption(getOptions(props.rawData));
chart.value = _chart;
}
onMounted(() => {
reInitChart();
});
</script>
<template>
<div class="chart yield-chart">
<div ref="yieldChartRef" class="chart-container"></div>
<div class="text-intro">
<div class="text-intro__item">
<span class="legend-box green"></span>
<span>当前产量: {{ rawData.nowProduction }}</span>
</div>
<div class="text-intro__item">
<span>目标产量: {{ rawData.targetProduction }}</span>
</div>
</div>
</div>
</template>
<style scoped>
.yield-chart {
height: 240px;
flex-grow: 1;
position: relative;
}
.chart-container {
margin: auto;
width: 320px;
height: 100%;
background: "#0f01";
}
.text-intro {
position: absolute;
height: auto;
width: 220px;
bottom: 18px;
left: 0;
right: 0;
margin: 0 auto;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
align-items: center;
user-select: none;
}
.text-intro__item {
font-size: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.legend-box {
width: 16px;
height: 16px;
border-radius: 4px;
background: #4cf0e8;
}
</style>

View File

@ -0,0 +1,146 @@
const radius = ["58%", "72%"];
const radius2 = ["45%", "58%"];
const grid = {
top: 0,
left: 24,
right: 24,
bottom: 32,
};
const title = {
// 由外部负责展示,此处占位
text: " ",
left: "50%",
top: "30%",
textAlign: "center",
textStyle: {
fontWeight: 400,
fontSize: 48,
color: "#fffd",
},
subtext: "当前成品率\u2002",
subtextStyle: {
fontSize: 20,
fontWeight: 100,
color: "#fffd",
align: "right",
},
};
const tooltip = {
// trigger: "item",
show: false,
};
const legend = {
top: "5%",
left: "center",
};
const bgSerie = {
type: "pie",
radius: radius,
center: ["50%", "40%"],
emptyCircleStyle: {
color: "#042c5f33",
},
};
const dataSerie = {
type: "pie",
radius: radius,
center: ["50%", "40%"],
avoidLabelOvervlap: false,
label: {
show: false,
// position: "center",
},
labelLine: {
show: false,
},
data: [
{
value: 90,
name: "当前成品率",
selected: false,
itemStyle: {
borderJoin: "round",
borderCap: "round",
borderWidth: 12,
borderRadius: "50%",
color: {
type: "linear",
x: 1,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "#4CF0E811" },
{ offset: 1, color: "#4CF0E8" },
],
},
},
},
{
value: 20,
name: "-",
itemStyle: { color: "transparent" },
label: { show: false },
},
],
};
const targetSerie = {
type: "pie",
radius: radius2,
center: ["50%", "40%"],
avoidLabelOvervlap: false,
label: {
show: false,
},
labelLine: {
show: false,
},
data: [
{
value: 90,
name: "目标成品率",
selected: false,
itemStyle: {
borderJoin: "round",
borderCap: "round",
borderWidth: 12,
borderRadius: "50%",
color: {
type: "linear",
x: 1,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "#1065ff66" },
{ offset: 1, color: "#1065ff" },
],
},
},
},
{
value: 20,
name: "-",
itemStyle: { color: "transparent" },
label: { show: false },
},
],
};
export default (data) => {
dataSerie.data[0].value = data.nowYield;
dataSerie.data[1].value = data.targetYield - data.nowYield;
return {
tooltip,
title,
grid,
series: [
// background
bgSerie,
// actual data
dataSerie,
// target data
targetSerie,
],
};
};

View File

@ -0,0 +1,102 @@
const radius = ["55%", "70%"];
const grid = {
top: 0,
left: 24,
right: 24,
bottom: 32,
};
const title = {
text: "75%",
left: "50%",
top: "30%",
textAlign: "center",
textStyle: {
fontWeight: 400,
fontSize: 48,
color: "#fffd",
},
subtext: "当前产量\u2002",
subtextStyle: {
fontSize: 20,
fontWeight: 100,
color: "#fffd",
align: "right",
},
};
const tooltip = {
// trigger: "item",
show: false,
};
const legend = {
top: "5%",
left: "center",
};
const bgSerie = {
type: "pie",
radius: radius,
center: ["50%", "40%"],
emptyCircleStyle: {
color: "#042c5f33",
},
};
const dataSerie = {
type: "pie",
radius: radius,
center: ["50%", "40%"],
avoidLabelOvervlap: false,
label: {
show: false,
// position: "center",
},
labelLine: {
show: false,
},
data: [
{
value: 90,
name: "当前产量",
selected: false,
itemStyle: {
borderJoin: "round",
borderCap: "round",
borderWidth: 12,
borderRadius: "50%",
color: {
type: "linear",
x: 1,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: "#4CF0E811" },
{ offset: 1, color: "#4CF0E8" },
],
},
},
},
{
value: 20,
name: "-",
itemStyle: { color: "transparent" },
label: { show: false },
},
],
};
export default (data) => {
title.text =
(100 * (+data.nowProduction / +data.targetProduction)).toFixed(0) + "%";
dataSerie.data[0].value = data.nowProduction;
dataSerie.data[1].value = data.targetProduction - data.nowProduction;
return {
tooltip,
title,
grid,
series: [
// background
bgSerie,
// actual data
dataSerie,
],
};
};

View File

@ -0,0 +1,102 @@
<script setup>
import { ref, onMounted, nextTick } from "vue";
import * as echarts from "echarts";
import Container from "../Base/Container.vue";
import { useWsStore } from "../../store";
import setupFn from "./LineTodayOptions";
const show = ref(false);
const chartContainer = ref(null);
const chartInstance = ref(null);
const store = useWsStore();
onMounted(() => {
chartContainer.value.classList.add("h-full");
const d = loadData(store.data2.dailyTarget);
// const d = loadData([
// {
// targetProduction: 100,
// nowProduction: 66,
// targetYield: 13,
// nowYield: 3,
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
} else {
if (!chartInstance.value)
chartInstance.value = echarts.init(chartContainer.value);
setupFn(chartInstance.value, d);
show.value = true;
}
});
//
store.$subscribe((mutation, state) => {
const d = loadData(state.data2.dailyTarget);
// const d = loadData([
// {
// targetProduction: 100,
// nowProduction: 66,
// targetYield: 13,
// nowYield: 3,
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
} else {
if (!chartInstance.value)
chartInstance.value = echarts.init(chartContainer.value);
setupFn(chartInstance.value, d);
show.value = true;
}
});
// utils
function loadData(dailyTarget) {
if (
dailyTarget == undefined ||
// dailyTarget?.length == 0 ||
!dailyTarget[0]
) {
return null;
}
return {
targetProduction: dailyTarget[0].targetProduction,
nowProduction: dailyTarget[0].nowProduction,
targetYield: dailyTarget[0].targetYield,
nowYield: dailyTarget[0].nowYield,
};
}
</script>
<template>
<Container class="chart" title="本日生产线情况" icon="cube">
<div
ref="chartContainer"
class="chart-chart"
:style="{ opacity: show ? 1 : 0 }"
></div>
<p v-show="!show" class="empty-data-hint">暂无数据</p>
</Container>
</template>
<style scoped>
.chart {
/* height: 300px; */
height: auto;
}
.chart-chart {
height: 100%;
}
</style>

View File

@ -1,79 +1,83 @@
<script setup> <script setup>
import { ref, onMounted, nextTick } from "vue"; import { ref, onMounted, nextTick } from "vue";
import * as echarts from "echarts";
import Container from "../Base/Container.vue"; import Container from "../Base/Container.vue";
import { useWsStore } from "../../store"; import { useWsStore } from "../../store";
import setupFn from "./LineTodayOptions"; import YieldChart from "../Chart/YieldChart.vue";
import RateChart from "../Chart/RateChart.vue";
const show = ref(false); const displayProductionChart = ref(false);
const chartContainer = ref(null); const displayRateChart = ref(false);
const chartInstance = ref(null); const websocketData = ref(null);
const store = useWsStore(); const store = useWsStore();
onMounted(() => { onMounted(() => {
chartContainer.value.classList.add("h-full"); websocketData.value = loadData([
const d = loadData(store.data2.dailyTarget); {
// const d = loadData([ targetProduction: 120,
// { nowProduction: 10,
// targetProduction: 100, targetYield: 13,
// nowProduction: 66, nowYield: 3,
// targetYield: 13, },
// nowYield: 3, ]);
// }, // const d = loadData(state.data2.dailyTarget);
// ]); console.log("websocketData==>", websocketData);
if (!d) { if (!websocketData.value) {
show.value = false; displayProductionChart.value = false;
if (chartInstance.value) { displayRateChart.value = false;
chartInstance.value.dispose();
chartInstance.value = null;
}
} else { } else {
if (!chartInstance.value) /** 阻止 targetProduction == 0 */
chartInstance.value = echarts.init(chartContainer.value); if (!websocketData.value.targetProduction) {
setupFn(chartInstance.value, d); displayProductionChart.value = false;
show.value = true; } else {
displayProductionChart.value = true;
}
/** 阻止 targetYield == 0 */
if (!websocketData.value.targetYield) {
displayRateChart.value = false;
} else {
displayRateChart.value = true;
}
} }
}); });
// //
store.$subscribe((mutation, state) => { // store.$subscribe((mutation, state) => {
const d = loadData(state.data2.dailyTarget); // // const d = loadData([
// const d = loadData([ // // {
// { // // targetProduction: 100,
// targetProduction: 100, // // nowProduction: 66,
// nowProduction: 66, // // targetYield: 13,
// targetYield: 13, // // nowYield: 3,
// nowYield: 3, // // },
// }, // // ]);
// ]); // const d = loadData(state.data2.dailyTarget);
if (!d) { // if (!d) {
show.value = false; // displayProductionChart.value = false;
if (chartInstance.value) { // displayRateChart.value = false;
chartInstance.value.dispose(); // } else {
chartInstance.value = null; // displayRateChart.value = false;
} // if (!d.targetProduction) {
} else { // displayProductionChart.value = false;
if (!chartInstance.value) // } else {
chartInstance.value = echarts.init(chartContainer.value); // displayProductionChart.value = true;
setupFn(chartInstance.value, d); // }
show.value = true; // }
} // });
});
// utils // utils
function loadData(dailyTarget) { function loadData(dailyTarget) {
if ( if (dailyTarget == undefined || !dailyTarget[0]) {
dailyTarget == undefined ||
// dailyTarget?.length == 0 ||
!dailyTarget[0]
) {
return null; return null;
} }
return { return {
//
targetProduction: dailyTarget[0].targetProduction, targetProduction: dailyTarget[0].targetProduction,
//
nowProduction: dailyTarget[0].nowProduction, nowProduction: dailyTarget[0].nowProduction,
//
targetYield: dailyTarget[0].targetYield, targetYield: dailyTarget[0].targetYield,
//
nowYield: dailyTarget[0].nowYield, nowYield: dailyTarget[0].nowYield,
}; };
} }
@ -81,12 +85,34 @@ function loadData(dailyTarget) {
<template> <template>
<Container class="chart" title="本日生产线情况" icon="cube"> <Container class="chart" title="本日生产线情况" icon="cube">
<div <!-- <div
ref="chartContainer" ref="chartContainer"
class="chart-chart" class="chart-chart"
:style="{ opacity: show ? 1 : 0 }" :style="{ opacity: show ? 1 : 0 }"
></div> ></div>
<p v-show="!show" class="empty-data-hint">暂无数据</p> <p v-show="!show" class="empty-data-hint">暂无数据</p> -->
<div class="container-body__h-full">
<yield-chart v-if="displayProductionChart" :raw-data="websocketData" />
<rate-chart
v-if="displayRateChart"
:raw-data="websocketData"
:isOnlyChild="!displayProductionChart"
/>
<p
v-if="!displayProductionChart && !displayRateChart"
style="
height: 100%;
line-height: 350px;
user-select: none;
flex: 1;
color: #fffc;
font-size: 24px;
text-align: center;
"
>
- 暂无数据 -
</p>
</div>
</Container> </Container>
</template> </template>
@ -99,4 +125,10 @@ function loadData(dailyTarget) {
.chart-chart { .chart-chart {
height: 100%; height: 100%;
} }
.container-body__h-full {
height: 100%;
display: flex;
gap: 12px;
}
</style> </style>

View File

@ -27,6 +27,8 @@ const setupFn = (chart, datalist = [0.0, 0.0, 0.0, 0.0]) => {
axisLabel: { axisLabel: {
fontSize: 14, fontSize: 14,
color: "#fff", color: "#fff",
rotate: 32,
margin: 12
}, },
splitLine: { splitLine: {
show: true, show: true,

View File

@ -27,6 +27,8 @@ const setupFn = (chart, datalist = [0.0, 0.0, 0.0, 0.0]) => {
axisLabel: { axisLabel: {
fontSize: 14, fontSize: 14,
color: "#fff", color: "#fff",
rotate: 32,
margin: 12
}, },
splitLine: { splitLine: {
show: true, show: true,