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, }; }