diff --git a/contracts/admin-openapi.json b/contracts/admin-openapi.json index ef64dcb..8e4eea8 100644 --- a/contracts/admin-openapi.json +++ b/contracts/admin-openapi.json @@ -1711,6 +1711,72 @@ "x-permissions": ["resource-grant:create"] } }, + "/admin/resource-shop/items": { + "get": { + "operationId": "listResourceShopItems", + "responses": { + "200": { + "$ref": "#/components/responses/EmptyResponse" + } + }, + "x-permission": "resource-shop:view", + "x-permissions": ["resource-shop:view"] + }, + "post": { + "operationId": "upsertResourceShopItems", + "responses": { + "200": { + "$ref": "#/components/responses/EmptyResponse" + } + }, + "x-permission": "resource-shop:update", + "x-permissions": ["resource-shop:update"] + } + }, + "/admin/resource-shop/items/{shop_item_id}/disable": { + "post": { + "operationId": "disableResourceShopItem", + "responses": { + "200": { + "$ref": "#/components/responses/EmptyResponse" + } + }, + "parameters": [ + { + "in": "path", + "name": "shop_item_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "x-permission": "resource-shop:update", + "x-permissions": ["resource-shop:update"] + } + }, + "/admin/resource-shop/items/{shop_item_id}/enable": { + "post": { + "operationId": "enableResourceShopItem", + "responses": { + "200": { + "$ref": "#/components/responses/EmptyResponse" + } + }, + "parameters": [ + { + "in": "path", + "name": "shop_item_id", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "x-permission": "resource-shop:update", + "x-permissions": ["resource-shop:update"] + } + }, "/admin/resource-groups": { "get": { "operationId": "listResourceGroups", diff --git a/src/app/navigation/menu.js b/src/app/navigation/menu.js index ec79baf..7600599 100644 --- a/src/app/navigation/menu.js +++ b/src/app/navigation/menu.js @@ -24,6 +24,7 @@ import SendOutlined from "@mui/icons-material/SendOutlined"; import ShieldOutlined from "@mui/icons-material/ShieldOutlined"; import SettingsApplicationsOutlined from "@mui/icons-material/SettingsApplicationsOutlined"; import SportsEsportsOutlined from "@mui/icons-material/SportsEsportsOutlined"; +import StorefrontOutlined from "@mui/icons-material/StorefrontOutlined"; import TaskAltOutlined from "@mui/icons-material/TaskAltOutlined"; import WalletOutlined from "@mui/icons-material/WalletOutlined"; import WorkspacePremiumOutlined from "@mui/icons-material/WorkspacePremiumOutlined"; @@ -63,6 +64,7 @@ const iconMap = { settings: SettingsApplicationsOutlined, shield: ShieldOutlined, sports_esports: SportsEsportsOutlined, + storefront: StorefrontOutlined, task: TaskAltOutlined, users: ManageAccountsOutlined, wallet: WalletOutlined, @@ -127,6 +129,7 @@ export const fallbackNavigation = [ label: "资源管理", children: [ routeNavItem("resource-list", { icon: Inventory2Outlined }), + routeNavItem("resource-shop-list", { icon: StorefrontOutlined }), routeNavItem("resource-group-list", { icon: CategoryOutlined }), routeNavItem("gift-list", { icon: CardGiftcardOutlined }), routeNavItem("resource-grant-list", { icon: SendOutlined }), diff --git a/src/app/permissions.ts b/src/app/permissions.ts index f9c4f4f..6c5ab18 100644 --- a/src/app/permissions.ts +++ b/src/app/permissions.ts @@ -83,6 +83,8 @@ export const PERMISSIONS = { resourceView: "resource:view", resourceCreate: "resource:create", resourceUpdate: "resource:update", + resourceShopView: "resource-shop:view", + resourceShopUpdate: "resource-shop:update", resourceGroupView: "resource-group:view", resourceGroupCreate: "resource-group:create", resourceGroupUpdate: "resource-group:update", @@ -150,6 +152,7 @@ export const MENU_CODES = { appConfigVersions: "app-config-versions", resources: "resources", resourceList: "resource-list", + resourceShopList: "resource-shop-list", resourceGroupList: "resource-group-list", resourceGrantList: "resource-grant-list", giftList: "gift-list", diff --git a/src/features/app-config/hooks/useBannerConfigPage.js b/src/features/app-config/hooks/useBannerConfigPage.js index cdcbca2..a4bfd02 100644 --- a/src/features/app-config/hooks/useBannerConfigPage.js +++ b/src/features/app-config/hooks/useBannerConfigPage.js @@ -16,7 +16,7 @@ const emptyForm = () => ({ countryCode: "", coverUrl: "", description: "", - displayScope: "home", + displayScopes: ["home"], endsAtMs: "", param: "", platform: "android", @@ -179,14 +179,15 @@ export function useBannerConfigPage() { } function normalizeForm(form) { - const displayScope = form.displayScope || "home"; + const displayScopes = normalizeDisplayScopes(form.displayScopes || form.displayScope); return { ...form, countryCode: form.countryCode || "", - displayScope, + displayScope: displayScopes[0] || "home", + displayScopes, endsAtMs: form.endsAtMs || 0, regionId: form.regionId || 0, - roomSmallImageUrl: displayScope === "room" ? form.roomSmallImageUrl || "" : "", + roomSmallImageUrl: displayScopes.includes("room") ? form.roomSmallImageUrl || "" : "", sortOrder: form.sortOrder || 0, startsAtMs: form.startsAtMs || 0, }; @@ -198,7 +199,7 @@ function formFromBanner(item) { countryCode: item.countryCode || "", coverUrl: item.coverUrl || "", description: item.description || "", - displayScope: item.displayScope || "home", + displayScopes: normalizeDisplayScopes(item.displayScopes || item.displayScope), endsAtMs: item.endsAtMs || "", param: item.param || "", platform: item.platform || "android", @@ -209,3 +210,11 @@ function formFromBanner(item) { status: item.status || "active", }; } + +function normalizeDisplayScopes(value) { + const values = Array.isArray(value) ? value : String(value || "").split(","); + const known = ["home", "room", "recharge"]; + const seen = new Set(values.map((item) => String(item || "").trim()).filter(Boolean)); + const normalized = known.filter((scope) => seen.has(scope)); + return normalized.length ? normalized : ["home"]; +} diff --git a/src/features/app-config/pages/BannerConfigPage.jsx b/src/features/app-config/pages/BannerConfigPage.jsx index 8901dba..9c0dc7c 100644 --- a/src/features/app-config/pages/BannerConfigPage.jsx +++ b/src/features/app-config/pages/BannerConfigPage.jsx @@ -2,6 +2,8 @@ import AddOutlined from "@mui/icons-material/AddOutlined"; import DeleteOutlineOutlined from "@mui/icons-material/DeleteOutlineOutlined"; import EditOutlined from "@mui/icons-material/EditOutlined"; import ImageOutlined from "@mui/icons-material/ImageOutlined"; +import Checkbox from "@mui/material/Checkbox"; +import ListItemText from "@mui/material/ListItemText"; import MenuItem from "@mui/material/MenuItem"; import TextField from "@mui/material/TextField"; import { useMemo } from "react"; @@ -94,7 +96,7 @@ export function BannerConfigPage() { > page.setForm({ coverUrl })} /> - {page.form.displayScope === "room" ? ( + {hasDisplayScope(page.form.displayScopes, "room") ? ( displayScopeListLabel(selected), + }, + }} + value={page.form.displayScopes} onChange={(event) => { - const displayScope = event.target.value; + const displayScopes = normalizeSelectedDisplayScopes(event.target.value); page.setForm({ - displayScope, - roomSmallImageUrl: displayScope === "room" ? page.form.roomSmallImageUrl : "", + displayScopes, + roomSmallImageUrl: displayScopes.includes("room") + ? page.form.roomSmallImageUrl + : "", }); }} > {APP_BANNER_DISPLAY_SCOPE_OPTIONS.map((option) => ( - {option.label} + + ))} @@ -259,7 +270,7 @@ function bannerColumns(page) { { key: "displayScope", label: "显示范围", - render: (item) => displayScopeLabel(item.displayScope), + render: (item) => displayScopeListLabel(item.displayScopes || item.displayScope), filter: createOptionsColumnFilter({ options: displayScopeFilterOptions, placeholder: "搜索显示范围", @@ -437,6 +448,23 @@ function displayScopeLabel(value) { return APP_BANNER_DISPLAY_SCOPE_OPTIONS.find((option) => option.value === value)?.label || value || "-"; } +function displayScopeListLabel(value) { + const values = normalizeSelectedDisplayScopes(value); + return values.map((scope) => displayScopeLabel(scope)).join("、") || "-"; +} + +function normalizeSelectedDisplayScopes(value) { + const values = Array.isArray(value) ? value : String(value || "").split(","); + const allowed = APP_BANNER_DISPLAY_SCOPE_OPTIONS.map((option) => option.value); + const seen = new Set(values.map((item) => String(item || "").trim()).filter(Boolean)); + const selected = allowed.filter((scope) => seen.has(scope)); + return selected.length ? selected : ["home"]; +} + +function hasDisplayScope(value, scope) { + return normalizeSelectedDisplayScopes(value).includes(scope); +} + function deliveryTimeLabel(startsAtMs, endsAtMs) { const start = startsAtMs ? formatMillis(startsAtMs) : "不限"; const end = endsAtMs ? formatMillis(endsAtMs) : "不限"; diff --git a/src/features/app-config/schema.test.ts b/src/features/app-config/schema.test.ts index 1dea04a..f220dac 100644 --- a/src/features/app-config/schema.test.ts +++ b/src/features/app-config/schema.test.ts @@ -8,6 +8,7 @@ const validBannerForm = { coverUrl: "https://media.haiyihy.com/banner/home.png", description: "", displayScope: "home", + displayScopes: ["home"], endsAtMs: "1800000000000", param: "https://h5.example.com/activity", platform: "android", @@ -43,16 +44,26 @@ describe("app config form schema", () => { test("keeps banner display scope and delivery time fields", () => { const payload = parseForm(appBannerSchema, validBannerForm); - expect(payload.displayScope).toBe("home"); + expect(payload.displayScopes).toEqual(["home"]); expect(payload.startsAtMs).toBe(1700000000000); expect(payload.endsAtMs).toBe(1800000000000); }); + test("accepts multiple banner display scopes", () => { + const payload = parseForm(appBannerSchema, { + ...validBannerForm, + displayScopes: ["home", "room", "recharge"], + roomSmallImageUrl: "https://media.haiyihy.com/banner/room-small.png", + }); + + expect(payload.displayScopes).toEqual(["home", "room", "recharge"]); + }); + test("requires room small image for room banner", () => { expect(() => parseForm(appBannerSchema, { ...validBannerForm, - displayScope: "room", + displayScopes: ["home", "room"], roomSmallImageUrl: "", }), ).toThrow(FormValidationError); diff --git a/src/features/app-config/schema.ts b/src/features/app-config/schema.ts index 50718d6..7044acf 100644 --- a/src/features/app-config/schema.ts +++ b/src/features/app-config/schema.ts @@ -1,5 +1,7 @@ import { z } from "zod"; +const appBannerDisplayScopes = ["home", "room", "recharge"] as const; + const requiredH5LinkURLSchema = z .string() .trim() @@ -46,7 +48,8 @@ export const appBannerSchema = z .max(1024, "封面图地址不能超过 1024 个字符") .refine((value) => !/\s/.test(value), "封面图地址不能包含空白字符"), description: z.string().trim().max(255, "描述不能超过 255 个字符"), - displayScope: z.enum(["home", "room", "recharge"]), + displayScope: z.enum(appBannerDisplayScopes).optional(), + displayScopes: z.array(z.enum(appBannerDisplayScopes)).min(1, "请选择显示范围"), endsAtMs: z.coerce.number().int().min(0, "投放结束时间不正确").default(0), param: z.string().trim().max(2048, "参数不能超过 2048 个字符"), platform: z.enum(["android", "ios"]), @@ -67,7 +70,7 @@ export const appBannerSchema = z if (value.bannerType === "h5" && /\s/.test(value.param)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "H5 链接不能包含空白字符", path: ["param"] }); } - if (value.displayScope === "room" && !value.roomSmallImageUrl) { + if (value.displayScopes.includes("room") && !value.roomSmallImageUrl) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "房间内显示需要上传房间内小屏图", diff --git a/src/features/resources/api.test.ts b/src/features/resources/api.test.ts index 34804b2..1cc5db7 100644 --- a/src/features/resources/api.test.ts +++ b/src/features/resources/api.test.ts @@ -5,9 +5,11 @@ import { createGift, createResource, createResourceGroup, + disableResourceShopItem, disableGift, disableResource, disableResourceGroup, + enableResourceShopItem, enableGift, enableResource, enableResourceGroup, @@ -18,11 +20,13 @@ import { listGiftTypes, listResourceGrants, listGifts, + listResourceShopItems, listResources, updateGift, updateGiftTypes, updateResource, updateResourceGroup, + upsertResourceShopItems, } from "./api"; afterEach(() => { @@ -266,6 +270,50 @@ test("emoji pack APIs use generated admin paths", async () => { }); }); +test("resource shop APIs use generated admin paths", async () => { + vi.stubGlobal( + "fetch", + vi.fn( + async () => new Response(JSON.stringify({ code: 0, data: { items: [], page: 1, pageSize: 10, total: 0 } })), + ), + ); + + await listResourceShopItems({ page: 1, page_size: 10, resource_type: "avatar_frame", status: "active" }); + await upsertResourceShopItems({ + items: [ + { + durationDays: 3, + effectiveFromMs: 0, + effectiveToMs: 0, + resourceId: 11, + sortOrder: 0, + status: "active", + }, + ], + }); + await enableResourceShopItem(99); + await disableResourceShopItem(99); + + const [listUrl, listInit] = vi.mocked(fetch).mock.calls[0]; + const [upsertUrl, upsertInit] = vi.mocked(fetch).mock.calls[1]; + const [enableUrl, enableInit] = vi.mocked(fetch).mock.calls[2]; + const [disableUrl, disableInit] = vi.mocked(fetch).mock.calls[3]; + + expect(String(listUrl)).toContain("/api/v1/admin/resource-shop/items?"); + expect(String(listUrl)).toContain("resource_type=avatar_frame"); + expect(String(listUrl)).toContain("status=active"); + expect(listInit?.method).toBe("GET"); + expect(String(upsertUrl)).toContain("/api/v1/admin/resource-shop/items"); + expect(upsertInit?.method).toBe("POST"); + expect(JSON.parse(String(upsertInit?.body))).toMatchObject({ + items: [{ durationDays: 3, resourceId: 11, status: "active" }], + }); + expect(String(enableUrl)).toContain("/api/v1/admin/resource-shop/items/99/enable"); + expect(enableInit?.method).toBe("POST"); + expect(String(disableUrl)).toContain("/api/v1/admin/resource-shop/items/99/disable"); + expect(disableInit?.method).toBe("POST"); +}); + test("gift type APIs save all tabs with one request", async () => { vi.stubGlobal( "fetch", diff --git a/src/features/resources/api.ts b/src/features/resources/api.ts index ffab74a..e844a99 100644 --- a/src/features/resources/api.ts +++ b/src/features/resources/api.ts @@ -93,6 +93,22 @@ export interface ResourceGroupDto { updatedAtMs?: number; } +export interface ResourceShopItemDto { + appCode?: string; + shopItemId: number; + resourceId: number; + resource?: ResourceDto; + status?: string; + durationDays?: number; + priceType?: string; + coinPrice?: number; + effectiveFromMs?: number; + effectiveToMs?: number; + sortOrder?: number; + createdAtMs?: number; + updatedAtMs?: number; +} + export interface GiftDto { appCode?: string; giftId: string; @@ -241,6 +257,20 @@ export interface ResourceGroupPayload { items: ResourceGroupItemPayload[]; } +export interface ResourceShopItemPayload { + durationDays: number; + effectiveFromMs: number; + effectiveToMs: number; + resourceId: number; + shopItemId?: number; + sortOrder: number; + status: string; +} + +export interface ResourceShopItemsPayload { + items: ResourceShopItemPayload[]; +} + export function listResources(query: PageQuery = {}): Promise> { const endpoint = API_ENDPOINTS.listResources; return apiRequest>(apiEndpointPath(API_OPERATIONS.listResources), { @@ -290,6 +320,45 @@ export function listResourceGroups(query: PageQuery = {}): Promise> { + const endpoint = API_ENDPOINTS.listResourceShopItems; + return apiRequest>(apiEndpointPath(API_OPERATIONS.listResourceShopItems), { + method: endpoint.method, + query, + }); +} + +export function upsertResourceShopItems(payload: ResourceShopItemsPayload): Promise { + const endpoint = API_ENDPOINTS.upsertResourceShopItems; + return apiRequest( + apiEndpointPath(API_OPERATIONS.upsertResourceShopItems), + { + body: payload, + method: endpoint.method, + }, + ); +} + +export function enableResourceShopItem(shopItemId: EntityId): Promise { + const endpoint = API_ENDPOINTS.enableResourceShopItem; + return apiRequest( + apiEndpointPath(API_OPERATIONS.enableResourceShopItem, { shop_item_id: shopItemId }), + { + method: endpoint.method, + }, + ); +} + +export function disableResourceShopItem(shopItemId: EntityId): Promise { + const endpoint = API_ENDPOINTS.disableResourceShopItem; + return apiRequest( + apiEndpointPath(API_OPERATIONS.disableResourceShopItem, { shop_item_id: shopItemId }), + { + method: endpoint.method, + }, + ); +} + export function createResourceGroup(payload: ResourceGroupPayload): Promise { const endpoint = API_ENDPOINTS.createResourceGroup; return apiRequest(apiEndpointPath(API_OPERATIONS.createResourceGroup), { diff --git a/src/features/resources/constants.js b/src/features/resources/constants.js index 60c5c3b..4e14d16 100644 --- a/src/features/resources/constants.js +++ b/src/features/resources/constants.js @@ -72,6 +72,27 @@ export const resourceTypeFilters = [ export const resourceTypeLabels = Object.fromEntries(resourceTypeFilters.filter(([value]) => value)); +export const resourceShopDurationOptions = [ + ["1", "1天"], + ["3", "3天"], + ["7", "7天"], +]; + +export const resourceShopSellableTypes = [ + "avatar_frame", + "profile_card", + "vehicle", + "chat_bubble", + "badge", + "mic_seat_icon", + "mic_seat_animation", +]; + +export const resourceShopTypeFilters = [ + ["", "全部类型"], + ...resourceTypeFilters.filter(([value]) => resourceShopSellableTypes.includes(value)), +]; + export const resourceGroupAssetOptions = [ ["COIN", "金币"], ["DIAMOND", "钻石"], diff --git a/src/features/resources/hooks/useResourcePages.js b/src/features/resources/hooks/useResourcePages.js index c04ed02..0d72edb 100644 --- a/src/features/resources/hooks/useResourcePages.js +++ b/src/features/resources/hooks/useResourcePages.js @@ -8,9 +8,11 @@ import { createGift, createResource, createResourceGroup, + disableResourceShopItem, disableGift, disableResource, disableResourceGroup, + enableResourceShopItem, enableGift, enableResource, enableResourceGroup, @@ -22,13 +24,15 @@ import { listGifts, listResourceGrants, listResourceGroups, + listResourceShopItems, listResources, updateGift, updateGiftTypes, updateResource, updateResourceGroup, + upsertResourceShopItems, } from "@/features/resources/api"; -import { defaultGiftTypeOptions } from "@/features/resources/constants.js"; +import { defaultGiftTypeOptions, resourceShopSellableTypes } from "@/features/resources/constants.js"; import { useResourceAbilities } from "@/features/resources/permissions.js"; import { emojiPackFormSchema, @@ -37,6 +41,7 @@ import { resourceFormSchema, resourceGrantFormSchema, resourceGroupCreateFormSchema, + resourceShopItemsFormSchema, } from "@/features/resources/schema.js"; const pageSize = 50; @@ -308,6 +313,243 @@ export function useResourceListPage() { }; } +export function useResourceShopPage() { + const abilities = useResourceAbilities(); + const { showToast } = useToast(); + const [query, setQuery] = useState(""); + const [status, setStatus] = useState(""); + const [resourceType, setResourceType] = useState(""); + const [page, setPage] = useState(1); + const [drawerOpen, setDrawerOpen] = useState(false); + const [drawerQuery, setDrawerQuery] = useState(""); + const [drawerResourceType, setDrawerResourceType] = useState(""); + const [batchDurationDays, setBatchDurationDays] = useState("1"); + const [resourceOptions, setResourceOptions] = useState([]); + const [resourceOptionsLoading, setResourceOptionsLoading] = useState(false); + const [draftByResourceId, setDraftByResourceId] = useState({}); + const [loadingAction, setLoadingAction] = useState(""); + const filters = useMemo( + () => ({ + keyword: query, + resource_type: resourceType, + status, + }), + [query, resourceType, status], + ); + const result = usePaginatedQuery({ + errorMessage: "加载道具商店失败", + fetcher: listResourceShopItems, + filters, + page, + pageSize, + queryKey: ["resource-shop", filters, page], + }); + const shopItemsByResourceId = useMemo(() => { + const items = new Map(); + (result.data?.items || []).forEach((item) => { + if (item.resourceId) { + items.set(Number(item.resourceId), item); + } + }); + return items; + }, [result.data?.items]); + const selectedDrafts = useMemo( + () => + Object.values(draftByResourceId) + .map((draft) => ({ + ...draft, + resource: resourceOptions.find( + (resource) => String(resource.resourceId) === String(draft.resourceId), + ), + })) + .sort((left, right) => Number(left.sortOrder || 0) - Number(right.sortOrder || 0)), + [draftByResourceId, resourceOptions], + ); + const filteredResourceOptions = useMemo(() => { + const keyword = drawerQuery.trim().toLowerCase(); + return resourceOptions.filter((resource) => { + if (drawerResourceType && resource.resourceType !== drawerResourceType) { + return false; + } + if (!keyword) { + return true; + } + return `${resource.name || ""} ${resource.resourceCode || ""}`.toLowerCase().includes(keyword); + }); + }, [drawerQuery, drawerResourceType, resourceOptions]); + + useEffect(() => { + if (!drawerOpen) { + return undefined; + } + let ignore = false; + setResourceOptionsLoading(true); + listResources({ page: 1, page_size: 100, status: "active" }) + .then((data) => { + if (!ignore) { + setResourceOptions(toShopResourceOptions(data.items || [])); + } + }) + .catch((err) => { + if (!ignore) { + showToast(err.message || "加载售卖资源失败", "error"); + } + }) + .finally(() => { + if (!ignore) { + setResourceOptionsLoading(false); + } + }); + return () => { + ignore = true; + }; + }, [drawerOpen, showToast]); + + const openShopDrawer = () => { + setDraftByResourceId({}); + setDrawerQuery(""); + setDrawerResourceType(""); + setBatchDurationDays("1"); + setDrawerOpen(true); + }; + + const closeShopDrawer = () => { + setDrawerOpen(false); + setDraftByResourceId({}); + }; + + const toggleDraftResource = (resource) => { + if (!resource?.resourceId) { + return; + } + const resourceId = String(resource.resourceId); + setDraftByResourceId((current) => { + if (current[resourceId]) { + const next = { ...current }; + delete next[resourceId]; + return next; + } + const existing = shopItemsByResourceId.get(Number(resource.resourceId)); + return { + ...current, + [resourceId]: { + durationDays: String(existing?.durationDays || batchDurationDays), + effectiveFrom: msToDatetimeLocal(existing?.effectiveFromMs), + effectiveTo: msToDatetimeLocal(existing?.effectiveToMs), + resourceId, + sortOrder: String(existing?.sortOrder ?? Object.keys(current).length), + }, + }; + }); + }; + + const updateDraftItem = (resourceId, patch) => { + setDraftByResourceId((current) => ({ + ...current, + [resourceId]: { + ...current[resourceId], + ...patch, + }, + })); + }; + + const applyBatchDuration = (durationDays) => { + setBatchDurationDays(durationDays); + setDraftByResourceId((current) => + Object.fromEntries( + Object.entries(current).map(([resourceId, draft]) => [resourceId, { ...draft, durationDays }]), + ), + ); + }; + + const submitShopItems = async (event) => { + event.preventDefault(); + if (!abilities.canUpdateShop) { + return; + } + setLoadingAction("resource-shop-upsert"); + try { + const parsed = parseForm(resourceShopItemsFormSchema, { items: selectedDrafts }); + await upsertResourceShopItems({ + items: parsed.items.map((item) => ({ + durationDays: Number(item.durationDays), + effectiveFromMs: datetimeLocalToMs(item.effectiveFrom), + effectiveToMs: datetimeLocalToMs(item.effectiveTo), + resourceId: Number(item.resourceId), + shopItemId: shopItemsByResourceId.get(Number(item.resourceId))?.shopItemId, + sortOrder: Number(item.sortOrder || 0), + status: "active", + })), + }); + showToast("售卖资源已保存", "success"); + closeShopDrawer(); + await result.reload(); + } catch (err) { + showToast(err.message || "保存售卖资源失败", "error"); + } finally { + setLoadingAction(""); + } + }; + + const toggleShopItem = async (item, nextEnabled = item.status !== "active") => { + if (!abilities.canUpdateShop || !item?.shopItemId) { + return; + } + if ((item.status === "active") === nextEnabled) { + return; + } + setLoadingAction(`resource-shop-status-${item.shopItemId}`); + try { + if (nextEnabled) { + await enableResourceShopItem(item.shopItemId); + } else { + await disableResourceShopItem(item.shopItemId); + } + showToast(nextEnabled ? "售卖资源已启用" : "售卖资源已禁用", "success"); + await result.reload(); + } catch (err) { + showToast(err.message || "操作失败", "error"); + } finally { + setLoadingAction(""); + } + }; + + const resetFilters = () => { + setQuery(""); + setStatus(""); + setResourceType(""); + setPage(1); + }; + + return { + ...sharedPageState({ page, query, result, setPage, setQuery }), + abilities, + applyBatchDuration, + batchDurationDays, + changeDrawerQuery: setDrawerQuery, + changeDrawerResourceType: setDrawerResourceType, + changeResourceType: resetSetter(setResourceType, setPage), + changeStatus: resetSetter(setStatus, setPage), + closeShopDrawer, + drawerOpen, + drawerQuery, + drawerResourceType, + filteredResourceOptions, + loadingAction, + openShopDrawer, + resourceOptionsLoading, + resourceType, + resetFilters, + selectedDrafts, + selectedResourceIds: new Set(Object.keys(draftByResourceId)), + status, + submitShopItems, + toggleDraftResource, + toggleShopItem, + updateDraftItem, + }; +} + export function useResourceGroupListPage() { const abilities = useResourceAbilities(); const { showToast } = useToast(); @@ -1245,6 +1487,16 @@ function toGiftResourceOptions(items, selectedGift) { ); } +function toShopResourceOptions(items) { + return uniqueResources(items).filter( + (resource) => + resourceShopSellableTypes.includes(resource.resourceType) && + resource.status === "active" && + resource.priceType === "coin" && + Number(resource.coinPrice || 0) > 0, + ); +} + function uniqueResources(resources) { const seen = new Set(); return resources.filter((resource) => { diff --git a/src/features/resources/pages/ResourceShopPage.jsx b/src/features/resources/pages/ResourceShopPage.jsx new file mode 100644 index 0000000..10ace64 --- /dev/null +++ b/src/features/resources/pages/ResourceShopPage.jsx @@ -0,0 +1,344 @@ +import Add from "@mui/icons-material/Add"; +import StorefrontOutlined from "@mui/icons-material/StorefrontOutlined"; +import Checkbox from "@mui/material/Checkbox"; +import MenuItem from "@mui/material/MenuItem"; +import TextField from "@mui/material/TextField"; +import { AdminSwitch } from "@/shared/ui/AdminSwitch.jsx"; +import { Button } from "@/shared/ui/Button.jsx"; +import { DataState } from "@/shared/ui/DataState.jsx"; +import { DataTable } from "@/shared/ui/DataTable.jsx"; +import { + AdminActionIconButton, + AdminListBody, + AdminListPage, + AdminListToolbar, +} from "@/shared/ui/AdminListLayout.jsx"; +import { SideDrawer } from "@/shared/ui/SideDrawer.jsx"; +import { createOptionsColumnFilter, createTextColumnFilter } from "@/shared/ui/tableFilters.js"; +import { formatMillis } from "@/shared/utils/time.js"; +import { + resourcePriceTypeLabels, + resourceShopDurationOptions, + resourceShopTypeFilters, + resourceStatusFilters, + resourceTypeLabels, +} from "@/features/resources/constants.js"; +import { useResourceShopPage } from "@/features/resources/hooks/useResourcePages.js"; +import styles from "@/features/resources/resources.module.css"; + +const shopColumns = [ + { + key: "resource", + label: "售卖资源", + width: "minmax(270px, 1.4fr)", + render: (item) => , + }, + { + key: "type", + label: "类型", + width: "minmax(120px, 0.65fr)", + render: (item) => resourceTypeLabels[item.resource?.resourceType] || item.resource?.resourceType || "-", + }, + { + key: "sale", + label: "售卖规格", + width: "minmax(150px, 0.8fr)", + render: (item) => , + }, + { + key: "effective", + label: "生效时间", + width: "minmax(220px, 1fr)", + render: (item) => , + }, + { + key: "sort", + label: "排序", + width: "minmax(80px, 0.4fr)", + render: (item) => item.sortOrder ?? 0, + }, + { + key: "status", + label: "状态", + width: "minmax(92px, 0.5fr)", + }, + { + key: "time", + label: "更新时间", + width: "minmax(170px, 0.8fr)", + render: (item) => formatMillis(item.updatedAtMs || item.createdAtMs), + }, +]; + +export function ResourceShopPage() { + const page = useResourceShopPage(); + const items = page.data.items || []; + const total = page.data.total || 0; + const columns = shopColumns.map((column) => { + if (column.key === "resource") { + return { + ...column, + filter: createTextColumnFilter({ + placeholder: "搜索资源名称、资源编码", + value: page.query, + onChange: page.changeQuery, + }), + }; + } + if (column.key === "type") { + return { + ...column, + filter: createOptionsColumnFilter({ + options: resourceShopTypeFilters, + placeholder: "搜索类型", + value: page.resourceType, + onChange: page.changeResourceType, + }), + }; + } + if (column.key === "status") { + return { + ...column, + filter: createOptionsColumnFilter({ + options: resourceStatusFilters, + placeholder: "搜索状态", + value: page.status, + onChange: page.changeStatus, + }), + render: (item) => , + }; + } + return column; + }); + + return ( + + + + + ) : null + } + /> + + + 0 + ? { + page: page.page, + pageSize: page.data.pageSize || 50, + total, + onPageChange: page.setPage, + } + : undefined + } + rowKey={(item) => item.shopItemId} + /> + + + + + ); +} + +function ResourceShopDrawer({ page }) { + const saving = page.loadingAction === "resource-shop-upsert"; + const disabled = !page.abilities.canUpdateShop || saving; + return ( + + + + + } + as="form" + open={page.drawerOpen} + title="添加售卖资源" + width="wide" + onClose={saving ? undefined : page.closeShopDrawer} + onSubmit={page.submitShopItems} + > +
+ page.changeDrawerQuery(event.target.value)} + /> + page.changeDrawerResourceType(event.target.value)} + > + {resourceShopTypeFilters.map(([value, label]) => ( + + {label} + + ))} + + page.applyBatchDuration(event.target.value)} + > + {resourceShopDurationOptions.map(([value, label]) => ( + + {label} + + ))} + +
+ + {page.filteredResourceOptions.length > 0 ? ( +
+ {page.filteredResourceOptions.map((resource) => ( + + ))} +
+ ) : ( +
暂无可售卖资源
+ )} +
+
+ ); +} + +function ResourceSelectionRow({ disabled, page, resource }) { + const resourceId = String(resource.resourceId); + const selected = page.selectedResourceIds.has(resourceId); + const draft = selected ? page.selectedDrafts.find((item) => String(item.resourceId) === resourceId) : null; + return ( +
+ page.toggleDraftResource(resource)} + /> + + {resourcePriceLabel(resource)} + {draft ? ( +
+ page.updateDraftItem(resourceId, { durationDays: event.target.value })} + > + {resourceShopDurationOptions.map(([value, label]) => ( + + {label} + + ))} + + page.updateDraftItem(resourceId, { effectiveFrom: event.target.value })} + /> + page.updateDraftItem(resourceId, { effectiveTo: event.target.value })} + /> + page.updateDraftItem(resourceId, { sortOrder: event.target.value })} + /> +
+ ) : null} +
+ ); +} + +function ResourceShopStatusSwitch({ item, page }) { + const checked = item.status === "active"; + return ( + page.toggleShopItem(item, event.target.checked)} + /> + ); +} + +function ResourceIdentity({ resource = {} }) { + const imageUrl = resource.previewUrl || resource.assetUrl || resource.animationUrl; + return ( +
+ + {imageUrl ? : } + + + {resource.name || "-"} + {resource.resourceCode || resource.resourceId || "-"} + +
+ ); +} + +function SaleSpec({ item }) { + return ( +
+ {item.durationDays || 1}天 + {resourcePriceLabel(item)} +
+ ); +} + +function EffectiveTime({ item }) { + const from = item.effectiveFromMs ? formatMillis(item.effectiveFromMs) : "立即生效"; + const to = item.effectiveToMs ? formatMillis(item.effectiveToMs) : "长期"; + return ( +
+ {from} + {to} +
+ ); +} + +function resourcePriceLabel(item = {}) { + if (item.priceType === "coin" || item.coinPrice > 0) { + return `${item.coinPrice || 0}金币`; + } + return resourcePriceTypeLabels[item.priceType] || "-"; +} diff --git a/src/features/resources/permissions.js b/src/features/resources/permissions.js index 4d94fa0..fb37c19 100644 --- a/src/features/resources/permissions.js +++ b/src/features/resources/permissions.js @@ -11,6 +11,7 @@ export function useResourceAbilities() { canCreateGroup: can(PERMISSIONS.resourceGroupCreate), canCreateEmojiPack: can(PERMISSIONS.emojiPackCreate), canStatusGift: can(PERMISSIONS.giftStatus), + canUpdateShop: can(PERMISSIONS.resourceShopUpdate), canUpdateGroup: can(PERMISSIONS.resourceGroupUpdate), canUpdateGift: can(PERMISSIONS.giftUpdate), canUpdate: can(PERMISSIONS.resourceUpdate), @@ -18,5 +19,6 @@ export function useResourceAbilities() { canView: can(PERMISSIONS.resourceView), canViewEmojiPack: can(PERMISSIONS.emojiPackView), canViewGrant: can(PERMISSIONS.resourceGrantView), + canViewShop: can(PERMISSIONS.resourceShopView), }; } diff --git a/src/features/resources/resources.module.css b/src/features/resources/resources.module.css index c8de3c0..dcc3d69 100644 --- a/src/features/resources/resources.module.css +++ b/src/features/resources/resources.module.css @@ -152,3 +152,57 @@ justify-content: flex-end; gap: var(--space-2); } + +.shopDrawerTools { + display: grid; + grid-template-columns: minmax(220px, 1fr) minmax(160px, 0.7fr) minmax(150px, 0.55fr); + gap: var(--space-3); +} + +.shopSelectionList { + display: grid; + gap: var(--space-2); +} + +.shopSelectionRow { + display: grid; + min-height: 56px; + align-items: center; + gap: var(--space-3); + grid-template-columns: 40px minmax(220px, 1fr) minmax(92px, 0.35fr) minmax(0, 2fr); + padding: var(--space-2) 0; + border-bottom: 1px solid var(--border-muted); +} + +.shopSelectionControls { + display: grid; + min-width: 0; + gap: var(--space-2); + grid-template-columns: minmax(112px, 0.7fr) minmax(170px, 1fr) minmax(170px, 1fr) minmax(84px, 0.45fr); +} + +.shopBasePrice { + color: var(--text-secondary); + font-weight: 650; + white-space: nowrap; +} + +.shopEmpty { + display: flex; + min-height: 180px; + align-items: center; + justify-content: center; + color: var(--text-tertiary); +} + +@media (max-width: 860px) { + .shopDrawerTools, + .shopSelectionRow, + .shopSelectionControls { + grid-template-columns: 1fr; + } + + .shopSelectionRow { + align-items: stretch; + } +} diff --git a/src/features/resources/routes.js b/src/features/resources/routes.js index 285824f..e5f30e8 100644 --- a/src/features/resources/routes.js +++ b/src/features/resources/routes.js @@ -9,6 +9,14 @@ export const resourceRoutes = [ path: "/resources", permission: PERMISSIONS.resourceView, }, + { + label: "道具商店", + loader: () => import("./pages/ResourceShopPage.jsx").then((module) => module.ResourceShopPage), + menuCode: MENU_CODES.resourceShopList, + pageKey: "resource-shop-list", + path: "/resource-shop", + permission: PERMISSIONS.resourceShopView, + }, { label: "资源组列表", loader: () => import("./pages/ResourceGroupListPage.jsx").then((module) => module.ResourceGroupListPage), diff --git a/src/features/resources/schema.js b/src/features/resources/schema.js index 89f3207..4976786 100644 --- a/src/features/resources/schema.js +++ b/src/features/resources/schema.js @@ -16,6 +16,7 @@ const resourceTypes = [ const walletAssetTypes = ["COIN", "DIAMOND"]; const resourcePriceTypes = ["coin", "free"]; const badgeForms = ["strip", "tile"]; +const resourceShopDurations = ["1", "3", "7"]; const optionalWalletAssetTypeSchema = z .preprocess((value) => { if (typeof value !== "string") { @@ -285,6 +286,82 @@ export const giftTypeConfigFormSchema = z.object({ .min(1, "请至少保留一个礼物类型"), }); +export const resourceShopItemsFormSchema = z + .object({ + items: z + .array( + z.object({ + durationDays: z.union([z.string(), z.number()]), + effectiveFrom: z.string().optional(), + effectiveTo: z.string().optional(), + resourceId: z.union([z.string(), z.number()]), + sortOrder: z.union([z.string(), z.number()]).optional(), + }), + ) + .min(1, "请至少选择一个资源"), + }) + .superRefine((value, context) => { + const resourceIds = new Set(); + value.items.forEach((item, index) => { + const resourceId = Number(item.resourceId); + const durationDays = String(item.durationDays || "").trim(); + const effectiveFromMs = datetimeLocalToMs(item.effectiveFrom); + const effectiveToMs = datetimeLocalToMs(item.effectiveTo); + const sortOrder = Number(item.sortOrder || 0); + + if (!Number.isInteger(resourceId) || resourceId <= 0) { + context.addIssue({ + code: "custom", + message: "请选择资源", + path: ["items", index, "resourceId"], + }); + } + if (resourceIds.has(resourceId)) { + context.addIssue({ + code: "custom", + message: "同一个资源不能重复添加", + path: ["items", index, "resourceId"], + }); + } + resourceIds.add(resourceId); + if (!resourceShopDurations.includes(durationDays)) { + context.addIssue({ + code: "custom", + message: "售卖天数只能选择 1、3、7 天", + path: ["items", index, "durationDays"], + }); + } + if (effectiveFromMs < 0) { + context.addIssue({ + code: "custom", + message: "请选择生效开始时间", + path: ["items", index, "effectiveFrom"], + }); + } + if (effectiveToMs < 0) { + context.addIssue({ + code: "custom", + message: "请选择生效结束时间", + path: ["items", index, "effectiveTo"], + }); + } + if (effectiveFromMs > 0 && effectiveToMs > 0 && effectiveToMs <= effectiveFromMs) { + context.addIssue({ + code: "custom", + message: "生效结束时间必须晚于开始时间", + path: ["items", index, "effectiveTo"], + }); + } + if (!Number.isInteger(sortOrder) || sortOrder < 0) { + context.addIssue({ + code: "custom", + message: "排序不能小于 0", + path: ["items", index, "sortOrder"], + }); + } + }); + }); + function datetimeLocalToMs(value) { const trimmed = String(value || "").trim(); if (!trimmed) { diff --git a/src/features/resources/schema.test.ts b/src/features/resources/schema.test.ts index b3698bf..738d02c 100644 --- a/src/features/resources/schema.test.ts +++ b/src/features/resources/schema.test.ts @@ -6,6 +6,7 @@ import { resourceFormSchema, resourceGrantFormSchema, resourceGroupCreateFormSchema, + resourceShopItemsFormSchema, } from "./schema.js"; describe("resource form schema", () => { @@ -147,4 +148,33 @@ describe("resource form schema", () => { expect(payload.subjectType).toBe("resource"); }); + + test("validates resource shop durations", () => { + const payload = parseForm(resourceShopItemsFormSchema, { + items: [ + { + durationDays: "3", + effectiveFrom: "", + effectiveTo: "", + resourceId: "11", + sortOrder: "0", + }, + ], + }); + + expect(payload.items[0].durationDays).toBe("3"); + expect(() => + parseForm(resourceShopItemsFormSchema, { + items: [ + { + durationDays: "2", + effectiveFrom: "", + effectiveTo: "", + resourceId: "11", + sortOrder: "0", + }, + ], + }), + ).toThrow(FormValidationError); + }); }); diff --git a/src/shared/api/generated/endpoints.ts b/src/shared/api/generated/endpoints.ts index 10fc5ae..33631bc 100644 --- a/src/shared/api/generated/endpoints.ts +++ b/src/shared/api/generated/endpoints.ts @@ -5,1495 +5,1527 @@ import type { PermissionCode } from "@/app/permissions"; export type ApiHttpMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT"; export interface ApiEndpoint { - method: ApiHttpMethod; - operationId: string; - path: string; - permission?: PermissionCode; - permissions?: PermissionCode[]; + method: ApiHttpMethod; + operationId: string; + path: string; + permission?: PermissionCode; + permissions?: PermissionCode[]; } export const API_OPERATIONS = { - appBanUser: "appBanUser", - appGetUser: "appGetUser", - appListBannedUsers: "appListBannedUsers", - appListLoginLogs: "appListLoginLogs", - appListUserLoginLogs: "appListUserLoginLogs", - appListUsers: "appListUsers", - appSetPassword: "appSetPassword", - appUnbanUser: "appUnbanUser", - appUpdateUser: "appUpdateUser", - batchUpdateUserStatus: "batchUpdateUserStatus", - cancelRoomPin: "cancelRoomPin", - changePassword: "changePassword", - closeAgency: "closeAgency", - createAchievementDefinition: "createAchievementDefinition", - createAgency: "createAgency", - createAppVersion: "createAppVersion", - createBanner: "createBanner", - createBD: "createBD", - createBDLeader: "createBDLeader", - createCatalog: "createCatalog", - createCoinAdjustment: "createCoinAdjustment", - createCoinSeller: "createCoinSeller", - createCountry: "createCountry", - createEmojiPack: "createEmojiPack", - createExploreTab: "createExploreTab", - createGift: "createGift", - createH5Link: "createH5Link", - createMenu: "createMenu", - createPermission: "createPermission", - createPlatform: "createPlatform", - createRechargeProduct: "createRechargeProduct", - createRegion: "createRegion", - createResource: "createResource", - createResourceGroup: "createResourceGroup", - createRole: "createRole", - createRoomPin: "createRoomPin", - createTaskDefinition: "createTaskDefinition", - createTier: "createTier", - createUser: "createUser", - creditCoinSellerStock: "creditCoinSellerStock", - dashboardOverview: "dashboardOverview", - deleteAppVersion: "deleteAppVersion", - deleteBanner: "deleteBanner", - deleteBDLeader: "deleteBDLeader", - deleteCatalog: "deleteCatalog", - deleteCountry: "deleteCountry", - deleteExploreTab: "deleteExploreTab", - deleteH5Link: "deleteH5Link", - deleteMenu: "deleteMenu", - deletePermission: "deletePermission", - deleteRechargeProduct: "deleteRechargeProduct", - deleteRole: "deleteRole", - deleteRoom: "deleteRoom", - disableCountry: "disableCountry", - disableGift: "disableGift", - disableRegion: "disableRegion", - disableResource: "disableResource", - disableResourceGroup: "disableResourceGroup", - enableCountry: "enableCountry", - enableGift: "enableGift", - enableRegion: "enableRegion", - enableResource: "enableResource", - enableResourceGroup: "enableResourceGroup", - exportLoginLogs: "exportLoginLogs", - exportOperationLogs: "exportOperationLogs", - exportUsers: "exportUsers", - getCountry: "getCountry", - getFirstRechargeRewardConfig: "getFirstRechargeRewardConfig", - getLuckyGiftConfig: "getLuckyGiftConfig", - getLuckyGiftDrawSummary: "getLuckyGiftDrawSummary", - getRedPacket: "getRedPacket", - getRedPacketConfig: "getRedPacketConfig", - getRegion: "getRegion", - getRegistrationRewardConfig: "getRegistrationRewardConfig", - getResource: "getResource", - getResourceGroup: "getResourceGroup", - getRoleDataScopes: "getRoleDataScopes", - getRoomConfig: "getRoomConfig", - getRoomTreasureConfig: "getRoomTreasureConfig", - getSevenDayCheckInConfig: "getSevenDayCheckInConfig", - getUser: "getUser", - grantResource: "grantResource", - grantResourceGroup: "grantResourceGroup", - listAchievementDefinitions: "listAchievementDefinitions", - listAgencies: "listAgencies", - listApps: "listApps", - listAppVersions: "listAppVersions", - listBanners: "listBanners", - listBDLeaders: "listBDLeaders", - listBDs: "listBDs", - listCatalog: "listCatalog", - listCoinAdjustments: "listCoinAdjustments", - listCoinLedger: "listCoinLedger", - listCoinSellers: "listCoinSellers", - listCountries: "listCountries", - listEmojiPackCategories: "listEmojiPackCategories", - listEmojiPacks: "listEmojiPacks", - listExploreTabs: "listExploreTabs", - listFirstRechargeRewardClaims: "listFirstRechargeRewardClaims", - listGifts: "listGifts", - listGiftTypes: "listGiftTypes", - listH5Links: "listH5Links", - listHosts: "listHosts", - listLevelConfig: "listLevelConfig", - listLoginLogs: "listLoginLogs", - listLuckyGiftConfigs: "listLuckyGiftConfigs", - listLuckyGiftDraws: "listLuckyGiftDraws", - listOperationLogs: "listOperationLogs", - listPermissions: "listPermissions", - listPlatforms: "listPlatforms", - listRechargeBills: "listRechargeBills", - listRechargeProducts: "listRechargeProducts", - listRedPackets: "listRedPackets", - listRegionBlocks: "listRegionBlocks", - listRegions: "listRegions", - listRegistrationRewardClaims: "listRegistrationRewardClaims", - listResourceGrants: "listResourceGrants", - listResourceGroups: "listResourceGroups", - listResources: "listResources", - listRoles: "listRoles", - listRoomPins: "listRoomPins", - listRooms: "listRooms", - listSevenDayCheckInClaims: "listSevenDayCheckInClaims", - listSystemMenus: "listSystemMenus", - listTaskDefinitions: "listTaskDefinitions", - listUserLeaderboards: "listUserLeaderboards", - listUsers: "listUsers", - login: "login", - logout: "logout", - lookupCoinAdjustmentTarget: "lookupCoinAdjustmentTarget", - me: "me", - navigationMenus: "navigationMenus", - refresh: "refresh", - replaceRegionBlocks: "replaceRegionBlocks", - replaceRegionCountries: "replaceRegionCountries", - replaceRoleDataScopes: "replaceRoleDataScopes", - replaceRolePermissions: "replaceRolePermissions", - resetUserPassword: "resetUserPassword", - search: "search", - setAgencyJoinEnabled: "setAgencyJoinEnabled", - setBDLeaderStatus: "setBDLeaderStatus", - setBDStatus: "setBDStatus", - setCoinSellerStatus: "setCoinSellerStatus", - setGameStatus: "setGameStatus", - setTaskDefinitionStatus: "setTaskDefinitionStatus", - sortMenus: "sortMenus", - syncPermissions: "syncPermissions", - updateAchievementDefinition: "updateAchievementDefinition", - updateAppVersion: "updateAppVersion", - updateBanner: "updateBanner", - updateCatalog: "updateCatalog", - updateCountry: "updateCountry", - updateExploreTab: "updateExploreTab", - updateFirstRechargeRewardConfig: "updateFirstRechargeRewardConfig", - updateGift: "updateGift", - updateGiftType: "updateGiftType", - updateGiftTypes: "updateGiftTypes", - updateH5Link: "updateH5Link", - updateH5Links: "updateH5Links", - updateMenu: "updateMenu", - updateMenuVisible: "updateMenuVisible", - updatePermission: "updatePermission", - updatePlatform: "updatePlatform", - updateRechargeProduct: "updateRechargeProduct", - updateRedPacketConfig: "updateRedPacketConfig", - updateRegion: "updateRegion", - updateRegistrationRewardConfig: "updateRegistrationRewardConfig", - updateResource: "updateResource", - updateResourceGroup: "updateResourceGroup", - updateResourceGroupItems: "updateResourceGroupItems", - updateRole: "updateRole", - updateRoom: "updateRoom", - updateRoomConfig: "updateRoomConfig", - updateRoomTreasureConfig: "updateRoomTreasureConfig", - updateSevenDayCheckInConfig: "updateSevenDayCheckInConfig", - updateTaskDefinition: "updateTaskDefinition", - updateTier: "updateTier", - updateTrack: "updateTrack", - updateUser: "updateUser", - updateUserStatus: "updateUserStatus", - uploadFile: "uploadFile", - uploadImage: "uploadImage", - upsertLuckyGiftConfig: "upsertLuckyGiftConfig", - upsertRule: "upsertRule", + appBanUser: "appBanUser", + appGetUser: "appGetUser", + appListBannedUsers: "appListBannedUsers", + appListLoginLogs: "appListLoginLogs", + appListUserLoginLogs: "appListUserLoginLogs", + appListUsers: "appListUsers", + appSetPassword: "appSetPassword", + appUnbanUser: "appUnbanUser", + appUpdateUser: "appUpdateUser", + batchUpdateUserStatus: "batchUpdateUserStatus", + cancelRoomPin: "cancelRoomPin", + changePassword: "changePassword", + closeAgency: "closeAgency", + createAchievementDefinition: "createAchievementDefinition", + createAgency: "createAgency", + createAppVersion: "createAppVersion", + createBanner: "createBanner", + createBD: "createBD", + createBDLeader: "createBDLeader", + createCatalog: "createCatalog", + createCoinAdjustment: "createCoinAdjustment", + createCoinSeller: "createCoinSeller", + createCountry: "createCountry", + createEmojiPack: "createEmojiPack", + createExploreTab: "createExploreTab", + createGift: "createGift", + createH5Link: "createH5Link", + createMenu: "createMenu", + createPermission: "createPermission", + createPlatform: "createPlatform", + createRechargeProduct: "createRechargeProduct", + createRegion: "createRegion", + createResource: "createResource", + createResourceGroup: "createResourceGroup", + createRole: "createRole", + createRoomPin: "createRoomPin", + createTaskDefinition: "createTaskDefinition", + createTier: "createTier", + createUser: "createUser", + creditCoinSellerStock: "creditCoinSellerStock", + dashboardOverview: "dashboardOverview", + deleteAppVersion: "deleteAppVersion", + deleteBanner: "deleteBanner", + deleteBDLeader: "deleteBDLeader", + deleteCatalog: "deleteCatalog", + deleteCountry: "deleteCountry", + deleteExploreTab: "deleteExploreTab", + deleteH5Link: "deleteH5Link", + deleteMenu: "deleteMenu", + deletePermission: "deletePermission", + deleteRechargeProduct: "deleteRechargeProduct", + deleteRole: "deleteRole", + deleteRoom: "deleteRoom", + disableCountry: "disableCountry", + disableGift: "disableGift", + disableRegion: "disableRegion", + disableResource: "disableResource", + disableResourceGroup: "disableResourceGroup", + disableResourceShopItem: "disableResourceShopItem", + enableCountry: "enableCountry", + enableGift: "enableGift", + enableRegion: "enableRegion", + enableResource: "enableResource", + enableResourceGroup: "enableResourceGroup", + enableResourceShopItem: "enableResourceShopItem", + exportLoginLogs: "exportLoginLogs", + exportOperationLogs: "exportOperationLogs", + exportUsers: "exportUsers", + getCountry: "getCountry", + getFirstRechargeRewardConfig: "getFirstRechargeRewardConfig", + getLuckyGiftConfig: "getLuckyGiftConfig", + getLuckyGiftDrawSummary: "getLuckyGiftDrawSummary", + getRedPacket: "getRedPacket", + getRedPacketConfig: "getRedPacketConfig", + getRegion: "getRegion", + getRegistrationRewardConfig: "getRegistrationRewardConfig", + getResource: "getResource", + getResourceGroup: "getResourceGroup", + getRoleDataScopes: "getRoleDataScopes", + getRoomConfig: "getRoomConfig", + getRoomTreasureConfig: "getRoomTreasureConfig", + getSevenDayCheckInConfig: "getSevenDayCheckInConfig", + getUser: "getUser", + grantResource: "grantResource", + grantResourceGroup: "grantResourceGroup", + listAchievementDefinitions: "listAchievementDefinitions", + listAgencies: "listAgencies", + listApps: "listApps", + listAppVersions: "listAppVersions", + listBanners: "listBanners", + listBDLeaders: "listBDLeaders", + listBDs: "listBDs", + listCatalog: "listCatalog", + listCoinAdjustments: "listCoinAdjustments", + listCoinLedger: "listCoinLedger", + listCoinSellers: "listCoinSellers", + listCountries: "listCountries", + listEmojiPackCategories: "listEmojiPackCategories", + listEmojiPacks: "listEmojiPacks", + listExploreTabs: "listExploreTabs", + listFirstRechargeRewardClaims: "listFirstRechargeRewardClaims", + listGifts: "listGifts", + listGiftTypes: "listGiftTypes", + listH5Links: "listH5Links", + listHosts: "listHosts", + listLevelConfig: "listLevelConfig", + listLoginLogs: "listLoginLogs", + listLuckyGiftConfigs: "listLuckyGiftConfigs", + listLuckyGiftDraws: "listLuckyGiftDraws", + listOperationLogs: "listOperationLogs", + listPermissions: "listPermissions", + listPlatforms: "listPlatforms", + listRechargeBills: "listRechargeBills", + listRechargeProducts: "listRechargeProducts", + listRedPackets: "listRedPackets", + listRegionBlocks: "listRegionBlocks", + listRegions: "listRegions", + listRegistrationRewardClaims: "listRegistrationRewardClaims", + listResourceGrants: "listResourceGrants", + listResourceGroups: "listResourceGroups", + listResources: "listResources", + listResourceShopItems: "listResourceShopItems", + listRoles: "listRoles", + listRoomPins: "listRoomPins", + listRooms: "listRooms", + listSevenDayCheckInClaims: "listSevenDayCheckInClaims", + listSystemMenus: "listSystemMenus", + listTaskDefinitions: "listTaskDefinitions", + listUserLeaderboards: "listUserLeaderboards", + listUsers: "listUsers", + login: "login", + logout: "logout", + lookupCoinAdjustmentTarget: "lookupCoinAdjustmentTarget", + me: "me", + navigationMenus: "navigationMenus", + refresh: "refresh", + replaceRegionBlocks: "replaceRegionBlocks", + replaceRegionCountries: "replaceRegionCountries", + replaceRoleDataScopes: "replaceRoleDataScopes", + replaceRolePermissions: "replaceRolePermissions", + resetUserPassword: "resetUserPassword", + search: "search", + setAgencyJoinEnabled: "setAgencyJoinEnabled", + setBDLeaderStatus: "setBDLeaderStatus", + setBDStatus: "setBDStatus", + setCoinSellerStatus: "setCoinSellerStatus", + setGameStatus: "setGameStatus", + setTaskDefinitionStatus: "setTaskDefinitionStatus", + sortMenus: "sortMenus", + syncPermissions: "syncPermissions", + updateAchievementDefinition: "updateAchievementDefinition", + updateAppVersion: "updateAppVersion", + updateBanner: "updateBanner", + updateCatalog: "updateCatalog", + updateCountry: "updateCountry", + updateExploreTab: "updateExploreTab", + updateFirstRechargeRewardConfig: "updateFirstRechargeRewardConfig", + updateGift: "updateGift", + updateGiftType: "updateGiftType", + updateGiftTypes: "updateGiftTypes", + updateH5Link: "updateH5Link", + updateH5Links: "updateH5Links", + updateMenu: "updateMenu", + updateMenuVisible: "updateMenuVisible", + updatePermission: "updatePermission", + updatePlatform: "updatePlatform", + updateRechargeProduct: "updateRechargeProduct", + updateRedPacketConfig: "updateRedPacketConfig", + updateRegion: "updateRegion", + updateRegistrationRewardConfig: "updateRegistrationRewardConfig", + updateResource: "updateResource", + updateResourceGroup: "updateResourceGroup", + updateResourceGroupItems: "updateResourceGroupItems", + updateRole: "updateRole", + updateRoom: "updateRoom", + updateRoomConfig: "updateRoomConfig", + updateRoomTreasureConfig: "updateRoomTreasureConfig", + updateSevenDayCheckInConfig: "updateSevenDayCheckInConfig", + updateTaskDefinition: "updateTaskDefinition", + updateTier: "updateTier", + updateTrack: "updateTrack", + updateUser: "updateUser", + updateUserStatus: "updateUserStatus", + uploadFile: "uploadFile", + uploadImage: "uploadImage", + upsertLuckyGiftConfig: "upsertLuckyGiftConfig", + upsertResourceShopItems: "upsertResourceShopItems", + upsertRule: "upsertRule" } as const; export type ApiOperationId = (typeof API_OPERATIONS)[keyof typeof API_OPERATIONS]; export const API_ENDPOINTS: Record = { - appBanUser: { - method: "POST", - operationId: API_OPERATIONS.appBanUser, - path: "/v1/app/users/{id}/ban", - permission: "app-user:status", - permissions: ["app-user:status"], - }, - appGetUser: { - method: "GET", - operationId: API_OPERATIONS.appGetUser, - path: "/v1/app/users/{id}", - permission: "app-user:view", - permissions: ["app-user:view"], - }, - appListBannedUsers: { - method: "GET", - operationId: API_OPERATIONS.appListBannedUsers, - path: "/v1/app/users/bans", - permission: "app-user:view", - permissions: ["app-user:view"], - }, - appListLoginLogs: { - method: "GET", - operationId: API_OPERATIONS.appListLoginLogs, - path: "/v1/app/users/login-logs", - permission: "app-user:view", - permissions: ["app-user:view"], - }, - appListUserLoginLogs: { - method: "GET", - operationId: API_OPERATIONS.appListUserLoginLogs, - path: "/v1/app/users/{id}/login-logs", - permission: "app-user:view", - permissions: ["app-user:view"], - }, - appListUsers: { - method: "GET", - operationId: API_OPERATIONS.appListUsers, - path: "/v1/app/users", - permission: "app-user:view", - permissions: ["app-user:view"], - }, - appSetPassword: { - method: "POST", - operationId: API_OPERATIONS.appSetPassword, - path: "/v1/app/users/{id}/password", - permission: "app-user:password", - permissions: ["app-user:password"], - }, - appUnbanUser: { - method: "POST", - operationId: API_OPERATIONS.appUnbanUser, - path: "/v1/app/users/{id}/unban", - permission: "app-user:status", - permissions: ["app-user:status"], - }, - appUpdateUser: { - method: "PATCH", - operationId: API_OPERATIONS.appUpdateUser, - path: "/v1/app/users/{id}", - permission: "app-user:update", - permissions: ["app-user:update"], - }, - batchUpdateUserStatus: { - method: "POST", - operationId: API_OPERATIONS.batchUpdateUserStatus, - path: "/v1/users/batch/status", - permission: "user:status", - permissions: ["user:status"], - }, - cancelRoomPin: { - method: "DELETE", - operationId: API_OPERATIONS.cancelRoomPin, - path: "/v1/admin/rooms/pins/{pin_id}", - permission: "room-pin:cancel", - permissions: ["room-pin:cancel"], - }, - changePassword: { - method: "POST", - operationId: API_OPERATIONS.changePassword, - path: "/v1/auth/change-password", - }, - closeAgency: { - method: "POST", - operationId: API_OPERATIONS.closeAgency, - path: "/v1/admin/agencies/{agency_id}/close", - permission: "agency:status", - permissions: ["agency:status"], - }, - createAchievementDefinition: { - method: "POST", - operationId: API_OPERATIONS.createAchievementDefinition, - path: "/v1/admin/activity/achievements", - permission: "achievement:create", - permissions: ["achievement:create"], - }, - createAgency: { - method: "POST", - operationId: API_OPERATIONS.createAgency, - path: "/v1/admin/agencies", - permission: "agency:create", - permissions: ["agency:create"], - }, - createAppVersion: { - method: "POST", - operationId: API_OPERATIONS.createAppVersion, - path: "/v1/admin/app-config/versions", - permission: "app-version:create", - permissions: ["app-version:create"], - }, - createBanner: { - method: "POST", - operationId: API_OPERATIONS.createBanner, - path: "/v1/admin/app-config/banners", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - createBD: { - method: "POST", - operationId: API_OPERATIONS.createBD, - path: "/v1/admin/bds", - permission: "bd:create", - permissions: ["bd:create"], - }, - createBDLeader: { - method: "POST", - operationId: API_OPERATIONS.createBDLeader, - path: "/v1/admin/bd-leaders", - permission: "bd:create", - permissions: ["bd:create"], - }, - createCatalog: { - method: "POST", - operationId: API_OPERATIONS.createCatalog, - path: "/v1/admin/game/games", - permission: "game:create", - permissions: ["game:create"], - }, - createCoinAdjustment: { - method: "POST", - operationId: API_OPERATIONS.createCoinAdjustment, - path: "/v1/admin/operations/coin-adjustments", - permission: "coin-adjustment:create", - permissions: ["coin-adjustment:create"], - }, - createCoinSeller: { - method: "POST", - operationId: API_OPERATIONS.createCoinSeller, - path: "/v1/admin/coin-sellers", - permission: "coin-seller:create", - permissions: ["coin-seller:create"], - }, - createCountry: { - method: "POST", - operationId: API_OPERATIONS.createCountry, - path: "/v1/admin/countries", - permission: "country:create", - permissions: ["country:create"], - }, - createEmojiPack: { - method: "POST", - operationId: API_OPERATIONS.createEmojiPack, - path: "/v1/admin/emoji-packs", - permission: "emoji-pack:create", - permissions: ["emoji-pack:create"], - }, - createExploreTab: { - method: "POST", - operationId: API_OPERATIONS.createExploreTab, - path: "/v1/admin/app-config/explore-tabs", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - createGift: { - method: "POST", - operationId: API_OPERATIONS.createGift, - path: "/v1/admin/gifts", - permission: "gift:create", - permissions: ["gift:create"], - }, - createH5Link: { - method: "POST", - operationId: API_OPERATIONS.createH5Link, - path: "/v1/admin/app-config/h5-links", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - createMenu: { - method: "POST", - operationId: API_OPERATIONS.createMenu, - path: "/v1/system/menus", - permission: "menu:create", - permissions: ["menu:create"], - }, - createPermission: { - method: "POST", - operationId: API_OPERATIONS.createPermission, - path: "/v1/permissions", - permission: "permission:create", - permissions: ["permission:create"], - }, - createPlatform: { - method: "POST", - operationId: API_OPERATIONS.createPlatform, - path: "/v1/admin/game/platforms", - permission: "game:update", - permissions: ["game:update"], - }, - createRechargeProduct: { - method: "POST", - operationId: API_OPERATIONS.createRechargeProduct, - path: "/v1/admin/payment/recharge-products", - permission: "payment-product:create", - permissions: ["payment-product:create"], - }, - createRegion: { - method: "POST", - operationId: API_OPERATIONS.createRegion, - path: "/v1/admin/regions", - permission: "region:create", - permissions: ["region:create"], - }, - createResource: { - method: "POST", - operationId: API_OPERATIONS.createResource, - path: "/v1/admin/resources", - permission: "resource:create", - permissions: ["resource:create"], - }, - createResourceGroup: { - method: "POST", - operationId: API_OPERATIONS.createResourceGroup, - path: "/v1/admin/resource-groups", - permission: "resource-group:create", - permissions: ["resource-group:create"], - }, - createRole: { - method: "POST", - operationId: API_OPERATIONS.createRole, - path: "/v1/roles", - permission: "role:create", - permissions: ["role:create", "role:manage"], - }, - createRoomPin: { - method: "POST", - operationId: API_OPERATIONS.createRoomPin, - path: "/v1/admin/rooms/pins", - permission: "room-pin:create", - permissions: ["room-pin:create"], - }, - createTaskDefinition: { - method: "POST", - operationId: API_OPERATIONS.createTaskDefinition, - path: "/v1/admin/activity/daily-tasks", - permission: "daily-task:create", - permissions: ["daily-task:create"], - }, - createTier: { - method: "POST", - operationId: API_OPERATIONS.createTier, - path: "/v1/admin/users/level-config/tiers", - permission: "level-config:update", - permissions: ["level-config:update"], - }, - createUser: { - method: "POST", - operationId: API_OPERATIONS.createUser, - path: "/v1/users", - permission: "user:create", - permissions: ["user:create"], - }, - creditCoinSellerStock: { - method: "POST", - operationId: API_OPERATIONS.creditCoinSellerStock, - path: "/v1/admin/coin-sellers/{user_id}/stock-credits", - permission: "coin-seller:stock-credit", - permissions: ["coin-seller:stock-credit"], - }, - dashboardOverview: { - method: "GET", - operationId: API_OPERATIONS.dashboardOverview, - path: "/v1/dashboard/overview", - permission: "overview:view", - permissions: ["overview:view"], - }, - deleteAppVersion: { - method: "DELETE", - operationId: API_OPERATIONS.deleteAppVersion, - path: "/v1/admin/app-config/versions/{version_id}", - permission: "app-version:delete", - permissions: ["app-version:delete"], - }, - deleteBanner: { - method: "DELETE", - operationId: API_OPERATIONS.deleteBanner, - path: "/v1/admin/app-config/banners/{banner_id}", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - deleteBDLeader: { - method: "DELETE", - operationId: API_OPERATIONS.deleteBDLeader, - path: "/v1/admin/bd-leaders/{user_id}", - permission: "bd:update", - permissions: ["bd:update"], - }, - deleteCatalog: { - method: "DELETE", - operationId: API_OPERATIONS.deleteCatalog, - path: "/v1/admin/game/games/{game_id}", - permission: "game:delete", - permissions: ["game:delete"], - }, - deleteCountry: { - method: "DELETE", - operationId: API_OPERATIONS.deleteCountry, - path: "/v1/admin/countries/{country_id}", - permission: "country:status", - permissions: ["country:status"], - }, - deleteExploreTab: { - method: "DELETE", - operationId: API_OPERATIONS.deleteExploreTab, - path: "/v1/admin/app-config/explore-tabs/{tab_id}", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - deleteH5Link: { - method: "DELETE", - operationId: API_OPERATIONS.deleteH5Link, - path: "/v1/admin/app-config/h5-links/{key}", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - deleteMenu: { - method: "DELETE", - operationId: API_OPERATIONS.deleteMenu, - path: "/v1/system/menus/{id}", - permission: "menu:delete", - permissions: ["menu:delete"], - }, - deletePermission: { - method: "DELETE", - operationId: API_OPERATIONS.deletePermission, - path: "/v1/permissions/{id}", - permission: "permission:delete", - permissions: ["permission:delete"], - }, - deleteRechargeProduct: { - method: "DELETE", - operationId: API_OPERATIONS.deleteRechargeProduct, - path: "/v1/admin/payment/recharge-products/{product_id}", - permission: "payment-product:delete", - permissions: ["payment-product:delete"], - }, - deleteRole: { - method: "DELETE", - operationId: API_OPERATIONS.deleteRole, - path: "/v1/roles/{id}", - permission: "role:delete", - permissions: ["role:delete", "role:manage"], - }, - deleteRoom: { - method: "DELETE", - operationId: API_OPERATIONS.deleteRoom, - path: "/v1/admin/rooms/{room_id}", - permission: "room:delete", - permissions: ["room:delete"], - }, - disableCountry: { - method: "POST", - operationId: API_OPERATIONS.disableCountry, - path: "/v1/admin/countries/{country_id}/disable", - permission: "country:status", - permissions: ["country:status"], - }, - disableGift: { - method: "POST", - operationId: API_OPERATIONS.disableGift, - path: "/v1/admin/gifts/{gift_id}/disable", - permission: "gift:status", - permissions: ["gift:status"], - }, - disableRegion: { - method: "DELETE", - operationId: API_OPERATIONS.disableRegion, - path: "/v1/admin/regions/{region_id}", - permission: "region:status", - permissions: ["region:status"], - }, - disableResource: { - method: "POST", - operationId: API_OPERATIONS.disableResource, - path: "/v1/admin/resources/{resource_id}/disable", - permission: "resource:update", - permissions: ["resource:update"], - }, - disableResourceGroup: { - method: "POST", - operationId: API_OPERATIONS.disableResourceGroup, - path: "/v1/admin/resource-groups/{group_id}/disable", - permission: "resource-group:update", - permissions: ["resource-group:update"], - }, - enableCountry: { - method: "POST", - operationId: API_OPERATIONS.enableCountry, - path: "/v1/admin/countries/{country_id}/enable", - permission: "country:status", - permissions: ["country:status"], - }, - enableGift: { - method: "POST", - operationId: API_OPERATIONS.enableGift, - path: "/v1/admin/gifts/{gift_id}/enable", - permission: "gift:status", - permissions: ["gift:status"], - }, - enableRegion: { - method: "POST", - operationId: API_OPERATIONS.enableRegion, - path: "/v1/admin/regions/{region_id}/enable", - permission: "region:status", - permissions: ["region:status"], - }, - enableResource: { - method: "POST", - operationId: API_OPERATIONS.enableResource, - path: "/v1/admin/resources/{resource_id}/enable", - permission: "resource:update", - permissions: ["resource:update"], - }, - enableResourceGroup: { - method: "POST", - operationId: API_OPERATIONS.enableResourceGroup, - path: "/v1/admin/resource-groups/{group_id}/enable", - permission: "resource-group:update", - permissions: ["resource-group:update"], - }, - exportLoginLogs: { - method: "GET", - operationId: API_OPERATIONS.exportLoginLogs, - path: "/v1/logs/login/export", - permission: "log:export", - permissions: ["log:export"], - }, - exportOperationLogs: { - method: "GET", - operationId: API_OPERATIONS.exportOperationLogs, - path: "/v1/logs/operations/export", - permission: "log:export", - permissions: ["log:export"], - }, - exportUsers: { - method: "GET", - operationId: API_OPERATIONS.exportUsers, - path: "/v1/users/export", - permission: "user:export", - permissions: ["user:export"], - }, - getCountry: { - method: "GET", - operationId: API_OPERATIONS.getCountry, - path: "/v1/admin/countries/{country_id}", - permission: "country:view", - permissions: ["country:view"], - }, - getFirstRechargeRewardConfig: { - method: "GET", - operationId: API_OPERATIONS.getFirstRechargeRewardConfig, - path: "/v1/admin/activity/first-recharge-reward/config", - permission: "first-recharge-reward:view", - permissions: ["first-recharge-reward:view"], - }, - getLuckyGiftConfig: { - method: "GET", - operationId: API_OPERATIONS.getLuckyGiftConfig, - path: "/v1/admin/activity/lucky-gifts/config", - permission: "lucky-gift:view", - permissions: ["lucky-gift:view"], - }, - getLuckyGiftDrawSummary: { - method: "GET", - operationId: API_OPERATIONS.getLuckyGiftDrawSummary, - path: "/v1/admin/activity/lucky-gifts/draw-summary", - permission: "lucky-gift:view", - permissions: ["lucky-gift:view"], - }, - getRedPacket: { - method: "GET", - operationId: API_OPERATIONS.getRedPacket, - path: "/v1/admin/activity/red-packets/{packet_id}", - permission: "red-packet:view", - permissions: ["red-packet:view"], - }, - getRedPacketConfig: { - method: "GET", - operationId: API_OPERATIONS.getRedPacketConfig, - path: "/v1/admin/activity/red-packets/config", - permission: "red-packet:view", - permissions: ["red-packet:view"], - }, - getRegion: { - method: "GET", - operationId: API_OPERATIONS.getRegion, - path: "/v1/admin/regions/{region_id}", - permission: "region:view", - permissions: ["region:view"], - }, - getRegistrationRewardConfig: { - method: "GET", - operationId: API_OPERATIONS.getRegistrationRewardConfig, - path: "/v1/admin/activity/registration-reward/config", - permission: "registration-reward:view", - permissions: ["registration-reward:view"], - }, - getResource: { - method: "GET", - operationId: API_OPERATIONS.getResource, - path: "/v1/admin/resources/{resource_id}", - permission: "resource:view", - permissions: ["resource:view"], - }, - getResourceGroup: { - method: "GET", - operationId: API_OPERATIONS.getResourceGroup, - path: "/v1/admin/resource-groups/{group_id}", - permission: "resource-group:view", - permissions: ["resource-group:view"], - }, - getRoleDataScopes: { - method: "GET", - operationId: API_OPERATIONS.getRoleDataScopes, - path: "/v1/roles/{id}/data-scopes", - permission: "role:data-scope", - permissions: ["role:data-scope"], - }, - getRoomConfig: { - method: "GET", - operationId: API_OPERATIONS.getRoomConfig, - path: "/v1/admin/rooms/config", - permission: "room-config:view", - permissions: ["room-config:view"], - }, - getRoomTreasureConfig: { - method: "GET", - operationId: API_OPERATIONS.getRoomTreasureConfig, - path: "/v1/admin/activity/room-treasure/config", - permission: "room-treasure:view", - permissions: ["room-treasure:view"], - }, - getSevenDayCheckInConfig: { - method: "GET", - operationId: API_OPERATIONS.getSevenDayCheckInConfig, - path: "/v1/admin/activity/seven-day-checkin/config", - permission: "seven-day-checkin:view", - permissions: ["seven-day-checkin:view"], - }, - getUser: { - method: "GET", - operationId: API_OPERATIONS.getUser, - path: "/v1/users/{id}", - permission: "user:view", - permissions: ["user:view"], - }, - grantResource: { - method: "POST", - operationId: API_OPERATIONS.grantResource, - path: "/v1/admin/resource-grants/resource", - permission: "resource-grant:create", - permissions: ["resource-grant:create"], - }, - grantResourceGroup: { - method: "POST", - operationId: API_OPERATIONS.grantResourceGroup, - path: "/v1/admin/resource-grants/group", - permission: "resource-grant:create", - permissions: ["resource-grant:create"], - }, - listAchievementDefinitions: { - method: "GET", - operationId: API_OPERATIONS.listAchievementDefinitions, - path: "/v1/admin/activity/achievements", - permission: "achievement:view", - permissions: ["achievement:view"], - }, - listAgencies: { - method: "GET", - operationId: API_OPERATIONS.listAgencies, - path: "/v1/admin/agencies", - permission: "agency:view", - permissions: ["agency:view"], - }, - listApps: { - method: "GET", - operationId: API_OPERATIONS.listApps, - path: "/v1/admin/apps", - }, - listAppVersions: { - method: "GET", - operationId: API_OPERATIONS.listAppVersions, - path: "/v1/admin/app-config/versions", - permission: "app-version:view", - permissions: ["app-version:view"], - }, - listBanners: { - method: "GET", - operationId: API_OPERATIONS.listBanners, - path: "/v1/admin/app-config/banners", - permission: "app-config:view", - permissions: ["app-config:view"], - }, - listBDLeaders: { - method: "GET", - operationId: API_OPERATIONS.listBDLeaders, - path: "/v1/admin/bd-leaders", - permission: "bd:view", - permissions: ["bd:view"], - }, - listBDs: { - method: "GET", - operationId: API_OPERATIONS.listBDs, - path: "/v1/admin/bds", - permission: "bd:view", - permissions: ["bd:view"], - }, - listCatalog: { - method: "GET", - operationId: API_OPERATIONS.listCatalog, - path: "/v1/admin/game/games", - permission: "game:view", - permissions: ["game:view"], - }, - listCoinAdjustments: { - method: "GET", - operationId: API_OPERATIONS.listCoinAdjustments, - path: "/v1/admin/operations/coin-adjustments", - permission: "coin-adjustment:view", - permissions: ["coin-adjustment:view"], - }, - listCoinLedger: { - method: "GET", - operationId: API_OPERATIONS.listCoinLedger, - path: "/v1/admin/operations/coin-ledger", - permission: "coin-ledger:view", - permissions: ["coin-ledger:view"], - }, - listCoinSellers: { - method: "GET", - operationId: API_OPERATIONS.listCoinSellers, - path: "/v1/admin/coin-sellers", - permission: "coin-seller:view", - permissions: ["coin-seller:view"], - }, - listCountries: { - method: "GET", - operationId: API_OPERATIONS.listCountries, - path: "/v1/admin/countries", - permission: "country:view", - permissions: ["country:view"], - }, - listEmojiPackCategories: { - method: "GET", - operationId: API_OPERATIONS.listEmojiPackCategories, - path: "/v1/admin/emoji-packs/categories", - permission: "emoji-pack:view", - permissions: ["emoji-pack:view"], - }, - listEmojiPacks: { - method: "GET", - operationId: API_OPERATIONS.listEmojiPacks, - path: "/v1/admin/emoji-packs", - permission: "emoji-pack:view", - permissions: ["emoji-pack:view"], - }, - listExploreTabs: { - method: "GET", - operationId: API_OPERATIONS.listExploreTabs, - path: "/v1/admin/app-config/explore-tabs", - permission: "app-config:view", - permissions: ["app-config:view"], - }, - listFirstRechargeRewardClaims: { - method: "GET", - operationId: API_OPERATIONS.listFirstRechargeRewardClaims, - path: "/v1/admin/activity/first-recharge-reward/claims", - permission: "first-recharge-reward:view", - permissions: ["first-recharge-reward:view"], - }, - listGifts: { - method: "GET", - operationId: API_OPERATIONS.listGifts, - path: "/v1/admin/gifts", - permission: "gift:view", - permissions: ["gift:view"], - }, - listGiftTypes: { - method: "GET", - operationId: API_OPERATIONS.listGiftTypes, - path: "/v1/admin/gift-types", - permission: "gift:view", - permissions: ["gift:view"], - }, - listH5Links: { - method: "GET", - operationId: API_OPERATIONS.listH5Links, - path: "/v1/admin/app-config/h5-links", - permission: "app-config:view", - permissions: ["app-config:view"], - }, - listHosts: { - method: "GET", - operationId: API_OPERATIONS.listHosts, - path: "/v1/admin/hosts", - permission: "host:view", - permissions: ["host:view"], - }, - listLevelConfig: { - method: "GET", - operationId: API_OPERATIONS.listLevelConfig, - path: "/v1/admin/users/level-config", - permission: "level-config:view", - permissions: ["level-config:view"], - }, - listLoginLogs: { - method: "GET", - operationId: API_OPERATIONS.listLoginLogs, - path: "/v1/logs/login", - permission: "log:view", - permissions: ["log:view"], - }, - listLuckyGiftConfigs: { - method: "GET", - operationId: API_OPERATIONS.listLuckyGiftConfigs, - path: "/v1/admin/activity/lucky-gifts/configs", - permission: "lucky-gift:view", - permissions: ["lucky-gift:view"], - }, - listLuckyGiftDraws: { - method: "GET", - operationId: API_OPERATIONS.listLuckyGiftDraws, - path: "/v1/admin/activity/lucky-gifts/draws", - permission: "lucky-gift:view", - permissions: ["lucky-gift:view"], - }, - listOperationLogs: { - method: "GET", - operationId: API_OPERATIONS.listOperationLogs, - path: "/v1/logs/operations", - permission: "log:view", - permissions: ["log:view"], - }, - listPermissions: { - method: "GET", - operationId: API_OPERATIONS.listPermissions, - path: "/v1/permissions", - permission: "permission:view", - permissions: ["permission:view", "role:permission", "role:manage"], - }, - listPlatforms: { - method: "GET", - operationId: API_OPERATIONS.listPlatforms, - path: "/v1/admin/game/platforms", - permission: "game:view", - permissions: ["game:view"], - }, - listRechargeBills: { - method: "GET", - operationId: API_OPERATIONS.listRechargeBills, - path: "/v1/admin/payment/recharge-bills", - permission: "payment-bill:view", - permissions: ["payment-bill:view"], - }, - listRechargeProducts: { - method: "GET", - operationId: API_OPERATIONS.listRechargeProducts, - path: "/v1/admin/payment/recharge-products", - permission: "payment-product:view", - permissions: ["payment-product:view"], - }, - listRedPackets: { - method: "GET", - operationId: API_OPERATIONS.listRedPackets, - path: "/v1/admin/activity/red-packets", - permission: "red-packet:view", - permissions: ["red-packet:view"], - }, - listRegionBlocks: { - method: "GET", - operationId: API_OPERATIONS.listRegionBlocks, - path: "/v1/admin/users/region-blocks", - permission: "region-block:view", - permissions: ["region-block:view"], - }, - listRegions: { - method: "GET", - operationId: API_OPERATIONS.listRegions, - path: "/v1/admin/regions", - permission: "region:view", - permissions: ["region:view"], - }, - listRegistrationRewardClaims: { - method: "GET", - operationId: API_OPERATIONS.listRegistrationRewardClaims, - path: "/v1/admin/activity/registration-reward/claims", - permission: "registration-reward:view", - permissions: ["registration-reward:view"], - }, - listResourceGrants: { - method: "GET", - operationId: API_OPERATIONS.listResourceGrants, - path: "/v1/admin/resource-grants", - permission: "resource-grant:view", - permissions: ["resource-grant:view"], - }, - listResourceGroups: { - method: "GET", - operationId: API_OPERATIONS.listResourceGroups, - path: "/v1/admin/resource-groups", - permission: "resource-group:view", - permissions: ["resource-group:view"], - }, - listResources: { - method: "GET", - operationId: API_OPERATIONS.listResources, - path: "/v1/admin/resources", - permission: "resource:view", - permissions: ["resource:view"], - }, - listRoles: { - method: "GET", - operationId: API_OPERATIONS.listRoles, - path: "/v1/roles", - permission: "role:view", - permissions: ["role:view"], - }, - listRoomPins: { - method: "GET", - operationId: API_OPERATIONS.listRoomPins, - path: "/v1/admin/rooms/pins", - permission: "room-pin:view", - permissions: ["room-pin:view"], - }, - listRooms: { - method: "GET", - operationId: API_OPERATIONS.listRooms, - path: "/v1/admin/rooms", - permission: "room:view", - permissions: ["room:view"], - }, - listSevenDayCheckInClaims: { - method: "GET", - operationId: API_OPERATIONS.listSevenDayCheckInClaims, - path: "/v1/admin/activity/seven-day-checkin/claims", - permission: "seven-day-checkin:view", - permissions: ["seven-day-checkin:view"], - }, - listSystemMenus: { - method: "GET", - operationId: API_OPERATIONS.listSystemMenus, - path: "/v1/system/menus", - permission: "menu:view", - permissions: ["menu:view"], - }, - listTaskDefinitions: { - method: "GET", - operationId: API_OPERATIONS.listTaskDefinitions, - path: "/v1/admin/activity/daily-tasks", - permission: "daily-task:view", - permissions: ["daily-task:view"], - }, - listUserLeaderboards: { - method: "GET", - operationId: API_OPERATIONS.listUserLeaderboards, - path: "/v1/admin/activity/user-leaderboards", - permission: "user-leaderboard:view", - permissions: ["user-leaderboard:view"], - }, - listUsers: { - method: "GET", - operationId: API_OPERATIONS.listUsers, - path: "/v1/users", - permission: "user:view", - permissions: ["user:view"], - }, - login: { - method: "POST", - operationId: API_OPERATIONS.login, - path: "/v1/auth/login", - }, - logout: { - method: "POST", - operationId: API_OPERATIONS.logout, - path: "/v1/auth/logout", - }, - lookupCoinAdjustmentTarget: { - method: "GET", - operationId: API_OPERATIONS.lookupCoinAdjustmentTarget, - path: "/v1/admin/operations/coin-adjustments/target", - permission: "coin-adjustment:create", - permissions: ["coin-adjustment:create"], - }, - me: { - method: "GET", - operationId: API_OPERATIONS.me, - path: "/v1/auth/me", - }, - navigationMenus: { - method: "GET", - operationId: API_OPERATIONS.navigationMenus, - path: "/v1/navigation/menus", - }, - refresh: { - method: "POST", - operationId: API_OPERATIONS.refresh, - path: "/v1/auth/refresh", - }, - replaceRegionBlocks: { - method: "PUT", - operationId: API_OPERATIONS.replaceRegionBlocks, - path: "/v1/admin/users/region-blocks", - permission: "region-block:update", - permissions: ["region-block:update"], - }, - replaceRegionCountries: { - method: "PUT", - operationId: API_OPERATIONS.replaceRegionCountries, - path: "/v1/admin/regions/{region_id}/countries", - permission: "region:update", - permissions: ["region:update"], - }, - replaceRoleDataScopes: { - method: "PUT", - operationId: API_OPERATIONS.replaceRoleDataScopes, - path: "/v1/roles/{id}/data-scopes", - permission: "role:data-scope", - permissions: ["role:data-scope"], - }, - replaceRolePermissions: { - method: "PUT", - operationId: API_OPERATIONS.replaceRolePermissions, - path: "/v1/roles/{id}/permissions", - permission: "role:permission", - permissions: ["role:permission", "role:manage"], - }, - resetUserPassword: { - method: "POST", - operationId: API_OPERATIONS.resetUserPassword, - path: "/v1/users/{id}/reset-password", - permission: "user:reset-password", - permissions: ["user:reset-password"], - }, - search: { - method: "GET", - operationId: API_OPERATIONS.search, - path: "/v1/search", - }, - setAgencyJoinEnabled: { - method: "POST", - operationId: API_OPERATIONS.setAgencyJoinEnabled, - path: "/v1/admin/agencies/{agency_id}/join-enabled", - permission: "agency:status", - permissions: ["agency:status"], - }, - setBDLeaderStatus: { - method: "PATCH", - operationId: API_OPERATIONS.setBDLeaderStatus, - path: "/v1/admin/bd-leaders/{user_id}/status", - permission: "bd:update", - permissions: ["bd:update"], - }, - setBDStatus: { - method: "PATCH", - operationId: API_OPERATIONS.setBDStatus, - path: "/v1/admin/bds/{user_id}/status", - permission: "bd:update", - permissions: ["bd:update"], - }, - setCoinSellerStatus: { - method: "PATCH", - operationId: API_OPERATIONS.setCoinSellerStatus, - path: "/v1/admin/coin-sellers/{user_id}/status", - permission: "coin-seller:update", - permissions: ["coin-seller:update"], - }, - setGameStatus: { - method: "PATCH", - operationId: API_OPERATIONS.setGameStatus, - path: "/v1/admin/game/games/{game_id}/status", - permission: "game:status", - permissions: ["game:status"], - }, - setTaskDefinitionStatus: { - method: "POST", - operationId: API_OPERATIONS.setTaskDefinitionStatus, - path: "/v1/admin/activity/daily-tasks/{task_id}/status", - permission: "daily-task:status", - permissions: ["daily-task:status"], - }, - sortMenus: { - method: "PUT", - operationId: API_OPERATIONS.sortMenus, - path: "/v1/system/menus/sort", - permission: "menu:sort", - permissions: ["menu:sort"], - }, - syncPermissions: { - method: "POST", - operationId: API_OPERATIONS.syncPermissions, - path: "/v1/permissions/sync", - permission: "permission:sync", - permissions: ["permission:sync"], - }, - updateAchievementDefinition: { - method: "PUT", - operationId: API_OPERATIONS.updateAchievementDefinition, - path: "/v1/admin/activity/achievements/{achievement_id}", - permission: "achievement:update", - permissions: ["achievement:update"], - }, - updateAppVersion: { - method: "PUT", - operationId: API_OPERATIONS.updateAppVersion, - path: "/v1/admin/app-config/versions/{version_id}", - permission: "app-version:update", - permissions: ["app-version:update"], - }, - updateBanner: { - method: "PUT", - operationId: API_OPERATIONS.updateBanner, - path: "/v1/admin/app-config/banners/{banner_id}", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - updateCatalog: { - method: "PATCH", - operationId: API_OPERATIONS.updateCatalog, - path: "/v1/admin/game/games/{game_id}", - permission: "game:update", - permissions: ["game:update"], - }, - updateCountry: { - method: "PATCH", - operationId: API_OPERATIONS.updateCountry, - path: "/v1/admin/countries/{country_id}", - permission: "country:update", - permissions: ["country:update"], - }, - updateExploreTab: { - method: "PUT", - operationId: API_OPERATIONS.updateExploreTab, - path: "/v1/admin/app-config/explore-tabs/{tab_id}", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - updateFirstRechargeRewardConfig: { - method: "PUT", - operationId: API_OPERATIONS.updateFirstRechargeRewardConfig, - path: "/v1/admin/activity/first-recharge-reward/config", - permission: "first-recharge-reward:update", - permissions: ["first-recharge-reward:update"], - }, - updateGift: { - method: "PUT", - operationId: API_OPERATIONS.updateGift, - path: "/v1/admin/gifts/{gift_id}", - permission: "gift:update", - permissions: ["gift:update"], - }, - updateGiftType: { - method: "PUT", - operationId: API_OPERATIONS.updateGiftType, - path: "/v1/admin/gift-types/{type_code}", - permission: "gift:update", - permissions: ["gift:update"], - }, - updateGiftTypes: { - method: "PUT", - operationId: API_OPERATIONS.updateGiftTypes, - path: "/v1/admin/gift-types", - permission: "gift:update", - permissions: ["gift:update"], - }, - updateH5Link: { - method: "PUT", - operationId: API_OPERATIONS.updateH5Link, - path: "/v1/admin/app-config/h5-links/{key}", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - updateH5Links: { - method: "PUT", - operationId: API_OPERATIONS.updateH5Links, - path: "/v1/admin/app-config/h5-links", - permission: "app-config:update", - permissions: ["app-config:update"], - }, - updateMenu: { - method: "PATCH", - operationId: API_OPERATIONS.updateMenu, - path: "/v1/system/menus/{id}", - permission: "menu:update", - permissions: ["menu:update"], - }, - updateMenuVisible: { - method: "PATCH", - operationId: API_OPERATIONS.updateMenuVisible, - path: "/v1/system/menus/{id}/visible", - permission: "menu:visible", - permissions: ["menu:visible"], - }, - updatePermission: { - method: "PATCH", - operationId: API_OPERATIONS.updatePermission, - path: "/v1/permissions/{id}", - permission: "permission:update", - permissions: ["permission:update"], - }, - updatePlatform: { - method: "PATCH", - operationId: API_OPERATIONS.updatePlatform, - path: "/v1/admin/game/platforms/{platform_code}", - permission: "game:update", - permissions: ["game:update"], - }, - updateRechargeProduct: { - method: "PUT", - operationId: API_OPERATIONS.updateRechargeProduct, - path: "/v1/admin/payment/recharge-products/{product_id}", - permission: "payment-product:update", - permissions: ["payment-product:update"], - }, - updateRedPacketConfig: { - method: "PUT", - operationId: API_OPERATIONS.updateRedPacketConfig, - path: "/v1/admin/activity/red-packets/config", - permission: "red-packet:update", - permissions: ["red-packet:update"], - }, - updateRegion: { - method: "PATCH", - operationId: API_OPERATIONS.updateRegion, - path: "/v1/admin/regions/{region_id}", - permission: "region:update", - permissions: ["region:update"], - }, - updateRegistrationRewardConfig: { - method: "PUT", - operationId: API_OPERATIONS.updateRegistrationRewardConfig, - path: "/v1/admin/activity/registration-reward/config", - permission: "registration-reward:update", - permissions: ["registration-reward:update"], - }, - updateResource: { - method: "PUT", - operationId: API_OPERATIONS.updateResource, - path: "/v1/admin/resources/{resource_id}", - permission: "resource:update", - permissions: ["resource:update"], - }, - updateResourceGroup: { - method: "PUT", - operationId: API_OPERATIONS.updateResourceGroup, - path: "/v1/admin/resource-groups/{group_id}", - permission: "resource-group:update", - permissions: ["resource-group:update"], - }, - updateResourceGroupItems: { - method: "PUT", - operationId: API_OPERATIONS.updateResourceGroupItems, - path: "/v1/admin/resource-groups/{group_id}/items", - permission: "resource-group:update", - permissions: ["resource-group:update"], - }, - updateRole: { - method: "PATCH", - operationId: API_OPERATIONS.updateRole, - path: "/v1/roles/{id}", - permission: "role:update", - permissions: ["role:update", "role:manage"], - }, - updateRoom: { - method: "PATCH", - operationId: API_OPERATIONS.updateRoom, - path: "/v1/admin/rooms/{room_id}", - permission: "room:update", - permissions: ["room:update"], - }, - updateRoomConfig: { - method: "PUT", - operationId: API_OPERATIONS.updateRoomConfig, - path: "/v1/admin/rooms/config", - permission: "room-config:update", - permissions: ["room-config:update"], - }, - updateRoomTreasureConfig: { - method: "PUT", - operationId: API_OPERATIONS.updateRoomTreasureConfig, - path: "/v1/admin/activity/room-treasure/config", - permission: "room-treasure:update", - permissions: ["room-treasure:update"], - }, - updateSevenDayCheckInConfig: { - method: "PUT", - operationId: API_OPERATIONS.updateSevenDayCheckInConfig, - path: "/v1/admin/activity/seven-day-checkin/config", - permission: "seven-day-checkin:update", - permissions: ["seven-day-checkin:update"], - }, - updateTaskDefinition: { - method: "PUT", - operationId: API_OPERATIONS.updateTaskDefinition, - path: "/v1/admin/activity/daily-tasks/{task_id}", - permission: "daily-task:update", - permissions: ["daily-task:update"], - }, - updateTier: { - method: "PUT", - operationId: API_OPERATIONS.updateTier, - path: "/v1/admin/users/level-config/tiers/{tier_id}", - permission: "level-config:update", - permissions: ["level-config:update"], - }, - updateTrack: { - method: "PUT", - operationId: API_OPERATIONS.updateTrack, - path: "/v1/admin/users/level-config/tracks/{track}", - permission: "level-config:update", - permissions: ["level-config:update"], - }, - updateUser: { - method: "PATCH", - operationId: API_OPERATIONS.updateUser, - path: "/v1/users/{id}", - permission: "user:update", - permissions: ["user:update"], - }, - updateUserStatus: { - method: "PATCH", - operationId: API_OPERATIONS.updateUserStatus, - path: "/v1/users/{id}/status", - permission: "user:status", - permissions: ["user:status"], - }, - uploadFile: { - method: "POST", - operationId: API_OPERATIONS.uploadFile, - path: "/v1/admin/files/upload", - permission: "upload:create", - permissions: ["upload:create"], - }, - uploadImage: { - method: "POST", - operationId: API_OPERATIONS.uploadImage, - path: "/v1/admin/files/image/upload", - permission: "upload:create", - permissions: ["upload:create"], - }, - upsertLuckyGiftConfig: { - method: "PUT", - operationId: API_OPERATIONS.upsertLuckyGiftConfig, - path: "/v1/admin/activity/lucky-gifts/config", - permission: "lucky-gift:update", - permissions: ["lucky-gift:update"], - }, - upsertRule: { - method: "PUT", - operationId: API_OPERATIONS.upsertRule, - path: "/v1/admin/users/level-config/rules/{track}/{level}", - permission: "level-config:update", - permissions: ["level-config:update"], - }, + appBanUser: { + method: "POST", + operationId: API_OPERATIONS.appBanUser, + path: "/v1/app/users/{id}/ban", + permission: "app-user:status", + permissions: ["app-user:status"] + }, + appGetUser: { + method: "GET", + operationId: API_OPERATIONS.appGetUser, + path: "/v1/app/users/{id}", + permission: "app-user:view", + permissions: ["app-user:view"] + }, + appListBannedUsers: { + method: "GET", + operationId: API_OPERATIONS.appListBannedUsers, + path: "/v1/app/users/bans", + permission: "app-user:view", + permissions: ["app-user:view"] + }, + appListLoginLogs: { + method: "GET", + operationId: API_OPERATIONS.appListLoginLogs, + path: "/v1/app/users/login-logs", + permission: "app-user:view", + permissions: ["app-user:view"] + }, + appListUserLoginLogs: { + method: "GET", + operationId: API_OPERATIONS.appListUserLoginLogs, + path: "/v1/app/users/{id}/login-logs", + permission: "app-user:view", + permissions: ["app-user:view"] + }, + appListUsers: { + method: "GET", + operationId: API_OPERATIONS.appListUsers, + path: "/v1/app/users", + permission: "app-user:view", + permissions: ["app-user:view"] + }, + appSetPassword: { + method: "POST", + operationId: API_OPERATIONS.appSetPassword, + path: "/v1/app/users/{id}/password", + permission: "app-user:password", + permissions: ["app-user:password"] + }, + appUnbanUser: { + method: "POST", + operationId: API_OPERATIONS.appUnbanUser, + path: "/v1/app/users/{id}/unban", + permission: "app-user:status", + permissions: ["app-user:status"] + }, + appUpdateUser: { + method: "PATCH", + operationId: API_OPERATIONS.appUpdateUser, + path: "/v1/app/users/{id}", + permission: "app-user:update", + permissions: ["app-user:update"] + }, + batchUpdateUserStatus: { + method: "POST", + operationId: API_OPERATIONS.batchUpdateUserStatus, + path: "/v1/users/batch/status", + permission: "user:status", + permissions: ["user:status"] + }, + cancelRoomPin: { + method: "DELETE", + operationId: API_OPERATIONS.cancelRoomPin, + path: "/v1/admin/rooms/pins/{pin_id}", + permission: "room-pin:cancel", + permissions: ["room-pin:cancel"] + }, + changePassword: { + method: "POST", + operationId: API_OPERATIONS.changePassword, + path: "/v1/auth/change-password" + }, + closeAgency: { + method: "POST", + operationId: API_OPERATIONS.closeAgency, + path: "/v1/admin/agencies/{agency_id}/close", + permission: "agency:status", + permissions: ["agency:status"] + }, + createAchievementDefinition: { + method: "POST", + operationId: API_OPERATIONS.createAchievementDefinition, + path: "/v1/admin/activity/achievements", + permission: "achievement:create", + permissions: ["achievement:create"] + }, + createAgency: { + method: "POST", + operationId: API_OPERATIONS.createAgency, + path: "/v1/admin/agencies", + permission: "agency:create", + permissions: ["agency:create"] + }, + createAppVersion: { + method: "POST", + operationId: API_OPERATIONS.createAppVersion, + path: "/v1/admin/app-config/versions", + permission: "app-version:create", + permissions: ["app-version:create"] + }, + createBanner: { + method: "POST", + operationId: API_OPERATIONS.createBanner, + path: "/v1/admin/app-config/banners", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + createBD: { + method: "POST", + operationId: API_OPERATIONS.createBD, + path: "/v1/admin/bds", + permission: "bd:create", + permissions: ["bd:create"] + }, + createBDLeader: { + method: "POST", + operationId: API_OPERATIONS.createBDLeader, + path: "/v1/admin/bd-leaders", + permission: "bd:create", + permissions: ["bd:create"] + }, + createCatalog: { + method: "POST", + operationId: API_OPERATIONS.createCatalog, + path: "/v1/admin/game/games", + permission: "game:create", + permissions: ["game:create"] + }, + createCoinAdjustment: { + method: "POST", + operationId: API_OPERATIONS.createCoinAdjustment, + path: "/v1/admin/operations/coin-adjustments", + permission: "coin-adjustment:create", + permissions: ["coin-adjustment:create"] + }, + createCoinSeller: { + method: "POST", + operationId: API_OPERATIONS.createCoinSeller, + path: "/v1/admin/coin-sellers", + permission: "coin-seller:create", + permissions: ["coin-seller:create"] + }, + createCountry: { + method: "POST", + operationId: API_OPERATIONS.createCountry, + path: "/v1/admin/countries", + permission: "country:create", + permissions: ["country:create"] + }, + createEmojiPack: { + method: "POST", + operationId: API_OPERATIONS.createEmojiPack, + path: "/v1/admin/emoji-packs", + permission: "emoji-pack:create", + permissions: ["emoji-pack:create"] + }, + createExploreTab: { + method: "POST", + operationId: API_OPERATIONS.createExploreTab, + path: "/v1/admin/app-config/explore-tabs", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + createGift: { + method: "POST", + operationId: API_OPERATIONS.createGift, + path: "/v1/admin/gifts", + permission: "gift:create", + permissions: ["gift:create"] + }, + createH5Link: { + method: "POST", + operationId: API_OPERATIONS.createH5Link, + path: "/v1/admin/app-config/h5-links", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + createMenu: { + method: "POST", + operationId: API_OPERATIONS.createMenu, + path: "/v1/system/menus", + permission: "menu:create", + permissions: ["menu:create"] + }, + createPermission: { + method: "POST", + operationId: API_OPERATIONS.createPermission, + path: "/v1/permissions", + permission: "permission:create", + permissions: ["permission:create"] + }, + createPlatform: { + method: "POST", + operationId: API_OPERATIONS.createPlatform, + path: "/v1/admin/game/platforms", + permission: "game:update", + permissions: ["game:update"] + }, + createRechargeProduct: { + method: "POST", + operationId: API_OPERATIONS.createRechargeProduct, + path: "/v1/admin/payment/recharge-products", + permission: "payment-product:create", + permissions: ["payment-product:create"] + }, + createRegion: { + method: "POST", + operationId: API_OPERATIONS.createRegion, + path: "/v1/admin/regions", + permission: "region:create", + permissions: ["region:create"] + }, + createResource: { + method: "POST", + operationId: API_OPERATIONS.createResource, + path: "/v1/admin/resources", + permission: "resource:create", + permissions: ["resource:create"] + }, + createResourceGroup: { + method: "POST", + operationId: API_OPERATIONS.createResourceGroup, + path: "/v1/admin/resource-groups", + permission: "resource-group:create", + permissions: ["resource-group:create"] + }, + createRole: { + method: "POST", + operationId: API_OPERATIONS.createRole, + path: "/v1/roles", + permission: "role:create", + permissions: ["role:create","role:manage"] + }, + createRoomPin: { + method: "POST", + operationId: API_OPERATIONS.createRoomPin, + path: "/v1/admin/rooms/pins", + permission: "room-pin:create", + permissions: ["room-pin:create"] + }, + createTaskDefinition: { + method: "POST", + operationId: API_OPERATIONS.createTaskDefinition, + path: "/v1/admin/activity/daily-tasks", + permission: "daily-task:create", + permissions: ["daily-task:create"] + }, + createTier: { + method: "POST", + operationId: API_OPERATIONS.createTier, + path: "/v1/admin/users/level-config/tiers", + permission: "level-config:update", + permissions: ["level-config:update"] + }, + createUser: { + method: "POST", + operationId: API_OPERATIONS.createUser, + path: "/v1/users", + permission: "user:create", + permissions: ["user:create"] + }, + creditCoinSellerStock: { + method: "POST", + operationId: API_OPERATIONS.creditCoinSellerStock, + path: "/v1/admin/coin-sellers/{user_id}/stock-credits", + permission: "coin-seller:stock-credit", + permissions: ["coin-seller:stock-credit"] + }, + dashboardOverview: { + method: "GET", + operationId: API_OPERATIONS.dashboardOverview, + path: "/v1/dashboard/overview", + permission: "overview:view", + permissions: ["overview:view"] + }, + deleteAppVersion: { + method: "DELETE", + operationId: API_OPERATIONS.deleteAppVersion, + path: "/v1/admin/app-config/versions/{version_id}", + permission: "app-version:delete", + permissions: ["app-version:delete"] + }, + deleteBanner: { + method: "DELETE", + operationId: API_OPERATIONS.deleteBanner, + path: "/v1/admin/app-config/banners/{banner_id}", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + deleteBDLeader: { + method: "DELETE", + operationId: API_OPERATIONS.deleteBDLeader, + path: "/v1/admin/bd-leaders/{user_id}", + permission: "bd:update", + permissions: ["bd:update"] + }, + deleteCatalog: { + method: "DELETE", + operationId: API_OPERATIONS.deleteCatalog, + path: "/v1/admin/game/games/{game_id}", + permission: "game:delete", + permissions: ["game:delete"] + }, + deleteCountry: { + method: "DELETE", + operationId: API_OPERATIONS.deleteCountry, + path: "/v1/admin/countries/{country_id}", + permission: "country:status", + permissions: ["country:status"] + }, + deleteExploreTab: { + method: "DELETE", + operationId: API_OPERATIONS.deleteExploreTab, + path: "/v1/admin/app-config/explore-tabs/{tab_id}", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + deleteH5Link: { + method: "DELETE", + operationId: API_OPERATIONS.deleteH5Link, + path: "/v1/admin/app-config/h5-links/{key}", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + deleteMenu: { + method: "DELETE", + operationId: API_OPERATIONS.deleteMenu, + path: "/v1/system/menus/{id}", + permission: "menu:delete", + permissions: ["menu:delete"] + }, + deletePermission: { + method: "DELETE", + operationId: API_OPERATIONS.deletePermission, + path: "/v1/permissions/{id}", + permission: "permission:delete", + permissions: ["permission:delete"] + }, + deleteRechargeProduct: { + method: "DELETE", + operationId: API_OPERATIONS.deleteRechargeProduct, + path: "/v1/admin/payment/recharge-products/{product_id}", + permission: "payment-product:delete", + permissions: ["payment-product:delete"] + }, + deleteRole: { + method: "DELETE", + operationId: API_OPERATIONS.deleteRole, + path: "/v1/roles/{id}", + permission: "role:delete", + permissions: ["role:delete","role:manage"] + }, + deleteRoom: { + method: "DELETE", + operationId: API_OPERATIONS.deleteRoom, + path: "/v1/admin/rooms/{room_id}", + permission: "room:delete", + permissions: ["room:delete"] + }, + disableCountry: { + method: "POST", + operationId: API_OPERATIONS.disableCountry, + path: "/v1/admin/countries/{country_id}/disable", + permission: "country:status", + permissions: ["country:status"] + }, + disableGift: { + method: "POST", + operationId: API_OPERATIONS.disableGift, + path: "/v1/admin/gifts/{gift_id}/disable", + permission: "gift:status", + permissions: ["gift:status"] + }, + disableRegion: { + method: "DELETE", + operationId: API_OPERATIONS.disableRegion, + path: "/v1/admin/regions/{region_id}", + permission: "region:status", + permissions: ["region:status"] + }, + disableResource: { + method: "POST", + operationId: API_OPERATIONS.disableResource, + path: "/v1/admin/resources/{resource_id}/disable", + permission: "resource:update", + permissions: ["resource:update"] + }, + disableResourceGroup: { + method: "POST", + operationId: API_OPERATIONS.disableResourceGroup, + path: "/v1/admin/resource-groups/{group_id}/disable", + permission: "resource-group:update", + permissions: ["resource-group:update"] + }, + disableResourceShopItem: { + method: "POST", + operationId: API_OPERATIONS.disableResourceShopItem, + path: "/v1/admin/resource-shop/items/{shop_item_id}/disable", + permission: "resource-shop:update", + permissions: ["resource-shop:update"] + }, + enableCountry: { + method: "POST", + operationId: API_OPERATIONS.enableCountry, + path: "/v1/admin/countries/{country_id}/enable", + permission: "country:status", + permissions: ["country:status"] + }, + enableGift: { + method: "POST", + operationId: API_OPERATIONS.enableGift, + path: "/v1/admin/gifts/{gift_id}/enable", + permission: "gift:status", + permissions: ["gift:status"] + }, + enableRegion: { + method: "POST", + operationId: API_OPERATIONS.enableRegion, + path: "/v1/admin/regions/{region_id}/enable", + permission: "region:status", + permissions: ["region:status"] + }, + enableResource: { + method: "POST", + operationId: API_OPERATIONS.enableResource, + path: "/v1/admin/resources/{resource_id}/enable", + permission: "resource:update", + permissions: ["resource:update"] + }, + enableResourceGroup: { + method: "POST", + operationId: API_OPERATIONS.enableResourceGroup, + path: "/v1/admin/resource-groups/{group_id}/enable", + permission: "resource-group:update", + permissions: ["resource-group:update"] + }, + enableResourceShopItem: { + method: "POST", + operationId: API_OPERATIONS.enableResourceShopItem, + path: "/v1/admin/resource-shop/items/{shop_item_id}/enable", + permission: "resource-shop:update", + permissions: ["resource-shop:update"] + }, + exportLoginLogs: { + method: "GET", + operationId: API_OPERATIONS.exportLoginLogs, + path: "/v1/logs/login/export", + permission: "log:export", + permissions: ["log:export"] + }, + exportOperationLogs: { + method: "GET", + operationId: API_OPERATIONS.exportOperationLogs, + path: "/v1/logs/operations/export", + permission: "log:export", + permissions: ["log:export"] + }, + exportUsers: { + method: "GET", + operationId: API_OPERATIONS.exportUsers, + path: "/v1/users/export", + permission: "user:export", + permissions: ["user:export"] + }, + getCountry: { + method: "GET", + operationId: API_OPERATIONS.getCountry, + path: "/v1/admin/countries/{country_id}", + permission: "country:view", + permissions: ["country:view"] + }, + getFirstRechargeRewardConfig: { + method: "GET", + operationId: API_OPERATIONS.getFirstRechargeRewardConfig, + path: "/v1/admin/activity/first-recharge-reward/config", + permission: "first-recharge-reward:view", + permissions: ["first-recharge-reward:view"] + }, + getLuckyGiftConfig: { + method: "GET", + operationId: API_OPERATIONS.getLuckyGiftConfig, + path: "/v1/admin/activity/lucky-gifts/config", + permission: "lucky-gift:view", + permissions: ["lucky-gift:view"] + }, + getLuckyGiftDrawSummary: { + method: "GET", + operationId: API_OPERATIONS.getLuckyGiftDrawSummary, + path: "/v1/admin/activity/lucky-gifts/draw-summary", + permission: "lucky-gift:view", + permissions: ["lucky-gift:view"] + }, + getRedPacket: { + method: "GET", + operationId: API_OPERATIONS.getRedPacket, + path: "/v1/admin/activity/red-packets/{packet_id}", + permission: "red-packet:view", + permissions: ["red-packet:view"] + }, + getRedPacketConfig: { + method: "GET", + operationId: API_OPERATIONS.getRedPacketConfig, + path: "/v1/admin/activity/red-packets/config", + permission: "red-packet:view", + permissions: ["red-packet:view"] + }, + getRegion: { + method: "GET", + operationId: API_OPERATIONS.getRegion, + path: "/v1/admin/regions/{region_id}", + permission: "region:view", + permissions: ["region:view"] + }, + getRegistrationRewardConfig: { + method: "GET", + operationId: API_OPERATIONS.getRegistrationRewardConfig, + path: "/v1/admin/activity/registration-reward/config", + permission: "registration-reward:view", + permissions: ["registration-reward:view"] + }, + getResource: { + method: "GET", + operationId: API_OPERATIONS.getResource, + path: "/v1/admin/resources/{resource_id}", + permission: "resource:view", + permissions: ["resource:view"] + }, + getResourceGroup: { + method: "GET", + operationId: API_OPERATIONS.getResourceGroup, + path: "/v1/admin/resource-groups/{group_id}", + permission: "resource-group:view", + permissions: ["resource-group:view"] + }, + getRoleDataScopes: { + method: "GET", + operationId: API_OPERATIONS.getRoleDataScopes, + path: "/v1/roles/{id}/data-scopes", + permission: "role:data-scope", + permissions: ["role:data-scope"] + }, + getRoomConfig: { + method: "GET", + operationId: API_OPERATIONS.getRoomConfig, + path: "/v1/admin/rooms/config", + permission: "room-config:view", + permissions: ["room-config:view"] + }, + getRoomTreasureConfig: { + method: "GET", + operationId: API_OPERATIONS.getRoomTreasureConfig, + path: "/v1/admin/activity/room-treasure/config", + permission: "room-treasure:view", + permissions: ["room-treasure:view"] + }, + getSevenDayCheckInConfig: { + method: "GET", + operationId: API_OPERATIONS.getSevenDayCheckInConfig, + path: "/v1/admin/activity/seven-day-checkin/config", + permission: "seven-day-checkin:view", + permissions: ["seven-day-checkin:view"] + }, + getUser: { + method: "GET", + operationId: API_OPERATIONS.getUser, + path: "/v1/users/{id}", + permission: "user:view", + permissions: ["user:view"] + }, + grantResource: { + method: "POST", + operationId: API_OPERATIONS.grantResource, + path: "/v1/admin/resource-grants/resource", + permission: "resource-grant:create", + permissions: ["resource-grant:create"] + }, + grantResourceGroup: { + method: "POST", + operationId: API_OPERATIONS.grantResourceGroup, + path: "/v1/admin/resource-grants/group", + permission: "resource-grant:create", + permissions: ["resource-grant:create"] + }, + listAchievementDefinitions: { + method: "GET", + operationId: API_OPERATIONS.listAchievementDefinitions, + path: "/v1/admin/activity/achievements", + permission: "achievement:view", + permissions: ["achievement:view"] + }, + listAgencies: { + method: "GET", + operationId: API_OPERATIONS.listAgencies, + path: "/v1/admin/agencies", + permission: "agency:view", + permissions: ["agency:view"] + }, + listApps: { + method: "GET", + operationId: API_OPERATIONS.listApps, + path: "/v1/admin/apps" + }, + listAppVersions: { + method: "GET", + operationId: API_OPERATIONS.listAppVersions, + path: "/v1/admin/app-config/versions", + permission: "app-version:view", + permissions: ["app-version:view"] + }, + listBanners: { + method: "GET", + operationId: API_OPERATIONS.listBanners, + path: "/v1/admin/app-config/banners", + permission: "app-config:view", + permissions: ["app-config:view"] + }, + listBDLeaders: { + method: "GET", + operationId: API_OPERATIONS.listBDLeaders, + path: "/v1/admin/bd-leaders", + permission: "bd:view", + permissions: ["bd:view"] + }, + listBDs: { + method: "GET", + operationId: API_OPERATIONS.listBDs, + path: "/v1/admin/bds", + permission: "bd:view", + permissions: ["bd:view"] + }, + listCatalog: { + method: "GET", + operationId: API_OPERATIONS.listCatalog, + path: "/v1/admin/game/games", + permission: "game:view", + permissions: ["game:view"] + }, + listCoinAdjustments: { + method: "GET", + operationId: API_OPERATIONS.listCoinAdjustments, + path: "/v1/admin/operations/coin-adjustments", + permission: "coin-adjustment:view", + permissions: ["coin-adjustment:view"] + }, + listCoinLedger: { + method: "GET", + operationId: API_OPERATIONS.listCoinLedger, + path: "/v1/admin/operations/coin-ledger", + permission: "coin-ledger:view", + permissions: ["coin-ledger:view"] + }, + listCoinSellers: { + method: "GET", + operationId: API_OPERATIONS.listCoinSellers, + path: "/v1/admin/coin-sellers", + permission: "coin-seller:view", + permissions: ["coin-seller:view"] + }, + listCountries: { + method: "GET", + operationId: API_OPERATIONS.listCountries, + path: "/v1/admin/countries", + permission: "country:view", + permissions: ["country:view"] + }, + listEmojiPackCategories: { + method: "GET", + operationId: API_OPERATIONS.listEmojiPackCategories, + path: "/v1/admin/emoji-packs/categories", + permission: "emoji-pack:view", + permissions: ["emoji-pack:view"] + }, + listEmojiPacks: { + method: "GET", + operationId: API_OPERATIONS.listEmojiPacks, + path: "/v1/admin/emoji-packs", + permission: "emoji-pack:view", + permissions: ["emoji-pack:view"] + }, + listExploreTabs: { + method: "GET", + operationId: API_OPERATIONS.listExploreTabs, + path: "/v1/admin/app-config/explore-tabs", + permission: "app-config:view", + permissions: ["app-config:view"] + }, + listFirstRechargeRewardClaims: { + method: "GET", + operationId: API_OPERATIONS.listFirstRechargeRewardClaims, + path: "/v1/admin/activity/first-recharge-reward/claims", + permission: "first-recharge-reward:view", + permissions: ["first-recharge-reward:view"] + }, + listGifts: { + method: "GET", + operationId: API_OPERATIONS.listGifts, + path: "/v1/admin/gifts", + permission: "gift:view", + permissions: ["gift:view"] + }, + listGiftTypes: { + method: "GET", + operationId: API_OPERATIONS.listGiftTypes, + path: "/v1/admin/gift-types", + permission: "gift:view", + permissions: ["gift:view"] + }, + listH5Links: { + method: "GET", + operationId: API_OPERATIONS.listH5Links, + path: "/v1/admin/app-config/h5-links", + permission: "app-config:view", + permissions: ["app-config:view"] + }, + listHosts: { + method: "GET", + operationId: API_OPERATIONS.listHosts, + path: "/v1/admin/hosts", + permission: "host:view", + permissions: ["host:view"] + }, + listLevelConfig: { + method: "GET", + operationId: API_OPERATIONS.listLevelConfig, + path: "/v1/admin/users/level-config", + permission: "level-config:view", + permissions: ["level-config:view"] + }, + listLoginLogs: { + method: "GET", + operationId: API_OPERATIONS.listLoginLogs, + path: "/v1/logs/login", + permission: "log:view", + permissions: ["log:view"] + }, + listLuckyGiftConfigs: { + method: "GET", + operationId: API_OPERATIONS.listLuckyGiftConfigs, + path: "/v1/admin/activity/lucky-gifts/configs", + permission: "lucky-gift:view", + permissions: ["lucky-gift:view"] + }, + listLuckyGiftDraws: { + method: "GET", + operationId: API_OPERATIONS.listLuckyGiftDraws, + path: "/v1/admin/activity/lucky-gifts/draws", + permission: "lucky-gift:view", + permissions: ["lucky-gift:view"] + }, + listOperationLogs: { + method: "GET", + operationId: API_OPERATIONS.listOperationLogs, + path: "/v1/logs/operations", + permission: "log:view", + permissions: ["log:view"] + }, + listPermissions: { + method: "GET", + operationId: API_OPERATIONS.listPermissions, + path: "/v1/permissions", + permission: "permission:view", + permissions: ["permission:view","role:permission","role:manage"] + }, + listPlatforms: { + method: "GET", + operationId: API_OPERATIONS.listPlatforms, + path: "/v1/admin/game/platforms", + permission: "game:view", + permissions: ["game:view"] + }, + listRechargeBills: { + method: "GET", + operationId: API_OPERATIONS.listRechargeBills, + path: "/v1/admin/payment/recharge-bills", + permission: "payment-bill:view", + permissions: ["payment-bill:view"] + }, + listRechargeProducts: { + method: "GET", + operationId: API_OPERATIONS.listRechargeProducts, + path: "/v1/admin/payment/recharge-products", + permission: "payment-product:view", + permissions: ["payment-product:view"] + }, + listRedPackets: { + method: "GET", + operationId: API_OPERATIONS.listRedPackets, + path: "/v1/admin/activity/red-packets", + permission: "red-packet:view", + permissions: ["red-packet:view"] + }, + listRegionBlocks: { + method: "GET", + operationId: API_OPERATIONS.listRegionBlocks, + path: "/v1/admin/users/region-blocks", + permission: "region-block:view", + permissions: ["region-block:view"] + }, + listRegions: { + method: "GET", + operationId: API_OPERATIONS.listRegions, + path: "/v1/admin/regions", + permission: "region:view", + permissions: ["region:view"] + }, + listRegistrationRewardClaims: { + method: "GET", + operationId: API_OPERATIONS.listRegistrationRewardClaims, + path: "/v1/admin/activity/registration-reward/claims", + permission: "registration-reward:view", + permissions: ["registration-reward:view"] + }, + listResourceGrants: { + method: "GET", + operationId: API_OPERATIONS.listResourceGrants, + path: "/v1/admin/resource-grants", + permission: "resource-grant:view", + permissions: ["resource-grant:view"] + }, + listResourceGroups: { + method: "GET", + operationId: API_OPERATIONS.listResourceGroups, + path: "/v1/admin/resource-groups", + permission: "resource-group:view", + permissions: ["resource-group:view"] + }, + listResources: { + method: "GET", + operationId: API_OPERATIONS.listResources, + path: "/v1/admin/resources", + permission: "resource:view", + permissions: ["resource:view"] + }, + listResourceShopItems: { + method: "GET", + operationId: API_OPERATIONS.listResourceShopItems, + path: "/v1/admin/resource-shop/items", + permission: "resource-shop:view", + permissions: ["resource-shop:view"] + }, + listRoles: { + method: "GET", + operationId: API_OPERATIONS.listRoles, + path: "/v1/roles", + permission: "role:view", + permissions: ["role:view"] + }, + listRoomPins: { + method: "GET", + operationId: API_OPERATIONS.listRoomPins, + path: "/v1/admin/rooms/pins", + permission: "room-pin:view", + permissions: ["room-pin:view"] + }, + listRooms: { + method: "GET", + operationId: API_OPERATIONS.listRooms, + path: "/v1/admin/rooms", + permission: "room:view", + permissions: ["room:view"] + }, + listSevenDayCheckInClaims: { + method: "GET", + operationId: API_OPERATIONS.listSevenDayCheckInClaims, + path: "/v1/admin/activity/seven-day-checkin/claims", + permission: "seven-day-checkin:view", + permissions: ["seven-day-checkin:view"] + }, + listSystemMenus: { + method: "GET", + operationId: API_OPERATIONS.listSystemMenus, + path: "/v1/system/menus", + permission: "menu:view", + permissions: ["menu:view"] + }, + listTaskDefinitions: { + method: "GET", + operationId: API_OPERATIONS.listTaskDefinitions, + path: "/v1/admin/activity/daily-tasks", + permission: "daily-task:view", + permissions: ["daily-task:view"] + }, + listUserLeaderboards: { + method: "GET", + operationId: API_OPERATIONS.listUserLeaderboards, + path: "/v1/admin/activity/user-leaderboards", + permission: "user-leaderboard:view", + permissions: ["user-leaderboard:view"] + }, + listUsers: { + method: "GET", + operationId: API_OPERATIONS.listUsers, + path: "/v1/users", + permission: "user:view", + permissions: ["user:view"] + }, + login: { + method: "POST", + operationId: API_OPERATIONS.login, + path: "/v1/auth/login" + }, + logout: { + method: "POST", + operationId: API_OPERATIONS.logout, + path: "/v1/auth/logout" + }, + lookupCoinAdjustmentTarget: { + method: "GET", + operationId: API_OPERATIONS.lookupCoinAdjustmentTarget, + path: "/v1/admin/operations/coin-adjustments/target", + permission: "coin-adjustment:create", + permissions: ["coin-adjustment:create"] + }, + me: { + method: "GET", + operationId: API_OPERATIONS.me, + path: "/v1/auth/me" + }, + navigationMenus: { + method: "GET", + operationId: API_OPERATIONS.navigationMenus, + path: "/v1/navigation/menus" + }, + refresh: { + method: "POST", + operationId: API_OPERATIONS.refresh, + path: "/v1/auth/refresh" + }, + replaceRegionBlocks: { + method: "PUT", + operationId: API_OPERATIONS.replaceRegionBlocks, + path: "/v1/admin/users/region-blocks", + permission: "region-block:update", + permissions: ["region-block:update"] + }, + replaceRegionCountries: { + method: "PUT", + operationId: API_OPERATIONS.replaceRegionCountries, + path: "/v1/admin/regions/{region_id}/countries", + permission: "region:update", + permissions: ["region:update"] + }, + replaceRoleDataScopes: { + method: "PUT", + operationId: API_OPERATIONS.replaceRoleDataScopes, + path: "/v1/roles/{id}/data-scopes", + permission: "role:data-scope", + permissions: ["role:data-scope"] + }, + replaceRolePermissions: { + method: "PUT", + operationId: API_OPERATIONS.replaceRolePermissions, + path: "/v1/roles/{id}/permissions", + permission: "role:permission", + permissions: ["role:permission","role:manage"] + }, + resetUserPassword: { + method: "POST", + operationId: API_OPERATIONS.resetUserPassword, + path: "/v1/users/{id}/reset-password", + permission: "user:reset-password", + permissions: ["user:reset-password"] + }, + search: { + method: "GET", + operationId: API_OPERATIONS.search, + path: "/v1/search" + }, + setAgencyJoinEnabled: { + method: "POST", + operationId: API_OPERATIONS.setAgencyJoinEnabled, + path: "/v1/admin/agencies/{agency_id}/join-enabled", + permission: "agency:status", + permissions: ["agency:status"] + }, + setBDLeaderStatus: { + method: "PATCH", + operationId: API_OPERATIONS.setBDLeaderStatus, + path: "/v1/admin/bd-leaders/{user_id}/status", + permission: "bd:update", + permissions: ["bd:update"] + }, + setBDStatus: { + method: "PATCH", + operationId: API_OPERATIONS.setBDStatus, + path: "/v1/admin/bds/{user_id}/status", + permission: "bd:update", + permissions: ["bd:update"] + }, + setCoinSellerStatus: { + method: "PATCH", + operationId: API_OPERATIONS.setCoinSellerStatus, + path: "/v1/admin/coin-sellers/{user_id}/status", + permission: "coin-seller:update", + permissions: ["coin-seller:update"] + }, + setGameStatus: { + method: "PATCH", + operationId: API_OPERATIONS.setGameStatus, + path: "/v1/admin/game/games/{game_id}/status", + permission: "game:status", + permissions: ["game:status"] + }, + setTaskDefinitionStatus: { + method: "POST", + operationId: API_OPERATIONS.setTaskDefinitionStatus, + path: "/v1/admin/activity/daily-tasks/{task_id}/status", + permission: "daily-task:status", + permissions: ["daily-task:status"] + }, + sortMenus: { + method: "PUT", + operationId: API_OPERATIONS.sortMenus, + path: "/v1/system/menus/sort", + permission: "menu:sort", + permissions: ["menu:sort"] + }, + syncPermissions: { + method: "POST", + operationId: API_OPERATIONS.syncPermissions, + path: "/v1/permissions/sync", + permission: "permission:sync", + permissions: ["permission:sync"] + }, + updateAchievementDefinition: { + method: "PUT", + operationId: API_OPERATIONS.updateAchievementDefinition, + path: "/v1/admin/activity/achievements/{achievement_id}", + permission: "achievement:update", + permissions: ["achievement:update"] + }, + updateAppVersion: { + method: "PUT", + operationId: API_OPERATIONS.updateAppVersion, + path: "/v1/admin/app-config/versions/{version_id}", + permission: "app-version:update", + permissions: ["app-version:update"] + }, + updateBanner: { + method: "PUT", + operationId: API_OPERATIONS.updateBanner, + path: "/v1/admin/app-config/banners/{banner_id}", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + updateCatalog: { + method: "PATCH", + operationId: API_OPERATIONS.updateCatalog, + path: "/v1/admin/game/games/{game_id}", + permission: "game:update", + permissions: ["game:update"] + }, + updateCountry: { + method: "PATCH", + operationId: API_OPERATIONS.updateCountry, + path: "/v1/admin/countries/{country_id}", + permission: "country:update", + permissions: ["country:update"] + }, + updateExploreTab: { + method: "PUT", + operationId: API_OPERATIONS.updateExploreTab, + path: "/v1/admin/app-config/explore-tabs/{tab_id}", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + updateFirstRechargeRewardConfig: { + method: "PUT", + operationId: API_OPERATIONS.updateFirstRechargeRewardConfig, + path: "/v1/admin/activity/first-recharge-reward/config", + permission: "first-recharge-reward:update", + permissions: ["first-recharge-reward:update"] + }, + updateGift: { + method: "PUT", + operationId: API_OPERATIONS.updateGift, + path: "/v1/admin/gifts/{gift_id}", + permission: "gift:update", + permissions: ["gift:update"] + }, + updateGiftType: { + method: "PUT", + operationId: API_OPERATIONS.updateGiftType, + path: "/v1/admin/gift-types/{type_code}", + permission: "gift:update", + permissions: ["gift:update"] + }, + updateGiftTypes: { + method: "PUT", + operationId: API_OPERATIONS.updateGiftTypes, + path: "/v1/admin/gift-types", + permission: "gift:update", + permissions: ["gift:update"] + }, + updateH5Link: { + method: "PUT", + operationId: API_OPERATIONS.updateH5Link, + path: "/v1/admin/app-config/h5-links/{key}", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + updateH5Links: { + method: "PUT", + operationId: API_OPERATIONS.updateH5Links, + path: "/v1/admin/app-config/h5-links", + permission: "app-config:update", + permissions: ["app-config:update"] + }, + updateMenu: { + method: "PATCH", + operationId: API_OPERATIONS.updateMenu, + path: "/v1/system/menus/{id}", + permission: "menu:update", + permissions: ["menu:update"] + }, + updateMenuVisible: { + method: "PATCH", + operationId: API_OPERATIONS.updateMenuVisible, + path: "/v1/system/menus/{id}/visible", + permission: "menu:visible", + permissions: ["menu:visible"] + }, + updatePermission: { + method: "PATCH", + operationId: API_OPERATIONS.updatePermission, + path: "/v1/permissions/{id}", + permission: "permission:update", + permissions: ["permission:update"] + }, + updatePlatform: { + method: "PATCH", + operationId: API_OPERATIONS.updatePlatform, + path: "/v1/admin/game/platforms/{platform_code}", + permission: "game:update", + permissions: ["game:update"] + }, + updateRechargeProduct: { + method: "PUT", + operationId: API_OPERATIONS.updateRechargeProduct, + path: "/v1/admin/payment/recharge-products/{product_id}", + permission: "payment-product:update", + permissions: ["payment-product:update"] + }, + updateRedPacketConfig: { + method: "PUT", + operationId: API_OPERATIONS.updateRedPacketConfig, + path: "/v1/admin/activity/red-packets/config", + permission: "red-packet:update", + permissions: ["red-packet:update"] + }, + updateRegion: { + method: "PATCH", + operationId: API_OPERATIONS.updateRegion, + path: "/v1/admin/regions/{region_id}", + permission: "region:update", + permissions: ["region:update"] + }, + updateRegistrationRewardConfig: { + method: "PUT", + operationId: API_OPERATIONS.updateRegistrationRewardConfig, + path: "/v1/admin/activity/registration-reward/config", + permission: "registration-reward:update", + permissions: ["registration-reward:update"] + }, + updateResource: { + method: "PUT", + operationId: API_OPERATIONS.updateResource, + path: "/v1/admin/resources/{resource_id}", + permission: "resource:update", + permissions: ["resource:update"] + }, + updateResourceGroup: { + method: "PUT", + operationId: API_OPERATIONS.updateResourceGroup, + path: "/v1/admin/resource-groups/{group_id}", + permission: "resource-group:update", + permissions: ["resource-group:update"] + }, + updateResourceGroupItems: { + method: "PUT", + operationId: API_OPERATIONS.updateResourceGroupItems, + path: "/v1/admin/resource-groups/{group_id}/items", + permission: "resource-group:update", + permissions: ["resource-group:update"] + }, + updateRole: { + method: "PATCH", + operationId: API_OPERATIONS.updateRole, + path: "/v1/roles/{id}", + permission: "role:update", + permissions: ["role:update","role:manage"] + }, + updateRoom: { + method: "PATCH", + operationId: API_OPERATIONS.updateRoom, + path: "/v1/admin/rooms/{room_id}", + permission: "room:update", + permissions: ["room:update"] + }, + updateRoomConfig: { + method: "PUT", + operationId: API_OPERATIONS.updateRoomConfig, + path: "/v1/admin/rooms/config", + permission: "room-config:update", + permissions: ["room-config:update"] + }, + updateRoomTreasureConfig: { + method: "PUT", + operationId: API_OPERATIONS.updateRoomTreasureConfig, + path: "/v1/admin/activity/room-treasure/config", + permission: "room-treasure:update", + permissions: ["room-treasure:update"] + }, + updateSevenDayCheckInConfig: { + method: "PUT", + operationId: API_OPERATIONS.updateSevenDayCheckInConfig, + path: "/v1/admin/activity/seven-day-checkin/config", + permission: "seven-day-checkin:update", + permissions: ["seven-day-checkin:update"] + }, + updateTaskDefinition: { + method: "PUT", + operationId: API_OPERATIONS.updateTaskDefinition, + path: "/v1/admin/activity/daily-tasks/{task_id}", + permission: "daily-task:update", + permissions: ["daily-task:update"] + }, + updateTier: { + method: "PUT", + operationId: API_OPERATIONS.updateTier, + path: "/v1/admin/users/level-config/tiers/{tier_id}", + permission: "level-config:update", + permissions: ["level-config:update"] + }, + updateTrack: { + method: "PUT", + operationId: API_OPERATIONS.updateTrack, + path: "/v1/admin/users/level-config/tracks/{track}", + permission: "level-config:update", + permissions: ["level-config:update"] + }, + updateUser: { + method: "PATCH", + operationId: API_OPERATIONS.updateUser, + path: "/v1/users/{id}", + permission: "user:update", + permissions: ["user:update"] + }, + updateUserStatus: { + method: "PATCH", + operationId: API_OPERATIONS.updateUserStatus, + path: "/v1/users/{id}/status", + permission: "user:status", + permissions: ["user:status"] + }, + uploadFile: { + method: "POST", + operationId: API_OPERATIONS.uploadFile, + path: "/v1/admin/files/upload", + permission: "upload:create", + permissions: ["upload:create"] + }, + uploadImage: { + method: "POST", + operationId: API_OPERATIONS.uploadImage, + path: "/v1/admin/files/image/upload", + permission: "upload:create", + permissions: ["upload:create"] + }, + upsertLuckyGiftConfig: { + method: "PUT", + operationId: API_OPERATIONS.upsertLuckyGiftConfig, + path: "/v1/admin/activity/lucky-gifts/config", + permission: "lucky-gift:update", + permissions: ["lucky-gift:update"] + }, + upsertResourceShopItems: { + method: "POST", + operationId: API_OPERATIONS.upsertResourceShopItems, + path: "/v1/admin/resource-shop/items", + permission: "resource-shop:update", + permissions: ["resource-shop:update"] + }, + upsertRule: { + method: "PUT", + operationId: API_OPERATIONS.upsertRule, + path: "/v1/admin/users/level-config/rules/{track}/{level}", + permission: "level-config:update", + permissions: ["level-config:update"] + } }; export const API_OPERATION_IDS = Object.values(API_OPERATIONS); export const API_PERMISSION_CODES = Array.from( - new Set( - Object.values(API_ENDPOINTS) - .flatMap((endpoint) => endpoint.permissions || (endpoint.permission ? [endpoint.permission] : [])) - .filter((permission): permission is PermissionCode => Boolean(permission)), - ), + new Set( + Object.values(API_ENDPOINTS) + .flatMap((endpoint) => endpoint.permissions || (endpoint.permission ? [endpoint.permission] : [])) + .filter((permission): permission is PermissionCode => Boolean(permission)) + ) ); export type ApiPathParams = Record; export function apiEndpointPath(operationId: ApiOperationId, params: ApiPathParams = {}) { - let endpointPath = API_ENDPOINTS[operationId].path; + let endpointPath = API_ENDPOINTS[operationId].path; - for (const [key, value] of Object.entries(params)) { - endpointPath = endpointPath.replace(`{${key}}`, encodeURIComponent(String(value))); - } + for (const [key, value] of Object.entries(params)) { + endpointPath = endpointPath.replace(`{${key}}`, encodeURIComponent(String(value))); + } - return endpointPath; + return endpointPath; } diff --git a/src/shared/api/generated/schema.d.ts b/src/shared/api/generated/schema.d.ts index cdbfdee..69cf47a 100644 --- a/src/shared/api/generated/schema.d.ts +++ b/src/shared/api/generated/schema.d.ts @@ -1172,6 +1172,54 @@ export interface paths { patch?: never; trace?: never; }; + "/admin/resource-shop/items": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["listResourceShopItems"]; + put?: never; + post: operations["upsertResourceShopItems"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/admin/resource-shop/items/{shop_item_id}/disable": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["disableResourceShopItem"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/admin/resource-shop/items/{shop_item_id}/enable": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["enableResourceShopItem"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/admin/resource-groups": { parameters: { query?: never; @@ -3931,6 +3979,58 @@ export interface operations { 200: components["responses"]["EmptyResponse"]; }; }; + listResourceShopItems: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: components["responses"]["EmptyResponse"]; + }; + }; + upsertResourceShopItems: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: components["responses"]["EmptyResponse"]; + }; + }; + disableResourceShopItem: { + parameters: { + query?: never; + header?: never; + path: { + shop_item_id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: components["responses"]["EmptyResponse"]; + }; + }; + enableResourceShopItem: { + parameters: { + query?: never; + header?: never; + path: { + shop_item_id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: components["responses"]["EmptyResponse"]; + }; + }; listResourceGroups: { parameters: { query?: never; diff --git a/src/shared/api/types.ts b/src/shared/api/types.ts index c2c90fa..e04ba66 100644 --- a/src/shared/api/types.ts +++ b/src/shared/api/types.ts @@ -652,6 +652,7 @@ export interface AppBannerDto { createdAtMs?: number; description?: string; displayScope?: "home" | "room" | "recharge" | string; + displayScopes?: Array<"home" | "room" | "recharge" | string>; endsAtMs?: number; id: number; param?: string; @@ -670,6 +671,7 @@ export interface AppBannerPayload { coverUrl: string; description?: string; displayScope?: "home" | "room" | "recharge"; + displayScopes?: Array<"home" | "room" | "recharge">; endsAtMs?: number; param?: string; platform: "android" | "ios"; diff --git a/src/shared/ui/DataTable.jsx b/src/shared/ui/DataTable.jsx index 84071a6..5e11139 100644 --- a/src/shared/ui/DataTable.jsx +++ b/src/shared/ui/DataTable.jsx @@ -14,6 +14,9 @@ import { PaginationBar } from "@/shared/ui/PaginationBar.jsx"; const DEFAULT_COLUMN_WIDTH = "minmax(120px, 1fr)"; const DEFAULT_RESIZE_MIN_WIDTH = 72; const DEFAULT_RESIZE_MAX_WIDTH = 960; +const ACTION_COLUMN_WIDTH = "112px"; +const DEFAULT_COMPACT_MIN_WIDTH = 220; +const LOW_PRIORITY_COMPACT_MIN_WIDTH = 180; export function DataTable({ className = "", @@ -64,11 +67,14 @@ export function DataTable({ const preparedColumns = useMemo( () => - columns.map((column) => ({ - ...column, - fixed: resolveColumnFixed(column, fixedEdges && hasHorizontalOverflow), - width: columnWidths[column.key] || column.width || DEFAULT_COLUMN_WIDTH - })), + columns.map((column) => { + const normalizedColumn = normalizeColumn(column); + return { + ...normalizedColumn, + fixed: resolveColumnFixed(normalizedColumn, fixedEdges && hasHorizontalOverflow), + width: columnWidths[normalizedColumn.key] || normalizedColumn.width || DEFAULT_COLUMN_WIDTH + }; + }), [columnWidths, columns, fixedEdges, hasHorizontalOverflow] ); @@ -483,6 +489,42 @@ function cellClassName(column, extraClassName = "") { .join(" "); } +function normalizeColumn(column) { + const actionColumn = isActionColumn(column); + const className = [column.className || "", actionColumn ? "admin-cell--actions" : ""].filter(Boolean).join(" "); + return { + ...column, + className, + resizable: actionColumn ? false : column.resizable, + width: actionColumn ? ACTION_COLUMN_WIDTH : normalizeColumnWidth(column) + }; +} + +function normalizeColumnWidth(column) { + if (!column.width || typeof column.width !== "string") { + return column.width; + } + + const minmaxMatch = column.width.match(/^minmax\(\s*(\d+(?:\.\d+)?)px\s*,\s*(.+)\)$/i); + if (!minmaxMatch) { + return column.width; + } + + const minWidth = Number(minmaxMatch[1]); + const flexibleWidth = minmaxMatch[2]; + const maxCompactWidth = isLowPriorityColumn(column) ? LOW_PRIORITY_COMPACT_MIN_WIDTH : DEFAULT_COMPACT_MIN_WIDTH; + const compactMinWidth = Math.min(minWidth, maxCompactWidth); + return `minmax(${compactMinWidth}px, ${flexibleWidth})`; +} + +function isActionColumn(column) { + return column.key === "actions" || column.label === "操作"; +} + +function isLowPriorityColumn(column) { + return /description|detail|remark|param|url|metadata|context|reason/i.test(String(column.key || "")); +} + function resolveColumnFixed(column, fixedEdges) { if (fixedEdges && (column.fixed === "left" || column.fixed === "right")) { return column.fixed; diff --git a/src/styles/shared-ui.css b/src/styles/shared-ui.css index ac1adc5..909143a 100644 --- a/src/styles/shared-ui.css +++ b/src/styles/shared-ui.css @@ -1178,6 +1178,11 @@ overflow-wrap: anywhere; } +.admin-cell--actions { + justify-content: center; + overflow: visible; +} + .admin-cell:first-child { padding-left: var(--admin-table-cell-x); } @@ -1385,6 +1390,28 @@ flex: 1; min-height: 0; overflow: auto; + scrollbar-color: var(--border-strong) var(--bg-subtle); + scrollbar-gutter: stable; + scrollbar-width: thin; +} + +.table-frame .table-scroll::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +.table-frame .table-scroll::-webkit-scrollbar-track { + background: var(--bg-subtle); +} + +.table-frame .table-scroll::-webkit-scrollbar-thumb { + border: 2px solid var(--bg-subtle); + border-radius: 999px; + background: var(--border-strong); +} + +.table-frame .table-scroll::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); } .table-frame .admin-row--head {