fix: 修复商品批量删除与恢复

This commit is contained in:
hh
2026-07-13 14:31:26 +08:00
parent f803948143
commit bd3b484fde
4 changed files with 258 additions and 12 deletions
+40 -1
View File
@@ -44,6 +44,7 @@ import { AdminApp } from "./routes/admin/admin-app";
import { TrashPage } from "./routes/trash";
import { ModelsPage } from "./routes/models";
import { money } from "./routes/stage-config";
import type { ProductBatchResult } from "./routes/products";
const crumbLabels: Partial<Record<Page, string>> = {
dashboard: "工作台",
@@ -501,6 +502,40 @@ export function App() {
}
}
async function runProductBatch<T>(ids: string[], work: (id: string) => Promise<T>, successText: string): Promise<ProductBatchResult> {
const uniqueIds = Array.from(new Set(ids));
if (!uniqueIds.length) return { succeededIds: [], failedIds: [] };
if (actionInFlightRef.current) {
setNotice({ type: "error", text: "操作进行中,请稍候…" });
return { succeededIds: [], failedIds: uniqueIds };
}
actionInFlightRef.current = true;
setLoading(true);
setNotice(null);
try {
const results = await Promise.allSettled(uniqueIds.map(work));
const succeededIds = uniqueIds.filter((_, index) => results[index].status === "fulfilled");
const failedIds = uniqueIds.filter((_, index) => results[index].status === "rejected");
if (succeededIds.length && !failedIds.length) {
setNotice({ type: "success", text: `${successText} ${succeededIds.length}` });
} else if (succeededIds.length) {
setNotice({ type: "error", text: `${successText} ${succeededIds.length} 项,失败 ${failedIds.length}` });
} else {
const firstFailure = results.find((result): result is PromiseRejectedResult => result.status === "rejected");
setNotice({ type: "error", text: firstFailure?.reason instanceof Error ? firstFailure.reason.message : "操作失败" });
}
if (succeededIds.length) {
void loadData();
void refreshProjectDetail();
}
return { succeededIds, failedIds };
} finally {
setLoading(false);
actionInFlightRef.current = false;
}
}
async function markNotificationRead(id: string) {
await api.markNotificationRead(id).catch(() => undefined);
await reloadNotifications();
@@ -741,6 +776,7 @@ export function App() {
onCreate={(payload) => action(() => api.createProduct(payload), "")}
onUploadImage={(productId, formData) => action(() => api.uploadProductImage(productId, formData), "")}
onDelete={(productId) => action(() => api.deleteProduct(productId), "已移至垃圾桶")}
onDeleteMany={(ids) => runProductBatch(ids, (id) => api.deleteProduct(id), "已移至垃圾桶")}
/>
);
case "productCreateUpload":
@@ -756,11 +792,12 @@ export function App() {
onCreate={(payload) => action(() => api.createProduct(payload), "")}
onUploadImage={(productId, formData) => action(() => api.uploadProductImage(productId, formData), "")}
onDelete={(productId) => action(() => api.deleteProduct(productId), "已移至垃圾桶")}
onDeleteMany={(ids) => runProductBatch(ids, (id) => api.deleteProduct(id), "已移至垃圾桶")}
autoOpenCreate
/>
);
case "productDetail":
if (!activeProduct) return <ProductsPage products={products} loading={!dataLoaded} navigate={navigate} openProduct={(productId, tab) => navigate("productDetail", { productId, hash: tab === "videos" ? "videos" : undefined })} onCreate={(payload) => action(() => api.createProduct(payload), "")} onDelete={(productId) => action(() => api.deleteProduct(productId), "已移至垃圾桶")} />;
if (!activeProduct) return <ProductsPage products={products} loading={!dataLoaded} navigate={navigate} openProduct={(productId, tab) => navigate("productDetail", { productId, hash: tab === "videos" ? "videos" : undefined })} onCreate={(payload) => action(() => api.createProduct(payload), "")} onDelete={(productId) => action(() => api.deleteProduct(productId), "已移至垃圾桶")} onDeleteMany={(ids) => runProductBatch(ids, (id) => api.deleteProduct(id), "已移至垃圾桶")} />;
return (
<ProductDetailPage
product={activeProduct}
@@ -847,6 +884,8 @@ export function App() {
navigate={navigate}
onRestore={(id) => action(() => api.restoreProduct(id), "已恢复到商品库")}
onPurge={(id) => action(() => api.purgeProduct(id), "已彻底删除")}
onRestoreProducts={(ids) => runProductBatch(ids, (id) => api.restoreProduct(id), "已恢复到商品库")}
onPurgeProducts={(ids) => runProductBatch(ids, (id) => api.purgeProduct(id), "已彻底删除")}
onChanged={() => { void loadData(); }}
/>
);