init
2
.env
Normal file
@ -0,0 +1,2 @@
|
||||
# Place your StackBlitz environment variables here,
|
||||
# and they will be securely synced to your account.
|
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
}
|
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Vue 3 + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
24
_gitignore
Normal file
@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
13
index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
1940
package-lock.json
generated
Normal file
22
package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "vite-vue-starter",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"echarts": "^5.4.3",
|
||||
"element-plus": "^2.4.4",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.3.11",
|
||||
"vue3-marquee": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.2",
|
||||
"vite": "^5.0.8"
|
||||
}
|
||||
}
|
1
public/vite.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | 大小: 1.5 KiB |
71
src/App.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<script setup>
|
||||
import { ref, provide } from "vue";
|
||||
import MainPage from "./MainPage.vue";
|
||||
import Slider from "./components/Slider.vue";
|
||||
import Client from "./utils/ws";
|
||||
import { useWsStore } from "./store";
|
||||
|
||||
const store = useWsStore();
|
||||
|
||||
const url = "ws://192.168.1.101:8082/QbMonitoring/websocket";
|
||||
let urlPath = document.location.pathname;
|
||||
if (urlPath === "/") {
|
||||
urlPath = "/1-1";
|
||||
}
|
||||
new Client(
|
||||
{
|
||||
url: url + urlPath,
|
||||
name: urlPath,
|
||||
},
|
||||
(message) => {
|
||||
try {
|
||||
|
||||
const data = JSON.parse(message.data);
|
||||
console.log("message", JSON.parse(message.data));
|
||||
|
||||
if ("specificationChanges" in data) {
|
||||
console.log('[*] setting data1')
|
||||
// 分屏推送1数据
|
||||
store.updateData('1', data);
|
||||
} else if ("deliveryNotification" in data) {
|
||||
// 分屏推送3数据
|
||||
console.log('[*] setting data3')
|
||||
store.updateData('3', data);
|
||||
} else {
|
||||
// 分屏推送2数据
|
||||
console.log('[*] setting data2')
|
||||
store.updateData('2', data);
|
||||
}
|
||||
} catch(err) {
|
||||
console.log('[x] 未解析的ws数据: ', err);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const styles = ref({});
|
||||
function setSize(value) {
|
||||
const v = (value / 100).toFixed(2);
|
||||
console.log("size change", value);
|
||||
styles.value = {
|
||||
transform: `scale(${v})`,
|
||||
// transform: `scale(${v * 24 / 33}, ${v})`,
|
||||
transformOrigin: "top left",
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="app-container">
|
||||
<MainPage :style="styles" />
|
||||
<Slider @size-change="setSize" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
#app-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
57
src/MainPage.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import Tools from './components/Tools.vue';
|
||||
import NavMenu from './components/NavMenu.vue';
|
||||
import AnnoucementPage from './pages/AnnouncementPage.vue';
|
||||
import RealtimePage from './pages/RealtimePage.vue';
|
||||
import AppHeader from './components/Base/Header.vue';
|
||||
import AlertListPage from './pages/AlertListPage.vue'
|
||||
import DataPage from './pages/DataPage.vue';
|
||||
|
||||
|
||||
const currentPage = ref('3d');
|
||||
const handlePageChange = (page) => {
|
||||
currentPage.value = page;
|
||||
console.log(currentPage.value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<Tools v-if="currentPage !== 'announcement'" />
|
||||
<AppHeader v-if="currentPage !== 'announcement'" />
|
||||
<AnnoucementPage
|
||||
v-if="currentPage === 'announcement'"
|
||||
class="annoucement-page"
|
||||
@home="() => handlePageChange('3d')"
|
||||
/>
|
||||
<div v-else class="pages-wrapper">
|
||||
<NavMenu @change="handlePageChange" />
|
||||
<div v-if="currentPage === '3d'" class="3d-page">3d</div>
|
||||
<DataPage v-if="currentPage === 'data'" />
|
||||
<AlertListPage v-if="currentPage === 'alert'" />
|
||||
<RealtimePage v-if="currentPage === 'realtime'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.main-container {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: #000;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/**
|
||||
background: url('https://img1.baidu.com/it/u=2052683582,2603151390&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800')
|
||||
100% / 100% no-repeat;
|
||||
*/
|
||||
background: url(./assets/bg.png) 100% / cover no-repeat;
|
||||
}
|
||||
|
||||
.pages-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
二進制
src/assets/1.png
Normal file
After Width: | Height: | 大小: 3.1 KiB |
二進制
src/assets/2.png
Normal file
After Width: | Height: | 大小: 3.5 KiB |
二進制
src/assets/3.png
Normal file
After Width: | Height: | 大小: 3.1 KiB |
二進制
src/assets/bg.png
Normal file
After Width: | Height: | 大小: 761 KiB |
二進制
src/assets/header-bg.png
Normal file
After Width: | Height: | 大小: 25 KiB |
二進制
src/assets/header-bg@2x.png
Normal file
After Width: | Height: | 大小: 90 KiB |
二進制
src/assets/leftcorner@2x.png
Normal file
After Width: | Height: | 大小: 4.3 KiB |
二進制
src/assets/logo@2x.png
Normal file
After Width: | Height: | 大小: 12 KiB |
二進制
src/assets/rightcorner@2x.png
Normal file
After Width: | Height: | 大小: 5.2 KiB |
24
src/assets/svg/check.svg
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="26px" height="26px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>任务</title>
|
||||
<defs>
|
||||
<linearGradient x1="91.384997%" y1="100%" x2="25.4330364%" y2="7.84095011e-14%" id="linearGradient-1">
|
||||
<stop stop-color="#4BFFC8" offset="0%"></stop>
|
||||
<stop stop-color="#45F2EC" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="91.384997%" y1="100%" x2="25.4330364%" y2="7.84095011e-14%" id="linearGradient-2">
|
||||
<stop stop-color="#FFFFFF" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="环动科技热处理车间立库看板" transform="translate(-989.000000, -621.000000)" fill-rule="nonzero">
|
||||
<g id="编组-36" transform="translate(982.000000, 621.000000)">
|
||||
<g id="任务" transform="translate(7.000000, 0.000000)">
|
||||
<rect id="矩形" fill="#FFFFFF" opacity="0" x="0" y="0" width="32" height="32"></rect>
|
||||
<path d="M24.8336138,7.21888656 C25.307557,7.21888656 25.7025096,7.62700427 25.6893445,8.08778234 L25.6893445,25.768495 C25.6893445,26.5452352 25.2417316,26.6505559 24.859944,26.6505559 L7.17923134,26.6505559 C6.6921231,26.6505559 6.31033556,26.2556033 6.31033556,25.7816601 L6.31033556,8.10094743 C6.31033556,7.61383919 6.70528819,7.23205165 7.17923134,7.23205165 L10.3915127,7.23205165 L10.3915127,9.00933847 C10.3915127,9.41745619 10.733805,9.75974847 11.1419227,9.75974847 L20.8709225,9.75974847 C21.2790402,9.75974847 21.6213325,9.43062128 21.6213325,9.00933847 L21.6213325,7.21888656 Z M21.3580307,13.7224398 C21.0289035,13.3933127 20.5154651,13.3933127 20.1863379,13.7224398 L14.5385153,19.3702624 L11.7738469,16.6319242 C11.4447197,16.302797 10.9312813,16.302797 10.6021541,16.6319242 C10.2730269,16.9610514 10.2730269,17.4744898 10.6021541,17.803617 L13.9460864,21.1475493 C14.2752136,21.4766764 14.788652,21.4766764 15.1177792,21.1475493 L21.3711958,14.9072977 C21.5423419,14.7361516 21.6213325,14.5386753 21.6213325,14.3148688 C21.6213325,14.0910623 21.5291768,13.893586 21.3580307,13.7224398 Z M19.896706,5.34944412 C20.1863379,5.34944412 20.4364746,5.59958078 20.4364746,5.88921271 L20.4364746,8.10094743 C20.4364746,8.39057936 20.1863379,8.64071602 19.896706,8.64071602 L12.1161392,8.64071602 L12.1161392,8.6670462 C11.8265073,8.6670462 11.5763706,8.41690953 11.5763706,8.1272776 L11.5763706,5.88921271 C11.5763706,5.59958078 11.8265073,5.34944412 12.1161392,5.34944412 L19.896706,5.34944412 Z" id="形状结合" fill="url(#linearGradient-2)"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | 大小: 2.8 KiB |
22
src/assets/svg/cube-twice.svg
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="26px" height="26px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>更多 2</title>
|
||||
<defs>
|
||||
<linearGradient x1="100%" y1="100%" x2="20.318998%" y2="7.84095011e-14%" id="linearGradient-1">
|
||||
<stop stop-color="#4BFFC8" offset="0%"></stop>
|
||||
<stop stop-color="#45F2EC" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="100%" y1="100%" x2="20.318998%" y2="7.84095011e-14%" id="linearGradient-2">
|
||||
<stop stop-color="#FFFFFF" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="环动科技热处理车间立库看板" transform="translate(-670.000000, -119.000000)" fill-rule="nonzero">
|
||||
<g id="更多-2" transform="translate(670.000000, 119.000000)">
|
||||
<rect id="矩形" fill="#FFFFFF" opacity="0" x="0" y="0" width="32" height="32"></rect>
|
||||
<path d="M18.6666667,12 L18.6666667,5.33333333 L7.33333333,5.33333333 C6.22876383,5.33333333 5.33333333,6.22876383 5.33333333,7.33333333 L5.33333333,18.6666667 L5.33333333,18.6666667 L12,18.6666667 L12,12 L18.6666667,12 Z M20,13.3333333 L20,20 L13.3333333,20 L13.3333333,26.6666667 L24.6666667,26.6666667 C25.7712362,26.6666667 26.6666667,25.7712362 26.6666667,24.6666667 L26.6666667,13.3333333 L26.6666667,13.3333333 L20,13.3333333 Z" id="形状" fill="url(#linearGradient-2)"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | 大小: 1.6 KiB |
12
src/assets/svg/cube.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="26px" height="26px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>多种 2</title>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="环动科技热处理车间立库看板" transform="translate(-39.000000, -620.000000)" fill="#FFFFFF" fill-rule="nonzero">
|
||||
<g id="多种-2" transform="translate(39.000000, 620.000000)">
|
||||
<rect id="矩形" opacity="0" x="0" y="0" width="32" height="32"></rect>
|
||||
<path d="M26,23 L18.2,27.8 C17.6,28.2 17,27.8 17,27 L17,15.8 C17,15.6 17.2,15.2 17.4,15 L25.2,10.2 C25.8,9.8 26.4,10.2 26.4,11 L26.4,22.4 C26.4,22.6 26.2,23 26,23 Z M6,23 L13.8,27.8 C14.4,28.2 15,27.8 15,27 L15,15.8 C15,15.6 14.8,15.2 14.6,15 L6.8,10.2 C6.4,10 5.6,10.4 5.6,11 L5.6,22.4 C5.6,22.6 5.8,23 6,23 Z M15.8,4 L6.8,7.4 C6.4,7.6 6.4,8.2 6.8,8.4 L15.8,14 C16,14 16.2,14 16.2,14 L25.4,8.4 C25.8,8.2 25.8,7.6 25.4,7.4 L16.2,4 C16,4 16,4 15.8,4 Z" id="形状"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | 大小: 1.1 KiB |
40
src/assets/svg/stack.svg
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="26px" height="26px" viewBox="0 0 24.4721163 23.7661066" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>多种</title>
|
||||
<defs>
|
||||
<linearGradient x1="100%" y1="89.6187762%" x2="20.318998%" y2="10.3812238%" id="linearGradient-1">
|
||||
<stop stop-color="#4BFFC8" offset="0%"></stop>
|
||||
<stop stop-color="#45F2EC" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="100%" y1="89.6187762%" x2="20.318998%" y2="10.3812238%" id="linearGradient-2">
|
||||
<stop stop-color="#FFFFFF" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="100%" y1="54.7269958%" x2="20.318998%" y2="45.2730042%" id="linearGradient-3">
|
||||
<stop stop-color="#4BFFC8" offset="0%"></stop>
|
||||
<stop stop-color="#45F2EC" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="100%" y1="54.7269958%" x2="20.318998%" y2="45.2730042%" id="linearGradient-4">
|
||||
<stop stop-color="#FFFFFF" offset="0%"></stop>
|
||||
<stop stop-color="#FFFFFF" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="环动科技热处理车间立库看板" transform="translate(-43.763942, -124.000000)">
|
||||
<g id="多种" transform="translate(40.000000, 120.000000)">
|
||||
<rect id="矩形" x="0" y="0" width="32" height="32"></rect>
|
||||
<g id="异常" transform="translate(3.763942, 4.000000)" fill-rule="nonzero">
|
||||
<rect id="矩形" fill="#FFFFFF" opacity="0" x="0.236058137" y="0" width="22.6666667" height="22.6666667"></rect>
|
||||
<g transform="translate(0.000000, 1.333333)">
|
||||
<rect id="矩形" fill="#FFFFFF" opacity="0" x="3.05901453" y="5.09835756" width="17.3344157" height="17.3344157"></rect>
|
||||
<g id="数量_面性">
|
||||
<rect id="矩形" fill="#FFFFFF" opacity="0" x="0" y="0" width="21.7851425" height="21.7851425"></rect>
|
||||
<path d="M12.237403,12.1431998 C12.1208704,12.1431998 12.0057183,12.1179773 11.8998678,12.0692379 L0.469391828,6.80449511 C0.183288453,6.67275726 2.8725996e-07,6.38657609 2.8725996e-07,6.07159989 C2.8725996e-07,5.7566237 0.183288453,5.47044252 0.469391828,5.33870467 L11.8998678,0.073961899 C12.1133182,-0.0238729288 12.3587984,-0.0238729288 12.5722488,0.073961899 L24.0027247,5.33870467 C24.2888281,5.47044252 24.4721163,5.7566237 24.4721163,6.07159989 C24.4721163,6.38657609 24.2888281,6.67275726 24.0027247,6.80449511 L12.5722488,12.0692379 C12.4672224,12.1175995 12.3530285,12.142823 12.237403,12.1431998 L12.237403,12.1431998 Z M23.2644505,15.0102321 L12.237403,20.0893977 L1.21035562,15.0102321 L1.21035562,16.7866626 L11.8998678,21.7111806 C12.1133182,21.8090154 12.3587984,21.8090154 12.5722488,21.7111806 L23.2644505,16.7866626 L23.2644505,15.0102321 Z" id="形状" fill="url(#linearGradient-2)"></path>
|
||||
<path d="M23.2644505,10.1838817 L12.237403,15.2643921 L1.21035562,10.1838817 L1.21035562,11.9683807 L11.8998678,16.891554 C12.1133182,16.9893888 12.3587984,16.9893888 12.5722488,16.891554 L23.2644505,11.9683807 L23.2644505,10.1838817 Z" id="路径" fill="url(#linearGradient-4)"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | 大小: 3.5 KiB |
114
src/components/Base/Container.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<script setup>
|
||||
import Icon from './Icon.vue';
|
||||
import Corner from './Corner.vue';
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Default title',
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'icon',
|
||||
},
|
||||
corner: {
|
||||
type: Array,
|
||||
default: ['tl', 'tr', 'bl', 'br'], //'trbl', // top right bottom left
|
||||
},
|
||||
cubeCorner: {
|
||||
type: String,
|
||||
default: 'bl',
|
||||
validator: (value, props) => {
|
||||
return ['bl', 'br'].includes(value);
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container-border">
|
||||
<Corner
|
||||
v-if="corner.indexOf('tl') !== -1"
|
||||
position="top-left"
|
||||
key="top-left"
|
||||
/>
|
||||
<Corner
|
||||
v-if="corner.indexOf('tr') !== -1"
|
||||
position="top-right"
|
||||
key="top-right"
|
||||
/>
|
||||
<Corner
|
||||
v-if="corner.indexOf('bl') !== -1"
|
||||
position="bottom-left"
|
||||
key="bottom-left"
|
||||
/>
|
||||
<Corner
|
||||
v-if="corner.indexOf('br') !== -1"
|
||||
position="bottom-right"
|
||||
key="bottom-right"
|
||||
/>
|
||||
|
||||
<div class="container">
|
||||
<div class="cube" :class="[`cube-${cubeCorner}`]"></div>
|
||||
<div class="container-header">
|
||||
<Icon :name="icon" />
|
||||
<span>{{ title }}</span>
|
||||
</div>
|
||||
<div class="container-body">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container-border {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cube {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
background: #1f8fff;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cube-bl {
|
||||
transform: rotate(45deg);
|
||||
bottom: -13px;
|
||||
left: -13px;
|
||||
}
|
||||
|
||||
.cube-br {
|
||||
transform: rotate(45deg);
|
||||
bottom: -13px;
|
||||
right: -13px;
|
||||
}
|
||||
|
||||
.container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.container-header {
|
||||
background: #006acd66;
|
||||
backdrop-filter: blur(2px);
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.container-body {
|
||||
background: #ffffff33;
|
||||
backdrop-filter: blur(1px);
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
62
src/components/Base/Corner.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
position: {
|
||||
type: String,
|
||||
default: 'bottom-left',
|
||||
},
|
||||
});
|
||||
|
||||
const styles = computed(() => {
|
||||
switch (props.position) {
|
||||
case 'top-left':
|
||||
return {
|
||||
transform: 'rotate(90deg)',
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 'unset',
|
||||
right: 'unset',
|
||||
};
|
||||
case 'top-right':
|
||||
return {
|
||||
transform: 'rotate(180deg)',
|
||||
top: 0,
|
||||
left: 'unset',
|
||||
bottom: 'unset',
|
||||
right: 0,
|
||||
};
|
||||
case 'bottom-left':
|
||||
return {
|
||||
transform: 'rotate(0deg)',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 'unset',
|
||||
top: 'unset',
|
||||
};
|
||||
case 'bottom-right':
|
||||
return {
|
||||
transform: 'rotate(-90deg)',
|
||||
top: 'unset',
|
||||
left: 'unset',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="corner" :style="styles"></div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.corner {
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-left: 2px solid #0078e4;
|
||||
border-bottom: 2px solid #0078e4;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
37
src/components/Base/Header.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="header">
|
||||
<div>
|
||||
<Icon htmlRole="logo" icon="logo" />
|
||||
<h1 class="header__title">郴州旗滨光伏光电玻璃有限公司</h1>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.header {
|
||||
position: relative;
|
||||
height: 90px;
|
||||
background: url(../../assets/header-bg@2x.png) 100% / 100% no-repeat;
|
||||
}
|
||||
|
||||
.header > div {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
/** width: 520px; **/
|
||||
width: 480px;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.header__title {
|
||||
font-weight: 400;
|
||||
letter-spacing: 2px;
|
||||
color: #fff;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
51
src/components/Base/Icon.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<script setup>
|
||||
// import icons
|
||||
import checkIcon from '../../assets/svg/check.svg';
|
||||
import cubeIcon from '../../assets/svg/cube.svg';
|
||||
import cube2Icon from '../../assets/svg/cube-twice.svg';
|
||||
import stackIcon from '../../assets/svg/stack.svg';
|
||||
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
default: 'icon',
|
||||
},
|
||||
htmlRole: {
|
||||
type: String,
|
||||
default: 'icon', // 'icon' | 'logo'
|
||||
},
|
||||
});
|
||||
|
||||
const icon = computed(() => {
|
||||
switch (props.name) {
|
||||
case 'icon':
|
||||
case 'cube':
|
||||
return cubeIcon;
|
||||
case 'cube-2':
|
||||
return cube2Icon;
|
||||
case 'stack':
|
||||
return stackIcon;
|
||||
case 'check':
|
||||
return checkIcon;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="icon">
|
||||
<img :src="icon" :class="icon" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background: #fff3;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
54
src/components/Dribbble/Dialog.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<script setup>
|
||||
import './style.css';
|
||||
import { Close } from '@element-plus/icons-vue';
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
const contentVisible = ref(false);
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
contentVisible.value = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {});
|
||||
|
||||
function close() {
|
||||
contentVisible.value = false;
|
||||
setTimeout(() => {
|
||||
emit('close');
|
||||
}, 150);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="modal">
|
||||
<div class="dribbble-dialog pop-out" :class="{ visible: contentVisible }">
|
||||
<div class="logo"></div>
|
||||
<div class="left"></div>
|
||||
<div class="right"></div>
|
||||
<div class="content-text">
|
||||
<p>Advance your career with a</p>
|
||||
<p>Professional Diploma in UX Design</p>
|
||||
<button>Learn More</button>
|
||||
</div>
|
||||
<el-button
|
||||
:icon="Close"
|
||||
size="small"
|
||||
circle
|
||||
style="
|
||||
background: #eeeb;
|
||||
color: #000;
|
||||
border: none;
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
right: 8px;
|
||||
z-index: -10;
|
||||
"
|
||||
@click="close"
|
||||
></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
i
|
105
src/components/Dribbble/style.css
Normal file
@ -0,0 +1,105 @@
|
||||
.modal {
|
||||
background: #0003;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.dribbble-dialog {
|
||||
position: relative;
|
||||
margin: 12px;
|
||||
background: #fff;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 0 32px 2px #0001;
|
||||
overflow-x: hidden;
|
||||
height: auto;
|
||||
padding: 20px;
|
||||
transition: all 0.1s cubic-bezier(0, 0.48, 0, 1.18);
|
||||
}
|
||||
|
||||
.content-text {
|
||||
margin: 56px 56px 32px;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
outline: none;
|
||||
appearance: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 20px;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.1s ease-out;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
cursor: pointer;
|
||||
background: #000b;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 128px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
background: url(../../assets/logo@2x.png) center / contain no-repeat;
|
||||
}
|
||||
|
||||
.left {
|
||||
width: 160px;
|
||||
height: 80px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: url(../../assets/leftcorner@2x.png) center / 100% 100% no-repeat;
|
||||
z-index: -100;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 100px;
|
||||
height: 118px;
|
||||
position: absolute;
|
||||
z-index: -100;
|
||||
top: -2px;
|
||||
right: 0;
|
||||
background: url(../../assets/rightcorner@2x.png) center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(-56px);
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.pop-out {
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
}
|
||||
|
||||
.pop-out.visible {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
52
src/components/HourChart.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import Container from './Base/Container.vue';
|
||||
|
||||
const chartChart = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
chartChart.value.classList.add('h-full');
|
||||
const mc = echarts.init(chartChart.value);
|
||||
mc.setOption({
|
||||
grid: {
|
||||
top: 24,
|
||||
bottom: 24,
|
||||
left: 24,
|
||||
right: 24,
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '销量',
|
||||
type: 'bar',
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container class="chart" title="小时数据" icon="cube">
|
||||
<div ref="chartChart" class="chart-chart"></div>
|
||||
</Container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.chart {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-inner {
|
||||
background: #0f0;
|
||||
}
|
||||
|
||||
.chart-chart {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
55
src/components/NavMenu.vue
Normal file
@ -0,0 +1,55 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const emit = defineEmits(['change']);
|
||||
const handleClick = (page) => {
|
||||
emit('change', page);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="nav-menu">
|
||||
<ul>
|
||||
<li><button @click="(e) => handleClick('3d')">三维界面</button></li>
|
||||
<li><button @click="(e) => handleClick('data')">数据界面</button></li>
|
||||
<li><button @click="(e) => handleClick('realtime')">实时数据</button></li>
|
||||
<li><button @click="(e) => handleClick('alert')">报警列表</button></li>
|
||||
<li>
|
||||
<button @click="(e) => handleClick('announcement')">公告页面</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.nav-menu {
|
||||
width: 480px;
|
||||
padding: 12px;
|
||||
background: #0006;
|
||||
color: #fff;
|
||||
/**
|
||||
position: fixed;
|
||||
top: 45%;
|
||||
left: 10px;
|
||||
*/
|
||||
}
|
||||
|
||||
button {
|
||||
appearance: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: #7777;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
ul,
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
</style>
|
56
src/components/RealtimeChart.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<!-- 货物情况 -->
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import Container from './Base/Container.vue';
|
||||
|
||||
const cargoChart = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
cargoChart.value.classList.add('h-full');
|
||||
const mc = echarts.init(cargoChart.value);
|
||||
mc.setOption({
|
||||
grid: {
|
||||
top: 24,
|
||||
bottom: 24,
|
||||
left: 24,
|
||||
right: 24,
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '销量',
|
||||
type: 'bar',
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container class="cargo" title="实时数据" icon="cube">
|
||||
<div ref="cargoChart" class="cargo-chart"></div>
|
||||
</Container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.cargo {
|
||||
height: 640px;
|
||||
width: 80%;
|
||||
align-self: self-end;
|
||||
}
|
||||
|
||||
.cargo-inner {
|
||||
background: #0f0;
|
||||
}
|
||||
|
||||
.cargo-chart {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
49
src/components/RealtimeTable.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<!-- 实时数据表格 -->
|
||||
<script setup>
|
||||
|
||||
const tableData = [
|
||||
{ productLine: '00A', mbt: '---', mbb: '---', dkt: '---', dkb: '---', dmt: '---', dmb: '---', syt: '---', syb: '---', ght: '---', ghb: '---', gh1: '---', gh2: '---', bzt: '---', bzb: '---' },
|
||||
{ productLine: '00B', mbt: '---', mbb: '---', dkt: '---', dkb: '---', dmt: '---', dmb: '---', syt: '---', syb: '---', ght: '---', ghb: '---', gh1: '---', gh2: '---', bzt: '---', bzb: '---' },
|
||||
{ productLine: '00C', mbt: '---', mbb: '---', dkt: '---', dkb: '---', dmt: '---', dmb: '---', syt: '---', syb: '---', ght: '---', ghb: '---', gh1: '---', gh2: '---', bzt: '---', bzb: '---' },
|
||||
{ productLine: '00D', mbt: '---', mbb: '---', dkt: '---', dkb: '---', dmt: '---', dmb: '---', syt: '---', syb: '---', ght: '---', ghb: '---', gh1: '---', gh2: '---', bzt: '---', bzb: '---' },
|
||||
{ productLine: '00E', mbt: '---', mbb: '---', dkt: '---', dkb: '---', dmt: '---', dmb: '---', syt: '---', syb: '---', ght: '---', ghb: '---', gh1: '---', gh2: '---', bzt: '---', bzb: '---' },
|
||||
{ productLine: '00F', mbt: '---', mbb: '---', dkt: '---', dkb: '---', dmt: '---', dmb: '---', syt: '---', syb: '---', ght: '---', ghb: '---', gh1: '---', gh2: '---', bzt: '---', bzb: '---' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="realtime-table">
|
||||
<el-table class="dark-table" :data="tableData" :show-overflow-tooltip="true" row-class-name="dark-row"
|
||||
header-row-class-name="dark-header">
|
||||
<el-table-column prop="productLine" label="产线"></el-table-column>
|
||||
<el-table-column prop="mbt" label="磨边上"></el-table-column>
|
||||
<el-table-column prop="mbb" label="磨边下"></el-table-column>
|
||||
<el-table-column prop="dkt" label="打孔上"></el-table-column>
|
||||
<el-table-column prop="dkb" label="打孔下"></el-table-column>
|
||||
<el-table-column prop="dmt" label="镀膜上"></el-table-column>
|
||||
<el-table-column prop="dmb" label="镀膜下"></el-table-column>
|
||||
<el-table-column prop="syt" label="丝印上"></el-table-column>
|
||||
<el-table-column prop="syb" label="丝印下"></el-table-column>
|
||||
<el-table-column prop="ght" label="固化上"></el-table-column>
|
||||
<el-table-column prop="ghb" label="固化下"></el-table-column>
|
||||
<el-table-column prop="gh1" label="钢化上"></el-table-column>
|
||||
<el-table-column prop="gh2" label="钢化下"></el-table-column>
|
||||
<el-table-column prop="bzt" label="包装上"></el-table-column>
|
||||
<el-table-column prop="bzb" label="包装下"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.realtime-table {
|
||||
background: #00f3;
|
||||
height: 240px;
|
||||
width: 80%;
|
||||
align-self: self-start;
|
||||
}
|
||||
|
||||
.dark-table {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
65
src/components/Slider.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
|
||||
const emit = defineEmits(['size-change']);
|
||||
const size = ref(100);
|
||||
const slider = ref(null);
|
||||
|
||||
// watchers
|
||||
watch(size, (value) => {
|
||||
if (value == null) return;
|
||||
emit('size-change', value);
|
||||
});
|
||||
|
||||
// handlers
|
||||
function keydownHandler(e) {
|
||||
if (e.shiftKey && e.key === 'L') {
|
||||
if (slider.value) {
|
||||
slider.value.classList.toggle('show');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// hooks
|
||||
onMounted(() => {
|
||||
document.addEventListener('keydown', keydownHandler);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="slider" class="slider">
|
||||
<input type="range" min="0" max="100" v-model="size" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.slider {
|
||||
height: 5vh;
|
||||
width: 20vw;
|
||||
border-radius: 88px;
|
||||
box-shadow: 0 0 68px 8px rgba(0, 0, 0, 0.3);
|
||||
padding: 32px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
bottom: -5vh;
|
||||
opacity: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
transition: opacity 0.3s ease-out, bottom 0.3s ease-out;
|
||||
}
|
||||
|
||||
.slider input {
|
||||
width: 100%;
|
||||
transform: translateY(-7px);
|
||||
color: #0b58ff;
|
||||
background: #fcc;
|
||||
}
|
||||
|
||||
.slider.show {
|
||||
opacity: 1;
|
||||
bottom: 64px;
|
||||
}
|
||||
</style>
|
52
src/components/TeamChartDay.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import Container from './Base/Container.vue';
|
||||
|
||||
const chartChart = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
chartChart.value.classList.add('h-full');
|
||||
const mc = echarts.init(chartChart.value);
|
||||
mc.setOption({
|
||||
grid: {
|
||||
top: 24,
|
||||
bottom: 24,
|
||||
left: 24,
|
||||
right: 24,
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '销量',
|
||||
type: 'bar',
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container class="chart" title="本日班组情况" icon="cube">
|
||||
<div ref="chartChart" class="chart-chart"></div>
|
||||
</Container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.chart {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-inner {
|
||||
background: #0f0;
|
||||
}
|
||||
|
||||
.chart-chart {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
52
src/components/TeamChartMonth.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import Container from './Base/Container.vue';
|
||||
|
||||
const chartChart = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
chartChart.value.classList.add('h-full');
|
||||
const mc = echarts.init(chartChart.value);
|
||||
mc.setOption({
|
||||
grid: {
|
||||
top: 24,
|
||||
bottom: 24,
|
||||
left: 24,
|
||||
right: 24,
|
||||
},
|
||||
tooltip: {},
|
||||
xAxis: {
|
||||
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '销量',
|
||||
type: 'bar',
|
||||
data: [5, 20, 36, 10, 10, 20],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container class="chart" title="本月班组情况" icon="cube">
|
||||
<div ref="chartChart" class="chart-chart"></div>
|
||||
</Container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.chart {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.chart-inner {
|
||||
background: #0f0;
|
||||
}
|
||||
|
||||
.chart-chart {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
21
src/components/Tools.vue
Normal file
@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tools">
|
||||
<button>Home</button>
|
||||
<button>Settings</button>
|
||||
<button>AutoScroll</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.tools {
|
||||
background: #00f;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
left: 24px;
|
||||
}
|
||||
</style>
|
11
src/components/data.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"code": 0,
|
||||
"data": [
|
||||
{ "date": "2023-01-01", "检测项目": "光刻胶&显影", "光刻胶残留": "1" },
|
||||
{ "date": "2023-01-01", "检测项目": "激光一", "磨面擦伤": "1" },
|
||||
{ "date": "2023-01-01", "检测项目": "激光二", "刻线宽度不良": "1" },
|
||||
{ "date": "2023-01-02", "检测项目": "光刻胶&显影", "光刻胶残留": "2" },
|
||||
{ "date": "2023-01-02", "检测项目": "激光一", "刻线宽度不良": "2" },
|
||||
{ "date": "2023-01-03", "检测项目": "激光二", "擦伤": "3" }
|
||||
]
|
||||
}
|
16
src/main.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
|
||||
import './style.css';
|
||||
import ElementPlus from 'element-plus';
|
||||
import 'element-plus/dist/index.css';
|
||||
import Vue3Marquee from 'vue3-marquee';
|
||||
import App from './App.vue';
|
||||
const pinia = createPinia()
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(pinia);
|
||||
app.use(ElementPlus);
|
||||
app.use(Vue3Marquee, { name: 'ScrollText' });
|
||||
app.mount('#app');
|
1
src/pages/3D.vue
Normal file
@ -0,0 +1 @@
|
||||
<!-- 三维页面 -->
|
140
src/pages/AlertListPage.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<!-- 报警列表页面 -->
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const tableData = [
|
||||
{ id: 1, eqName: '设备00A', eqIndex: '1', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 2, eqName: '设备00B', eqIndex: '2', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 3, eqName: '设备00C', eqIndex: '3', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 4, eqName: '设备00D', eqIndex: '4', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 5, eqName: '设备00E', eqIndex: '5', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 6, eqName: '设备00F', eqIndex: '6', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 7, eqName: '设备00G', eqIndex: '7', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 1, eqName: '设备00A', eqIndex: '1', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 2, eqName: '设备00B', eqIndex: '2', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 3, eqName: '设备00C', eqIndex: '3', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 4, eqName: '设备00D', eqIndex: '4', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 5, eqName: '设备00E', eqIndex: '5', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 6, eqName: '设备00F', eqIndex: '6', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 7, eqName: '设备00G', eqIndex: '7', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 1, eqName: '设备00A', eqIndex: '1', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 2, eqName: '设备00B', eqIndex: '2', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 3, eqName: '设备00C', eqIndex: '3', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 4, eqName: '设备00D', eqIndex: '4', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 5, eqName: '设备00E', eqIndex: '5', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 6, eqName: '设备00F', eqIndex: '6', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 7, eqName: '设备00G', eqIndex: '7', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 1, eqName: '设备00A', eqIndex: '1', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 2, eqName: '设备00B', eqIndex: '2', alarmGrade: 1, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 3, eqName: '设备00C', eqIndex: '3', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 4, eqName: '设备00D', eqIndex: '4', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 5, eqName: '设备00E', eqIndex: '5', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 6, eqName: '设备00F', eqIndex: '6', alarmGrade: 3, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
{ id: 7, eqName: '设备00G', eqIndex: '7', alarmGrade: 2, alarmDetail: 'lorem sdf fkj', position: 'x,y' },
|
||||
]
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="alert-list-page">
|
||||
<div class="alert-list">
|
||||
<div class="alert-list__table" style="">
|
||||
<el-table class="dark-table" :data="tableData" :show-overflow-tooltip="true" row-class-name="dark-row"
|
||||
header-row-class-name="dark-header">
|
||||
<el-table-column prop="eqName" label="设备名" width="90"></el-table-column>
|
||||
<el-table-column prop="eqIndex" label="序号" width="60"></el-table-column>
|
||||
<el-table-column prop="alarmGrade" label="报警等级" width="90"></el-table-column>
|
||||
<el-table-column prop="alarmDetail" label="报警细节" width="144"></el-table-column>
|
||||
<el-table-column prop="position" label="定位"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<button class="alert-btn">忽略</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.dark-table {
|
||||
/* height: 72vh; */
|
||||
/* height: 72%; */
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dark-row {
|
||||
color: #fff;
|
||||
background: #005eff25 !important;
|
||||
}
|
||||
|
||||
.dark-row>td.el-table__cell {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.dark-row:hover>td.el-table__cell {
|
||||
background-color: #005effaa !important;
|
||||
}
|
||||
|
||||
.dark-header {
|
||||
background-color: transparent !important;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dark-header>th.el-table__cell.is-leaf {
|
||||
border-bottom: none;
|
||||
background-color: #005eff95 !important;
|
||||
font-weight: 400;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.dark-header>th.el-table__cell {
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
.alert-list-page {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alert-list {
|
||||
height: 100%;
|
||||
width: 480px;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.alert-list__table {
|
||||
height: calc(100% - 72px);
|
||||
background: linear-gradient(to right, transparent, #0ba6ff80);
|
||||
}
|
||||
|
||||
.alert-list__table>>>.el-table__inner-wrapper::before {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
button {
|
||||
appearance: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.alert-btn {
|
||||
height: 72px;
|
||||
background: #0f04;
|
||||
color: #fff;
|
||||
font-size: 32px;
|
||||
line-height: 1;
|
||||
letter-spacing: 2px;
|
||||
transition: all .2s ease-out;
|
||||
}
|
||||
|
||||
.alert-btn:hover {
|
||||
background: #0f08;
|
||||
}
|
||||
</style>
|
68
src/pages/AnnouncementPage.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<!-- 公告页面 -->
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
const emit = defineEmits(['home']);
|
||||
const content = ref('公告加载中...');
|
||||
|
||||
const handleClose = () => {
|
||||
emit('home');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="announcement-page">
|
||||
<h1 class="announcement-title">公告栏</h1>
|
||||
<main class="announcement-content">
|
||||
<ScrollText :vertical="true" :duration="10" :pause-on-hover="true">
|
||||
{{ content }}
|
||||
</ScrollText>
|
||||
</main>
|
||||
<div class="announcement-footer">
|
||||
<button
|
||||
style="position: absolute; left: 0; bottom: 10px"
|
||||
@click="handleClose"
|
||||
>
|
||||
返回
|
||||
</button>
|
||||
<ScrollText> 数据加载异常 </ScrollText>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.announcement-page {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: #000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.announcement-title {
|
||||
color: #fff;
|
||||
font-size: 72px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.announcement-content {
|
||||
/* background: #ccc3; */
|
||||
flex: 1;
|
||||
padding: 8px 80px;
|
||||
font-size: 72px;
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
.announcement-footer {
|
||||
height: 128px;
|
||||
/* background: #ccc1; */
|
||||
font-size: 64px;
|
||||
padding: 0 80px;
|
||||
line-height: 128px;
|
||||
font-family: sans-serif;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
43
src/pages/DataPage.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<!-- 实时数据页面 -->
|
||||
<script setup>
|
||||
import HourChart from "../components/HourChart.vue";
|
||||
import TeamChartDay from "../components/TeamChartDay.vue";
|
||||
import TeamChartMonth from "../components/TeamChartMonth.vue";
|
||||
|
||||
import { useWsStore } from '../store'
|
||||
|
||||
const store = useWsStore();
|
||||
|
||||
console.log('store', store.data1.test);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="data-page">
|
||||
<div class="data-list">
|
||||
<HourChart />
|
||||
<TeamChartDay />
|
||||
<TeamChartMonth />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.data-page {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.data-list {
|
||||
height: 100%;
|
||||
width: 480px;
|
||||
background: #ccc3;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
21
src/pages/RealtimePage.vue
Normal file
@ -0,0 +1,21 @@
|
||||
<!-- 实时数据页面 -->
|
||||
<script setup>
|
||||
import Chart from '../components/RealtimeChart.vue';
|
||||
import RealtimeTable from '../components/RealtimeTable.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="realtime-page">
|
||||
<Chart />
|
||||
<RealtimeTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.realtime-page {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
</style>
|
41
src/store/index.js
Normal file
@ -0,0 +1,41 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from 'vue';
|
||||
|
||||
|
||||
export const useWsStore = defineStore("wsData", () => {
|
||||
const data1 = ref({ test: 'hello world'});
|
||||
const data2 = ref({});
|
||||
const data3 = ref({});
|
||||
|
||||
function updateData(category, data) {
|
||||
console.log('update', data)
|
||||
switch (category) {
|
||||
case "1":
|
||||
data1.value = data;
|
||||
break;
|
||||
case "2":
|
||||
data2.value = data;
|
||||
break;
|
||||
case "3":
|
||||
data3.value = data;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { data1, data2, data3, updateData };
|
||||
});
|
||||
// export const useWsStore = defineStore('wsData', {
|
||||
// state: () => ({
|
||||
// data1: {
|
||||
// test: 'hello world'
|
||||
// },
|
||||
// data2: null,
|
||||
// data3: null,
|
||||
// }),
|
||||
// actions: {
|
||||
// updateData(category, data) {
|
||||
// this[category] = data
|
||||
// }
|
||||
// }
|
||||
// })
|
4
src/style.css
Normal file
@ -0,0 +1,4 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
}
|
22
src/utils/connects.js
Normal file
@ -0,0 +1,22 @@
|
||||
import Client from './ws'
|
||||
|
||||
const uid_list = [
|
||||
// 磨边 丝印 钢化 包装
|
||||
// 一线
|
||||
'1-1', '1-2', '1-3', '1-4',
|
||||
// 二线
|
||||
'2-1', '2-2', '2-3', '2-4',
|
||||
// 三线
|
||||
'3-1', '3-2', '3-3', '3-4',
|
||||
]
|
||||
|
||||
const url = 'wss://192.168.1.101:8082/QbMonitoring/websocket/'
|
||||
|
||||
uid_list.forEach(uid => {
|
||||
new Client({
|
||||
url: url + uid,
|
||||
name: '/' + uid
|
||||
}, message => {
|
||||
console.log('message', message);
|
||||
})
|
||||
})
|
95
src/utils/ws.js
Normal file
@ -0,0 +1,95 @@
|
||||
export default class XClient {
|
||||
url = "";
|
||||
name = "";
|
||||
ws = null;
|
||||
timeout = 1000 * 5;
|
||||
heartbeatDelay = 1000 * 60 * 3;
|
||||
reconnectCount = 0;
|
||||
onmessage = null;
|
||||
hb = 0;
|
||||
|
||||
constructor(
|
||||
config,
|
||||
onmessage
|
||||
) {
|
||||
this.url = config.url;
|
||||
this.name = config.name;
|
||||
this.ws = new WebSocket(config.url);
|
||||
this.timeout = config.timeout || 1000 * 5;
|
||||
|
||||
this.ws.onopen = () => {
|
||||
console.log(`[*] ${this.name} 初始化连接成功`);
|
||||
this.hb = this.heartbeat();
|
||||
};
|
||||
this.onmessage = onmessage;
|
||||
this.ws.onmessage = onmessage;
|
||||
this.ws.onerror = (err) => {
|
||||
console.log(`[*] ${this.name} 连接错误`, err);
|
||||
this.tryReconnect();
|
||||
};
|
||||
this.ws.onclose = (e) => {
|
||||
console.log(`[*] ${this.name} 连接关闭`);
|
||||
};
|
||||
}
|
||||
|
||||
heartbeat() {
|
||||
if (this.hb) clearInterval(this.hb);
|
||||
return setInterval(() => {
|
||||
console.log(`${this.name} ping...`);
|
||||
if (this.ws.readyState == WebSocket.OPEN) {
|
||||
this.ws.send("ping");
|
||||
} else {
|
||||
clearInterval(this.hb);
|
||||
this.tryReconnect();
|
||||
}
|
||||
}, this.heartbeatDelay);
|
||||
}
|
||||
|
||||
tryReconnect() {
|
||||
console.log(`[*] ${this.name} 重连中,已尝试:`, this.reconnectCount, "次");
|
||||
setTimeout(
|
||||
() => {
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
this.reconnectCount = 0;
|
||||
console.log(`[*] ${this.name} 已恢复连接,取消重连`);
|
||||
return;
|
||||
}
|
||||
this.reconnectCount++;
|
||||
this.ws = new WebSocket(this.url);
|
||||
this.ws.onopen = () => {
|
||||
console.log(`[*] ${this.name} 重连成功`);
|
||||
this.reconnectCount = 0;
|
||||
this.hb = this.heartbeat();
|
||||
};
|
||||
this.ws.onmessage = this.onmessage;
|
||||
this.ws.onerror = (err) => {
|
||||
console.log(`[*] ${this.name} 重连出错`);
|
||||
this.tryReconnect();
|
||||
};
|
||||
this.ws.onclose = (e) => {
|
||||
console.log(`[*] ${this.name} 重连连接关闭`);
|
||||
};
|
||||
},
|
||||
this.reconnectCount == 0 ? 0 : this.timeout
|
||||
);
|
||||
}
|
||||
|
||||
logStatus() {
|
||||
console.log(
|
||||
`[*] ${this.name} 重连状态: 连接中`,
|
||||
this.ws.readyState == WebSocket.CONNECTING
|
||||
);
|
||||
console.log(
|
||||
`[*] ${this.name} 重连状态: 已连接`,
|
||||
this.ws.readyState == WebSocket.OPEN
|
||||
);
|
||||
console.log(
|
||||
`[*] ${this.name} 重连状态: 关闭中`,
|
||||
this.ws.readyState == WebSocket.CLOSING
|
||||
);
|
||||
console.log(
|
||||
`[*] ${this.name} 重连状态: 关闭`,
|
||||
this.ws.readyState == WebSocket.CLOSED
|
||||
);
|
||||
}
|
||||
}
|
7
vite.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
})
|