furniture-3d-system-Wu/furniture-3d-system/docs/plans/2026-04-02-asset-center-edit-delete-toast.md
WuYongJie 5821d73291 初始提交:3D家具安装展示系统
包含:
- furniture-3d-system:Next.js 16 全栈应用(资产中心、产品管理、3D装配动画)
- autocad-plugin:AutoCAD 家具导出插件源码
- 资产中心改造:编辑弹窗化、删除功能、Toast反馈、自定义Select组件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:00:19 +08:00

6.9 KiB
Raw Blame History

资产中心编辑弹窗化 + 删除功能 + Toast 反馈 实施计划

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: 将资产族编辑从内联改为弹窗、在编辑弹窗中加入删除功能、将反馈提示从 inline 横幅改为 Toast。

Architecture: 前端全栈改造——后端补 DELETE API(repository → service → route),前端补 delete API 调用、将内联编辑改为 Modal 弹窗、复用 DeleteConfirmDialog 处理删除确认、用 useToast 替换 feedback 状态。

Tech Stack: Next.js 16 (API Routes) + Prisma 7 + React 19 + useToast + DeleteConfirmDialog + Modal


改动范围概览

层级 文件 改动
Repository src/server/repositories/asset-family.repository.ts 加 delete 方法
Repository src/server/repositories/asset-variant.repository.ts 加 delete 方法
Service src/server/services/asset-center.service.ts 加 deleteFamily、deleteVariant
API Route src/app/api/asset-center/families/[id]/route.ts 加 DELETE handler
API Route src/app/api/asset-center/variants/[id]/route.ts 加 DELETE handler
前端 API src/lib/open-product/platform-api.ts 加 deleteAssetFamily、deleteAssetVariant
前端页面 src/app/asset-center/AssetCenterClient.tsx 主要改动:弹窗化 + 删除 + Toast

Task 1: 后端 — Repository 层添加 delete 方法

Files:

  • Modify: src/server/repositories/asset-family.repository.ts
  • Modify: src/server/repositories/asset-variant.repository.ts

Step 1: 在 asset-family.repository.ts 添加 deleteById 方法

在 repository class 中添加:

async deleteById(id: string): Promise<void> {
  await this.prisma.assetFamily.delete({ where: { id } })
}

Step 2: 在 asset-variant.repository.ts 添加 deleteById 方法

同样添加:

async deleteById(id: string): Promise<void> {
  await this.prisma.assetVariant.delete({ where: { id } })
}

说明: AssetVariant 已有 onDelete: Cascade 关联 AssetFamily,删除族会自动级联删除其所有规格款。


Task 2: 后端 — Service 层添加 delete 方法

Files:

  • Modify: src/server/services/asset-center.service.ts

Step 1: 在 AssetCenterService 添加 deleteFamily 方法

async deleteFamily(id: string): Promise<void> {
  const existing = await assetFamilyRepository.findById(id)
  if (!existing) {
    throw new AppError(ErrorCode.ASSET_FAMILY_NOT_FOUND, '资产族不存在')
  }
  // Prisma 级联:删除族会自动删除其下所有规格款
  await assetFamilyRepository.deleteById(id)
}

Step 2: 在 AssetCenterService 添加 deleteVariant 方法

async deleteVariant(id: string): Promise<void> {
  const existing = await assetVariantRepository.findById(id)
  if (!existing) {
    throw new AppError(ErrorCode.ASSET_VARIANT_NOT_FOUND, '规格款不存在')
  }
  await assetVariantRepository.deleteById(id)
}

Task 3: 后端 — API Route 层添加 DELETE handler

Files:

  • Modify: src/app/api/asset-center/families/[id]/route.ts
  • Modify: src/app/api/asset-center/variants/[id]/route.ts

Step 1: 在 families/[id]/route.ts 添加 DELETE handler

export async function DELETE(
  request: NextRequest,
  context: { params: Promise<{ id: string }> },
) {
  return handleRequest(
    request,
    async (ctx) => {
      const { id } = await context.params
      try {
        await assetCenterService.deleteFamily(id)
        return jsonSuccess({ success: true }, 200, ctx.requestId)
      } catch (error) {
        if (error instanceof AppError) {
          return jsonError(error.code, error.message, error.statusCode, ctx.requestId)
        }
        throw error
      }
    },
    { requireAuth: true },
  )
}

Step 2: 在 variants/[id]/route.ts 添加 DELETE handler

同上模式,调用 assetCenterService.deleteVariant(id)。


Task 4: 前端 — platform-api.ts 添加删除调用

Files:

  • Modify: src/lib/open-product/platform-api.ts

Step 1: 添加 deleteAssetFamily 和 deleteAssetVariant

export async function deleteAssetFamily(id: string): Promise<void> {
  await requestPlatform<{ success: boolean }>(`/api/asset-center/families/${id}`, {
    method: 'DELETE',
  })
}

export async function deleteAssetVariant(id: string): Promise<void> {
  await requestPlatform<{ success: boolean }>(`/api/asset-center/variants/${id}`, {
    method: 'DELETE',
  })
}

Task 5: 前端 — AssetCenterClient.tsx 核心改造

Files:

  • Modify: src/app/asset-center/AssetCenterClient.tsx

这是最大的改动任务,包含三个子目标:

5a. 反馈系统:feedback 状态 → useToast

  • 删除 feedback state 和 showSuccess/showError 函数
  • 导入 useToast,改用 toast.success() / toast.error()
  • 删除 PlatformSplitLayout 的 feedback prop
  • 在组件底部添加 <ToastContainer toasts={toast.toasts} onClose={toast.removeToast} />

5b. 资产族编辑:内联 → 弹窗

  • 删除 editingFamilyId、editFamilyForm、startEditFamily、cancelEditFamily 相关代码
  • 新增 familyModalOpen、familyModalMode(create/edit)、familyForm、editingFamilyId 状态
  • 点击编辑铅笔图标时打开 Modal 弹窗(而非展开内联表单)
  • 弹窗底部放"取消"和"保存"按钮
  • 删除按钮放在弹窗 footer 左侧(仅编辑模式显示),点击触发 DeleteConfirmDialog
  • 新建资产族也改为弹窗(保持一致体验)

5c. 规格款弹窗添加删除按钮

  • 在现有规格款编辑弹窗的 footer 左侧添加删除按钮(仅编辑模式)
  • 点击后弹出 DeleteConfirmDialog,确认后调用 deleteAssetVariant
  • 删除成功后从列表移除、关闭弹窗、Toast 提示

5d. 新增状态管理

新增状态:

// 资产族弹窗
const [familyModalOpen, setFamilyModalOpen] = useState(false)
const [familyModalMode, setFamilyModalMode] = useState<'create' | 'edit'>('create')
const [familyForm, setFamilyForm] = useState({
  type: 'BOARD' as AssetFamilyDTO['type'],
  code: '', name: '', description: '', roles: '', available: false,
})
const [editingFamilyId, setEditingFamilyId] = useState<string | null>(null)

// 删除确认弹窗
const [deleteTarget, setDeleteTarget] = useState<{
  type: 'family' | 'variant'
  id: string
  name: string
  cascadeCount?: number
} | null>(null)

Task 6: 类型检查 + 浏览器验证

Step 1: 运行 npx tsc --noEmit 确认无类型错误

Step 2: 浏览器验证:

  • 点击编辑资产族 → 弹窗打开 → 编辑保存 → Toast 提示
  • 弹窗内点击删除 → DeleteConfirmDialog 弹出 → 确认删除 → Toast 提示 + 列表更新
  • 规格款编辑弹窗 → 点击删除 → 确认 → Toast + 列表更新
  • 新建资产族弹窗 → 创建 → Toast 提示