import AddOutlined from "@mui/icons-material/AddOutlined"; import CloseOutlined from "@mui/icons-material/CloseOutlined"; import MeetingRoomOutlined from "@mui/icons-material/MeetingRoomOutlined"; import Autocomplete from "@mui/material/Autocomplete"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; import Tooltip from "@mui/material/Tooltip"; import { Button } from "@/shared/ui/Button.jsx"; import { AdminFormDialog } from "@/shared/ui/AdminFormDialog.jsx"; import { AdminUserIdentity } from "@/shared/ui/AdminUserIdentity.jsx"; import { DataState } from "@/shared/ui/DataState.jsx"; import { DataTable } from "@/shared/ui/DataTable.jsx"; import { IconButton } from "@/shared/ui/IconButton.jsx"; import { AdminFilterResetButton } from "@/shared/ui/AdminListLayout.jsx"; import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js"; import { createRegionColumnFilter } from "@/shared/ui/RegionFilterControl.jsx"; import { formatMillis } from "@/shared/utils/time.js"; import { useRoomPinsPage } from "@/features/rooms/hooks/useRoomPinsPage.js"; import styles from "@/features/rooms/rooms.module.css"; const pinStatusOptions = [ { label: "有效", value: "active" }, { label: "已过期", value: "expired" }, { label: "已取消", value: "cancelled" }, { label: "全部", value: "all" }, ]; const pinTypeOptions = [ { label: "区域置顶", value: "region" }, { label: "国家置顶", value: "country" }, { label: "全区置顶", value: "global" }, ]; const columns = [ { key: "room", label: "房间信息", width: "minmax(280px, 1.5fr)", render: (pin) => , }, { key: "user", label: "用户信息", width: "minmax(240px, 1.2fr)", render: (pin) => , }, { key: "region", label: "区域", width: "minmax(140px, 0.7fr)", render: (pin) => pin.room?.regionName || (pin.room?.visibleRegionId ? `区域 ${pin.room.visibleRegionId}` : "-"), }, { key: "weight", label: "排序", width: "minmax(100px, 0.5fr)", render: (pin) => Number(pin.weight || 0).toLocaleString("zh-CN"), }, { key: "pinType", label: "置顶类型", width: "minmax(130px, 0.7fr)", render: (pin) => pinTypeLabel(pin.pinType), }, { key: "pinnedAt", label: "置顶时间", width: "minmax(170px, 0.9fr)", render: (pin) => formatMillis(pin.pinnedAtMs), }, { key: "remaining", label: "剩余时间", width: "minmax(150px, 0.8fr)", render: (pin) => formatRemaining(pin), }, { key: "expiresAt", label: "到期时间", width: "minmax(170px, 0.9fr)", render: (pin) => formatMillis(pin.expiresAtMs), }, ]; export function RoomPinsPage() { const page = useRoomPinsPage(); const items = page.data.items || []; const total = page.data.total || 0; const tableColumns = [ ...columns.map((column) => column.key === "room" ? { ...column, filter: createTextColumnFilter({ placeholder: "搜索房间 ID", value: page.query, onChange: page.changeQuery, }), } : column.key === "region" ? { ...column, filter: createRegionColumnFilter({ loading: page.loadingRegions, options: page.regionOptions, value: page.regionId, onChange: page.changeRegionId, }), } : column.key === "remaining" ? { ...column, filter: createOptionsColumnFilter({ options: pinStatusOptions, placeholder: "置顶状态", value: page.status, onChange: page.changeStatus, }), } : column, ), { key: "actions", label: "操作", width: "minmax(104px, 0.6fr)", render: (pin) => , }, ]; return (
{page.abilities.canPinCreate ? (
) : null}
pin.id} pagination={ total > 0 ? { page: page.page, pageSize: page.data.pageSize || 50, total, onPageChange: page.setPage, } : undefined } />
options} getOptionLabel={(option) => roomOptionLabel(option)} isOptionEqualToValue={(option, value) => option.roomId === value.roomId} loading={page.roomOptionsLoading} noOptionsText="当前无数据" inputValue={page.roomInput} options={page.roomOptions} renderInput={(params) => ( )} renderOption={(props, option) => (
  • )} size="small" value={page.selectedRoom} onChange={(_, option) => page.selectRoom(option)} onInputChange={(_, value, reason) => { if (reason === "input") { page.changeRoomInput(value); } if (reason === "clear") { page.selectRoom(null); } }} /> page.setForm({ ...page.form, pinType: event.target.value })} > {pinTypeOptions.map((option) => ( {option.label} ))} page.setForm({ ...page.form, weight: event.target.value })} /> page.setForm({ ...page.form, pinnedAtMs: event.target.value })} /> page.setForm({ ...page.form, expiresAtMs: event.target.value })} />
    ); } function PinRoomIdentity({ room = {} }) { return (
    {room.coverUrl ? : }
    {room.title || "-"}
    长ID {room.roomId || "-"}
    短ID {room.roomShortId || "-"}
    ); } function PinUserIdentity({ user = {} }) { return ; } function RoomPinActions({ page, pin }) { const canCancel = page.abilities.canPinCancel && pin.status === "active" && Number(pin.remainingMs || 0) > 0; if (!canCancel) { return -; } return (
    page.cancelPin(pin)} >
    ); } function roomOptionLabel(room) { if (!room) { return ""; } return [room.title, room.roomShortId, room.roomId].filter(Boolean).join(" / "); } function formatRemaining(pin) { if (pin.status === "cancelled") { return "-"; } const ms = Number(pin.remainingMs || 0); if (ms <= 0) { return "0天"; } const dayMs = 24 * 60 * 60 * 1000; const days = Math.floor(ms / dayMs); const hours = Math.floor((ms % dayMs) / (60 * 60 * 1000)); if (days > 0) { return `${days}天${hours > 0 ? `${hours}小时` : ""}`; } return `${Math.max(hours, 1)}小时`; } function pinTypeLabel(pinType) { if (pinType === "global") { return "全区置顶"; } if (pinType === "country") { return "国家置顶"; } return "区域置顶"; }