Compare commits
4 Commits
0a8bddbea0
...
f46a95df79
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f46a95df79 | ||
|
|
5bbb158f57 | ||
|
|
20c00c14d5 | ||
|
|
2f9ae0a10e |
@ -12,6 +12,8 @@ const RECHARGE_REWARD_BASE = '/go/resident-activity/recharge-reward';
|
|||||||
const TASK_CENTER_BASE = '/go/resident-activity/task-center';
|
const TASK_CENTER_BASE = '/go/resident-activity/task-center';
|
||||||
const VOICE_ROOM_RED_PACKET_BASE = '/go/resident-activity/voice-room-red-packet';
|
const VOICE_ROOM_RED_PACKET_BASE = '/go/resident-activity/voice-room-red-packet';
|
||||||
const VOICE_ROOM_ROCKET_BASE = '/go/resident-activity/voice-room-rocket';
|
const VOICE_ROOM_ROCKET_BASE = '/go/resident-activity/voice-room-rocket';
|
||||||
|
const WHEEL_BASE = '/go/resident-activity/wheel';
|
||||||
|
const SMASH_GOLDEN_EGG_BASE = '/go/resident-activity/smash-golden-egg';
|
||||||
|
|
||||||
export async function getResidentInviteConfig(sysOrigin: string) {
|
export async function getResidentInviteConfig(sysOrigin: string) {
|
||||||
return requestClient.get<Record<string, any>>('/resident-activity/invite/config', {
|
return requestClient.get<Record<string, any>>('/resident-activity/invite/config', {
|
||||||
@ -100,6 +102,51 @@ export async function pageResidentVipUserStates(params: Record<string, any>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getResidentWheelConfig(sysOrigin: string) {
|
||||||
|
return requestClient.get<Record<string, any>>(`${WHEEL_BASE}/config`, {
|
||||||
|
params: { sysOrigin },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveResidentWheelConfig(data: Record<string, any>) {
|
||||||
|
return requestClient.post<Record<string, any>>(`${WHEEL_BASE}/config/save`, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveResidentWheelCategoryConfig(data: Record<string, any>) {
|
||||||
|
return requestClient.post<Record<string, any>>(
|
||||||
|
`${WHEEL_BASE}/config/category/save`,
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pageResidentWheelDrawRecords(params: Record<string, any>) {
|
||||||
|
return requestClient.get<Record<string, any>>(`${WHEEL_BASE}/record/page`, {
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getResidentSmashGoldenEggConfig(sysOrigin: string) {
|
||||||
|
return requestClient.get<Record<string, any>>(`${SMASH_GOLDEN_EGG_BASE}/config`, {
|
||||||
|
params: { sysOrigin },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveResidentSmashGoldenEggConfig(data: Record<string, any>) {
|
||||||
|
return requestClient.post<Record<string, any>>(
|
||||||
|
`${SMASH_GOLDEN_EGG_BASE}/config/save`,
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pageResidentSmashGoldenEggDrawRecords(
|
||||||
|
params: Record<string, any>,
|
||||||
|
) {
|
||||||
|
return requestClient.get<Record<string, any>>(
|
||||||
|
`${SMASH_GOLDEN_EGG_BASE}/draw-record/page`,
|
||||||
|
{ params },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function getResidentRechargeRewardConfig(sysOrigin: string) {
|
export async function getResidentRechargeRewardConfig(sysOrigin: string) {
|
||||||
return requestClient.get<Record<string, any>>(`${RECHARGE_REWARD_BASE}/config`, {
|
return requestClient.get<Record<string, any>>(`${RECHARGE_REWARD_BASE}/config`, {
|
||||||
params: { sysOrigin },
|
params: { sysOrigin },
|
||||||
|
|||||||
@ -62,6 +62,12 @@ const ROUTE_MENU_OVERRIDES: Record<
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const LOCAL_RESIDENT_ACTIVITY_FALLBACK_ROUTES = new Set([
|
||||||
|
'ResidentWheelConfig',
|
||||||
|
'ResidentSmashGoldenEggConfig',
|
||||||
|
'ResidentVoiceRoomRocket',
|
||||||
|
]);
|
||||||
|
|
||||||
function normalizeRoutePath(path?: string | null) {
|
function normalizeRoutePath(path?: string | null) {
|
||||||
return String(path || '')
|
return String(path || '')
|
||||||
.trim()
|
.trim()
|
||||||
@ -109,6 +115,7 @@ function buildAuthorizedMenuMatcher(menus: LegacyMenu[]) {
|
|||||||
const aliasSet = new Set<string>();
|
const aliasSet = new Set<string>();
|
||||||
const routerSet = new Set<string>();
|
const routerSet = new Set<string>();
|
||||||
const titleSet = new Set<string>();
|
const titleSet = new Set<string>();
|
||||||
|
let hasResidentActivityAccess = false;
|
||||||
const queue = [...menus];
|
const queue = [...menus];
|
||||||
|
|
||||||
while (queue.length > 0) {
|
while (queue.length > 0) {
|
||||||
@ -119,18 +126,34 @@ function buildAuthorizedMenuMatcher(menus: LegacyMenu[]) {
|
|||||||
if (item.alias) {
|
if (item.alias) {
|
||||||
aliasSet.add(String(item.alias));
|
aliasSet.add(String(item.alias));
|
||||||
}
|
}
|
||||||
if (item.router) {
|
const normalizedRouter = normalizeRoutePath(item.router);
|
||||||
routerSet.add(normalizeRoutePath(item.router));
|
if (normalizedRouter) {
|
||||||
|
routerSet.add(normalizedRouter);
|
||||||
}
|
}
|
||||||
if (item.menuType === 2 && item.menuName) {
|
if (item.menuType === 2 && item.menuName) {
|
||||||
titleSet.add(String(item.menuName).trim());
|
titleSet.add(String(item.menuName).trim());
|
||||||
}
|
}
|
||||||
|
const menuName = String(item.menuName || '').trim();
|
||||||
|
if (
|
||||||
|
String(item.alias || '') === 'ResidentActivityManager' ||
|
||||||
|
menuName === '常驻活动' ||
|
||||||
|
normalizedRouter === 'resident-activity/manager' ||
|
||||||
|
normalizedRouter.startsWith('resident-activity/manager/')
|
||||||
|
) {
|
||||||
|
hasResidentActivityAccess = true;
|
||||||
|
}
|
||||||
if (Array.isArray(item.childrens) && item.childrens.length > 0) {
|
if (Array.isArray(item.childrens) && item.childrens.length > 0) {
|
||||||
queue.push(...item.childrens);
|
queue.push(...item.childrens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (route: RouteRecordRaw) => {
|
return (route: RouteRecordRaw) => {
|
||||||
|
if (
|
||||||
|
hasResidentActivityAccess &&
|
||||||
|
LOCAL_RESIDENT_ACTIVITY_FALLBACK_ROUTES.has(String(route.name || ''))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
for (const alias of collectRouteAliases(route)) {
|
for (const alias of collectRouteAliases(route)) {
|
||||||
if (aliasSet.has(alias)) {
|
if (aliasSet.has(alias)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -23,6 +23,19 @@ const routes: RouteRecordRaw[] = [
|
|||||||
component: () => import('#/views/resident-activity/vip-config.vue'),
|
component: () => import('#/views/resident-activity/vip-config.vue'),
|
||||||
meta: { title: 'VIP' },
|
meta: { title: 'VIP' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'ResidentWheelConfig',
|
||||||
|
path: 'wheel/config',
|
||||||
|
component: () => import('#/views/resident-activity/wheel-config.vue'),
|
||||||
|
meta: { title: '转盘' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ResidentSmashGoldenEggConfig',
|
||||||
|
path: 'smash-golden-egg/config',
|
||||||
|
component: () =>
|
||||||
|
import('#/views/resident-activity/smash-golden-egg.vue'),
|
||||||
|
meta: { title: '砸蛋' },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'ResidentRechargeRewardConfig',
|
name: 'ResidentRechargeRewardConfig',
|
||||||
path: 'recharge-reward/config',
|
path: 'recharge-reward/config',
|
||||||
|
|||||||
@ -1,14 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, reactive, ref, watch } from 'vue';
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
|
|
||||||
import { listEmojiGroupsBySysOrigin } from '#/api/legacy/app-system';
|
|
||||||
import { listBadgePictureBySysOrigin } from '#/api/legacy/badge';
|
|
||||||
import { listGiftBySysOrigin } from '#/api/legacy/gift';
|
|
||||||
import {
|
|
||||||
listNotFamilyBySysOriginType,
|
|
||||||
listSysOriginTypeList,
|
|
||||||
} from '#/api/legacy/props';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
Empty,
|
Empty,
|
||||||
@ -18,8 +10,32 @@ import {
|
|||||||
Spin,
|
Spin,
|
||||||
} from 'antdv-next';
|
} from 'antdv-next';
|
||||||
|
|
||||||
|
import { listEmojiGroupsBySysOrigin } from '#/api/legacy/app-system';
|
||||||
|
import { listBadgePictureBySysOrigin } from '#/api/legacy/badge';
|
||||||
|
import { listGiftBySysOrigin } from '#/api/legacy/gift';
|
||||||
|
import {
|
||||||
|
listNotFamilyBySysOriginType,
|
||||||
|
listSysOriginTypeList,
|
||||||
|
} from '#/api/legacy/props';
|
||||||
|
|
||||||
defineOptions({ name: 'OperatePropsSourceSelectDrawer' });
|
defineOptions({ name: 'OperatePropsSourceSelectDrawer' });
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
defaultType?: string;
|
||||||
|
open: boolean;
|
||||||
|
sysOrigin: string;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
defaultType: 'AVATAR_FRAME',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
close: [];
|
||||||
|
select: [item: SourceItem];
|
||||||
|
}>();
|
||||||
|
|
||||||
type SourceTypeOption = {
|
type SourceTypeOption = {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
@ -53,22 +69,6 @@ const typeSelectOptions = TYPE_OPTIONS.map((item) => ({
|
|||||||
value: item.value as any,
|
value: item.value as any,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
defaultType?: string;
|
|
||||||
open: boolean;
|
|
||||||
sysOrigin: string;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
defaultType: 'AVATAR_FRAME',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
close: [];
|
|
||||||
select: [item: SourceItem];
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const keyword = ref('');
|
const keyword = ref('');
|
||||||
const query = reactive({
|
const query = reactive({
|
||||||
@ -103,6 +103,89 @@ const currentList = computed(() => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function firstPresent(record: Record<string, any>, keys: string[]) {
|
||||||
|
for (const key of keys) {
|
||||||
|
const value = record?.[key];
|
||||||
|
if (value !== undefined && value !== null && String(value).trim() !== '') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeSourceItem(
|
||||||
|
item: Record<string, any>,
|
||||||
|
type: string,
|
||||||
|
options: {
|
||||||
|
coverKeys?: string[];
|
||||||
|
idKeys?: string[];
|
||||||
|
nameKeys?: string[];
|
||||||
|
sourceUrlKeys?: string[];
|
||||||
|
} = {},
|
||||||
|
): SourceItem {
|
||||||
|
const id = firstPresent(
|
||||||
|
item,
|
||||||
|
options.idKeys || [
|
||||||
|
'id',
|
||||||
|
'resourceId',
|
||||||
|
'sourceId',
|
||||||
|
'propsId',
|
||||||
|
'propsSourceId',
|
||||||
|
'badgeConfigId',
|
||||||
|
'giftId',
|
||||||
|
'groupId',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
amount: firstPresent(item, ['amount', 'giftCandy', 'price', 'goldAmount']),
|
||||||
|
cover: String(
|
||||||
|
firstPresent(
|
||||||
|
item,
|
||||||
|
options.coverKeys || [
|
||||||
|
'cover',
|
||||||
|
'coverUrl',
|
||||||
|
'resourceCover',
|
||||||
|
'resourceCoverUrl',
|
||||||
|
'giftPhoto',
|
||||||
|
'selectUrl',
|
||||||
|
'icon',
|
||||||
|
'smallIcon',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
id: id as number | string,
|
||||||
|
name: String(
|
||||||
|
firstPresent(
|
||||||
|
item,
|
||||||
|
options.nameKeys || [
|
||||||
|
'name',
|
||||||
|
'resourceName',
|
||||||
|
'sourceName',
|
||||||
|
'giftName',
|
||||||
|
'badgeName',
|
||||||
|
'groupName',
|
||||||
|
'title',
|
||||||
|
'remark',
|
||||||
|
],
|
||||||
|
) || (id ? `资源 ${id}` : ''),
|
||||||
|
),
|
||||||
|
sourceUrl: String(
|
||||||
|
firstPresent(
|
||||||
|
item,
|
||||||
|
options.sourceUrlKeys || [
|
||||||
|
'sourceUrl',
|
||||||
|
'resourceUrl',
|
||||||
|
'url',
|
||||||
|
'giftSourceUrl',
|
||||||
|
'animationUrl',
|
||||||
|
'playUrl',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.open,
|
() => props.open,
|
||||||
(open) => {
|
(open) => {
|
||||||
@ -150,56 +233,53 @@ async function loadSource(type: string) {
|
|||||||
store.loading = true;
|
store.loading = true;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
if (type === 'GIFT') {
|
switch (type) {
|
||||||
const result = await listGiftBySysOrigin(props.sysOrigin);
|
case 'BADGE':
|
||||||
store.list = (result || []).map((item) => ({
|
case 'ROOM_BADGE': {
|
||||||
amount: item.giftCandy,
|
|
||||||
cover: item.giftPhoto,
|
|
||||||
id: item.id,
|
|
||||||
name: item.giftName,
|
|
||||||
sourceUrl: item.giftSourceUrl,
|
|
||||||
type,
|
|
||||||
}));
|
|
||||||
} else if (type === 'EMOJI') {
|
|
||||||
const result = await listEmojiGroupsBySysOrigin(props.sysOrigin);
|
|
||||||
store.list = (result || []).map((item) => ({
|
|
||||||
amount: item.amount,
|
|
||||||
cover: item.cover,
|
|
||||||
id: item.id || '',
|
|
||||||
name: item.groupName || '',
|
|
||||||
sourceUrl: '',
|
|
||||||
type,
|
|
||||||
}));
|
|
||||||
} else if (type === 'BADGE' || type === 'ROOM_BADGE') {
|
|
||||||
const badgeType = type === 'BADGE' ? 'ACTIVITY' : 'ROOM_ACHIEVEMENT';
|
const badgeType = type === 'BADGE' ? 'ACTIVITY' : 'ROOM_ACHIEVEMENT';
|
||||||
const result = await listBadgePictureBySysOrigin(props.sysOrigin, badgeType);
|
const result = await listBadgePictureBySysOrigin(props.sysOrigin, badgeType);
|
||||||
store.list = (result || []).map((item) => ({
|
store.list = (result || []).map((item) =>
|
||||||
cover: item.selectUrl,
|
normalizeSourceItem(item, type, {
|
||||||
id: item.badgeConfigId || '',
|
coverKeys: ['selectUrl', 'cover', 'coverUrl'],
|
||||||
name: item.badgeName || '',
|
idKeys: ['badgeConfigId', 'id', 'badgeId'],
|
||||||
sourceUrl: item.animationUrl,
|
nameKeys: ['badgeName', 'name'],
|
||||||
type,
|
sourceUrlKeys: ['animationUrl', 'sourceUrl', 'resourceUrl'],
|
||||||
}));
|
}),
|
||||||
} else if (type === 'NOBLE_VIP') {
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'EMOJI': {
|
||||||
|
const result = await listEmojiGroupsBySysOrigin(props.sysOrigin);
|
||||||
|
store.list = (result || []).map((item) =>
|
||||||
|
normalizeSourceItem(item, type, {
|
||||||
|
idKeys: ['id', 'groupId'],
|
||||||
|
nameKeys: ['groupName', 'name'],
|
||||||
|
sourceUrlKeys: [],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'GIFT': {
|
||||||
|
const result = await listGiftBySysOrigin(props.sysOrigin);
|
||||||
|
store.list = (result || []).map((item) =>
|
||||||
|
normalizeSourceItem(item, type, {
|
||||||
|
coverKeys: ['giftPhoto', 'cover', 'coverUrl'],
|
||||||
|
idKeys: ['id', 'giftId'],
|
||||||
|
nameKeys: ['giftName', 'name'],
|
||||||
|
sourceUrlKeys: ['giftSourceUrl', 'sourceUrl', 'resourceUrl'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'NOBLE_VIP': {
|
||||||
const result = await listNotFamilyBySysOriginType(props.sysOrigin, type);
|
const result = await listNotFamilyBySysOriginType(props.sysOrigin, type);
|
||||||
store.list = (result || []).map((item) => ({
|
store.list = (result || []).map((item) => normalizeSourceItem(item, type));
|
||||||
amount: item.amount,
|
break;
|
||||||
cover: item.cover,
|
}
|
||||||
id: item.id || '',
|
default: {
|
||||||
name: item.name || '',
|
|
||||||
sourceUrl: item.sourceUrl,
|
|
||||||
type,
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
const result = await listSysOriginTypeList(props.sysOrigin, type);
|
const result = await listSysOriginTypeList(props.sysOrigin, type);
|
||||||
store.list = (result || []).map((item) => ({
|
store.list = (result || []).map((item) => normalizeSourceItem(item, type));
|
||||||
amount: item.amount,
|
}
|
||||||
cover: item.cover,
|
|
||||||
id: item.id || '',
|
|
||||||
name: item.name || '',
|
|
||||||
sourceUrl: item.sourceUrl,
|
|
||||||
type,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
store.loaded = true;
|
store.loaded = true;
|
||||||
} finally {
|
} finally {
|
||||||
@ -258,7 +338,7 @@ function handleSelect(item: SourceItem) {
|
|||||||
:src="item.cover || 'https://dummyimage.com/88x88/e2e8f0/64748b&text=+'"
|
:src="item.cover || 'https://dummyimage.com/88x88/e2e8f0/64748b&text=+'"
|
||||||
alt=""
|
alt=""
|
||||||
class="source-cover"
|
class="source-cover"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="source-name">{{ item.name || '-' }}</div>
|
<div class="source-name">{{ item.name || '-' }}</div>
|
||||||
<div class="source-meta">ID {{ item.id }}</div>
|
<div class="source-meta">ID {{ item.id }}</div>
|
||||||
|
|||||||
@ -0,0 +1,452 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { listBadgePictureBySysOrigin } from '#/api/legacy/badge';
|
||||||
|
import { listGiftBySysOrigin } from '#/api/legacy/gift';
|
||||||
|
import {
|
||||||
|
listNotFamilyBySysOriginType,
|
||||||
|
pagePropsSource,
|
||||||
|
} from '#/api/legacy/props';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Drawer,
|
||||||
|
Empty,
|
||||||
|
Input,
|
||||||
|
Pagination,
|
||||||
|
Space,
|
||||||
|
Spin,
|
||||||
|
} from 'antdv-next';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ResidentActivityResourceSelectDrawer' });
|
||||||
|
|
||||||
|
type ResourceItem = {
|
||||||
|
amount?: number | string;
|
||||||
|
cover: string;
|
||||||
|
id: number | string;
|
||||||
|
name: string;
|
||||||
|
sourceUrl: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
defaultType?: string;
|
||||||
|
fixedType?: boolean;
|
||||||
|
open: boolean;
|
||||||
|
sysOrigin: string;
|
||||||
|
title?: string;
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
defaultType: 'ALL_PROPS',
|
||||||
|
fixedType: false,
|
||||||
|
title: '选择资源',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
close: [];
|
||||||
|
select: [item: ResourceItem];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const typeOptions = [
|
||||||
|
{ label: '全部资源', value: 'ALL_PROPS' },
|
||||||
|
{ label: '自定义', value: 'CUSTOMIZE' },
|
||||||
|
{ label: '头像框', value: 'AVATAR_FRAME' },
|
||||||
|
{ label: '座驾', value: 'RIDE' },
|
||||||
|
{ label: '聊天气泡', value: 'CHAT_BUBBLE' },
|
||||||
|
{ label: '贵族 VIP', value: 'NOBLE_VIP' },
|
||||||
|
{ label: '主题背景', value: 'THEME' },
|
||||||
|
{ label: '飘窗', value: 'FLOAT_PICTURE' },
|
||||||
|
{ label: '礼物', value: 'GIFT' },
|
||||||
|
{ label: '徽章', value: 'BADGE' },
|
||||||
|
].map((item) => ({ ...item, value: item.value as any }));
|
||||||
|
|
||||||
|
const listOnlyTypes = new Set(['BADGE', 'GIFT', 'NOBLE_VIP']);
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const list = ref<ResourceItem[]>([]);
|
||||||
|
const total = ref(0);
|
||||||
|
|
||||||
|
const query = reactive({
|
||||||
|
cursor: 1,
|
||||||
|
keyword: '',
|
||||||
|
limit: 24,
|
||||||
|
type: 'ALL_PROPS',
|
||||||
|
});
|
||||||
|
|
||||||
|
const localRows = ref<ResourceItem[]>([]);
|
||||||
|
|
||||||
|
const filteredLocalRows = computed(() => {
|
||||||
|
const keyword = query.keyword.trim().toLowerCase();
|
||||||
|
if (!keyword) {
|
||||||
|
return localRows.value;
|
||||||
|
}
|
||||||
|
return localRows.value.filter(
|
||||||
|
(item) =>
|
||||||
|
String(item.id).toLowerCase().includes(keyword) ||
|
||||||
|
item.name.toLowerCase().includes(keyword),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function firstPresent(record: Record<string, any>, keys: string[]) {
|
||||||
|
for (const key of keys) {
|
||||||
|
const value = record?.[key];
|
||||||
|
if (value !== undefined && value !== null && String(value).trim() !== '') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeResource(
|
||||||
|
item: Record<string, any>,
|
||||||
|
type: string,
|
||||||
|
options: {
|
||||||
|
coverKeys?: string[];
|
||||||
|
idKeys?: string[];
|
||||||
|
nameKeys?: string[];
|
||||||
|
sourceUrlKeys?: string[];
|
||||||
|
} = {},
|
||||||
|
): ResourceItem {
|
||||||
|
const id = firstPresent(
|
||||||
|
item,
|
||||||
|
options.idKeys || ['id', 'resourceId', 'sourceId', 'propsId'],
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
amount: firstPresent(item, ['amount', 'giftCandy', 'price']),
|
||||||
|
cover: String(
|
||||||
|
firstPresent(
|
||||||
|
item,
|
||||||
|
options.coverKeys || [
|
||||||
|
'cover',
|
||||||
|
'coverUrl',
|
||||||
|
'resourceCover',
|
||||||
|
'resourceCoverUrl',
|
||||||
|
'giftPhoto',
|
||||||
|
'selectUrl',
|
||||||
|
'icon',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
id: id as number | string,
|
||||||
|
name: String(
|
||||||
|
firstPresent(
|
||||||
|
item,
|
||||||
|
options.nameKeys || [
|
||||||
|
'name',
|
||||||
|
'resourceName',
|
||||||
|
'sourceName',
|
||||||
|
'giftName',
|
||||||
|
'badgeName',
|
||||||
|
'title',
|
||||||
|
'remark',
|
||||||
|
],
|
||||||
|
) || (id ? `资源 ${id}` : ''),
|
||||||
|
),
|
||||||
|
sourceUrl: String(
|
||||||
|
firstPresent(
|
||||||
|
item,
|
||||||
|
options.sourceUrlKeys || [
|
||||||
|
'sourceUrl',
|
||||||
|
'resourceUrl',
|
||||||
|
'url',
|
||||||
|
'giftSourceUrl',
|
||||||
|
'animationUrl',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyLocalPage() {
|
||||||
|
const rows = filteredLocalRows.value;
|
||||||
|
total.value = rows.length;
|
||||||
|
const start = (query.cursor - 1) * query.limit;
|
||||||
|
list.value = rows.slice(start, start + query.limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadListType(type: string) {
|
||||||
|
if (type === 'GIFT') {
|
||||||
|
const result = await listGiftBySysOrigin(props.sysOrigin);
|
||||||
|
localRows.value = (result || []).map((item) =>
|
||||||
|
normalizeResource(item, type, {
|
||||||
|
coverKeys: ['giftPhoto', 'cover'],
|
||||||
|
idKeys: ['id', 'giftId'],
|
||||||
|
nameKeys: ['giftName', 'name'],
|
||||||
|
sourceUrlKeys: ['giftSourceUrl', 'sourceUrl'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
applyLocalPage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === 'BADGE') {
|
||||||
|
const result = await listBadgePictureBySysOrigin(props.sysOrigin, 'ACTIVITY');
|
||||||
|
localRows.value = (result || []).map((item) =>
|
||||||
|
normalizeResource(item, type, {
|
||||||
|
coverKeys: ['selectUrl', 'cover'],
|
||||||
|
idKeys: ['badgeConfigId', 'id'],
|
||||||
|
nameKeys: ['badgeName', 'name'],
|
||||||
|
sourceUrlKeys: ['animationUrl', 'sourceUrl'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
applyLocalPage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === 'NOBLE_VIP') {
|
||||||
|
const result = await listNotFamilyBySysOriginType(props.sysOrigin, type);
|
||||||
|
localRows.value = (result || []).map((item) =>
|
||||||
|
normalizeResource(item, type),
|
||||||
|
);
|
||||||
|
applyLocalPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData(reset = false) {
|
||||||
|
if (!props.open || !props.sysOrigin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reset) {
|
||||||
|
query.cursor = 1;
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
if (listOnlyTypes.has(query.type)) {
|
||||||
|
await loadListType(query.type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const keyword = query.keyword.trim();
|
||||||
|
const params: Record<string, any> = {
|
||||||
|
cursor: query.cursor,
|
||||||
|
del: false,
|
||||||
|
limit: query.limit,
|
||||||
|
sysOrigin: props.sysOrigin,
|
||||||
|
};
|
||||||
|
if (query.type && query.type !== 'ALL_PROPS') {
|
||||||
|
params.type = query.type;
|
||||||
|
}
|
||||||
|
if (keyword) {
|
||||||
|
if (/^\d+$/.test(keyword)) {
|
||||||
|
params.id = keyword;
|
||||||
|
} else {
|
||||||
|
params.name = keyword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const result = await pagePropsSource(params);
|
||||||
|
list.value = (result.records || []).map((item) =>
|
||||||
|
normalizeResource(item, String(item.type || query.type || '')),
|
||||||
|
);
|
||||||
|
total.value = result.total || 0;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTypeChange(value: string) {
|
||||||
|
query.type = value || 'ALL_PROPS';
|
||||||
|
query.keyword = '';
|
||||||
|
localRows.value = [];
|
||||||
|
void loadData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSearch() {
|
||||||
|
void loadData(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePageChange(page: number, pageSize: number) {
|
||||||
|
query.cursor = page;
|
||||||
|
query.limit = pageSize;
|
||||||
|
if (listOnlyTypes.has(query.type)) {
|
||||||
|
applyLocalPage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelect(item: ResourceItem) {
|
||||||
|
emit('select', item);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.open,
|
||||||
|
(open) => {
|
||||||
|
if (!open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
query.type = props.defaultType || 'ALL_PROPS';
|
||||||
|
query.keyword = '';
|
||||||
|
query.cursor = 1;
|
||||||
|
localRows.value = [];
|
||||||
|
void loadData(true);
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.defaultType,
|
||||||
|
(value) => {
|
||||||
|
if (!props.open || !value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
query.type = value;
|
||||||
|
query.keyword = '';
|
||||||
|
localRows.value = [];
|
||||||
|
void loadData(true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.sysOrigin,
|
||||||
|
() => {
|
||||||
|
localRows.value = [];
|
||||||
|
if (props.open) {
|
||||||
|
void loadData(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Drawer
|
||||||
|
:open="open"
|
||||||
|
destroy-on-close
|
||||||
|
:title="title"
|
||||||
|
width="920"
|
||||||
|
@close="emit('close')"
|
||||||
|
>
|
||||||
|
<div v-if="!fixedType" class="type-filter">
|
||||||
|
<Button
|
||||||
|
v-for="item in typeOptions"
|
||||||
|
:key="item.value"
|
||||||
|
size="small"
|
||||||
|
:type="query.type === item.value ? 'primary' : 'default'"
|
||||||
|
@click="handleTypeChange(item.value)"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Space class="toolbar" wrap>
|
||||||
|
<Input
|
||||||
|
v-model:value="query.keyword"
|
||||||
|
allow-clear
|
||||||
|
placeholder="资源名称 / ID"
|
||||||
|
style="width: 260px"
|
||||||
|
@press-enter="handleSearch"
|
||||||
|
/>
|
||||||
|
<Button :loading="loading" type="primary" @click="handleSearch">
|
||||||
|
搜索
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
<Spin :spinning="loading">
|
||||||
|
<div v-if="list.length > 0" class="resource-grid">
|
||||||
|
<button
|
||||||
|
v-for="item in list"
|
||||||
|
:key="`${item.type}-${item.id}`"
|
||||||
|
class="resource-card"
|
||||||
|
type="button"
|
||||||
|
@click="handleSelect(item)"
|
||||||
|
>
|
||||||
|
<div class="resource-cover-wrap">
|
||||||
|
<img
|
||||||
|
:src="item.cover || 'https://dummyimage.com/88x88/e2e8f0/64748b&text=+'"
|
||||||
|
alt=""
|
||||||
|
class="resource-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="resource-name">{{ item.name || '-' }}</div>
|
||||||
|
<div class="resource-meta">ID {{ item.id }}</div>
|
||||||
|
<div class="resource-type">{{ item.type || '-' }}</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<Empty v-else description="暂无可选资源" />
|
||||||
|
</Spin>
|
||||||
|
|
||||||
|
<div class="pager">
|
||||||
|
<Pagination
|
||||||
|
:current="query.cursor"
|
||||||
|
:page-size="query.limit"
|
||||||
|
:total="total"
|
||||||
|
show-size-changer
|
||||||
|
@change="handlePageChange"
|
||||||
|
@showSizeChange="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.toolbar {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-filter {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 16px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-card {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: center;
|
||||||
|
transition:
|
||||||
|
border-color 0.2s ease,
|
||||||
|
box-shadow 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-card:hover {
|
||||||
|
border-color: #2563eb;
|
||||||
|
box-shadow: 0 12px 24px rgb(37 99 235 / 12%);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-cover-wrap {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 88px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-cover {
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 88px;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 88px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-name {
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.4;
|
||||||
|
min-height: 40px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-meta,
|
||||||
|
.resource-type {
|
||||||
|
color: #64748b;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 6px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pager {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1552
apps/src/views/resident-activity/smash-golden-egg.vue
Normal file
1552
apps/src/views/resident-activity/smash-golden-egg.vue
Normal file
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,8 @@ import {
|
|||||||
} from '#/api/legacy/resident-activity';
|
} from '#/api/legacy/resident-activity';
|
||||||
import { getAllowedSysOrigins } from '#/views/system/shared';
|
import { getAllowedSysOrigins } from '#/views/system/shared';
|
||||||
|
|
||||||
|
import ResourceSelectDrawer from './components/resource-select-drawer.vue';
|
||||||
|
|
||||||
defineOptions({ name: 'ResidentVoiceRoomRocketPage' });
|
defineOptions({ name: 'ResidentVoiceRoomRocketPage' });
|
||||||
|
|
||||||
const RIYADH_TIMEZONE = 'Asia/Riyadh';
|
const RIYADH_TIMEZONE = 'Asia/Riyadh';
|
||||||
@ -41,7 +43,6 @@ type LevelRow = {
|
|||||||
id?: number | string;
|
id?: number | string;
|
||||||
level: number;
|
level: number;
|
||||||
needEnergy: number;
|
needEnergy: number;
|
||||||
progressBarUrl: string;
|
|
||||||
rocketAnimationUrl: string;
|
rocketAnimationUrl: string;
|
||||||
rocketIconUrl: string;
|
rocketIconUrl: string;
|
||||||
shakeThresholdPercent: string;
|
shakeThresholdPercent: string;
|
||||||
@ -64,6 +65,16 @@ type RewardRow = {
|
|||||||
weight: number;
|
weight: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ResourceOption = {
|
||||||
|
amount?: number | string;
|
||||||
|
cover: string;
|
||||||
|
id: number | string;
|
||||||
|
name: string;
|
||||||
|
remark?: string;
|
||||||
|
sourceUrl: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
const accessStore = useAccessStore();
|
const accessStore = useAccessStore();
|
||||||
const sysOriginOptions = computed(() => {
|
const sysOriginOptions = computed(() => {
|
||||||
const options = getAllowedSysOrigins(accessStore.accessCodes || []);
|
const options = getAllowedSysOrigins(accessStore.accessCodes || []);
|
||||||
@ -99,6 +110,23 @@ const configForm = reactive({
|
|||||||
const levelRows = ref<LevelRow[]>([]);
|
const levelRows = ref<LevelRow[]>([]);
|
||||||
const rewardRows = ref<RewardRow[]>([]);
|
const rewardRows = ref<RewardRow[]>([]);
|
||||||
|
|
||||||
|
const resourcePickerOpen = ref(false);
|
||||||
|
const resourcePickerTitle = ref('选择资源');
|
||||||
|
const resourcePickerDefaultType = ref('ALL_PROPS');
|
||||||
|
const resourcePickerFixedType = ref(false);
|
||||||
|
const resourcePickerTarget = ref<
|
||||||
|
| {
|
||||||
|
field: 'rocketAnimationUrl' | 'rocketIconUrl';
|
||||||
|
kind: 'level';
|
||||||
|
row: Record<string, any>;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
kind: 'reward';
|
||||||
|
row: Record<string, any>;
|
||||||
|
}
|
||||||
|
| null
|
||||||
|
>(null);
|
||||||
|
|
||||||
const sceneOptions = [
|
const sceneOptions = [
|
||||||
{ label: '贡献第一', value: 'TOP1' },
|
{ label: '贡献第一', value: 'TOP1' },
|
||||||
{ label: '点火人', value: 'IGNITE' },
|
{ label: '点火人', value: 'IGNITE' },
|
||||||
@ -113,6 +141,7 @@ const rewardTypeOptions = [
|
|||||||
{ label: 'VIP', value: 'VIP_CARD' },
|
{ label: 'VIP', value: 'VIP_CARD' },
|
||||||
{ label: '礼物', value: 'GIFT' },
|
{ label: '礼物', value: 'GIFT' },
|
||||||
{ label: '徽章', value: 'BADGE' },
|
{ label: '徽章', value: 'BADGE' },
|
||||||
|
{ label: '轮空', value: 'NONE' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const levelOptions = computed(() =>
|
const levelOptions = computed(() =>
|
||||||
@ -122,6 +151,12 @@ const levelOptions = computed(() =>
|
|||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function rewardTypeOptionsForRow(row: Record<string, any>) {
|
||||||
|
return row.rewardScene === 'IN_ROOM'
|
||||||
|
? rewardTypeOptions
|
||||||
|
: rewardTypeOptions.filter((item) => item.value !== 'NONE');
|
||||||
|
}
|
||||||
|
|
||||||
const statusMeta = computed(() => {
|
const statusMeta = computed(() => {
|
||||||
if (!configForm.configured) {
|
if (!configForm.configured) {
|
||||||
return { color: 'warning', text: '未配置' };
|
return { color: 'warning', text: '未配置' };
|
||||||
@ -134,10 +169,14 @@ const statusMeta = computed(() => {
|
|||||||
const levelColumns = [
|
const levelColumns = [
|
||||||
{ dataIndex: 'level', key: 'level', title: '等级', width: 90 },
|
{ dataIndex: 'level', key: 'level', title: '等级', width: 90 },
|
||||||
{ dataIndex: 'needEnergy', key: 'needEnergy', title: '所需能量', width: 160 },
|
{ dataIndex: 'needEnergy', key: 'needEnergy', title: '所需能量', width: 160 },
|
||||||
{ dataIndex: 'shakeThresholdPercent', key: 'shakeThresholdPercent', title: '晃动阈值(%)', width: 160 },
|
|
||||||
{ dataIndex: 'rocketIconUrl', key: 'rocketIconUrl', title: '火箭图标', width: 260 },
|
{ dataIndex: 'rocketIconUrl', key: 'rocketIconUrl', title: '火箭图标', width: 260 },
|
||||||
{ dataIndex: 'rocketAnimationUrl', key: 'rocketAnimationUrl', title: '发射动画', width: 260 },
|
{
|
||||||
{ dataIndex: 'progressBarUrl', key: 'progressBarUrl', title: '进度条资源', width: 260 },
|
dataIndex: 'rocketAnimationUrl',
|
||||||
|
key: 'rocketAnimationUrl',
|
||||||
|
title: '发射动画',
|
||||||
|
width: 260,
|
||||||
|
},
|
||||||
|
{ dataIndex: 'shakeThresholdPercent', key: 'shakeThresholdPercent', title: '晃动阈值(%)', width: 160 },
|
||||||
{ dataIndex: 'enabled', key: 'enabled', title: '启用', width: 90 },
|
{ dataIndex: 'enabled', key: 'enabled', title: '启用', width: 90 },
|
||||||
{ dataIndex: 'sort', key: 'sort', title: '排序', width: 100 },
|
{ dataIndex: 'sort', key: 'sort', title: '排序', width: 100 },
|
||||||
];
|
];
|
||||||
@ -145,9 +184,9 @@ const levelColumns = [
|
|||||||
const rewardColumns = [
|
const rewardColumns = [
|
||||||
{ dataIndex: 'rewardScene', key: 'rewardScene', title: '奖励场景', width: 150 },
|
{ dataIndex: 'rewardScene', key: 'rewardScene', title: '奖励场景', width: 150 },
|
||||||
{ dataIndex: 'rewardType', key: 'rewardType', title: '奖励类型', width: 150 },
|
{ dataIndex: 'rewardType', key: 'rewardType', title: '奖励类型', width: 150 },
|
||||||
{ dataIndex: 'rewardItemId', key: 'rewardItemId', title: '资源ID', width: 170 },
|
{ dataIndex: 'rewardItemId', key: 'rewardItemId', title: '资源', width: 220 },
|
||||||
{ dataIndex: 'rewardName', key: 'rewardName', title: '奖励名称', width: 180 },
|
{ dataIndex: 'rewardName', key: 'rewardName', title: '奖励名称', width: 180 },
|
||||||
{ dataIndex: 'rewardCover', key: 'rewardCover', title: '封面URL', width: 220 },
|
{ dataIndex: 'rewardCover', key: 'rewardCover', title: '封面', width: 220 },
|
||||||
{ dataIndex: 'rewardAmount', key: 'rewardAmount', title: '数量/金币/天数', width: 150 },
|
{ dataIndex: 'rewardAmount', key: 'rewardAmount', title: '数量/金币/天数', width: 150 },
|
||||||
{ dataIndex: 'expireDays', key: 'expireDays', title: '有效天数', width: 130 },
|
{ dataIndex: 'expireDays', key: 'expireDays', title: '有效天数', width: 130 },
|
||||||
{ dataIndex: 'weight', key: 'weight', title: '权重', width: 110 },
|
{ dataIndex: 'weight', key: 'weight', title: '权重', width: 110 },
|
||||||
@ -161,7 +200,6 @@ function createDefaultLevel(level: number): LevelRow {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
level,
|
level,
|
||||||
needEnergy: level * 100,
|
needEnergy: level * 100,
|
||||||
progressBarUrl: '',
|
|
||||||
rocketAnimationUrl: '',
|
rocketAnimationUrl: '',
|
||||||
rocketIconUrl: '',
|
rocketIconUrl: '',
|
||||||
shakeThresholdPercent: '95.0000',
|
shakeThresholdPercent: '95.0000',
|
||||||
@ -246,7 +284,6 @@ function normalizeLevelRows(rows: Array<Record<string, any>> | undefined) {
|
|||||||
enabled: row.enabled === undefined ? true : Boolean(row.enabled),
|
enabled: row.enabled === undefined ? true : Boolean(row.enabled),
|
||||||
id: row.id,
|
id: row.id,
|
||||||
needEnergy: toNumber(row.needEnergy, level * 100),
|
needEnergy: toNumber(row.needEnergy, level * 100),
|
||||||
progressBarUrl: String(row.progressBarUrl || ''),
|
|
||||||
rocketAnimationUrl: String(row.rocketAnimationUrl || ''),
|
rocketAnimationUrl: String(row.rocketAnimationUrl || ''),
|
||||||
rocketIconUrl: String(row.rocketIconUrl || ''),
|
rocketIconUrl: String(row.rocketIconUrl || ''),
|
||||||
shakeThresholdPercent: String(row.shakeThresholdPercent || '95.0000'),
|
shakeThresholdPercent: String(row.shakeThresholdPercent || '95.0000'),
|
||||||
@ -273,6 +310,115 @@ function normalizeRewardRows(rows: Array<Record<string, any>> | undefined) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rewardResourceType(rewardType: string) {
|
||||||
|
const value = String(rewardType || '').trim();
|
||||||
|
const mapping: Record<string, string> = {
|
||||||
|
AVATAR_FRAME: 'AVATAR_FRAME',
|
||||||
|
BADGE: 'BADGE',
|
||||||
|
CHAT_BUBBLE: 'CHAT_BUBBLE',
|
||||||
|
GIFT: 'GIFT',
|
||||||
|
MOUNT: 'RIDE',
|
||||||
|
VIP_CARD: 'NOBLE_VIP',
|
||||||
|
};
|
||||||
|
return mapping[value] || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewardTypeText(rewardType: string) {
|
||||||
|
return (
|
||||||
|
rewardTypeOptions.find((item) => item.value === rewardType)?.label ||
|
||||||
|
rewardType ||
|
||||||
|
'资源'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRewardResourceDisabled(row: Record<string, any>) {
|
||||||
|
return row.rewardType === 'GOLD' || row.rewardType === 'NONE';
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLevelResourcePicker(
|
||||||
|
row: Record<string, any>,
|
||||||
|
field: 'rocketAnimationUrl' | 'rocketIconUrl',
|
||||||
|
) {
|
||||||
|
resourcePickerTarget.value = {
|
||||||
|
field,
|
||||||
|
kind: 'level',
|
||||||
|
row,
|
||||||
|
};
|
||||||
|
resourcePickerTitle.value =
|
||||||
|
field === 'rocketIconUrl' ? '选择火箭图标资源' : '选择发射动画资源';
|
||||||
|
resourcePickerDefaultType.value = 'ALL_PROPS';
|
||||||
|
resourcePickerFixedType.value = false;
|
||||||
|
resourcePickerOpen.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openRewardResourcePicker(row: Record<string, any>) {
|
||||||
|
if (isRewardResourceDisabled(row)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const sourceType = rewardResourceType(row.rewardType);
|
||||||
|
if (!sourceType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resourcePickerTarget.value = {
|
||||||
|
kind: 'reward',
|
||||||
|
row,
|
||||||
|
};
|
||||||
|
resourcePickerTitle.value = `选择${rewardTypeText(row.rewardType)}资源`;
|
||||||
|
resourcePickerDefaultType.value = sourceType;
|
||||||
|
resourcePickerFixedType.value = true;
|
||||||
|
resourcePickerOpen.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearLevelResource(
|
||||||
|
row: Record<string, any>,
|
||||||
|
field: 'rocketAnimationUrl' | 'rocketIconUrl',
|
||||||
|
) {
|
||||||
|
row[field] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearRewardResource(row: Record<string, any>) {
|
||||||
|
row.rewardItemId = null;
|
||||||
|
row.rewardCover = '';
|
||||||
|
if (row.rewardName !== '金币' && row.rewardName !== '轮空') {
|
||||||
|
row.rewardName = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRewardSceneChange(row: Record<string, any>) {
|
||||||
|
if (row.rewardScene !== 'IN_ROOM' && row.rewardType === 'NONE') {
|
||||||
|
row.rewardType = 'GOLD';
|
||||||
|
handleRewardTypeChange(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleResourceSelect(item: ResourceOption) {
|
||||||
|
const target = resourcePickerTarget.value;
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (target.kind === 'level') {
|
||||||
|
const value =
|
||||||
|
target.field === 'rocketIconUrl'
|
||||||
|
? String(item.cover || item.sourceUrl || '')
|
||||||
|
: String(item.sourceUrl || item.cover || '');
|
||||||
|
target.row[target.field] = value;
|
||||||
|
} else {
|
||||||
|
target.row.rewardItemId = item.id;
|
||||||
|
target.row.rewardName = item.name || String(item.id || '');
|
||||||
|
target.row.rewardCover = item.cover || item.sourceUrl || '';
|
||||||
|
}
|
||||||
|
resourcePickerOpen.value = false;
|
||||||
|
resourcePickerTarget.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resourceUrlName(url: string) {
|
||||||
|
const text = String(url || '').trim();
|
||||||
|
if (!text) {
|
||||||
|
return '未选择';
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
async function loadConfig() {
|
async function loadConfig() {
|
||||||
if (!selectedSysOrigin.value) {
|
if (!selectedSysOrigin.value) {
|
||||||
return;
|
return;
|
||||||
@ -361,7 +507,6 @@ async function saveLevels() {
|
|||||||
id: row.id,
|
id: row.id,
|
||||||
level: row.level,
|
level: row.level,
|
||||||
needEnergy: toNumber(row.needEnergy, row.level * 100),
|
needEnergy: toNumber(row.needEnergy, row.level * 100),
|
||||||
progressBarUrl: row.progressBarUrl,
|
|
||||||
rocketAnimationUrl: row.rocketAnimationUrl,
|
rocketAnimationUrl: row.rocketAnimationUrl,
|
||||||
rocketIconUrl: row.rocketIconUrl,
|
rocketIconUrl: row.rocketIconUrl,
|
||||||
shakeThresholdPercent: row.shakeThresholdPercent,
|
shakeThresholdPercent: row.shakeThresholdPercent,
|
||||||
@ -376,18 +521,19 @@ async function saveLevels() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRewardRow(scene = 'TOP1') {
|
function addRewardRow(scene = 'TOP1', rewardType = 'GOLD') {
|
||||||
|
const isNone = rewardType === 'NONE';
|
||||||
rewardRows.value.push({
|
rewardRows.value.push({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
expireDays: null,
|
expireDays: null,
|
||||||
level: rewardLevel.value,
|
level: rewardLevel.value,
|
||||||
localKey: `new-${Date.now()}-${rewardRows.value.length}`,
|
localKey: `new-${Date.now()}-${rewardRows.value.length}`,
|
||||||
rewardAmount: 1,
|
rewardAmount: isNone ? 0 : 1,
|
||||||
rewardCover: '',
|
rewardCover: '',
|
||||||
rewardItemId: null,
|
rewardItemId: null,
|
||||||
rewardName: scene === 'TOP1' ? '金币' : '',
|
rewardName: isNone ? '轮空' : rewardType === 'GOLD' ? '金币' : '',
|
||||||
rewardScene: scene,
|
rewardScene: scene,
|
||||||
rewardType: 'GOLD',
|
rewardType,
|
||||||
sort: rewardRows.value.length + 1,
|
sort: rewardRows.value.length + 1,
|
||||||
weight: 1,
|
weight: 1,
|
||||||
});
|
});
|
||||||
@ -398,12 +544,30 @@ function removeRewardRow(index: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleRewardTypeChange(row: Record<string, any>) {
|
function handleRewardTypeChange(row: Record<string, any>) {
|
||||||
|
if (row.rewardType === 'NONE') {
|
||||||
|
if (row.rewardScene !== 'IN_ROOM') {
|
||||||
|
row.rewardScene = 'IN_ROOM';
|
||||||
|
}
|
||||||
|
row.rewardItemId = null;
|
||||||
|
row.rewardCover = '';
|
||||||
|
row.expireDays = null;
|
||||||
|
row.rewardAmount = 0;
|
||||||
|
row.rewardName = '轮空';
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (row.rewardType === 'GOLD') {
|
if (row.rewardType === 'GOLD') {
|
||||||
row.rewardItemId = null;
|
row.rewardItemId = null;
|
||||||
|
row.rewardCover = '';
|
||||||
row.expireDays = null;
|
row.expireDays = null;
|
||||||
if (!row.rewardName) {
|
if (!row.rewardName) {
|
||||||
row.rewardName = '金币';
|
row.rewardName = '金币';
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row.rewardItemId = null;
|
||||||
|
row.rewardCover = '';
|
||||||
|
if (row.rewardName === '金币' || row.rewardName === '轮空') {
|
||||||
|
row.rewardName = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,12 +581,20 @@ function validateRewards() {
|
|||||||
message.warning('请选择奖励类型');
|
message.warning('请选择奖励类型');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (row.rewardType === 'NONE' && row.rewardScene !== 'IN_ROOM') {
|
||||||
|
message.warning('轮空只能配置在房用户奖励');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!String(row.rewardName || '').trim()) {
|
if (!String(row.rewardName || '').trim()) {
|
||||||
message.warning('请输入奖励名称');
|
message.warning('请输入奖励名称');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (row.rewardType !== 'GOLD' && !String(row.rewardItemId || '').trim()) {
|
if (
|
||||||
message.warning('非金币奖励必须填写资源ID');
|
row.rewardType !== 'GOLD' &&
|
||||||
|
row.rewardType !== 'NONE' &&
|
||||||
|
!String(row.rewardItemId || '').trim()
|
||||||
|
) {
|
||||||
|
message.warning('非金币奖励必须选择资源');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,14 +611,20 @@ async function saveRewards() {
|
|||||||
level: rewardLevel.value,
|
level: rewardLevel.value,
|
||||||
rewards: rewardRows.value.map((row) => ({
|
rewards: rewardRows.value.map((row) => ({
|
||||||
enabled: row.enabled,
|
enabled: row.enabled,
|
||||||
expireDays: toOptionalNumber(row.expireDays),
|
expireDays:
|
||||||
|
row.rewardType === 'GOLD' || row.rewardType === 'NONE'
|
||||||
|
? undefined
|
||||||
|
: toOptionalNumber(row.expireDays),
|
||||||
id: row.id,
|
id: row.id,
|
||||||
level: rewardLevel.value,
|
level: rewardLevel.value,
|
||||||
rewardAmount: toNumber(row.rewardAmount, 1),
|
rewardAmount:
|
||||||
rewardCover: row.rewardCover,
|
row.rewardType === 'NONE' ? 0 : toNumber(row.rewardAmount, 1),
|
||||||
|
rewardCover: row.rewardType === 'NONE' ? '' : row.rewardCover,
|
||||||
rewardItemId:
|
rewardItemId:
|
||||||
row.rewardType === 'GOLD' ? undefined : toOptionalString(row.rewardItemId),
|
row.rewardType === 'GOLD' || row.rewardType === 'NONE'
|
||||||
rewardName: row.rewardName.trim(),
|
? undefined
|
||||||
|
: toOptionalString(row.rewardItemId),
|
||||||
|
rewardName: row.rewardType === 'NONE' ? '轮空' : row.rewardName.trim(),
|
||||||
rewardScene: row.rewardScene,
|
rewardScene: row.rewardScene,
|
||||||
rewardType: row.rewardType,
|
rewardType: row.rewardType,
|
||||||
sort: toNumber(row.sort, 1),
|
sort: toNumber(row.sort, 1),
|
||||||
@ -605,7 +783,7 @@ watch(rewardLevel, () => {
|
|||||||
:data-source="levelRows"
|
:data-source="levelRows"
|
||||||
:loading="levelLoading"
|
:loading="levelLoading"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
:scroll="{ x: 1420 }"
|
:scroll="{ x: 1240 }"
|
||||||
row-key="level"
|
row-key="level"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
@ -620,24 +798,70 @@ watch(rewardLevel, () => {
|
|||||||
class="table-number"
|
class="table-number"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="column.key === 'rocketIconUrl'">
|
||||||
|
<div class="resource-cell">
|
||||||
|
<div class="resource-cell__preview">
|
||||||
|
<img
|
||||||
|
v-if="record.rocketIconUrl"
|
||||||
|
:src="record.rocketIconUrl"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<span>{{ resourceUrlName(record.rocketIconUrl) }}</span>
|
||||||
|
</div>
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="openLevelResourcePicker(record, 'rocketIconUrl')"
|
||||||
|
>
|
||||||
|
{{ record.rocketIconUrl ? '更换资源' : '选择资源' }}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
v-if="record.rocketIconUrl"
|
||||||
|
size="small"
|
||||||
|
@click="clearLevelResource(record, 'rocketIconUrl')"
|
||||||
|
>
|
||||||
|
清除
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'rocketAnimationUrl'">
|
||||||
|
<div class="resource-cell">
|
||||||
|
<div class="resource-cell__preview">
|
||||||
|
<img
|
||||||
|
v-if="record.rocketAnimationUrl"
|
||||||
|
:src="record.rocketAnimationUrl"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<span>{{ resourceUrlName(record.rocketAnimationUrl) }}</span>
|
||||||
|
</div>
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="
|
||||||
|
openLevelResourcePicker(record, 'rocketAnimationUrl')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ record.rocketAnimationUrl ? '更换资源' : '选择资源' }}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
v-if="record.rocketAnimationUrl"
|
||||||
|
size="small"
|
||||||
|
@click="clearLevelResource(record, 'rocketAnimationUrl')"
|
||||||
|
>
|
||||||
|
清除
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template v-else-if="column.key === 'shakeThresholdPercent'">
|
<template v-else-if="column.key === 'shakeThresholdPercent'">
|
||||||
<Input
|
<Input
|
||||||
v-model:value="record.shakeThresholdPercent"
|
v-model:value="record.shakeThresholdPercent"
|
||||||
class="table-input"
|
class="table-input"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'rocketIconUrl'">
|
|
||||||
<Input v-model:value="record.rocketIconUrl" class="table-input" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="column.key === 'rocketAnimationUrl'">
|
|
||||||
<Input
|
|
||||||
v-model:value="record.rocketAnimationUrl"
|
|
||||||
class="table-input"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="column.key === 'progressBarUrl'">
|
|
||||||
<Input v-model:value="record.progressBarUrl" class="table-input" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="column.key === 'enabled'">
|
<template v-else-if="column.key === 'enabled'">
|
||||||
<Switch v-model:checked="record.enabled" />
|
<Switch v-model:checked="record.enabled" />
|
||||||
</template>
|
</template>
|
||||||
@ -676,6 +900,7 @@ watch(rewardLevel, () => {
|
|||||||
<Button @click="addRewardRow('TOP1')">添加贡献第一</Button>
|
<Button @click="addRewardRow('TOP1')">添加贡献第一</Button>
|
||||||
<Button @click="addRewardRow('IGNITE')">添加点火人</Button>
|
<Button @click="addRewardRow('IGNITE')">添加点火人</Button>
|
||||||
<Button @click="addRewardRow('IN_ROOM')">添加在房用户</Button>
|
<Button @click="addRewardRow('IN_ROOM')">添加在房用户</Button>
|
||||||
|
<Button @click="addRewardRow('IN_ROOM', 'NONE')">添加在房轮空</Button>
|
||||||
<Button type="primary" :loading="rewardSaving" @click="saveRewards">
|
<Button type="primary" :loading="rewardSaving" @click="saveRewards">
|
||||||
保存当前等级奖励
|
保存当前等级奖励
|
||||||
</Button>
|
</Button>
|
||||||
@ -695,33 +920,67 @@ watch(rewardLevel, () => {
|
|||||||
v-model:value="record.rewardScene"
|
v-model:value="record.rewardScene"
|
||||||
:options="sceneOptions"
|
:options="sceneOptions"
|
||||||
class="table-select"
|
class="table-select"
|
||||||
|
@change="() => handleRewardSceneChange(record)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'rewardType'">
|
<template v-else-if="column.key === 'rewardType'">
|
||||||
<Select
|
<Select
|
||||||
v-model:value="record.rewardType"
|
v-model:value="record.rewardType"
|
||||||
:options="rewardTypeOptions"
|
:options="rewardTypeOptionsForRow(record)"
|
||||||
class="table-select"
|
class="table-select"
|
||||||
@change="() => handleRewardTypeChange(record)"
|
@change="() => handleRewardTypeChange(record)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'rewardItemId'">
|
<template v-else-if="column.key === 'rewardItemId'">
|
||||||
|
<div class="resource-cell">
|
||||||
|
<div class="resource-cell__summary">
|
||||||
|
<span v-if="isRewardResourceDisabled(record)">-</span>
|
||||||
|
<span v-else-if="record.rewardItemId">
|
||||||
|
{{ record.rewardName || '已选资源' }} / ID:
|
||||||
|
{{ record.rewardItemId }}
|
||||||
|
</span>
|
||||||
|
<span v-else>未选择</span>
|
||||||
|
</div>
|
||||||
|
<Space v-if="!isRewardResourceDisabled(record)">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="openRewardResourcePicker(record)"
|
||||||
|
>
|
||||||
|
{{ record.rewardItemId ? '更换资源' : '选择资源' }}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
v-if="record.rewardItemId"
|
||||||
|
size="small"
|
||||||
|
@click="clearRewardResource(record)"
|
||||||
|
>
|
||||||
|
清除
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'rewardName'">
|
||||||
<Input
|
<Input
|
||||||
v-model:value="record.rewardItemId"
|
v-model:value="record.rewardName"
|
||||||
:disabled="record.rewardType === 'GOLD'"
|
:disabled="record.rewardType === 'NONE'"
|
||||||
class="table-input-small"
|
class="table-input-small"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'rewardName'">
|
|
||||||
<Input v-model:value="record.rewardName" class="table-input-small" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="column.key === 'rewardCover'">
|
<template v-else-if="column.key === 'rewardCover'">
|
||||||
<Input v-model:value="record.rewardCover" class="table-input" />
|
<div class="cover-preview">
|
||||||
|
<img
|
||||||
|
v-if="record.rewardCover"
|
||||||
|
:src="record.rewardCover"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<span>{{ record.rewardCover || '-' }}</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'rewardAmount'">
|
<template v-else-if="column.key === 'rewardAmount'">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="record.rewardAmount"
|
v-model:value="record.rewardAmount"
|
||||||
:min="1"
|
:disabled="record.rewardType === 'NONE'"
|
||||||
|
:min="record.rewardType === 'NONE' ? 0 : 1"
|
||||||
:precision="0"
|
:precision="0"
|
||||||
class="table-number"
|
class="table-number"
|
||||||
/>
|
/>
|
||||||
@ -729,7 +988,9 @@ watch(rewardLevel, () => {
|
|||||||
<template v-else-if="column.key === 'expireDays'">
|
<template v-else-if="column.key === 'expireDays'">
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="record.expireDays"
|
v-model:value="record.expireDays"
|
||||||
:disabled="record.rewardType === 'GOLD'"
|
:disabled="
|
||||||
|
record.rewardType === 'GOLD' || record.rewardType === 'NONE'
|
||||||
|
"
|
||||||
:min="0"
|
:min="0"
|
||||||
:precision="0"
|
:precision="0"
|
||||||
class="table-number"
|
class="table-number"
|
||||||
@ -777,6 +1038,16 @@ watch(rewardLevel, () => {
|
|||||||
</Card>
|
</Card>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
|
<ResourceSelectDrawer
|
||||||
|
:default-type="resourcePickerDefaultType"
|
||||||
|
:fixed-type="resourcePickerFixedType"
|
||||||
|
:open="resourcePickerOpen"
|
||||||
|
:sys-origin="selectedSysOrigin"
|
||||||
|
:title="resourcePickerTitle"
|
||||||
|
@close="resourcePickerOpen = false"
|
||||||
|
@select="handleResourceSelect"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
@ -843,4 +1114,60 @@ watch(rewardLevel, () => {
|
|||||||
.table-number {
|
.table-number {
|
||||||
width: 110px;
|
width: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resource-cell {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
min-width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-cell__preview {
|
||||||
|
align-items: center;
|
||||||
|
color: #6b7280;
|
||||||
|
display: flex;
|
||||||
|
font-size: 12px;
|
||||||
|
gap: 8px;
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-cell__preview img {
|
||||||
|
border-radius: 4px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
height: 32px;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-cell__preview span,
|
||||||
|
.resource-cell__summary {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 12px;
|
||||||
|
max-width: 220px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-preview {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 220px;
|
||||||
|
gap: 8px;
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-preview img {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 4px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-preview span {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
1158
apps/src/views/resident-activity/wheel-config.vue
Normal file
1158
apps/src/views/resident-activity/wheel-config.vue
Normal file
File diff suppressed because it is too large
Load Diff
1
var/chatapp3-admin-dev.pid
Normal file
1
var/chatapp3-admin-dev.pid
Normal file
@ -0,0 +1 @@
|
|||||||
|
4934
|
||||||
Loading…
x
Reference in New Issue
Block a user