Compare commits
No commits in common. "00b8020599a6b5dd894517bceacaaf42d441c9cf" and "c08f9e7a839cfbe9d0d1a73df2c819bfdc2e2839" have entirely different histories.
00b8020599
...
c08f9e7a83
@ -3871,42 +3871,6 @@
|
|||||||
},
|
},
|
||||||
"put": {
|
"put": {
|
||||||
"operationId": "replaceRegionBlocks",
|
"operationId": "replaceRegionBlocks",
|
||||||
"requestBody": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"type": "object",
|
|
||||||
"required": ["keywords"],
|
|
||||||
"properties": {
|
|
||||||
"keywords": {
|
|
||||||
"type": "array",
|
|
||||||
"maxItems": 200,
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 128
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"whitelist_ips": {
|
|
||||||
"type": "array",
|
|
||||||
"maxItems": 500,
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 64
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"whitelist_user_ids": {
|
|
||||||
"type": "array",
|
|
||||||
"maxItems": 500,
|
|
||||||
"items": {
|
|
||||||
"type": "string",
|
|
||||||
"maxLength": 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"$ref": "#/components/responses/EmptyResponse"
|
"$ref": "#/components/responses/EmptyResponse"
|
||||||
|
|||||||
@ -30,12 +30,6 @@ const agencyColumns = [
|
|||||||
render: (item) => <AgencyOwner item={item} />,
|
render: (item) => <AgencyOwner item={item} />,
|
||||||
width: "minmax(220px, 1.2fr)",
|
width: "minmax(220px, 1.2fr)",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "contact",
|
|
||||||
label: "联系方式",
|
|
||||||
render: (item) => item.contact || "-",
|
|
||||||
width: "minmax(150px, 0.85fr)",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "activeHostCount",
|
key: "activeHostCount",
|
||||||
label: "子 Host",
|
label: "子 Host",
|
||||||
|
|||||||
@ -33,12 +33,6 @@ const bdLeaderBaseColumns = [
|
|||||||
render: (item, _index, context) => regionName(item, context?.regionOptions),
|
render: (item, _index, context) => regionName(item, context?.regionOptions),
|
||||||
width: "minmax(130px, 0.75fr)",
|
width: "minmax(130px, 0.75fr)",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "contact",
|
|
||||||
label: "联系方式",
|
|
||||||
render: (item) => item.contact || "-",
|
|
||||||
width: "minmax(150px, 0.85fr)",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "salaryWallet",
|
key: "salaryWallet",
|
||||||
label: "工资钱包",
|
label: "工资钱包",
|
||||||
|
|||||||
@ -28,12 +28,6 @@ const bdColumns = [
|
|||||||
render: (item) => <span className={styles.inlineValue}>{formatCount(item.agencyCount)}</span>,
|
render: (item) => <span className={styles.inlineValue}>{formatCount(item.agencyCount)}</span>,
|
||||||
width: "minmax(110px, 0.65fr)",
|
width: "minmax(110px, 0.65fr)",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "contact",
|
|
||||||
label: "联系方式",
|
|
||||||
render: (item) => item.contact || "-",
|
|
||||||
width: "minmax(150px, 0.85fr)",
|
|
||||||
},
|
|
||||||
{ key: "role", label: "角色", width: "minmax(100px, 0.65fr)" },
|
{ key: "role", label: "角色", width: "minmax(100px, 0.65fr)" },
|
||||||
{
|
{
|
||||||
key: "salaryWallet",
|
key: "salaryWallet",
|
||||||
|
|||||||
@ -24,12 +24,6 @@ const hostColumns = [
|
|||||||
render: (item) => <HostStatusSwitch item={item} />,
|
render: (item) => <HostStatusSwitch item={item} />,
|
||||||
width: "minmax(90px, 0.7fr)",
|
width: "minmax(90px, 0.7fr)",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
key: "contact",
|
|
||||||
label: "联系方式",
|
|
||||||
render: (item) => item.contact || "-",
|
|
||||||
width: "minmax(150px, 0.85fr)",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "diamond",
|
key: "diamond",
|
||||||
label: "钻石",
|
label: "钻石",
|
||||||
|
|||||||
@ -19,19 +19,9 @@ export interface IPWhitelistDto {
|
|||||||
updatedAtMs: number;
|
updatedAtMs: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserWhitelistDto {
|
|
||||||
whitelistId: number;
|
|
||||||
userId: string;
|
|
||||||
displayUserId: string;
|
|
||||||
enabled: boolean;
|
|
||||||
createdAtMs: number;
|
|
||||||
updatedAtMs: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RegionBlockPayload {
|
export interface RegionBlockPayload {
|
||||||
keywords: string[];
|
keywords: string[];
|
||||||
whitelist_ips?: string[];
|
whitelist_ips?: string[];
|
||||||
whitelist_user_ids?: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddRegionBlockWhitelistIPResult {
|
export interface AddRegionBlockWhitelistIPResult {
|
||||||
@ -42,13 +32,10 @@ export interface AddRegionBlockWhitelistIPResult {
|
|||||||
export interface RegionBlockConfigDto extends ApiList<RegionBlockDto> {
|
export interface RegionBlockConfigDto extends ApiList<RegionBlockDto> {
|
||||||
whitelistItems: IPWhitelistDto[];
|
whitelistItems: IPWhitelistDto[];
|
||||||
whitelistTotal: number;
|
whitelistTotal: number;
|
||||||
whitelistUserItems: UserWhitelistDto[];
|
|
||||||
whitelistUserTotal: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RawRegionBlock = RegionBlockDto & Record<string, unknown>;
|
type RawRegionBlock = RegionBlockDto & Record<string, unknown>;
|
||||||
type RawIPWhitelist = IPWhitelistDto & Record<string, unknown>;
|
type RawIPWhitelist = IPWhitelistDto & Record<string, unknown>;
|
||||||
type RawUserWhitelist = UserWhitelistDto & Record<string, unknown>;
|
|
||||||
type RawRegionBlockConfig = ApiList<RawRegionBlock> & Record<string, unknown>;
|
type RawRegionBlockConfig = ApiList<RawRegionBlock> & Record<string, unknown>;
|
||||||
|
|
||||||
export function listRegionBlocks(): Promise<RegionBlockConfigDto> {
|
export function listRegionBlocks(): Promise<RegionBlockConfigDto> {
|
||||||
@ -89,14 +76,11 @@ export async function addRegionBlockWhitelistIP(ipAddress: string): Promise<AddR
|
|||||||
|
|
||||||
function normalizeRegionBlockConfig(data: RawRegionBlockConfig): RegionBlockConfigDto {
|
function normalizeRegionBlockConfig(data: RawRegionBlockConfig): RegionBlockConfigDto {
|
||||||
const rawWhitelist = (data.whitelistItems ?? data.whitelist_items ?? []) as RawIPWhitelist[];
|
const rawWhitelist = (data.whitelistItems ?? data.whitelist_items ?? []) as RawIPWhitelist[];
|
||||||
const rawUserWhitelist = (data.whitelistUserItems ?? data.whitelist_user_items ?? []) as RawUserWhitelist[];
|
|
||||||
return {
|
return {
|
||||||
items: (data.items || []).map(normalizeRegionBlock),
|
items: (data.items || []).map(normalizeRegionBlock),
|
||||||
total: Number(data.total || 0),
|
total: Number(data.total || 0),
|
||||||
whitelistItems: rawWhitelist.map(normalizeIPWhitelist),
|
whitelistItems: rawWhitelist.map(normalizeIPWhitelist),
|
||||||
whitelistTotal: numberValue(data.whitelistTotal ?? data.whitelist_total),
|
whitelistTotal: numberValue(data.whitelistTotal ?? data.whitelist_total),
|
||||||
whitelistUserItems: rawUserWhitelist.map(normalizeUserWhitelist),
|
|
||||||
whitelistUserTotal: numberValue(data.whitelistUserTotal ?? data.whitelist_user_total),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,17 +105,6 @@ function normalizeIPWhitelist(item: RawIPWhitelist): IPWhitelistDto {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeUserWhitelist(item: RawUserWhitelist): UserWhitelistDto {
|
|
||||||
return {
|
|
||||||
whitelistId: numberValue(item.whitelistId ?? item.whitelist_id),
|
|
||||||
userId: stringValue(item.userId ?? item.user_id),
|
|
||||||
displayUserId: stringValue(item.displayUserId ?? item.display_user_id),
|
|
||||||
enabled: Boolean(item.enabled),
|
|
||||||
createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms),
|
|
||||||
updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringValue(value: unknown) {
|
function stringValue(value: unknown) {
|
||||||
return value === undefined || value === null ? "" : String(value);
|
return value === undefined || value === null ? "" : String(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,14 +4,9 @@ import { useAdminQuery } from "@/shared/hooks/useAdminQuery.js";
|
|||||||
import { useToast } from "@/shared/ui/ToastProvider.jsx";
|
import { useToast } from "@/shared/ui/ToastProvider.jsx";
|
||||||
import { listRegionBlocks, replaceRegionBlocks } from "@/features/region-blocks/api";
|
import { listRegionBlocks, replaceRegionBlocks } from "@/features/region-blocks/api";
|
||||||
import { useRegionBlockAbilities } from "@/features/region-blocks/permissions.js";
|
import { useRegionBlockAbilities } from "@/features/region-blocks/permissions.js";
|
||||||
import {
|
import { regionBlockIPSchema, regionBlockKeywordSchema, regionBlockReplaceSchema } from "@/features/region-blocks/schema";
|
||||||
regionBlockIPSchema,
|
|
||||||
regionBlockKeywordSchema,
|
|
||||||
regionBlockReplaceSchema,
|
|
||||||
regionBlockUserIDSchema,
|
|
||||||
} from "@/features/region-blocks/schema";
|
|
||||||
|
|
||||||
const emptyData = { items: [], total: 0, whitelistItems: [], whitelistTotal: 0, whitelistUserItems: [], whitelistUserTotal: 0 };
|
const emptyData = { items: [], total: 0, whitelistItems: [], whitelistTotal: 0 };
|
||||||
const countryCodePattern = /^[A-Za-z]{2,3}$/;
|
const countryCodePattern = /^[A-Za-z]{2,3}$/;
|
||||||
|
|
||||||
export function useRegionBlockPage() {
|
export function useRegionBlockPage() {
|
||||||
@ -19,10 +14,8 @@ export function useRegionBlockPage() {
|
|||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const [keywordInput, setKeywordInput] = useState("");
|
const [keywordInput, setKeywordInput] = useState("");
|
||||||
const [ipInput, setIPInput] = useState("");
|
const [ipInput, setIPInput] = useState("");
|
||||||
const [userIDInput, setUserIDInput] = useState("");
|
|
||||||
const [draftKeywords, setDraftKeywords] = useState([]);
|
const [draftKeywords, setDraftKeywords] = useState([]);
|
||||||
const [draftWhitelistIPs, setDraftWhitelistIPs] = useState([]);
|
const [draftWhitelistIPs, setDraftWhitelistIPs] = useState([]);
|
||||||
const [draftWhitelistUserIDs, setDraftWhitelistUserIDs] = useState([]);
|
|
||||||
const [dirty, setDirty] = useState(false);
|
const [dirty, setDirty] = useState(false);
|
||||||
const [whitelistDialogOpen, setWhitelistDialogOpen] = useState(false);
|
const [whitelistDialogOpen, setWhitelistDialogOpen] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
@ -41,13 +34,8 @@ export function useRegionBlockPage() {
|
|||||||
() => (data.whitelistItems || []).map((item) => item.ipAddress).filter(Boolean),
|
() => (data.whitelistItems || []).map((item) => item.ipAddress).filter(Boolean),
|
||||||
[data.whitelistItems],
|
[data.whitelistItems],
|
||||||
);
|
);
|
||||||
const serverWhitelistUserIDs = useMemo(
|
|
||||||
() => (data.whitelistUserItems || []).map((item) => item.userId).filter(Boolean),
|
|
||||||
[data.whitelistUserItems],
|
|
||||||
);
|
|
||||||
const serverKeywordKey = serverKeywords.join("\n");
|
const serverKeywordKey = serverKeywords.join("\n");
|
||||||
const serverWhitelistKey = serverWhitelistIPs.join("\n");
|
const serverWhitelistKey = serverWhitelistIPs.join("\n");
|
||||||
const serverWhitelistUserKey = serverWhitelistUserIDs.join("\n");
|
|
||||||
const serverBlockByKeyword = useMemo(() => {
|
const serverBlockByKeyword = useMemo(() => {
|
||||||
const blocks = new Map();
|
const blocks = new Map();
|
||||||
(data.items || []).forEach((item) => blocks.set(normalizeKey(item.keyword), item));
|
(data.items || []).forEach((item) => blocks.set(normalizeKey(item.keyword), item));
|
||||||
@ -58,19 +46,13 @@ export function useRegionBlockPage() {
|
|||||||
(data.whitelistItems || []).forEach((item) => items.set(normalizeKey(item.ipAddress), item));
|
(data.whitelistItems || []).forEach((item) => items.set(normalizeKey(item.ipAddress), item));
|
||||||
return items;
|
return items;
|
||||||
}, [data.whitelistItems]);
|
}, [data.whitelistItems]);
|
||||||
const serverWhitelistByUserID = useMemo(() => {
|
|
||||||
const items = new Map();
|
|
||||||
(data.whitelistUserItems || []).forEach((item) => items.set(normalizeKey(item.userId), item));
|
|
||||||
return items;
|
|
||||||
}, [data.whitelistUserItems]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!dirty) {
|
if (!dirty) {
|
||||||
setDraftKeywords(serverKeywords);
|
setDraftKeywords(serverKeywords);
|
||||||
setDraftWhitelistIPs(serverWhitelistIPs);
|
setDraftWhitelistIPs(serverWhitelistIPs);
|
||||||
setDraftWhitelistUserIDs(serverWhitelistUserIDs);
|
|
||||||
}
|
}
|
||||||
}, [dirty, serverKeywordKey, serverKeywords, serverWhitelistIPs, serverWhitelistKey, serverWhitelistUserIDs, serverWhitelistUserKey]);
|
}, [dirty, serverKeywordKey, serverKeywords, serverWhitelistIPs, serverWhitelistKey]);
|
||||||
|
|
||||||
const draftItems = useMemo(
|
const draftItems = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -105,23 +87,6 @@ export function useRegionBlockPage() {
|
|||||||
}),
|
}),
|
||||||
[draftWhitelistIPs, serverWhitelistByIP],
|
[draftWhitelistIPs, serverWhitelistByIP],
|
||||||
);
|
);
|
||||||
const draftWhitelistUserItems = useMemo(
|
|
||||||
() =>
|
|
||||||
draftWhitelistUserIDs.map((userID, index) => {
|
|
||||||
const saved = serverWhitelistByUserID.get(normalizeKey(userID));
|
|
||||||
return (
|
|
||||||
saved || {
|
|
||||||
whitelistId: `draft-user-${index}-${userID}`,
|
|
||||||
userId: userID,
|
|
||||||
displayUserId: "",
|
|
||||||
createdAtMs: 0,
|
|
||||||
enabled: true,
|
|
||||||
updatedAtMs: 0,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
[draftWhitelistUserIDs, serverWhitelistByUserID],
|
|
||||||
);
|
|
||||||
|
|
||||||
const addKeyword = () => {
|
const addKeyword = () => {
|
||||||
if (!abilities.canUpdate) {
|
if (!abilities.canUpdate) {
|
||||||
@ -169,29 +134,6 @@ export function useRegionBlockPage() {
|
|||||||
addIP();
|
addIP();
|
||||||
};
|
};
|
||||||
|
|
||||||
const addUserID = () => {
|
|
||||||
if (!abilities.canUpdate) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const userID = parseForm(regionBlockUserIDSchema, userIDInput);
|
|
||||||
if (draftWhitelistUserIDs.some((item) => normalizeKey(item) === normalizeKey(userID))) {
|
|
||||||
showToast("白名单用户已存在", "warning");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setDraftWhitelistUserIDs([...draftWhitelistUserIDs, userID]);
|
|
||||||
setUserIDInput("");
|
|
||||||
setDirty(true);
|
|
||||||
} catch (err) {
|
|
||||||
showValidationError(err, showToast, "用户 ID/短 ID/靓号参数不正确");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitUserIDInput = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
addUserID();
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeKeyword = (keyword) => {
|
const removeKeyword = (keyword) => {
|
||||||
if (!abilities.canUpdate) {
|
if (!abilities.canUpdate) {
|
||||||
return;
|
return;
|
||||||
@ -208,21 +150,11 @@ export function useRegionBlockPage() {
|
|||||||
setDirty(true);
|
setDirty(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeUserID = (userID) => {
|
|
||||||
if (!abilities.canUpdate) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setDraftWhitelistUserIDs(draftWhitelistUserIDs.filter((item) => normalizeKey(item) !== normalizeKey(userID)));
|
|
||||||
setDirty(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetDraft = () => {
|
const resetDraft = () => {
|
||||||
setDraftKeywords(serverKeywords);
|
setDraftKeywords(serverKeywords);
|
||||||
setDraftWhitelistIPs(serverWhitelistIPs);
|
setDraftWhitelistIPs(serverWhitelistIPs);
|
||||||
setDraftWhitelistUserIDs(serverWhitelistUserIDs);
|
|
||||||
setKeywordInput("");
|
setKeywordInput("");
|
||||||
setIPInput("");
|
setIPInput("");
|
||||||
setUserIDInput("");
|
|
||||||
setDirty(false);
|
setDirty(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -232,15 +164,10 @@ export function useRegionBlockPage() {
|
|||||||
}
|
}
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
try {
|
try {
|
||||||
const payload = parseForm(regionBlockReplaceSchema, {
|
const payload = parseForm(regionBlockReplaceSchema, { keywords: draftKeywords, whitelist_ips: draftWhitelistIPs });
|
||||||
keywords: draftKeywords,
|
|
||||||
whitelist_ips: draftWhitelistIPs,
|
|
||||||
whitelist_user_ids: draftWhitelistUserIDs,
|
|
||||||
});
|
|
||||||
const saved = await replaceRegionBlocks(payload);
|
const saved = await replaceRegionBlocks(payload);
|
||||||
setDraftKeywords((saved.items || []).map((item) => item.keyword).filter(Boolean));
|
setDraftKeywords((saved.items || []).map((item) => item.keyword).filter(Boolean));
|
||||||
setDraftWhitelistIPs((saved.whitelistItems || []).map((item) => item.ipAddress).filter(Boolean));
|
setDraftWhitelistIPs((saved.whitelistItems || []).map((item) => item.ipAddress).filter(Boolean));
|
||||||
setDraftWhitelistUserIDs((saved.whitelistUserItems || []).map((item) => item.userId).filter(Boolean));
|
|
||||||
setDirty(false);
|
setDirty(false);
|
||||||
showToast("地区屏蔽配置已保存", "success");
|
showToast("地区屏蔽配置已保存", "success");
|
||||||
await reload();
|
await reload();
|
||||||
@ -255,11 +182,9 @@ export function useRegionBlockPage() {
|
|||||||
abilities,
|
abilities,
|
||||||
addIP,
|
addIP,
|
||||||
addKeyword,
|
addKeyword,
|
||||||
addUserID,
|
|
||||||
dirty,
|
dirty,
|
||||||
draftItems,
|
draftItems,
|
||||||
draftWhitelistItems,
|
draftWhitelistItems,
|
||||||
draftWhitelistUserItems,
|
|
||||||
error,
|
error,
|
||||||
ipInput,
|
ipInput,
|
||||||
keywordInput,
|
keywordInput,
|
||||||
@ -268,17 +193,13 @@ export function useRegionBlockPage() {
|
|||||||
reload,
|
reload,
|
||||||
removeIP,
|
removeIP,
|
||||||
removeKeyword,
|
removeKeyword,
|
||||||
removeUserID,
|
|
||||||
resetDraft,
|
resetDraft,
|
||||||
save,
|
save,
|
||||||
saving,
|
saving,
|
||||||
setIPInput,
|
setIPInput,
|
||||||
setKeywordInput,
|
setKeywordInput,
|
||||||
setUserIDInput,
|
|
||||||
submitIPInput,
|
submitIPInput,
|
||||||
submitInput,
|
submitInput,
|
||||||
submitUserIDInput,
|
|
||||||
userIDInput,
|
|
||||||
whitelistDialogOpen,
|
whitelistDialogOpen,
|
||||||
closeWhitelistDialog: () => setWhitelistDialogOpen(false),
|
closeWhitelistDialog: () => setWhitelistDialogOpen(false),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export function RegionBlockPage() {
|
|||||||
const page = useRegionBlockPage();
|
const page = useRegionBlockPage();
|
||||||
const columns = buildColumns(page);
|
const columns = buildColumns(page);
|
||||||
const whitelistColumns = buildWhitelistColumns(page);
|
const whitelistColumns = buildWhitelistColumns(page);
|
||||||
const userWhitelistColumns = buildUserWhitelistColumns(page);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AdminListPage>
|
<AdminListPage>
|
||||||
@ -101,25 +100,6 @@ export function RegionBlockPage() {
|
|||||||
>
|
>
|
||||||
白名单IP列表
|
白名单IP列表
|
||||||
</Button>
|
</Button>
|
||||||
<form className={styles.addForm} onSubmit={page.submitUserIDInput}>
|
|
||||||
<TextField
|
|
||||||
className={styles.userInput}
|
|
||||||
disabled={!page.abilities.canUpdate || page.saving}
|
|
||||||
label="用户ID/短ID/靓号白名单"
|
|
||||||
placeholder="900025 或 VIP2026"
|
|
||||||
size="small"
|
|
||||||
value={page.userIDInput}
|
|
||||||
onChange={(event) => page.setUserIDInput(event.target.value)}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
disabled={!page.abilities.canUpdate || page.saving}
|
|
||||||
startIcon={<AddOutlined fontSize="small" />}
|
|
||||||
type="submit"
|
|
||||||
variant="primary"
|
|
||||||
>
|
|
||||||
添加用户
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -143,15 +123,6 @@ export function RegionBlockPage() {
|
|||||||
rowKey={(item) => item.whitelistId || item.ipAddress}
|
rowKey={(item) => item.whitelistId || item.ipAddress}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.tableGroup}>
|
|
||||||
<h2 className={styles.tableTitle}>用户ID/短ID/靓号白名单</h2>
|
|
||||||
<DataTable
|
|
||||||
columns={userWhitelistColumns}
|
|
||||||
items={page.draftWhitelistUserItems}
|
|
||||||
minWidth="860px"
|
|
||||||
rowKey={(item) => item.whitelistId || item.userId}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</AdminListBody>
|
</AdminListBody>
|
||||||
</DataState>
|
</DataState>
|
||||||
<WhitelistDialog page={page} />
|
<WhitelistDialog page={page} />
|
||||||
@ -237,48 +208,6 @@ function buildWhitelistColumns(page) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildUserWhitelistColumns(page) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: "userId",
|
|
||||||
label: "内部用户ID",
|
|
||||||
width: "minmax(220px, 1fr)",
|
|
||||||
render: (item) => <KeywordCell item={{ keyword: item.userId, enabled: item.enabled }} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "displayUserId",
|
|
||||||
label: "当前短ID/靓号",
|
|
||||||
width: "minmax(180px, 0.8fr)",
|
|
||||||
render: (item) => item.displayUserId || (String(item.whitelistId || "").startsWith("draft-user-") ? "保存后解析" : "-"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "updatedAtMs",
|
|
||||||
label: "更新时间",
|
|
||||||
width: "minmax(180px, 0.8fr)",
|
|
||||||
render: (item) => (item.updatedAtMs ? formatMillis(item.updatedAtMs) : "-"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "actions",
|
|
||||||
label: "操作",
|
|
||||||
width: "minmax(96px, 0.4fr)",
|
|
||||||
render: (item) => (
|
|
||||||
<Tooltip arrow title="移除">
|
|
||||||
<span>
|
|
||||||
<IconButton
|
|
||||||
disabled={!page.abilities.canUpdate || page.saving}
|
|
||||||
label="移除"
|
|
||||||
tone="danger"
|
|
||||||
onClick={() => page.removeUserID(item.userId)}
|
|
||||||
>
|
|
||||||
<DeleteOutlineOutlined fontSize="small" />
|
|
||||||
</IconButton>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildWhitelistDialogColumns() {
|
function buildWhitelistDialogColumns() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -20,10 +20,6 @@
|
|||||||
flex: 0 1 220px;
|
flex: 0 1 220px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.userInput {
|
|
||||||
flex: 0 1 280px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tableGroup {
|
.tableGroup {
|
||||||
display: grid;
|
display: grid;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
@ -116,8 +112,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.keywordInput,
|
.keywordInput,
|
||||||
.ipInput,
|
.ipInput {
|
||||||
.userInput {
|
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,17 +13,9 @@ export const regionBlockIPSchema = z
|
|||||||
.max(64, "IP 不能超过 64 个字符")
|
.max(64, "IP 不能超过 64 个字符")
|
||||||
.refine((value) => isIPv4(value) || isIPv6(value), "请输入正确的 IP 地址");
|
.refine((value) => isIPv4(value) || isIPv6(value), "请输入正确的 IP 地址");
|
||||||
|
|
||||||
export const regionBlockUserIDSchema = z
|
|
||||||
.string()
|
|
||||||
.trim()
|
|
||||||
.min(1, "请输入用户 ID/短 ID/靓号")
|
|
||||||
.max(64, "用户 ID/短 ID/靓号不能超过 64 个字符")
|
|
||||||
.refine((value) => !/\s/.test(value), "用户 ID/短 ID/靓号不能包含空白");
|
|
||||||
|
|
||||||
export const regionBlockReplaceSchema = z.object({
|
export const regionBlockReplaceSchema = z.object({
|
||||||
keywords: z.array(regionBlockKeywordSchema).max(200, "最多配置 200 个屏蔽词"),
|
keywords: z.array(regionBlockKeywordSchema).max(200, "最多配置 200 个屏蔽词"),
|
||||||
whitelist_ips: z.array(regionBlockIPSchema).max(500, "最多配置 500 个白名单 IP"),
|
whitelist_ips: z.array(regionBlockIPSchema).max(500, "最多配置 500 个白名单 IP"),
|
||||||
whitelist_user_ids: z.array(regionBlockUserIDSchema).max(500, "最多配置 500 个白名单用户"),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type RegionBlockReplaceForm = z.infer<typeof regionBlockReplaceSchema>;
|
export type RegionBlockReplaceForm = z.infer<typeof regionBlockReplaceSchema>;
|
||||||
|
|||||||
10
src/shared/api/generated/schema.d.ts
vendored
10
src/shared/api/generated/schema.d.ts
vendored
@ -7051,15 +7051,7 @@ export interface operations {
|
|||||||
path?: never;
|
path?: never;
|
||||||
cookie?: never;
|
cookie?: never;
|
||||||
};
|
};
|
||||||
requestBody?: {
|
requestBody?: never;
|
||||||
content: {
|
|
||||||
"application/json": {
|
|
||||||
keywords: string[];
|
|
||||||
whitelist_ips?: string[];
|
|
||||||
whitelist_user_ids?: string[];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
responses: {
|
responses: {
|
||||||
200: components["responses"]["EmptyResponse"];
|
200: components["responses"]["EmptyResponse"];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -575,7 +575,6 @@ export interface BDProfileDto {
|
|||||||
createdByDisplayUserId?: string;
|
createdByDisplayUserId?: string;
|
||||||
createdByUsername?: string;
|
createdByUsername?: string;
|
||||||
createdByUserId?: number;
|
createdByUserId?: number;
|
||||||
contact?: string;
|
|
||||||
displayUserId?: string;
|
displayUserId?: string;
|
||||||
prettyDisplayUserId?: string;
|
prettyDisplayUserId?: string;
|
||||||
prettyId?: string;
|
prettyId?: string;
|
||||||
@ -604,7 +603,6 @@ export interface AgencyDto {
|
|||||||
maxHosts?: number;
|
maxHosts?: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
ownerAvatar?: string;
|
ownerAvatar?: string;
|
||||||
contact?: string;
|
|
||||||
ownerDisplayUserId?: string;
|
ownerDisplayUserId?: string;
|
||||||
ownerUsername?: string;
|
ownerUsername?: string;
|
||||||
ownerUserId?: string;
|
ownerUserId?: string;
|
||||||
@ -680,7 +678,6 @@ export interface HostProfileDto {
|
|||||||
currentAgencyOwnerDisplayUserId?: string;
|
currentAgencyOwnerDisplayUserId?: string;
|
||||||
currentAgencyOwnerUserId?: string;
|
currentAgencyOwnerUserId?: string;
|
||||||
currentAgencyOwnerUsername?: string;
|
currentAgencyOwnerUsername?: string;
|
||||||
contact?: string;
|
|
||||||
currentMembershipId?: number;
|
currentMembershipId?: number;
|
||||||
diamond?: number;
|
diamond?: number;
|
||||||
displayUserId?: string;
|
displayUserId?: string;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user