using Assets.Framework.Tool;
using Assets.MyGame.Scripts.Net;
using Assets.MyGame.Scripts.Net.API.GameConfig_SubClass;
using Assets.MyGame.Scripts.Net.APIRequest.Objs;
using Assets.MyGame.Scripts.Net.APIRequest.Params;
using Assets.MyGame.Scripts.Net.APIResponses;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class ZhanLing_Panel : SubUIBase
{
public Toggle toggle_MoRenShowZhnaLingJiangLi;
[Header("战令等级奖励页面")]
public TextMeshProUGUI tmp_Level;
public TextMeshProUGUI tmp_Exp;
public Slider slider_LevelExp;
public LevelGiftitem levelGiftitemPrefab;
public Transform levelGiftitemParent;
public LevelGiftitem levelGiftitem_100;
public Button btn_GetAllGift;
public Button btn_BuyJinJieZhanLing;
public TextMeshProUGUI btn_BuyZhanLing_Label;
public TextMeshProUGUI tmp_ActiveTime; //战令刷新时间 30天10:01:50
[Header("任务页面")]
public RenWuItem renWuItemPrefab;
public Transform renWuItemParent;
[Header("购买等级礼包页面")]
public BackPackPropItem buyLevelGiftitemPrefab;
public Transform buyLevelGiftitemMianFeiParent;
public Transform buyLevelGiftitemJingYingParent;
public Transform buyLevelGiftitemZhiZunParent;
public Slider slider_BuyLevelExpCount;
public Button btn_Buy;
public TextMeshProUGUI tmp_PriceNum;
public TextMeshProUGUI tmp_BuyLabel; //购买 99999 点经验值升至 100 级
public Button btn_Up;
public Button btn_Down;
[Header("活动切换项")]
public GameObject huoDongToggleItemPrefab;
public Transform huoDongToggleItemParent;
[Header("购买进阶战令页面")]
public Button btn_JinJie;
public Button btn_ZhiZun;
public Button btn_ZhiZunAndJinJie;
private BattleOrderConfigInfo _config;
private UserBattleOrderInfo _userData;
private int _selectedBuyLevel;
private List _buyLevelConfigs; // 含 payType/payCount
private List _advanceGiftConfigs; // 含 giftList
public Toggle toggle_HD;
public Toggle toggle_GG;
// ==================== 生命周期 ====================
public override void Awake()
{
base.Awake();
btn_CloseGG.onClick.AddListener(() => uIManager.Hide(this));
}
protected override void OnShow(object args = null)
{
base.OnShow(args);
RefreshAll();
LoadNoticeList();
switch (PanelType)
{
case UIPanel.ActivityPenel:
toggle_HD.isOn = true;
toggle_MoRenShowZhnaLingJiangLi.isOn = true;
break;
case UIPanel.AnnouncementPanel:
toggle_GG.isOn = true;
break;
}
}
private void RefreshAll()
{
APIRequestList.GetBattleOrder(res =>
{
if (res == null || !res.isOpen) return;
_config = res.config;
_userData = res.userBattleOrder;
RefreshLevelPage();
RefreshTasksPage();
RefreshBuyPage();
RefreshBtnLabels();
});
APIRequestList.GetBattleOrderConfig(cfg =>
{
if (cfg != null)
{
_buyLevelConfigs = cfg.levelConfig;
_advanceGiftConfigs = cfg.advanceGift;
}
});
}
// ==================== 等级奖励页面 ====================
private int _maxLevel = 100;
private void RefreshLevelPage()
{
if (_config?.levelConfig == null || _userData == null) return;
int level = _userData.level;
long exp = _userData.exp;
var lvCfg = _config.levelConfig.Find(c => c.level == level);
long expNeeded = lvCfg?.exp ?? 100L;
tmp_Level.text = $"Lv.{level}";
tmp_Exp.text = $"{exp}/{expNeeded}";
slider_LevelExp.maxValue = expNeeded;
slider_LevelExp.value = Mathf.Clamp(exp, 0, expNeeded);
// 战令剩余时间
RefreshActiveTime();
// 清空旧列表
for (int i = levelGiftitemParent.childCount - 1; i >= 0; i--)
Destroy(levelGiftitemParent.GetChild(i).gameObject);
// 已领取的等级集合
var claimedSet = _userData.receivedLevels != null
? new HashSet(_userData.receivedLevels)
: new HashSet();
// 构建等级礼包列表(1-99级显示礼包内容,100级占位)
foreach (var lv in _config.levelConfig)
{
if (lv.level > _maxLevel) continue;
if (lv.level == _maxLevel)
{
// 100级占位:创建一个空对象保持布局对齐
var placeholder = new GameObject("Placeholder_Lv100", typeof(RectTransform));
placeholder.transform.SetParent(levelGiftitemParent, false);
var rt = placeholder.GetComponent();
var prefabRt = levelGiftitemPrefab.GetComponent();
if (rt != null && prefabRt != null)
{
rt.sizeDelta = prefabRt.sizeDelta;
rt.anchorMin = prefabRt.anchorMin;
rt.anchorMax = prefabRt.anchorMax;
rt.pivot = prefabRt.pivot;
}
// 如果 prefab 有 LayoutElement,也复制
var prefabLE = levelGiftitemPrefab.GetComponent();
if (prefabLE != null)
{
var le = placeholder.AddComponent();
le.preferredWidth = prefabLE.preferredWidth;
le.preferredHeight = prefabLE.preferredHeight;
le.minWidth = prefabLE.minWidth;
le.minHeight = prefabLE.minHeight;
}
continue;
}
var item = Instantiate(levelGiftitemPrefab, levelGiftitemParent);
item.gameObject.SetActive(true);
bool isClaimed = claimedSet.Contains(lv.level);
var nf = FirstGift(lv.normalGiftList);
var lx = FirstGift(lv.luxuryGiftList);
var sz = FirstGift(lv.supremeGiftList);
LevelGiftType giftType = 0;
if (nf != null) giftType |= LevelGiftType.MianFei;
if (lx != null && _userData.isLuxury) giftType |= LevelGiftType.JingYing;
if (sz != null && _userData.isSupreme) giftType |= LevelGiftType.ZhiZun;
item.Init(
ResolveGiftImageUrl(nf), nf?.count ?? 0,
ResolveGiftImageUrl(lx), lx?.count ?? 0,
ResolveGiftImageUrl(sz), sz?.count ?? 0,
lv.level, giftType, isClaimed,
nf?.type ?? 0, lx?.type ?? 0, sz?.type ?? 0);
}
// 100级礼包
var lv100 = _config.levelConfig.Find(c => c.level == _maxLevel);
if (lv100 != null && levelGiftitem_100 != null)
{
bool isClaimed = claimedSet.Contains(_maxLevel);
var nf100 = FirstGift(lv100.normalGiftList);
var lx100 = FirstGift(lv100.luxuryGiftList);
var sz100 = FirstGift(lv100.supremeGiftList);
LevelGiftType giftType100 = LevelGiftType.MianFei;
if (lx100 != null && _userData.isLuxury) giftType100 |= LevelGiftType.JingYing;
if (sz100 != null && _userData.isSupreme) giftType100 |= LevelGiftType.ZhiZun;
levelGiftitem_100.Init(
ResolveGiftImageUrl(nf100), nf100?.count ?? 0,
ResolveGiftImageUrl(lx100), lx100?.count ?? 0,
ResolveGiftImageUrl(sz100), sz100?.count ?? 0,
_maxLevel, giftType100, isClaimed,
nf100?.type ?? 0, lx100?.type ?? 0, sz100?.type ?? 0);
levelGiftitem_100.gameObject.SetActive(true);
}
}
// ==================== 任务页面 ====================
private void RefreshTasksPage()
{
if (renWuItemPrefab == null || renWuItemParent == null) return;
for (int i = renWuItemParent.childCount - 1; i >= 0; i--)
Destroy(renWuItemParent.GetChild(i).gameObject);
APIRequestList.GetUserTaskList(tasks =>
{
if (tasks == null) return;
foreach (var t in tasks)
{
int curr = (int)t.count;
float progress = t.taskCount > 0 ? (float)t.count / t.taskCount : 0f;
CreateTaskItem(t.exp, curr, t.taskCount, t.remark, progress,
t.id, t.isFinish, t.isGet, UIPanel.None);
}
});
}
private void CreateTaskItem(long expCount, int currJinDu, int maxJinDu, string label,
float progress, string taskId, bool isFinish, bool isGet, UIPanel targetPanel)
{
var item = Instantiate(renWuItemPrefab, renWuItemParent);
item.gameObject.SetActive(true);
item.Init(expCount, currJinDu, maxJinDu, label, progress,
taskId, isFinish, isGet, targetPanel, uIManager, RefreshAll);
}
// ==================== 购买等级页面 ====================
private void RefreshBuyPage()
{
if (_config?.levelConfig == null) return;
slider_BuyLevelExpCount.minValue = 1;
slider_BuyLevelExpCount.maxValue = _maxLevel;
slider_BuyLevelExpCount.value = _userData.level;
slider_BuyLevelExpCount.wholeNumbers = true;
slider_BuyLevelExpCount.onValueChanged.RemoveAllListeners();
slider_BuyLevelExpCount.onValueChanged.AddListener(OnBuyLevelSliderChanged);
if (btn_Up != null)
{
btn_Up.onClick.RemoveAllListeners();
btn_Up.onClick.AddListener(OnBuyLevelUp);
}
if (btn_Down != null)
{
btn_Down.onClick.RemoveAllListeners();
btn_Down.onClick.AddListener(OnBuyLevelDown);
}
_selectedBuyLevel = _userData.level;
UpdateBuyLevelGifts(_selectedBuyLevel);
UpdateBuyPrice();
}
private void OnBuyLevelSliderChanged(float value)
{
_selectedBuyLevel = Mathf.RoundToInt(value);
UpdateBuyLevelGifts(_selectedBuyLevel);
UpdateBuyPrice();
}
/// 购买等级 +1(受 maxLevel 限制)
private void OnBuyLevelUp()
{
if (slider_BuyLevelExpCount == null) return;
int target = Mathf.Min(_selectedBuyLevel + 1, _maxLevel);
if (target == _selectedBuyLevel) return;
slider_BuyLevelExpCount.value = target; // 触发 OnBuyLevelSliderChanged
}
/// 购买等级 -1(不低于当前等级)
private void OnBuyLevelDown()
{
if (slider_BuyLevelExpCount == null) return;
int minLevel = Mathf.Max(1, _userData.level);
int target = Mathf.Max(_selectedBuyLevel - 1, minLevel);
if (target == _selectedBuyLevel) return;
slider_BuyLevelExpCount.value = target; // 触发 OnBuyLevelSliderChanged
}
private void UpdateBuyLevelGifts(int targetLevel)
{
ClearBuyGiftParent(buyLevelGiftitemMianFeiParent);
ClearBuyGiftParent(buyLevelGiftitemJingYingParent);
ClearBuyGiftParent(buyLevelGiftitemZhiZunParent);
// 从当前等级+1到目标等级,累加所有礼包并合并相同奖励(数量累加)
var mergedNormal = MergeGifts(_config?.levelConfig, _userData.level + 1, targetLevel, c => c.normalGiftList);
var mergedLuxury = MergeGifts(_config?.levelConfig, _userData.level + 1, targetLevel, c => c.luxuryGiftList);
var mergedSupreme = MergeGifts(_config?.levelConfig, _userData.level + 1, targetLevel, c => c.supremeGiftList);
AddBuyGiftList(buyLevelGiftitemMianFeiParent, mergedNormal);
AddBuyGiftList(buyLevelGiftitemJingYingParent, mergedLuxury);
AddBuyGiftList(buyLevelGiftitemZhiZunParent, mergedSupreme);
}
private void ClearBuyGiftParent(Transform parent)
{
if (parent == null) return;
for (int i = parent.childCount - 1; i >= 0; i--)
Destroy(parent.GetChild(i).gameObject);
}
///
/// 把指定等级范围内每一级的同种礼包合并:相同奖励(giftType 相同,
/// 道具再按 otherId 区分)数量累加,返回合并后的列表。
///
private List MergeGifts(List levelConfig, int fromLevel, int toLevel,
System.Func> selector)
{
var result = new List();
if (levelConfig == null) return result;
// 合并键:金币="1",钻石="2",道具="3:otherId"
foreach (var cfg in levelConfig)
{
if (cfg.level < fromLevel || cfg.level > toLevel) continue;
var gifts = selector(cfg);
if (gifts == null) continue;
foreach (var gift in gifts)
{
if (gift == null) continue;
string key = gift.type == 3 ? $"3:{gift.otherId}" : gift.type.ToString();
int idx = result.FindIndex(g =>
(g.type == 3 ? $"3:{g.otherId}" : g.type.ToString()) == key);
if (idx >= 0)
{
// 已存在同种奖励,数量累加(随机取值用 minCount 之和)
if (gift.isRandom)
result[idx].minCount += gift.minCount;
else
result[idx].count += gift.count;
}
else
{
// 克隆一份避免修改原始配置
var copy = new GiftConfig
{
type = gift.type,
otherId = gift.otherId,
isRandom = gift.isRandom,
count = gift.count,
minCount = gift.minCount,
maxCount = gift.maxCount
};
result.Add(copy);
}
}
}
return result;
}
private void AddBuyGiftList(Transform parent, List gifts)
{
if (parent == null || gifts == null) return;
foreach (var gift in gifts)
{
var obj = Instantiate(buyLevelGiftitemPrefab, parent);
int count = gift.isRandom ? gift.minCount : gift.count;
var data = new BackPackPropItemData { count = count, giftType = gift.type };
// 道具(type==3)才需要查道具表拿图标与子类型;金币/钻石用本地 sprite
if (gift.type == 3)
{
string imageUrl = ResolveGiftImageUrl(gift);
if (!string.IsNullOrEmpty(imageUrl))
data.url = APIManager.baseURL + imageUrl;
data.propEnum = (PropEnum)ResolveGiftPropType(gift);
}
obj.Init(data);
}
}
private void UpdateBuyPrice()
{
int levelsToBuy = _selectedBuyLevel - _userData.level;
if (levelsToBuy <= 0)
{
tmp_PriceNum.text = "已达成";
if (tmp_BuyLabel != null) tmp_BuyLabel.text = "";
btn_Buy.interactable = false;
}
else
{
// 计算从当前等级到目标等级所需总经验和总花费
long totalExp = 0;
int totalCost = 0;
int costPayType = 2; // 默认钻石
if (_buyLevelConfigs != null)
{
for (int lv = _userData.level + 1; lv <= _selectedBuyLevel; lv++)
{
var cfg = _buyLevelConfigs.Find(c => c.level == lv);
if (cfg != null)
{
totalExp += cfg.exp;
totalCost += cfg.payCount;
if (cfg.payType > 0) costPayType = cfg.payType;
}
}
}
tmp_PriceNum.text = costPayType switch
{
1 => $"{totalCost}",
3 => $"¥{totalCost}",
_ => $"{totalCost}",
};
if (tmp_BuyLabel != null)
tmp_BuyLabel.text = $"购买 {totalExp} 点经验值升至 {_selectedBuyLevel} 级";
btn_Buy.interactable = true;
}
}
// ==================== 按钮事件 ====================
private void RefreshBtnLabels()
{
if (btn_BuyZhanLing_Label != null)
{
btn_BuyZhanLing_Label.text = (_userData.isLuxury || _userData.isSupreme) ? "已购买" : "购买战令";
}
btn_GetAllGift.onClick.RemoveAllListeners();
btn_GetAllGift.onClick.AddListener(() =>
{
APIRequestList.ReceiveAllBattleOrderRewards(res =>
{
if (_userData.receivedLevels == null)
_userData.receivedLevels = new List();
for (int lv = 1; lv <= _userData.level; lv++)
{
if (!_userData.receivedLevels.Contains(lv))
_userData.receivedLevels.Add(lv);
}
ShowHuoDe(res);
RefreshAll();
});
});
btn_Buy.onClick.RemoveAllListeners();
btn_Buy.onClick.AddListener(() =>
{
int levelsToBuy = _selectedBuyLevel - _userData.level;
if (levelsToBuy <= 0) return;
APIRequestList.BuyBattleOrderLevel(new BuyBattleOrderLevelParam { levelCount = levelsToBuy }, res =>
{
RefreshAll();
});
});
btn_JinJie.onClick.RemoveAllListeners();
btn_JinJie.onClick.AddListener(() => BuyAdvance(1));
btn_ZhiZun.onClick.RemoveAllListeners();
btn_ZhiZun.onClick.AddListener(() => BuyAdvance(2));
btn_ZhiZunAndJinJie.onClick.RemoveAllListeners();
btn_ZhiZunAndJinJie.onClick.AddListener(() => BuyAdvance(3));
// 三个按钮的 child(0) 显示购买价格
RefreshAdvanceBtnLabels();
}
private void RefreshAdvanceBtnLabels()
{
if (_config?.advanceGift == null) return;
var jinJie = _config.advanceGift.Find(a => a.type == 1);
var zhiZun = _config.advanceGift.Find(a => a.type == 2);
var all = _config.advanceGift.Find(a => a.type == 3);
SetBtnPrice(btn_JinJie, jinJie, _userData.isLuxury);
SetBtnPrice(btn_ZhiZun, zhiZun, _userData.isSupreme);
SetBtnPrice(btn_ZhiZunAndJinJie, all, _userData.isLuxury && _userData.isSupreme);
}
private void SetBtnPrice(Button btn, BattleOrderAdvanceInfo info, bool isBought)
{
if (btn == null || info == null) return;
// 已购买则显示"已购买",否则显示价格
if (isBought)
{
var label = btn.transform.childCount > 0
? btn.transform.GetChild(0).GetComponent()
: null;
if (label != null) label.text = "已购买";
}
else
{
SetBtnText(btn, info.payType, info.payCount);
}
}
private void SetBtnText(Button btn, int payType, int price)
{
if (btn == null) return;
var label = btn.transform.childCount > 0
? btn.transform.GetChild(0).GetComponent()
: null;
if (label == null) return;
label.text = payType switch
{
1 => $"{price}",
2 => $"{price}",
_ => $"¥{price}",
};
}
private void BuyAdvance(int type)
{
APIRequestList.BuyBattleOrderAdvance(new BuyBattleOrderAdvanceParam { type = type }, res =>
{
if (type == 1 || type == 3) _userData.isLuxury = true;
if (type == 2 || type == 3) _userData.isSupreme = true;
RefreshAll();
});
}
// ==================== 工具 ====================
/// 弹出获得奖励面板
private static void ShowHuoDe(List gifts)
{
if (gifts == null || gifts.Count == 0) return;
var data = gifts.Select(g => new BackPackPropItemData
{
url = g.type == 3 ? APIManager.baseURL + (g.product?.imageUrl ?? "") : "",
count = g.isRandom ? g.minCount : g.count,
giftType = g.type,
propEnum = g.type == 3 ? (PropEnum)(g.product?.type ?? 0) : PropEnum.none,
}).ToList();
UIManager.Instance.ShowHuoDe(data);
}
/// 取礼物列表第一项(列表为空返回 null)
private static GiftConfig FirstGift(List list)
{
return (list != null && list.Count > 0) ? list[0] : null;
}
///
/// 通过 otherId 在 propConfig 中查找道具图片地址。
/// 新版 GiftConfig 已移除 product,道具图标需用 otherId 查道具表。
///
private static string ResolveGiftImageUrl(GiftConfig gift)
{
if (gift == null || string.IsNullOrEmpty(gift.otherId)) return "";
var match = GameManager.Instance?.gameConfig?.propConfig?.Find(p => p.number == gift.otherId);
return match?.imageUrl ?? "";
}
/// 通过 otherId 在 propConfig 中查找道具类型
private static int ResolveGiftPropType(GiftConfig gift)
{
if (gift == null || string.IsNullOrEmpty(gift.otherId)) return 0;
var match = GameManager.Instance?.gameConfig?.propConfig?.Find(p => p.number == gift.otherId);
return match?.type ?? 0;
}
/// HTML 转 TextMeshPro 兼容格式
private static string HtmlToTMP(string html)
{
if (string.IsNullOrEmpty(html)) return html;
string result = html;
//
/
→
result = System.Text.RegularExpressions.Regex.Replace(result, @"
", "
");
//
→ 去标签,末尾加换行
result = System.Text.RegularExpressions.Regex.Replace(result, @"
", "\n");
result = System.Text.RegularExpressions.Regex.Replace(result, @"]*>", "");
// \n 转义
result = result.Replace("\\n", "\n");
//
result = System.Text.RegularExpressions.Regex.Replace(result, @"", "\n");
result = System.Text.RegularExpressions.Regex.Replace(result, @"]*>", "");
//
→ 去掉标签保留内容(TMP 不支持动态切换字体)
result = System.Text.RegularExpressions.Regex.Replace(result, @"", "");
result = System.Text.RegularExpressions.Regex.Replace(result, @"
]*>", "");
// → 去标签保留内容
result = System.Text.RegularExpressions.Regex.Replace(result, @"?span[^>]*>", "");
//
result = result.Replace(" ", " ");
// 多余空行
result = System.Text.RegularExpressions.Regex.Replace(result, @"\n{3,}", "\n\n");
return result;
}
/// 刷新战令剩余时间(格式:30天10:01:50)
private void RefreshActiveTime()
{
if (tmp_ActiveTime == null || _config == null) return;
long now = BeijingTimeManager.Instance.CurrentTimestampMs / 1000;
long remain = _config.endTime - now;
if (remain <= 0)
{
tmp_ActiveTime.text = "已结束";
return;
}
int days = (int)(remain / 86400);
int hours = (int)((remain % 86400) / 3600);
int mins = (int)((remain % 3600) / 60);
int secs = (int)(remain % 60);
tmp_ActiveTime.text = $"{days}天{hours:D2}:{mins:D2}:{secs:D2}";
}
[Header("公告")]
public Button btn_CloseGG;
//------------公告------------------
public AnnouncementItem announcementItemPrefab;
public Transform announcementItemParent;
public TextMeshProUGUI tmp_TitleLabel;
public TextMeshProUGUI tmp_Content;
public Image img_TopImg;
private List noticeList;
private void LoadNoticeList()
{
APIRequestList.GetNoticeList(new NoticeListObj
{
keyWord = "",
pageIndex = 0,
pageSize = 50
}, list =>
{
if (list == null) return;
noticeList = list;
// 清除旧列表
for (int i = announcementItemParent.childCount - 1; i >= 0; i--)
Destroy(announcementItemParent.GetChild(i).gameObject);
foreach (var item in list)
{
var obj = Instantiate(announcementItemPrefab.gameObject, announcementItemParent);
var tempItem = obj.GetComponent();
tempItem.Init(item.title, item.createTime);
tempItem.tMP_Header.text = item.title;
string noticeId = item.id;
obj.GetComponent().onValueChanged.RemoveAllListeners();
obj.GetComponent().onValueChanged.AddListener((isOn) =>
{
if (isOn) OnNoticeClick(noticeId);
});
}
// 默认选中第一条公告
if (list.Count > 0)
{
var firstToggle = announcementItemParent.GetChild(0).GetComponent();
firstToggle.isOn = true;
OnNoticeClick(list[0].id);
}
});
}
private void OnNoticeClick(string noticeId)
{
APIRequestList.GetNotice(new NoticeIdParam { id = noticeId }, notice =>
{
if (notice == null) return;
if (tmp_TitleLabel != null) tmp_TitleLabel.text = notice.title;
if (tmp_Content != null) tmp_Content.text = HtmlToTMP(notice.content);
// 加载顶部图片
if (img_TopImg != null && !string.IsNullOrEmpty(notice.topImage))
{
WebTool.DownImage(APIManager.baseURL + notice.topImage, texture =>
{
if (texture != null && img_TopImg != null)
img_TopImg.sprite = Sprite.Create(texture,
new Rect(0, 0, texture.width, texture.height), Vector2.one * 0.5f);
});
}
});
}
}