删除确认 Hook - 统一管理单删/批量删除的确认弹窗与执行

复制代码
/*
 * @Description: 删除确认 Hook - 统一管理单删/批量删除的确认弹窗与执行
 * @Version: 1.0.0
 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getImageUrl } from '@/utils/image'

interface DeleteableItem {
  id?: number | string
  nickName?: string
  realName?: string
  [key: string]: any
}

export function useDelete<TRow extends DeleteableItem>(
  deleteSingleApi: (params: { id: number }) => Promise<any>,
  deleteBatchApi: (ids: string[]) => Promise<any>,
  /** 资源名称,用于提示文案,默认"用户" */
  resourceName: string = '用户',
  /** 确认弹窗图标路径,默认 /info-circle-filled.png */
  iconPath: string = '/info-circle-filled.png',
) {
  const tipsShow = ref(false)
  const titleValve = ref('')
  const tips = ref('')
  const iconUrl = ref('')
  const selectedRows = ref<TRow[]>([])
  const currentRow = ref<TRow | null>(null)
  /** 区分单删 / 批量删 */
  const isBatchMode = ref(false)

  /** 单条删除确认 */
  const confirmSingleDelete = (row: TRow) => {
    currentRow.value = row
    isBatchMode.value = false
    tipsShow.value = true
    iconUrl.value = getImageUrl(iconPath)
    titleValve.value = `你确定要删除${resourceName}:${row.nickName}吗?`
    tips.value = `删除${resourceName}:${row.nickName}后无法恢复,请谨慎操作!`
  }

  /** 批量删除确认 */
  const confirmBatchDelete = () => {
    if (selectedRows.value.length === 0) {
      ElMessage.warning(`请选择${resourceName}后再进行删除操作`)
      return
    }
    isBatchMode.value = true
    tipsShow.value = true
    iconUrl.value = getImageUrl(iconPath)
    titleValve.value = `你确定要删除选中${resourceName}吗?`
    tips.value = '删除后无法恢复,请谨慎操作!'
  }

  /** 确定删除 */
  const handleConfirm = async (onSuccess?: () => void) => {
    try {
      if (isBatchMode.value) {
        const ids = selectedRows.value
          .map(item => String(item.id!))
        await deleteBatchApi(ids)
        ElMessage.success(`成功删除 ${ids.length} 条${resourceName}信息`)
      } else {
        await deleteSingleApi({ id: Number(currentRow.value!.id!) })
        ElMessage.success(`${resourceName}:${currentRow.value?.realName}已删除`)
      }
      tipsShow.value = false
      onSuccess?.()
    } catch (error: any) {
      ElMessage.error(error.msg)
    }
  }

  /** 取消删除 */
  const handleCancel = () => {
    tipsShow.value = false
  }

  return {
    tipsShow,
    titleValve,
    tips,
    iconUrl,
    selectedRows,
    currentRow,
    confirmSingleDelete,
    confirmBatchDelete,
    handleConfirm,
    handleCancel,
  }
}

//useDelete --- 删除确认 Hook
function useDelete<TRow extends DeleteableItem>(
  deleteSingleApi: (params: { id: number }) => Promise<any>,
  deleteBatchApi: (ids: string[]) => Promise<any>,
  resourceName?: string,    // 默认 '用户'
  iconPath?: string,        // 默认 '/info-circle-filled.png'
)

参数

|-----------------|---------------------------------------------|----|-------------------------------------|
| 参数 | 类型 | 必填 | 说明 |
| deleteSingleApi | (params: { id: number }) => Promise<any> | 是 | 单条删除的 API 方法 |
| deleteBatchApi | (ids: string\[\]) => Promise<any> | 是 | 批量删除的 API 方法 |
| resourceName | string | 是 | 资源名称,用于自动生成提示文案(如 '角色' 、 '商品' ) |
| iconPath | string | 是 | 确认弹窗图标路径,默认 /info-circle-filled.png |

返回值

|---------------------|------------------------------------|----------------------------------------|
| 属性 | 类型 | 说明 |
| tipsShow | Ref<boolean> | 删除确认弹窗可见性,绑定到 MessageBoxTisp 的 v-model |
| titleValve | Ref<string> | 弹窗标题 |
| tips | Ref<string> | 弹窗提示文案 |
| iconUrl | Ref<string> | 弹窗图标 |
| selectedRows | Ref<TRow\[\]> | 被选中的行数据,批量删除前需赋值 |
| currentRow | Ref<TRow | null> | 当前操作的单个行数据 |
| confirmSingleDelete | (row: TRow) => void | 触发单条删除确认 |
| confirmBatchDelete | () => void | 触发批量删除确认 |
| handleConfirm | (onSuccess?: () => void) => void | 确认删除,传入删除成功后的回调 |
| handleCancel | () => void | 取消删除 |

使用示例

场景一:同时支持单删和批量删除

复制代码
<template>
  <CustomTable @selection-change="onSelectionChange">
    <template #action="{ row }">
      <CustomButtons @click="deleteHandler.confirmSingleDelete(row)">删除</CustomButtons>
    </template>
  </CustomTable>
  <CustomButtons @click="deleteHandler.confirmBatchDelete">批量删除</CustomButtons>
  <MessageBoxTisp
    v-model="deleteHandler.tipsShow.value"
    :titleValve="deleteHandler.titleValve.value"
    :tips="deleteHandler.tips.value"
    :iconUrl="deleteHandler.iconUrl.value"
    @confirm="deleteHandler.handleConfirm(onSubmit)"
    @cancel="deleteHandler.handleCancel"
  />
</template>

<script setup lang="ts">
import { useDelete } from '@/hooks/useDelete'
import { deleteUser, deleteUserAll } from '@/api/login/user'

const deleteHandler = useDelete<Request>(deleteUser, deleteUserAll)

const onSelectionChange = (selection: Request[]) => {
  deleteHandler.selectedRows.value = selection
}
</script>

场景二:仅批量删除

复制代码
const deleteHandler = useDelete<TreeNode>(
  async () => {},  // 单删不可用,传空函数
  deleteRoleAll,
  '角色',           // 提示文案自动适配
  '/del_icon.png',  // 自定义图标
)

// 同步勾选数据到 selectedRows
const handleCheckChange = (data: TreeNode, checked: boolean) => {
  // ...维护 checkedNodes
  deleteHandler.selectedRows.value = checkedNodes.value as any
}

// 删除时调用
const handleDelete = () => {
  deleteHandler.selectedRows.value = checkedNodes.value as any
  deleteHandler.confirmBatchDelete()
}

// 确认后执行清理
const handleConfirm = () => {
  deleteHandler.handleConfirm(async () => {
    checkedNodes.value = []
    await getRole()
  })
}

自动生成的提示文案

|---------------------|---------------|----------------|---|
| 方法 | 资源名= '用户' | 资源名= '角色' | |
| confirmSingleDelete | 你确定要删除用户:张三吗? | 你确定要删除角色:管理员吗? | |
| confirmBatchDelete | 你确定要删除选中用户吗? | 你确定要删除选中角色吗? | |
| handleConfirm (批量) | 成功删除 3 条用户信息 | 成功删除 3 条角色信息 | |

相关推荐
云间寄信1 小时前
JS:数据结构与集合
javascript
假如让我当三天老蒯1 小时前
React+TS 项目结构(自学项目用)
前端·react.js
yingyima1 小时前
Celery 分布式任务队列:我差点被这行代码坑死
前端
用户125758524361 小时前
XYGo Admin 即时通讯模块解析:基于 WebSocket 的企业级消息架构实践
前端
铁皮饭盒1 小时前
彩色命令行,Node21自带函数1行实现 ,Bun也兼容, 附Bun.color实现渐变色的代码
前端·后端
零度晚风2 小时前
JS:基础语法与控制结构
javascript
锋行天下2 小时前
关于websocket,真实场景踩坑经验
前端·后端
Asize2 小时前
重生之我在 Vibe Coding 时代当程序员:第十二课,Prompt 不是咒语,是可以沉淀的业务接口
前端·人工智能·python
布兰妮甜2 小时前
Vue 项目 `localhost:3000` 打不开?404 常见原因排查指南
前端·javascript·vue.js·vuecli·4040排查