233 lines
6.8 KiB
JavaScript
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,
|
|
};
|
|
}
|