new-map
ihzero 2022-11-03 09:57:01 +08:00
parent fbf504e87f
commit ac3caee8ee
14 changed files with 693 additions and 238 deletions

View File

@ -162,7 +162,10 @@ export function getDeviceBaseDataStatics(params, mode: ErrorMessageMode = 'modal
} }
/** /**
* @description: * @description:
* *"1": "监控设备",
"2": "土壤设备",
"3": "水质设备",
"4": "气象设备"
*/ */
export function getAgriculturalDeviceBasic(params, mode: ErrorMessageMode = 'modal') { export function getAgriculturalDeviceBasic(params, mode: ErrorMessageMode = 'modal') {
return defHttp.get( return defHttp.get(
@ -175,3 +178,45 @@ export function getAgriculturalDeviceBasic(params, mode: ErrorMessageMode = 'mod
}, },
) )
} }
/**
* @description:
*/
export function getDeviceDataStatics(params, mode: ErrorMessageMode = 'modal') {
return defHttp.get(
{
url: '/api/device-data-statics',
params,
},
{
errorMessageMode: mode,
},
)
}
/**
* @description:
*/
export function getDevicesNum(params, mode: ErrorMessageMode = 'modal') {
return defHttp.get(
{
url: '/api/devices-num',
params,
},
{
errorMessageMode: mode,
},
)
}
/**
* @description: -
*/
export function getRiceShrimpIndustry(params, mode: ErrorMessageMode = 'modal') {
return defHttp.get(
{
url: '/api/charts/rice-shrimp-industry',
params,
},
{
errorMessageMode: mode,
},
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,12 +1,15 @@
<template> <template>
<div class="bg-[#0A404E] bg-opacity-40 flex flex-col w-full" :style="{ width, height }"> <div class="bg-[#0A404E] bg-opacity-40 flex flex-col w-full" :style="{ width, height }">
<div class="flex items-center justify-between h-49px px-14px"> <div class="flex items-center justify-between h-49px px-14px relative">
<div <div
class="flex items-center bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE]" class="flex items-center bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE]"
> >
<span class="block w-8.5px h-8.5px rounded-full bg-[#6CCDDA]"></span> <span class="block w-8.5px h-8.5px rounded-full bg-[#6CCDDA]"></span>
<span class="ml-10.5px text-18px">{{ title }}</span> <span class="ml-10.5px text-18px">{{ title }}</span>
</div> </div>
<div class="absolute left-100px right-100px">
<slot name="center"> </slot>
</div>
<slot name="right"> <slot name="right">
<img class="w-76.5px h-7.5px" :src="HeadIcon" alt="" srcset="" /> <img class="w-76.5px h-7.5px" :src="HeadIcon" alt="" srcset="" />
</slot> </slot>

View File

@ -1,5 +1,5 @@
<template> <template>
<Box title="渔业"> <Box title="稻虾价格">
<div class="h-full flex flex-col"> <div class="h-full flex flex-col">
<div class="py-10px"> <div class="py-10px">
<ul class="flex items-center justify-center m-0"> <ul class="flex items-center justify-center m-0">

View File

@ -1,61 +1,51 @@
<template> <template>
<Box title="畜牧业"> <Box title="稻虾产业">
<div class="h-full flex flex-col"> <div class="h-full flex flex-col">
<div class="py-10px">
<ul class="flex items-center justify-center m-0">
<li
class="mx-11px text-white text-12px cursor-pointer"
:class="{ active: currentTab == item.key }"
@click="changeTab(item.key)"
v-for="item in tabList"
:key="item.key"
>{{ item.value }}</li
>
</ul>
</div>
<div class="flex-1" ref="chartRef"> </div> <div class="flex-1" ref="chartRef"> </div>
</div> </div>
</Box> </Box>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref, Ref, onMounted } from 'vue' import { defineComponent, reactive, ref, Ref, onBeforeMount, watch } from 'vue'
import Box from './Box.vue' import Box from './Box.vue'
import { useECharts } from '/@/hooks/web/useECharts' import { useECharts } from '/@/hooks/web/useECharts'
import echarts from '/@/utils/lib/echarts' import { getRiceShrimpIndustry } from '/@/api/sys/other'
import { useVisualizationStore } from '/@/store/modules/visualization'
export default defineComponent({ export default defineComponent({
components: { components: {
Box, Box,
}, },
setup() { setup() {
const tabList = reactive([ const Data = reactive({
{ x_axis: [],
key: '0', series: [],
value: '全部', })
},
{
key: '1',
value: '猪',
},
{
key: '2',
value: '牛',
},
])
const currentTab = ref<String>('0')
const chartRef = ref<HTMLDivElement | null>(null) const chartRef = ref<HTMLDivElement | null>(null)
const changeTab = (key: String) => { const visualizationStore = useVisualizationStore()
if (currentTab.value == key) return
currentTab.value = key
chartsInit()
}
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
async function getData() {
const resData = await getRiceShrimpIndustry({
year: visualizationStore.getYear,
})
Data.x_axis = resData.x_axis
Data.series = resData.series
console.log(Data)
chartsInit()
}
const chartsInit = () => { const chartsInit = () => {
const legendData = []
const series = []
Data.series.forEach((e) => {
legendData.push(e.name)
})
return
setOptions({ setOptions({
grid: { left: '2%', right: '2%', top: '10%', bottom: '2%', containLabel: true }, grid: { left: '2%', right: '2%', top: '10%', bottom: '2%', containLabel: true },
legend: { legend: {
@ -77,7 +67,7 @@
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
data: [...new Array(10)].map((_item, index) => `${index + 6}:00`), data: Data.x_axis,
axisTick: { axisTick: {
show: false, show: false,
}, },
@ -135,15 +125,17 @@
}) })
} }
onMounted(() => { onBeforeMount(() => {
chartsInit() getData()
}) })
watch(
() => visualizationStore.getYear,
() => getData(),
)
return { return {
tabList,
currentTab,
chartRef, chartRef,
changeTab,
} }
}, },
}) })

View File

@ -7,7 +7,10 @@
> >
{{ currentTabValue }} {{ currentTabValue }}
</div> </div>
<div class="absolute right-18px top-1/2 transform -translate-y-1/2"> <div
class="absolute right-18px top-1/2 transform -translate-y-1/2"
v-if="tabList.length > 1"
>
<Dropdown <Dropdown
overlayClassName="dropdownClass" overlayClassName="dropdownClass"
placement="bottomRight" placement="bottomRight"
@ -28,9 +31,9 @@
</Dropdown> </Dropdown>
</div> </div>
</div> </div>
<div class="flex-1 px-11px"> <div class="flex-1 px-11px flex flex-col">
<div class="h-196px border border-solid"></div> <div class="flex-1 border border-solid"></div>
<div class="grid grid-cols-3 gap-x-6px mt-10px"> <div class="grid grid-cols-3 gap-x-6px my-10px">
<div class="border border-solid h-66px"></div> <div class="border border-solid h-66px"></div>
<div class="border border-solid h-66px"></div> <div class="border border-solid h-66px"></div>
<div class="border border-solid h-66px"></div> <div class="border border-solid h-66px"></div>
@ -41,10 +44,10 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref, onMounted, onBeforeMount, computed } from 'vue' import { defineComponent, reactive, ref, onBeforeMount, computed, toRefs } from 'vue'
import { DownOutlined } from '@ant-design/icons-vue' import { DownOutlined } from '@ant-design/icons-vue'
import { Dropdown, Menu } from 'ant-design-vue' import { Dropdown, Menu } from 'ant-design-vue'
import { getDeviceBaseDataStatics } from '/@/api/sys/other' import { getAgriculturalDeviceBasic } from '/@/api/sys/other'
import { useVisualizationStore } from '/@/store/modules/visualization' import { useVisualizationStore } from '/@/store/modules/visualization'
import Box from './Box.vue' import Box from './Box.vue'
export default defineComponent({ export default defineComponent({
@ -56,45 +59,38 @@
MenuItem: Menu.Item, MenuItem: Menu.Item,
}, },
setup() { setup() {
const tabList = reactive([
{
key: '0',
value: '基地1',
},
{
key: '1',
value: '基地2',
},
{
key: '2',
value: '基地3',
},
])
const visualizationStore = useVisualizationStore() const visualizationStore = useVisualizationStore()
const currentTab = ref<String>('0') const Data = reactive({
tabList: ref<any>([]),
currentTab: ref<number | string>(''),
})
const chartRef = ref<HTMLDivElement | null>(null) const chartRef = ref<HTMLDivElement | null>(null)
const currentTabValue = computed(() => tabList.find((e) => e.key == currentTab.value)?.value) const currentTabValue = computed(
() => Data.tabList.find((e) => e.id == Data.currentTab)?.name ?? '',
)
async function getDevice() {
await getDeviceBaseDataStatics({
base_id: visualizationStore.getAddresId,
// device_type,
})
}
function onMenuClick({ key }) { function onMenuClick({ key }) {
if (currentTab.value == key) return if (Data.currentTab == key) return
currentTab.value = key Data.currentTab = key
} }
onBeforeMount(() => {})
onMounted(() => {}) async function getTabs() {
const resData = await getAgriculturalDeviceBasic({
device_type: 1,
})
Data.tabList = resData
if (resData.length) Data.currentTab = resData[0].id
}
onBeforeMount(() => {
getTabs()
})
return { return {
tabList, ...toRefs(Data),
currentTab,
chartRef, chartRef,
currentTabValue, currentTabValue,
onMenuClick, onMenuClick,
@ -102,9 +98,3 @@
}, },
}) })
</script> </script>
<style scoped lang="less">
.active {
@apply font-bold text-15px text-[#76E9F0];
}
</style>

View File

@ -1,28 +1,46 @@
<template> <template>
<Box title="气象数据"> <Box title="气象数据">
<template #center>
<div
class="text-center bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE] text-15px font-bold"
>
{{ currentTabValue }}
</div>
</template>
<template #right> <template #right>
<div class="w-250px flex justify-end"> <div class="py-10px relative">
<a-tabs <div class="" v-if="tabList.length > 1">
:tabBarGutter="14" <Dropdown
v-model:activeKey="activeKey" overlayClassName="dropdownClass"
:tab-position="mode" placement="bottomRight"
:style="{ height: '48px', color: 'white' }" trigger="click"
@tabScroll="callback" :style="{ height: '300px' }"
color="red" >
> <div class="cursor-pointer">
<a-tab-pane v-for="i in 10" :key="i" :tab="`Tab-${i}`" /> <span class="text-white text-12px">更多</span>
</a-tabs> <DownOutlined :style="{ fontSize: '12px', color: '#FFF' }" />
</div>
<template #overlay>
<Menu @click="onMenuClick">
<menu-item v-for="item in tabList" :key="item.id">
<div>{{ item.name }}</div>
</menu-item>
</Menu>
</template>
</Dropdown>
</div>
</div> </div>
</template> </template>
<div class="pl-23px py-23px"> <div class="pl-23px py-23px">
<div class="grid grid-cols-3 gap-20px"> <div class="grid grid-cols-3 gap-20px">
<div v-for="item in 6" :key="item"> <div v-for="item in list" :key="item.key">
<div class="text-11px text-white">空气温度</div> <div class="text-11px text-white">{{ item.label }}</div>
<div <div
class="mt-11px bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE]" class="mt-11px bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE]"
> >
<span class="text-18px font-bold">18.12</span> <!-- <span class="text-18px font-bold">{{ item.value }}</span> -->
<span class="text-11px ml-4px"></span> <CountTo :startVal="0" :endVal="item.value" class="text-18px font-bold" separator="" />
<span class="text-11px ml-4px">{{ item.unit }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -31,68 +49,109 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, ref } from 'vue' import { defineComponent, reactive, ref, onBeforeMount, computed, toRefs } from 'vue'
import { DownOutlined } from '@ant-design/icons-vue'
import type { TabsProps } from 'ant-design-vue' import { Dropdown, Menu } from 'ant-design-vue'
import { getAgriculturalDeviceBasic, getDevices, getDeviceDataStatics } from '/@/api/sys/other'
import { useVisualizationStore } from '/@/store/modules/visualization'
import { CountTo } from '/@/components/CountTo'
import Box from './Box.vue' import Box from './Box.vue'
import { Tabs, TabPane } from 'ant-design-vue' import { cloneDeep } from 'lodash'
const defaultList = [
{
label: '空气温度',
value: 0,
unit: '℃',
key: 'air_temperature',
},
{
label: '空气湿度',
value: 0,
unit: '%',
key: 'air_humidity',
},
{
label: '光照强度',
value: 0,
unit: 'lux',
key: 'illumination',
},
{
label: '降雨量',
value: 0,
unit: 'mm',
key: 'current_rainfall',
},
{
label: '风速',
value: 0,
unit: 'm/s',
key: 'wind_speed',
},
{
label: '大气压力',
value: 0,
unit: 'Kpa',
key: 'air_pressure',
},
]
export default defineComponent({ export default defineComponent({
components: { components: {
Box, Box,
[Tabs.name]: Tabs, Dropdown,
[TabPane.name]: TabPane, DownOutlined,
Menu,
MenuItem: Menu.Item,
CountTo,
}, },
setup() { setup() {
const mode = ref<TabsProps['tabPosition']>('top') const visualizationStore = useVisualizationStore()
const activeKey = ref(1) const Data = reactive({
const callback: TabsProps['onTabScroll'] = (val) => { tabList: ref<any>([]),
console.log(val) currentTab: ref<number | string>(''),
list: cloneDeep(defaultList),
})
const chartRef = ref<HTMLDivElement | null>(null)
const currentTabValue = computed(
() => Data.tabList.find((e) => e.id == Data.currentTab)?.name ?? '',
)
function onMenuClick({ key }) {
if (Data.currentTab == key) return
Data.currentTab = key
getData()
} }
async function getData() {
const devices = await getDevices({ base: Data.currentTab, type: 4, status: 1 })
if (devices.length) {
const { list } = await getDeviceDataStatics({ device_id: devices[0].id })
Data.list.forEach((e) => (e.value = Number(list[e.key])))
} else {
Data.list.forEach((e) => (e.value = 0))
}
}
async function getTabs() {
const resData = await getAgriculturalDeviceBasic({
device_type: 4,
})
Data.tabList = resData
if (resData.length) onMenuClick({ key: resData[0].id })
}
onBeforeMount(() => {
getTabs()
})
return { return {
mode, ...toRefs(Data),
callback, chartRef,
activeKey, currentTabValue,
onMenuClick,
} }
}, },
}) })
</script> </script>
<style scoped lang="less">
::v-deep(.ant-tabs-nav) {
&::before {
border: none;
}
.ant-tabs-ink-bar {
@apply bg-[#76E9F0];
}
.ant-tabs-tab {
&:hover {
@apply text-[#76E9F0];
}
}
.ant-tabs-tab-active {
.ant-tabs-tab-btn {
@apply text-[#76E9F0];
}
}
}
</style>
<style>
.ant-tabs-dropdown {
/* background: red; */
}
.ant-tabs-dropdown-menu {
border: 1px solid #396684;
background: rgba(28, 44, 52, 0.9);
}
.ant-tabs-dropdown-menu-item {
color: white;
}
</style>

View File

@ -31,24 +31,27 @@
</Dropdown> </Dropdown>
</div> </div>
</div> </div>
<div class="flex-1 px-30px grid grid-cols-2 gap-y-10px gap-x-90px pb-16px"> <div class="flex-1 px-30px grid grid-cols-2 gap-y-10px gap-x-10px pb-16px">
<div class="flex items-center" v-for="item in 4" :key="item"> <div class="flex" v-for="(item, index) in list" :key="index">
<div> <div class="text-center">
<SvgIcon name="jd1-icon" :size="65" /> <img class="w-65.5px h-65.5px" :src="item.img" alt="" srcset="" />
<div class="text-12px font-bold text-white mt-11px">AI智能监控</div> <div class="text-12px font-bold text-white mt-11px">{{ item.name }}</div>
</div> </div>
<div class="ml-24px"> <div class="ml-18px">
<div class="flex items-center h-22px"> <div class="flex items-center h-22px">
<div class="w-7px h-7px bg-[#76E9F0]"></div> <div class="w-7px h-7px bg-[#76E9F0]"></div>
<div class="ml-11px text-11px text-white">在线</div> <div class="ml-11px text-11px text-white">在线</div>
<div class="text-white ml-10px">{{ item.value[0] }}</div>
</div> </div>
<div class="flex items-center h-22px"> <div class="flex items-center h-22px">
<div class="w-7px h-7px bg-[#F7B379]"></div> <div class="w-7px h-7px bg-[#F7B379]"></div>
<div class="ml-11px text-11px text-white">离线</div> <div class="ml-11px text-11px text-white">离线</div>
<div class="text-white ml-10px">{{ item.value[1] }}</div>
</div> </div>
<div class="flex items-center h-22px"> <div class="flex items-center h-22px">
<div class="w-7px h-7px bg-[#EB313E]"></div> <div class="w-7px h-7px bg-[#EB313E]"></div>
<div class="ml-11px text-11px text-white">故障</div> <div class="ml-11px text-11px text-white">故障</div>
<div class="text-white ml-10px">{{ item.value[2] }}</div>
</div> </div>
</div> </div>
</div> </div>
@ -58,17 +61,44 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref, onMounted, onBeforeMount, toRefs, computed } from 'vue' import { defineComponent, reactive, ref, onBeforeMount, toRefs, computed, watch } from 'vue'
import { SvgIcon } from '/@/components/Icon'
import Box from './Box.vue' import Box from './Box.vue'
import { getAgriculturalBasic } from '/@/api/sys/other' import { getAgriculturalBasic, getDevicesNum } from '/@/api/sys/other'
import { useVisualizationStore } from '/@/store/modules/visualization' import { useVisualizationStore } from '/@/store/modules/visualization'
import { Dropdown, Menu } from 'ant-design-vue' import { Dropdown, Menu } from 'ant-design-vue'
import { DownOutlined } from '@ant-design/icons-vue' import { DownOutlined } from '@ant-design/icons-vue'
import { cloneDeep } from 'lodash-es'
import d01 from '/@/assets/images/d01.png'
import d02 from '/@/assets/images/d02.png'
import d03 from '/@/assets/images/d03.png'
import d04 from '/@/assets/images/d04.png'
const defaultDevice = [
{
name: 'AI智能监控',
value: [0, 0, 0],
img: d01,
},
{
name: '水质监测',
value: [0, 0, 0],
img: d02,
},
{
name: '土壤监测',
value: [0, 0, 0],
img: d03,
},
{
name: '气象监测',
value: [0, 0, 0],
img: d04,
},
]
export default defineComponent({ export default defineComponent({
components: { components: {
Box, Box,
SvgIcon,
Dropdown, Dropdown,
Menu, Menu,
MenuItem: Menu.Item, MenuItem: Menu.Item,
@ -78,6 +108,7 @@
const Data = reactive({ const Data = reactive({
tabList: ref<any>([]), tabList: ref<any>([]),
currentTab: ref<number | string>(''), currentTab: ref<number | string>(''),
list: cloneDeep(defaultDevice),
}) })
const chartRef = ref<HTMLDivElement | null>(null) const chartRef = ref<HTMLDivElement | null>(null)
@ -91,22 +122,40 @@
function onMenuClick({ key }) { function onMenuClick({ key }) {
if (Data.currentTab == key) return if (Data.currentTab == key) return
Data.currentTab = key Data.currentTab = key
getData()
} }
async function getDevices() { async function getTabs() {
const resData = await getAgriculturalBasic({ const resData = await getAgriculturalBasic({
parent_id: visualizationStore.getAddresId, parent_id: visualizationStore.getAddresId,
type: 1, type: 1,
}) })
Data.tabList = resData Data.tabList = resData
if (resData.length) Data.currentTab = resData[0].id let defaultId = ''
if (resData.length) defaultId = resData[0].id
onMenuClick({ key: defaultId })
} }
onBeforeMount(() => {}) async function getData() {
onMounted(() => { const resData = await getDevicesNum({
getDevices() base_id: Data.currentTab,
})
Object.keys(resData).map((e, index) => {
Data.list[index].value = resData[e].slice(1)
})
}
onBeforeMount(() => {
getTabs()
}) })
watch(
() => visualizationStore.getAddresId,
() => {
getTabs()
},
)
return { return {
...toRefs(Data), ...toRefs(Data),
currentTabValue, currentTabValue,

View File

@ -1,28 +1,210 @@
<template> <template>
<Box title="水质监测数据"> <Box title="水质监测数据">
<template #center>
<div
class="text-center bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE] text-15px font-bold"
>
{{ currentTabValue }}
</div>
</template>
<template #right>
<div class="py-10px relative">
<div class="" v-if="tabList.length > 1">
<Dropdown
overlayClassName="dropdownClass"
placement="bottomRight"
trigger="click"
:style="{ height: '300px' }"
>
<div class="cursor-pointer">
<span class="text-white text-12px">更多</span>
<DownOutlined :style="{ fontSize: '12px', color: '#FFF' }" />
</div>
<template #overlay>
<Menu @click="onMenuClick">
<menu-item v-for="item in tabList" :key="item.id">
<div>{{ item.name }}</div>
</menu-item>
</Menu>
</template>
</Dropdown>
</div>
</div>
</template>
<div class="h-full flex flex-col"> <div class="h-full flex flex-col">
<div class="h-30px flex items-center px-10px">
<div
class="text-white mx-5px text-12px cursor-pointer"
:class="{ active: item.key == currentMenu }"
v-for="(item, index) in menu"
@click="onChangeMenu(item)"
:key="index"
>
{{ item.name }}
</div>
</div>
<div class="flex-1" ref="chartRef"> </div> <div class="flex-1" ref="chartRef"> </div>
</div> </div>
</Box> </Box>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref, Ref, onMounted } from 'vue' import { defineComponent, reactive, ref, Ref, onBeforeMount, computed, toRefs } from 'vue'
import Box from './Box.vue' import Box from './Box.vue'
import { useECharts } from '/@/hooks/web/useECharts' import { useECharts } from '/@/hooks/web/useECharts'
import echarts from '/@/utils/lib/echarts' import echarts from '/@/utils/lib/echarts'
import { getAgriculturalDeviceBasic, getDeviceBaseDataStatics } from '/@/api/sys/other'
import { DownOutlined } from '@ant-design/icons-vue'
import { Dropdown, Menu } from 'ant-design-vue'
import { cloneDeep } from 'lodash'
import { chartBarColors } from './colors'
import { dateUtil } from '/@/utils/dateUtil'
const desList = [
{
key: 'turbidity',
unit: 'NTU',
name: '浊度',
},
{
key: 'chlorine',
unit: 'mg/L',
name: '余氯',
},
{
key: 'ph',
unit: null,
name: 'PH值',
},
{
key: 'temperature',
unit: '℃',
name: '温度',
},
{
key: 'oxygen',
unit: 'mg/L',
name: '溶解氧',
},
{
key: 'conductivity',
unit: 'uS/cm',
name: '电导率',
},
]
export default defineComponent({ export default defineComponent({
components: { components: {
Box, Box,
Dropdown,
DownOutlined,
Menu,
MenuItem: Menu.Item,
}, },
setup() { setup() {
const Data = reactive({
tabList: ref<any>([]),
menu: cloneDeep(desList),
currentMenu: 'turbidity',
currentTab: ref<number | string>(''),
list: [] as any,
})
const chartRef = ref<HTMLDivElement | null>(null) const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
const currentTabValue = computed(
() => Data.tabList.find((e) => e.id == Data.currentTab)?.name ?? '',
)
function onMenuClick({ key }) {
if (Data.currentTab == key) return
Data.currentTab = key
}
async function getTabs() {
const resData = await getAgriculturalDeviceBasic({
device_type: 3,
})
Data.tabList = resData
if (resData.length) Data.currentTab = resData[0].id
getData()
}
async function getData() {
const resData = await getDeviceBaseDataStatics({
base_id: Data.currentTab,
device_type: 3,
device_column: Data.currentMenu,
})
const arr = [] as any
for (const key in resData) {
if (Object.prototype.hasOwnProperty.call(resData, key)) {
arr.push({
name: key,
data: Object.keys(resData[key]).map((e) => {
return {
key: e,
value: resData[key][e] ? Number(resData[key][e]) : null,
}
}),
})
}
}
Data.list = arr
chartsInit()
}
function onChangeMenu({ key }) {
if (Data.currentMenu == key) return
Data.currentMenu = key
getData()
}
onBeforeMount(() => {
getTabs()
})
const chartsInit = () => { const chartsInit = () => {
const data = Data.list.map((e, index) => {
const color = chartBarColors[index % Data.list.length]
return {
axis: e.data.map((e) => dateUtil(e.key).format('HH:mm')),
name: e.name,
series: {
name: e.name,
data: e.data.map((e) => e.value),
type: 'bar',
label: {
show: true,
position: 'top',
color: '#fff',
},
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: color.itemColor1,
},
{
offset: 1,
color: color.itemColor2,
},
]),
},
},
}
})
setOptions({ setOptions({
grid: { left: '2%', right: '2%', top: '6%', bottom: '2%', containLabel: true }, grid: { left: '2%', right: '2%', top: '20px', bottom: '2%', containLabel: true },
legend: {
data: data.map((e) => e.name),
top: '0%',
right: '0',
textStyle: {
color: '#ffffff',
},
},
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
@ -34,7 +216,7 @@
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
data: [...new Array(10)].map((_item, index) => `${index + 6}:00`), data: data[0]?.axis ?? [],
axisTick: { axisTick: {
show: false, show: false,
}, },
@ -63,45 +245,22 @@
}, },
}, },
], ],
series: [ series: data.map((e) => e.series),
{
data: [11, 22, 40, 18, 3, 55, 66, 33, 14, 30],
type: 'bar',
label: {
show: true,
position: 'top',
color: '#fff',
},
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: '#76E9F0',
},
{
offset: 1,
color: '#1A3537',
},
]),
},
},
],
}) })
} }
onMounted(() => {
chartsInit()
})
return { return {
...toRefs(Data),
currentTabValue,
onMenuClick,
onChangeMenu,
chartRef, chartRef,
} }
}, },
}) })
</script> </script>
<style scoped>
<style scoped lang="less">
.active { .active {
@apply font-bold text-15px text-[#76E9F0]; color: #76e9f0;
} }
</style> </style>

View File

@ -1,29 +1,196 @@
<template> <template>
<Box title="土壤监测数据"> <Box title="土壤监测数据">
<template #center>
<div
class="text-center bg-clip-text text-transparent bg-gradient-to-t from-[#76E9F0] to-[#A7E6EE] text-15px font-bold"
>
{{ currentTabValue }}
</div>
</template>
<template #right>
<div class="py-10px relative">
<div class="" v-if="tabList.length > 1">
<Dropdown
overlayClassName="dropdownClass"
placement="bottomRight"
trigger="click"
:style="{ height: '300px' }"
>
<div class="cursor-pointer">
<span class="text-white text-12px">更多</span>
<DownOutlined :style="{ fontSize: '12px', color: '#FFF' }" />
</div>
<template #overlay>
<Menu @click="onMenuClick">
<menu-item v-for="item in tabList" :key="item.id">
<div>{{ item.name }}</div>
</menu-item>
</Menu>
</template>
</Dropdown>
</div>
</div>
</template>
<div class="h-full flex flex-col"> <div class="h-full flex flex-col">
<div class="h-30px flex items-center px-10px">
<div
class="text-white mx-5px text-12px cursor-pointer"
:class="{ active: item.key == currentMenu }"
v-for="(item, index) in menu"
@click="onChangeMenu(item)"
:key="index"
>
{{ item.name }}
</div>
</div>
<div class="flex-1" ref="chartRef"> </div> <div class="flex-1" ref="chartRef"> </div>
</div> </div>
</Box> </Box>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, ref, Ref, onMounted } from 'vue' import { defineComponent, reactive, ref, Ref, onBeforeMount, computed, toRefs } from 'vue'
import Box from './Box.vue' import Box from './Box.vue'
import { useECharts } from '/@/hooks/web/useECharts' import { useECharts } from '/@/hooks/web/useECharts'
import { getAgriculturalDeviceBasic, getDeviceBaseDataStatics } from '/@/api/sys/other'
import { DownOutlined } from '@ant-design/icons-vue'
import { Dropdown, Menu } from 'ant-design-vue'
import { cloneDeep } from 'lodash'
import { dateUtil } from '/@/utils/dateUtil'
import { chartLineColors } from './colors'
const desList = [
{
key: 'temperature',
unit: ' ℃',
name: '温度',
},
{
key: 'conductivity',
unit: 'us/cm',
name: '电导率 ',
},
{
key: 'humidity',
unit: '%',
name: '湿度',
},
{
key: 'n',
unit: 'mg/kg',
name: '氮',
},
{
key: 'p',
unit: 'mg/kg',
name: '磷',
},
{
key: 'k',
unit: 'mg/kg',
name: '钾',
},
]
export default defineComponent({ export default defineComponent({
components: { components: {
Box, Box,
Dropdown,
DownOutlined,
Menu,
MenuItem: Menu.Item,
}, },
setup() { setup() {
const Data = reactive({
tabList: ref<any>([]),
menu: cloneDeep(desList),
currentMenu: 'temperature',
currentTab: ref<number | string>(''),
list: [] as any,
})
const chartRef = ref<HTMLDivElement | null>(null) const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>) const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
const currentTabValue = computed(
() => Data.tabList.find((e) => e.id == Data.currentTab)?.name ?? '',
)
function onMenuClick({ key }) {
if (Data.currentTab == key) return
Data.currentTab = key
}
async function getTabs() {
const resData = await getAgriculturalDeviceBasic({
device_type: 2,
})
Data.tabList = resData
if (resData.length) Data.currentTab = resData[0].id
getData()
}
async function getData() {
const resData = await getDeviceBaseDataStatics({
base_id: Data.currentTab,
device_type: 2,
device_column: Data.currentMenu,
})
const arr = [] as any
for (const key in resData) {
if (Object.prototype.hasOwnProperty.call(resData, key)) {
arr.push({
name: key,
data: Object.keys(resData[key]).map((e) => {
return {
key: e,
value: resData[key][e],
}
}),
})
}
}
Data.list = arr
chartsInit()
}
function onChangeMenu({ key }) {
if (Data.currentMenu == key) return
Data.currentMenu = key
getData()
}
onBeforeMount(() => {
getTabs()
})
const chartsInit = () => { const chartsInit = () => {
const data = Data.list.map((e, index) => {
const color = chartLineColors[index % Data.list.length]
return {
axis: e.data.map((e) => dateUtil(e.key).format('HH:mm')),
name: e.name,
series: {
name: e.name,
data: e.data.map((e) => e.value),
type: 'line',
symbol: 'none',
itemStyle: {
color: color.itemColor,
},
areaStyle: {
color: color.areaColor,
},
},
}
})
setOptions({ setOptions({
grid: { left: '2%', right: '2%', top: '20%', bottom: '2%', containLabel: true }, grid: { left: '2%', right: '2%', top: '20px', bottom: '2%', containLabel: true },
legend: { legend: {
data: ['销售水量', '主营业务'], data: data.map((e) => e.name),
top: '0%', top: '0%',
right: '0', right: '0',
textStyle: { textStyle: {
@ -41,7 +208,7 @@
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
data: [...new Array(10)].map((_item, index) => `${index + 6}:00`), data: data[0]?.axis ?? [],
axisTick: { axisTick: {
show: false, show: false,
}, },
@ -70,48 +237,22 @@
}, },
}, },
], ],
series: [ series: data.map((e) => e.series),
{
name: '销售水量',
data: [11, 22, 40, 18, 3, 55, 66, 33, 14, 30],
type: 'line',
symbol: 'none',
itemStyle: {
color: '#00F4B9',
},
areaStyle: {
color: 'rgba(0, 244, 185, 0.4)',
},
},
{
name: '主营业务',
data: [11, 22, 40, 18, 3, 55, 66, 33, 14, 30].reverse(),
type: 'line',
symbol: 'none',
itemStyle: {
color: '#28F2E6',
},
areaStyle: {
color: 'rgba(40, 242, 230, 0.4)',
},
},
],
}) })
} }
onMounted(() => {
chartsInit()
})
return { return {
...toRefs(Data),
currentTabValue,
onMenuClick,
onChangeMenu,
chartRef, chartRef,
} }
}, },
}) })
</script> </script>
<style scoped>
<style scoped lang="less">
.active { .active {
@apply font-bold text-15px text-[#76E9F0]; color: #76e9f0;
} }
</style> </style>

View File

@ -0,0 +1,17 @@
export const chartColors = []
export const chartLineColors = [
{
itemColor: '#00F4B9',
areaColor: 'rgba(0, 244, 185, 0.4)',
},
{
itemColor: '#28F2E6',
areaColor: 'rgba(40, 242, 230, 0.4)',
},
]
export const chartBarColors = [
{
itemColor1: '#76E9F0',
itemColor2: '#1A3537',
},
]