feat: 扩展 Agent 业务查询与学生增改工具

This commit is contained in:
2026-08-04 14:41:59 +08:00
parent 216a20ffaf
commit 3a1ed717d8
23 changed files with 1630 additions and 2 deletions

View File

@@ -87,6 +87,109 @@ export class ExpensesService {
return qb.getMany();
}
/**
* Agent tool: 费用查询(宿舍费 + 个人附加费),返回白名单字段。
*/
async agentSearchExpenses(query?: {
keyword?: string;
periodStart?: string;
periodEnd?: string;
limit?: number;
}): Promise<{
roomExpenses: {
id: number;
expenseType: string;
amount: number;
periodStart: string;
periodEnd: string;
roomNumber: string;
status: string;
}[];
personalExpenses: {
id: number;
expenseType: string;
amount: number;
expenseDate: string;
studentName: string;
studentNo: string;
status: string;
}[];
}> {
const limit = Math.max(1, Math.min(query?.limit ?? 10, 30));
const roomQb = this.roomExpRepo
.createQueryBuilder('e')
.leftJoin('e.room', 'room')
.select('e.id', 'id')
.addSelect('e.expenseType', 'expenseType')
.addSelect('e.amount', 'amount')
.addSelect('e.periodStart', 'periodStart')
.addSelect('e.periodEnd', 'periodEnd')
.addSelect('room.roomNumber', 'roomNumber')
.where('e.status = :status', { status: 'active' });
if (query?.keyword) {
roomQb.andWhere('room.roomNumber LIKE :keyword', { keyword: `%${query.keyword}%` });
}
if (query?.periodStart) {
roomQb.andWhere('e.periodStart >= :periodStart', { periodStart: query.periodStart });
}
if (query?.periodEnd) {
roomQb.andWhere('e.periodEnd <= :periodEnd', { periodEnd: query.periodEnd });
}
const roomRows = await roomQb
.orderBy('e.createdAt', 'DESC')
.limit(limit)
.getRawMany<Record<string, unknown>>();
const personalQb = this.personalExpRepo
.createQueryBuilder('e')
.leftJoin('e.student', 'student')
.select('e.id', 'id')
.addSelect('e.expenseType', 'expenseType')
.addSelect('e.amount', 'amount')
.addSelect('e.expenseDate', 'expenseDate')
.addSelect('student.name', 'studentName')
.addSelect('student.studentNo', 'studentNo')
.where('e.status = :status', { status: 'active' });
if (query?.keyword) {
personalQb.andWhere(
'(student.name LIKE :keyword OR student.studentNo LIKE :keyword)',
{ keyword: `%${query.keyword}%` },
);
}
if (query?.periodStart) {
personalQb.andWhere('e.expenseDate >= :periodStart', { periodStart: query.periodStart });
}
if (query?.periodEnd) {
personalQb.andWhere('e.expenseDate <= :periodEnd', { periodEnd: query.periodEnd });
}
const personalRows = await personalQb
.orderBy('e.createdAt', 'DESC')
.limit(limit)
.getRawMany<Record<string, unknown>>();
return {
roomExpenses: roomRows.map((row) => ({
id: Number(row.id),
expenseType: String(row.expenseType),
amount: Number(row.amount),
periodStart: String(row.periodStart),
periodEnd: String(row.periodEnd),
roomNumber: row.roomNumber == null ? '' : String(row.roomNumber),
status: String(row.status),
})),
personalExpenses: personalRows.map((row) => ({
id: Number(row.id),
expenseType: String(row.expenseType),
amount: Number(row.amount),
expenseDate: String(row.expenseDate),
studentName: row.studentName == null ? '' : String(row.studentName),
studentNo: row.studentNo == null ? '' : String(row.studentNo),
status: String(row.status),
})),
};
}
async deleteRoomExpense(id: number) {
const e = await this.roomExpRepo.findOne({ where: { id } });
if (!e) throw new NotFoundException('费用记录不存在');