Compare commits

...

31 Commits

Author SHA1 Message Date
DESKTOP-FUDKNA8\znjsz
d77506ed31 update carosul 2024-03-21 17:05:20 +08:00
DESKTOP-FUDKNA8\znjsz
f03cf59e73 update 环 2024-03-21 15:18:50 +08:00
DESKTOP-FUDKNA8\znjsz
c2e901e4bc Merge branch 'master' of http://git.picaiba.com/g7hoo/chenzhou 2024-03-21 10:48:24 +08:00
DESKTOP-FUDKNA8\znjsz
8cf50b9cb9 1 2024-03-21 10:47:49 +08:00
gtz
04e98ab1db 管理端备份 2024-03-21 10:31:12 +08:00
gtz
347e51e9a4 Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-21 10:30:57 +08:00
DESKTOP-FUDKNA8\znjsz
fe7b34615a 1 2024-03-21 10:30:40 +08:00
gtz
1b0746cc2d Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-20 11:45:43 +08:00
DESKTOP-FUDKNA8\znjsz
c992fa0200 1 2024-03-20 11:22:50 +08:00
gtz
b97532e4e1 Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-20 10:43:12 +08:00
DESKTOP-FUDKNA8\znjsz
82573307e9 1 2024-03-20 10:36:40 +08:00
gtz
20f5cec3e9 Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-20 10:32:32 +08:00
DESKTOP-FUDKNA8\znjsz
67d59c5693 1 2024-03-20 10:30:30 +08:00
gtz
43f7ccac4c Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-20 10:23:40 +08:00
DESKTOP-FUDKNA8\znjsz
55947ceb16 update 2024-03-20 09:18:16 +08:00
DESKTOP-FUDKNA8\znjsz
fccd2ab9cc 1 2024-03-19 16:53:05 +08:00
gtz
e44b2b5f5b Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-19 16:47:46 +08:00
DESKTOP-FUDKNA8\znjsz
43a6f59afe update chart 2024-03-19 16:43:08 +08:00
gtz
aeb43c8d41 Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-03-19 15:58:00 +08:00
gtz
5652cff730 1 2024-03-19 15:57:57 +08:00
Melete
f66b3a8a7a update 2024-03-18 19:58:42 +08:00
DESKTOP-FUDKNA8\znjsz
476b936660 conflict 2024-03-18 17:16:30 +08:00
DESKTOP-FUDKNA8\znjsz
59c652c3cf add 导航 & update chart样式 & update 横坐标倾斜 2024-03-18 17:14:20 +08:00
DESKTOP-FUDKNA8\znjsz
bb7f77e3ac add 导航 & update chart样式 2024-03-18 17:13:41 +08:00
gtz
e306b0f837 1 2024-03-16 10:12:01 +08:00
DESKTOP-FUDKNA8\znjsz
85cc0c4c43 update alert list 3d info 2024-03-15 16:08:48 +08:00
DESKTOP-FUDKNA8\znjsz
cfcdf4eb0a 1 2024-03-15 14:49:00 +08:00
gtz
ae7adebae0 Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-02-28 16:51:57 +08:00
gtz
ae3c430d38 1 2024-02-28 16:51:52 +08:00
gtz
d4001ed86e Merge branch 'master' of git.picaiba.com:g7hoo/chenzhou 2024-02-27 16:00:17 +08:00
gtz
9cdd255947 1 2024-02-27 15:52:28 +08:00
22 changed files with 2555 additions and 487 deletions

View File

@@ -134,6 +134,12 @@ function handleResolutionChange(width, height) {
</div>
<!-- <button @click="handleIgnore" class="alert-btn">忽略</button> -->
</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>
</template>

View File

@@ -13,7 +13,7 @@ import { useSettings } from "./store/settings";
const props = defineProps(["path"]);
const pages = ['3d', 'data', 'realtime', 'alert', 'announcement']
const pages = ["3d", "data", "realtime", "alert", "announcement"];
const currentPage = ref("3d");
const handlePageChange = (page) => {
currentPage.value = page;
@@ -23,67 +23,84 @@ const mainContainer = ref(null);
const store = useSettings();
const timer = ref(null);
function startCarousel(pages, duration) {
if (timer.value) clearInterval(timer.value);
timer.value = setInterval(() => {
handlePageChange(
pages[(pages.indexOf(currentPage.value) + 1) % pages.length]
);
}, duration);
}
store.$subscribe((mutation, state) => {
const pages = state.settings.carouselPages;
// 如果更新了时间
if (mutation.events.key == 'carouselTime' && state.settings.carouselTime > 0 && state.settings.carousel) {
if (timer.value) clearInterval(timer.value);
timer.value = setInterval(() => {
handlePageChange(pages[(pages.indexOf(currentPage.value) + 1) % pages.length])
}, state.settings.carouselTime * 1000);
} else if (mutation.events.key == 'carousel') {
if (
mutation.events.key == "carouselTime" &&
state.settings.carouselTime > 0 &&
state.settings.carousel
) {
startCarousel(pages, state.settings.carouselTime * 1000);
} else if (mutation.events.key == "carousel") {
// 如果更新了状态
if (state.settings.carousel) {
timer.value = setInterval(() => {
handlePageChange(pages[(pages.indexOf(currentPage.value) + 1) % pages.length])
}, state.settings.carouselTime * 1000);
startCarousel(pages, state.settings.carouselTime * 1000);
} else {
clearInterval(timer.value);
timer.value = null;
}
} else if (mutation.events.key == "carouselPages") {
if (state.settings.carousel) {
startCarousel(pages, state.settings.carouselTime * 1000);
} else {
clearInterval(timer.value);
timer.value = null;
}
}
})
});
// 检查状态
onMounted(() => {
const settings = store.settings;
const pages = settings.carouselPages;
if (settings.carousel) {
// 开始轮播
if (timer.value) clearInterval(timer.value);
timer.value = setInterval(() => {
handlePageChange(pages[(pages.indexOf(currentPage.value) + 1) % pages.length])
handlePageChange(
pages[(pages.indexOf(currentPage.value) + 1) % pages.length]
);
}, settings.carouselTime * 1000);
}
// 设置分辨率
handleResolutionChange(settings.resolution.width, settings.resolution.height);
})
});
const pathMap = {
// 钢三线
'/3-1': 1,
'/3-2': 2,
'/3-3': 11, // 3,
'/3-4': 12,
"/3-1": 1,
"/3-2": 2,
"/3-3": 11, // 3,
"/3-4": 12,
// 钢二线
'/2-1': 5,
'/2-2': 6,
'/2-3': 7,
'/2-4': 4,
"/2-1": 5,
"/2-2": 6,
"/2-3": 7,
"/2-4": 4,
// 钢一线
'/1-1': 9,
'/1-2': 10,
'/1-3': 3,
'/1-4': 8
}
"/1-1": 9,
"/1-2": 10,
"/1-3": 3,
"/1-4": 8,
};
function handleResolutionChange(width, height) {
console.log('document.documentElement', document.documentElement)
console.log("document.documentElement", document.documentElement);
if (mainContainer.value) {
// mainContainer.value.style.width = `${width}px`;
// mainContainer.value.style.height = `${height}px`;
// changeScale(mainContainer.value, width, height)
changeScale(mainContainer.value, width, height)
changeScale(mainContainer.value, width, height);
}
}
@@ -102,23 +119,37 @@ function resetScale(elm) {
elm.style.transform = "initial";
elm.style.transformOrigin = "initial";
}
</script>
<template>
<div id="main-container" ref="mainContainer" class="main-container">
<DatetimeTool v-if="currentPage !== 'announcement'" />
<Tools v-if="currentPage !== 'announcement'" @change-resolution="handleResolutionChange" />
<Tools
v-if="currentPage !== 'announcement'"
@change-resolution="handleResolutionChange"
/>
<AppHeader v-if="currentPage !== 'announcement'" />
<AnnoucementPage v-if="currentPage === 'announcement'" class="annoucement-page"
@home="() => handlePageChange('3d')" />
<AnnoucementPage
v-if="currentPage === 'announcement'"
class="annoucement-page"
@home="() => handlePageChange('3d')"
/>
<div v-else class="pages-wrapper">
<NavMenu @change="handlePageChange" :value="currentPage" />
<!-- <TriplePage v-if="currentPage === '3d'" :line="pathMap[path] ?? '1'" /> -->
<ThreeDimension v-if="currentPage === '3d'" :line="pathMap[path] ?? '1'" />
<ThreeDimension
v-if="currentPage === '3d'"
:line="pathMap[path] ?? '1'"
/>
<DataPage v-if="currentPage === 'data'" :line="pathMap[path] ?? '1'" />
<AlertListPage v-if="currentPage === 'alert'" :line="pathMap[path] ?? '1'" />
<RealtimePage v-if="currentPage === 'realtime'" :line="pathMap[path] ?? '1'" />
<AlertListPage
v-if="currentPage === 'alert'"
:line="pathMap[path] ?? '1'"
/>
<RealtimePage
v-if="currentPage === 'realtime'"
:line="pathMap[path] ?? '1'"
/>
</div>
</div>
</template>

View File

@@ -75,10 +75,68 @@ function handleResolutionChange(width, height) {
<TodayRate class=" " />
<SumRate class=" " />
</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>
</template>
<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 {
height: 100%;
background: transparent;

View File

@@ -0,0 +1,159 @@
<script setup>
import { computed, nextTick, onMounted, ref, watch } from "vue";
import * as echarts from "echarts";
import getOptions from "./rateOption";
const props = defineProps({
isOnlyChild: {
type: Boolean,
default: false,
},
rawData: {
type: Object,
default: () => {
return {
targetProduction: 0,
nowProduction: 0,
targetYield: 0,
nowYield: 0,
};
},
},
displayPlaceholder: {
type: Boolean,
default: false,
},
});
watch(
() => props.isOnlyChild,
(newVal) => {
reInitChart();
}
);
const rate = computed(() => {
if (!props.rawData?.nowYield || props.rawData.nowYield == 0) return [0, 0];
// const _rate = ((props.rawData.nowYield / props.rawData.targetYield) * 100)
// .toFixed(2)
// .toString();
// return [parseInt(_rate), _rate.split(".")[1]];
return [
parseInt(props.rawData.nowYield),
((props.rawData.nowYield + "").split(".")[1] ?? "").padStart(2, "0"),
];
});
const chart = ref(null);
const rateChartRef = ref(null);
function reInitChart() {
if (chart.value) chart.value.dispose();
const _chart = echarts.init(rateChartRef.value);
_chart.setOption(getOptions(props.rawData));
chart.value = _chart;
}
onMounted(() => {
nextTick(() => {
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>当前成品率: {{ props.rawData?.nowYield ?? 0 }}%</span>
</div>
<div class="text-intro__item">
<span class="legend-box blue"></span>
<span>目标成品率: {{ props.rawData?.targetYield ?? 0 }}%</span>
</div>
</div>
</div>
</template>
<style scoped>
.rate-chart {
height: 240px;
flex-grow: 1;
position: relative;
}
.chart-placeholder,
.chart-container {
margin: auto;
width: 320px;
height: 100%;
background: "#0f01";
position: relative;
}
.fake-chart-title {
user-select: none;
position: absolute;
top: 30%;
left: 36%;
}
.fake-chart-title.is-only-child {
left: 36%;
}
.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,110 @@
<script setup>
import { nextTick, onMounted, ref, watch } 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,
};
},
},
displayPlaceholder: {
type: Boolean,
default: false,
},
});
const chart = ref(null);
const yieldChartRef = ref(null);
function reInitChart() {
// if (props.displayPlaceholder) return;
if (chart.value) chart.value.dispose();
const _chart = echarts.init(yieldChartRef.value);
_chart.setOption(
getOptions(
props.rawData ?? {
nowProduction: 0,
targetProduction: 0,
}
)
);
chart.value = _chart;
}
onMounted(() => {
nextTick(() => {
reInitChart();
});
});
</script>
<template>
<div class="chart yield-chart">
<!-- <div v-if="displayPlaceholder" class="chart-placeholder"></div>
<div v-else ref="yieldChartRef" class="chart-container"></div> -->
<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 ?? 0 }}</span>
</div>
<div v-if="!displayPlaceholder" class="text-intro__item">
<span>目标产量: {{ rawData?.targetProduction ?? 0 }}</span>
</div>
</div>
</div>
</template>
<style scoped>
.yield-chart {
height: 240px;
flex-grow: 1;
position: relative;
}
.chart-placeholder,
.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,149 @@
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) => {
title.subtext = "当前成品率\u2002";
dataSerie.data[0].value = data?.nowYield ?? 0;
dataSerie.data[1].value = 100 - (data?.nowYield ?? 0);
targetSerie.data[0].value = data?.targetYield ?? 0;
targetSerie.data[1].value = 100 - (data?.targetYield ?? 0);
return {
tooltip,
title,
grid,
series: [
// background
bgSerie,
// actual data
dataSerie,
// target data
targetSerie,
],
};
};

View File

@@ -0,0 +1,157 @@
const radius = ["58%", "72%"];
const radius2 = ["45%", "58%"];
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 },
},
],
};
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) => {
// title.text =
// (100 * (+data.nowProduction / +data.targetProduction)).toFixed(0) + "%";
// 外圈
title.text = data.nowProduction || 0;
dataSerie.data[0].value = data.nowProduction;
dataSerie.data[1].value = !data.targetProduction
? data.nowProduction == 0
? 1
: 0
: data.targetProduction - data.nowProduction;
// 内圈
targetSerie.data[0].value = data?.targetProduction ?? 0;
targetSerie.data[1].value = data?.targetProduction ? 0 : 1;
return {
tooltip,
title,
grid,
series: [
// background
bgSerie,
dataSerie,
targetSerie,
],
};
};

View File

@@ -25,15 +25,9 @@ store.$subscribe((mutation, state) => {
if (chart.value) chart.value.dispose();
return;
}
hourData.value = (state.data2?.lineHourList ?? [
// { lineName: '001', hour: '00:00', num: 10 },
// { lineName: '002', hour: '00:20', num: 20 },
// { lineName: '003', hour: '00:30', num: 30 },
// { lineName: '004', hour: '00:40', num: 14 },
// { lineName: '005', hour: '00:50', num: 50 },
]).map((item, index) => ({
hourData.value = (state.data2?.lineHourList ?? []).map((item, index) => ({
id: `${item.lineName}_${index}`,
hour: item.hour || '__',
hour: item.hour || "__",
data: item.num || 0,
}));
setupChart();
@@ -46,7 +40,7 @@ function setupChart() {
chartSetup(
chart.value,
hourData.value.map((item) => item.hour),
hourData.value.map((item) => item.num)
hourData.value.map((item) => item.data)
);
});

View File

@@ -12,45 +12,45 @@ const show = ref(false);
onMounted(() => {
chartContainer.value.classList.add("h-full");
// const d = loadData(store.data2.lineSevenDayLogList);
const d = loadData([
{
data: [
{ day: "10-10", num: Math.floor(Math.random() * 500) },
{ day: "10-11", num: Math.floor(Math.random() * 500) },
{ day: "10-12", num: Math.floor(Math.random() * 500) },
{ day: "10-13", num: Math.floor(Math.random() * 500) },
{ day: "10-14", num: Math.floor(Math.random() * 500) },
{ day: "10-15", num: Math.floor(Math.random() * 500) },
{ day: "10-16", num: Math.floor(Math.random() * 500) },
],
name: "钢一线",
},
{
data: [
{ day: "10-10", num: Math.floor(Math.random() * 500) },
{ day: "10-11", num: Math.floor(Math.random() * 500) },
{ day: "10-12", num: Math.floor(Math.random() * 500) },
{ day: "10-13", num: Math.floor(Math.random() * 500) },
{ day: "10-14", num: Math.floor(Math.random() * 500) },
{ day: "10-15", num: Math.floor(Math.random() * 500) },
{ day: "10-16", num: Math.floor(Math.random() * 500) },
],
name: "钢二线",
},
{
data: [
{ day: "10-10", num: Math.floor(Math.random() * 500) },
{ day: "10-11", num: Math.floor(Math.random() * 500) },
{ day: "10-12", num: Math.floor(Math.random() * 500) },
{ day: "10-13", num: Math.floor(Math.random() * 500) },
{ day: "10-14", num: Math.floor(Math.random() * 500) },
{ day: "10-15", num: Math.floor(Math.random() * 500) },
{ day: "10-16", num: Math.floor(Math.random() * 500) },
],
name: "钢三线",
},
]);
const d = loadData(store.data2.lineSevenDayLogList);
// const d = loadData([
// {
// data: [
// { day: "10-10", num: Math.floor(Math.random() * 500) },
// { day: "10-11", num: Math.floor(Math.random() * 500) },
// { day: "10-12", num: Math.floor(Math.random() * 500) },
// { day: "10-13", num: Math.floor(Math.random() * 500) },
// { day: "10-14", num: Math.floor(Math.random() * 500) },
// { day: "10-15", num: Math.floor(Math.random() * 500) },
// { day: "10-16", num: Math.floor(Math.random() * 500) },
// ],
// name: "钢一线",
// },
// {
// data: [
// { day: "10-10", num: Math.floor(Math.random() * 500) },
// { day: "10-11", num: Math.floor(Math.random() * 500) },
// { day: "10-12", num: Math.floor(Math.random() * 500) },
// { day: "10-13", num: Math.floor(Math.random() * 500) },
// { day: "10-14", num: Math.floor(Math.random() * 500) },
// { day: "10-15", num: Math.floor(Math.random() * 500) },
// { day: "10-16", num: Math.floor(Math.random() * 500) },
// ],
// name: "钢二线",
// },
// {
// data: [
// { day: "10-10", num: Math.floor(Math.random() * 500) },
// { day: "10-11", num: Math.floor(Math.random() * 500) },
// { day: "10-12", num: Math.floor(Math.random() * 500) },
// { day: "10-13", num: Math.floor(Math.random() * 500) },
// { day: "10-14", num: Math.floor(Math.random() * 500) },
// { day: "10-15", num: Math.floor(Math.random() * 500) },
// { day: "10-16", num: Math.floor(Math.random() * 500) },
// ],
// name: "钢三线",
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
@@ -67,45 +67,45 @@ onMounted(() => {
// 订阅
store.$subscribe((mutation, state) => {
// const d = loadData(state.data2.lineSevenDayLogList);
const d = loadData([
{
data: [
{ day: "10-10", num: Math.floor(Math.random() * 500) },
{ day: "10-11", num: Math.floor(Math.random() * 500) },
{ day: "10-12", num: Math.floor(Math.random() * 500) },
{ day: "10-13", num: Math.floor(Math.random() * 500) },
{ day: "10-14", num: Math.floor(Math.random() * 500) },
{ day: "10-15", num: Math.floor(Math.random() * 500) },
{ day: "10-16", num: Math.floor(Math.random() * 500) },
],
name: "钢一线",
},
{
data: [
{ day: "10-10", num: Math.floor(Math.random() * 500) },
{ day: "10-11", num: Math.floor(Math.random() * 500) },
{ day: "10-12", num: Math.floor(Math.random() * 500) },
{ day: "10-13", num: Math.floor(Math.random() * 500) },
{ day: "10-14", num: Math.floor(Math.random() * 500) },
{ day: "10-15", num: Math.floor(Math.random() * 500) },
{ day: "10-16", num: Math.floor(Math.random() * 500) },
],
name: "钢二线",
},
{
data: [
{ day: "10-10", num: Math.floor(Math.random() * 500) },
{ day: "10-11", num: Math.floor(Math.random() * 500) },
{ day: "10-12", num: Math.floor(Math.random() * 500) },
{ day: "10-13", num: Math.floor(Math.random() * 500) },
{ day: "10-14", num: Math.floor(Math.random() * 500) },
{ day: "10-15", num: Math.floor(Math.random() * 500) },
{ day: "10-16", num: Math.floor(Math.random() * 500) },
],
name: "钢三线",
},
]);
const d = loadData(state.data2.lineSevenDayLogList);
// const d = loadData([
// {
// data: [
// { day: "10-10", num: Math.floor(Math.random() * 500) },
// { day: "10-11", num: Math.floor(Math.random() * 500) },
// { day: "10-12", num: Math.floor(Math.random() * 500) },
// { day: "10-13", num: Math.floor(Math.random() * 500) },
// { day: "10-14", num: Math.floor(Math.random() * 500) },
// { day: "10-15", num: Math.floor(Math.random() * 500) },
// { day: "10-16", num: Math.floor(Math.random() * 500) },
// ],
// name: "钢一线",
// },
// {
// data: [
// { day: "10-10", num: Math.floor(Math.random() * 500) },
// { day: "10-11", num: Math.floor(Math.random() * 500) },
// { day: "10-12", num: Math.floor(Math.random() * 500) },
// { day: "10-13", num: Math.floor(Math.random() * 500) },
// { day: "10-14", num: Math.floor(Math.random() * 500) },
// { day: "10-15", num: Math.floor(Math.random() * 500) },
// { day: "10-16", num: Math.floor(Math.random() * 500) },
// ],
// name: "钢二线",
// },
// {
// data: [
// { day: "10-10", num: Math.floor(Math.random() * 500) },
// { day: "10-11", num: Math.floor(Math.random() * 500) },
// { day: "10-12", num: Math.floor(Math.random() * 500) },
// { day: "10-13", num: Math.floor(Math.random() * 500) },
// { day: "10-14", num: Math.floor(Math.random() * 500) },
// { day: "10-15", num: Math.floor(Math.random() * 500) },
// { day: "10-16", num: Math.floor(Math.random() * 500) },
// ],
// name: "钢三线",
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {

View File

@@ -1,208 +1,363 @@
<script setup>
import { ref } from 'vue';
import { useSettings } from '../store/settings'
import { ref } from "vue";
import { useSettings } from "../store/settings";
const emit = defineEmits(["close", "change-resolution"]);
const store = useSettings();
const settings = ref(store.settings);
store.$subscribe((mutation, state) => {
settings.value.fullscreen = state.settings.fullscreen;
})
settings.value.fullscreen = state.settings.fullscreen;
});
function handleCancel() {
emit('close')
emit("close");
}
function handleConfirm() {
// alert(JSON.stringify(settings, null, 2))
// changeScale(settings.resolution.width, settings.resolution.height)
if (settings.value.resolution.width < 480) store.settings.resolution.width = 480;
if (settings.value.resolution.width > 7680) store.settings.resolution.width = 7680;
if (settings.value.resolution.height < 270) store.settings.resolution.height = 270;
if (settings.value.resolution.height > 4320) store.settings.resolution.height = 4320;
if (settings.value.resolution.width < 480)
store.settings.resolution.width = 480;
if (settings.value.resolution.width > 7680)
store.settings.resolution.width = 7680;
if (settings.value.resolution.height < 270)
store.settings.resolution.height = 270;
if (settings.value.resolution.height > 4320)
store.settings.resolution.height = 4320;
emit('change-resolution', store.settings.resolution.width, store.settings.resolution.height)
emit(
"change-resolution",
store.settings.resolution.width,
store.settings.resolution.height
);
}
</script>
<template>
<div class="setting-dialog">
<h1>设置</h1>
<div class="main-content">
<div class="form-item">
<label for="carousel">轮播时间</label>
<input id="carousel" type="number" v-model="settings.carouselTime" />
<span></span>
</div>
<div class="form-item">
<label for="resolution1">分辨率</label>
<input id="resolution1" type="number" min="480" max="7680" v-model="settings.resolution.width" />
<span>X</span>
<input id="resolution2" type="number" min="270" max="4320" v-model="settings.resolution.height" />
<span>px</span>
</div>
<div class="form-item selector">
<div class="opt opt1">
<div class="setting-dialog">
<h1>设置</h1>
<div class="main-content">
<div class="form-item">
<label for="carousel">轮播时间</label>
<input id="carousel" type="number" v-model="settings.carouselTime" />
<span></span>
</div>
<div
class="form-item"
style="display: flex; flex-direction: column; gap: 12px"
>
<label for="carouselPages">轮播项目</label>
<div class="carousel-page__list">
<div>
<input
type="checkbox"
id="cp-3d"
name="carouselPages"
:class="[
settings.carouselPages.includes('3d') ? 'checked' : '',
'carousel-page',
]"
@change="
() => {
store.updateSettings({ type: 'carousel-page', value: '3d' });
}
"
/>
<label for="cp-3d">三维界面</label>
</div>
<div>
<input
type="checkbox"
id="cp-data"
name="carouselPages"
:class="[
settings.carouselPages.includes('data') ? 'checked' : '',
'carousel-page',
]"
@change="
() => {
store.updateSettings({
type: 'carousel-page',
value: 'data',
});
}
"
/>
<label for="cp-data">数据界面</label>
</div>
<div>
<input
type="checkbox"
id="cp-realtime"
name="carouselPages"
:class="[
settings.carouselPages.includes('realtime') ? 'checked' : '',
'carousel-page',
]"
@change="
() => {
store.updateSettings({
type: 'carousel-page',
value: 'realtime',
});
}
"
/>
<label for="cp-realtime">实时数据</label>
</div>
<div>
<input
type="checkbox"
id="cp-alert"
name="carouselPages"
:class="[
settings.carouselPages.includes('alert') ? 'checked' : '',
'carousel-page',
]"
@change="
() => {
store.updateSettings({
type: 'carousel-page',
value: 'alert',
});
}
"
/>
<label for="cp-alert">报警列表</label>
</div>
<div>
<input
type="checkbox"
id="cp-announcement"
name="carouselPages"
:class="[
settings.carouselPages.includes('announcement')
? 'checked'
: '',
'carousel-page',
]"
@change="
() => {
store.updateSettings({
type: 'carousel-page',
value: 'announcement',
});
}
"
/>
<label for="cp-announcement">公告页面</label>
</div>
</div>
</div>
<div class="form-item">
<label for="resolution1">分辨率</label>
<input
id="resolution1"
type="number"
min="480"
max="7680"
v-model="settings.resolution.width"
/>
<span>X</span>
<input
id="resolution2"
type="number"
min="270"
max="4320"
v-model="settings.resolution.height"
/>
<span>px</span>
</div>
<div class="form-item selector">
<!-- <div class="opt opt1">
<input type="checkbox" id="fullscreen" name="fullscreen" :class="[settings.fullscreen ? 'checked' : '']"
v-model="settings.fullscreen" />
<label for="fullscreen">全屏显示</label>
</div>
<div class="opt opt2">
<input type="checkbox" id="status" name="status" :class="[settings.eqStatus ? 'checked' : '']"
v-model="settings.eqStatus" />
<label for="status">设备状态</label>
</div>
</div>
</div>
<div class="footer">
<button @click="handleCancel" class="btn btn-cancel">取消</button>
<button @click="handleConfirm" class="btn btn-confirm">确认</button>
</div> -->
<div class="opt opt2">
<input
type="checkbox"
id="status"
name="status"
:class="[settings.eqStatus ? 'checked' : '', 'carousel-page']"
v-model="settings.eqStatus"
/>
<label for="status">设备状态</label>
</div>
</div>
</div>
<div class="modal"></div>
<div class="footer">
<button @click="handleCancel" class="btn btn-cancel">取消</button>
<button @click="handleConfirm" class="btn btn-confirm">确认</button>
</div>
</div>
<div class="modal"></div>
</template>
<style scoped>
* {
user-select: none;
user-select: none;
}
.setting-dialog {
position: absolute;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 577px;
height: 422px;
background: url(../assets/dialog-bg.png) 100% / contain no-repeat;
z-index: 1001;
transition: all .3s ease-out;
display: flex;
flex-direction: column;
gap: 18px;
padding: 24px 80px;
position: absolute;
margin: auto;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 577px;
height: 422px;
background: url(../assets/dialog-bg.png) 100% / contain no-repeat;
z-index: 1001;
transition: all 0.3s ease-out;
display: flex;
flex-direction: column;
gap: 12px;
padding: 24px 80px;
}
.main-content {
flex: 1;
padding-top: 10px;
flex: 1;
padding-top: 10px;
}
.form-item {
margin: 32px 0;
display: flex;
gap: 8px;
color: #fff;
font-size: 28px;
letter-spacing: 2px;
padding: 0 12px;
margin: 20px 0;
display: flex;
gap: 8px;
color: #fff;
font-size: 24px;
letter-spacing: 2px;
padding: 0 12px;
}
.form-item.selector {
gap: 32px;
gap: 32px;
}
.opt {
margin-left: 24px;
display: flex;
align-items: center;
gap: 8px;
display: flex;
align-items: center;
gap: 8px;
}
.opt2 {
font-size: 16px;
}
.form-item input {
flex: 1;
border: none;
appearance: none;
outline: none;
border-radius: 4px;
padding: 4px 12px;
font-size: 18px;
flex: 1;
border: none;
appearance: none;
outline: none;
border-radius: 4px;
padding: 4px 12px;
font-size: 18px;
}
input#resolution1,
input#resolution2 {
width: 10px;
width: 10px;
}
input[type="checkbox"] {
appearance: initial;
width: 24px;
height: 24px;
background: #fff;
flex: unset;
padding: unset;
font-size: unset;
cursor: pointer;
appearance: initial;
width: 24px;
height: 24px;
background: #fff;
flex: unset;
padding: unset;
font-size: unset;
cursor: pointer;
}
input[type="checkbox"].checked {
background: #0049ff;
position: relative;
background: #0049ff;
position: relative;
}
input[type="checkbox"].checked::after {
content: '\2713';
color: #fff;
font-size: 22px;
line-height: 24px;
text-align: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: "\2713";
color: #fff;
font-size: 22px;
line-height: 24px;
text-align: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.carousel-page__list {
display: flex;
gap: 8px;
flex-wrap: wrap;
font-size: 16px;
}
.carousel-page__list > div {
display: flex;
align-items: center;
gap: 8px;
}
input[type="checkbox"].carousel-page {
width: 18px;
height: 18px;
}
input[type="checkbox"].carousel-page.checked::after {
font-size: 14px;
line-height: 18px;
}
label {
cursor: pointer;
user-select: none;
cursor: pointer;
user-select: none;
}
.footer {
display: flex;
gap: 12px;
display: flex;
gap: 12px;
}
.btn {
flex: 1;
padding: 18px;
font-size: 28px;
cursor: pointer;
letter-spacing: 12px;
background: url(../assets/dialog-button.png) 0 0 / 100% 100% no-repeat;
flex: 1;
padding: 12px;
font-size: 20px;
cursor: pointer;
letter-spacing: 8px;
background: url(../assets/dialog-button.png) 0 0 / 100% 100% no-repeat;
}
button {
appearance: none;
outline: none;
background: none;
border: none;
color: #fff;
appearance: none;
outline: none;
background: none;
border: none;
color: #fff;
}
.modal {
/* position: fixed;
/* position: fixed;
height: 1080px;
width: 1920px; */
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: #0003;
backdrop-filter: blur(3px);
z-index: 999;
transition: all .3s ease-out;
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: #0003;
backdrop-filter: blur(3px);
z-index: 999;
transition: all 0.3s ease-out;
}
.setting-dialog>h1 {
text-align: center;
letter-spacing: 24px;
font-weight: 400;
text-shadow: 0 5px 1px #001124;
user-select: none;
color: #fff;
.setting-dialog > h1 {
text-align: center;
letter-spacing: 24px;
font-weight: 400;
text-shadow: 0 5px 1px #001124;
user-select: none;
color: #fff;
}
</style>
</style>

View File

@@ -1,43 +1,47 @@
<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 "./LineMonthOptions";
import YieldChart from "../Chart/YieldChart.vue";
import RateChart from "../Chart/RateChart.vue";
const show = ref(false);
const chartContainer = ref(null);
const chartInstance = ref(null);
const displayProductionChart = ref(false);
const displayRateChart = ref(false);
const websocketData = ref(null);
const refreshToken = ref(1);
const store = useWsStore();
onMounted(() => {
chartContainer.value.classList.add("h-full");
const d = loadData(store.data2.monthlyTarget);
// const d = loadData([
// websocketData.value = loadData([
// {
// targetProduction: 100,
// nowProduction: 66,
// targetYield: 13,
// nowYield: 3,
// targetProduction: 0,
// nowProduction: 10,
// targetYield: 10.34,
// nowYield: 3.11,
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
websocketData.value = loadData(store.data2.monthlyTarget);
if (!websocketData.value) {
displayProductionChart.value = false;
displayRateChart.value = false;
} else {
if (!chartInstance.value)
chartInstance.value = echarts.init(chartContainer.value);
setupFn(chartInstance.value, d);
show.value = true;
/** 阻止 targetProduction == 0 */
if (!websocketData.value.targetProduction) {
displayProductionChart.value = false;
} else {
displayProductionChart.value = true;
}
/** 阻止 targetYield == 0 */
if (!websocketData.value.targetYield) {
displayRateChart.value = false;
} else {
displayRateChart.value = true;
}
}
});
// 订阅
store.$subscribe((mutation, state) => {
const d = loadData(state.data2.monthlyTarget);
// const d = loadData([
// {
// targetProduction: 100,
@@ -46,30 +50,35 @@ store.$subscribe((mutation, state) => {
// nowYield: 3,
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
websocketData.value = loadData(state.data2.monthlyTarget);
if (!websocketData.value) {
displayProductionChart.value = false;
displayRateChart.value = false;
} else {
if (!chartInstance.value)
chartInstance.value = echarts.init(chartContainer.value);
setupFn(chartInstance.value, d);
show.value = true;
/** 阻止 targetProduction == 0 */
if (!websocketData.value.targetProduction) {
displayProductionChart.value = false;
} else {
if (refreshToken.value > 100000) refreshToken.value = 0;
refreshToken.value += 1;
displayProductionChart.value = true;
}
/** 阻止 targetYield == 0 */
if (!websocketData.value.targetYield) {
displayRateChart.value = false;
} else {
if (refreshToken.value > 100000) refreshToken.value = 0;
refreshToken.value += 1;
displayRateChart.value = true;
}
}
});
// utils
function loadData(monthlyTarget) {
if (
monthlyTarget == undefined ||
// monthlyTarget?.length == 0 ||
!monthlyTarget[0]
) {
if (monthlyTarget == undefined || !monthlyTarget[0]) {
return null;
}
return {
targetProduction: monthlyTarget[0].targetProduction,
nowProduction: monthlyTarget[0].nowProduction,
@@ -81,12 +90,38 @@ function loadData(monthlyTarget) {
<template>
<Container class="chart" title="本月生产线情况" icon="cube">
<div
<!-- <div
ref="chartContainer"
class="chart-chart"
:style="{ opacity: show ? 1 : 0 }"
></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
:key="refreshToken + '_yield_chart_linemonth'"
:raw-data="websocketData"
/>
<rate-chart
:display-placeholder="!displayRateChart"
:key="refreshToken + '_rate_chart_linemonth'"
: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>
</template>
@@ -99,4 +134,10 @@ function loadData(monthlyTarget) {
.chart-chart {
height: 100%;
}
.container-body__h-full {
height: 100%;
display: flex;
gap: 12px;
}
</style>

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,43 +1,47 @@
<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";
import YieldChart from "../Chart/YieldChart.vue";
import RateChart from "../Chart/RateChart.vue";
const show = ref(false);
const chartContainer = ref(null);
const chartInstance = ref(null);
const displayProductionChart = ref(false);
const displayRateChart = ref(false);
const websocketData = ref(null);
const refreshToken = ref(1);
const store = useWsStore();
onMounted(() => {
chartContainer.value.classList.add("h-full");
const d = loadData(store.data2.dailyTarget);
// const d = loadData([
// websocketData.value = loadData([
// {
// targetProduction: 100,
// nowProduction: 66,
// targetYield: 13,
// nowYield: 3,
// targetProduction: 1220,
// nowProduction: 8,
// targetYield: null,
// nowYield: null,
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
websocketData.value = loadData(store.data2.dailyTarget);
if (!websocketData.value) {
displayProductionChart.value = false;
displayRateChart.value = false;
} else {
if (!chartInstance.value)
chartInstance.value = echarts.init(chartContainer.value);
setupFn(chartInstance.value, d);
show.value = true;
/** 阻止 targetProduction == 0 */
if (!websocketData.value.targetProduction) {
displayProductionChart.value = false;
} else {
displayProductionChart.value = true;
}
/** 阻止 targetYield == 0 */
if (!websocketData.value.targetYield) {
displayRateChart.value = false;
} else {
displayRateChart.value = true;
}
}
});
// 订阅
store.$subscribe((mutation, state) => {
const d = loadData(state.data2.dailyTarget);
// const d = loadData([
// {
// targetProduction: 100,
@@ -46,34 +50,44 @@ store.$subscribe((mutation, state) => {
// nowYield: 3,
// },
// ]);
if (!d) {
show.value = false;
if (chartInstance.value) {
chartInstance.value.dispose();
chartInstance.value = null;
}
websocketData.value = loadData(state.data2.dailyTarget);
if (!websocketData.value) {
displayProductionChart.value = false;
displayRateChart.value = false;
} else {
if (!chartInstance.value)
chartInstance.value = echarts.init(chartContainer.value);
setupFn(chartInstance.value, d);
show.value = true;
/** 阻止 targetProduction == 0 */
if (!websocketData.value.targetProduction) {
displayProductionChart.value = false;
} else {
if (refreshToken.value > 100000) refreshToken.value = 0;
refreshToken.value += 1;
displayProductionChart.value = true;
}
/** 阻止 targetYield == 0 */
if (!websocketData.value.targetYield) {
displayRateChart.value = false;
} else {
if (refreshToken.value > 100000) refreshToken.value = 0;
refreshToken.value += 1;
displayRateChart.value = true;
}
}
});
// utils
function loadData(dailyTarget) {
if (
dailyTarget == undefined ||
// dailyTarget?.length == 0 ||
!dailyTarget[0]
) {
if (dailyTarget == undefined || !dailyTarget[0]) {
return null;
}
return {
// 目标产量
targetProduction: dailyTarget[0].targetProduction,
// 当前产量
nowProduction: dailyTarget[0].nowProduction,
// 目标成品率
targetYield: dailyTarget[0].targetYield,
// 当前成品率
nowYield: dailyTarget[0].nowYield,
};
}
@@ -81,12 +95,38 @@ function loadData(dailyTarget) {
<template>
<Container class="chart" title="本日生产线情况" icon="cube">
<div
<!-- <div
ref="chartContainer"
class="chart-chart"
:style="{ opacity: show ? 1 : 0 }"
></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
:key="refreshToken + '_yield_chart_linetoday'"
:raw-data="websocketData"
/>
<rate-chart
:display-placeholder="!displayRateChart"
:key="refreshToken + '_rate_chart_linetoday'"
: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>
</template>
@@ -99,4 +139,10 @@ function loadData(dailyTarget) {
.chart-chart {
height: 100%;
}
.container-body__h-full {
height: 100%;
display: flex;
gap: 12px;
}
</style>

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ const pinia = createPinia();
setTimeout(() => {
window.location.reload();
}, 24 * 60 * 60 * 1000);
}, 60 * 60 * 1000);
const app = createApp(App);
app.use(pinia);

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,7 @@ const props = defineProps({
}
.data-list {
height: 100%;
/* height: 100%; */
width: 480px;
position: absolute;

View File

@@ -13,6 +13,7 @@ export const useSettings = defineStore("settings", () => {
},
carousel: true,
carouselTime: 30, // s
carouselPages: ["3d", "data", "realtime", "alert", "announcement"],
fullscreen: false,
eqStatus: true,
}
@@ -70,6 +71,20 @@ export const useSettings = defineStore("settings", () => {
settings.value.resolution.height = value.height;
settings.value.resolution.width = value.width;
break;
case "carousel-page":
const exists = settings.value.carouselPages.includes(value);
if (exists)
settings.value.carouselPages = settings.value.carouselPages.filter(
(page) => page !== value
);
else {
settings.value.carouselPages.splice(
["3d", "data", "realtime", "alert", "announcement"].indexOf(value),
0,
value
);
}
break;
}
}
return { settings, updateSettings, rewriteSettings };

View File

@@ -88,7 +88,7 @@ export default class Glass {
this.el.style.width = size ? `${size}px` : "16px";
this.el.style.height = size ? `${size}px` : "16px";
this.el.style.transformOrigin = "center";
this.el.style.transition = `all ${distance / 25}s linear`;
this.el.style.transition = `all ${distance / 10}s linear`;
this.el.style.zIndex = "100";
this.el.style.pointerEvents = "none";
// this.el.style.transform = `rotate(${angle}deg) skew(32deg, 8deg)`;

View File

@@ -7,7 +7,7 @@ export default function useWebsocket(store, path, excludePaths = []) {
}
// const url = "ws://192.168.1.101:8082/QbMonitoring/websocket";
const url = "ws://192.168.0.33:8082/QbMonitoring/websocket";
const url = "ws://192.168.0.254:8082/QbMonitoring/websocket";
function connectPath(store, path) {
new Client(
{

BIN
郴州管理端.rar Normal file

Binary file not shown.