虫情诱惑

develop
ihzero 2023-08-28 18:14:20 +08:00
parent 00c152cbfb
commit 2280ba56f6
7 changed files with 647 additions and 1 deletions

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<!-- <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> -->
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"

View File

@ -999,3 +999,17 @@ export function citydataEdit(data, mode: ErrorMessageMode = 'modal') {
},
)
}
/**
* @description:
*/
export function getWormPhotos(device, params, mode: ErrorMessageMode = 'modal') {
return defHttp.get(
{
url: `/api/devices/${device}/worm-photos`,
params,
},
{
errorMessageMode: mode,
},
)
}

View File

@ -43,6 +43,30 @@ const main: AppRouteModule = {
title: '水质监控',
},
},
{
path: 'insect-monitors',
name: 'MainInsectMonitors',
component: () => import('/@/views/main/insect-monitors/index.vue'),
meta: {
title: '昆虫性诱监测',
},
},
{
path: 'pests',
name: 'MainPests',
component: () => import('/@/views/main/pests/index.vue'),
meta: {
title: '虫情监测',
},
},
{
path: 'insecticidal-lamp',
name: 'MainInsecticidalLamp',
component: () => import('/@/views/main/insecticidal-lamp/index.vue'),
meta: {
title: '杀虫灯监测',
},
},
],
}

View File

@ -0,0 +1,209 @@
<template>
<PageWrapper>
<Card>
<Form ref="formRef" :model="formState">
<Row :gutter="[16, 16]">
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem label="基地">
<Select
@select="onChange('base_id')"
:fieldNames="{ label: 'name', value: 'id' }"
:options="baseDate"
v-model:value="formState.base_id"
placeholder="请选择基地"
/>
</FormItem>
</Col>
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem label="检测点">
<Select
@select="onChange('device_id')"
placeholder="请选择检测点"
:options="pointDate"
v-model:value="formState.device_id"
/>
</FormItem>
</Col>
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem label="日期">
<RangePicker
:disabledDate="disabledDate"
@change="onChangTime"
v-model:value="formState.time"
/>
</FormItem>
</Col>
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem>
<RadioGroup
@change="onChange('time_interval')"
button-style="solid"
v-model:value="formState.time_interval"
>
<RadioButton value="day">今天</RadioButton>
<RadioButton value="week">近一周</RadioButton>
<RadioButton value="month">近一个月</RadioButton>
</RadioGroup>
</FormItem>
</Col>
</Row>
</Form>
<List
:grid="{ gutter: 16, xs: 1, sm: 2, md: 2, lg: 3, xl: 4, xxl: 5, column: 8 }"
:data-source="list"
>
<template #renderItem="{ item }">
<List-item>
<Card :hoverable="true" class="card" :bodyStyle="{ padding: 0 }">
<div>
<a-image :src="item.url" />
</div>
<div class="text-gray-500 px-5 py-3"> 时间 {{ item.time }} </div>
</Card>
</List-item>
</template>
</List>
</Card>
</PageWrapper>
</template>
<script lang="ts" setup>
import dayjs from 'dayjs'
import { formatDataByObject, getWeek, getMonth } from '/@/utils/index'
import {
getaGriculturalDevicePoint,
getGriculturalDeviceBasic,
getWormPhotos,
} from '/@/api/sys/user'
import { PageWrapper } from '/@/components/Page'
import {
Card,
Form,
FormItem,
Select,
Row,
Col,
RangePicker,
Radio,
List,
Image,
} from 'ant-design-vue'
import { reactive, ref, onMounted } from 'vue'
const RadioButton = Radio.Button
const RadioGroup = Radio.Group
const ListItem = List.Item
const AImage = Image
const disabledDate = (current) => {
return current && current > dayjs().endOf('day')
}
const formState = reactive({
base_id: undefined, //
device_id: undefined, //
time: undefined, //
time_interval: 'day',
})
const baseDate = ref<any>([])
const pointDate = ref<any>([])
const list = ref<any>([])
const getBase = async () => {
const res = await getGriculturalDeviceBasic({ device_type: 2 })
if (res.length == 0) return
baseDate.value = res
if (!formState.base_id) formState.base_id = res?.[0]?.id ?? undefined
getPoint()
}
const onChangTime = (e) => {
if (e === null) formState.time_interval = 'day'
else formState.time_interval = ''
getPoint()
}
const onChange = (e: string | undefined) => {
if (e === 'base_id') formState.device_id = undefined
if (e === 'time') formState.time_interval = ''
if (e === 'time_interval') {
formState.time = undefined
return getData()
}
getPoint()
}
//
const getPoint = async () => {
if (baseDate.value.length == 0) return
const res = await getaGriculturalDevicePoint({
device_type: 6,
agricultural_basic: formState.base_id,
})
pointDate.value = formatDataByObject(res)
if (!formState.device_id) formState.device_id = pointDate.value?.[0]?.value ?? undefined
getData()
}
//
const getData = async () => {
const params = {
device_id: formState.device_id,
start_time: '',
end_time: '',
}
if (formState.time) {
params.start_time = dayjs(formState.time?.[0]).format('YYYY-MM-DD')
params.end_time = dayjs(formState.time?.[1]).format('YYYY-MM-DD')
}
if (formState.time_interval === 'week') {
const { WeekStartDate, WeekEndDate } = getWeek()
params.start_time = WeekStartDate
params.end_time = WeekEndDate
} else if (formState.time_interval === 'month') {
const { MonthStartDate, MonthEndDate } = getMonth()
params.start_time = MonthStartDate
params.end_time = MonthEndDate
} else if (formState.time_interval === 'day') {
params.start_time = dayjs().endOf('day').format('YYYY-MM-DD')
params.end_time = dayjs().endOf('day').format('YYYY-MM-DD')
}
if (params.device_id == null) return (list.value = [])
const res = await getWormPhotos(params.device_id, params)
list.value = res
}
onMounted(() => {
getBase()
})
</script>

View File

@ -0,0 +1,138 @@
<template>
<Card :loading="loading">
<template #title>
<div class="flex items-end">
<div class="text-18px font-extrabold">{{ title }}</div>
<div class="ml-8px text-14px">{{ unit }}</div>
</div>
</template>
<template #extra></template>
<div ref="chartRef" :style="{ width, height }"></div>
</Card>
</template>
<script lang="ts" setup>
import dayjs from 'dayjs'
import { Card } from 'ant-design-vue'
import { Ref, ref, watch, computed } from 'vue'
import { useECharts } from '/@/hooks/web/useECharts'
import echarts from '/@/utils/lib/echarts'
const props = defineProps({
loading: Boolean,
title: {
type: String as PropType<string>,
default: '标题',
},
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: '300px',
},
data: {
type: Object as PropType<object>,
default: () => {},
},
company: {
type: String as PropType<string>,
default: '',
},
time: {
type: Object as PropType<object>,
default: () => {},
},
unit: {
type: String as PropType<string>,
default: '',
},
})
const format = computed(() => {
if (props.time) {
const start_time = dayjs(props.time?.[0]).format('YYYY-MM-DD')
const end_time = dayjs(props.time?.[1]).format('YYYY-MM-DD')
if (start_time === end_time) return 'HH:mm'
}
if (props.company === 'day') return 'HH:mm'
return 'YYYY-MM-DD'
})
const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
watch(
() => props.data,
(e) => {
if (e) {
setOptions({
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
width: 1,
color: '#019680',
},
},
},
xAxis: {
type: 'category',
data: Object.keys(e).map((e) => dayjs(e).format(format.value)),
axisTick: {
show: false,
},
axisLine: {
show: false,
},
},
yAxis: [
{
type: 'value',
axisTick: {
show: false,
},
splitLine: {
lineStyle: {
type: 'dashed',
},
},
},
],
grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true },
series: [
{
smooth: true,
data: Object.values(e),
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: '#d7f3f2',
},
{
offset: 1,
color: '#ebf9f9',
},
]),
},
itemStyle: {
color: '#5ab1ef',
},
},
],
dataZoom: [
{
type: 'inside', //sliderinside
show: false,
xAxisIndex: 0,
},
],
})
}
},
{
immediate: true,
},
)
</script>
<style scoped></style>

View File

@ -0,0 +1,252 @@
<template>
<PageWrapper>
<Card>
<Form ref="formRef" :model="formState">
<Row :gutter="[16, 16]">
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem label="基地">
<Select
@select="onChange('base_id')"
:fieldNames="{ label: 'name', value: 'id' }"
:options="baseDate"
v-model:value="formState.base_id"
placeholder="请选择基地"
/>
</FormItem>
</Col>
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem label="检测点">
<Select
@select="onChange('device_id')"
placeholder="请选择检测点"
:options="pointDate"
v-model:value="formState.device_id"
/>
</FormItem>
</Col>
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem label="日期">
<RangePicker
:disabledDate="disabledDate"
@change="onChangTime"
v-model:value="formState.time"
/>
</FormItem>
</Col>
<Col
:xs="{ span: 24 }"
:sm="{ span: 12 }"
:md="{ span: 8 }"
:lg="{ span: 6 }"
:xl="{ span: 6 }"
:xxl="{ span: 4 }"
>
<FormItem>
<RadioGroup
@change="onChange('time_interval')"
button-style="solid"
v-model:value="formState.time_interval"
>
<RadioButton value="day">今天</RadioButton>
<RadioButton value="week">近一周</RadioButton>
<RadioButton value="month">近一个月</RadioButton>
</RadioGroup>
</FormItem>
</Col>
</Row>
</Form>
<div class="mt-20px md:flex enter-y flex-wrap -mr-4">
<div v-for="(item, index) in tagMenus" :key="index">
<LineCharts
:company="formState.time_interval"
class="md:w-386px w-full !mr-4 !mb-4"
:extra="extra"
v-if="
statisData[item.value] &&
Object.values(statisData[item.value]).some((value) => value !== null)
"
:loading="false"
:title="item.lable"
:data="statisData[item.value]"
:time="formState.time"
:unit="item.unit"
/>
</div>
</div>
</Card>
</PageWrapper>
</template>
<script lang="ts" setup>
import dayjs from 'dayjs'
import icon1 from '/@/assets/images/icon_1.png'
import uicon1 from '/@/assets/images/uicon_1.png'
import LineCharts from './components/LineCharts.vue'
import { formatDataByObject, getWeek, getMonth } from '/@/utils/index'
import {
getaGriculturalDevicePoint,
getGriculturalDeviceBasic,
getAmonitoringData,
} from '/@/api/sys/user'
import { PageWrapper } from '/@/components/Page'
import { Card, Form, FormItem, Select, Row, Col, RangePicker, Radio } from 'ant-design-vue'
import { reactive, ref, onMounted, computed } from 'vue'
const RadioButton = Radio.Button
const RadioGroup = Radio.Group
const disabledDate = (current) => {
return current && current > dayjs().endOf('day')
}
const extra = computed(() => {
const name1 = baseDate.value?.find((e: any) => e.id === formState.base_id)?.name
const name2 = pointDate.value?.find((e: any) => e.value === formState.device_id)?.label ?? ''
return name1 + '-' + name2
})
const tagMenus = [
{
lable: '大气湿度',
value: 'air_humidity',
icon: icon1,
icon1: uicon1,
unit: '',
},
{
lable: '大气气温',
value: 'air_temperature',
icon: icon1,
icon1: uicon1,
unit: '',
},
{
lable: '蓄电池电压',
value: 'battery_vol',
icon: icon1,
icon1: uicon1,
unit: '',
},
{
lable: '充电电压',
value: 'charging_vol',
icon: icon1,
icon1: uicon1,
unit: '',
},
{
lable: '高压值',
value: 'high_vol',
icon: icon1,
icon1: uicon1,
unit: '',
},
{
lable: '杀虫数',
value: 'killed_num',
icon: icon1,
icon1: uicon1,
unit: '',
},
]
const formState = reactive({
base_id: undefined, //
device_id: undefined, //
time: undefined, //
time_interval: 'day',
})
const statisData = ref<any>({})
const baseDate = ref<any>([])
const pointDate = ref<any>([])
const getBase = async () => {
const res = await getGriculturalDeviceBasic({ device_type: 2 })
if (res.length == 0) return
baseDate.value = res
if (!formState.base_id) formState.base_id = res?.[0]?.id ?? undefined
getPoint()
}
const onChangTime = (e) => {
if (e === null) formState.time_interval = 'day'
else formState.time_interval = ''
getPoint()
}
const onChange = (e: string | undefined) => {
if (e === 'base_id') formState.device_id = undefined
if (e === 'time') formState.time_interval = ''
if (e === 'time_interval') {
formState.time = undefined
return getDate()
}
getPoint()
}
//
const getPoint = async () => {
if (baseDate.value.length == 0) return
const res = await getaGriculturalDevicePoint({
device_type: 7,
agricultural_basic: formState.base_id,
})
pointDate.value = formatDataByObject(res)
if (!formState.device_id) formState.device_id = pointDate.value?.[0]?.value ?? undefined
getDate()
}
//
const getDate = async () => {
const params = {
device_id: formState.device_id,
start_time: '',
end_time: '',
}
if (formState.time) {
params.start_time = dayjs(formState.time?.[0]).format('YYYY-MM-DD')
params.end_time = dayjs(formState.time?.[1]).format('YYYY-MM-DD')
}
if (formState.time_interval === 'week') {
const { WeekStartDate, WeekEndDate } = getWeek()
params.start_time = WeekStartDate
params.end_time = WeekEndDate
} else if (formState.time_interval === 'month') {
const { MonthStartDate, MonthEndDate } = getMonth()
params.start_time = MonthStartDate
params.end_time = MonthEndDate
} else if (formState.time_interval === 'day') {
params.start_time = dayjs().endOf('day').format('YYYY-MM-DD')
params.end_time = dayjs().endOf('day').format('YYYY-MM-DD')
}
if (params.device_id == null) return (statisData.value = {})
const res = await getAmonitoringData(params)
statisData.value = res
}
onMounted(() => {
getBase()
})
</script>

View File

@ -0,0 +1,9 @@
<template>
<PageWrapper>
<Card>虫情监测</Card>
</PageWrapper>
</template>
<script setup lang="ts">
import { Card } from 'ant-design-vue'
import { PageWrapper } from '/@/components/Page'
</script>