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> |
<template> |
||||
<header class="page-header"> |
<header |
||||
|
:class="{ 'bg-center': scene === 'center', 'bg-farm': scene === 'farm' }" |
||||
|
> |
||||
<!-- 时间--> |
<!-- 时间--> |
||||
<PageTime></PageTime> |
<PageTime></PageTime> |
||||
|
|
||||
<!-- 按钮组--> |
<!-- 按钮组--> |
||||
<PageButtons @click-btn="onClickBtn"></PageButtons> |
<PageButtons @click-btn="onClickBtn"></PageButtons> |
||||
|
|
||||
|
<CommonWeather></CommonWeather> |
||||
</header> |
</header> |
||||
</template> |
</template> |
||||
|
|
||||
<script setup> |
<script setup> |
||||
|
import { inject } from 'vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
|
||||
|
const scene = inject('scene'); |
||||
const modalDisplay = useModal(); // 是否显示modal |
const modalDisplay = useModal(); // 是否显示modal |
||||
const monitorDisplay = useMonitor(); // 是否显示video |
const router = useRouter(); |
||||
|
|
||||
function onClickBtn({ index: btnIndex, item }) { |
function onClickBtn({ index: btnIndex, item }) { |
||||
console.log('btnIndex: ', btnIndex); |
|
||||
if (btnIndex === 0) { |
if (btnIndex === 0) { |
||||
modalDisplay.value = !modalDisplay.value; |
modalDisplay.value = !modalDisplay.value; |
||||
} else if (btnIndex === 2) { |
} else if (btnIndex === 2) { |
||||
monitorDisplay.value = !monitorDisplay.value; |
// monitorDisplay.value = !monitorDisplay.value; |
||||
|
if (scene === 'farm') { |
||||
|
// 跳转到 / |
||||
|
router.push('/'); |
||||
|
} else { |
||||
|
// 跳转到 /farm |
||||
|
router.push('/farm'); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<style scoped> |
<style scoped> |
||||
.page-header { |
.bg-center { |
||||
position: relative; |
position: relative; |
||||
height: 115rem; |
height: 115rem; |
||||
background: url('@/assets/images/top.png') no-repeat center; |
background: url('@/assets/images/top.png') no-repeat center; |
||||
background-size: 100% 114rem; |
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> |
</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> |
@ -1,19 +1,9 @@ |
|||||
<template> |
<template> |
||||
hello index |
<div></div> |
||||
{{ data.code }} |
</template> |
||||
</template> |
|
||||
|
<script> |
||||
<script setup> |
export default { |
||||
const { data } = await useFetch('/api/hello'); |
layout: 'default', |
||||
console.log('res: ', data); |
}; |
||||
</script> |
</script> |
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
layout: "default" |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
|
|
||||
</style> |
|
||||
|
@ -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