From b8bbaec2ac1852637e810b29fffd5ac3fee0f055 Mon Sep 17 00:00:00 2001 From: zhx Date: Sat, 16 May 2026 02:21:43 +0800 Subject: [PATCH] feat: extend VIP resource config --- .../components/resource-config-modal.vue | 2 +- apps/src/views/props/shared.ts | 4 ++ .../views/resident-activity/vip-config.vue | 59 ++++++++++++++++--- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/apps/src/views/props/components/resource-config-modal.vue b/apps/src/views/props/components/resource-config-modal.vue index 349bdbd..117e1f8 100644 --- a/apps/src/views/props/components/resource-config-modal.vue +++ b/apps/src/views/props/components/resource-config-modal.vue @@ -102,7 +102,7 @@ const nobleVipNameOptions = NOBLE_VIP_OPTIONS.map((item) => ({ value: item.value as any, })); const badgeTypeOptions = BADGE_TYPE_OPTIONS.filter((item) => - ['ACHIEVEMENT', 'ACTIVITY'].includes(String(item.value)), + ['VIP', 'ACHIEVEMENT', 'ACTIVITY'].includes(String(item.value)), ).map((item) => ({ label: item.name, value: item.value as any, diff --git a/apps/src/views/props/shared.ts b/apps/src/views/props/shared.ts index a82877c..df6da75 100644 --- a/apps/src/views/props/shared.ts +++ b/apps/src/views/props/shared.ts @@ -21,6 +21,7 @@ export const PROPS_TYPES: OptionItem[] = [ export const PROPS_RESOURCE_CONFIG_TYPES: OptionItem[] = [ ...PROPS_TYPES, + { value: 'VIP_EFFECT_IMAGE', name: 'VIP动效图' }, { value: 'BADGE', name: '徽章' }, ]; @@ -64,6 +65,7 @@ export const NOBLE_VIP_OPTIONS: OptionItem[] = [ ]; export const BADGE_TYPE_OPTIONS: OptionItem[] = [ + { value: 'VIP', name: '用户-VIP徽章' }, { value: 'ACHIEVEMENT', name: '用户-成就徽章' }, { value: 'ADMINISTRATOR', name: '用户-管理员' }, { value: 'ACTIVITY', name: '用户-活动徽章' }, @@ -128,6 +130,7 @@ export const PROPS_SOURCE_GROUP_TYPE_MAP: Record< CUSTOMIZE: { value: 'CUSTOMIZE', name: '自定义(只读)' }, FRAGMENTS: { value: 'FRAGMENTS', name: '碎片' }, DATA_CARD: { value: 'PROPS', name: '资料卡' }, + VIP_EFFECT_IMAGE: { value: 'PROPS', name: 'VIP动效图' }, PROP_COUPON: { value: 'PROP_COUPON', name: '道具券' }, HONOR_ACTIVITY: { value: 'BADGE', name: '荣誉-活动' }, }; @@ -290,6 +293,7 @@ export function isPropsSourceType(type?: null | string) { 'NOBLE_VIP', 'RIDE', 'THEME', + 'VIP_EFFECT_IMAGE', ].includes(String(type || '')); } diff --git a/apps/src/views/resident-activity/vip-config.vue b/apps/src/views/resident-activity/vip-config.vue index f5c668b..5df570e 100644 --- a/apps/src/views/resident-activity/vip-config.vue +++ b/apps/src/views/resident-activity/vip-config.vue @@ -32,11 +32,14 @@ import { defineOptions({ name: 'ResidentVipConfigPage' }); const resourceFields = [ - { key: 'badge', title: '徽章', type: 'BADGE' }, + { key: 'longBadge', title: '长徽章素材', type: 'BADGE', badgeTypes: ['VIP'] }, + { key: 'shortBadge', title: '短徽章素材', type: 'BADGE', badgeTypes: ['ACTIVITY', 'ACHIEVEMENT'] }, { key: 'avatarFrame', title: '头像框', type: 'AVATAR_FRAME' }, { key: 'entryEffect', title: '进场特效', type: 'RIDE' }, { key: 'chatBubble', title: '聊天气泡', type: 'CHAT_BUBBLE' }, { key: 'floatPicture', title: '飘窗', type: 'FLOAT_PICTURE' }, + { key: 'backgroundCard', title: '背景卡素材', type: 'DATA_CARD' }, + { key: 'effectImage', title: '动效图', type: 'VIP_EFFECT_IMAGE' }, ] as const; type ResourceField = (typeof resourceFields)[number]; @@ -163,16 +166,19 @@ function createResource() { function createLevel(level: number) { return { avatarFrame: createResource(), - badge: createResource(), + backgroundCard: createResource(), chatBubble: createResource(), displayName: `VIP ${level}`, durationDays: 30, enabled: false, entryEffect: createResource(), + effectImage: createResource(), floatPicture: createResource(), level, levelCode: `VIP${level}`, + longBadge: createResource(), priceGold: 0, + shortBadge: createResource(), }; } @@ -282,12 +288,42 @@ async function loadResourceOptions(field: ResourceField) { } resourceLoading[field.key] = true; try { - resourceRows[field.key] = await listSysOriginTypeList(form.sysOrigin, field.type); + resourceRows[field.key] = filterResourceRowsByField( + await listSysOriginTypeList(form.sysOrigin, field.type), + field, + ); } finally { resourceLoading[field.key] = false; } } +function filterResourceRowsByField(rows: Array>, field: ResourceField) { + if (!('badgeTypes' in field) || !field.badgeTypes?.length) { + return rows; + } + const allowed = new Set(field.badgeTypes.map((item) => String(item).toUpperCase())); + return rows.filter((item) => allowed.has(resourceBadgeType(item))); +} + +function resourceBadgeType(value: Record) { + const expand = parseJsonObject(value.expand); + return String(expand.badgeType || 'ACTIVITY').toUpperCase(); +} + +function parseJsonObject(value: unknown) { + if (typeof value !== 'string' || !value.trim()) { + return {} as Record; + } + try { + const parsed = JSON.parse(value); + return parsed && typeof parsed === 'object' && !Array.isArray(parsed) + ? (parsed as Record) + : ({} as Record); + } catch { + return {} as Record; + } +} + async function loadResourceOptionsByKey(key: string) { const field = findResourceField(key); if (field) { @@ -329,17 +365,20 @@ function normalizeLevels(levels: Array> | undefined) { } return Array.from({ length: 5 }, (_, index) => { const level = index + 1; - const item = levelMap.get(level) || createLevel(level); + const item = (levelMap.get(level) || createLevel(level)) as Record; return { ...createLevel(level), displayName: String(item.displayName || `VIP ${level}`), enabled: Boolean(item.enabled), priceGold: Number(item.priceGold || 0), - badge: normalizeResource(item.badge), + longBadge: normalizeResource(item.longBadge || item['badge']), + shortBadge: normalizeResource(item.shortBadge), avatarFrame: normalizeResource(item.avatarFrame), entryEffect: normalizeResource(item.entryEffect), chatBubble: normalizeResource(item.chatBubble), floatPicture: normalizeResource(item.floatPicture), + backgroundCard: normalizeResource(item.backgroundCard), + effectImage: normalizeResource(item.effectImage), }; }); } @@ -357,16 +396,20 @@ function buildSavePayload() { sysOrigin: form.sysOrigin, levels: (form.levels || []).map((item: Record) => ({ avatarFrame: buildResourceSavePayload(item.avatarFrame), - badge: buildResourceSavePayload(item.badge), + badge: buildResourceSavePayload(item.longBadge), + backgroundCard: buildResourceSavePayload(item.backgroundCard), chatBubble: buildResourceSavePayload(item.chatBubble), displayName: String(item.displayName || '').trim(), durationDays: 30, enabled: Boolean(item.enabled), entryEffect: buildResourceSavePayload(item.entryEffect), + effectImage: buildResourceSavePayload(item.effectImage), floatPicture: buildResourceSavePayload(item.floatPicture), level: Number(item.level || 0), levelCode: `VIP${Number(item.level || 0)}`, + longBadge: buildResourceSavePayload(item.longBadge), priceGold: Number(item.priceGold || 0), + shortBadge: buildResourceSavePayload(item.shortBadge), })), }; } @@ -551,7 +594,7 @@ watch( :data-source="form.levels" :pagination="false" row-key="level" - :scroll="{ x: 1700 }" + :scroll="{ x: 2600 }" >