2026-06-29 14:26:00 +08:00

233 lines
6.8 KiB
JavaScript

import { useMemo, useState } from "react";
import { parseForm } from "@/shared/forms/validation";
import { useRegionOptions } from "@/shared/hooks/useRegionOptions.js";
import { usePaginatedQuery } from "@/shared/hooks/usePaginatedQuery.js";
import { useConfirm } from "@/shared/ui/ConfirmProvider.jsx";
import { useToast } from "@/shared/ui/ToastProvider.jsx";
import { emptyUserIdentityFilter, userIdentityFilterParams } from "@/shared/ui/userIdentityFilter.js";
import { deleteRoom, listRooms, updateRoom } from "@/features/rooms/api";
import { useRoomAbilities } from "@/features/rooms/permissions.js";
import { roomStatusSchema, roomUpdateSchema } from "@/features/rooms/schema";
const pageSize = 50;
const emptyData = { items: [], page: 1, pageSize, total: 0 };
const emptyForm = () => ({
coverUrl: "",
description: "",
title: "",
visibleRegionId: 0,
});
const emptyStatusForm = () => ({ closeReason: "", status: "active" });
export function useRoomsPage() {
const abilities = useRoomAbilities();
const confirm = useConfirm();
const { showToast } = useToast();
const { loadingRegions, regionOptions } = useRegionOptions();
const [query, setQuery] = useState("");
const [ownerFilter, setOwnerFilter] = useState(emptyUserIdentityFilter);
const [status, setStatus] = useState("");
const [regionId, setRegionId] = useState("");
const [contributionSortDirection, setContributionSortDirection] = useState("");
const [page, setPage] = useState(1);
const [activeAction, setActiveAction] = useState("");
const [activeRoom, setActiveRoom] = useState(null);
const [form, setForm] = useState(emptyForm);
const [statusForm, setStatusForm] = useState(emptyStatusForm);
const [loadingAction, setLoadingAction] = useState("");
const filters = useMemo(
() => ({
keyword: query,
region_id: regionId,
sort_by: contributionSortDirection ? "room_contribution" : "",
sort_direction: contributionSortDirection,
status,
...userIdentityFilterParams(ownerFilter, {
displayUserId: "owner_display_user_id",
userId: "owner_user_id",
username: "owner_username",
}),
}),
[contributionSortDirection, ownerFilter, query, regionId, status],
);
const {
data = emptyData,
error,
loading,
reload,
} = usePaginatedQuery({
errorMessage: "加载房间列表失败",
fetcher: listRooms,
filters,
page,
pageSize,
queryKey: ["rooms", filters, page],
});
const changeQuery = (value) => {
setQuery(value);
setPage(1);
};
const changeOwnerFilter = (value) => {
setOwnerFilter(value);
setPage(1);
};
const changeStatus = (value) => {
setStatus(value);
setPage(1);
};
const changeRegionId = (value) => {
setRegionId(value);
setPage(1);
};
const toggleContributionSort = () => {
setContributionSortDirection((current) => (current === "desc" ? "asc" : "desc"));
setPage(1);
};
const resetFilters = () => {
setQuery("");
setOwnerFilter(emptyUserIdentityFilter);
setStatus("");
setRegionId("");
setPage(1);
};
const openEdit = (room) => {
setActiveRoom(room);
setForm({
coverUrl: room.coverUrl || "",
description: "",
title: room.title || "",
visibleRegionId: room.visibleRegionId || 0,
});
setActiveAction("edit");
};
const openDetail = (room) => {
setActiveRoom(room);
setActiveAction("detail");
};
const openStatus = (room, statusValue = "closed") => {
setActiveRoom(room);
setStatusForm({ closeReason: "", status: statusValue });
setActiveAction("status");
};
const closeAction = () => {
setActiveAction("");
setActiveRoom(null);
};
const submitEdit = async (event) => {
event.preventDefault();
if (!activeRoom) {
return;
}
await runAction("edit", "房间已更新", async () => {
const payload = parseForm(roomUpdateSchema, form);
if (!String(form.description || "").trim()) {
delete payload.description;
}
await updateRoom(activeRoom.roomId, payload);
closeAction();
await reload();
});
};
const submitStatus = async (event) => {
event.preventDefault();
if (!activeRoom) {
return;
}
await runAction(`status-${activeRoom.roomId}`, "房间状态已更新", async () => {
const payload = parseForm(roomStatusSchema, statusForm);
await updateRoom(activeRoom.roomId, payload);
closeAction();
await reload();
});
};
const toggleRoomStatus = async (room, checked) => {
if (!checked) {
openStatus(room, "closed");
return;
}
await runAction(`status-${room.roomId}`, "房间状态已更新", async () => {
await updateRoom(room.roomId, { status: "active" });
await reload();
});
};
const removeRoom = async (room) => {
const ok = await confirm({
confirmText: "删除",
message: `${room.title || room.roomId} 会从房间列表和房间状态中删除。`,
title: "删除房间",
tone: "danger",
});
if (!ok) {
return;
}
await runAction(`delete-${room.roomId}`, "房间已删除", async () => {
await deleteRoom(room.roomId);
await reload();
});
};
const runAction = async (action, successMessage, submitter) => {
setLoadingAction(action);
try {
await submitter();
showToast(successMessage, "success");
} catch (err) {
showToast(err.message || "操作失败", "error");
} finally {
setLoadingAction("");
}
};
return {
abilities,
activeAction,
activeRoom,
changeOwnerFilter,
changeQuery,
changeRegionId,
changeStatus,
closeAction,
contributionSortDirection,
data,
error,
form,
loading,
loadingAction,
loadingRegions,
openDetail,
openEdit,
openStatus,
ownerFilter,
page,
query,
regionId,
regionOptions,
reload,
removeRoom,
resetFilters,
setForm,
setPage,
setStatusForm,
status,
statusForm,
submitStatus,
submitEdit,
toggleRoomStatus,
toggleContributionSort,
};
}