feat: initial commit with Nuxt 3 student management system
- Add Nuxt 3 + Prisma + SQLite full-stack setup - Add student CRUD API with batch import/export - Add stats dashboard with gender/class distribution - Add target community settings feature - Add Docker deployment support (Dockerfile + docker-compose) - Add README with development and deployment instructions
This commit is contained in:
87
server/api/stats/index.get.ts
Normal file
87
server/api/stats/index.get.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { prisma, defaultCommunities } from '~/server/utils/prisma'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const students = await prisma.student.findMany()
|
||||
|
||||
// 获取设置的目标小区
|
||||
const settings = await prisma.settings.findMany({
|
||||
where: { key: 'targetCommunities' }
|
||||
})
|
||||
const targetCommunities = settings.length > 0
|
||||
? JSON.parse(settings[0].value)
|
||||
: defaultCommunities
|
||||
|
||||
// 基础统计
|
||||
const total = students.length
|
||||
const genderStats = {
|
||||
male: students.filter(s => s.gender === '男').length,
|
||||
female: students.filter(s => s.gender === '女').length
|
||||
}
|
||||
|
||||
// 班级统计
|
||||
const classStats: Record<string, { count: number; male: number; female: number }> = {}
|
||||
students.forEach(s => {
|
||||
if (!classStats[s.className]) {
|
||||
classStats[s.className] = { count: 0, male: 0, female: 0 }
|
||||
}
|
||||
classStats[s.className].count++
|
||||
if (s.gender === '男') classStats[s.className].male++
|
||||
else if (s.gender === '女') classStats[s.className].female++
|
||||
})
|
||||
|
||||
// 年龄段统计
|
||||
const currentYear = new Date().getFullYear()
|
||||
const ageGroups = {
|
||||
'3岁以下': 0,
|
||||
'3-4岁': 0,
|
||||
'4-5岁': 0,
|
||||
'5-6岁': 0,
|
||||
'6岁以上': 0
|
||||
}
|
||||
students.forEach(s => {
|
||||
if (!s.birthday) return
|
||||
const birthYear = parseInt(s.birthday.substring(0, 4))
|
||||
if (isNaN(birthYear)) return
|
||||
const age = currentYear - birthYear
|
||||
if (age < 3) ageGroups['3岁以下']++
|
||||
else if (age < 4) ageGroups['3-4岁']++
|
||||
else if (age < 5) ageGroups['4-5岁']++
|
||||
else if (age <= 6) ageGroups['5-6岁']++
|
||||
else ageGroups['6岁以上']++
|
||||
})
|
||||
|
||||
// 目标小区统计
|
||||
const addressStats: Record<string, { count: number; male: number; female: number }> = {}
|
||||
targetCommunities.forEach(name => {
|
||||
addressStats[name] = { count: 0, male: 0, female: 0 }
|
||||
})
|
||||
students.forEach(s => {
|
||||
if (!s.address) return
|
||||
targetCommunities.forEach(community => {
|
||||
if (s.address.includes(community)) {
|
||||
addressStats[community].count++
|
||||
if (s.gender === '男') addressStats[community].male++
|
||||
else if (s.gender === '女') addressStats[community].female++
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const filteredAddressStats = Object.entries(addressStats)
|
||||
.filter(([_, v]) => v.count > 0)
|
||||
.map(([name, v]) => ({ name, ...v }))
|
||||
.sort((a, b) => b.count - a.count)
|
||||
|
||||
const targetCommunityTotal = filteredAddressStats.reduce((sum, s) => sum + s.count, 0)
|
||||
|
||||
return {
|
||||
total,
|
||||
genderStats,
|
||||
classStats: Object.entries(classStats).map(([name, v]) => ({ name, ...v })),
|
||||
ageGroups,
|
||||
targetCommunities,
|
||||
addressStats: filteredAddressStats,
|
||||
targetCommunityTotal,
|
||||
targetCommunityMale: filteredAddressStats.reduce((sum, s) => sum + s.male, 0),
|
||||
targetCommunityFemale: filteredAddressStats.reduce((sum, s) => sum + s.female, 0)
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user