修改
This commit is contained in:
parent
0a8bddbea0
commit
2f9ae0a10e
@ -29,6 +29,12 @@ import {
|
|||||||
saveVoiceRoomRocketLevelConfigs,
|
saveVoiceRoomRocketLevelConfigs,
|
||||||
saveVoiceRoomRocketRewardConfigs,
|
saveVoiceRoomRocketRewardConfigs,
|
||||||
} from '#/api/legacy/resident-activity';
|
} from '#/api/legacy/resident-activity';
|
||||||
|
import { listBadgePictureBySysOrigin } from '#/api/legacy/badge';
|
||||||
|
import { listGiftBySysOrigin } from '#/api/legacy/gift';
|
||||||
|
import {
|
||||||
|
listNotFamilyBySysOriginType,
|
||||||
|
listSysOriginTypeList,
|
||||||
|
} from '#/api/legacy/props';
|
||||||
import { getAllowedSysOrigins } from '#/views/system/shared';
|
import { getAllowedSysOrigins } from '#/views/system/shared';
|
||||||
|
|
||||||
defineOptions({ name: 'ResidentVoiceRoomRocketPage' });
|
defineOptions({ name: 'ResidentVoiceRoomRocketPage' });
|
||||||
@ -41,7 +47,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 +69,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 || []);
|
||||||
@ -80,6 +95,12 @@ const rewardLoading = ref(false);
|
|||||||
const configSaving = ref(false);
|
const configSaving = ref(false);
|
||||||
const levelSaving = ref(false);
|
const levelSaving = ref(false);
|
||||||
const rewardSaving = ref(false);
|
const rewardSaving = ref(false);
|
||||||
|
const rocketResourceLoading = ref(false);
|
||||||
|
const rocketResourceRows = ref<ResourceOption[]>([]);
|
||||||
|
const rewardResourceLoading = reactive<Record<string, boolean>>({});
|
||||||
|
const rewardResourceRows = reactive<Record<string, ResourceOption[]>>({});
|
||||||
|
|
||||||
|
const ROCKET_RESOURCE_TYPE = 'CUSTOMIZE';
|
||||||
|
|
||||||
const configForm = reactive({
|
const configForm = reactive({
|
||||||
broadcastDurationSeconds: 7,
|
broadcastDurationSeconds: 7,
|
||||||
@ -113,6 +134,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 +144,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 +162,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 +177,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 +193,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 +277,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 +303,183 @@ function normalizeRewardRows(rows: Array<Record<string, any>> | undefined) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePropsResource(item: Record<string, any>, type: string): ResourceOption {
|
||||||
|
return {
|
||||||
|
amount: item.amount,
|
||||||
|
cover: String(item.cover || item.img || item.icon || ''),
|
||||||
|
id: item.id,
|
||||||
|
name: String(item.name || item.title || item.remark || item.id || ''),
|
||||||
|
remark: item.remark,
|
||||||
|
sourceUrl: String(item.sourceUrl || item.url || item.cover || ''),
|
||||||
|
type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeGiftResource(item: Record<string, any>): ResourceOption {
|
||||||
|
return {
|
||||||
|
amount: item.giftCandy,
|
||||||
|
cover: String(item.giftPhoto || ''),
|
||||||
|
id: item.id,
|
||||||
|
name: String(item.giftName || item.id || ''),
|
||||||
|
sourceUrl: String(item.giftSourceUrl || item.giftPhoto || ''),
|
||||||
|
type: 'GIFT',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeBadgeResource(item: Record<string, any>): ResourceOption {
|
||||||
|
return {
|
||||||
|
cover: String(item.selectUrl || item.cover || ''),
|
||||||
|
id: item.badgeConfigId || item.id,
|
||||||
|
name: String(item.badgeName || item.name || item.id || ''),
|
||||||
|
sourceUrl: String(item.animationUrl || item.selectUrl || item.cover || ''),
|
||||||
|
type: 'BADGE',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function optionLabel(item: ResourceOption) {
|
||||||
|
return `${item.id} / ${item.name}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toResourceSelectOptions(rows: ResourceOption[]) {
|
||||||
|
return rows
|
||||||
|
.filter((item) => item.id !== undefined && item.id !== null && item.id !== '')
|
||||||
|
.map((item) => ({
|
||||||
|
label: optionLabel(item),
|
||||||
|
value: String(item.id),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toRocketResourceSelectOptions(
|
||||||
|
record: Record<string, any>,
|
||||||
|
key: 'rocketAnimationUrl' | 'rocketIconUrl',
|
||||||
|
) {
|
||||||
|
const options = rocketResourceRows.value
|
||||||
|
.map((item) => {
|
||||||
|
const value =
|
||||||
|
key === 'rocketIconUrl'
|
||||||
|
? String(item.cover || item.sourceUrl || '')
|
||||||
|
: String(item.sourceUrl || item.cover || '');
|
||||||
|
return {
|
||||||
|
label: optionLabel(item),
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((item) => item.value);
|
||||||
|
const current = String(record[key] || '');
|
||||||
|
if (current && !options.some((item) => item.value === current)) {
|
||||||
|
options.unshift({ label: current, value: current });
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadRocketResources() {
|
||||||
|
if (!selectedSysOrigin.value || rocketResourceLoading.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rocketResourceLoading.value = true;
|
||||||
|
try {
|
||||||
|
const result = await listSysOriginTypeList(
|
||||||
|
selectedSysOrigin.value,
|
||||||
|
ROCKET_RESOURCE_TYPE,
|
||||||
|
);
|
||||||
|
rocketResourceRows.value = (result || []).map((item) =>
|
||||||
|
normalizePropsResource(item, ROCKET_RESOURCE_TYPE),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
rocketResourceLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 isRewardResourceDisabled(row: Record<string, any>) {
|
||||||
|
return row.rewardType === 'GOLD' || row.rewardType === 'NONE';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadRewardResources(rewardType: string) {
|
||||||
|
const type = String(rewardType || '').trim();
|
||||||
|
const sourceType = rewardResourceType(type);
|
||||||
|
if (
|
||||||
|
!selectedSysOrigin.value ||
|
||||||
|
!sourceType ||
|
||||||
|
(rewardResourceRows[type] || []).length > 0
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rewardResourceLoading[type] = true;
|
||||||
|
try {
|
||||||
|
if (type === 'GIFT') {
|
||||||
|
const result = await listGiftBySysOrigin(selectedSysOrigin.value);
|
||||||
|
rewardResourceRows[type] = (result || []).map(normalizeGiftResource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type === 'BADGE') {
|
||||||
|
const result = await listBadgePictureBySysOrigin(
|
||||||
|
selectedSysOrigin.value,
|
||||||
|
'ACTIVITY',
|
||||||
|
);
|
||||||
|
rewardResourceRows[type] = (result || []).map(normalizeBadgeResource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const loader =
|
||||||
|
type === 'VIP_CARD' ? listNotFamilyBySysOriginType : listSysOriginTypeList;
|
||||||
|
const result = await loader(selectedSysOrigin.value, sourceType);
|
||||||
|
rewardResourceRows[type] = (result || []).map((item) =>
|
||||||
|
normalizePropsResource(item, sourceType),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
rewardResourceLoading[type] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rewardResourceOptions(row: Record<string, any>) {
|
||||||
|
const rows = rewardResourceRows[row.rewardType] || [];
|
||||||
|
const options = toResourceSelectOptions(rows);
|
||||||
|
const current = String(row.rewardItemId || '').trim();
|
||||||
|
if (current && !options.some((item) => item.value === current)) {
|
||||||
|
options.unshift({
|
||||||
|
label: `${current} / ${row.rewardName || '已配置资源'}`,
|
||||||
|
value: current,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRewardSceneChange(row: Record<string, any>) {
|
||||||
|
if (row.rewardScene !== 'IN_ROOM' && row.rewardType === 'NONE') {
|
||||||
|
row.rewardType = 'GOLD';
|
||||||
|
handleRewardTypeChange(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRewardResourceChange(
|
||||||
|
row: Record<string, any>,
|
||||||
|
value?: null | number | string,
|
||||||
|
) {
|
||||||
|
const selected =
|
||||||
|
(rewardResourceRows[row.rewardType] || []).find(
|
||||||
|
(item) => String(item.id) === String(value),
|
||||||
|
) || null;
|
||||||
|
if (!selected) {
|
||||||
|
row.rewardItemId = value || null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row.rewardItemId = selected.id;
|
||||||
|
row.rewardName = selected.name;
|
||||||
|
row.rewardCover = selected.cover || selected.sourceUrl || '';
|
||||||
|
}
|
||||||
|
|
||||||
async function loadConfig() {
|
async function loadConfig() {
|
||||||
if (!selectedSysOrigin.value) {
|
if (!selectedSysOrigin.value) {
|
||||||
return;
|
return;
|
||||||
@ -316,7 +523,7 @@ async function loadRewards() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadAll() {
|
async function loadAll() {
|
||||||
await Promise.all([loadConfig(), loadLevels(), loadRewards()]);
|
await Promise.all([loadConfig(), loadLevels(), loadRewards(), loadRocketResources()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveConfig() {
|
async function saveConfig() {
|
||||||
@ -361,7 +568,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 +582,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,13 +605,32 @@ 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 = '';
|
||||||
|
}
|
||||||
|
void loadRewardResources(row.rewardType);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateRewards() {
|
function validateRewards() {
|
||||||
@ -417,12 +643,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 +673,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),
|
||||||
@ -474,6 +714,10 @@ watch(
|
|||||||
watch(
|
watch(
|
||||||
selectedSysOrigin,
|
selectedSysOrigin,
|
||||||
() => {
|
() => {
|
||||||
|
rocketResourceRows.value = [];
|
||||||
|
Object.keys(rewardResourceRows).forEach((key) => {
|
||||||
|
delete rewardResourceRows[key];
|
||||||
|
});
|
||||||
void loadAll();
|
void loadAll();
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
@ -605,7 +849,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 +864,38 @@ watch(rewardLevel, () => {
|
|||||||
class="table-number"
|
class="table-number"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="column.key === 'rocketIconUrl'">
|
||||||
|
<Select
|
||||||
|
v-model:value="record.rocketIconUrl"
|
||||||
|
:loading="rocketResourceLoading"
|
||||||
|
:options="toRocketResourceSelectOptions(record, 'rocketIconUrl')"
|
||||||
|
allow-clear
|
||||||
|
class="table-resource-select"
|
||||||
|
option-filter-prop="label"
|
||||||
|
show-search
|
||||||
|
@focus="loadRocketResources"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'rocketAnimationUrl'">
|
||||||
|
<Select
|
||||||
|
v-model:value="record.rocketAnimationUrl"
|
||||||
|
:loading="rocketResourceLoading"
|
||||||
|
:options="
|
||||||
|
toRocketResourceSelectOptions(record, 'rocketAnimationUrl')
|
||||||
|
"
|
||||||
|
allow-clear
|
||||||
|
class="table-resource-select"
|
||||||
|
option-filter-prop="label"
|
||||||
|
show-search
|
||||||
|
@focus="loadRocketResources"
|
||||||
|
/>
|
||||||
|
</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 +934,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 +954,53 @@ 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'">
|
||||||
<Input
|
<Select
|
||||||
v-model:value="record.rewardItemId"
|
v-model:value="record.rewardItemId"
|
||||||
:disabled="record.rewardType === 'GOLD'"
|
:disabled="isRewardResourceDisabled(record)"
|
||||||
class="table-input-small"
|
:loading="rewardResourceLoading[record.rewardType]"
|
||||||
|
:options="rewardResourceOptions(record)"
|
||||||
|
allow-clear
|
||||||
|
class="table-resource-select"
|
||||||
|
option-filter-prop="label"
|
||||||
|
show-search
|
||||||
|
@change="(value) => handleRewardResourceChange(record, value)"
|
||||||
|
@focus="() => loadRewardResources(record.rewardType)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.key === 'rewardName'">
|
<template v-else-if="column.key === 'rewardName'">
|
||||||
<Input v-model:value="record.rewardName" class="table-input-small" />
|
<Input
|
||||||
|
v-model:value="record.rewardName"
|
||||||
|
:disabled="record.rewardType === 'NONE'"
|
||||||
|
class="table-input-small"
|
||||||
|
/>
|
||||||
</template>
|
</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 +1008,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"
|
||||||
@ -840,7 +1121,34 @@ watch(rewardLevel, () => {
|
|||||||
width: 140px;
|
width: 140px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-resource-select {
|
||||||
|
width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
.table-number {
|
.table-number {
|
||||||
width: 110px;
|
width: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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>
|
||||||
|
|||||||
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