Ver Fonte

增强鱼类和鱼友控制器的记录查找逻辑,支持包括已删除记录的查询;在实体中新增 delFlag 字段以标记删除状态,并在服务中实现相关的删除和恢复功能,确保数据管理的灵活性和完整性。

wuyi há 3 meses atrás
pai
commit
671d94b19e

+ 2 - 2
src/controllers/fish-friends.controller.ts

@@ -19,9 +19,9 @@ export class FishFriendsController {
     try {
       const fishFriendsData = request.body
 
-      // 检查是否已存在相同 ID 的记录
+      // 检查是否已存在相同 ID 的记录(包括已删除的记录)
       try {
-        await this.fishFriendsService.findById(fishFriendsData.id)
+        await this.fishFriendsService.findByIdIncludeDeleted(fishFriendsData.id)
         return reply.code(400).send({ message: '记录已存在' })
       } catch (error) {
         // 记录不存在,可以继续创建

+ 2 - 2
src/controllers/fish.controller.ts

@@ -40,10 +40,10 @@ export class FishController {
         fishData.ip = getClientIP(request)
       }
 
-      // 检查用户是否存在
+      // 检查用户是否存在(包括已删除的记录)
       let existingFish: any = null
       try {
-        existingFish = await this.fishService.findById(fishData.id as string)
+        existingFish = await this.fishService.findByIdIncludeDeleted(fishData.id as string)
       } catch (error) {
         this.app.log.debug(`Fish with id ${fishData.id} not found, will create new record`)
       }

+ 6 - 1
src/entities/fish-friends.entity.ts

@@ -1,6 +1,8 @@
-import { Entity, PrimaryColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm'
+import { Entity, PrimaryColumn, Column, CreateDateColumn, UpdateDateColumn, Index } from 'typeorm'
 
 @Entity()
+@Index(['delFlag'])
+@Index(['delFlag', 'ownerId'])
 export class FishFriends {
   @PrimaryColumn({ type: 'bigint' })
   id: string
@@ -26,6 +28,9 @@ export class FishFriends {
   @Column({ nullable: true })
   remark: string
 
+  @Column({ default: false })
+  delFlag: boolean
+
   @CreateDateColumn()
   createdAt: Date
 

+ 7 - 1
src/entities/fish.entity.ts

@@ -1,4 +1,4 @@
-import { Entity, PrimaryGeneratedColumn, Column, UpdateDateColumn, CreateDateColumn, PrimaryColumn } from 'typeorm'
+import { Entity, PrimaryGeneratedColumn, Column, UpdateDateColumn, CreateDateColumn, PrimaryColumn, Index } from 'typeorm'
 export enum ResultEnum {
   Success = 'success',
   Tagged = 'tagged',
@@ -6,6 +6,9 @@ export enum ResultEnum {
 }
 
 @Entity()
+@Index(['delFlag', 'ownerId'])
+@Index(['delFlag', 'result'])
+@Index(['delFlag', 'createdAt'])
 export class Fish {
   @PrimaryColumn({ type: 'bigint' })
   id: string
@@ -43,6 +46,9 @@ export class Fish {
   @Column({ nullable: true })
   remark: string
 
+  @Column({ default: false })
+  delFlag: boolean
+
   @CreateDateColumn()
   createdAt: Date
 

+ 24 - 10
src/services/fish-friends.service.ts

@@ -18,25 +18,29 @@ export class FishFriendsService {
   }
 
   async findById(id: string): Promise<FishFriends> {
+    return this.fishFriendsRepository.findOneOrFail({ where: { id, delFlag: false } })
+  }
+
+  async findByIdIncludeDeleted(id: string): Promise<FishFriends> {
     return this.fishFriendsRepository.findOneOrFail({ where: { id } })
   }
 
   async findByFishId(fishId: string): Promise<FishFriends[]> {
-    return this.fishFriendsRepository.find({ where: { fishId } })
+    return this.fishFriendsRepository.find({ where: { fishId, delFlag: false } })
   }
 
   async findByOwnerId(ownerId: number): Promise<FishFriends[]> {
-    return this.fishFriendsRepository.find({ where: { ownerId } })
+    return this.fishFriendsRepository.find({ where: { ownerId, delFlag: false } })
   }
 
   async findByTgUsername(tgUsername: string): Promise<FishFriends[]> {
-    return this.fishFriendsRepository.find({ where: { tgUsername } })
+    return this.fishFriendsRepository.find({ where: { tgUsername, delFlag: false } })
   }
 
   async list(query: ListFishFriendsQuery): Promise<PaginationResponse<Partial<FishFriends>>> {
     const { page, size, id, fishId, ownerId, tgName, tgUsername, tgRemarkName, tgPhone, remark, createdAt } = query
 
-    const whereConditions: any = {}
+    const whereConditions: any = { delFlag: false }
 
     if (id) {
       whereConditions.id = id
@@ -95,11 +99,19 @@ export class FishFriendsService {
   }
 
   async delete(id: string): Promise<void> {
-    await this.fishFriendsRepository.delete(id)
+    await this.fishFriendsRepository.update(id, { delFlag: true })
   }
 
   async batchDelete(ids: string[]): Promise<void> {
-    await this.fishFriendsRepository.delete({ id: In(ids) })
+    await this.fishFriendsRepository.update({ id: In(ids) }, { delFlag: true })
+  }
+
+  async restore(id: string): Promise<void> {
+    await this.fishFriendsRepository.update(id, { delFlag: false })
+  }
+
+  async batchRestore(ids: string[]): Promise<void> {
+    await this.fishFriendsRepository.update({ id: In(ids) }, { delFlag: false })
   }
 
   async batchUpsert(dataList: Partial<FishFriends>[]): Promise<void> {
@@ -107,11 +119,11 @@ export class FishFriendsService {
   }
 
   async countByFishId(fishId: string): Promise<number> {
-    return this.fishFriendsRepository.count({ where: { fishId } })
+    return this.fishFriendsRepository.count({ where: { fishId, delFlag: false } })
   }
 
   async countByOwnerId(ownerId: number): Promise<number> {
-    return this.fishFriendsRepository.count({ where: { ownerId } })
+    return this.fishFriendsRepository.count({ where: { ownerId, delFlag: false } })
   }
 
   async getStatistics(): Promise<{
@@ -119,13 +131,14 @@ export class FishFriendsService {
     byFishId: { [key: string]: number }
     byOwnerId: { [key: number]: number }
   }> {
-    const total = await this.fishFriendsRepository.count()
+    const total = await this.fishFriendsRepository.count({ where: { delFlag: false } })
 
     // 按 fishId 统计
     const fishIdStats = await this.fishFriendsRepository
       .createQueryBuilder('fishFriends')
       .select('fishFriends.fishId', 'fishId')
       .addSelect('COUNT(*)', 'count')
+      .where('fishFriends.delFlag = :delFlag', { delFlag: false })
       .groupBy('fishFriends.fishId')
       .getRawMany()
 
@@ -139,6 +152,7 @@ export class FishFriendsService {
       .createQueryBuilder('fishFriends')
       .select('fishFriends.ownerId', 'ownerId')
       .addSelect('COUNT(*)', 'count')
+      .where('fishFriends.delFlag = :delFlag', { delFlag: false })
       .groupBy('fishFriends.ownerId')
       .getRawMany()
 
@@ -155,7 +169,7 @@ export class FishFriendsService {
   }
 
   async exportToExcel(query?: ListFishFriendsQuery): Promise<Buffer> {
-    const whereConditions: any = {}
+    const whereConditions: any = { delFlag: false }
 
     if (query) {
       const { id, fishId, tgName, tgUsername, tgRemarkName, tgPhone, remark, createdAt } = query

+ 54 - 11
src/services/fish.service.ts

@@ -59,34 +59,38 @@ export class FishService {
   }
 
   async findById(id: string): Promise<Fish> {
+    return this.fishRepository.findOneOrFail({ where: { id, delFlag: false } })
+  }
+
+  async findByIdIncludeDeleted(id: string): Promise<Fish> {
     return this.fishRepository.findOneOrFail({ where: { id } })
   }
 
   async findByName(name: string): Promise<Fish | null> {
-    return this.fishRepository.findOne({ where: { name } })
+    return this.fishRepository.findOne({ where: { name, delFlag: false } })
   }
 
   async findByUsername(username: string): Promise<Fish | null> {
-    return this.fishRepository.findOne({ where: { username } })
+    return this.fishRepository.findOne({ where: { username, delFlag: false } })
   }
 
   async findByPhone(phone: string): Promise<Fish | null> {
-    return this.fishRepository.findOne({ where: { phone } })
+    return this.fishRepository.findOne({ where: { phone, delFlag: false } })
   }
 
   async findByOwnerId(ownerId: number): Promise<Fish[]> {
-    return this.fishRepository.find({ where: { ownerId } })
+    return this.fishRepository.find({ where: { ownerId, delFlag: false } })
   }
 
   async findByResult(result: ResultEnum): Promise<Fish[]> {
-    return this.fishRepository.find({ where: { result } })
+    return this.fishRepository.find({ where: { result, delFlag: false } })
   }
 
   async list(query: ListFishQuery): Promise<PaginationResponse<Partial<Fish>>> {
     const { page, size, id, name, username, phone, result, ownerId, ownerName, remark, createdAt, loginTime } = query
     console.log('query: ', query)
 
-    const whereConditions: any = {}
+    const whereConditions: any = { delFlag: false }
 
     if (id) {
       whereConditions.id = id
@@ -185,11 +189,46 @@ export class FishService {
   }
 
   async delete(id: string): Promise<void> {
-    await this.fishRepository.delete(id)
+    await this.fishRepository.update(id, { delFlag: true })
+    
+    try {
+      await this.fishFriendsRepository.update({ fishId: id }, { delFlag: true })
+      this.app.log.info(`Fish ${id} deleted, related FishFriends records also marked as deleted`)
+    } catch (error) {
+      this.app.log.error(`Failed to delete related FishFriends for Fish ${id}: ${error}`)
+    }
   }
 
   async batchDelete(ids: string[]): Promise<void> {
-    await this.fishRepository.delete({ id: In(ids) })
+    await this.fishRepository.update({ id: In(ids) }, { delFlag: true })
+    
+    try {
+      await this.fishFriendsRepository.update({ fishId: In(ids) }, { delFlag: true })
+      this.app.log.info(`Fish batch deleted (${ids.length} records), related FishFriends records also marked as deleted`)
+    } catch (error) {
+      this.app.log.error(`Failed to delete related FishFriends for Fish batch: ${error}`)
+    }
+  }
+
+  async restore(id: string): Promise<void> {
+    await this.fishRepository.update(id, { delFlag: false })
+    
+    try {
+      await this.fishFriendsRepository.update({ fishId: id }, { delFlag: false })
+      this.app.log.info(`Fish ${id} restored, related FishFriends records also restored`)
+    } catch (error) {
+      this.app.log.error(`Failed to restore related FishFriends for Fish ${id}: ${error}`)
+    }
+  }
+
+  async batchRestore(ids: string[]): Promise<void> {
+    await this.fishRepository.update({ id: In(ids) }, { delFlag: false })
+    try {
+      await this.fishFriendsRepository.update({ fishId: In(ids) }, { delFlag: false })
+      this.app.log.info(`Fish batch restored (${ids.length} records), related FishFriends records also restored`)
+    } catch (error) {
+      this.app.log.error(`Failed to restore related FishFriends for Fish batch: ${error}`)
+    }
   }
 
   async batchUpdateOwner(
@@ -236,11 +275,11 @@ export class FishService {
   }
 
   async countByResult(result: ResultEnum): Promise<number> {
-    return this.fishRepository.count({ where: { result } })
+    return this.fishRepository.count({ where: { result, delFlag: false } })
   }
 
   async countByOwnerId(ownerId: number): Promise<number> {
-    return this.fishRepository.count({ where: { ownerId } })
+    return this.fishRepository.count({ where: { ownerId, delFlag: false } })
   }
 
   async getStatistics(ownerId?: number): Promise<{
@@ -281,6 +320,10 @@ export class FishService {
         parameters.ownerId = ownerId
       }
 
+      // 始终排除已删除的记录
+      conditions.push('fish.delFlag = :delFlag')
+      parameters.delFlag = false
+
       if (includeTimeRange) {
         conditions.push('fish.createdAt >= :startDate', 'fish.createdAt <= :today')
         parameters.startDate = startDate
@@ -358,7 +401,7 @@ export class FishService {
   }
 
   async exportToExcel(query?: ListFishQuery): Promise<Buffer> {
-    const whereConditions: any = {}
+    const whereConditions: any = { delFlag: false }
 
     if (query) {
       const { id, name, username, phone, result, ownerName, remark, createdAt, loginTime } = query