完成统计分析

This commit is contained in:
bicey 2024-05-25 14:59:03 +08:00
parent 7e2ae9e565
commit a5de0b4987
7 changed files with 442 additions and 43 deletions

View File

@ -14,7 +14,7 @@
4. 健康监测与预警(前端基本完成,未接入后端) 4. 健康监测与预警(前端基本完成,未接入后端)
系统应具备健康监测功能,定期收集和分析动物的健康数据,如体温、心率、呼吸频率等。同时,系统应提供预警功能,当动物的健康数据出现异常时,及时提醒管理人员采取相应措施。 系统应具备健康监测功能,定期收集和分析动物的健康数据,如体温、心率、呼吸频率等。同时,系统应提供预警功能,当动物的健康数据出现异常时,及时提醒管理人员采取相应措施。
5. 统计分析(未开始 5. 统计分析(前端基本完成,无需后端
系统应提供统计分析功能,对动物信息、饲养记录、健康数据等进行统计分析,生成各类报表和图表。这有助于管理人员了解动物的整体状况和饲养效果,为决策提供支持。 系统应提供统计分析功能,对动物信息、饲养记录、健康数据等进行统计分析,生成各类报表和图表。这有助于管理人员了解动物的整体状况和饲养效果,为决策提供支持。
6. 用户权限管理(前端基本完成,未接入后端) 6. 用户权限管理(前端基本完成,未接入后端)
@ -223,7 +223,7 @@ health: {
## 统计分析 ## 统计分析
--- ---
无需后端
## 需求分析 ## 需求分析

View File

@ -3,6 +3,7 @@
/*浏览器默认margin为8px会出现滚动条的问题因此此处设置为0*/ /*浏览器默认margin为8px会出现滚动条的问题因此此处设置为0*/
body { body {
margin: 0; margin: 0;
background-color: aliceblue;
} }
/*相对定位*/ /*相对定位*/
@ -41,7 +42,7 @@ body {
/*与pages组件相关的所有样式*/ /*与pages组件相关的所有样式*/
.table { .table {
height: 506px; height: 516px;
margin: 0 30px; margin: 0 30px;
} }

View File

@ -1,8 +1,10 @@
<script> <script>
import {mapState} from "vuex"; import {mapState} from "vuex";
import {Menu, User} from "@element-plus/icons-vue";
export default { export default {
name: "ZooAside", name: "ZooAside",
components: {User, Menu},
data() { data() {
return {} return {}
}, },
@ -16,7 +18,9 @@ export default {
this.$router.push(path) this.$router.push(path)
} }
}, },
watch: {} mounted() {
console.log('auth', this.loginUser)
}
} }
</script> </script>
@ -42,30 +46,14 @@ export default {
<el-sub-menu index="1"> <el-sub-menu index="1">
<template #title="scope"> <template #title="scope">
<el-icon> <el-icon>
<location/> <Menu/>
</el-icon> </el-icon>
<span>管理员</span> <span>用户功能</span>
</template> </template>
<el-menu-item index="/panel/home" @click="toPath('/panel/home')">首页</el-menu-item> <el-menu-item index="/panel/home" @click="toPath('/panel/home')">首页</el-menu-item>
<el-menu-item index="/panel/user" @click="toPath('/panel/user')">用户管理</el-menu-item> <el-menu-item index="/panel/user" @click="toPath('/panel/user')" v-if="loginUser.auth===0">用户管理</el-menu-item>
<el-menu-item index="/panel/animal" @click="toPath('/panel/animal')">动物基本数据</el-menu-item> <el-menu-item index="/panel/animal" @click="toPath('/panel/animal')">动物基本数据</el-menu-item>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon>
<location/>
</el-icon>
<span>饲养员</span>
</template>
<el-menu-item index="/panel/breeding" @click="toPath('/panel/breeding')">饲养计划</el-menu-item> <el-menu-item index="/panel/breeding" @click="toPath('/panel/breeding')">饲养计划</el-menu-item>
</el-sub-menu>
<el-sub-menu index="3">
<template #title>
<el-icon>
<location/>
</el-icon>
<span>兽医</span>
</template>
<el-menu-item index="/panel/archive" @click="toPath('/panel/archive')">动物档案</el-menu-item> <el-menu-item index="/panel/archive" @click="toPath('/panel/archive')">动物档案</el-menu-item>
<el-menu-item index="/panel/health" @click="toPath('/panel/health')">健康检测</el-menu-item> <el-menu-item index="/panel/health" @click="toPath('/panel/health')">健康检测</el-menu-item>
</el-sub-menu> </el-sub-menu>
@ -75,6 +63,9 @@ export default {
</template> </template>
<style scoped> <style scoped>
#aside{
background-color: white;
}
.aside-icon { .aside-icon {
width: 200px; width: 200px;
margin-top: 20px; margin-top: 20px;

View File

@ -1,24 +1,412 @@
<script> <script>
import {mapState} from "vuex";
import {Minus, Plus} from "@element-plus/icons-vue";
export default { export default {
name: "ZooHome", name: "ZooHome",
data() { data() {
return { return {
adminCount: 0,
keeperCount: 0,
veterinaryCount: 0,
speciesCount: 0,
normalCount: 0,
abnormalCount: 0,
foodCount: Math.floor((Math.random() * 201)),//
foodCapacity: 200,//
breedingAnimalCount: 0,//
healthAnimalCount: 0,//
handleAnimalCount: 0,//
percentageColors: [
{color: '#f56c6c', percentage: 30},
{color: '#e6a23c', percentage: 60},
{color: '#5cb87a', percentage: 90},
],
childhoodCount: 0,//
adolescenceCount: 0,//
adulthoodCount: 0,//
oldCount: 0,//
} }
}, },
methods: { watch: {
users: {
immediate: true,
handler(value) {
this.adminCount = 0
this.keeperCount = 0
this.veterinaryCount = 0
this.users.forEach(e => {
if (e.auth === 0) {
this.adminCount++
} else if (e.auth === 1) {
this.keeperCount++
} else if (e.auth === 2) {
this.veterinaryCount++
}
})
}
},
animals: {
immediate: true,
handler(value) {
this.speciesCount = 0
const speciesSet = new Set()
this.normalCount = 0
this.abnormalCount = 0
this.childhoodCount = 0
this.adolescenceCount = 0
this.adulthoodCount = 0
this.oldCount = 0
this.animals.forEach(e => {
speciesSet.add(e.species)
if (e.state === 0) {
this.normalCount++
} else if (e.state === 1) {
this.abnormalCount++
}
if (e.phase === '幼年期') {
this.childhoodCount++
} else if (e.phase === '成长期') {
this.adolescenceCount++
} else if (e.phase === '成年期') {
this.adulthoodCount++
} else if (e.phase === '老年期') {
this.oldCount++
}
})
this.speciesCount = speciesSet.size
this.breedingAnimalCount = Number((Math.random() * this.animals.length).toFixed(0))
}
}
},
computed: {
Plus() {
return Plus
},
Minus() {
return Minus
},
...mapState(["users", 'animals']),
},
methods: {
decreaseFood() {
if (this.foodCount > 0) {
this.foodCount--
}
},
increaseFood() {
if (this.foodCount < this.foodCapacity) {
this.foodCount++
}
},
decreaseBreeding(){
if (this.breedingAnimalCount > 0) {
this.breedingAnimalCount--
}
},
increaseBreeding(){
if (this.breedingAnimalCount < this.animals.length) {
this.breedingAnimalCount++
}
},
decreaseHealth(){
if (this.healthAnimalCount > 0) {
this.healthAnimalCount--
}
},
increaseHealth(){
if (this.healthAnimalCount < this.animals.length) {
this.healthAnimalCount++
}
},
decreaseHandle(){
if (this.handleAnimalCount > 0) {
this.handleAnimalCount--
}
},
increaseHandle(){
if (this.handleAnimalCount < this.abnormalCount) {
this.handleAnimalCount++
}
}
} }
} }
</script> </script>
<template> <template>
<div> <div id="home-root">
这是home界面 <div class="statistics" style="padding-bottom: 20px">
<el-row>
<el-col :span="24">
<div class="title">用户统计</div>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-statistic title="系统用户总数" :value="users.length"/>
</el-col>
<el-col :span="6">
<el-statistic :value="adminCount" :value-style="{color:'#409EFF'}">
<template #title>
<span style="color: #409EFF">管理员数量</span>
</template>
<template #suffix>
<span style="color: #409EFF" v-if="users.length===0">(0%)</span>
<span style="color: #409EFF" v-else>
({{ (adminCount / users.length * 100).toFixed(1) }}%)
</span>
</template>
</el-statistic>
</el-col>
<el-col :span="6">
<el-statistic :value="keeperCount" :value-style="{color:'#67C23A'}">
<template #title>
<span style="color: #67C23A">饲养员数量</span>
</template>
<template #suffix>
<span style="color: #67C23A" v-if="users.length===0">(0%)</span>
<span style="color: #67C23A" v-else>
({{ (keeperCount / users.length * 100).toFixed(1) }}%)
</span>
</template>
</el-statistic>
</el-col>
<el-col :span="6">
<el-statistic :value="keeperCount" :value-style="{color:'#E6A23C'}">
<template #title>
<span style="color: #E6A23C">兽医数量</span>
</template>
<template #suffix>
<span style="color: #E6A23C" v-if="users.length===0">(0%)</span>
<span style="color: #E6A23C" v-else>
({{ (veterinaryCount / users.length * 100).toFixed(1) }}%)
</span>
</template>
</el-statistic>
</el-col>
</el-row>
</div>
<div class="statistics" style="margin-bottom: 0">
<el-row>
<el-col :span="24">
<div class="title">动物统计</div>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-row>
<el-col :span="6">
<el-statistic title="动物总数" :value="animals.length"/>
</el-col>
<el-col :span="6">
<el-statistic :value="speciesCount" title="动物种类"/>
</el-col>
<el-col :span="6">
<el-statistic :value="normalCount" :value-style="{color:'#67C23A'}">
<template #title>
<span style="color: #67C23A">健康动物</span>
</template>
<template #suffix>
<span style="color: #67C23A" v-if="animals.length===0">(0%)</span>
<span style="color: #67C23A" v-else>({{ (normalCount / animals.length * 100).toFixed(1) }}%)</span>
</template>
</el-statistic>
</el-col>
<el-col :span="6">
<el-statistic :value="abnormalCount" :value-style="{color:'#f56c6c'}">
<template #title>
<span style="color: #f56c6c">异常动物</span>
</template>
<template #suffix>
<span style="color: #f56c6c" v-if="animals.length===0">(0%)</span>
<span style="color: #f56c6c" v-else>({{ (abnormalCount / animals.length * 100).toFixed(1) }}%)</span>
</template>
</el-statistic>
</el-col>
</el-row>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div class="statistics">
<el-row>
<el-col :span="24">
<div class="title">日常统计</div>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-progress type="dashboard" :percentage="Number((breedingAnimalCount/animals.length*100).toFixed(1))"
:color="percentageColors">
<template #default="{ percentage }">
<span class="percentage-label">今日饲养进度</span>
<span class="percentage-value" v-if="!percentage">0%</span>
<span class="percentage-value" v-else>{{ percentage }}%</span>
<span class="percentage-label">{{ breedingAnimalCount }}/{{ animals.length }}</span>
<span v-if="percentage>=0">
<el-button :icon="Minus" @click="decreaseBreeding" size="small" style="width: 10px"/>
<el-button :icon="Plus" @click="increaseBreeding" size="small" style="width: 10px"/>
</span>
</template>
</el-progress>
</el-col>
<el-col :span="12">
<el-progress type="dashboard" :percentage="Number((foodCount/foodCapacity*100).toFixed(1))"
:color="percentageColors">
<template #default="{ percentage }">
<span class="percentage-label">食物库存</span>
<span class="percentage-value">{{ percentage }}%</span>
<span class="percentage-label">{{ foodCount }}/{{ foodCapacity }}</span>
<span v-if="percentage>=0">
<el-button :icon="Minus" @click="decreaseFood" size="small" style="width: 10px"/>
<el-button :icon="Plus" @click="increaseFood" size="small" style="width: 10px"/>
</span>
</template>
</el-progress>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-progress type="dashboard" :percentage="Number((healthAnimalCount/animals.length*100).toFixed(1))"
:color="percentageColors">
<template #default="{ percentage }">
<span class="percentage-label">今日监测进度</span>
<span class="percentage-value" v-if="!percentage">0%</span>
<span class="percentage-value" v-else>{{ percentage }}%</span>
<span class="percentage-label">{{ healthAnimalCount }}/{{ animals.length }}</span>
<span v-if="percentage>=0">
<el-button :icon="Minus" @click="decreaseHealth" size="small" style="width: 10px"/>
<el-button :icon="Plus" @click="increaseHealth" size="small" style="width: 10px"/>
</span>
</template>
</el-progress>
</el-col>
<el-col :span="12">
<el-progress type="dashboard" :percentage="Number((handleAnimalCount/abnormalCount*100).toFixed(1))"
:color="percentageColors">
<template #default="{ percentage }">
<span class="percentage-label">异常处理进度</span>
<span class="percentage-value" v-if="!percentage">0%</span>
<span class="percentage-value" v-else>{{ percentage }}%</span>
<span class="percentage-label">{{ handleAnimalCount }}/{{ abnormalCount }}</span>
<span v-if="percentage>=0">
<el-button :icon="Minus" @click="decreaseHandle" size="small" style="width: 10px"/>
<el-button :icon="Plus" @click="increaseHandle" size="small" style="width: 10px"/>
</span>
</template>
</el-progress>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="12">
<div class="statistics">
<el-row>
<el-col :span="24">
<div class="title">生命阶段统计</div>
</el-col>
</el-row>
<el-row style="padding: 40px 0">
<el-col :span="12">
<el-statistic :value="childhoodCount" :value-style="{color:'#67C23A'}">
<template #title>
<span style="color: #67C23A">幼年期</span>
</template>
<template #suffix>
<span style="color: #67C23A" v-if="animals.length===0">(0%)</span>
<span style="color: #67C23A" v-else>({{ (childhoodCount / animals.length * 100).toFixed(1) }}%)</span>
</template>
</el-statistic>
</el-col>
<el-col :span="12">
<el-statistic :value="adolescenceCount" :value-style="{color:'#409EFF'}">
<template #title>
<span style="color: #409EFF">成长期</span>
</template>
<template #suffix>
<span style="color: #409EFF" v-if="animals.length===0">(0%)</span>
<span style="color: #409EFF" v-else>({{ (adolescenceCount / animals.length * 100).toFixed(1) }}%)</span>
</template>
</el-statistic>
</el-col>
</el-row>
<el-row style="padding: 40px 0">
<el-col :span="12">
<el-statistic :value="adulthoodCount" :value-style="{color:'#E6A23C'}">
<template #title>
<span style="color: #E6A23C">成年期</span>
</template>
<template #suffix>
<span style="color: #E6A23C" v-if="animals.length===0">(0%)</span>
<span style="color: #E6A23C" v-else>({{ (adulthoodCount / animals.length * 100).toFixed(1) }}%)</span>
</template>
</el-statistic>
</el-col>
<el-col :span="12">
<el-statistic :value="oldCount" :value-style="{color:'#909399'}">
<template #title>
<span style="color: #909399">老年期</span>
</template>
<template #suffix>
<span style="color: #909399" v-if="animals.length===0">(0%)</span>
<span style="color: #909399" v-else>({{ (oldCount / animals.length * 100).toFixed(1) }}%)</span>
</template>
</el-statistic>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
#home-root {
margin: 20px;
background-color: white;
border: gray 1px solid;
}
.statistics {
border: darkgray 1px solid;
margin: 20px;
}
.title {
margin-top: 10px;
font-size: 20px;
}
.statistics, .title {
text-align: center;
}
.percentage-value {
display: block;
margin-top: 10px;
font-size: 28px;
}
.percentage-label {
display: block;
margin-top: 10px;
font-size: 12px;
}
.clear::after {
content: "";
clear: both;
display: block;
}
</style> </style>

View File

@ -1,6 +1,6 @@
<script> <script>
import {mapMutations,mapState,mapActions} from "vuex"; import {mapMutations, mapState, mapActions} from "vuex";
export default { export default {
name: "ZooContainer", name: "ZooContainer",
@ -10,7 +10,13 @@ export default {
form: { form: {
username: '', username: '',
password: '123456', password: '123456',
} },
picture: [
'https://www4.bing.com//th?id=OHR.BambooPanda_ZH-CN8455481760_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
'https://www4.bing.com//th?id=OHR.PolarBearCubs_ZH-CN2913942257_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
'https://www4.bing.com//th?id=OHR.WhiteEyes_ZH-CN1130380430_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp',
'https://www4.bing.com//th?id=OHR.ZebraCousins_ZH-CN8159888859_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp'
]
} }
}, },
computed: { computed: {
@ -21,7 +27,7 @@ export default {
...mapMutations(['updateLoginUser']), ...mapMutations(['updateLoginUser']),
// //
login() { login() {
console.log('登录',this.form) console.log('登录', this.form)
// //
if (!this.form.username || !this.form.password) { if (!this.form.username || !this.form.password) {
// //
@ -60,16 +66,23 @@ export default {
<template> <template>
<div id="login-root"> <div id="login-root">
<!-- 背景图片--> <!-- 背景图片-->
<el-carousel height="400px" motion-blur> <!-- <img src="https://www4.bing.com//th?id=OHR.BambooPanda_ZH-CN8455481760_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp" width="90%" height="auto" class="center"/>-->
<el-carousel-item v-for="item in 4" :key="item"> <div>
<h3 class="small justify-center" text="2xl">{{ item }}</h3> <el-carousel motion-blur height="700px" style="width: auto;">
</el-carousel-item> <el-carousel-item v-for="(item,index) in picture" :key="index" style="text-align: center">
</el-carousel> <img :src="item" width="auto" height="100%"/>
<!-- 登录表单--> </el-carousel-item>
</el-carousel>
</div>
<!-- 登录表单-->
<div class="center"> <div class="center">
<el-card style="width: 480px" shadow="always" header="登录"> <el-card style="width: 350px" shadow="always">
<el-form :model="form" label-width="auto" style="max-width: 600px"> <template #header>
<div style="text-align: center;font-size: 25px">登录</div>
</template>
<el-form :model="form" label-width="auto" style="width: 400px">
<el-form-item label="用户名"> <el-form-item label="用户名">
<el-input v-model="form.username" style="width: 240px" placeholder="请输入用户名"/> <el-input v-model="form.username" style="width: 240px" placeholder="请输入用户名"/>
</el-form-item> </el-form-item>
@ -97,6 +110,10 @@ export default {
#login-root { #login-root {
width: 100%; width: 100%;
height: 700px; height: 700px;
background-color: skyblue; background-color: aliceblue;
}
.center {
opacity: 0.95;
} }
</style> </style>

View File

@ -50,15 +50,15 @@ export default {
top: 0; top: 0;
} }
.footer { .footer {
height: 30px; height: 20px;
bottom: 0; bottom: 0;
text-align: center; text-align: center;
line-height: 30px; line-height: 20px;
background-color: lightgray; background-color: lightgray;
} }
.main { .main {
/*有footer*/ /*有footer*/
height: 606px; height: 616px;
/*没footer*/ /*没footer*/
/*height: 636px;*/ /*height: 636px;*/

View File

@ -3,7 +3,7 @@ import {copy, generateAnimals, generateArchives, generateBreedingPlans, generate
const actions = { const actions = {
//获取登录用户 //获取登录用户
getLoginUser(context, user) { getLoginUser(context, value) {
//此处接入后端登录接口验证登录用户名和密码,验证通过方可通行 //此处接入后端登录接口验证登录用户名和密码,验证通过方可通行
//密码错误 //密码错误
if (false) { if (false) {
@ -12,6 +12,8 @@ const actions = {
type: 'error', type: 'error',
}) })
} }
const user = context.state.users.find(user => user.username === value.username)
user.auth = 0
//登录成功 //登录成功
context.commit('updateLoginUser', user);//存储登录用户,这里拉取远程登录的用户作为参数 context.commit('updateLoginUser', user);//存储登录用户,这里拉取远程登录的用户作为参数
}, },