修改完成待测试
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import { computed, ref } from "vue";
|
||||
import { isRequestCancelled } from "@/services/api/request-controller.js";
|
||||
import { getRequestErrorMessage } from "@/services/api/request-error-message.js";
|
||||
|
||||
export const useBatchDeletion = ({
|
||||
items,
|
||||
visibleItems = items,
|
||||
getId = (item) => item?.id,
|
||||
canDelete = (item) => item?.canDelete === true,
|
||||
deleteOne,
|
||||
resourceName,
|
||||
isActive = () => true,
|
||||
onEmpty = () => {},
|
||||
}) => {
|
||||
const selectionMode = ref(false);
|
||||
const selectedIds = ref([]);
|
||||
const confirmationVisible = ref(false);
|
||||
const deleting = ref(false);
|
||||
const notice = ref("");
|
||||
const error = ref("");
|
||||
|
||||
const deletableItems = computed(() => visibleItems.value.filter(canDelete));
|
||||
const allSelected = computed(
|
||||
() =>
|
||||
deletableItems.value.length > 0 &&
|
||||
deletableItems.value.every((item) => selectedIds.value.includes(getId(item))),
|
||||
);
|
||||
const selectedCount = computed(() => selectedIds.value.length);
|
||||
const confirmationMessage = computed(
|
||||
() =>
|
||||
`将选中的 ${selectedCount.value} 条${resourceName}移入回收站;管理员可在保留期内恢复。`,
|
||||
);
|
||||
|
||||
const clearFeedback = () => {
|
||||
notice.value = "";
|
||||
error.value = "";
|
||||
};
|
||||
const exitSelectionMode = () => {
|
||||
selectionMode.value = false;
|
||||
selectedIds.value = [];
|
||||
confirmationVisible.value = false;
|
||||
};
|
||||
const enterSelectionMode = () => {
|
||||
if (!deletableItems.value.length || deleting.value) return;
|
||||
clearFeedback();
|
||||
selectedIds.value = [];
|
||||
selectionMode.value = true;
|
||||
};
|
||||
const isSelected = (item) => selectedIds.value.includes(getId(item));
|
||||
const toggleSelection = (item) => {
|
||||
if (!selectionMode.value || !canDelete(item) || deleting.value) return;
|
||||
const id = getId(item);
|
||||
selectedIds.value = isSelected(item)
|
||||
? selectedIds.value.filter((selectedId) => selectedId !== id)
|
||||
: [...selectedIds.value, id];
|
||||
clearFeedback();
|
||||
};
|
||||
const toggleAll = () => {
|
||||
if (!selectionMode.value || deleting.value) return;
|
||||
selectedIds.value = allSelected.value ? [] : deletableItems.value.map(getId);
|
||||
clearFeedback();
|
||||
};
|
||||
const requestDelete = () => {
|
||||
if (!selectionMode.value || !selectedIds.value.length || deleting.value) return;
|
||||
clearFeedback();
|
||||
confirmationVisible.value = true;
|
||||
};
|
||||
const cancelDelete = () => {
|
||||
if (!deleting.value) confirmationVisible.value = false;
|
||||
};
|
||||
const confirmDelete = async () => {
|
||||
if (!selectionMode.value || !selectedIds.value.length || deleting.value) return;
|
||||
const pendingIds = selectedIds.value.slice();
|
||||
deleting.value = true;
|
||||
clearFeedback();
|
||||
let deletedCount = 0;
|
||||
let failedRequest = null;
|
||||
try {
|
||||
for (const id of pendingIds) {
|
||||
const target = items.value.find((item) => getId(item) === id);
|
||||
if (!target || !canDelete(target)) continue;
|
||||
try {
|
||||
await deleteOne(target);
|
||||
} catch (cause) {
|
||||
failedRequest = cause;
|
||||
break;
|
||||
}
|
||||
if (!isActive()) return;
|
||||
deletedCount += 1;
|
||||
items.value = items.value.filter((item) => getId(item) !== id);
|
||||
selectedIds.value = selectedIds.value.filter((selectedId) => selectedId !== id);
|
||||
}
|
||||
if (!isActive()) return;
|
||||
confirmationVisible.value = false;
|
||||
if (failedRequest && !isRequestCancelled(failedRequest)) {
|
||||
const failureCopy = getRequestErrorMessage(
|
||||
failedRequest,
|
||||
`剩余${resourceName}删除失败,请稍后重试。`,
|
||||
);
|
||||
error.value = deletedCount ? `已删除 ${deletedCount} 条;${failureCopy}` : failureCopy;
|
||||
} else if (deletedCount) {
|
||||
notice.value = `已删除 ${deletedCount} 条${resourceName}。`;
|
||||
}
|
||||
if (!items.value.length) {
|
||||
exitSelectionMode();
|
||||
onEmpty();
|
||||
} else if (!selectedIds.value.length) {
|
||||
selectionMode.value = false;
|
||||
}
|
||||
} finally {
|
||||
if (isActive()) deleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
selectionMode,
|
||||
selectedIds,
|
||||
selectedCount,
|
||||
deletableItems,
|
||||
allSelected,
|
||||
confirmationVisible,
|
||||
confirmationMessage,
|
||||
deleting,
|
||||
notice,
|
||||
error,
|
||||
enterSelectionMode,
|
||||
exitSelectionMode,
|
||||
isSelected,
|
||||
toggleSelection,
|
||||
toggleAll,
|
||||
requestDelete,
|
||||
cancelDelete,
|
||||
confirmDelete,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user