feat: 集成 AI 对话与只读查询工具

This commit is contained in:
2026-07-23 14:24:40 +08:00
parent 302dbe0621
commit f3b59935d6
52 changed files with 4942 additions and 4 deletions

View File

@@ -36,5 +36,6 @@ import { DashboardController } from './dashboard.controller';
],
controllers: [DashboardController],
providers: [DashboardService],
exports: [DashboardService],
})
export class DashboardModule {}

View File

@@ -15,6 +15,11 @@ import { ClassroomRental } from '../entities/classroom-rental.entity';
import { ClassTeacher } from '../entities/class-teacher.entity';
import { ClassStudent } from '../entities/class-student.entity';
interface AgentAttendanceStatusRow {
status: string;
count: string | number;
}
@Injectable()
export class DashboardService {
constructor(
@@ -39,6 +44,32 @@ export class DashboardService {
return [...new Set(assignments.map((assignment) => assignment.classId))];
}
async agentGetDashboardStats(userId: number, canManageAll: boolean) {
const accessibleClassIds = await this.getAccessibleClassIds(userId, canManageAll);
const today = this.getChinaDate(new Date());
const totalStudents = accessibleClassIds
? await this.countStudentsInClasses(accessibleClassIds)
: await this.studentRepo.count({ where: { status: 'active' } });
const classCount = accessibleClassIds ? accessibleClassIds.length : await this.classRepo.count({ where: { isArchived: false } });
const attendanceQb = this.attendanceRepo
.createQueryBuilder('attendance')
.select('attendance.status', 'status')
.addSelect('COUNT(attendance.id)', 'count')
.where('attendance.attendanceDate = :today', { today });
this.applyClassScope(attendanceQb, 'attendance', accessibleClassIds);
const rows = await attendanceQb.groupBy('attendance.status').getRawMany<AgentAttendanceStatusRow>();
const attendanceByStatus = rows.reduce((result, row) => {
result[String(row.status)] = Number(row.count || 0);
return result;
}, {} as Record<string, number>);
const attendanceTotal = Object.values(attendanceByStatus).reduce<number>(
(sum, count) => sum + Number(count),
0,
);
const present = attendanceByStatus.present ?? 0;
return { date: today, totalStudents, classCount, attendanceTotal, present, attendanceRate: attendanceTotal ? Number(((present / attendanceTotal) * 100).toFixed(1)) : 0, attendanceByStatus };
}
async getStats(accessibleClassIds?: number[]) {
const todayStr = this.getChinaDate(new Date());
const currentMonth = todayStr.slice(0, 7); // YYYY-MM