feat: 知识点软删除 + 批量删除接口
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 41s

- DELETE /knowledge-items/:id 软删除(设 deletedAt)
- POST /knowledge-items/batch-delete 批量软删除
- softDelete 校验归属权 + 自动更新父KB的itemCount

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-05-27 22:47:22 +08:00
parent b5de001dbb
commit c331d08644
3 changed files with 54 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import { Controller, Get, Post, Patch, Body, Param, Query } from '@nestjs/common'; import { Controller, Get, Post, Patch, Delete, Body, Param, Query, HttpCode, HttpStatus } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { KnowledgeItemsService } from './knowledge-items.service'; import { KnowledgeItemsService } from './knowledge-items.service';
import { CurrentUser } from '../../common/decorators/current-user.decorator'; import { CurrentUser } from '../../common/decorators/current-user.decorator';
@ -32,4 +32,20 @@ export class KnowledgeItemsController {
async update(@Param('id') id: string, @Body() body: any) { async update(@Param('id') id: string, @Body() body: any) {
return this.service.update(id, body); return this.service.update(id, body);
} }
@Delete(':id')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '软删除知识点' })
async delete(@CurrentUser() user: UserPayload, @Param('id') id: string) {
await this.service.softDelete(id, String(user?.id || 'anonymous'));
return { success: true, message: '已删除' };
}
@Post('batch-delete')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '批量软删除知识点' })
async batchDelete(@CurrentUser() user: UserPayload, @Body() body: { ids: string[] }) {
const count = await this.service.batchSoftDelete(body.ids || [], String(user?.id || 'anonymous'));
return { success: true, message: `已删除 ${count} 个知识点`, count };
}
} }

View File

@ -50,4 +50,19 @@ export class KnowledgeItemsRepository {
data: dto, data: dto,
}); });
} }
async softDelete(id: string) {
const item = await this.prisma.knowledgeItem.update({
where: { id },
data: { deletedAt: new Date() },
});
// 更新知识库 itemCount
await this.prisma.knowledgeBase.update({
where: { id: item.knowledgeBaseId },
data: { itemCount: { decrement: 1 } },
});
return item;
}
} }

View File

@ -1,4 +1,4 @@
import { Injectable, NotFoundException } from '@nestjs/common'; import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';
import { KnowledgeItemsRepository } from './knowledge-items.repository'; import { KnowledgeItemsRepository } from './knowledge-items.repository';
@Injectable() @Injectable()
@ -24,4 +24,25 @@ export class KnowledgeItemsService {
if (!item) throw new NotFoundException('知识点不存在'); if (!item) throw new NotFoundException('知识点不存在');
return item; return item;
} }
async softDelete(id: string, userId: string) {
const item = await this.repository.findById(id);
if (!item) throw new NotFoundException('知识点不存在');
if (item.userId !== userId) throw new ForbiddenException('无权操作');
return this.repository.softDelete(id);
}
async batchSoftDelete(ids: string[], userId: string) {
if (!ids.length) return 0;
let count = 0;
for (const id of ids) {
try {
await this.softDelete(id, userId);
count++;
} catch {
// 跳过不存在的或无权操作的
}
}
return count;
}
} }