删除确认 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 条角色信息 | |

相关推荐
橙子家2 小时前
浏览器缓存之【身份与会话管理】:Cookies 和 Private state tokens
前端
To_OC2 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
最新资讯动态3 小时前
HDC 2026 | 对话鲸鸿动能:存量时代,品牌如何夺回营销“主动权”?
前端
最新资讯动态3 小时前
游戏出海,从产品走向体系
前端
最新资讯动态3 小时前
20人团队跑出百万DAU、大厂也来抢量:谁在鸿蒙生态跑出加速度
前端
最新资讯动态3 小时前
千万开发者背后,鸿蒙商业化的B面
前端
爱勇宝5 小时前
AI 时代:智商决定起点,情商决定走多远
前端·ai编程
kyriewen5 小时前
用了半年 Claude Code 后,我尝试关掉它写了一周代码——结果比想象中严重
前端·javascript·ai编程
IT_陈寒6 小时前
Vite的静态资源打包让我熬夜到三点,这坑千万别跳
前端·人工智能·后端
山河木马6 小时前
矩阵专题0-webGL中的矩阵
javascript·webgl·计算机图形学