杀虫灯监测

wechat
ihzero 2023-09-12 01:43:56 +08:00
parent 795b5e8a63
commit 378d2a60e1
9 changed files with 732 additions and 15 deletions

View File

@ -1,5 +1,5 @@
<template>
<div>
<view>
<u-dropdown ref="dropdownRef">
<SearchItem
v-for="schema in getSchema"
@ -12,7 +12,7 @@
></SearchItem>
</u-dropdown>
<portal-target name="calendar-portal" />
</div>
</view>
</template>
<script>
import SearchItem from './components/SearchItem.vue'

View File

@ -198,6 +198,22 @@
"navigationStyle": "custom"
}
},{
"path" : "pages/index/pests",
"style" :
{
"navigationBarTitleText": "虫情监测",
"enablePullDownRefresh": false
}
},{
"path" : "pages/index/insecticidal-lamp",
"style" :
{
"navigationBarTitleText": "杀虫灯监测",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {

View File

@ -0,0 +1,246 @@
<template>
<view>
<view class="bg-white">
<SearchForm
:schemas="searchFormSchema"
@submit="handleSubmit"
></SearchForm>
</view>
<view class="h-80vh flex-center">
<view class="w-full">
<qiun-data-charts type="column" :opts="opts" :chartData="chartData" />
</view>
</view>
</view>
</template>
<script>
import SearchForm from '@/components/search-form'
import { http } from '@/api/index.js'
import { formatDataByObject } from '@/utils/index.js'
import QiunDataCharts from '@/components/qiun-data-charts/qiun-data-charts.vue'
export default {
components: {
SearchForm,
QiunDataCharts,
},
data() {
return {
filterParmas: {},
searchFormSchema: [
{
field: 'base',
label: '基地',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get(
'/api/agricultural-device-basic',
{
params: e,
}
)
return data.data
},
onOptionsChange: (options) => {
const { setFieldsValue } = formActionType
if (options.length) {
setFieldsValue({
base: options[0].value,
})
}
},
labelField: 'name',
valueField: 'id',
params: {
device_type: 5,
},
}
},
},
{
field: 'device_id',
component: 'ApiSelect',
label: '监控点',
componentProps: ({ formModel, formActionType }) => {
return {
placeholder: '监控点',
api: async (e) => {
if (e.agricultural_basic == null) return []
const { data } = await http.get(
`/api/agricultural-device-point/${e.agricultural_basic}`,
{
params: e,
}
)
return formatDataByObject(data.data)
},
onOptionsChange: (options) => {
const { setFieldsValue } = formActionType
if (options.length)
setFieldsValue({
device_id: options[0].value,
})
},
params: {
device_type: 5,
agricultural_basic: formModel.base,
},
labelField: 'label',
valueField: 'value',
}
},
},
{
field: '[start_time, end_time]',
label: '日期',
component: 'Calendar',
defaultValue: [
this.$u.timeFormat(
new Date().getTime() - 1000 * 60 * 60 * 24 * 7,
'yyyy-mm-dd'
),
this.$u.timeFormat(new Date().getTime(), 'yyyy-mm-dd'),
],
componentProps: {
mode: 'range',
placeholder: ['开始时间', '结束时间'],
},
},
],
opts: {
timing: 'easeOut',
duration: 1000,
rotate: false,
rotateLock: false,
color: [
'#1890FF',
'#91CB74',
'#FAC858',
'#EE6666',
'#73C0DE',
'#3CA272',
'#FC8452',
'#9A60B4',
'#ea7ccc',
],
padding: [15, 15, 15, 5],
fontSize: 13,
fontColor: '#666666',
dataLabel: true,
dataPointShape: true,
dataPointShapeType: 'solid',
touchMoveLimit: 60,
enableScroll: false,
enableMarkLine: false,
legend: {
show: false,
},
xAxis: {
disableGrid: true,
labelCount: 7,
rotateLabel: true,
rotateAngle: 30,
},
yAxis: {
data: [
{
min: 0,
},
],
},
extra: {
column: {
type: 'group',
width: 30,
activeBgColor: '#000000',
activeBgOpacity: 0.08,
seriesGap: 2,
categoryGap: 3,
barBorderCircle: false,
linearType: 'none',
linearOpacity: 1,
colorStop: 0,
meterBorder: 1,
meterFillColor: '#FFFFFF',
labelPosition: 'outside',
},
tooltip: {
showBox: true,
showArrow: true,
showCategory: false,
borderWidth: 0,
borderRadius: 0,
borderColor: '#000000',
borderOpacity: 0.7,
bgColor: '#000000',
bgOpacity: 0.7,
gridType: 'solid',
dashLength: 4,
gridColor: '#CCCCCC',
boxPadding: 3,
fontSize: 13,
lineHeight: 20,
fontColor: '#FFFFFF',
legendShow: true,
legendShape: 'auto',
splitLine: true,
horizentalLine: false,
xAxisLabel: false,
yAxisLabel: false,
labelBgColor: '#FFFFFF',
labelBgOpacity: 0.7,
labelFontColor: '#666666',
},
markLine: {
type: 'solid',
dashLength: 4,
data: [],
},
},
},
chartData: {},
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.getData()
},
async getData() {
if (!this.filterParmas.device_id) return
try {
const { data } = await http.get(
`/api/devices/${this.filterParmas.device_id}/worm-statics`,
{
params: this.filterParmas,
}
)
const { data: resData } = data
const xAxis = []
const seriesData = []
Object.keys(resData ?? {}).forEach((key) => {
xAxis.push(key)
seriesData.push(resData[key])
})
let res = {
categories: xAxis,
series: [
{
name: '虫情统计',
data: seriesData,
},
],
}
this.chartData = JSON.parse(JSON.stringify(res))
} catch (error) {}
},
},
}
</script>

View File

@ -0,0 +1,169 @@
<template>
<view>
<u-sticky>
<view class="bg-white">
<SearchForm
:schemas="searchFormSchema"
@submit="handleSubmit"
></SearchForm>
</view>
</u-sticky>
<mescroll-body
@init="mescrollInit"
@up="upCallback"
:up="upOption"
:down="downOption"
>
<view
class="mx-20rpx my-20rpx bg-white shadow shadow-lg"
v-for="(item, i) in dataList"
:key="i"
>
<view class="h-500rpx">
<u-image class="!h-full" :src="item.url"></u-image>
</view>
<view class="p-16rpx">时间: {{ item.time }}</view>
</view>
</mescroll-body>
</view>
</template>
<script>
import SearchForm from '@/components/search-form'
import { http } from '@/api/index.js'
import { formatDataByObject } from '@/utils/index.js'
import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js'
export default {
mixins: [MescrollMixin],
components: {
SearchForm,
},
data() {
return {
filterParmas: {},
dataList: [],
downOption: {
use: false,
},
upOption: {
auto: false,
page: {
size: 20,
},
},
searchFormSchema: [
{
field: 'base',
label: '基地',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get(
'/api/agricultural-device-basic',
{
params: e,
}
)
return data.data
},
onOptionsChange: (options) => {
const { setFieldsValue } = formActionType
if (options.length) {
setFieldsValue({
base: options[0].value,
})
}
},
labelField: 'name',
valueField: 'id',
params: {
device_type: 5,
},
}
},
},
{
field: 'device_id',
component: 'ApiSelect',
label: '监控点',
componentProps: ({ formModel, formActionType }) => {
return {
placeholder: '监控点',
api: async (e) => {
if (e.agricultural_basic == null) return []
const { data } = await http.get(
`/api/agricultural-device-point/${e.agricultural_basic}`,
{
params: e,
}
)
return formatDataByObject(data.data)
},
onOptionsChange: (options) => {
const { setFieldsValue } = formActionType
if (options.length)
setFieldsValue({
device_id: options[0].value,
})
},
params: {
device_type: 5,
agricultural_basic: formModel.base,
},
labelField: 'label',
valueField: 'value',
}
},
},
{
field: '[start_time, end_time]',
label: '日期',
component: 'Calendar',
defaultValue: [
this.$u.timeFormat(
new Date().getTime() - 1000 * 60 * 60 * 24 * 7,
'yyyy-mm-dd'
),
this.$u.timeFormat(new Date().getTime(), 'yyyy-mm-dd'),
],
componentProps: {
mode: 'range',
placeholder: ['开始时间', '结束时间'],
},
},
],
}
},
methods: {
upCallback({ num, size }) {
this.getData({
...this.filterParmas,
page: num,
per_page: size,
})
},
handleSubmit(e) {
this.filterParmas = e
this.mescroll.resetUpScroll()
},
async getData(e) {
if (!e.device_id) return
try {
const { data } = await http.get(
`/api/devices/${e.device_id}/worm-photos`,
{
params: e,
}
)
if (e.page == 1) this.dataList = []
const { data: list, meta } = data
this.dataList = this.dataList.concat(list)
this.mescroll.endByPage(list.length, meta.total)
} catch (error) {
this.mescroll.endErr()
}
},
},
}
</script>

View File

@ -50,6 +50,14 @@
label:'昆虫性诱监测',
url:'/pages/index/insect-monitors'
},
{
label:'虫情监测',
url:'/pages/index/pests'
},
{
label:'杀虫灯检测',
url:'/pages/index/insecticidal-lamp'
},
],
},
// {

View File

@ -1,12 +1,12 @@
<template>
<div>
<view>
<u-sticky>
<div class="bg-white">
<view class="bg-white">
<SearchForm
:schemas="searchFormSchema"
@submit="handleSubmit"
></SearchForm>
</div>
</view>
</u-sticky>
<mescroll-body
@init="mescrollInit"
@ -19,13 +19,13 @@
v-for="(item, i) in dataList"
:key="i"
>
<div class="h-500rpx">
<view class="h-500rpx">
<u-image class="!h-full" :src="item.url"></u-image>
</div>
<div class="p-16rpx">时间: {{ item.time }}</div>
</view>
<view class="p-16rpx">时间: {{ item.time }}</view>
</view>
</mescroll-body>
</div>
</view>
</template>
<script>
import SearchForm from '@/components/search-form'
@ -97,7 +97,6 @@ export default {
params: e,
}
)
console.log(formatDataByObject(data.data))
return formatDataByObject(data.data)
},
onOptionsChange: (options) => {
@ -122,7 +121,10 @@ export default {
label: '日期',
component: 'Calendar',
defaultValue: [
this.$u.timeFormat(new Date().getTime(), 'yyyy-mm-dd'),
this.$u.timeFormat(
new Date().getTime() - 1000 * 60 * 60 * 24 * 7,
'yyyy-mm-dd'
),
this.$u.timeFormat(new Date().getTime(), 'yyyy-mm-dd'),
],
componentProps: {

View File

@ -0,0 +1,225 @@
<template>
<view>
<u-sticky>
<view class="bg-white">
<SearchForm
:schemas="searchFormSchema"
@submit="handleSubmit"
></SearchForm>
</view>
</u-sticky>
<view>
<view
class="bg-white my-20rpx shadow shadow-lg pb-20rpx"
v-for="(item, i) in chatList"
:key="i"
>
<div class="p-20rpx text-32rpx">
{{ item.lable }}
</div>
<qiun-data-charts type="area" :opts="opts" :chartData="item.chatOpt" />
</view>
</view>
</view>
</template>
<script>
import SearchForm from '@/components/search-form'
import { http } from '@/api/index.js'
import { formatDataByObject } from '@/utils/index.js'
import QiunDataCharts from '@/components/qiun-data-charts/qiun-data-charts.vue'
const tagMenus = [
{
lable: '大气湿度',
value: 'air_humidity',
unit: '',
},
{
lable: '大气气温',
value: 'air_temperature',
unit: '',
},
{
lable: '蓄电池电压',
value: 'battery_vol',
unit: '',
},
{
lable: '充电电压',
value: 'charging_vol',
unit: '',
},
{
lable: '高压值',
value: 'high_vol',
unit: '',
},
{
lable: '杀虫数',
value: 'killed_num',
unit: '',
},
]
export default {
components: {
SearchForm,
QiunDataCharts,
},
data() {
return {
filterParmas: {},
searchFormSchema: [
{
field: 'base',
label: '基地',
component: 'ApiSelect',
componentProps: ({ formActionType }) => {
return {
api: async (e) => {
const { data } = await http.get(
'/api/agricultural-device-basic',
{
params: e,
}
)
return data.data
},
onOptionsChange: (options) => {
const { setFieldsValue } = formActionType
if (options.length) {
setFieldsValue({
base: options[0].value,
})
}
},
labelField: 'name',
valueField: 'id',
params: {
device_type: 7,
},
}
},
},
{
field: 'device_id',
component: 'ApiSelect',
label: '监控点',
componentProps: ({ formModel, formActionType }) => {
return {
placeholder: '监控点',
api: async (e) => {
if (e.agricultural_basic == null) return []
const { data } = await http.get(
`/api/agricultural-device-point/${e.agricultural_basic}`,
{
params: e,
}
)
return formatDataByObject(data.data)
},
onOptionsChange: (options) => {
const { setFieldsValue } = formActionType
if (options.length)
setFieldsValue({
device_id: options[0].value,
})
},
params: {
device_type: 7,
agricultural_basic: formModel.base,
},
labelField: 'label',
valueField: 'value',
}
},
},
{
field: '[start_time, end_time]',
label: '日期',
component: 'Calendar',
defaultValue: [
this.$u.timeFormat(
new Date().getTime() - 1000 * 60 * 60 * 24 * 7,
'yyyy-mm-dd'
),
this.$u.timeFormat(new Date().getTime(), 'yyyy-mm-dd'),
],
componentProps: {
mode: 'range',
placeholder: ['开始时间', '结束时间'],
},
},
],
chatList: [],
opts: {
dataLabel: false, //
padding: [15, 15, 15, 15],
xAxis: {
disableGrid: true,
labelCount: 7,
rotateLabel: true,
rotateAngle: 30,
},
yAxis: {
gridType: 'dash',
data: [
{
min: 0,
},
],
},
legend: {
show: false,
},
extra: {
area: {
type: 'curve',
opacity: 0.9,
addLine: true,
gradient: true,
},
},
},
}
},
methods: {
handleSubmit(e) {
this.filterParmas = e
this.getData()
},
async getData() {
this.chatList = []
if (!this.filterParmas.device_id) return
const { data } = await http.get('/api/monitoring-data', {
params: this.filterParmas,
})
const { data: resData } = data
const arr = []
Object.keys(resData).forEach((key) => {
const item = tagMenus.find((item) => item.value === key)
if (item) {
let res = {
categories: Object.keys(resData[key]).map((item) => {
return this.$u.date(item, 'yyyy-mm-dd')
}),
series: [
{
name: item.lable,
data: Object.values(resData[key]),
},
],
}
arr.push({
...item,
chatOpt: JSON.parse(JSON.stringify(res)),
})
}
})
console.log(arr)
this.chatList = arr
},
},
}
</script>

View File

@ -1,3 +1,43 @@
<template>
<div>11</div>
</template>
<view>
<u-sticky>
<view class="px-26rpx">
<u-subsection
:list="list"
::current="current"
@change="handleChangeSub"
></u-subsection>
</view>
</u-sticky>
<PestsChart v-if="current == 0"></PestsChart>
<PestsImage v-if="current == 1"></PestsImage>
</view>
</template>
<script>
import PestsChart from './components/pests-chart.vue'
import PestsImage from './components/pests-images.vue'
export default {
components: {
PestsChart,
PestsImage,
},
data() {
return {
list: [
{
name: '虫情统计',
},
{
name: '虫情图片',
},
],
current: 0,
}
},
methods: {
handleChangeSub(e) {
this.current = e
},
},
}
</script>

View File

@ -1,6 +1,6 @@
import { defineConfig } from 'windicss/helpers'
import colors from 'windicss/colors'
import plugin from 'windicss/plugin'
export default defineConfig({
darkMode: 'class',
extract: {
@ -20,5 +20,16 @@ export default defineConfig({
},
shortcuts: {
}
},
plugins: [
plugin(({ addComponents }) => {
addComponents({
'.flex-center': {
display: 'flex',
'align-items': 'center',
'justify-content': 'center',
}
})
}),
]
})