You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
7.3 KiB
191 lines
7.3 KiB
|
3 weeks ago
|
|
||
|
|
//*********************
|
||
|
|
// create by 流云
|
||
|
|
// time: Sat Aug 15 2026
|
||
|
|
// desc: 每日商店槽位已满 — 选择替换
|
||
|
|
//*********************
|
||
|
|
import { _decorator, EventTouch, instantiate, Label, Layout, Node, v3 } from 'cc';
|
||
|
|
import { Auto_PopReplaceSkill } from './Auto_PopReplaceSkill';
|
||
|
|
import { DailyShopDataManager } from '../../manager/DailyShopDataManager';
|
||
|
|
import { DailyShopParsed, DailyShopSlotEntry } from '../../manager/DailyShopTypes';
|
||
|
|
import { DailyShopLotteryIcon } from '../PopDailyShopLottery/DailyShopLotteryIcon';
|
||
|
|
const { ccclass } = _decorator;
|
||
|
|
|
||
|
|
export type PopReplaceSkillParam = {
|
||
|
|
goodsId: number;
|
||
|
|
/** 确认替换:传入选中要卸下的携带 id,购买逻辑由调用方处理 */
|
||
|
|
onConfirm?: (replaceOwnedId: number) => void;
|
||
|
|
/** 放弃替换:清除待替换订单并刷新界面 */
|
||
|
|
onCancel?: () => void;
|
||
|
|
};
|
||
|
|
|
||
|
|
@ccclass('UIPopReplaceSkill')
|
||
|
|
export class UIPopReplaceSkill extends Auto_PopReplaceSkill {
|
||
|
|
|
||
|
|
/** 列表项选中时 quality / icon 相对预制缩放的倍率 */
|
||
|
|
private static readonly ITEM_SELECT_SCALE = 1.1;
|
||
|
|
|
||
|
|
private _goodsId = 0;
|
||
|
|
private _newGoods: DailyShopParsed | null = null;
|
||
|
|
private _entries: DailyShopSlotEntry[] = [];
|
||
|
|
private _selectedIndex = 0;
|
||
|
|
private _listNodes: Node[] = [];
|
||
|
|
private _onConfirm: ((replaceOwnedId: number) => void) | null = null;
|
||
|
|
private _onCancel: (() => void) | null = null;
|
||
|
|
|
||
|
|
onLoad(): void {
|
||
|
|
super.onLoad();
|
||
|
|
if (this.ui_item?.isValid) this.ui_item.active = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
onInit(): void {
|
||
|
|
const p = (this.prema ?? {}) as PopReplaceSkillParam;
|
||
|
|
this._goodsId = Number(p.goodsId) || 0;
|
||
|
|
this._onConfirm = typeof p.onConfirm === 'function' ? p.onConfirm : null;
|
||
|
|
this._onCancel = typeof p.onCancel === 'function' ? p.onCancel : null;
|
||
|
|
this._selectedIndex = 0;
|
||
|
|
this._listNodes = [];
|
||
|
|
|
||
|
|
this._newGoods = DailyShopDataManager.getParsed(this._goodsId);
|
||
|
|
if (!this._newGoods) {
|
||
|
|
this.close(2);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this._entries = DailyShopDataManager.getOccupiedSlotEntries(this._newGoods.kind);
|
||
|
|
if (this._entries.length <= 0) {
|
||
|
|
this.close(2);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this.ui_getQuality?.isValid) {
|
||
|
|
this._bindNewGoods(this.ui_getQuality, this._newGoods);
|
||
|
|
}
|
||
|
|
this._renderList();
|
||
|
|
this._refreshSelectedDesc();
|
||
|
|
this.showOpenCenterEff();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 绑定待替换的新道具 ui_getQuality */
|
||
|
|
private _bindNewGoods(root: Node, parsed: DailyShopParsed): void {
|
||
|
|
DailyShopLotteryIcon.bindReplaceNewItem(root, parsed);
|
||
|
|
this._setNameLabel(root.getChildByName('name'), parsed);
|
||
|
|
this._setLabel(root.getChildByName('desc'), DailyShopLotteryIcon.battleBuffDesc(parsed));
|
||
|
|
}
|
||
|
|
|
||
|
|
private _renderList(): void {
|
||
|
|
if (!this.ui_content?.isValid || !this.ui_item?.isValid) return;
|
||
|
|
this.ui_content.removeAllChildren();
|
||
|
|
this._listNodes = [];
|
||
|
|
for (let i = 0; i < this._entries.length; i++) {
|
||
|
|
const item = instantiate(this.ui_item);
|
||
|
|
item.active = true;
|
||
|
|
item.setPosition(v3(0, 0, 0));
|
||
|
|
item.parent = this.ui_content;
|
||
|
|
this._bindListItem(item, this._entries[i], i);
|
||
|
|
this._listNodes.push(item);
|
||
|
|
}
|
||
|
|
this.ui_content.getComponent(Layout)?.updateLayout();
|
||
|
|
}
|
||
|
|
|
||
|
|
private _bindListItem(item: Node, entry: DailyShopSlotEntry, listIndex: number): void {
|
||
|
|
const parsed = entry.parsed;
|
||
|
|
DailyShopLotteryIcon.bindReplaceListItem(item, parsed);
|
||
|
|
this._setNameLabel(item.getChildByName('name'), parsed);
|
||
|
|
this._cacheItemScaleBase(item);
|
||
|
|
this._updateItemSelect(item, listIndex === this._selectedIndex);
|
||
|
|
item['replaceListIndex'] = listIndex;
|
||
|
|
item.targetOff(Node.EventType.TOUCH_END);
|
||
|
|
item.on(Node.EventType.TOUCH_END, this._onClickListItem, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 缓存列表项 quality / icon 预制缩放,供选中态倍率计算 */
|
||
|
|
private _cacheItemScaleBase(item: Node): void {
|
||
|
|
const quality = item.getChildByName('quality');
|
||
|
|
const icon = item.getChildByName('icon') ?? quality?.getChildByName('icon');
|
||
|
|
item['replaceItemScaleBase'] = {
|
||
|
|
quality: quality?.isValid ? v3(quality.scale.x, quality.scale.y, quality.scale.z) : null,
|
||
|
|
icon: icon?.isValid ? v3(icon.scale.x, icon.scale.y, icon.scale.z) : null,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
private _updateItemSelect(item: Node, selected: boolean): void {
|
||
|
|
const select = item.getChildByName('select');
|
||
|
|
if (select?.isValid) select.active = selected;
|
||
|
|
const selectGou = item.getChildByName('selectGou');
|
||
|
|
if (selectGou?.isValid) selectGou.active = selected;
|
||
|
|
const mul = selected ? UIPopReplaceSkill.ITEM_SELECT_SCALE : 1;
|
||
|
|
this._setItemQualityIconScale(item, mul);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 仅缩放 quality / icon,其他节点保持不变 */
|
||
|
|
private _setItemQualityIconScale(item: Node, mul: number): void {
|
||
|
|
const base = item['replaceItemScaleBase'] as {
|
||
|
|
quality: { x: number; y: number; z: number } | null;
|
||
|
|
icon: { x: number; y: number; z: number } | null;
|
||
|
|
} | undefined;
|
||
|
|
const quality = item.getChildByName('quality');
|
||
|
|
if (quality?.isValid && base?.quality) {
|
||
|
|
quality.setScale(v3(base.quality.x * mul, base.quality.y * mul, base.quality.z));
|
||
|
|
}
|
||
|
|
const icon = item.getChildByName('icon') ?? quality?.getChildByName('icon');
|
||
|
|
if (icon?.isValid && base?.icon) {
|
||
|
|
icon.setScale(v3(base.icon.x * mul, base.icon.y * mul, base.icon.z));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private _refreshSelection(): void {
|
||
|
|
for (let i = 0; i < this._listNodes.length; i++) {
|
||
|
|
this._updateItemSelect(this._listNodes[i], i === this._selectedIndex);
|
||
|
|
}
|
||
|
|
this._refreshSelectedDesc();
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 面板 ui_desc 显示当前选中携带道具描述 */
|
||
|
|
private _refreshSelectedDesc(): void {
|
||
|
|
const entry = this._entries[this._selectedIndex];
|
||
|
|
const desc = entry ? DailyShopLotteryIcon.battleBuffDesc(entry.parsed) : '';
|
||
|
|
this._setLabel(this.ui_desc, desc);
|
||
|
|
}
|
||
|
|
|
||
|
|
private _setLabel(node: Node | null | undefined, text: string): void {
|
||
|
|
if (!node?.isValid) return;
|
||
|
|
const lb = node.getComponent(Label);
|
||
|
|
if (lb) lb.string = text;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 名称:文本 + 品质描边 */
|
||
|
|
private _setNameLabel(node: Node | null | undefined, parsed: DailyShopParsed): void {
|
||
|
|
if (!node?.isValid) return;
|
||
|
|
const lb = node.getComponent(Label);
|
||
|
|
if (!lb) return;
|
||
|
|
lb.string = parsed.name;
|
||
|
|
DailyShopLotteryIcon.applyNameOutline(lb, parsed.quality);
|
||
|
|
}
|
||
|
|
|
||
|
|
private _onClickListItem(event: EventTouch): void {
|
||
|
|
const item = event.currentTarget as Node;
|
||
|
|
const idx = Number(item?.['replaceListIndex']) || 0;
|
||
|
|
if (idx === this._selectedIndex) return;
|
||
|
|
this._selectedIndex = idx;
|
||
|
|
this._refreshSelection();
|
||
|
|
}
|
||
|
|
|
||
|
|
click_btnOkReplace(): void {
|
||
|
|
const entry = this._entries[this._selectedIndex];
|
||
|
|
if (!entry) return;
|
||
|
|
this._onConfirm?.(entry.id);
|
||
|
|
this.close(2);
|
||
|
|
}
|
||
|
|
|
||
|
|
click_btnCancelReplace(): void {
|
||
|
|
DailyShopDataManager.cancelPendingReplace();
|
||
|
|
this._onCancel?.();
|
||
|
|
this.close(2);
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 点击遮罩不关闭弹窗 */
|
||
|
|
click_bgMask(): void {
|
||
|
|
}
|
||
|
|
}
|