feat: KOC资源列表分页展示(每页15个)
This commit is contained in:
@@ -3171,6 +3171,22 @@ function ScreenshotTaskTable({ distributions }: { distributions: Distribution[]
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RESOURCE_PAGE_SIZE = 15;
|
||||||
|
|
||||||
|
function pageList(current: number, total: number): Array<number | "gap"> {
|
||||||
|
if (total <= 7) {
|
||||||
|
return Array.from({ length: total }, (_, index) => index + 1);
|
||||||
|
}
|
||||||
|
const items: Array<number | "gap"> = [1];
|
||||||
|
const start = Math.max(2, current - 1);
|
||||||
|
const end = Math.min(total - 1, current + 1);
|
||||||
|
if (start > 2) items.push("gap");
|
||||||
|
for (let page = start; page <= end; page += 1) items.push(page);
|
||||||
|
if (end < total - 1) items.push("gap");
|
||||||
|
items.push(total);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
function ResourcesPage({
|
function ResourcesPage({
|
||||||
accounts,
|
accounts,
|
||||||
distributions,
|
distributions,
|
||||||
@@ -3188,6 +3204,7 @@ function ResourcesPage({
|
|||||||
const [platformFilter, setPlatformFilter] = useState("全部平台");
|
const [platformFilter, setPlatformFilter] = useState("全部平台");
|
||||||
const [ipFilter, setIpFilter] = useState("");
|
const [ipFilter, setIpFilter] = useState("");
|
||||||
const [sourceFilter, setSourceFilter] = useState("");
|
const [sourceFilter, setSourceFilter] = useState("");
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
const [importOpen, setImportOpen] = useState(false);
|
const [importOpen, setImportOpen] = useState(false);
|
||||||
const [importMode, setImportMode] = useState<"bulk" | "single">("bulk");
|
const [importMode, setImportMode] = useState<"bulk" | "single">("bulk");
|
||||||
const [importFile, setImportFile] = useState<File | null>(null);
|
const [importFile, setImportFile] = useState<File | null>(null);
|
||||||
@@ -3307,11 +3324,21 @@ function ResourcesPage({
|
|||||||
platformFilter !== "全部平台" ||
|
platformFilter !== "全部平台" ||
|
||||||
Boolean(ipFilter.trim()) ||
|
Boolean(ipFilter.trim()) ||
|
||||||
Boolean(sourceFilter.trim());
|
Boolean(sourceFilter.trim());
|
||||||
|
const totalPages = Math.max(
|
||||||
|
1,
|
||||||
|
Math.ceil(filteredAccounts.length / RESOURCE_PAGE_SIZE),
|
||||||
|
);
|
||||||
|
const currentPage = Math.min(page, totalPages);
|
||||||
|
const pagedAccounts = filteredAccounts.slice(
|
||||||
|
(currentPage - 1) * RESOURCE_PAGE_SIZE,
|
||||||
|
currentPage * RESOURCE_PAGE_SIZE,
|
||||||
|
);
|
||||||
const clearFilters = () => {
|
const clearFilters = () => {
|
||||||
setQuery("");
|
setQuery("");
|
||||||
setPlatformFilter("全部平台");
|
setPlatformFilter("全部平台");
|
||||||
setIpFilter("");
|
setIpFilter("");
|
||||||
setSourceFilter("");
|
setSourceFilter("");
|
||||||
|
setPage(1);
|
||||||
};
|
};
|
||||||
const closeImport = () => {
|
const closeImport = () => {
|
||||||
if (importWorking || singleWorking) return;
|
if (importWorking || singleWorking) return;
|
||||||
@@ -3569,7 +3596,10 @@ function ResourcesPage({
|
|||||||
<div className="filter-chips">
|
<div className="filter-chips">
|
||||||
<button
|
<button
|
||||||
className={platformFilter === "全部平台" ? "active" : ""}
|
className={platformFilter === "全部平台" ? "active" : ""}
|
||||||
onClick={() => setPlatformFilter("全部平台")}
|
onClick={() => {
|
||||||
|
setPlatformFilter("全部平台");
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
全部平台
|
全部平台
|
||||||
</button>
|
</button>
|
||||||
@@ -3577,7 +3607,10 @@ function ResourcesPage({
|
|||||||
<button
|
<button
|
||||||
className={platformFilter === platform ? "active" : ""}
|
className={platformFilter === platform ? "active" : ""}
|
||||||
key={platform}
|
key={platform}
|
||||||
onClick={() => setPlatformFilter(platform)}
|
onClick={() => {
|
||||||
|
setPlatformFilter(platform);
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<PlatformBadge platform={platform} compact />
|
<PlatformBadge platform={platform} compact />
|
||||||
</button>
|
</button>
|
||||||
@@ -3590,7 +3623,10 @@ function ResourcesPage({
|
|||||||
<span aria-hidden="true">⌕</span>
|
<span aria-hidden="true">⌕</span>
|
||||||
<input
|
<input
|
||||||
aria-label="搜索账号名称、账号ID或当前联系人"
|
aria-label="搜索账号名称、账号ID或当前联系人"
|
||||||
onChange={(event) => setQuery(event.target.value)}
|
onChange={(event) => {
|
||||||
|
setQuery(event.target.value);
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
placeholder="搜索账号名称 / 账号ID / 当前联系人 / 标签"
|
placeholder="搜索账号名称 / 账号ID / 当前联系人 / 标签"
|
||||||
type="search"
|
type="search"
|
||||||
value={query}
|
value={query}
|
||||||
@@ -3601,7 +3637,10 @@ function ResourcesPage({
|
|||||||
<input
|
<input
|
||||||
aria-label="模糊搜索IP地区"
|
aria-label="模糊搜索IP地区"
|
||||||
list="resource-ip-options"
|
list="resource-ip-options"
|
||||||
onChange={(event) => setIpFilter(event.target.value)}
|
onChange={(event) => {
|
||||||
|
setIpFilter(event.target.value);
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
placeholder="搜索IP地区"
|
placeholder="搜索IP地区"
|
||||||
type="search"
|
type="search"
|
||||||
value={ipFilter}
|
value={ipFilter}
|
||||||
@@ -3615,7 +3654,10 @@ function ResourcesPage({
|
|||||||
<input
|
<input
|
||||||
aria-label="模糊搜索合作来源"
|
aria-label="模糊搜索合作来源"
|
||||||
list="resource-source-options"
|
list="resource-source-options"
|
||||||
onChange={(event) => setSourceFilter(event.target.value)}
|
onChange={(event) => {
|
||||||
|
setSourceFilter(event.target.value);
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
placeholder="搜索合作来源"
|
placeholder="搜索合作来源"
|
||||||
type="search"
|
type="search"
|
||||||
value={sourceFilter}
|
value={sourceFilter}
|
||||||
@@ -3634,7 +3676,7 @@ function ResourcesPage({
|
|||||||
清空筛选
|
清空筛选
|
||||||
</button>
|
</button>
|
||||||
<div className="resource-toolbar-summary">
|
<div className="resource-toolbar-summary">
|
||||||
<span>共 <b>{filteredAccounts.length}</b> 个结果</span>
|
<span>共 <b>{filteredAccounts.length}</b> 个结果{totalPages > 1 ? ` · 第 ${currentPage}/${totalPages} 页` : ""}</span>
|
||||||
<button
|
<button
|
||||||
className="export-data-button"
|
className="export-data-button"
|
||||||
disabled={runningIdRefresh || idRefreshStarting}
|
disabled={runningIdRefresh || idRefreshStarting}
|
||||||
@@ -3660,7 +3702,7 @@ function ResourcesPage({
|
|||||||
{idRefreshError && <div className="form-error">{idRefreshError}</div>}
|
{idRefreshError && <div className="form-error">{idRefreshError}</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className="resource-grid">
|
<div className="resource-grid">
|
||||||
{filteredAccounts.map(({ account, sources, partnerManagedOnly }) => {
|
{pagedAccounts.map(({ account, sources, partnerManagedOnly }) => {
|
||||||
const profileLink = resourceProfileLink(account);
|
const profileLink = resourceProfileLink(account);
|
||||||
const accountTags = (account.tags || "")
|
const accountTags = (account.tags || "")
|
||||||
.split(/[,,、;;|]/)
|
.split(/[,,、;;|]/)
|
||||||
@@ -3762,6 +3804,35 @@ function ResourcesPage({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<div className="resource-pagination">
|
||||||
|
<button
|
||||||
|
disabled={currentPage === 1}
|
||||||
|
onClick={() => setPage(currentPage - 1)}
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</button>
|
||||||
|
{pageList(currentPage, totalPages).map((item, index) =>
|
||||||
|
item === "gap" ? (
|
||||||
|
<span className="gap" key={`gap-${index}`}>…</span>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className={item === currentPage ? "active" : ""}
|
||||||
|
key={item}
|
||||||
|
onClick={() => setPage(item)}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
disabled={currentPage === totalPages}
|
||||||
|
onClick={() => setPage(currentPage + 1)}
|
||||||
|
>
|
||||||
|
下一页
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
{editAccount && (
|
{editAccount && (
|
||||||
<div className="modal-backdrop" role="presentation" onMouseDown={closeAccountEdit}>
|
<div className="modal-backdrop" role="presentation" onMouseDown={closeAccountEdit}>
|
||||||
|
|||||||
@@ -2577,6 +2577,49 @@ a {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-pagination {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-pagination button {
|
||||||
|
min-width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #66736f;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-pagination button:hover:not(:disabled) {
|
||||||
|
background: #f0f4f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-pagination button.active {
|
||||||
|
color: #34443f;
|
||||||
|
background: white;
|
||||||
|
border-color: #dce2de;
|
||||||
|
box-shadow: 0 1px 3px rgb(18 31 28 / 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-pagination button:disabled {
|
||||||
|
color: #b7c1bd;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-pagination .gap {
|
||||||
|
color: #9aa4a0;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.resource-import-modal {
|
.resource-import-modal {
|
||||||
width: min(780px, calc(100vw - 32px));
|
width: min(780px, calc(100vw - 32px));
|
||||||
max-height: min(86vh, 820px);
|
max-height: min(86vh, 820px);
|
||||||
|
|||||||
Reference in New Issue
Block a user