229 lines
8.9 KiB
JavaScript
229 lines
8.9 KiB
JavaScript
import Add from "@mui/icons-material/Add";
|
|
import EditOutlined from "@mui/icons-material/EditOutlined";
|
|
import { AdminSwitch } from "@/shared/ui/AdminSwitch.jsx";
|
|
import TextField from "@mui/material/TextField";
|
|
import Tooltip from "@mui/material/Tooltip";
|
|
import { formatMillis } from "@/shared/utils/time.js";
|
|
import { DataState } from "@/shared/ui/DataState.jsx";
|
|
import { IconButton } from "@/shared/ui/IconButton.jsx";
|
|
import { MultiValueAutocomplete } from "@/shared/ui/MultiValueAutocomplete.jsx";
|
|
import { regionStatusFilters } from "@/features/host-org/constants.js";
|
|
import { HostOrgActionModal } from "@/features/host-org/components/HostOrgActionModal.jsx";
|
|
import { HostOrgTable } from "@/features/host-org/components/HostOrgTable.jsx";
|
|
import { useHostRegionsPage } from "@/features/host-org/hooks/useHostRegionsPage.js";
|
|
import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js";
|
|
import styles from "@/features/host-org/host-org.module.css";
|
|
|
|
const baseRegionColumns = [
|
|
{ key: "regionId", label: "区域 ID", width: "minmax(90px, 0.6fr)" },
|
|
{ key: "regionCode", label: "区域编码", width: "minmax(110px, 0.8fr)" },
|
|
{ key: "name", label: "区域名称", width: "minmax(150px, 1fr)" },
|
|
{
|
|
key: "countries",
|
|
label: "国家码",
|
|
render: (item) => <CountryCodes countries={item.countries} />,
|
|
width: "minmax(220px, 1.5fr)",
|
|
},
|
|
{ key: "sortOrder", label: "排序", width: "minmax(80px, 0.5fr)" },
|
|
{
|
|
key: "updatedAtMs",
|
|
label: "更新时间",
|
|
render: (item) => formatMillis(item.updatedAtMs),
|
|
width: "minmax(170px, 1fr)",
|
|
},
|
|
];
|
|
|
|
export function HostRegionsPage() {
|
|
const page = useHostRegionsPage();
|
|
const createDisabled = !page.abilities.canCreate;
|
|
const updateDisabled = !page.abilities.canUpdate;
|
|
const items = page.data.items || [];
|
|
const total = page.data.total || 0;
|
|
const regionColumns = [
|
|
...baseRegionColumns.slice(0, 3),
|
|
{
|
|
key: "status",
|
|
label: "状态",
|
|
render: (item) => <RegionStatusSwitch item={item} page={page} />,
|
|
filter: createOptionsColumnFilter({
|
|
options: regionStatusFilters,
|
|
placeholder: "搜索状态",
|
|
value: page.status,
|
|
onChange: page.changeStatus,
|
|
}),
|
|
width: "minmax(90px, 0.6fr)",
|
|
},
|
|
...baseRegionColumns.slice(3),
|
|
].map((column) =>
|
|
column.key === "regionCode"
|
|
? {
|
|
...column,
|
|
filter: createTextColumnFilter({
|
|
placeholder: "搜索区域、国家码",
|
|
value: page.query,
|
|
onChange: page.changeQuery,
|
|
}),
|
|
}
|
|
: column,
|
|
);
|
|
const columns = page.abilities.canUpdate
|
|
? [
|
|
...regionColumns,
|
|
{
|
|
key: "actions",
|
|
label: "操作",
|
|
render: (item) => <RegionActions item={item} page={page} />,
|
|
width: "minmax(80px, 0.5fr)",
|
|
},
|
|
]
|
|
: regionColumns;
|
|
return (
|
|
<section className={styles.root}>
|
|
<div className={styles.contentPanel}>
|
|
{page.abilities.canCreate ? (
|
|
<div className={styles.toolbar}>
|
|
<div className={styles.toolbarActions}>
|
|
<Tooltip arrow title="创建区域">
|
|
<span>
|
|
<IconButton label="创建区域" onClick={page.openCreateRegion} sx={primaryActionSx}>
|
|
<Add fontSize="small" />
|
|
</IconButton>
|
|
</span>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
|
|
<DataState error={page.error} loading={page.loading} onRetry={page.reload}>
|
|
<div className={styles.listBlock}>
|
|
<HostOrgTable
|
|
columns={columns}
|
|
items={items}
|
|
rowKey={(item) => item.regionId}
|
|
pagination={{ page: 1, pageSize: Math.max(items.length, 1), total }}
|
|
/>
|
|
</div>
|
|
</DataState>
|
|
</div>
|
|
|
|
<HostOrgActionModal
|
|
disabled={page.activeAction === "edit" ? updateDisabled : createDisabled}
|
|
loading={page.loadingAction === "region-create" || page.loadingAction === "region-edit"}
|
|
open={page.activeAction === "create" || page.activeAction === "edit"}
|
|
sectionTitle="区域信息"
|
|
onClose={page.closeAction}
|
|
onSubmit={page.submitRegion}
|
|
title={page.activeAction === "edit" ? "编辑区域" : "创建区域"}
|
|
>
|
|
<TextField
|
|
disabled={page.activeAction === "edit" ? updateDisabled : createDisabled}
|
|
label="区域编码"
|
|
required
|
|
value={page.regionForm.regionCode}
|
|
onChange={(event) => page.setRegionForm({ ...page.regionForm, regionCode: event.target.value })}
|
|
/>
|
|
<TextField
|
|
disabled={page.activeAction === "edit" ? updateDisabled : createDisabled}
|
|
label="区域名称"
|
|
required
|
|
value={page.regionForm.name}
|
|
onChange={(event) => page.setRegionForm({ ...page.regionForm, name: event.target.value })}
|
|
/>
|
|
<TextField
|
|
disabled={page.activeAction === "edit" ? updateDisabled : createDisabled}
|
|
label="排序"
|
|
type="number"
|
|
value={page.regionForm.sortOrder}
|
|
onChange={(event) => page.setRegionForm({ ...page.regionForm, sortOrder: event.target.value })}
|
|
/>
|
|
<CountryCodeSelect
|
|
disabled={
|
|
page.isGlobalRegionForm || (page.activeAction === "edit" ? updateDisabled : createDisabled)
|
|
}
|
|
label={page.isGlobalRegionForm ? "国家码" : "国家码 *"}
|
|
labels={page.countryLabels}
|
|
loading={page.loadingCountries}
|
|
options={page.countryOptions}
|
|
value={page.regionForm.countries}
|
|
onChange={(countries) => page.setRegionForm({ ...page.regionForm, countries })}
|
|
/>
|
|
</HostOrgActionModal>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
function RegionActions({ item, page }) {
|
|
if (item.regionCode === "GLOBAL") {
|
|
return "-";
|
|
}
|
|
return (
|
|
<div className={styles.rowActions}>
|
|
{page.abilities.canUpdate ? (
|
|
<Tooltip arrow title="编辑区域">
|
|
<span>
|
|
<IconButton label="编辑区域" onClick={() => page.openEditRegion(item)}>
|
|
<EditOutlined fontSize="small" />
|
|
</IconButton>
|
|
</span>
|
|
</Tooltip>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function RegionStatusSwitch({ item, page }) {
|
|
const checked = item.status === "active";
|
|
const isGlobal = item.regionCode === "GLOBAL";
|
|
return (
|
|
<AdminSwitch
|
|
checked={checked}
|
|
disabled={isGlobal || !page.abilities.canStatus || page.loadingAction === `region-status-${item.regionId}`}
|
|
inputProps={{ "aria-label": checked ? "停用区域" : "启用区域" }}
|
|
onChange={(event) => page.toggleRegion(item, event.target.checked)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function CountryCodeSelect({ disabled, label, labels, loading, onChange, options, value }) {
|
|
const selected = value || [];
|
|
const mergedOptions = [...new Set([...options, ...selected])].sort();
|
|
return (
|
|
<MultiValueAutocomplete
|
|
disabled={disabled}
|
|
label={label}
|
|
labels={labels}
|
|
loading={loading}
|
|
options={mergedOptions}
|
|
value={selected}
|
|
onChange={onChange}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function CountryCodes({ countries = [] }) {
|
|
const items = Array.isArray(countries) ? countries : [];
|
|
if (!items.length) {
|
|
return "-";
|
|
}
|
|
return (
|
|
<div className="admin-tag-list">
|
|
{items.map((country) => (
|
|
<span className="admin-tag" key={country}>
|
|
{country}
|
|
</span>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const primaryActionSx = {
|
|
borderColor: "var(--primary)",
|
|
backgroundColor: "var(--primary)",
|
|
color: "var(--active-contrast)",
|
|
"&:hover": {
|
|
borderColor: "var(--primary-strong)",
|
|
backgroundColor: "var(--primary-strong)",
|
|
color: "var(--active-contrast)",
|
|
},
|
|
};
|