- 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
88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
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)
|
|
}
|
|
})
|