21 changed files with 619 additions and 71 deletions
After Width: | Height: | Size: 75 KiB |
@ -0,0 +1,56 @@ |
|||
<template> |
|||
<div class="weather-container" v-if="weather"> |
|||
今日天气 |
|||
<i :class="[`qi-${weather.icon}`, 'icon']"></i> |
|||
<span class="text">{{ weather.text }}</span> |
|||
<span class="temp">{{ weather.temp }}℃</span> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue'; |
|||
|
|||
const weather = ref(null); |
|||
async function getData() { |
|||
try { |
|||
const { data: rawData } = await useFetch('/api/weather'); |
|||
const { code, now } = rawData.value.data; |
|||
if (+code !== 200) { |
|||
throw new Error(code); |
|||
} else { |
|||
weather.value = now; |
|||
} |
|||
} catch (error) { |
|||
console.error(error); |
|||
} |
|||
} |
|||
|
|||
getData(); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.weather-container { |
|||
position: absolute; |
|||
right: 20rem; |
|||
top: 10rem; |
|||
color: #fff; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
.temp { |
|||
font-size: 25rem; |
|||
color: #fff; |
|||
font-family: impact; |
|||
margin-left: 14rem; |
|||
} |
|||
.text { |
|||
margin-left: 14rem; |
|||
} |
|||
.icon { |
|||
margin-left: 10rem; |
|||
color: #fff100; |
|||
font-size: 26rem; |
|||
font-weight: bolder; |
|||
} |
|||
</style> |
@ -1,5 +0,0 @@ |
|||
<template>1</template> |
|||
|
|||
<script setup></script> |
|||
|
|||
<style scoped></style> |
@ -1,11 +0,0 @@ |
|||
<template> |
|||
<div class="tab-container" v-show="show"></div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue'; |
|||
|
|||
const show = ref(false); |
|||
</script> |
|||
|
|||
<style scoped></style> |
@ -0,0 +1,94 @@ |
|||
<template> |
|||
<div id="humidity-container"></div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { nextTick } from 'vue'; |
|||
|
|||
async function getData() { |
|||
try { |
|||
const { data: rawData } = await useFetch('/api/datas'); |
|||
const { code, msg, data } = rawData.value; |
|||
if (code === 200) { |
|||
await nextTick(); |
|||
initChart(data); |
|||
} else { |
|||
throw new Error(msg); |
|||
} |
|||
} 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> |
@ -0,0 +1,91 @@ |
|||
<template> |
|||
<div id="soil-humidity-container"></div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { nextTick } from 'vue'; |
|||
|
|||
async function getData() { |
|||
try { |
|||
const { data: rawData } = await useFetch('/api/datas'); |
|||
const { code, msg, data } = rawData.value; |
|||
if (code === 200) { |
|||
await nextTick(); |
|||
initChart(data); |
|||
} else { |
|||
throw new Error(msg); |
|||
} |
|||
} 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, 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', |
|||
}, |
|||
}, |
|||
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> |
@ -0,0 +1,92 @@ |
|||
<template> |
|||
<div id="temperature-container"></div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { nextTick } from 'vue'; |
|||
|
|||
async function getData() { |
|||
try { |
|||
const { data: rawData } = await useFetch('/api/datas'); |
|||
const { code, msg, data } = rawData.value; |
|||
if (code === 200) { |
|||
await nextTick(); |
|||
initChart(data); |
|||
} else { |
|||
throw new Error(msg); |
|||
} |
|||
} 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) { |
|||
console.log('data1: ', 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> |
@ -1,32 +1,52 @@ |
|||
<template> |
|||
<header class="page-header"> |
|||
<header |
|||
:class="{ 'bg-center': scene === 'center', 'bg-farm': scene === 'farm' }" |
|||
> |
|||
<!-- 时间--> |
|||
<PageTime></PageTime> |
|||
|
|||
<!-- 按钮组--> |
|||
<PageButtons @click-btn="onClickBtn"></PageButtons> |
|||
|
|||
<CommonWeather></CommonWeather> |
|||
</header> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { inject } from 'vue'; |
|||
import { useRouter } from 'vue-router'; |
|||
|
|||
const scene = inject('scene'); |
|||
const modalDisplay = useModal(); // 是否显示modal |
|||
const monitorDisplay = useMonitor(); // 是否显示video |
|||
const router = useRouter(); |
|||
|
|||
function onClickBtn({ index: btnIndex, item }) { |
|||
console.log('btnIndex: ', btnIndex); |
|||
if (btnIndex === 0) { |
|||
modalDisplay.value = !modalDisplay.value; |
|||
} else if (btnIndex === 2) { |
|||
monitorDisplay.value = !monitorDisplay.value; |
|||
// monitorDisplay.value = !monitorDisplay.value; |
|||
if (scene === 'farm') { |
|||
// 跳转到 / |
|||
router.push('/'); |
|||
} else { |
|||
// 跳转到 /farm |
|||
router.push('/farm'); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.page-header { |
|||
.bg-center { |
|||
position: relative; |
|||
height: 115rem; |
|||
background: url('@/assets/images/top.png') no-repeat center; |
|||
background-size: 100% 114rem; |
|||
} |
|||
.bg-farm { |
|||
position: relative; |
|||
height: 115rem; |
|||
background: url('@/assets/images/farm-top.png') no-repeat center; |
|||
background-size: 100% 114rem; |
|||
} |
|||
</style> |
|||
|
@ -0,0 +1,119 @@ |
|||
export const body = { |
|||
left: { |
|||
width: '480rem', |
|||
data: [ |
|||
{ |
|||
width: '480rem', |
|||
height: '308rem', |
|||
background: { |
|||
image: 'assets/images/border-1.png', |
|||
}, |
|||
title: { |
|||
text: '室内/外温度折线', |
|||
color: '#fff', |
|||
size: '18rem', |
|||
align: 'center', |
|||
height: '40rem', |
|||
}, |
|||
component: 'DataFarmTemperature', |
|||
}, |
|||
{ |
|||
width: '480rem', |
|||
height: '308rem', |
|||
background: { |
|||
image: 'assets/images/border-1.png', |
|||
}, |
|||
title: { |
|||
text: '室内/外湿度折线', |
|||
color: '#fff', |
|||
size: '18rem', |
|||
align: 'center', |
|||
height: '40rem', |
|||
}, |
|||
component: 'DataFarmHumidity', |
|||
}, |
|||
{ |
|||
width: '480rem', |
|||
height: '308rem', |
|||
background: { |
|||
image: 'assets/images/border-1.png', |
|||
}, |
|||
title: { |
|||
text: '土壤湿度', |
|||
color: '#fff', |
|||
size: '18rem', |
|||
align: 'center', |
|||
height: '40rem', |
|||
}, |
|||
component: 'DataFarmSoilHumidity', |
|||
}, |
|||
], |
|||
}, |
|||
middle: { |
|||
width: '920rem', |
|||
data: [ |
|||
{ |
|||
width: '920rem', |
|||
height: '626rem', |
|||
background: { |
|||
image: 'assets/images/border-main.png', |
|||
}, |
|||
title: { |
|||
hide: true, |
|||
text: '3D地图', |
|||
}, |
|||
component: 'DataCenterMapContainer', |
|||
}, |
|||
{ |
|||
width: '920rem', |
|||
height: '300rem', |
|||
background: { |
|||
image: 'assets/images/border-3.png', |
|||
}, |
|||
title: { |
|||
text: '综合曲线', |
|||
color: '#fff', |
|||
size: '18rem', |
|||
align: 'center', |
|||
height: '40rem', |
|||
}, |
|||
component: 'DataCenterComplexChart', |
|||
}, |
|||
], |
|||
}, |
|||
right: { |
|||
width: '480rem', |
|||
data: [ |
|||
{ |
|||
width: '480rem', |
|||
height: '618rem', |
|||
background: { |
|||
image: 'assets/images/border-2.png', |
|||
}, |
|||
title: { |
|||
text: '时物链', |
|||
color: '#fff', |
|||
size: '18rem', |
|||
align: 'center', |
|||
height: '40rem', |
|||
}, |
|||
component: 'DataCenterTall', |
|||
}, |
|||
{ |
|||
width: '480rem', |
|||
height: '300rem', |
|||
background: { |
|||
image: 'assets/images/border-1.png', |
|||
}, |
|||
title: { |
|||
text: '实时报警', |
|||
color: '#fff', |
|||
size: '18rem', |
|||
align: 'center', |
|||
height: '40rem', |
|||
}, |
|||
component: 'DataCenterFaultChart', |
|||
}, |
|||
], |
|||
}, |
|||
}; |
@ -0,0 +1,18 @@ |
|||
import { body as centerBody } from '@/config/layout/dataCenterBody'; |
|||
import { body as farmBody } from '@/config/layout/dataFarmBody'; |
|||
|
|||
import { inject, computed } from 'vue'; |
|||
|
|||
export default function useLayoutConfig() { |
|||
const scene = inject('scene'); |
|||
|
|||
const body = computed(() => { |
|||
if (scene === 'farm') { |
|||
return farmBody; |
|||
} else { |
|||
return centerBody; |
|||
} |
|||
}); |
|||
|
|||
return body; |
|||
} |
@ -0,0 +1,41 @@ |
|||
<template> |
|||
<div class="page"> |
|||
<PageHeader></PageHeader> |
|||
<PageMain></PageMain> |
|||
<PageFooter></PageFooter> |
|||
|
|||
<PageModal></PageModal> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { onMounted, provide } from 'vue'; |
|||
|
|||
provide('scene', 'farm'); |
|||
|
|||
function setRem(html) { |
|||
const winWidth = html.clientWidth; |
|||
html.style.fontSize = winWidth / 1920 + 'px'; |
|||
} |
|||
|
|||
onMounted(() => { |
|||
const html = document.documentElement; |
|||
setRem(html); |
|||
window.addEventListener( |
|||
'resize', |
|||
() => { |
|||
setRem(html); |
|||
}, |
|||
false, |
|||
); |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.page { |
|||
width: 100%; |
|||
height: 100%; |
|||
background: url('@/assets/images/bg.png') no-repeat center center; |
|||
background-size: cover; |
|||
} |
|||
</style> |
@ -0,0 +1,9 @@ |
|||
<template> |
|||
<div></div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
layout: 'farm', |
|||
}; |
|||
</script> |
@ -0,0 +1,10 @@ |
|||
import type { IncomingMessage, ServerResponse } from 'http'; |
|||
import axios from 'axios'; |
|||
|
|||
export default async (req: IncomingMessage, res: ServerResponse) => { |
|||
const { data } = await axios.get( |
|||
'https://devapi.qweather.com/v7/weather/now?key=9764d65c999349a9b42c42a8f1052a81&location=112.48699,37.94036&lang =zh', |
|||
); |
|||
console.log('res: ', data); |
|||
return { code: 200, msg: 'ok', data }; |
|||
}; |
Loading…
Reference in new issue