Browse Source

feat: vite vue3 csr版本

master
wally 4 years ago
parent
commit
32b693b2c8
  1. 1
      alias.config.js
  2. 2
      index.html
  3. 32
      package-lock.json
  4. 1
      package.json
  5. 55
      src/components/Center/Left.vue
  6. 52
      src/components/Center/Middle.vue
  7. 64
      src/components/Center/Right.vue
  8. 49
      src/components/Center/YieldChart.vue
  9. 37
      src/components/Common/Address.vue
  10. 57
      src/components/Common/ComplexChart.vue
  11. 83
      src/components/Common/FaultChart.vue
  12. 46
      src/components/Common/Left.vue
  13. 29
      src/components/Common/Map.vue
  14. 25
      src/components/Common/MapContainer.vue
  15. 52
      src/components/Common/Modal.vue
  16. 34
      src/components/Common/Monitor.vue
  17. 56
      src/components/Farm/Header.vue
  18. 86
      src/components/Farm/Humidity.vue
  19. 72
      src/components/Farm/Left.vue
  20. 52
      src/components/Farm/Middle.vue
  21. 71
      src/components/Farm/News.vue
  22. 53
      src/components/Farm/Right.vue
  23. 81
      src/components/Farm/SoilHumidity.vue
  24. 83
      src/components/Farm/Temperature.vue
  25. 49
      src/components/Farm/YieldChart.vue
  26. 14
      src/config/layout/dataFarmBody.js
  27. 290
      src/mock/datas.js
  28. 6
      src/store/index.js
  29. 1
      src/utils/map.js
  30. 29
      src/views/Center.vue
  31. 35
      src/views/Farm.vue
  32. 1
      vite.config.js
  33. 17
      yarn.lock

1
alias.config.js

@ -13,6 +13,7 @@ module.exports = {
utils: resolve('src/utils'),
store: resolve('src/store'),
apis: resolve('src/apis'),
config: resolve('src/config'),
},
},
};

2
index.html

@ -10,8 +10,6 @@
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts-gl/dist/echarts-gl.min.js"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>

32
package-lock.json

@ -12,6 +12,7 @@
"axios": "^0.23.0",
"dayjs": "^1.10.7",
"echarts": "^5.2.2",
"echarts-gl": "^2.0.8",
"element-plus": "^1.1.0-beta.24",
"lodash": "^4.17.21",
"vite": "^2.6.4",
@ -3528,6 +3529,11 @@
"fsevents": "~2.3.2"
}
},
"node_modules/claygl": {
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/claygl/download/claygl-1.3.0.tgz",
"integrity": "sha1-em4pAyEFGaw1iEj114Bw7SEWhfM="
},
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.nlark.com/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1621915070206&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz",
@ -4272,6 +4278,18 @@
"zrender": "5.2.1"
}
},
"node_modules/echarts-gl": {
"version": "2.0.8",
"resolved": "https://registry.nlark.com/echarts-gl/download/echarts-gl-2.0.8.tgz",
"integrity": "sha1-gSYL4IkeXjDBcQMR+Ldk1lMpsDw=",
"dependencies": {
"claygl": "^1.2.1",
"zrender": "^5.1.1"
},
"peerDependencies": {
"echarts": "^5.1.2"
}
},
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.nlark.com/tslib/download/tslib-2.3.0.tgz",
@ -11772,6 +11790,11 @@
"readdirp": "~3.6.0"
}
},
"claygl": {
"version": "1.3.0",
"resolved": "https://registry.npm.taobao.org/claygl/download/claygl-1.3.0.tgz",
"integrity": "sha1-em4pAyEFGaw1iEj114Bw7SEWhfM="
},
"clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.nlark.com/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1621915070206&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz",
@ -12381,6 +12404,15 @@
}
}
},
"echarts-gl": {
"version": "2.0.8",
"resolved": "https://registry.nlark.com/echarts-gl/download/echarts-gl-2.0.8.tgz",
"integrity": "sha1-gSYL4IkeXjDBcQMR+Ldk1lMpsDw=",
"requires": {
"claygl": "^1.2.1",
"zrender": "^5.1.1"
}
},
"ejs": {
"version": "3.1.6",
"resolved": "https://registry.npmmirror.com/ejs/download/ejs-3.1.6.tgz",

1
package.json

@ -18,6 +18,7 @@
"axios": "^0.23.0",
"dayjs": "^1.10.7",
"echarts": "^5.2.2",
"echarts-gl": "^2.0.8",
"element-plus": "^1.1.0-beta.24",
"lodash": "^4.17.21",
"vite": "^2.6.4",

55
src/components/Center/Left.vue

@ -0,0 +1,55 @@
<!--suppress ES6UnusedImports -->
<template>
<div :style="{ width: body.left.width }">
<div
class="item m-t"
:style="{
width: body.left.data[0].width,
height: body.left.data[0].height,
'background-image': `url(${body.left.data[0].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.left.data[0]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterNews></DataCenterNews>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.left.data[1].width,
height: body.left.data[1].height,
'background-image': `url(${body.left.data[1].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.left.data[1]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterTall></DataCenterTall>
</div>
</div>
</div>
</template>
<script setup>
/* eslint-disable no-unused-vars */
import DataCenterTitle from 'components/Common/Title.vue';
import DataCenterNews from 'components/Center/News.vue';
import DataCenterTall from 'components/Common/Tall.vue';
import useLayoutConfig from '@/hooks/useLayoutConfig';
const body = useLayoutConfig();
</script>
<style scoped>
.item {
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
}
</style>

52
src/components/Center/Middle.vue

@ -0,0 +1,52 @@
<template>
<div :style="{ width: body.middle.width }">
<div
class="item m-t"
:style="{
width: body.middle.data[0].width,
height: body.middle.data[0].height,
'background-image': `url(${body.middle.data[0].background.image})`,
}"
>
<!-- 标题-->
<DataCenterTitle :item="body.middle.data[0]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterMapContainer></DataCenterMapContainer>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.middle.data[1].width,
height: body.middle.data[1].height,
'background-image': `url(${body.middle.data[1].background.image})`,
}"
>
<!-- 标题-->
<DataCenterTitle :item="body.middle.data[1]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterComplexChart></DataCenterComplexChart>
</div>
</div>
</div>
</template>
<script setup>
import DataCenterTitle from 'components/Common/Title.vue';
import DataCenterMapContainer from 'components/Common/MapContainer.vue';
import DataCenterComplexChart from 'components/Common/ComplexChart.vue';
import { body } from '@/config/layout/dataCenterBody';
</script>
<style scoped>
.item {
display: flex;
flex-direction: column;
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
}
</style>

64
src/components/Center/Right.vue

@ -0,0 +1,64 @@
<template>
<div :style="{ width: body.right.width }">
<div
class="item m-t"
:style="{
width: body.right.data[0].width,
height: body.right.data[0].height,
'background-image': `url(${body.right.data[0].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.right.data[0]"></DataCenterTitle>
</div>
<div
class="item m-t"
:style="{
width: body.right.data[1].width,
height: body.right.data[1].height,
'background-image': `url(${body.right.data[1].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.right.data[1]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterYieldChart></DataCenterYieldChart>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.right.data[2].width,
height: body.right.data[2].height,
'background-image': `url(${body.right.data[2].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.right.data[2]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterFaultChart></DataCenterFaultChart>
</div>
</div>
</div>
</template>
<script setup>
import DataCenterTitle from 'components/Common/Title.vue';
import DataCenterYieldChart from 'components/Center/YieldChart.vue';
import DataCenterFaultChart from 'components/Common/FaultChart.vue';
import useLayoutConfig from '@/hooks/useLayoutConfig';
const body = useLayoutConfig();
</script>
<style scoped>
.item {
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
}
</style>

49
src/components/Center/YieldChart.vue

@ -0,0 +1,49 @@
<template>
<div id="yield-chart"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import * as echarts from 'echarts';
onMounted(() => {
const chartDom = document.getElementById('yield-chart');
const myChart = echarts.init(chartDom);
const option = initOptions();
myChart.setOption(option);
});
function initOptions() {
return {
darkMode: true,
grid: {
top: 20,
bottom: 20,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2017', '2018', '2019', '2020', '2021'],
axisLabel: { color: '#fff' },
},
yAxis: {
type: 'value',
axisLabel: { color: '#fff' },
},
series: [
{
data: [224, 218, 135, 147, 260],
type: 'line',
areaStyle: {},
},
],
};
}
</script>
<style scoped>
#yield-chart {
width: 100%;
height: 100%;
}
</style>

37
src/components/Common/Address.vue

@ -0,0 +1,37 @@
<template>
<div class="address-container">
<img src="../../assets/icon-location.png" alt="" />
我的位置山西省 > 太原市 > {{ address }}
</div>
</template>
<script setup>
import { inject, computed } from 'vue';
const scene = inject('scene');
const address = computed(() => {
if (scene === 'farm') {
return '大井生态园';
}
return '山西省农科院';
});
</script>
<style scoped>
.address-container {
position: absolute;
left: 0rem;
top: 0rem;
box-shadow: 0 0 9rem #00d9ff inset;
padding: 8rem 16rem;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 14rem;
}
.address-container img {
margin-right: 10rem;
}
</style>

57
src/components/Common/ComplexChart.vue

@ -0,0 +1,57 @@
<template>
<div id="complex-container"></div>
</template>
<script setup>
import { nextTick } from 'vue';
import * as echarts from 'echarts';
import { generateChartOption } from '@/utils/complexChart';
import datas from '@/mock/datas';
let myChart = null;
let defaultSelectedLegend = {
'室内温度(℃)': true,
'室外温度(℃)': true,
'土壤温度(℃)': false,
'室内湿度(RH%)': true,
'室外湿度(RH%)': true,
'土壤湿度(RH%)': false,
'风速(m/s)': false,
'CO2(%)': false,
'光照(klux)': true,
};
async function getData() {
try {
await nextTick();
initChart(datas);
} catch (error) {
console.error(error);
}
}
//
function initChart(data) {
const chartDom = document.getElementById('complex-container');
myChart = echarts.init(chartDom);
render(data, defaultSelectedLegend);
myChart.on('legendselectchanged', event => {
defaultSelectedLegend = event.selected;
render(data, event.selected);
});
}
function render(data, selected) {
const option = generateChartOption(data, selected);
option && myChart.setOption(option);
}
getData();
</script>
<style scoped>
#complex-container {
height: 100%;
}
</style>

83
src/components/Common/FaultChart.vue

@ -0,0 +1,83 @@
<template>
<div class="container">
<div class="item" v-for="(item, key) in styles" :key="key">
<div
class="count"
:style="{
'background-image': `-webkit-linear-gradient(bottom, ${item.color[0]}, ${item.color[1]})`,
}"
>
{{ data[key] }}
</div>
<div class="title">{{ item.title }}</div>
<img :src="item.image" class="image" />
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const data = ref({
total: 32,
error: 1,
fault: 2,
in: 29,
});
const styles = ref({
total: {
title: '设备总数',
color: ['#08967e', '#08eb94'],
image: 'src/assets/circle-green.png',
},
error: {
title: '设备异常',
color: ['#e0a912', '#fde053'],
image: 'src/assets/circle-yellow.png',
},
fault: {
title: '设备预警',
color: ['#fc4768', '#f8d03f'],
image: 'src/assets/circle-red.png',
},
in: {
title: '接入设备',
color: ['#08dcf4', '#09b4c9'],
image: 'src/assets/circle-blue.png',
},
});
</script>
<style scoped>
.container {
display: flex;
justify-content: space-around;
align-items: center;
padding-top: 40rem;
}
.item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.count {
font-size: 30rem;
font-weight: bold;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.title {
font-size: 18rem;
color: #fff;
font-weight: bold;
margin-bottom: 16rem;
margin-top: 16rem;
}
.image {
width: 90rem;
height: 60rem;
}
</style>

46
src/components/Common/Left.vue

@ -1,46 +0,0 @@
<!--suppress ES6UnusedImports -->
<template>
<div :style="{ width: body.left.width }">
<div
class="item m-t"
:style="{
width: item.width,
height: item.height,
'background-image': `url(${item.background.image})`,
}"
v-for="item in body.left.data"
:key="item.title.text"
>
<!-- 区块标题-->
<DataCenterTitle :item="item"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<component :is="getComponent(item.component)"></component>
<!-- <component :is="DataCenterNews"></component>-->
</div>
</div>
</div>
</template>
<script setup>
/* eslint-disable no-unused-vars */
import DataCenterTitle from 'components/Common/Title.vue';
import useLayoutConfig from '@/hooks/useLayoutConfig';
import DataCenterNews from '@/components/Center/News.vue';
const body = useLayoutConfig();
const getComponent = name => {
return name;
};
</script>
<style scoped>
.item {
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
}
</style>

29
src/components/Common/Map.vue

@ -0,0 +1,29 @@
<template>
<div id="map" class="map"></div>
</template>
<script setup>
import { nextTick, onMounted } from 'vue';
import * as echarts from 'echarts';
import 'echarts-gl';
import ShanXiMap from 'config/map/shanxi';
import { initOptions } from '@/utils/map';
onMounted(async () => {
await nextTick();
const chartDom = document.getElementById('map');
console.log('chartDom: ', chartDom);
const myChart = echarts.init(chartDom);
echarts.registerMap('shanxi', ShanXiMap);
//
myChart.setOption(initOptions());
});
</script>
<style scoped>
.map {
width: 100%;
height: 100%;
}
</style>

25
src/components/Common/MapContainer.vue

@ -0,0 +1,25 @@
<template>
<div class="main-container">
<!-- 地图-->
<CommonMap></CommonMap>
<!-- 监控-->
<CommonMonitor></CommonMonitor>
<!-- 地址-->
<CommonAddress></CommonAddress>
</div>
</template>
<script setup>
import CommonMap from 'components/Common/Map.vue';
import CommonMonitor from 'components/Common/Monitor.vue';
import CommonAddress from 'components/Common/Address.vue';
</script>
<style scoped>
.main-container {
position: relative;
width: 100%;
height: 100%;
}
</style>

52
src/components/Common/Modal.vue

@ -0,0 +1,52 @@
<template>
<iframe id="modal-container" class="modal-container" v-show="modalDisplay" :src="src" frameborder="0" allow="microphone;camera"></iframe>
</template>
<script setup>
import { computed, inject, onMounted } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
const scene = inject('scene');
const src = computed(() => {
if (scene === 'farm') {
return 'https://www.tall.wiki/wl/7/#/farm';
}
return 'https://www.tall.wiki/wl/7/#/center';
});
// const src = 'http://localhost:8080/#/center';
const modalDisplay = computed(() => store.state.modal); // modal
onMounted(() => {
window.addEventListener(
'message',
event => {
// onInvitationReceived
console.log('event: ', event.data);
if (event.data === 'onInvitationReceived') {
store.commit('setModal', true);
}
console.log('event origin: ', event.source.origin);
},
false,
);
});
</script>
<style scoped>
.modal-container {
z-index: 9999;
position: absolute;
left: 50%;
top: 50%;
width: 676rem;
height: 510rem;
transform: translate3d(-50%, -50%, 0);
background: transparent;
/*background: url(assets/modal-bg.png) no-repeat center center;*/
/*background-size: 100%;*/
}
</style>

34
src/components/Common/Monitor.vue

@ -0,0 +1,34 @@
<template>
<div class="frame-container" v-show="monitorDisplay">
<iframe src="https://www.tall.wiki/kangfu/v1/?key=230659446" frameborder="0"></iframe>
</div>
</template>
<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
const monitorDisplay = computed(() => store.state.monitor);
</script>
<style scoped>
.frame-container {
position: absolute;
right: 0;
bottom: 0;
width: 275rem;
height: 200rem;
box-sizing: content-box;
background: url('@/assets/border-s-2.png') no-repeat center center;
background-size: 100%;
padding: 5rem;
overflow: hidden;
}
iframe {
display: block;
width: 100%;
height: 100%;
}
</style>

56
src/components/Farm/Header.vue

@ -0,0 +1,56 @@
<template>
<header :class="{ 'bg-center': scene === 'center', 'bg-farm': scene === 'farm' }">
<!-- 时间-->
<PageTime></PageTime>
<!-- 按钮组-->
<PageButtons @click-btn="onClickBtn"></PageButtons>
<CommonWeather></CommonWeather>
</header>
</template>
<script setup>
import PageTime from 'components/Common/Time.vue';
import PageButtons from 'components/Common/Buttons.vue';
import CommonWeather from 'components/Common/Weather.vue';
import { computed, inject } from 'vue';
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
const store = useStore();
const scene = inject('scene');
const modalDisplay = computed(() => store.state.modal); // modal
const router = useRouter();
function onClickBtn({ index: btnIndex }) {
if (btnIndex === 0) {
store.commit('setModal', !modalDisplay.value);
} else if (btnIndex === 2) {
// monitorDisplay.value = !monitorDisplay.value;
if (scene === 'farm') {
// /
router.push('/farm');
} else {
// /farm
router.push('/farm/farm');
}
}
}
</script>
<style scoped>
.bg-center {
position: relative;
height: 115rem;
background: url('@/assets/top.png') no-repeat center;
background-size: 100% 114rem;
}
.bg-farm {
position: relative;
height: 115rem;
background: url('@/assets/farm-top.png') no-repeat center;
background-size: 100% 114rem;
}
</style>

86
src/components/Farm/Humidity.vue

@ -0,0 +1,86 @@
<template>
<div id="humidity-container"></div>
</template>
<script setup>
import { nextTick } from 'vue';
import * as echarts from 'echarts';
import datas from '@/mock/datas';
async function getData() {
try {
await nextTick();
initChart(datas);
} catch (error) {
console.error(error);
}
}
getData();
//
function initChart(data) {
const chartDom = document.getElementById('humidity-container');
const option = initOption(data);
const myChart = echarts.init(chartDom);
myChart.setOption(option);
}
function initData(data) {
console.log('data1: ', data);
const result = { times: [], roomH: [], outH: [] };
data.forEach(item => {
result.times.push(item.time);
result.roomH.push(item.roomH);
result.outH.push(item.outH);
});
return result;
}
function initOption(data) {
const { time, roomH, outH } = initData(data);
return {
tooltip: { trigger: 'axis' },
grid: {
left: 5,
right: 5,
top: 30,
bottom: 30,
},
darkMode: true,
legend: { show: true, textStyle: { color: '#fff' } },
xAxis: {
type: 'category',
boundaryGap: false,
data: time,
axisTick: { alignWithLabel: true },
axisLabel: { color: '#fff' },
},
yAxis: {
type: 'value',
axisLabel: { formatter: '{value} °C' },
},
series: [
{
name: '室内湿度',
type: 'line',
data: roomH,
smooth: true,
},
{
name: '室外湿度',
type: 'line',
data: outH,
smooth: true,
},
],
};
}
</script>
<style scoped>
#humidity-container {
width: 100%;
height: 100%;
}
</style>

72
src/components/Farm/Left.vue

@ -0,0 +1,72 @@
<!--suppress ES6UnusedImports -->
<template>
<div :style="{ width: body.left.width }">
<div
class="item m-t"
:style="{
width: body.left.data[0].width,
height: body.left.data[0].height,
'background-image': `url(${body.left.data[0].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.left.data[0]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataFarmTemperature></DataFarmTemperature>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.left.data[1].width,
height: body.left.data[1].height,
'background-image': `url(${body.left.data[1].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.left.data[1]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataFarmHumidity></DataFarmHumidity>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.left.data[2].width,
height: body.left.data[2].height,
'background-image': `url(${body.left.data[2].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.left.data[2]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataFarmSoilHumidity></DataFarmSoilHumidity>
</div>
</div>
</div>
</template>
<script setup>
/* eslint-disable no-unused-vars */
import DataCenterTitle from 'components/Common/Title.vue';
import DataFarmTemperature from 'components/Farm/Temperature.vue';
import DataFarmHumidity from 'components/Farm/Humidity.vue';
import DataFarmSoilHumidity from 'components/Farm/SoilHumidity.vue';
import useLayoutConfig from '@/hooks/useLayoutConfig';
const body = useLayoutConfig();
console.log(body);
</script>
<style scoped>
.item {
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
}
</style>

52
src/components/Farm/Middle.vue

@ -0,0 +1,52 @@
<template>
<div :style="{ width: body.middle.width }">
<div
class="item m-t"
:style="{
width: body.middle.data[0].width,
height: body.middle.data[0].height,
'background-image': `url(${body.middle.data[0].background.image})`,
}"
>
<!-- 标题-->
<DataCenterTitle :item="body.middle.data[0]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterMapContainer></DataCenterMapContainer>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.middle.data[1].width,
height: body.middle.data[1].height,
'background-image': `url(${body.middle.data[1].background.image})`,
}"
>
<!-- 标题-->
<DataCenterTitle :item="body.middle.data[1]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterComplexChart></DataCenterComplexChart>
</div>
</div>
</div>
</template>
<script setup>
import DataCenterTitle from 'components/Common/Title.vue';
import DataCenterMapContainer from 'components/Common/MapContainer.vue';
import DataCenterComplexChart from 'components/Common/ComplexChart.vue';
import { body } from '@/config/layout/dataCenterBody';
</script>
<style scoped>
.item {
display: flex;
flex-direction: column;
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
}
</style>

71
src/components/Farm/News.vue

@ -0,0 +1,71 @@
<template>
<div style="height: 100%; overflow: hidden">
<ul class="list" :style="{ transform: `translate3d(0, ${translateY}px, 0)` }">
<li class="list-item" v-for="item in news" :key="item.title">
<div class="title">{{ item.title }}</div>
<div class="date">{{ item.date }}</div>
</li>
</ul>
</div>
</template>
<script setup>
import { ref, nextTick } from 'vue';
import newsData from '@/mock/news';
import useScrollList from '@/hooks/useScrollList';
const news = ref([]);
const { translateY, scrollList } = useScrollList();
//
async function getData() {
try {
news.value = newsData;
await nextTick();
const li = document.querySelector('.list-item');
const ul = document.querySelector('.list');
const liHeight = li.offsetHeight;
const ulHeight = liHeight * news.value.length - ul.parentElement.offsetHeight;
scrollList(liHeight, ulHeight); //
} catch (error) {
console.error(error);
}
}
getData();
</script>
<style scoped>
.list {
padding-left: 0;
list-style: disc inside;
transition: transform 300ms ease;
}
.list-item {
display: flex;
align-items: center;
padding: 10rem 0 10rem;
}
.list-item:before {
content: '';
width: 10rem;
height: 10rem;
background-color: #01fffd;
border-radius: 50%;
}
.list-item .title {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 16rem;
color: #fff;
padding-left: 10rem;
padding-right: 40rem;
}
.list-item .date {
color: #ccc;
font-size: 14rem;
}
</style>

53
src/components/Farm/Right.vue

@ -0,0 +1,53 @@
<template>
<div :style="{ width: body.right.width }">
<div
class="item m-t"
:style="{
width: body.right.data[0].width,
height: body.right.data[0].height,
'background-image': `url(${body.right.data[0].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.right.data[0]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterTall></DataCenterTall>
</div>
</div>
<div
class="item m-t"
:style="{
width: body.right.data[1].width,
height: body.right.data[1].height,
'background-image': `url(${body.right.data[1].background.image})`,
}"
>
<!-- 区块标题-->
<DataCenterTitle :item="body.right.data[1]"></DataCenterTitle>
<div class="p-16 flex-1 overflow-hidden">
<DataCenterFaultChart></DataCenterFaultChart>
</div>
</div>
</div>
</template>
<script setup>
import DataCenterTitle from 'components/Common/Title.vue';
import DataCenterTall from 'components/Common/Tall.vue';
import DataCenterFaultChart from 'components/Common/FaultChart.vue';
import useLayoutConfig from '@/hooks/useLayoutConfig';
const body = useLayoutConfig();
</script>
<style scoped>
.item {
background-position: left top;
background-size: 100% 100%;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
}
</style>

81
src/components/Farm/SoilHumidity.vue

@ -0,0 +1,81 @@
<template>
<div id="soil-humidity-container"></div>
</template>
<script setup>
import { nextTick } from 'vue';
import * as echarts from 'echarts';
import datas from '@/mock/datas';
async function getData() {
try {
await nextTick();
initChart(datas);
} catch (error) {
console.error(error);
}
}
getData();
//
function initChart(data) {
const chartDom = document.getElementById('soil-humidity-container');
const option = initOption(data);
const myChart = echarts.init(chartDom);
myChart.setOption(option);
}
function initData(data) {
const result = { times: [], soilH: [] };
data.forEach(item => {
result.times.push(item.time);
result.soilH.push(item.soilH);
});
return result;
}
function initOption(data) {
const { time, soilH } = initData(data);
return {
tooltip: { trigger: 'axis' },
grid: {
left: 5,
right: 5,
top: 30,
bottom: 30,
},
darkMode: true,
legend: { show: true, textStyle: { color: '#fff' } },
xAxis: {
type: 'category',
boundaryGap: false,
data: time,
axisTick: { alignWithLabel: true },
axisLabel: { color: '#fff' },
},
yAxis: {
type: 'value',
axisLabel: { formatter: '{value} °C' },
},
visualMap: {
show: false,
inRange: { color: ['#65B581', '#FFCE34', '#FD665F'] },
},
series: [
{
name: '土壤湿度',
type: 'bar',
data: soilH,
},
],
};
}
</script>
<style scoped>
#soil-humidity-container {
width: 100%;
height: 100%;
}
</style>

83
src/components/Farm/Temperature.vue

@ -0,0 +1,83 @@
<template>
<div id="temperature-container"></div>
</template>
<script setup>
import { nextTick } from 'vue';
import * as echarts from 'echarts';
import datas from '@/mock/datas';
async function getData() {
try {
await nextTick();
initChart(datas);
} catch (error) {
console.error(error);
}
}
getData();
//
function initChart(data) {
const chartDom = document.getElementById('temperature-container');
const option = initOption(data);
const myChart = echarts.init(chartDom);
myChart.setOption(option);
}
function initData(data) {
const result = { times: [], roomT: [], outT: [] };
data.forEach(item => {
result.times.push(item.time);
result.roomT.push(item.roomT);
result.outT.push(item.outT);
});
return result;
}
function initOption(data) {
const { time, roomT, outT } = initData(data);
return {
tooltip: { trigger: 'axis' },
grid: {
left: 5,
right: 5,
top: 30,
bottom: 30,
},
darkMode: true,
legend: { show: true, textStyle: { color: '#fff' } },
xAxis: {
type: 'category',
boundaryGap: false,
data: time,
axisTick: { alignWithLabel: true },
axisLabel: { color: '#fff' },
},
yAxis: {
type: 'value',
axisLabel: { formatter: '{value} °C' },
},
series: [
{
name: '室内温度',
type: 'line',
data: roomT,
},
{
name: '室外温度',
type: 'line',
data: outT,
},
],
};
}
</script>
<style scoped>
#temperature-container {
width: 100%;
height: 100%;
}
</style>

49
src/components/Farm/YieldChart.vue

@ -0,0 +1,49 @@
<template>
<div id="yield-chart"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import * as echarts from 'echarts';
onMounted(() => {
const chartDom = document.getElementById('yield-chart');
const myChart = echarts.init(chartDom);
const option = initOptions();
myChart.setOption(option);
});
function initOptions() {
return {
darkMode: true,
grid: {
top: 20,
bottom: 20,
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['2017', '2018', '2019', '2020', '2021'],
axisLabel: { color: '#fff' },
},
yAxis: {
type: 'value',
axisLabel: { color: '#fff' },
},
series: [
{
data: [224, 218, 135, 147, 260],
type: 'line',
areaStyle: {},
},
],
};
}
</script>
<style scoped>
#yield-chart {
width: 100%;
height: 100%;
}
</style>

14
src/config/layout/dataFarmBody.js

@ -6,7 +6,7 @@ export const body = {
{
width: '480rem',
height: '308rem',
background: { image: 'assets/border-1.png' },
background: { image: 'src/assets/border-1.png' },
title: {
text: '室内/外温度折线',
color: '#fff',
@ -19,7 +19,7 @@ export const body = {
{
width: '480rem',
height: '308rem',
background: { image: 'assets/border-1.png' },
background: { image: 'src/assets/border-1.png' },
title: {
text: '室内/外湿度折线',
color: '#fff',
@ -32,7 +32,7 @@ export const body = {
{
width: '480rem',
height: '308rem',
background: { image: 'assets/border-1.png' },
background: { image: 'src/assets/border-1.png' },
title: {
text: '土壤湿度',
color: '#fff',
@ -50,7 +50,7 @@ export const body = {
{
width: '920rem',
height: '626rem',
background: { image: 'assets/border-main.png' },
background: { image: 'src/assets/border-main.png' },
title: {
hide: true,
text: '3D地图',
@ -60,7 +60,7 @@ export const body = {
{
width: '920rem',
height: '300rem',
background: { image: 'assets/border-3.png' },
background: { image: 'src/assets/border-3.png' },
title: {
text: '综合曲线',
color: '#fff',
@ -78,7 +78,7 @@ export const body = {
{
width: '480rem',
height: '618rem',
background: { image: 'assets/border-2.png' },
background: { image: 'src/assets/border-2.png' },
title: {
text: '时物链',
color: '#fff',
@ -91,7 +91,7 @@ export const body = {
{
width: '480rem',
height: '300rem',
background: { image: 'assets/border-1.png' },
background: { image: 'src/assets/border-1.png' },
title: {
text: '实时报警',
color: '#fff',

290
src/mock/datas.js

@ -0,0 +1,290 @@
export default [
{
time: '00:00',
roomT: 19,
roomH: 60,
outT: '-5',
outH: 60,
soilT: 6,
soilH: 40,
windSpeed: 0,
co2: '0.01 ',
light: 3,
},
{
time: '01:00',
roomT: 19,
roomH: 70,
outT: '-6',
outH: 70,
soilT: 7,
soilH: 50,
windSpeed: 2,
co2: '0.02 ',
light: 2,
},
{
time: '02:00',
roomT: 19,
roomH: 80,
outT: '-7',
outH: 80,
soilT: 7,
soilH: 60,
windSpeed: 3,
co2: '0.03 ',
light: 1,
},
{
time: '03:00',
roomT: 19,
roomH: 90,
outT: '-8',
outH: 90,
soilT: 7,
soilH: 70,
windSpeed: 7,
co2: '0.04 ',
light: 1,
},
{
time: '04:00',
roomT: 18,
roomH: 100,
outT: '-9',
outH: 100,
soilT: 5,
soilH: 80,
windSpeed: 9,
co2: '0.05 ',
light: 4,
},
{
time: '05:00',
roomT: 18,
roomH: 95,
outT: '-10',
outH: 95,
soilT: 5,
soilH: 75,
windSpeed: 14,
co2: '0.06 ',
light: 8,
},
{
time: '06:00',
roomT: 19,
roomH: 90,
outT: '-5',
outH: 90,
soilT: 7,
soilH: 70,
windSpeed: 12,
co2: '0.07 ',
light: 10,
},
{
time: '07:00',
roomT: 19,
roomH: 85,
outT: '-1',
outH: 85,
soilT: 7,
soilH: 65,
windSpeed: 15,
co2: '0.08 ',
light: 20,
},
{
time: '08:00',
roomT: 20,
roomH: 80,
outT: 0,
outH: 80,
soilT: 10,
soilH: 60,
windSpeed: 13,
co2: '0.09 ',
light: 26,
},
{
time: '09:00',
roomT: 20,
roomH: 75,
outT: 1,
outH: 75,
soilT: 12,
soilH: 55,
windSpeed: 14,
co2: '0.09 ',
light: 35,
},
{
time: '10:00',
roomT: 21,
roomH: 70,
outT: 2,
outH: 70,
soilT: 14,
soilH: 50,
windSpeed: 9,
co2: '0.12 ',
light: 45,
},
{
time: '11:00',
roomT: 21,
roomH: 65,
outT: 3,
outH: 65,
soilT: 16,
soilH: 45,
windSpeed: 5,
co2: '0.14 ',
light: 50,
},
{
time: '12:00',
roomT: 23,
roomH: 60,
outT: 4,
outH: 60,
soilT: 19,
soilH: 40,
windSpeed: 8,
co2: '0.16 ',
light: 55,
},
{
time: '13:00',
roomT: 24,
roomH: 55,
outT: 5,
outH: 55,
soilT: 22,
soilH: 35,
windSpeed: 7,
co2: '0.18 ',
light: 65,
},
{
time: '14:00',
roomT: 28,
roomH: 50,
outT: 6,
outH: 50,
soilT: 23,
soilH: 30,
windSpeed: 6,
co2: '0.20 ',
light: 80,
},
{
time: '15:00',
roomT: 28,
roomH: 45,
outT: 6,
outH: 45,
soilT: 23,
soilH: 25,
windSpeed: 4,
co2: '0.19 ',
light: 70,
},
{
time: '16:00',
roomT: 26,
roomH: 40,
outT: 7,
outH: 40,
soilT: 20,
soilH: 20,
windSpeed: 11,
co2: '0.18 ',
light: 65,
},
{
time: '17:00',
roomT: 25,
roomH: 45,
outT: 5,
outH: 45,
soilT: 17,
soilH: 25,
windSpeed: 8,
co2: '0.17 ',
light: 55,
},
{
time: '18:00',
roomT: 24,
roomH: 50,
outT: 5,
outH: 50,
soilT: 14,
soilH: 30,
windSpeed: 5,
co2: '0.16 ',
light: 40,
},
{
time: '19:00',
roomT: 23,
roomH: 55,
outT: 1,
outH: 55,
soilT: 11,
soilH: 35,
windSpeed: 1,
co2: '0.15 ',
light: 35,
},
{
time: '20:00',
roomT: 22,
roomH: 60,
outT: 0,
outH: 60,
soilT: 8,
soilH: 40,
windSpeed: 5,
co2: '0.14 ',
light: 25,
},
{
time: '21:00',
roomT: 21,
roomH: 65,
outT: 0,
outH: 65,
soilT: 7,
soilH: 45,
windSpeed: 4,
co2: '0.13 ',
light: 6,
},
{
time: '22:00',
roomT: 20,
roomH: 70,
outT: '-3',
outH: 70,
soilT: 6,
soilH: 50,
windSpeed: 6,
co2: '0.12 ',
light: 5,
},
{
time: '23:00',
roomT: 20,
roomH: 75,
outT: '-4',
outH: 75,
soilT: 5,
soilH: 55,
windSpeed: 7,
co2: '0.11 ',
light: 4,
},
];

6
src/store/index.js

@ -1,7 +1,7 @@
import { createStore } from 'vuex';
export default createStore({
state: { modal: false },
state: { modal: false, monitor: true },
getters: {},
mutations: {
/**
@ -12,6 +12,10 @@ export default createStore({
setModal(state, display) {
state.modal = display;
},
setMonitor(state, display) {
state.monitor = display;
},
},
actions: {},
});

1
src/utils/map.js

@ -1,4 +1,5 @@
/* eslint-disable */
import * as echarts from 'echarts';
import ShanXiMap from 'config/map/shanxi';
import { values as ShanXiValues } from 'config/map/values';

29
src/views/Center.vue

@ -1,13 +1,34 @@
<template>
<PageHeader></PageHeader>
<PageLeft></PageLeft>
<div class="container">
<PageLeft></PageLeft>
<PageMiddle></PageMiddle>
<PageRight></PageRight>
</div>
<PageFooter></PageFooter>
<PageModal></PageModal>
</template>
<script setup>
import PageHeader from 'components/Center/Header.vue';
import { provide } from 'vue';
import PageModal from 'components/Common/Modal.vue';
import PageFooter from 'components/Common/Footer.vue';
import PageLeft from 'components/Common/Left.vue';
import PageLeft from 'components/Center/Left.vue';
import PageRight from 'components/Center/Right.vue';
import PageMiddle from 'components/Center/Middle.vue';
import PageHeader from 'components/Center/Header.vue';
provide('scene', 'center');
</script>
<style scoped></style>
<style scoped>
.container {
padding: 0 10rem;
margin-top: -10rem;
display: flex;
justify-content: space-between;
}
</style>

35
src/views/Farm.vue

@ -1,7 +1,34 @@
<template>farm</template>
<template>
<PageHeader></PageHeader>
<script>
export default { name: 'Farm' };
<div class="container">
<PageLeft></PageLeft>
<PageMiddle></PageMiddle>
<PageRight></PageRight>
</div>
<PageFooter></PageFooter>
<PageModal></PageModal>
</template>
<script setup>
import { provide } from 'vue';
import PageModal from 'components/Common/Modal.vue';
import PageFooter from 'components/Common/Footer.vue';
import PageLeft from 'components/Farm/Left.vue';
import PageRight from 'components/Farm/Right.vue';
import PageMiddle from 'components/Farm/Middle.vue';
import PageHeader from 'components/Farm/Header.vue';
provide('scene', 'farm');
</script>
<style scoped></style>
<style scoped>
.container {
padding: 0 10rem;
margin-top: -10rem;
display: flex;
justify-content: space-between;
}
</style>

1
vite.config.js

@ -20,6 +20,7 @@ export default defineConfig({
utils: resolve('src/utils'),
store: resolve('src/store'),
apis: resolve('src/apis'),
config: resolve('src/config'),
},
},
build: {

17
yarn.lock

@ -1752,6 +1752,11 @@
optionalDependencies:
"fsevents" "~2.3.2"
"claygl@^1.2.1":
"integrity" "sha1-em4pAyEFGaw1iEj114Bw7SEWhfM="
"resolved" "https://registry.npm.taobao.org/claygl/download/claygl-1.3.0.tgz"
"version" "1.3.0"
"clean-stack@^2.0.0":
"integrity" "sha1-7oRy27Ep5yezHooQpCfe6d/kAIs="
"resolved" "https://registry.nlark.com/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1621915070206&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz"
@ -2110,7 +2115,15 @@
dependencies:
"is-obj" "^2.0.0"
"echarts@^5.2.2":
"echarts-gl@^2.0.8":
"integrity" "sha1-gSYL4IkeXjDBcQMR+Ldk1lMpsDw="
"resolved" "https://registry.nlark.com/echarts-gl/download/echarts-gl-2.0.8.tgz"
"version" "2.0.8"
dependencies:
"claygl" "^1.2.1"
"zrender" "^5.1.1"
"echarts@^5.1.2", "echarts@^5.2.2":
"integrity" "sha1-7DyLKhUcu6cbo8LHz5svIEfOQ3A="
"resolved" "https://registry.npmmirror.com/echarts/download/echarts-5.2.2.tgz"
"version" "5.2.2"
@ -5111,7 +5124,7 @@
"resolved" "https://registry.nlark.com/yocto-queue/download/yocto-queue-0.1.0.tgz"
"version" "0.1.0"
"zrender@5.2.1":
"zrender@^5.1.1", "zrender@5.2.1":
"integrity" "sha1-X0u9qRW6bUErCxncJDG+qtBUF7s="
"resolved" "https://registry.nlark.com/zrender/download/zrender-5.2.1.tgz"
"version" "5.2.1"

Loading…
Cancel
Save