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

@@ -12,6 +12,17 @@ import { CancelBillDto, GenerateBillsDto, UpdateBillStatusDto } from './dto/bill
import { WalletsService } from '../wallets/wallets.service';
import { FinancialOperationsService } from '../financial-operations/financial-operations.service';
interface AgentBillRow {
billId: string | number;
studentName: string;
periodStart: string;
periodEnd: string;
totalAmount: string | number;
paidAmount: string | number;
outstandingAmount: string | number;
status: string;
}
@Injectable()
export class BillsService {
@@ -311,6 +322,42 @@ export class BillsService {
return this.attachDepositInfo(bills);
}
async agentSearchBills(query: {
keyword?: string; periodStart?: string; periodEnd?: string; status?: string; limit?: number;
}) {
const qb = this.billRepo
.createQueryBuilder('bill')
.leftJoin('bill.student', 'student')
.select('bill.id', 'billId')
.addSelect('student.name', 'studentName')
.addSelect('bill.periodStart', 'periodStart')
.addSelect('bill.periodEnd', 'periodEnd')
.addSelect('bill.totalAmount', 'totalAmount')
.addSelect('bill.paidAmount', 'paidAmount')
.addSelect('bill.outstandingAmount', 'outstandingAmount')
.addSelect('bill.status', 'status');
if (query.keyword) {
const billId = Number(query.keyword);
if (Number.isInteger(billId) && billId > 0) {
qb.andWhere('(student.name LIKE :keyword OR bill.id = :billId)', {
keyword: `%${query.keyword}%`,
billId,
});
} else {
qb.andWhere('student.name LIKE :keyword', { keyword: `%${query.keyword}%` });
}
}
if (query.periodStart) qb.andWhere('bill.periodStart >= :periodStart', { periodStart: query.periodStart });
if (query.periodEnd) qb.andWhere('bill.periodEnd <= :periodEnd', { periodEnd: query.periodEnd });
if (query.status) qb.andWhere('bill.status = :status', { status: query.status });
const rows = await qb.orderBy('bill.generatedAt', 'DESC').limit(query.limit ?? 20).getRawMany<AgentBillRow>();
return rows.map((row) => ({
...row,
billId: Number(row.billId), totalAmount: Number(row.totalAmount || 0),
paidAmount: Number(row.paidAmount || 0), outstandingAmount: Number(row.outstandingAmount || 0),
}));
}
async findOne(id: number) {
const bill = await this.billRepo.findOne({ where: { id }, relations: ['student', 'items'] });
if (!bill) throw new NotFoundException('账单不存在');