import { useEffect, 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 { cancelRoomPin, createRoomPin, listRoomPins, listRooms } from "@/features/rooms/api"; import { useRoomAbilities } from "@/features/rooms/permissions.js"; import { roomPinCreateSchema } from "@/features/rooms/schema"; const pageSize = 10; const emptyData = { items: [], page: 1, pageSize, total: 0 }; const emptyForm = () => ({ durationDays: "30", roomId: "", weight: "0" }); export function useRoomPinsPage() { const abilities = useRoomAbilities(); const confirm = useConfirm(); const { showToast } = useToast(); const { loadingRegions, regionOptions } = useRegionOptions(); const [query, setQuery] = useState(""); const [regionId, setRegionId] = useState(""); const [status, setStatus] = useState("active"); const [page, setPage] = useState(1); const [activeAction, setActiveAction] = useState(""); const [form, setForm] = useState(emptyForm); const [loadingAction, setLoadingAction] = useState(""); const [roomSearch, setRoomSearch] = useState(""); const [roomOptionsState, setRoomOptionsState] = useState({ error: "", loading: false, options: [] }); const filters = useMemo( () => ({ keyword: query, region_id: regionId, status, }), [query, regionId, status], ); const { data = emptyData, error, loading, reload, } = usePaginatedQuery({ errorMessage: "加载房间置顶列表失败", fetcher: listRoomPins, filters, page, pageSize, queryKey: ["room-pins", filters, page], }); useEffect(() => { if (activeAction !== "create") { return undefined; } let cancelled = false; const timer = window.setTimeout(async () => { setRoomOptionsState((current) => ({ ...current, error: "", loading: true })); try { const data = await listRooms({ keyword: roomSearch.trim(), page: 1, page_size: 20, status: "active", }); if (!cancelled) { setRoomOptionsState({ error: "", loading: false, options: data?.items || [] }); } } catch (err) { if (!cancelled) { setRoomOptionsState({ error: err.message || "搜索房间失败", loading: false, options: [] }); } } }, 300); return () => { cancelled = true; window.clearTimeout(timer); }; }, [activeAction, roomSearch]); const changeQuery = (value) => { setQuery(value); setPage(1); }; const changeRegionId = (value) => { setRegionId(value); setPage(1); }; const changeStatus = (value) => { setStatus(value || "active"); setPage(1); }; const resetFilters = () => { setQuery(""); setRegionId(""); setStatus("active"); setPage(1); }; const openCreate = () => { setForm(emptyForm()); setRoomSearch(""); setRoomOptionsState({ error: "", loading: false, options: [] }); setActiveAction("create"); }; const closeAction = () => { setActiveAction(""); }; const submitCreate = async (event) => { event.preventDefault(); await runAction("create", "房间已置顶", async () => { const payload = parseForm(roomPinCreateSchema, form); await createRoomPin(payload); closeAction(); await reload(); }); }; const cancelPin = async (pin) => { const room = pin.room || {}; const ok = await confirm({ confirmText: "取消置顶", message: room.title || room.roomShortId || room.roomId, title: "取消房间置顶", tone: "danger", }); if (!ok) { return; } await runAction(`cancel-${pin.id}`, "房间置顶已取消", async () => { await cancelRoomPin(pin.id); await reload(); }); }; const runAction = async (action, successMessage, submitter) => { setLoadingAction(action); try { await submitter(); showToast(successMessage, "success"); } catch (err) { showToast(err.message || "操作失败", "error"); } finally { setLoadingAction(""); } }; const selectedRoom = roomOptionsState.options.find((room) => room.roomId === form.roomId) || null; return { abilities, activeAction, cancelPin, changeQuery, changeRegionId, changeStatus, closeAction, data, error, form, loading, loadingAction, loadingRegions, openCreate, page, query, regionId, regionOptions, reload, resetFilters, roomOptions: roomOptionsState.options, roomOptionsError: roomOptionsState.error, roomOptionsLoading: roomOptionsState.loading, roomSearch, selectedRoom, setForm, setPage, setRoomSearch, status, submitCreate, }; }