chore: commit oxfmt formatting changes and verify artifacts
This commit is contained in:
@@ -19,8 +19,12 @@ export class BillsExportService {
|
||||
/**
|
||||
* 导出账单列表为 Excel
|
||||
*/
|
||||
async exportExcel(query: { periodStart?: string; periodEnd?: string; studentId?: number; status?: string }, res: Response) {
|
||||
const qb = this.billRepo.createQueryBuilder('b')
|
||||
async exportExcel(
|
||||
query: { periodStart?: string; periodEnd?: string; studentId?: number; status?: string },
|
||||
res: Response,
|
||||
) {
|
||||
const qb = this.billRepo
|
||||
.createQueryBuilder('b')
|
||||
.leftJoinAndSelect('b.student', 'student')
|
||||
.leftJoinAndSelect('b.items', 'items')
|
||||
.orderBy('b.generatedAt', 'DESC');
|
||||
@@ -34,7 +38,8 @@ export class BillsExportService {
|
||||
const studentIds = Array.from(new Set(bills.map((b) => b.studentId)));
|
||||
const depMap = new Map<number, number>();
|
||||
if (studentIds.length > 0) {
|
||||
const deposits = await this.depositRepo.createQueryBuilder('d')
|
||||
const deposits = await this.depositRepo
|
||||
.createQueryBuilder('d')
|
||||
.where('d.studentId IN (:...ids)', { ids: studentIds })
|
||||
.andWhere('d.status = :status', { status: 'paid' })
|
||||
.getMany();
|
||||
@@ -65,7 +70,11 @@ export class BillsExportService {
|
||||
ws.getRow(1).font = { bold: true };
|
||||
ws.getRow(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE0E0E0' } };
|
||||
|
||||
const statusMap: Record<string, string> = { draft: '草稿', confirmed: '已确认', paid: '已结清' };
|
||||
const statusMap: Record<string, string> = {
|
||||
draft: '草稿',
|
||||
confirmed: '已确认',
|
||||
paid: '已结清',
|
||||
};
|
||||
for (const bill of bills) {
|
||||
const total = Number(bill.totalAmount || 0);
|
||||
const dep = Number((depMap.get(bill.studentId) || 0).toFixed(2));
|
||||
@@ -116,7 +125,10 @@ export class BillsExportService {
|
||||
}
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||
res.setHeader(
|
||||
'Content-Type',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
);
|
||||
res.setHeader('Content-Disposition', `attachment; filename=bills_${Date.now()}.xlsx`);
|
||||
await workbook.xlsx.write(res);
|
||||
res.end();
|
||||
@@ -126,11 +138,18 @@ export class BillsExportService {
|
||||
* 导出单个学生的 PDF 账单
|
||||
*/
|
||||
async exportStudentPdf(billId: number, res: Response) {
|
||||
const bill = await this.billRepo.findOne({ where: { id: billId }, relations: ['student', 'items'] });
|
||||
if (!bill) { res.status(404).json({ message: '账单不存在' }); return; }
|
||||
const bill = await this.billRepo.findOne({
|
||||
where: { id: billId },
|
||||
relations: ['student', 'items'],
|
||||
});
|
||||
if (!bill) {
|
||||
res.status(404).json({ message: '账单不存在' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询该学生的可用押金(已缴未退)
|
||||
const deposits = await this.depositRepo.createQueryBuilder('d')
|
||||
const deposits = await this.depositRepo
|
||||
.createQueryBuilder('d')
|
||||
.where('d.studentId = :sid', { sid: bill.studentId })
|
||||
.andWhere('d.status = :status', { status: 'paid' })
|
||||
.getMany();
|
||||
@@ -146,12 +165,12 @@ export class BillsExportService {
|
||||
|
||||
// 注册中文字体(优先使用系统字体,兼容 macOS 和 Linux)
|
||||
const fontPaths = [
|
||||
'/System/Library/Fonts/PingFang.ttc', // macOS
|
||||
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', // Linux Noto
|
||||
'/System/Library/Fonts/PingFang.ttc', // macOS
|
||||
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc', // Linux Noto
|
||||
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc',
|
||||
'/usr/share/fonts/google-noto-cjk/NotoSansCJK-Regular.ttc',
|
||||
'/usr/share/fonts/noto-cjk/NotoSansSC-Regular.otf',
|
||||
'/usr/share/fonts/wqy-microhei/wqy-microhei.ttc', // Linux WenQuanYi
|
||||
'/usr/share/fonts/wqy-microhei/wqy-microhei.ttc', // Linux WenQuanYi
|
||||
'/usr/share/fonts/truetype/wqy/wqy-microhei.ttc',
|
||||
];
|
||||
let fontRegistered = false;
|
||||
@@ -171,12 +190,19 @@ export class BillsExportService {
|
||||
doc.font('Helvetica');
|
||||
}
|
||||
|
||||
const statusMap: Record<string, string> = { draft: '草稿', confirmed: '已确认', paid: '已结清' };
|
||||
const statusMap: Record<string, string> = {
|
||||
draft: '草稿',
|
||||
confirmed: '已确认',
|
||||
paid: '已结清',
|
||||
};
|
||||
|
||||
// 标题
|
||||
doc.fontSize(20).text('恭学教育基地水电费账单', { align: 'center' });
|
||||
doc.moveDown(0.5);
|
||||
doc.fontSize(10).fillColor('#666').text(`生成时间: ${new Date().toLocaleString('zh-CN')}`, { align: 'center' });
|
||||
doc
|
||||
.fontSize(10)
|
||||
.fillColor('#666')
|
||||
.text(`生成时间: ${new Date().toLocaleString('zh-CN')}`, { align: 'center' });
|
||||
doc.moveDown(1);
|
||||
|
||||
// 基本信息
|
||||
@@ -192,12 +218,24 @@ export class BillsExportService {
|
||||
doc.fontSize(12);
|
||||
doc.text(`分摊费用: ¥${Number(bill.sharedAmount).toFixed(2)}`);
|
||||
doc.text(`个人费用: ¥${Number(bill.personalAmount).toFixed(2)}`);
|
||||
doc.fontSize(14).fillColor('#007AFF').text(`应付总额: ¥${totalAmount.toFixed(2)}`);
|
||||
doc
|
||||
.fontSize(14)
|
||||
.fillColor('#007AFF')
|
||||
.text(`应付总额: ¥${totalAmount.toFixed(2)}`);
|
||||
doc.moveDown(0.3);
|
||||
if (availableDeposit > 0) {
|
||||
doc.fontSize(11).fillColor('#52C41A').text(`可用押金: ¥${availableDeposit.toFixed(2)}`);
|
||||
doc.fontSize(11).fillColor('#FA8C16').text(`押金抵扣: -¥${depositApplied.toFixed(2)}`);
|
||||
doc.fontSize(14).fillColor('#FF3B30').text(`抵扣后应付: ¥${amountAfterDeposit.toFixed(2)}`);
|
||||
doc
|
||||
.fontSize(11)
|
||||
.fillColor('#52C41A')
|
||||
.text(`可用押金: ¥${availableDeposit.toFixed(2)}`);
|
||||
doc
|
||||
.fontSize(11)
|
||||
.fillColor('#FA8C16')
|
||||
.text(`押金抵扣: -¥${depositApplied.toFixed(2)}`);
|
||||
doc
|
||||
.fontSize(14)
|
||||
.fillColor('#FF3B30')
|
||||
.text(`抵扣后应付: ¥${amountAfterDeposit.toFixed(2)}`);
|
||||
}
|
||||
doc.moveDown(1);
|
||||
|
||||
@@ -226,16 +264,23 @@ export class BillsExportService {
|
||||
const y = doc.y;
|
||||
x = 50;
|
||||
doc.fontSize(9).fillColor('#000');
|
||||
doc.text(item.expenseType || '', x, y, { width: colWidths[0] }); x += colWidths[0];
|
||||
doc.text(item.description || '', x, y, { width: colWidths[1] }); x += colWidths[1];
|
||||
doc.text(String(item.days || 0), x, y, { width: colWidths[2] }); x += colWidths[2];
|
||||
doc.text(String(item.totalRoomDays || 0), x, y, { width: colWidths[3] }); x += colWidths[3];
|
||||
doc.text(item.expenseType || '', x, y, { width: colWidths[0] });
|
||||
x += colWidths[0];
|
||||
doc.text(item.description || '', x, y, { width: colWidths[1] });
|
||||
x += colWidths[1];
|
||||
doc.text(String(item.days || 0), x, y, { width: colWidths[2] });
|
||||
x += colWidths[2];
|
||||
doc.text(String(item.totalRoomDays || 0), x, y, { width: colWidths[3] });
|
||||
x += colWidths[3];
|
||||
doc.text(Number(item.studentAmount).toFixed(2), x, y, { width: colWidths[4] });
|
||||
doc.moveDown(0.8);
|
||||
}
|
||||
|
||||
doc.moveDown(2);
|
||||
doc.fontSize(8).fillColor('#999').text('本账单由恭学教育基地管理系统自动生成', { align: 'center' });
|
||||
doc
|
||||
.fontSize(8)
|
||||
.fillColor('#999')
|
||||
.text('本账单由恭学教育基地管理系统自动生成', { align: 'center' });
|
||||
|
||||
doc.end();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import { Controller, Get, Post, Put, Delete, Param, Body, Query, UseGuards, Request, Res, Req } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Param,
|
||||
Body,
|
||||
Query,
|
||||
UseGuards,
|
||||
Request,
|
||||
Res,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import { BillsService } from './bills.service';
|
||||
import { BillsExportService } from './bills-export.service';
|
||||
import { GenerateBillsDto, UpdateBillStatusDto } from './dto/bill.dto';
|
||||
@@ -11,14 +24,26 @@ import type { Response } from 'express';
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('bills')
|
||||
export class BillsController {
|
||||
constructor(private service: BillsService, private exportService: BillsExportService, private logService: OperationLogsService) {}
|
||||
constructor(
|
||||
private service: BillsService,
|
||||
private exportService: BillsExportService,
|
||||
private logService: OperationLogsService,
|
||||
) {}
|
||||
|
||||
@Post('generate')
|
||||
@RequirePermission('bill:generate')
|
||||
async generateBills(@Body() dto: GenerateBillsDto, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.generateBills(dto);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '账单', action: '生成账单', detail: `周期 ${dto.periodStart}~${dto.periodEnd}, 生成 ${result.count} 条`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单',
|
||||
action: '生成账单',
|
||||
detail: `周期 ${dto.periodStart}~${dto.periodEnd}, 生成 ${result.count} 条`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -31,7 +56,8 @@ export class BillsController {
|
||||
@Query('status') status?: string,
|
||||
) {
|
||||
return this.service.findAll({
|
||||
periodStart, periodEnd,
|
||||
periodStart,
|
||||
periodEnd,
|
||||
studentId: studentId ? +studentId : undefined,
|
||||
status,
|
||||
});
|
||||
@@ -45,10 +71,23 @@ export class BillsController {
|
||||
|
||||
@Put(':id/status')
|
||||
@RequirePermission('bill:confirm')
|
||||
async updateStatus(@Param('id') id: string, @Body() dto: UpdateBillStatusDto, @Request() req: any) {
|
||||
async updateStatus(
|
||||
@Param('id') id: string,
|
||||
@Body() dto: UpdateBillStatusDto,
|
||||
@Request() req: any,
|
||||
) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.updateStatus(+id, dto);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '账单', action: `状态变更为${dto.status}`, targetId: +id, targetType: 'bill', ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单',
|
||||
action: `状态变更为${dto.status}`,
|
||||
targetId: +id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -57,7 +96,15 @@ export class BillsController {
|
||||
async batchUpdateStatus(@Body() body: { ids: number[]; status: string }, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.batchUpdateStatus(body.ids, body.status);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '账单', action: `批量状态变更为${body.status}`, detail: `IDs: ${body.ids.join(',')}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单',
|
||||
action: `批量状态变更为${body.status}`,
|
||||
detail: `IDs: ${body.ids.join(',')}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -66,7 +113,16 @@ export class BillsController {
|
||||
async remove(@Param('id') id: string, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.remove(+id);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '账单', action: '删除账单', targetId: +id, targetType: 'bill', ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单',
|
||||
action: '删除账单',
|
||||
targetId: +id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -75,7 +131,15 @@ export class BillsController {
|
||||
async batchRemove(@Body() body: { ids: number[] }, @Request() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
const result = await this.service.batchRemove(body.ids);
|
||||
await this.logService.log({ userId: req.user?.id, username: req.user?.username, module: '账单', action: '批量删除账单', detail: `IDs: ${body.ids.join(',')}`, ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req.user?.id,
|
||||
username: req.user?.username,
|
||||
module: '账单',
|
||||
action: '批量删除账单',
|
||||
detail: `IDs: ${body.ids.join(',')}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -90,19 +154,40 @@ export class BillsController {
|
||||
@Req() req?: any,
|
||||
) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
await this.logService.log({ userId: req?.user?.id, username: req?.user?.username, module: '账单', action: '导出Excel', detail: `筛选: 周期${periodStart || '全部'}~${periodEnd || '全部'}, 状态${status || '全部'}`, ipAddress, userAgent });
|
||||
return this.exportService.exportExcel({
|
||||
periodStart, periodEnd,
|
||||
studentId: studentId ? +studentId : undefined,
|
||||
status,
|
||||
}, res!);
|
||||
await this.logService.log({
|
||||
userId: req?.user?.id,
|
||||
username: req?.user?.username,
|
||||
module: '账单',
|
||||
action: '导出Excel',
|
||||
detail: `筛选: 周期${periodStart || '全部'}~${periodEnd || '全部'}, 状态${status || '全部'}`,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return this.exportService.exportExcel(
|
||||
{
|
||||
periodStart,
|
||||
periodEnd,
|
||||
studentId: studentId ? +studentId : undefined,
|
||||
status,
|
||||
},
|
||||
res!,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('export/pdf/:id')
|
||||
@RequirePermission('bill:export-pdf')
|
||||
async exportPdf(@Param('id') id: string, @Res() res: Response, @Req() req: any) {
|
||||
const { ipAddress, userAgent } = extractRequestInfo(req);
|
||||
await this.logService.log({ userId: req?.user?.id, username: req?.user?.username, module: '账单', action: '导出PDF', targetId: +id, targetType: 'bill', ipAddress, userAgent });
|
||||
await this.logService.log({
|
||||
userId: req?.user?.id,
|
||||
username: req?.user?.username,
|
||||
module: '账单',
|
||||
action: '导出PDF',
|
||||
targetId: +id,
|
||||
targetType: 'bill',
|
||||
ipAddress,
|
||||
userAgent,
|
||||
});
|
||||
return this.exportService.exportStudentPdf(+id, res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,17 @@ import { BillsExportService } from './bills-export.service';
|
||||
import { BillsController } from './bills.controller';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Bill, BillItem, RoomExpense, PersonalExpense, Occupancy, Room, Deposit])],
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
Bill,
|
||||
BillItem,
|
||||
RoomExpense,
|
||||
PersonalExpense,
|
||||
Occupancy,
|
||||
Room,
|
||||
Deposit,
|
||||
]),
|
||||
],
|
||||
controllers: [BillsController],
|
||||
providers: [BillsService, BillsExportService],
|
||||
exports: [BillsService],
|
||||
|
||||
@@ -37,13 +37,25 @@ export class BillsService {
|
||||
});
|
||||
if (existingDrafts.length > 0) {
|
||||
const draftIds = existingDrafts.map((b) => b.id);
|
||||
await this.itemRepo.createQueryBuilder().delete().where('billId IN (:...ids)', { ids: draftIds }).execute();
|
||||
await this.billRepo.createQueryBuilder().delete().where('id IN (:...ids)', { ids: draftIds }).execute();
|
||||
await this.itemRepo
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.where('billId IN (:...ids)', { ids: draftIds })
|
||||
.execute();
|
||||
await this.billRepo
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.where('id IN (:...ids)', { ids: draftIds })
|
||||
.execute();
|
||||
}
|
||||
|
||||
// 获取所有有费用的宿舍
|
||||
const roomExpenses = await this.roomExpRepo.createQueryBuilder('e')
|
||||
.where('e.periodStart = :periodStart AND e.periodEnd = :periodEnd', { periodStart, periodEnd })
|
||||
const roomExpenses = await this.roomExpRepo
|
||||
.createQueryBuilder('e')
|
||||
.where('e.periodStart = :periodStart AND e.periodEnd = :periodEnd', {
|
||||
periodStart,
|
||||
periodEnd,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
// 按宿舍分组费用
|
||||
@@ -58,7 +70,8 @@ export class BillsService {
|
||||
|
||||
for (const [roomId, expenses] of roomExpMap) {
|
||||
// 获取该宿舍在此周期内的所有入住记录
|
||||
const occupancies = await this.occRepo.createQueryBuilder('o')
|
||||
const occupancies = await this.occRepo
|
||||
.createQueryBuilder('o')
|
||||
.leftJoinAndSelect('o.student', 'student')
|
||||
.where('o.roomId = :roomId', { roomId })
|
||||
.andWhere('o.billingStartDate <= :periodEnd', { periodEnd })
|
||||
@@ -72,11 +85,16 @@ export class BillsService {
|
||||
let totalDays = 0;
|
||||
|
||||
for (const occ of occupancies) {
|
||||
const start = new Date(Math.max(new Date(occ.billingStartDate).getTime(), pStart.getTime()));
|
||||
const start = new Date(
|
||||
Math.max(new Date(occ.billingStartDate).getTime(), pStart.getTime()),
|
||||
);
|
||||
const end = occ.billingEndDate
|
||||
? new Date(Math.min(new Date(occ.billingEndDate).getTime(), pEnd.getTime()))
|
||||
: pEnd;
|
||||
const days = Math.max(0, Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1);
|
||||
const days = Math.max(
|
||||
0,
|
||||
Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1,
|
||||
);
|
||||
studentDays.push({ studentId: occ.studentId, days });
|
||||
totalDays += days;
|
||||
}
|
||||
@@ -107,8 +125,12 @@ export class BillsService {
|
||||
}
|
||||
|
||||
// 获取个人附加费
|
||||
const personalExps = await this.personalExpRepo.createQueryBuilder('pe')
|
||||
.where('pe.expenseDate >= :periodStart AND pe.expenseDate <= :periodEnd', { periodStart, periodEnd })
|
||||
const personalExps = await this.personalExpRepo
|
||||
.createQueryBuilder('pe')
|
||||
.where('pe.expenseDate >= :periodStart AND pe.expenseDate <= :periodEnd', {
|
||||
periodStart,
|
||||
periodEnd,
|
||||
})
|
||||
.getMany();
|
||||
|
||||
const personalMap = new Map<number, number>();
|
||||
@@ -162,8 +184,14 @@ export class BillsService {
|
||||
return { message: `成功生成 ${bills.length} 条账单`, count: bills.length, bills };
|
||||
}
|
||||
|
||||
async findAll(query?: { periodStart?: string; periodEnd?: string; studentId?: number; status?: string }) {
|
||||
const qb = this.billRepo.createQueryBuilder('b')
|
||||
async findAll(query?: {
|
||||
periodStart?: string;
|
||||
periodEnd?: string;
|
||||
studentId?: number;
|
||||
status?: string;
|
||||
}) {
|
||||
const qb = this.billRepo
|
||||
.createQueryBuilder('b')
|
||||
.leftJoinAndSelect('b.student', 'student')
|
||||
.orderBy('b.generatedAt', 'DESC');
|
||||
if (query?.periodStart) qb.andWhere('b.periodStart = :ps', { ps: query.periodStart });
|
||||
@@ -191,7 +219,8 @@ export class BillsService {
|
||||
if (!bills || bills.length === 0) return bills;
|
||||
const studentIds = Array.from(new Set(bills.map((b) => b.studentId)));
|
||||
if (studentIds.length === 0) return bills;
|
||||
const deposits = await this.depositRepo.createQueryBuilder('d')
|
||||
const deposits = await this.depositRepo
|
||||
.createQueryBuilder('d')
|
||||
.where('d.studentId IN (:...ids)', { ids: studentIds })
|
||||
.andWhere('d.status = :status', { status: 'paid' })
|
||||
.getMany();
|
||||
@@ -220,7 +249,12 @@ export class BillsService {
|
||||
}
|
||||
|
||||
async batchUpdateStatus(ids: number[], status: string) {
|
||||
await this.billRepo.createQueryBuilder().update().set({ status }).where('id IN (:...ids)', { ids }).execute();
|
||||
await this.billRepo
|
||||
.createQueryBuilder()
|
||||
.update()
|
||||
.set({ status })
|
||||
.where('id IN (:...ids)', { ids })
|
||||
.execute();
|
||||
return { message: `成功更新 ${ids.length} 条账单状态` };
|
||||
}
|
||||
|
||||
@@ -233,7 +267,11 @@ export class BillsService {
|
||||
}
|
||||
|
||||
async batchRemove(ids: number[]) {
|
||||
await this.itemRepo.createQueryBuilder().delete().where('billId IN (:...ids)', { ids }).execute();
|
||||
await this.itemRepo
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.where('billId IN (:...ids)', { ids })
|
||||
.execute();
|
||||
await this.billRepo.createQueryBuilder().delete().where('id IN (:...ids)', { ids }).execute();
|
||||
return { message: `成功删除 ${ids.length} 条账单` };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user