From 484239463e0802b47070d5df8d7b6931a64b0a67 Mon Sep 17 00:00:00 2001
From: lcy <1459594991@qq.com>
Date: 星期一, 30 三月 2026 17:03:52 +0800
Subject: [PATCH] 492 武将返场

---
 Main/System/HeroReturn/HeroReturnRankCell.cs                                                         |   76 
 Main/System/HeroReturn/HeroReturnStarUpCell.cs.meta                                                  |   11 
 Main/System/HeroReturn/HeroReturnRankAwardCell.cs.meta                                               |   11 
 Main/System/HeroReturn/HeroReturnCallResultCell.cs.meta                                              |   11 
 Main/System/Redpoint/MainRedDot.cs                                                                   |    1 
 Main/System/HeroReturn/HeroReturnCallChangeCell.cs                                                   |   33 
 Main/System/HeroReturn/HeroReturnStarUpWin.cs                                                        |  159 +
 Main/System/HeroReturn/HeroReturnCallWin.cs                                                          |  417 ++++
 Main/System/HeroReturn/HeroReturnRankWin.cs                                                          |  175 +
 Main/System/HeroReturn/HeroReturnShopLineCell.cs.meta                                                |   11 
 Main/System/HeroReturn/HeroReturnCallChangeItem.cs                                                   |   41 
 Main/System/HeroReturn/HeroReturnPopWin.cs                                                           |   96 
 Main/System/HeroReturn/HeroReturnGiftWin.cs                                                          |   86 
 Main/System/HeroReturn/HeroReturnCallChooseWin.cs.meta                                               |   11 
 Main/System/HeroReturn/HeroReturnCallHistoryCell.cs.meta                                             |   11 
 Main/Utility/EnumHelper.cs                                                                           |    2 
 Main/System/HeroReturn/HeroReturnCallChangeCell.cs.meta                                              |   11 
 Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs                                                  |  100 
 Main/System/HeroReturn/HeroReturnStarUpCell.cs                                                       |  126 +
 Main/System/HeroReturn/HeroReturnRankWin.cs.meta                                                     |   11 
 Main/System/HeroReturn/HeroReturnWin.cs                                                              |  268 ++
 Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs                                               |   17 
 Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs                                                  |  119 +
 Main/System/HeroReturn/HeroReturnSkinWin.cs.meta                                                     |   11 
 Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs                                                 |   33 
 Main/System/OpenServerActivity/OperationTimeHepler.cs                                                |    7 
 Main/System/HeroReturn/HeroReturnRankTop3Cell.cs.meta                                                |   11 
 Main/System/HeroReturn/HeroReturnCallBubbleCell.cs.meta                                              |   11 
 Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs.meta                                            |   11 
 Main/System/HeroReturn/HeroReturnShopCell.cs.meta                                                    |   11 
 Main/System/HeroReturn/HeroReturnCallRateWin.cs.meta                                                 |   11 
 Main/System/HeroReturn/HeroReturnSkinTabCell.cs.meta                                                 |   11 
 Main/System/HeroReturn/HeroReturnCell.cs                                                             |   30 
 Main/System/HeroReturn/HeroReturnCallButton.cs                                                       |   95 
 Main/System/HeroReturn/HeroReturnCallHistoryWin.cs.meta                                              |   11 
 Main/System/HeroReturn/HeroReturnSkinAwardCell.cs                                                    |   18 
 Main/System/HeroReturn/HeroReturnShopWin.cs                                                          |   80 
 Main/System/HeroReturn/HeroReturnCallChangeWin.cs.meta                                               |   11 
 Main/System/UIBase/UIJumpManager.cs                                                                  |   41 
 Main/System/HeroReturn/HeroReturnSkinTabCell.cs                                                      |   28 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs                      |    1 
 Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs.meta                                             |   11 
 Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs                                                |   34 
 Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs.meta                                            |   11 
 Main/System/HeroReturn/HeroReturnShopWin.cs.meta                                                     |   11 
 Main/System/HeroDebut/HeroDebutStarUpWin.cs                                                          |    4 
 Main/System/HeroReturn/HeroReturnSkinWin.cs                                                          |  229 ++
 Main/System/HeroDebut/HeroDebutManager.cs                                                            |   65 
 Main/System/HeroReturn/HeroReturnWin.cs.meta                                                         |   11 
 Main/System/HeroReturn/HeroReturnCell.cs.meta                                                        |   11 
 Main/System/HeroReturn/HeroReturnCheckInWin.cs.meta                                                  |   11 
 Main/System/HeroReturn/HeroReturnManager.cs                                                          | 1152 +++++++++++
 Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs                                               |   21 
 Main/System/HeroReturn.meta                                                                          |    8 
 Main/System/HeroReturn/HeroReturnSkinAwardCell.cs.meta                                               |   11 
 Main/System/HeroReturn/HeroReturnCallRateItem.cs                                                     |  123 +
 Main/Config/Configs/ActHeroReturnArtConfig.cs                                                        |  107 +
 Main/System/HappyXB/HappyXBModel.cs                                                                  |   12 
 Main/System/HeroReturn/HeroReturnRankTop3Cell.cs                                                     |   47 
 Main/System/HeroReturn/HeroReturnCallRateItem.cs.meta                                                |   11 
 Main/System/HeroReturn/HeroReturnCallHistoryCell.cs                                                  |   42 
 Main/Config/Configs/ActHeroAppearConfig.cs                                                           |   37 
 Main/Config/Configs/ActHeroReturnSkinArtConfig.cs.meta                                               |   11 
 Main/System/HeroReturn/HeroReturnCallChooseCell.cs.meta                                              |   11 
 Main/System/HeroReturn/HeroReturnCallChooseItem.cs.meta                                              |   11 
 Main/Config/Configs/ActHeroReturnArtConfig.cs.meta                                                   |   11 
 Main/System/HeroReturn/HeroReturnShopCell.cs                                                         |  134 +
 Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs |    1 
 Main/Config/Configs/ActHeroAppearSkinArtConfig.cs                                                    |    2 
 Main/System/HeroReturn/HeroReturnStarUpWin.cs.meta                                                   |   11 
 Main/System/HeroReturn/HeroReturnRankCell.cs.meta                                                    |   11 
 Main/System/HeroReturn/HeroReturnCallChooseWin.cs                                                    |   95 
 Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs.meta                                          |   11 
 Main/Manager/UIManager.cs                                                                            |   39 
 Main/System/HeroDebut/HeroDebutWin.cs                                                                |    2 
 Main/System/HeroReturn/HeroReturnCallRateWin.cs                                                      |   83 
 Main/System/HeroReturn/HeroReturnGiftWin.cs.meta                                                     |   11 
 Main/System/HeroReturn/HeroReturnCallRateCell.cs                                                     |   28 
 Main/System/HeroReturn/HeroReturnCallRateCell.cs.meta                                                |   11 
 Main/System/HeroReturn/HeroReturnCallResultWin.cs                                                    |  370 +++
 Main/System/HeroReturn/HeroReturnCallResultWin.cs.meta                                               |   11 
 Main/System/HeroReturn/HeroReturnCallButton.cs.meta                                                  |   11 
 Main/System/HeroReturn/HeroReturnManager.cs.meta                                                     |   11 
 Main/Config/Configs/ActHeroReturnSkinArtConfig.cs                                                    |   56 
 Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs.meta                                             |   11 
 Main/System/HeroReturn/HeroReturnPopWin.cs.meta                                                      |   11 
 Main/System/HeroReturn/HeroReturnGiftCell.cs                                                         |  165 +
 Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs                                                 |   41 
 Main/System/HeroReturn/HeroReturnCallChangeItem.cs.meta                                              |   11 
 Main/Config/ConfigManager.cs                                                                         |    6 
 Main/System/HeroReturn/HeroReturnCallChooseCell.cs                                                   |   33 
 Main/System/HeroReturn/HeroReturnCallResultCell.cs                                                   |  104 +
 Main/System/HeroReturn/HeroReturnRankAwardCell.cs                                                    |   45 
 Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs                                                 |   28 
 Main/System/HeroReturn/HeroReturnCallChooseItem.cs                                                   |   41 
 Main/System/HeroReturn/HeroReturnGiftCell.cs.meta                                                    |   11 
 Main/System/Main/HomeWin.cs                                                                          |   24 
 Main/System/HeroReturn/HeroReturnCheckInWin.cs                                                       |   81 
 Main/Main.cs                                                                                         |    1 
 Main/System/HeroReturn/HeroReturnCallChangeWin.cs                                                    |  100 
 Main/System/HeroReturn/HeroReturnCheckInCell.cs                                                      |   60 
 Main/System/HeroDebut/HeroDebutCallWin.cs                                                            |    3 
 Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs.meta                                            |   11 
 Main/System/HeroReturn/HeroReturnCallWin.cs.meta                                                     |   11 
 Main/System/HeroReturn/HeroReturnShopLineCell.cs                                                     |   30 
 Main/System/HeroReturn/HeroReturnCheckInCell.cs.meta                                                 |   11 
 Main/Config/PartialConfigs/ActHeroAppearConfig.cs                                                    |   36 
 Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs.meta                                          |   11 
 Main/System/HeroReturn/HeroReturnCallHistoryWin.cs                                                   |   57 
 Main/System/HeroReturn/HeroReturnCallBubbleCell.cs                                                   |   23 
 110 files changed, 6,029 insertions(+), 84 deletions(-)

diff --git a/Main/Config/ConfigManager.cs b/Main/Config/ConfigManager.cs
index 02c6421..b5af31a 100644
--- a/Main/Config/ConfigManager.cs
+++ b/Main/Config/ConfigManager.cs
@@ -43,6 +43,8 @@
             typeof(ActHeroAppearConfig),
             typeof(ActHeroAppearSkinArtConfig),
             typeof(ActHeroAppearStarConfig),
+            typeof(ActHeroReturnArtConfig),
+            typeof(ActHeroReturnSkinArtConfig),
             typeof(ActLunhuidianTypeConfig),
             typeof(ActSignAwardConfig),
             typeof(ADAwardConfig),
@@ -278,6 +280,10 @@
         ClearConfigDictionary<ActHeroAppearSkinArtConfig>();
         // 娓呯┖ ActHeroAppearStarConfig 瀛楀吀
         ClearConfigDictionary<ActHeroAppearStarConfig>();
+        // 娓呯┖ ActHeroReturnArtConfig 瀛楀吀
+        ClearConfigDictionary<ActHeroReturnArtConfig>();
+        // 娓呯┖ ActHeroReturnSkinArtConfig 瀛楀吀
+        ClearConfigDictionary<ActHeroReturnSkinArtConfig>();
         // 娓呯┖ ActLunhuidianTypeConfig 瀛楀吀
         ClearConfigDictionary<ActLunhuidianTypeConfig>();
         // 娓呯┖ ActSignAwardConfig 瀛楀吀
diff --git a/Main/Config/Configs/ActHeroAppearConfig.cs b/Main/Config/Configs/ActHeroAppearConfig.cs
index a2d2229..fb2450f 100644
--- a/Main/Config/Configs/ActHeroAppearConfig.cs
+++ b/Main/Config/Configs/ActHeroAppearConfig.cs
@@ -1,6 +1,6 @@
 锘�//--------------------------------------------------------
 //    [Author]:           YYL
-//    [  Date ]:           2026骞�3鏈�9鏃�
+//    [  Date ]:           Thursday, March 26, 2026
 //--------------------------------------------------------
 
 using System.Collections.Generic;
@@ -17,6 +17,7 @@
     }
 
     public int CfgID;
+	public int ActNum;
 	public int[] ActHeroIDList;
 	public int ActTreasureType;
 	public int StarGiftTempID;
@@ -40,13 +41,15 @@
         string[] tables = input.Split('\t');
         int.TryParse(tables[0],out CfgID); 
 
-			if (tables[1].Contains("["))
+			int.TryParse(tables[1],out ActNum); 
+
+			if (tables[2].Contains("["))
 			{
-				ActHeroIDList = JsonMapper.ToObject<int[]>(tables[1]);
+				ActHeroIDList = JsonMapper.ToObject<int[]>(tables[2]);
 			}
 			else
 			{
-				string[] ActHeroIDListStringArray = tables[1].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				string[] ActHeroIDListStringArray = tables[2].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
 				ActHeroIDList = new int[ActHeroIDListStringArray.Length];
 				for (int i=0;i<ActHeroIDListStringArray.Length;i++)
 				{
@@ -54,17 +57,17 @@
 				}
 			}
 
-			int.TryParse(tables[2],out ActTreasureType); 
+			int.TryParse(tables[3],out ActTreasureType); 
 
-			int.TryParse(tables[3],out StarGiftTempID); 
+			int.TryParse(tables[4],out StarGiftTempID); 
 
-			if (tables[4].Contains("["))
+			if (tables[5].Contains("["))
 			{
-				SkinCTGIDList = JsonMapper.ToObject<int[]>(tables[4]);
+				SkinCTGIDList = JsonMapper.ToObject<int[]>(tables[5]);
 			}
 			else
 			{
-				string[] SkinCTGIDListStringArray = tables[4].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				string[] SkinCTGIDListStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
 				SkinCTGIDList = new int[SkinCTGIDListStringArray.Length];
 				for (int i=0;i<SkinCTGIDListStringArray.Length;i++)
 				{
@@ -72,13 +75,13 @@
 				}
 			}
 
-			if (tables[5].Contains("["))
+			if (tables[6].Contains("["))
 			{
-				GiftCTGIDList = JsonMapper.ToObject<int[]>(tables[5]);
+				GiftCTGIDList = JsonMapper.ToObject<int[]>(tables[6]);
 			}
 			else
 			{
-				string[] GiftCTGIDListStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				string[] GiftCTGIDListStringArray = tables[6].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
 				GiftCTGIDList = new int[GiftCTGIDListStringArray.Length];
 				for (int i=0;i<GiftCTGIDListStringArray.Length;i++)
 				{
@@ -86,15 +89,15 @@
 				}
 			}
 
-			int.TryParse(tables[6],out GiftShopType); 
+			int.TryParse(tables[7],out GiftShopType); 
 
-			int.TryParse(tables[7],out ExShopType); 
+			int.TryParse(tables[8],out ExShopType); 
 
-			int.TryParse(tables[8],out ExShopCostItemID); 
+			int.TryParse(tables[9],out ExShopCostItemID); 
 
-			int.TryParse(tables[9],out SignTempID); 
+			int.TryParse(tables[10],out SignTempID); 
 
-			int.TryParse(tables[10],out BillTempID); 
+			int.TryParse(tables[11],out BillTempID); 
         }
         catch (Exception exception)
         {
diff --git a/Main/Config/Configs/ActHeroAppearSkinArtConfig.cs b/Main/Config/Configs/ActHeroAppearSkinArtConfig.cs
index 94221ae..5c63844 100644
--- a/Main/Config/Configs/ActHeroAppearSkinArtConfig.cs
+++ b/Main/Config/Configs/ActHeroAppearSkinArtConfig.cs
@@ -1,6 +1,6 @@
 锘�//--------------------------------------------------------
 //    [Author]:           YYL
-//    [  Date ]:           2026骞�3鏈�11鏃�
+//    [  Date ]:           2026骞�3鏈�26鏃�
 //--------------------------------------------------------
 
 using System.Collections.Generic;
diff --git a/Main/Config/Configs/ActHeroReturnArtConfig.cs b/Main/Config/Configs/ActHeroReturnArtConfig.cs
new file mode 100644
index 0000000..4d28001
--- /dev/null
+++ b/Main/Config/Configs/ActHeroReturnArtConfig.cs
@@ -0,0 +1,107 @@
+锘�//--------------------------------------------------------
+//    [Author]:           YYL
+//    [  Date ]:           2026骞�3鏈�26鏃�
+//--------------------------------------------------------
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using LitJson;
+
+public partial class ActHeroReturnArtConfig : ConfigBase<int, ActHeroReturnArtConfig>
+{
+    static ActHeroReturnArtConfig()
+    {
+        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
+        visit = true; 
+    }
+
+    public int HeroID;
+	public int[][] HeroNameColor;
+	public int[][] CallBubbleItems;
+	public string EntryBgImage;
+	public string EntryTitleText;
+	public string PopBgImage;
+	public string PopTitleBgImage;
+	public string PopTitleImage;
+	public string PopInfoBgImage;
+	public int PopInfoBgUIEffectId;
+	public string PopInfoText;
+	public int[] PopInfoColor;
+	public string MainBgImage;
+	public string MainTitleImage;
+	public int MainSkinID;
+	public string StarUpHeroImage;
+	public string GiftBgImage;
+	public string GiftHeroImage;
+	public string RankAwardHeroImage;
+	public string CheckInBgImage;
+
+    public override int LoadKey(string _key)
+    {
+        int key = GetKey(_key);
+        return key;
+    }
+
+    public override void LoadConfig(string input)
+    {
+        try {
+        string[] tables = input.Split('\t');
+        int.TryParse(tables[0],out HeroID); 
+
+			HeroNameColor = JsonMapper.ToObject<int[][]>(tables[1].Replace("(", "[").Replace(")", "]")); 
+
+			CallBubbleItems = JsonMapper.ToObject<int[][]>(tables[2].Replace("(", "[").Replace(")", "]")); 
+
+			EntryBgImage = tables[3];
+
+			EntryTitleText = tables[4];
+
+			PopBgImage = tables[5];
+
+			PopTitleBgImage = tables[6];
+
+			PopTitleImage = tables[7];
+
+			PopInfoBgImage = tables[8];
+
+			int.TryParse(tables[9],out PopInfoBgUIEffectId); 
+
+			PopInfoText = tables[10];
+
+			if (tables[11].Contains("["))
+			{
+				PopInfoColor = JsonMapper.ToObject<int[]>(tables[11]);
+			}
+			else
+			{
+				string[] PopInfoColorStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
+				PopInfoColor = new int[PopInfoColorStringArray.Length];
+				for (int i=0;i<PopInfoColorStringArray.Length;i++)
+				{
+					 int.TryParse(PopInfoColorStringArray[i],out PopInfoColor[i]);
+				}
+			}
+
+			MainBgImage = tables[12];
+
+			MainTitleImage = tables[13];
+
+			int.TryParse(tables[14],out MainSkinID); 
+
+			StarUpHeroImage = tables[15];
+
+			GiftBgImage = tables[16];
+
+			GiftHeroImage = tables[17];
+
+			RankAwardHeroImage = tables[18];
+
+			CheckInBgImage = tables[19];
+        }
+        catch (Exception exception)
+        {
+            Debug.LogError(exception);
+        }
+    }
+}
diff --git a/Main/Config/Configs/ActHeroReturnArtConfig.cs.meta b/Main/Config/Configs/ActHeroReturnArtConfig.cs.meta
new file mode 100644
index 0000000..851219f
--- /dev/null
+++ b/Main/Config/Configs/ActHeroReturnArtConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 010dfd3e7d7da104f8daef3fb34fd922
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config/Configs/ActHeroReturnSkinArtConfig.cs b/Main/Config/Configs/ActHeroReturnSkinArtConfig.cs
new file mode 100644
index 0000000..0cb15c1
--- /dev/null
+++ b/Main/Config/Configs/ActHeroReturnSkinArtConfig.cs
@@ -0,0 +1,56 @@
+锘�//--------------------------------------------------------
+//    [Author]:           YYL
+//    [  Date ]:           Thursday, March 26, 2026
+//--------------------------------------------------------
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using LitJson;
+
+public partial class ActHeroReturnSkinArtConfig : ConfigBase<int, ActHeroReturnSkinArtConfig>
+{
+    static ActHeroReturnSkinArtConfig()
+    {
+        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
+        visit = true; 
+    }
+
+    public int SkinID;
+	public string MainSkinBuyBgImage;
+	public string BGImage;
+	public string HeroNameImage;
+	public string SkinInfoImage;
+	public string AwardBGImage;
+	public string TabInfoImage;
+
+    public override int LoadKey(string _key)
+    {
+        int key = GetKey(_key);
+        return key;
+    }
+
+    public override void LoadConfig(string input)
+    {
+        try {
+        string[] tables = input.Split('\t');
+        int.TryParse(tables[0],out SkinID); 
+
+			MainSkinBuyBgImage = tables[1];
+
+			BGImage = tables[2];
+
+			HeroNameImage = tables[3];
+
+			SkinInfoImage = tables[4];
+
+			AwardBGImage = tables[5];
+
+			TabInfoImage = tables[6];
+        }
+        catch (Exception exception)
+        {
+            Debug.LogError(exception);
+        }
+    }
+}
diff --git a/Main/Config/Configs/ActHeroReturnSkinArtConfig.cs.meta b/Main/Config/Configs/ActHeroReturnSkinArtConfig.cs.meta
new file mode 100644
index 0000000..7bf7cf8
--- /dev/null
+++ b/Main/Config/Configs/ActHeroReturnSkinArtConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5a29cc75b87652c4d9357b05ef1853f5
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config/PartialConfigs/ActHeroAppearConfig.cs b/Main/Config/PartialConfigs/ActHeroAppearConfig.cs
index c258cab..22c36bb 100644
--- a/Main/Config/PartialConfigs/ActHeroAppearConfig.cs
+++ b/Main/Config/PartialConfigs/ActHeroAppearConfig.cs
@@ -1,18 +1,40 @@
 using System.Collections.Generic;
+using System.Linq;
 public partial class ActHeroAppearConfig : ConfigBase<int, ActHeroAppearConfig>
 {
-    private static List<int> actTreasureTypeList;
-    public static List<int> GetActTreasureTypeList()
+    /// <summary>
+    /// 姝﹀皢鐧诲満鐨勬墍鏈夋嫑鍕熷瀹濈被鍨�
+    /// </summary>
+    private static HashSet<int> heroDebutActTreasureTypeList = new();
+    public static List<int> GetHeroDebutActTreasureTypeList()
     {
-        if (actTreasureTypeList == null)
+        if (heroDebutActTreasureTypeList.Count == 0)
         {
-            actTreasureTypeList = new();
             foreach (var item in GetValues())
             {
-                if (!actTreasureTypeList.Contains(item.ActTreasureType))
-                    actTreasureTypeList.Add(item.ActTreasureType);
+                if (item.ActNum != 10)
+                    continue;
+                heroDebutActTreasureTypeList.Add(item.ActTreasureType);
             }
         }
-        return actTreasureTypeList;
+        return heroDebutActTreasureTypeList.ToList();
+    }
+
+    /// <summary>
+    /// 姝﹀皢杩斿満鐨勬墍鏈夋嫑鍕熷瀹濈被鍨�
+    /// </summary>
+    private static HashSet<int> heroReturnActTreasureTypeList = new();
+    public static List<int> GetHeroReturnActTreasureTypeList()
+    {
+        if (heroReturnActTreasureTypeList.Count == 0)
+        {
+            foreach (var item in GetValues())
+            {
+                if (item.ActNum != 11)
+                    continue;
+                heroReturnActTreasureTypeList.Add(item.ActTreasureType);
+            }
+        }
+        return heroReturnActTreasureTypeList.ToList();
     }
 }
diff --git a/Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs b/Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs
index df067a9..31e7621 100644
--- a/Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs
+++ b/Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs
@@ -26,8 +26,40 @@
             sortDict[starTempID] = list;
         }
     }
+    public static List<int> GetHeroReturnAwardIndexSortList(int starTempID)
+    {
+        LoadSortList();
+        sortDict.TryGetValue(starTempID, out var list);
 
-    public static List<int> GetAwardIndexSortList(int starTempID)
+        List<int> res = new List<int>();
+        int heroId = HeroReturnManager.Instance.GetCurrentDisplayStarUpHeroId();
+        int nowStar = HeroReturnManager.Instance.GetNowHeroMaxStarCnt(heroId);
+        for (int i = HeroReturnManager.Instance.seeArr.Length - 1; i >= 0; i--)
+        {
+            int[] info = HeroReturnManager.Instance.seeArr[i];
+            int needStar = info[0];
+            int seeStar = info[1];
+            if (nowStar >= needStar)
+            {
+                for (int j = 0; j < seeStar; j++)
+                {
+                    if (j >= list.Count) continue;
+
+                    var config = GetConfig(starTempID, list[j]);
+                    if (config == null) continue;
+
+                    int tempStar = config.NeedStar;
+                    if (tempStar > seeStar) continue;
+
+                    res.Add(list[j]);
+                }
+                return res;
+            }
+        }
+
+        return null;
+    }
+    public static List<int> GetHeroDebutAwardIndexSortList(int starTempID)
     {
         LoadSortList();
         sortDict.TryGetValue(starTempID, out var list);
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs
index 290e6a8..cf3c32c 100644
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs
@@ -10,5 +10,6 @@
         ArenaManager.Instance.UpdateGameRecInfo(vNetData);
         HeroDebutManager.Instance.UpdateGameRecInfo(vNetData);
         QunyingManager.Instance.UpdateGameRecInfo(vNetData);
+        HeroReturnManager.Instance.UpdateGameRecInfo(vNetData);
     }
 }
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs
index 4b4846c..66006e9 100644
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs
@@ -10,5 +10,6 @@
         base.Done(vNetPack);
         HAA22_tagSCActHeroAppearPlayerInfo vNetData = vNetPack as HAA22_tagSCActHeroAppearPlayerInfo;
         HeroDebutManager.Instance.UpdateHeroAppearPlayerInfo(vNetData);
+        HeroReturnManager.Instance.UpdateHeroAppearPlayerInfo(vNetData);
     }
 }
diff --git a/Main/Main.cs b/Main/Main.cs
index 612f4de..2308b59 100644
--- a/Main/Main.cs
+++ b/Main/Main.cs
@@ -112,6 +112,7 @@
         managers.Add(GeneralActInfoManager.Instance);
         managers.Add(QunyingManager.Instance);
         managers.Add(ViewBuffManager.Instance);
+        managers.Add(HeroReturnManager.Instance);
 
         foreach (var manager in managers)
         {
diff --git a/Main/Manager/UIManager.cs b/Main/Manager/UIManager.cs
index e8079ce..490c18b 100644
--- a/Main/Manager/UIManager.cs
+++ b/Main/Manager/UIManager.cs
@@ -381,7 +381,44 @@
         return false;
     }
 
-    
+    // 妫�鏌ユ槸鍚﹀瓨鍦ㄤ换浣曞悓灞傜骇sortingOrde澶т簬鎴戠殑绐楀彛
+    public bool ExistAnySameLevelWinHigherSortingOrder(UILayer uiLayer, string excludeUIName)
+    {
+        int mySortingOrder = 0;
+        if (uiDict.TryGetValue(excludeUIName, out List<UIBase> excludeList) && excludeList.Count > 0)
+        {
+            foreach (var ui in excludeList)
+            {
+                if (ui.IsActive())
+                {
+                    mySortingOrder = ui.GetSortingOrder();
+                    break;
+                }
+            }
+        }
+
+        if (mySortingOrder == 0)
+            return false;
+
+        foreach (var uiList in uiDict.Values)
+        {
+            foreach (var ui in uiList)
+            {
+                if (!ui.IsActive())
+                    continue;
+                if (ui.uiName == excludeUIName)
+                    continue;
+                if (ui.uiLayer != uiLayer)
+                    continue;
+                if (ui.GetSortingOrder() > mySortingOrder)
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+
     // 鑾峰彇鎸囧畾绫诲瀷鐨勬墍鏈塙I瀹炰緥
     public List<T> GetAllUI<T>() where T : UIBase
     {
diff --git a/Main/System/HappyXB/HappyXBModel.cs b/Main/System/HappyXB/HappyXBModel.cs
index c33cee3..a940de5 100644
--- a/Main/System/HappyXB/HappyXBModel.cs
+++ b/Main/System/HappyXB/HappyXBModel.cs
@@ -182,14 +182,24 @@
             {
                 UIManager.Instance.OpenWindow<HeroCallResultWin>();
             }
+            return;
         }
 
-        if (ActHeroAppearConfig.GetActTreasureTypeList().Contains(type))
+        if (ActHeroAppearConfig.GetHeroDebutActTreasureTypeList().Contains(type))
         {
             if (!UIManager.Instance.IsOpened<HeroDebutCallResultWin>())
             {
                 UIManager.Instance.OpenWindow<HeroDebutCallResultWin>();
             }
+            return;
+        }
+
+        if (ActHeroAppearConfig.GetHeroReturnActTreasureTypeList().Contains(type))
+        {
+            if (!UIManager.Instance.IsOpened<HeroReturnCallResultWin>())
+            {
+                UIManager.Instance.OpenWindow<HeroReturnCallResultWin>();
+            }
         }
     }
 
diff --git a/Main/System/HeroDebut/HeroDebutCallWin.cs b/Main/System/HeroDebut/HeroDebutCallWin.cs
index f988de6..9096cbe 100644
--- a/Main/System/HeroDebut/HeroDebutCallWin.cs
+++ b/Main/System/HeroDebut/HeroDebutCallWin.cs
@@ -78,6 +78,7 @@
         PackManager.Instance.RefreshItemEvent += RefreshItemEvent;
         scroller.OnRefreshCell += OnRefreshCell;
         manager.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
+        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
 
         if (manager.isSendFirst)
         {
@@ -113,7 +114,7 @@
     // 1. 鍦ㄧ被涓0鏄庝竴涓叏灞�鐨� Sequence 鍙橀噺锛岀敤浜庣粺涓�绠℃帶鍔ㄧ敾
     private Sequence heroAnimSeq;
 
-    private void OnUpdateHeroAppearPlayerInfoEvent(int actNum)
+    private void OnUpdateHeroAppearPlayerInfoEvent()
     {
         changeRect.SetActive(false);
 
diff --git a/Main/System/HeroDebut/HeroDebutManager.cs b/Main/System/HeroDebut/HeroDebutManager.cs
index d966740..5a32e8f 100644
--- a/Main/System/HeroDebut/HeroDebutManager.cs
+++ b/Main/System/HeroDebut/HeroDebutManager.cs
@@ -77,9 +77,9 @@
     private void OnBeforePlayerDataInitializeEventOnRelogin()
     {
         isSendFirst = true;
-        starHeroIndexDict.Clear();
+        starHeroIndex = 0;
+        callHeroIndex = 0;
         starFreeAwardDict.Clear();
-        callHeroIndexDict.Clear();
     }
 
     private void OnPlayerLoginOk()
@@ -243,22 +243,23 @@
             OnNowCallChooseHeroIDChangeEvent?.Invoke();
         }
     }
-    public event Action<int> OnUpdateHeroAppearPlayerInfoEvent;
+    public int starHeroIndex = 0;
+    public int callHeroIndex = 0;
+    //<鍗囨槦璁″垝閫夋嫨鐨勬灏咺D绱㈠紩,鍗囨槦璁″垝鍏嶈垂濂栧姳璁板綍>
+    Dictionary<int, uint> starFreeAwardDict = new();
+
+    public event Action OnUpdateHeroAppearPlayerInfoEvent;
     public void UpdateHeroAppearPlayerInfo(HAA22_tagSCActHeroAppearPlayerInfo vNetData)
     {
         if (vNetData == null) return;
-        int actNum = vNetData.ActNum;
-        starHeroIndexDict[actNum] = vNetData.StarHeroIndex;
-        callHeroIndexDict[actNum] = vNetData.CallHeroIndex;
+        if (vNetData.ActNum != this.actNum) return;
 
-        if (!starFreeAwardDict.TryGetValue(actNum, out var dict))
-        {
-            dict = new Dictionary<int, uint>();
-            starFreeAwardDict[actNum] = dict;
-        }
-        dict[vNetData.StarHeroIndex] = vNetData.StarFreeAward;
+        int actNum = vNetData.ActNum;
+        starHeroIndex = vNetData.StarHeroIndex;
+        callHeroIndex = vNetData.CallHeroIndex;
+        starFreeAwardDict[starHeroIndex] = vNetData.StarFreeAward;
         UpdateRedpoint();
-        OnUpdateHeroAppearPlayerInfoEvent?.Invoke(actNum);
+        OnUpdateHeroAppearPlayerInfoEvent?.Invoke();
     }
 
     public void SendHeroAppearStarHeroSelect(int actNum, int starHeroIndex)
@@ -432,12 +433,6 @@
 
     #region 鍗囨槦璁″垝
 
-    //<娲诲姩缂栧彿,鍗囨槦璁″垝閫夋嫨鐨勬灏咺D绱㈠紩>
-    public Dictionary<int, int> starHeroIndexDict = new();
-
-    //<娲诲姩缂栧彿,<鍗囨槦璁″垝閫夋嫨鐨勬灏咺D绱㈠紩,鍗囨槦璁″垝鍏嶈垂濂栧姳璁板綍>>
-    public Dictionary<int, Dictionary<int, uint>> starFreeAwardDict = new();
-
     /// <summary>
     /// 褰撳墠鍗囨槦璁″垝閫変腑鐨勬灏咺D
     /// </summary>
@@ -445,12 +440,11 @@
     {
         var act = GetOperationHeroAppearInfo();
         if (act == null) return 0;
-        if (!starHeroIndexDict.TryGetValue(actNum, out int index)) return 0;
 
         var config = ActHeroAppearConfig.Get(act.CfgID);
-        if (config == null || config.ActHeroIDList?.Length <= index) return 0;
+        if (config == null || config.ActHeroIDList?.Length <= starHeroIndex) return 0;
 
-        return config.ActHeroIDList[index];
+        return config.ActHeroIDList[starHeroIndex];
     }
 
     private Dictionary<int, Dictionary<int, int[][]>> showHeroGiftItemInfoDict = new();
@@ -508,16 +502,14 @@
         // 娌¤幏寰楁灏嗘湰浣撲笉鍙鍙�
         if (!HeroManager.Instance.HasHero(heroId))return 0;
         
-        if (!starHeroIndexDict.TryGetValue(actNum, out int index)) return 0;
-        if (IsStarUpFreeHave(index, config.AwardIndex)) return 2;
+        if (IsStarUpFreeHave(starHeroIndex, config.AwardIndex)) return 2;
         if (IsHeroStarCntOk(heroConfig.HeroID, config.NeedStar)) return 1;
         return 0;
     }
 
     private bool IsStarUpFreeHave(int starHeroIndex, int awardIndex)
     {
-        if (!starFreeAwardDict.TryGetValue(actNum, out var dict)) return false;
-        if (!dict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
+        if (!starFreeAwardDict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
         return ((freeAward >> awardIndex) & 1u) == 1u;
     }
 
@@ -544,7 +536,7 @@
     public bool TryGetStarUpStateIndex(int starGiftTempID, int tarState, out int index)
     {
         index = 0;
-        var list = ActHeroAppearStarConfig.GetAwardIndexSortList(starGiftTempID);
+        var list = ActHeroAppearStarConfig.GetHeroDebutAwardIndexSortList(starGiftTempID);
         if (list == null) return false;
 
         for (int i = 0; i < list.Count; i++)
@@ -733,7 +725,7 @@
     }
     private string GetCallSkipKey(int cfgID, OperationDate startDate, OperationDate endDate)
     {
-        return string.Concat("HeroDebutManager_CallSkip_", cfgID, ToInt(startDate), ToInt(endDate), PlayerDatas.Instance.PlayerId);
+        return string.Concat("HeroDebutManager_CallSkip_", cfgID, "_", ToInt(startDate), "_", ToInt(endDate), "_", PlayerDatas.Instance.PlayerId);
     }
 
     public bool LoadCallSkipData(int cfgID, OperationDate startDate, OperationDate endDate)
@@ -746,9 +738,6 @@
         LocalSave.SetBool(GetCallSkipKey(cfgID, startDate, endDate), value);
     }
 
-    //<娲诲姩缂栧彿,鎷涘嫙閫夋嫨鐨勬灏咺D绱㈠紩>
-    public Dictionary<int, int> callHeroIndexDict = new();
-
     /// <summary>
     /// 褰撳墠鎷涘嫙閫変腑鐨勬灏咺D
     /// </summary>
@@ -756,12 +745,11 @@
     {
         var act = GetOperationHeroAppearInfo();
         if (act == null) return 0;
-        if (!callHeroIndexDict.TryGetValue(actNum, out int index)) return 0;
 
         var config = ActHeroAppearConfig.Get(act.CfgID);
-        if (config == null || config.ActHeroIDList?.Length <= index) return 0;
+        if (config == null || config.ActHeroIDList?.Length <= callHeroIndex) return 0;
 
-        return config.ActHeroIDList[index];
+        return config.ActHeroIDList[callHeroIndex];
     }
 
 
@@ -960,19 +948,10 @@
     {
         return gameRecDict;
     }
-    public List<HeroDebutGameRec> GetLastFourRecords()
-    {
-        if (gameRecDict == null || gameRecDict.Count == 0) return new List<HeroDebutGameRec>();
-
-        int count = gameRecDict.Count;
-        int takeCount = Math.Min(4, count);
-        return gameRecDict.GetRange(count - takeCount, takeCount);
-    }
 
     public event Action OnUpdateGameRecInfo;
     public void UpdateGameRecInfo(HA009_tagSCGameRecInfo vNetData)
     {
-
         var act = GetOperationHeroAppearInfo();
         if (act == null) return;
 
diff --git a/Main/System/HeroDebut/HeroDebutStarUpWin.cs b/Main/System/HeroDebut/HeroDebutStarUpWin.cs
index 5c46d69..4e14361 100644
--- a/Main/System/HeroDebut/HeroDebutStarUpWin.cs
+++ b/Main/System/HeroDebut/HeroDebutStarUpWin.cs
@@ -44,7 +44,7 @@
         manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
     }
 
-    private void OnUpdateHeroAppearPlayerInfoEvent(int obj)
+    private void OnUpdateHeroAppearPlayerInfoEvent()
     {
         scroller.m_Scorller.RefreshActiveCellViews();
     }
@@ -96,7 +96,7 @@
 
         if (appearConfig == null || heroConfig == null) return;
         int starGiftTempID = appearConfig.StarGiftTempID;
-        var list = ActHeroAppearStarConfig.GetAwardIndexSortList(starGiftTempID);
+        var list = ActHeroAppearStarConfig.GetHeroDebutAwardIndexSortList(starGiftTempID);
         if (list == null) return;
 
         scroller.Refresh();
diff --git a/Main/System/HeroDebut/HeroDebutWin.cs b/Main/System/HeroDebut/HeroDebutWin.cs
index c9ddc46..7c4b5f7 100644
--- a/Main/System/HeroDebut/HeroDebutWin.cs
+++ b/Main/System/HeroDebut/HeroDebutWin.cs
@@ -60,7 +60,7 @@
         manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
     }
 
-    private void OnUpdateHeroAppearPlayerInfoEvent(int obj)
+    private void OnUpdateHeroAppearPlayerInfoEvent()
     {
         Display();
     }
diff --git a/Main/System/HeroReturn.meta b/Main/System/HeroReturn.meta
new file mode 100644
index 0000000..70a9ff5
--- /dev/null
+++ b/Main/System/HeroReturn.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ad40f79e4689d234fac9fc2f4d8be9a7
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallBubbleCell.cs b/Main/System/HeroReturn/HeroReturnCallBubbleCell.cs
new file mode 100644
index 0000000..9b4af0c
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallBubbleCell.cs
@@ -0,0 +1,23 @@
+using UnityEngine;
+
+public class HeroReturnCallBubbleCell : MonoBehaviour
+{
+    [SerializeField] ButtonEx clickButton;
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] ImageEx iconImage;
+    [SerializeField] TextEx countText;
+    public void Display(int itemID, int count)
+    {
+        var config = ItemConfig.Get(itemID);
+        if (config == null) return;
+
+        bgImage.SetSprite($"HeroDebutCallBubbleBG{config.ItemColor}");
+        iconImage.SetItemSprite(itemID);
+        iconImage.SetNativeSize();
+        countText.text = count.ToString();
+
+        clickButton.SetListener(() => ItemTipUtility.Show(itemID));
+    }
+
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallBubbleCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallBubbleCell.cs.meta
new file mode 100644
index 0000000..4138c02
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallBubbleCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 10ed3265b0279984dbb79382f829567a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallButton.cs b/Main/System/HeroReturn/HeroReturnCallButton.cs
new file mode 100644
index 0000000..fdd1419
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallButton.cs
@@ -0,0 +1,95 @@
+using UnityEngine;
+
+public class HeroReturnCallButton : MonoBehaviour
+{
+    [SerializeField] ButtonEx clickButton;
+    [SerializeField] TextEx callText;
+    [SerializeField] TextEx needText;
+    [SerializeField] ImageEx needImage;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    HappyXBModel xbManager => HappyXBModel.Instance;
+    int index;
+    int type;
+    int needCostItemCnt;
+    long hasItemCnt;
+    int needCostMoneyCnt;
+    long moneyCount;
+    public void Display(int treasureType, int index)
+    {
+        this.index = index;
+        type = treasureType;
+        var treasureSetConfig = TreasureSetConfig.Get(treasureType);
+        if (treasureSetConfig == null) return;
+        if (treasureSetConfig.TreasureCountList == null || treasureSetConfig.TreasureCountList.Length <= index) return;
+        if (treasureSetConfig.CostItemCountList == null || treasureSetConfig.CostItemCountList.Length <= index) return;
+        if (treasureSetConfig.CostMoneyList == null || treasureSetConfig.CostMoneyList.Length <= index) return;
+
+        XBTypeInfo info = xbManager.GetXBInfoByType(treasureType);
+        if (info == null) return;
+
+        int treasureCnt = treasureSetConfig.TreasureCountList[index];
+
+        callText.text = Language.Get("HeroDebut23", treasureCnt);
+
+        int dailyMaxCountMoney = treasureSetConfig.DailyMaxCountMoney;
+        int nowMoneyCnt = info.treasureCountTodayGold;
+
+        needCostMoneyCnt = treasureSetConfig.CostMoneyList[index];
+        moneyCount = UIHelper.GetMoneyCnt(treasureSetConfig.CostMoneyType);
+
+        needCostItemCnt = treasureSetConfig.CostItemCountList[index];
+        hasItemCnt = PackManager.Instance.GetItemCountByID(PackType.Item, treasureSetConfig.CostItemID);
+
+        // 鐗╁搧涓嶈冻 && 娌¤秴璐у竵鎷涘嫙娆℃暟涓婇檺 
+        if (hasItemCnt < needCostItemCnt &&
+            nowMoneyCnt + treasureCnt <= dailyMaxCountMoney)
+        {
+            DisplayByMoney(treasureSetConfig.CostMoneyType, needCostMoneyCnt, moneyCount);
+            return;
+        }
+        DisplayByItem(treasureSetConfig.CostItemID, treasureCnt);
+    }
+
+    void DisplayByMoney(int moneyType, long needCostMoneyCnt, long moneyCount)
+    {
+
+        bool isEnough = moneyCount >= needCostMoneyCnt;
+        needText.text = Language.Get("L1100", RichTextMsgReplaceConfig.GetRichReplace("MONEY", moneyType), UIHelper.AppendColor(!isEnough ? TextColType.Red : TextColType.LightGreen, needCostMoneyCnt.ToString()));
+        needImage.SetIconWithMoneyType(moneyType);
+
+        clickButton.SetListener(() =>
+        {
+            if (!isEnough)
+            {
+                ItemTipUtility.ShowMoneyTip(moneyType, true);
+                return;
+            }
+            HeroUIManager.Instance.selectCallType = (HappXBTitle)type;
+            HeroUIManager.Instance.selectCallIndex = index;
+            HappyXBModel.Instance.SendXBQuest(type, index, 0);
+        });
+    }
+
+    void DisplayByItem(int itemID, int count)
+    {
+        ItemConfig itemConfig = ItemConfig.Get(itemID);
+        if (itemConfig == null) return;
+        bool isEnough = hasItemCnt >= needCostItemCnt;
+        needText.text = Language.Get("L1100", itemConfig.ItemName, UIHelper.AppendColor(!isEnough ? TextColType.Red : TextColType.LightGreen, count.ToString()));
+        needImage.SetItemSprite(itemID);
+
+        clickButton.SetListener(() =>
+        {
+            if (!isEnough)
+            {
+                ItemTipUtility.Show(itemID, true);
+                return;
+            }
+            HeroUIManager.Instance.selectCallType = (HappXBTitle)type;
+            HeroUIManager.Instance.selectCallIndex = index;
+            HappyXBModel.Instance.SendXBQuest(type, index, 2);
+        });
+
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallButton.cs.meta b/Main/System/HeroReturn/HeroReturnCallButton.cs.meta
new file mode 100644
index 0000000..f6fdfb8
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallButton.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d55190ecb673d464f88f4ec0a5425732
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallChangeCell.cs b/Main/System/HeroReturn/HeroReturnCallChangeCell.cs
new file mode 100644
index 0000000..c1cf3e5
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChangeCell.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+
+public class HeroReturnCallChangeCell : CellView
+{
+    [SerializeField] HeroReturnCallChangeItem[] items;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int rowIndex)
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var heroArr = config.ActHeroIDList;
+        if (heroArr.IsNullOrEmpty()) return;
+
+        for (int i = 0; i < items.Length; i++)
+        {
+            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
+            if (index < heroArr.Length)
+            {
+                items[i].SetActive(true);
+                items[i].Display(index, heroArr, act.CfgID);
+            }
+            else
+            {
+                items[i].SetActive(false);
+            }
+        }
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallChangeCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallChangeCell.cs.meta
new file mode 100644
index 0000000..08b9f82
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChangeCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e0d034734cb56844cb0216e77c5b3440
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallChangeItem.cs b/Main/System/HeroReturn/HeroReturnCallChangeItem.cs
new file mode 100644
index 0000000..445c6e4
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChangeItem.cs
@@ -0,0 +1,41 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnCallChangeItem : MonoBehaviour
+{
+
+    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
+    [SerializeField] Image jobImg;
+    [SerializeField] Text nameText;
+    [SerializeField] Transform select;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    HeroConfig heroConfig;
+    int index;
+    public void Display(int index, int[] heroIds, int cfgId)
+    {
+        this.index = index;
+        if (heroIds?.Length <= index) return;
+
+        int heroId = heroIds[index];
+        heroConfig = HeroConfig.Get(heroId);
+        if (heroConfig == null) return;
+        
+        int skinID = manager.GetDefaultSkinID(heroId);
+        var heroSkinConfig = HeroSkinConfig.Get(skinID);
+        if (heroSkinConfig == null) return;
+
+        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, OnClick);
+        nameText.text = heroConfig.Name;
+        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
+        bool isChoose = manager.nowCallChooseHeroID == heroId;
+        select?.SetActive(isChoose);
+    }
+
+    public void OnClick()
+    {
+        if (heroConfig == null) return;
+
+        manager.nowCallChooseHeroID = heroConfig.HeroID;
+
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallChangeItem.cs.meta b/Main/System/HeroReturn/HeroReturnCallChangeItem.cs.meta
new file mode 100644
index 0000000..d124830
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChangeItem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0720ebe725ea61345a7c09406a98e96e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallChangeWin.cs b/Main/System/HeroReturn/HeroReturnCallChangeWin.cs
new file mode 100644
index 0000000..0785f57
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChangeWin.cs
@@ -0,0 +1,100 @@
+using UnityEngine;
+
+public class HeroReturnCallChangeWin : UIBase
+{
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] ButtonEx okButton;
+    [SerializeField] ButtonEx previewButton;
+    [SerializeField] UIHeroController uiHeroController;
+    public const int rowCountMax = 4;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        okButton.SetListener(() =>
+        {
+            var act = manager.GetOperationHeroAppearInfo();
+            if (act == null) return;
+
+            int index = manager.GetHeroIdIndex(act.CfgID, manager.nowCallChooseHeroID);
+            if (index < 0) return;
+
+            if (manager.GetCurrentDisplayCallHeroId() == manager.nowCallChooseHeroID)
+            {
+                SysNotifyMgr.Instance.ShowTip("HeroDebut01");
+                return;
+            }
+
+            manager.SnedHeroAppearCallHeroSelect(manager.actNum, index);
+            CloseWindow();
+        });
+        previewButton.SetListener(() =>
+        {
+            HeroUIManager.Instance.selectForPreviewHeroID = manager.nowCallChooseHeroID;
+            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
+        });
+    }
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        manager.OnNowCallChooseHeroIDChangeEvent += OnNowCallChooseHeroIDChangeEvent;
+        manager.nowCallChooseHeroID = manager.GetCurrentDisplayCallHeroId();
+        Display();
+        CreateScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        manager.OnNowCallChooseHeroIDChangeEvent -= OnNowCallChooseHeroIDChangeEvent;
+    }
+
+    private void OnNowCallChooseHeroIDChangeEvent()
+    {
+        Display();
+        scroller.m_Scorller.RefreshActiveCellViews();
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnCallChangeCell;
+        _cell.Display(cell.index);
+    }
+
+    void CreateScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var arr = config.ActHeroIDList;
+        if (arr.IsNullOrEmpty()) return;
+
+
+        scroller.Refresh();
+        int rowCount = (int)Mathf.Ceil((float)arr.Length / rowCountMax);
+        for (int i = 0; i < rowCount; i++)
+        {
+            scroller.AddCell(ScrollerDataType.Header, i);
+        }
+        scroller.Restart();
+    }
+
+    void Display()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+
+        int skinID = manager.GetDefaultSkinID(manager.nowCallChooseHeroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        uiHeroController.Create(skinID, 1);
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallChangeWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallChangeWin.cs.meta
new file mode 100644
index 0000000..8ab7665
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChangeWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8aa8fd53cfed7704f8a1b6b0b8d75407
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallChooseCell.cs b/Main/System/HeroReturn/HeroReturnCallChooseCell.cs
new file mode 100644
index 0000000..cc3c8f3
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChooseCell.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+
+public class HeroReturnCallChooseCell : CellView
+{
+    [SerializeField] HeroReturnCallChooseItem[] items;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int rowIndex)
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var heroArr = config.ActHeroIDList;
+        if (heroArr.IsNullOrEmpty()) return;
+
+        for (int i = 0; i < items.Length; i++)
+        {
+            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
+            if (index < heroArr.Length)
+            {
+                items[i].SetActive(true);
+                items[i].Display(index, heroArr, act.CfgID);
+            }
+            else
+            {
+                items[i].SetActive(false);
+            }
+        }
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallChooseCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallChooseCell.cs.meta
new file mode 100644
index 0000000..6e708f9
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChooseCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0f45542ad2c6a5a4a9b16dacda70e468
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallChooseItem.cs b/Main/System/HeroReturn/HeroReturnCallChooseItem.cs
new file mode 100644
index 0000000..f7fc4bd
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChooseItem.cs
@@ -0,0 +1,41 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnCallChooseItem : MonoBehaviour
+{
+
+    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
+    [SerializeField] Image jobImg;
+    [SerializeField] Text nameText;
+    [SerializeField] Transform select;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    HeroConfig heroConfig;
+    int index;
+    public void Display(int index, int[] heroIds, int cfgId)
+    {
+        this.index = index;
+        if (heroIds?.Length <= index) return;
+
+        int heroId = heroIds[index];
+        heroConfig = HeroConfig.Get(heroId);
+        if (heroConfig == null) return;
+        
+        int skinID = manager.GetDefaultSkinID(heroId);
+        var heroSkinConfig = HeroSkinConfig.Get(skinID);
+        if (heroSkinConfig == null) return;
+
+        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, OnClick);
+        nameText.text = heroConfig.Name;
+        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
+        bool isChoose = manager.nowCallChooseHeroID == heroId;
+        select?.SetActive(isChoose);
+    }
+
+    public void OnClick()
+    {
+        if (heroConfig == null) return;
+
+        manager.nowCallChooseHeroID = heroConfig.HeroID;
+
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallChooseItem.cs.meta b/Main/System/HeroReturn/HeroReturnCallChooseItem.cs.meta
new file mode 100644
index 0000000..c59d10d
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChooseItem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 05796103e33a5c44b9ab102ee2fde400
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallChooseWin.cs b/Main/System/HeroReturn/HeroReturnCallChooseWin.cs
new file mode 100644
index 0000000..1a9b81d
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChooseWin.cs
@@ -0,0 +1,95 @@
+using UnityEngine;
+
+public class HeroReturnCallChooseWin : UIBase
+{
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] ButtonEx okButton;
+    [SerializeField] ButtonEx previewButton;
+    [SerializeField] UIHeroController uiHeroController;
+    public const int rowCountMax = 4;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        okButton.SetListener(() =>
+        {
+            var act = manager.GetOperationHeroAppearInfo();
+            if (act == null) return;
+
+            int index = manager.GetHeroIdIndex(act.CfgID, manager.nowCallChooseHeroID);
+            if (index < 0) return;
+
+            manager.SnedHeroAppearCallHeroSelect(manager.actNum, index);
+            manager.SaveCallChooseHeroStateKey(act);
+            CloseWindow();
+        });
+        previewButton.SetListener(() =>
+        {
+            HeroUIManager.Instance.selectForPreviewHeroID = manager.nowCallChooseHeroID;
+            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
+        });
+    }
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        manager.OnNowCallChooseHeroIDChangeEvent += OnNowCallChooseHeroIDChangeEvent;
+        manager.nowCallChooseHeroID = manager.GetCurrentDisplayCallHeroId();
+        Display();
+        CreateScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        manager.OnNowCallChooseHeroIDChangeEvent -= OnNowCallChooseHeroIDChangeEvent;
+    }
+
+    private void OnNowCallChooseHeroIDChangeEvent()
+    {
+        Display();
+        scroller.m_Scorller.RefreshActiveCellViews();
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnCallChooseCell;
+        _cell.Display(cell.index);
+    }
+
+    void CreateScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var arr = config.ActHeroIDList;
+        if (arr.IsNullOrEmpty()) return;
+
+
+        scroller.Refresh();
+        int rowCount = (int)Mathf.Ceil((float)arr.Length / rowCountMax);
+        for (int i = 0; i < rowCount; i++)
+        {
+            scroller.AddCell(ScrollerDataType.Header, i);
+        }
+        scroller.Restart();
+    }
+
+    void Display()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+
+        int skinID = manager.GetDefaultSkinID(manager.nowCallChooseHeroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        uiHeroController.Create(skinID, 1);
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallChooseWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallChooseWin.cs.meta
new file mode 100644
index 0000000..bcd91e2
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallChooseWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: df583e8bc2fc9ab47ab8db4a977622bc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallHistoryCell.cs b/Main/System/HeroReturn/HeroReturnCallHistoryCell.cs
new file mode 100644
index 0000000..004969a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallHistoryCell.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnCallHistoryCell : CellView
+{
+    [SerializeField] Color nameColor;
+    [SerializeField] TextEx infoText;
+    public virtual void Display(int index, List<HeroReturnGameRec> list)
+    {
+        if (list?.Count <= index) return;
+        var rec = list[index];
+
+        var itemconfig = ItemConfig.Get(rec.ItemID);
+        if (itemconfig == null) return;
+
+        //150 鏁翠釜姝﹀皢
+        if (itemconfig.Type == 150)
+        {
+            HeroConfig heroConfig = HeroConfig.Get(rec.ItemID);
+            if (heroConfig == null) return;
+            int quality = heroConfig.Quality;
+
+            infoText.text = Language.Get("HeroDebut29",
+                UIHelper.AppendColor(nameColor, rec.PlayerName),
+                UIHelper.AppendColor(UIHelper.GetUIColorByFunc(quality), Language.Get(StringUtility.Concat("CommonQuality", quality.ToString()))),
+                UIHelper.AppendColor(UIHelper.GetUIColorByFunc(quality), heroConfig.Name.ToString())
+            );
+        }
+        else
+        {
+            int quality = itemconfig.ItemColor;
+
+            infoText.text = Language.Get("HeroDebut30",
+                UIHelper.AppendColor(nameColor, rec.PlayerName),
+                UIHelper.AppendColor(UIHelper.GetUIColorByFunc(quality), itemconfig.ItemName.ToString()),
+                rec.ItemCount.ToString()
+            );
+        }
+
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallHistoryCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallHistoryCell.cs.meta
new file mode 100644
index 0000000..2ec4019
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallHistoryCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 38c9c575a3a11064597472dbd5e95a43
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs b/Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs
new file mode 100644
index 0000000..f737547
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnCallHistoryOutCell : HeroReturnCallHistoryCell
+{
+    [SerializeField] CanvasGroup canvasGroup;
+  
+    public override void Display(int index, List<HeroReturnGameRec> list)
+    {
+        base.Display(index, list);
+    }
+
+    // 鎻愪緵缁欏閮ㄨ缃�忔槑搴︾殑鏂规硶
+    public void SetAlpha(float alpha)
+    {
+        if (canvasGroup != null)
+        {
+            canvasGroup.alpha = alpha;
+        }
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs.meta
new file mode 100644
index 0000000..842da88
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8239f369fcc315847a4e250422c234d6
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallHistoryWin.cs b/Main/System/HeroReturn/HeroReturnCallHistoryWin.cs
new file mode 100644
index 0000000..61e5a66
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallHistoryWin.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnCallHistoryWin : UIBase
+{
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] RectTransform noRect;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void OnPreOpen()
+    {
+        scroller.lockType = EnhanceLockType.LockVerticalBottom;
+
+        scroller.OnRefreshCell += OnRefreshCell;
+        manager.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
+
+        CreateScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        manager.OnUpdateGameRecInfo -= OnUpdateGameRecInfo;
+    }
+
+    private void OnUpdateGameRecInfo()
+    {
+        scroller.m_Scorller.RefreshActiveCellViews();
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnCallHistoryCell;
+        _cell.Display(cell.index, list);
+    }
+    public List<HeroReturnGameRec> list;
+
+    void CreateScroller()
+    {
+        list = manager.GetGameRecList();
+        if (list == null)
+        {
+            noRect.SetActive(true);
+            scroller.SetActive(false);
+            return;
+        }
+        noRect.SetActive(false);
+        scroller.SetActive(true);
+
+        scroller.Refresh();
+        for (int i = 0; i < list.Count; i++)
+        {
+            scroller.AddCell(ScrollerDataType.Header, i);
+        }
+        scroller.Restart();
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallHistoryWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallHistoryWin.cs.meta
new file mode 100644
index 0000000..0b1ee58
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallHistoryWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 10151abcb0caf394aa8caa2c00f25bbe
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallRateCell.cs b/Main/System/HeroReturn/HeroReturnCallRateCell.cs
new file mode 100644
index 0000000..a99be23
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateCell.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnCallRateCell : CellView
+{
+    [SerializeField] HeroReturnCallRateItem[] items;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    public void Display(int rowIndex, Dictionary<int, int> gridRateDict, List<int> gridList, XBGetItemConfig xbConfig)
+    {
+        if (gridList == null) return;
+
+        for (int i = 0; i < items.Length; i++)
+        {
+            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
+            if (index < gridList.Count)
+            {
+                items[i].SetActive(true);
+                items[i].Display(index, gridRateDict, gridList, xbConfig);
+            }
+            else
+            {
+                items[i].SetActive(false);
+            }
+        }
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallRateCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallRateCell.cs.meta
new file mode 100644
index 0000000..6e8fa65
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cc363b85a77d3ce4b92b8f4ce95f524f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs b/Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs
new file mode 100644
index 0000000..f6052a4
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnCallRateHeroCell : CellView
+{
+
+    [SerializeField] ItemCell[] itemCells;
+    public void Display(int rowIndex, List<Item> dataList)
+    {
+        if (dataList == null) return;
+
+        for (int i = 0; i < itemCells.Length; i++)
+        {
+            int dataIndex = rowIndex * HeroReturnCallRateHeroWin.rowCountMax + i;
+
+            if (dataIndex < dataList.Count)
+            {
+                itemCells[i].SetActive(true);
+                itemCells[i].Init(new ItemCellModel(dataList[dataIndex].id, true, dataList[dataIndex].countEx));
+                itemCells[i].button.SetListener(() => ItemTipUtility.Show(dataList[dataIndex].id));
+            }
+            else
+            {
+                itemCells[i].SetActive(false);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs.meta
new file mode 100644
index 0000000..cdaec55
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 75a05dc1b9031fa40b0fea8347aceca7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs b/Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs
new file mode 100644
index 0000000..8954cd5
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs
@@ -0,0 +1,119 @@
+using System.Collections.Generic;
+using Cysharp.Threading.Tasks;
+using UnityEngine;
+
+public class HeroReturnCallRateHeroWin : UIBase
+{
+
+    [SerializeField] RectTransform rectTransform;
+    [SerializeField] RectTransform arrowImage;
+    [SerializeField] RectTransform arrowUpImage;
+    [SerializeField] ScrollerController scroller;
+
+    public static Vector3 worldPos; //涓栫晫鍧愭爣绯讳綅缃�
+    public static bool isDownShow = false;  // 鏄惁鍚戜笅鏄剧ず
+    public static List<Item> dataList;
+    public const int rowCountMax = 4;
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+
+        rectTransform.position = new Vector3(100, 100, 100);   //鍒濆鍖栨椂锛屽睆骞曡寖鍥村
+        arrowImage.SetActive(!isDownShow);
+        arrowUpImage.SetActive(isDownShow);
+        CreateScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        isDownShow = false;
+        scroller.OnRefreshCell -= OnRefreshCell;
+    }
+    
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnCallRateHeroCell;
+        _cell.Display(cell.index, dataList);
+    }
+
+    void CreateScroller()
+    {
+        if (dataList == null || dataList.Count == 0) return;
+
+        scroller.Refresh();
+        int rowCount = Mathf.CeilToInt((float)dataList.Count / rowCountMax);
+        for (int i = 0; i < rowCount; i++)
+        {
+            scroller.AddCell(ScrollerDataType.Header, i);
+        }
+        scroller.Restart();
+    }
+
+    protected override void OnOpen()
+    {
+        UpdatePos().Forget();
+    }
+
+    async UniTask UpdatePos()
+    {
+        await UniTask.DelayFrame(3);
+        // 闄愬埗鍦ㄥ睆骞曡寖鍥村唴
+        Vector3[] corners = new Vector3[4];
+        rectTransform.GetWorldCorners(corners);
+
+        float minY = corners[0].y;
+        float maxY = corners[0].y;
+
+        for (int i = 1; i < corners.Length; i++)
+        {
+            if (corners[i].y < minY) minY = corners[i].y;
+            if (corners[i].y > maxY) maxY = corners[i].y;
+        }
+
+
+        float screenHeight = maxY - minY;
+        Vector2 adjustedPos = new Vector2(worldPos.x, worldPos.y + (!isDownShow ? screenHeight * 0.5f : -screenHeight * 0.5f));
+
+        Vector2 screenAdjustedPos = CameraManager.uiCamera.WorldToScreenPoint(adjustedPos);
+        var rectWidth = rectTransform.rect.width * Screen.width / canvasScaler.referenceResolution.x;
+        screenAdjustedPos.x = Mathf.Clamp(screenAdjustedPos.x, rectWidth * 0.5f, Screen.width - rectWidth * 0.5f);
+        screenAdjustedPos.y = Mathf.Clamp(screenAdjustedPos.y, rectTransform.rect.height * 0.5f, Screen.height - rectTransform.rect.height * 0.5f - 15);
+
+        adjustedPos = CameraManager.uiCamera.ScreenToWorldPoint(screenAdjustedPos);
+        rectTransform.position = adjustedPos;
+
+        if (!isDownShow)
+        {
+            rectTransform.localPosition = new Vector3(rectTransform.localPosition.x, rectTransform.localPosition.y + 15, rectTransform.localPosition.z);
+        }
+        else
+        {
+            rectTransform.localPosition = new Vector3(rectTransform.localPosition.x, rectTransform.localPosition.y - 15, rectTransform.localPosition.z);
+        }
+
+        rectTransform.GetWorldCorners(corners);
+        float minX = corners[0].x;
+        float maxX = corners[0].x;
+
+        for (int i = 1; i < corners.Length; i++)
+        {
+            if (corners[i].x < minX) minX = corners[i].x;
+            if (corners[i].x > maxX) maxX = corners[i].x;
+        }
+
+        //鏄剧ずarrowImage 鐨剎杞翠笂鐨勪綅缃紝鍜寃orldPos鍚屾锛屼絾涓嶈秴杩噈inX 鍜� maxX鑼冨洿
+        if (!isDownShow)
+        {
+            Vector3 arrowImagePosition = arrowImage.position;
+            arrowImagePosition.x = Mathf.Clamp(worldPos.x, minX, maxX);
+            arrowImage.position = arrowImagePosition;
+        }
+        else
+        {
+            Vector3 arrowUpImagePosition = arrowUpImage.position;
+            arrowUpImagePosition.x = Mathf.Clamp(worldPos.x, minX, maxX);
+            arrowUpImage.position = arrowUpImagePosition;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs.meta
new file mode 100644
index 0000000..36c3893
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4488cbc55bbabcf43b390ebb827ec1f8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallRateItem.cs b/Main/System/HeroReturn/HeroReturnCallRateItem.cs
new file mode 100644
index 0000000..c03223b
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateItem.cs
@@ -0,0 +1,123 @@
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnCallRateItem : MonoBehaviour
+{
+    [SerializeField] ButtonEx libButton;
+    [SerializeField] ItemCell itemCell;
+    [SerializeField] Text rateText;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int index, Dictionary<int, int> gridRateDict, List<int> gridList, XBGetItemConfig xbConfig)
+    {
+        if (gridList?.Count <= index || gridRateDict?.Count != gridList?.Count || xbConfig == null) return;
+        if (xbConfig?.GridItemInfo == null || xbConfig?.GridLibInfo == null) return;
+        if (manager.xbGridArr == null) return;
+
+        int grid = gridList[index];
+        int rate = gridRateDict[grid];
+        rateText.text = Language.Get("TimingGift02", (double)rate / (double)100.0);
+        SetItemCell(grid, xbConfig.GridItemInfo, xbConfig.GridLibInfo, manager.xbGridArr);
+    }
+
+    public void SetCountActive(ItemCell itemCell, long count)
+    {
+        itemCell.countText.SetActive(count > 1);
+    }
+
+
+    private void SetItemCell(int grid, Dictionary<int, int[]> gridItemInfo, Dictionary<int, int> gridLibInfo, int[] xbGridArr)
+    {
+        libButton.SetActive(false);
+        itemCell.SetActive(false);
+        if (gridItemInfo.TryGetValue(grid, out var itemInfo))
+        {
+            itemCell.SetActive(true);
+            itemCell.Init(new ItemCellModel(itemInfo[0], true, itemInfo[1]));
+            SetCountActive(itemCell, itemInfo[1]);
+            itemCell.button.SetListener(() => ItemTipUtility.Show(itemInfo[0]));
+            return;
+        }
+
+        if (!gridLibInfo.TryGetValue(grid, out var libID)) return;
+
+        var list = TreasureItemLibConfig.GetItemIDList(libID);
+        if (list == null) return;
+        if (xbGridArr == null) return;
+
+        if (xbGridArr.Contains(grid))
+        {
+            int heroID = manager.GetCurrentDisplayCallHeroId();
+            if (!TryGetHeroItemInfo(heroID, libID, list, out int itemID, out int itemCount)) return;
+            itemCell.SetActive(true);
+            itemCell.Init(new ItemCellModel(itemID, true, itemCount));
+            SetCountActive(itemCell, itemCount);
+            itemCell.button.SetListener(() => ItemTipUtility.Show(itemID));
+        }
+        else
+        {
+            libButton.SetActive(true);
+            libButton.SetListener(() =>
+            {
+                HeroReturnCallRateHeroWin.worldPos = libButton.transform.position;
+                HeroReturnCallRateHeroWin.dataList = GetLibItemList(libID, list);
+                HeroReturnCallRateHeroWin.isDownShow = true;
+                UIManager.Instance.OpenWindow<HeroReturnCallRateHeroWin>();
+            });
+        }
+    }
+    public List<Item> GetLibItemList(int libID, List<int> itemList)
+    {
+        List<Item> res = new();
+        for (int i = 0; i < itemList.Count; i++)
+        {
+            int itemID = itemList[i];
+            var config = ItemConfig.Get(itemID);
+            if (config == null) continue;
+
+            if (!TreasureItemLibConfig.TryGetID(libID, itemID, out int id)) continue;
+            var treasureItemLibConfig = TreasureItemLibConfig.Get(id);
+            if (treasureItemLibConfig == null) continue;
+
+            res.Add(new Item(itemID, treasureItemLibConfig.ItemCount));
+        }
+        return res;
+    }
+
+    public bool TryGetHeroItemInfo(int heroID, int libID, List<int> itemList, out int itemID, out int itemCount)
+    {
+        itemID = 0;
+        itemCount = 0;
+        if (itemList == null) return false;
+
+        for (int i = 0; i < itemList.Count; i++)
+        {
+            itemID = itemList[i];
+            var config = ItemConfig.Get(itemID);
+            if (config == null) continue;
+
+            if (!TreasureItemLibConfig.TryGetID(libID, itemID, out int id)) continue;
+            var treasureItemLibConfig = TreasureItemLibConfig.Get(id);
+            if (treasureItemLibConfig == null) continue;
+
+            //鏈綋
+            if (config.Type == 150)
+            {
+                if (heroID == itemID)
+                {
+                    itemCount = treasureItemLibConfig.ItemCount;
+                    return true;
+                }
+            }
+            else if (config.Type == 151)
+            {
+                if (heroID == config.EffectValueA1)
+                {
+                    itemCount = treasureItemLibConfig.ItemCount;
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallRateItem.cs.meta b/Main/System/HeroReturn/HeroReturnCallRateItem.cs.meta
new file mode 100644
index 0000000..fdd6316
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateItem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e8caa7644bce7414d9ada3cef9ee1eff
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallRateWin.cs b/Main/System/HeroReturn/HeroReturnCallRateWin.cs
new file mode 100644
index 0000000..7cfdc2b
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateWin.cs
@@ -0,0 +1,83 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnCallRateWin : UIBase
+{
+    [SerializeField] ScrollerController scroller;
+    public const int rowCountMax = 4;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        CreateScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnCallRateCell;
+        _cell.Display(cell.index, gridRateDict, gridList, xbConfig);
+    }
+
+    Dictionary<int, int> gridRateDict;
+    List<int> gridList;
+    XBGetItemConfig xbConfig;
+    void CreateScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        xbConfig = HappyXBModel.Instance.GetXBItemConfigByType(config.ActTreasureType);
+        if (xbConfig == null || xbConfig.GridItemRateList1 == null) return;
+
+        gridRateDict = GetGridRateDict(xbConfig.GridItemRateList1);
+        if (gridRateDict == null) return;
+
+        gridList = GetSortedGridList();
+        if (gridList == null) return;
+
+        scroller.Refresh();
+        int rowCount = (int)Mathf.Ceil((float)gridList.Count / rowCountMax);
+        for (int i = 0; i < rowCount; i++)
+        {
+            scroller.AddCell(ScrollerDataType.Header, i);
+        }
+        scroller.Restart();
+    }
+
+    //<鏍煎瓙,涓囧垎鐜�>
+    public Dictionary<int, int> GetGridRateDict(int[][] gridItemRateList1)
+    {
+        Dictionary<int, int> res = new();
+        for (int i = 0; i < gridItemRateList1.Length; i++)
+        {
+            res[gridItemRateList1[i][1]] = i == 0 ?
+                gridItemRateList1[i][0] :
+                gridItemRateList1[i][0] - gridItemRateList1[i - 1][0];
+        }
+        return res;
+    }
+
+    public List<int> GetSortedGridList()
+    {
+        if (gridRateDict == null || gridRateDict.Count == 0) return null;
+        List<int> sortedGrids = new List<int>(gridRateDict.Keys);
+        sortedGrids.Sort();
+        // sortedGrids.Sort((a, b) =>
+        // {
+        //     int rateA = gridRateDict[a];
+        //     int rateB = gridRateDict[b];
+        //     return rateA.CompareTo(rateB);
+        // });
+
+        return sortedGrids;
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallRateWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallRateWin.cs.meta
new file mode 100644
index 0000000..89864dd
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallRateWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3dc8fff9b1f118d4682a6541f30741a0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallResultCell.cs b/Main/System/HeroReturn/HeroReturnCallResultCell.cs
new file mode 100644
index 0000000..d1b00cb
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallResultCell.cs
@@ -0,0 +1,104 @@
+using UnityEngine;
+using DG.Tweening;
+
+public class HeroReturnCallResultCell : MonoBehaviour
+{
+    [SerializeField] public ItemCell itemCell;
+    [SerializeField] UIEffectPlayer orbBaseEffect;    // 鍒濆鐘舵�佺壒鏁�
+    [SerializeField] UIEffectPlayer orbBoomEffect;    // 鐖嗗彂鐬棿鐗规晥
+    [SerializeField] UIEffectPlayer orbQualityEffect; // 鍝佽川搴曡壊鐗规晥
+    [SerializeField] UIEffectPlayer flowEffect;       // 鏈�缁堟祦鍏夌壒鏁�
+
+    [HideInInspector] public Vector3 originalLocalPos;
+
+    void Awake()
+    {
+        // 璁板綍鍒濆鏈湴鍧愭爣锛岀敤浜庡彂鐗屽姩鐢荤殑褰掍綅
+        originalLocalPos = transform.localPosition;
+    }
+
+    /// <summary>
+    /// 鍒濆鍖栨牸瀛愭暟鎹�
+    /// </summary>
+    public void DisplayItemCell(int itemID, int count)
+    {
+        itemCell.Init(new ItemCellModel(itemID, true, count));
+        itemCell.button.SetListener(() => ItemTipUtility.Show(itemID));
+    }
+
+    /// <summary>
+    /// 閲嶇疆鎵�鏈� UI 鍏冪礌鍜岀壒鏁堣嚦鍒濆鐘舵��
+    /// </summary>
+    public void ResetState()
+    {
+        itemCell.gameObject.SetActive(false);
+        orbBaseEffect.SetActive(false);
+        orbBoomEffect.SetActive(false);
+        orbQualityEffect.SetActive(false);
+        flowEffect.SetActive(false);
+    }
+
+    /// <summary>
+    /// 闃舵 1锛氭挱鏀惧垵濮嬪紩瀵煎厜鐐癸紙椋炶闃舵锛�
+    /// </summary>
+    public void PlayInitialOrb()
+    {
+        orbBaseEffect.SetActive(true);
+        orbBoomEffect.SetActive(false);
+        orbQualityEffect.SetActive(false);
+
+        orbBaseEffect.Play(4); // 鎾斁绱㈠紩涓�4鐨勯�氱敤椋炶鏁�
+    }
+
+    /// <summary>
+    /// 闃舵 2 & 3锛氭墽琛岀垎寮�銆佹樉鑹层�佺炕鐗屻�佸睍绀烘祦鍏夌殑缁勫悎搴忓垪
+    /// </summary>
+    /// <param name="qualityIndex">鍝佽川搴曡壊鐗规晥绱㈠紩</param>
+    /// <param name="flowQualityIndex">鏈�缁堟祦鍏夌壒鏁堢储寮�</param>
+    /// <returns>杩斿洖 Sequence 鏂逛究澶栭儴杩涜 Stagger锛堜氦閿欙級鎺掑垪</returns>
+    public Tween PlayExplosionFadeAndFlipReveal(int qualityIndex, int flowQualityIndex)
+    {
+        Sequence seq = DOTween.Sequence();
+
+        // [0.0s] 鍒囨崲鐗规晥锛氬叧闂琛屾�侊紝瑙﹀彂鐖嗗彂鎬�
+        seq.InsertCallback(0f, () =>
+        {
+            orbBaseEffect.SetActive(false);
+            orbBoomEffect.SetActive(true);
+            orbBoomEffect.Play(3);
+        });
+
+        // [0.2s] 灞曠ず鍝佽川鍩鸿壊
+        seq.InsertCallback(0.2f, () =>
+        {
+            orbQualityEffect.transform.localScale = Vector3.zero;
+            orbQualityEffect.SetActive(true);
+            orbQualityEffect.Play(qualityIndex);
+        });
+
+        // 鍝佽川鍏夊洟鐢卞皬鍙樺ぇ鐨勫洖寮瑰姩鐢�
+        seq.Insert(0.2f, orbQualityEffect.transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack));
+
+        // [0.8s] 鍑嗗缈荤墝锛氭縺娲� ItemCell 骞惰缃� 90 搴︿晶鍚戯紝鍑嗗鏃嬭浆
+        seq.InsertCallback(0.8f, () =>
+        {
+            itemCell.gameObject.SetActive(true);
+            itemCell.transform.localEulerAngles = new Vector3(0, 90f, 0);
+        });
+
+        // [0.8s] 缈昏浆鍔ㄤ綔锛堣�楁椂 0.3s锛夛細浠� 90 搴︽棆杞洖 0 搴�
+        seq.Insert(0.8f, itemCell.transform.DOLocalRotate(Vector3.zero, 0.3f, RotateMode.Fast).SetEase(Ease.OutSine));
+
+        // [1.1s] 搴忓垪瀹岀粨锛氭竻鐞嗕复鏃剁壒鏁堬紝婵�娲绘寔涔呮祦鍏�
+        seq.InsertCallback(1.1f, () =>
+        {
+            orbBoomEffect.SetActive(false);
+            orbQualityEffect.SetActive(false); 
+
+            flowEffect.SetActive(true);
+            flowEffect.Play(flowQualityIndex); 
+        });
+
+        return seq;
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnCallResultCell.cs.meta b/Main/System/HeroReturn/HeroReturnCallResultCell.cs.meta
new file mode 100644
index 0000000..15b417e
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallResultCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aa9f5a1a80f17304b84d946832fe6381
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallResultWin.cs b/Main/System/HeroReturn/HeroReturnCallResultWin.cs
new file mode 100644
index 0000000..994a845
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallResultWin.cs
@@ -0,0 +1,370 @@
+using UnityEngine;
+using DG.Tweening;
+using System.Collections.Generic;
+
+public class HeroReturnCallResultWin : UIBase
+{
+    [SerializeField] Transform moneyRect;
+    [SerializeField] OwnItemCell ownItemCell;
+    [SerializeField] ItemCell presentItemCell;         // 鎶藉崱鑾峰緱鐨勮禒閫侀亾鍏�
+    [SerializeField] RectTransform oneRect;             // 鍗曟娊瀹瑰櫒涓績鐐�
+    [SerializeField] HeroReturnCallResultCell oneCell;   // 鍗曟娊鍗曞厓鏍�
+    [SerializeField] RectTransform tenRect;             // 鍗佽繛瀹瑰櫒
+    [SerializeField] HeroReturnCallResultCell[] tenCell; // 鍗佽繛鍗曞厓鏍兼暟缁�
+
+    [SerializeField] UIEffectPlayer firstEffect;        // 寮�灞忓垵濮嬬壒鏁�
+
+    [SerializeField] HeroReturnCallButton callButton;    // 鍐嶆鎶藉彇鎸夐挳
+    [SerializeField] ButtonEx okButton;                 // 纭畾杩斿洖鎸夐挳
+
+
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    HappyXBModel xbManager => HappyXBModel.Instance;
+
+    bool isSkip;            // 鏄惁璺宠繃鍔ㄧ敾
+    int treasureType;       // 鎶藉崱瀹濆簱绫诲瀷
+    bool isOne = false;     // 鏄惁涓哄崟鎶芥ā寮�
+
+    private Sequence animSeq; // 涓诲姩鐢诲簭鍒�
+
+    protected override void InitComponent()
+    {
+        okButton.SetListener(CloseWindow);
+    }
+
+    protected override void OnPreOpen()
+    {
+        animSeq?.Kill();
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        treasureType = config.ActTreasureType;
+        // 鏍规嵁閰嶇疆鍜屾椂闂存埑鍔犺浇鐢ㄦ埛鐨勬槸鍚﹁烦杩囧姩鐢昏缃�
+        isSkip = manager.LoadCallSkipData(config.CfgID, act.startDate, act.endDate);
+
+        // 缁戝畾鏁版嵁鍒锋柊鍥炶皟
+        HappyXBModel.Instance.RefreshXBResultAct += RefreshXBResultAct;
+        HappyXBModel.Instance.RefreshXBTypeInfoAct += OnRefreshXBTypeInfoAct;
+
+        var treasureSetConfig = TreasureSetConfig.Get(config.ActTreasureType);
+        if (treasureSetConfig == null) return;
+        ownItemCell.itemID = treasureSetConfig.CostItemID;
+
+        RefreshXBResultAct();
+    }
+
+    protected override void OnPreClose()
+    {
+        animSeq?.Kill();
+        // 瑙g粦鍥炶皟锛岄槻姝㈠唴瀛樻硠婕�
+        HappyXBModel.Instance.RefreshXBResultAct -= RefreshXBResultAct;
+        HappyXBModel.Instance.RefreshXBTypeInfoAct -= OnRefreshXBTypeInfoAct;
+    }
+
+    /// <summary>
+    /// 鍒锋柊鎶藉崱缁撴灉鐣岄潰
+    /// </summary>
+    void RefreshXBResultAct()
+    {
+        isOne = HeroUIManager.Instance.selectCallIndex == 0;
+
+        // 鍒濆鍖栭《閮ㄨ禒閫佺墿鍝�
+        int itemId = xbManager.addXBAddItemID;
+        long count = xbManager.addXBItemCount;
+        presentItemCell.Init(new ItemCellModel(itemId, true, count));
+        presentItemCell.button.SetListener(() => ItemTipUtility.Show(itemId));
+
+        // 鏍规嵁鍗曟娊鎴栧崄杩炲~鍏呯墿鍝佹暟鎹�
+        if (isOne)
+        {
+            if (!xbManager.xbResultDict.IsNullOrEmpty())
+            {
+                oneCell.DisplayItemCell(xbManager.xbResultDict[0].itemId, xbManager.xbResultDict[0].count);
+            }
+        }
+        else
+        {
+            for (int i = 0; i < tenCell.Length; i++)
+            {
+                if (i < xbManager.xbResultDict?.Count)
+                {
+                    tenCell[i].DisplayItemCell(xbManager.xbResultDict[i].itemId, xbManager.xbResultDict[i].count);
+                }
+            }
+        }
+
+        callButton.Display(treasureType, HeroUIManager.Instance.selectCallIndex);
+
+        if (isSkip)
+        {
+            // 妯″紡锛氳烦杩囧姩鐢伙紝鐩存帴鏄剧ず鏈�缁堢姸鎬�
+            firstEffect.SetActive(false);
+            ShowImmediate();
+        }
+        else
+        {
+            // 妯″紡锛氭挱鏀惧畬鏁村睍绀哄姩鐢�
+            PrepareAnimation();
+            firstEffect.SetActive(true);
+            firstEffect.Play(0);
+
+            // 棰勭暀 1.1s 鐨勫紑灞忓姩鏁堟椂闂村悗锛屽紑濮嬫挱鏀惧彂鐗�/缈荤墝搴忓垪
+            PlayResultAnimation(1.1f);
+        }
+    }
+
+    private void OnRefreshXBTypeInfoAct() { RefreshXBResultAct(); }
+
+    /// <summary>
+    /// 闈欐�佹樉绀猴紙鏃犲姩鐢荤洿鎺ュ睍绀虹粨鏋滐級
+    /// </summary>
+    private void ShowImmediate()
+    {
+        animSeq?.Kill();
+        oneRect.SetActive(isOne);
+        tenRect.SetActive(!isOne);
+
+        ownItemCell.SetActive(true);
+        moneyRect.SetActive(true);
+        presentItemCell.SetActive(true);
+        callButton.SetActive(true);
+        okButton.SetActive(true);
+
+        if (isOne)
+        {
+            oneCell.SetActive(true);
+            oneCell.ResetState();
+            oneCell.itemCell.SetActive(true);
+        }
+        else
+        {
+            for (int i = 0; i < tenCell.Length; i++)
+            {
+                if (i < xbManager.xbResultDict?.Count)
+                {
+                    tenCell[i].SetActive(true);
+                    tenCell[i].transform.localPosition = tenCell[i].originalLocalPos;
+                    tenCell[i].ResetState();
+                    tenCell[i].itemCell.SetActive(true);
+                }
+                else
+                {
+                    tenCell[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// 鍔ㄧ敾鍓嶇疆鍑嗗锛堥殣钘忓厓绱犲苟閲嶇疆鍧愭爣锛�
+    /// </summary>
+    private void PrepareAnimation()
+    {
+        oneRect.SetActive(isOne);
+        tenRect.SetActive(!isOne);
+
+        ownItemCell.SetActive(false);
+        moneyRect.SetActive(false);
+        presentItemCell.SetActive(false);
+        callButton.SetActive(false);
+        okButton.SetActive(false);
+
+        if (isOne)
+        {
+            oneCell.SetActive(true);
+            oneCell.ResetState();
+        }
+        else
+        {
+            for (int i = 0; i < tenCell.Length; i++)
+            {
+                if (i < xbManager.xbResultDict?.Count)
+                {
+                    tenCell[i].SetActive(true);
+                    tenCell[i].ResetState();
+                    tenCell[i].transform.localPosition = tenCell[i].originalLocalPos;
+                }
+                else
+                {
+                    tenCell[i].SetActive(false);
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// 鏍稿績閫昏緫锛氱紪鎺掔粨鏋滃睍绀哄姩鐢绘椂闂磋酱
+    /// </summary>
+    private void PlayResultAnimation(float startDelay = 0f)
+    {
+        animSeq?.Kill();
+        animSeq = DOTween.Sequence();
+
+        if (isOne)
+        {
+            // ==================== 鍗曟娊鍔ㄧ敾閫昏緫 ====================
+            float timelineCursor = startDelay;
+
+            // 1. 鎾斁涓績鍏夊洟
+            animSeq.InsertCallback(timelineCursor, () => oneCell.PlayInitialOrb());
+
+            // 棰勭暀鐭殏鐨勫睍绀烘椂闂�
+            float finishShowTime = 0.12f;
+            timelineCursor += finishShowTime;
+
+            // 2. 瑙﹀彂鐖嗗紑涓庣炕鐗岀粍鍚堝姩鐢�
+            int itemId = xbManager.xbResultDict[0].itemId;
+            int quality = GetOrbQuality(itemId);
+            int flowQuality = GetFlowQuality(itemId);
+
+            animSeq.Insert(timelineCursor, oneCell.PlayExplosionFadeAndFlipReveal(quality, flowQuality));
+
+            // 鎺ㄨ繘娓告爣鑷崇粍鍚堝姩鐢荤粨鏉燂紙1.1s鍩虹鏃堕暱 + 0.3s缂撳啿锛�
+            timelineCursor += 1.4f;
+
+            // 3. 寮瑰嚭搴曢儴 UI
+            animSeq.InsertCallback(timelineCursor, ShowBottomUI);
+        }
+        else
+        {
+            // ==================== 鍗佽繛鍔ㄧ敾閫昏緫 ====================
+            int count = xbManager.xbResultDict.Count;
+            float staggerInterval = 0.1f; // 鍙戠墝闂撮殧
+            float moveDuration = 0.12f;    // 椋炶鏃堕棿
+            float timelineCursor = startDelay;
+
+            // 1. 渚濇浠庝腑蹇冪偣鍚戠洰鏍囦綅缃彂灏勫厜鍥紙鍙戠墝闃舵锛�
+            for (int i = 0; i < count; i++)
+            {
+                var cell = tenCell[i];
+                cell.transform.position = oneRect.position; // 璧峰浜庝腑蹇�
+                float delay = timelineCursor + i * staggerInterval;
+
+                animSeq.InsertCallback(delay, () => cell.PlayInitialOrb());
+                animSeq.Insert(delay, cell.transform.DOLocalMove(cell.originalLocalPos, moveDuration).SetEase(Ease.OutCubic));
+            }
+
+            // 璁$畻鎵�鏈夊崱鐗屽畬鎴愰琛岀殑鏃跺埢
+            float finishFlyingTime = ((count - 1) * staggerInterval) + moveDuration;
+            timelineCursor += finishFlyingTime;
+
+            // 2. 渚濇瑙﹀彂鐖嗗紑缈荤墝鍔ㄧ敾锛堝睍绀洪樁娈碉級
+            for (int i = 0; i < count; i++)
+            {
+                int itemId = xbManager.xbResultDict[i].itemId;
+                int quality = GetOrbQuality(itemId);
+                int flowQuality = GetFlowQuality(itemId);
+
+                animSeq.Insert(timelineCursor + i * staggerInterval, tenCell[i].PlayExplosionFadeAndFlipReveal(quality, flowQuality));
+            }
+
+            // 璁$畻鍏ㄩ儴鍗$墝缈昏浆瀹屾垚鐨勬椂闂寸偣骞跺姞鍏ョ紦鍐�
+            float finalFlipDuration = 1.1f + ((count - 1) * staggerInterval) + 0.3f;
+            timelineCursor += finalFlipDuration;
+
+            // 3. 寮瑰嚭搴曢儴 UI
+            animSeq.InsertCallback(timelineCursor, ShowBottomUI);
+        }
+    }
+
+    /// <summary>
+    /// 灞曠ず搴曢儴鎿嶄綔鎸夐挳锛屽苟妫�鏌ユ槸鍚﹁Е鍙戞灏嗙珛缁�
+    /// </summary>
+    private void ShowBottomUI()
+    {
+        ownItemCell.SetActive(true);
+        moneyRect.SetActive(true);
+        presentItemCell.SetActive(true);
+        callButton.SetActive(true);
+        okButton.SetActive(true);
+
+        presentItemCell.transform.localScale = Vector3.zero;
+        callButton.transform.localScale = Vector3.zero;
+        okButton.transform.localScale = Vector3.zero;
+
+        Sequence bottomSeq = DOTween.Sequence();
+        bottomSeq.Append(presentItemCell.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack));
+        bottomSeq.Join(callButton.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack));
+        bottomSeq.Join(okButton.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack));
+
+        bottomSeq.OnComplete(() =>
+        {
+            if (!isSkip)
+            {
+                CheckAndShowHeroLH();
+            }
+        });
+        animSeq.Append(bottomSeq);
+    }
+
+    /// <summary>
+    /// 妫�娴嬪苟灞曠ず楂樺搧璐ㄦ灏嗙珛缁橈紙寮圭獥灞曠ず锛�
+    /// </summary>
+    private void CheckAndShowHeroLH()
+    {
+        // 娓呯悊缂撳瓨鍒楄〃
+        ItemLogicUtility.Instance.poplhHeroIdList.Clear();
+
+        List<int> uniqueHeroIds = new List<int>();
+        int count = xbManager.xbResultDict.Count;
+
+        for (int i = 0; i < count; i++)
+        {
+            int itemId = xbManager.xbResultDict[i].itemId;
+
+            // 浠呭 HeroConfig 涓瓨鍦ㄧ殑瀹屾暣姝﹀皢杩涜澶勭悊
+            if (HeroConfig.HasKey(itemId))
+            {
+                // 浠呭睍绀洪珮浜庤瀹氬搧璐ㄧ殑姝﹀皢
+                if (HeroConfig.Get(itemId).Quality < HappyXBModel.Instance.lhQuality) continue;
+
+                if (!uniqueHeroIds.Contains(itemId))
+                {
+                    uniqueHeroIds.Add(itemId);
+                }
+            }
+        }
+
+        // 濡傛灉瀛樺湪绗﹀悎鏉′欢鐨勬灏嗭紝鎵撳紑澶у浘灞曠ず鐣岄潰
+        if (uniqueHeroIds.Count > 0)
+        {
+            ItemLogicUtility.Instance.poplhHeroIdList = uniqueHeroIds;
+
+            if (!UIManager.Instance.IsOpenedInList<HeroShowLHWin>())
+            {
+                UIManager.Instance.OpenWindow<HeroShowLHWin>();
+            }
+        }
+    }
+
+    // --- 杈呭姪鏂规硶锛氭槧灏勯厤缃搧璐ㄥ埌鐗规晥绱㈠紩 ---
+
+    private int GetOrbQuality(int itemId)
+    {
+        int qualityLevel = ItemConfig.Get(itemId).ItemColor;
+        switch (qualityLevel)
+        {
+            case 2: return 5; // 绱壊
+            case 3: return 2; // 榛勮壊
+            case 4: return 0; // 姗欒壊
+            case 5: return 1; // 绾㈣壊
+            default: return 0;
+        }
+    }
+
+    private int GetFlowQuality(int itemId)
+    {
+        int qualityLevel = ItemConfig.Get(itemId).ItemColor;
+        switch (qualityLevel)
+        {
+            case 2: return 3; // 绱壊
+            case 3: return 2; // 榛勮壊
+            case 4: return 0; // 姗欒壊
+            case 5: return 1; // 绾㈣壊
+            default: return 0;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnCallResultWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallResultWin.cs.meta
new file mode 100644
index 0000000..4667613
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallResultWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fafde75987e7b864ea3c2faa42578100
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCallWin.cs b/Main/System/HeroReturn/HeroReturnCallWin.cs
new file mode 100644
index 0000000..cb85902
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallWin.cs
@@ -0,0 +1,417 @@
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+using DG.Tweening;
+using System.Linq;
+using EnhancedUI.EnhancedScroller;
+
+public class HeroReturnCallWin : UIBase
+{
+    [SerializeField] RawImage chooseHeroBgImage;
+    [SerializeField] ButtonEx chooseHeroButton;
+    [SerializeField] ImageEx chooseHeroImage1;
+    [SerializeField] ImageEx chooseHeroImage2;
+    [SerializeField] Transform lhTransform;
+    [SerializeField] Transform heroCallTransform;
+    [SerializeField] Transform topTransform;
+    [SerializeField] Transform heroInfoTransform;
+
+
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] RectTransform changeRect;
+    [SerializeField] UIEffectPlayer changeUIEffect;
+
+    [SerializeField] OwnItemCell ownItemCell;
+    [SerializeField] ButtonEx closeBtn;
+    [SerializeField] Toggle skipToggle;
+    [SerializeField] HeroReturnCallButton xbButton1;
+    [SerializeField] HeroReturnCallButton xbButton10;
+    [SerializeField] TextEx resMoneyCallCntText;
+    [SerializeField] TextEx nextBigAwardCntText;
+    [SerializeField] GradientText heroQualityText;
+    [SerializeField] GradientText heroNameText;
+
+    [SerializeField] TextEx timeText;
+
+    [SerializeField] TextEx nameText;
+    [SerializeField] TextEx descText;
+    [SerializeField] ImageEx countryImage;
+    [SerializeField] ImageEx jobImage;
+    [SerializeField] ButtonEx changeHeroButton;//鏇存崲鑻遍泟
+    [SerializeField] ButtonEx previewButton;//婊$骇棰勮
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] ButtonEx shopButton; // 鍏戞崲鍟嗗簵
+    [SerializeField] RedpointBehaviour shopRedpoint;
+    [SerializeField] ButtonEx giftButton; // 鐨囨潈绀煎寘
+    [SerializeField] RedpointBehaviour giftRedpoint;
+
+    [SerializeField] ButtonEx rankButton;
+    [SerializeField] TextEx[] top3NameText;
+    [SerializeField] TextEx rankTipText;
+    [SerializeField] ButtonEx rateButton;
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] ButtonEx historyButton;
+    [SerializeField] UIHeroController lhController;
+    [SerializeField] UIHeroController uiHeroController;
+    [SerializeField] HeroReturnCallBubbleCell[] bubbleCell;
+
+    [SerializeField] float modleSize = 1f;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        shopButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnShopWin>());
+        giftButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnGiftWin>());
+        changeHeroButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallChangeWin>());
+        rankButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnRankWin>());
+        rateButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallRateWin>());
+        historyButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallHistoryWin>());
+        chooseHeroButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallChooseWin>());
+        previewButton.SetListener(OnClickPreview);
+        skipToggle.AddListener((value) =>
+        {
+            manager.SaveCallSkipData(config.CfgID, act.startDate, act.endDate, value);
+        });
+    }
+
+
+    protected override void OnPreOpen()
+    {
+        scroller.lockType = EnhanceLockType.LockVerticalBottom;
+        RankModel.Instance.ResetQueryParam();
+        RankModel.Instance.QueryRankByPage(manager.sendRankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID, groupValue1: manager.actNum);
+
+        HappyXBModel.Instance.RefreshXBTypeInfoAct += OnRefreshXBTypeInfoAct;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        RankModel.Instance.onRankRefresh += OnRankRefresh;
+        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
+        PackManager.Instance.RefreshItemEvent += RefreshItemEvent;
+        scroller.OnRefreshCell += OnRefreshCell;
+        manager.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
+        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
+
+        if (manager.isSendFirst)
+        {
+            act = manager.GetOperationHeroAppearInfo();
+            if (act == null) return;
+
+            config = ActHeroAppearConfig.Get(act.CfgID);
+            if (config == null) return;
+
+            int treasureType = config.ActTreasureType;
+            manager.SendViewGameRecPack(treasureType);
+        }
+
+        InitRedpoint();
+        CreateScroller();
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        HappyXBModel.Instance.RefreshXBTypeInfoAct -= OnRefreshXBTypeInfoAct;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        RankModel.Instance.onRankRefresh -= OnRankRefresh;
+        PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh;
+        PackManager.Instance.RefreshItemEvent -= RefreshItemEvent;
+        scroller.OnRefreshCell -= OnRefreshCell;
+        manager.OnUpdateGameRecInfo -= OnUpdateGameRecInfo;
+        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
+    }
+
+
+
+    private Sequence heroAnimSeq;
+
+    private void OnUpdateHeroAppearPlayerInfoEvent()
+    {
+        changeRect.SetActive(false);
+
+        if (heroAnimSeq != null)
+        {
+            heroAnimSeq.Kill();
+            heroAnimSeq = null;
+        }
+
+        Display();
+
+        Transform targetTrans = lhController.transform;
+
+        // 鍋滄 Transform 涓婂彲鑳芥畫鐣欑殑鍗曠嫭鍔ㄧ敾
+        targetTrans.DOKill();
+
+        int heroID = manager.GetCurrentDisplayCallHeroId();
+        int skinID = manager.GetDefaultSkinID(heroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+
+        float baseScaleValue = 1f; // 榛樿缂╂斁
+        if (skinConfig != null && skinConfig.TachieParam != null && skinConfig.TachieParam.Length == 4)
+        {
+            baseScaleValue = skinConfig.TachieParam[2];
+        }
+
+        Vector3 baseScale = Vector3.one * baseScaleValue;
+
+        targetTrans.localScale = baseScale;
+
+        CanvasGroup cg = lhController.GetComponent<CanvasGroup>();
+        if (cg == null) cg = lhController.gameObject.AddComponent<CanvasGroup>();
+        cg.DOKill();
+        cg.alpha = 0.8f;
+
+        changeUIEffect.Play();
+
+        heroAnimSeq = DOTween.Sequence();
+
+        heroAnimSeq.Append(targetTrans.DOScale(baseScale * 1.1f, 0.3f).SetEase(Ease.OutQuad));
+        heroAnimSeq.Append(targetTrans.DOScale(baseScale, 0.3f).SetEase(Ease.InQuad));
+
+        heroAnimSeq.Join(cg.DOFade(1f, 0.3f).SetEase(Ease.Linear));
+
+        heroAnimSeq.OnComplete(() =>
+        {
+            changeRect.SetActive(true);
+            heroAnimSeq = null;
+        });
+    }
+
+    private void OnUpdateGameRecInfo()
+    {
+        CreateScroller();
+    }
+
+    public void RefreshItemEvent(PackType packType, int index, int itemID)
+    {
+        if (packType != PackType.Item && treasureSetConfig?.CostItemID != itemID) return;
+        Display();
+    }
+    private void PlayerDataRefresh(PlayerDataType type)
+    {
+        if (type != PlayerDataType.Gold) return;
+        Display();
+    }
+
+    private void OnRankRefresh(int type)
+    {
+        if (type != manager.sendRankType) return;
+        ShowTop3();
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+
+    private void OnRefreshXBTypeInfoAct()
+    {
+        Display();
+    }
+
+    public void InitRedpoint()
+    {
+        shopRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Shop);
+        giftRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Gift);
+    }
+
+    private void OnClickPreview()
+    {
+        if (heroConfig == null) return;
+        HeroUIManager.Instance.selectForPreviewHeroID = heroConfig.HeroID;
+        UIManager.Instance.OpenWindow<HeroBestBaseWin>();
+    }
+    OperationHeroAppearInfo act;
+    ActHeroAppearConfig config;
+    HeroConfig heroConfig;
+    TreasureSetConfig treasureSetConfig;
+    XBTypeInfo xbTypeInfo;
+    private void Display()
+    {
+        act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int heroID = manager.GetCurrentDisplayCallHeroId();
+        heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null) return;
+
+        int skinID = manager.GetDefaultSkinID(heroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null || artConfig.CallBubbleItems == null) return;
+
+        int treasureType = config.ActTreasureType;
+        treasureSetConfig = TreasureSetConfig.Get(treasureType);
+        if (treasureSetConfig == null) return;
+
+        xbTypeInfo = HappyXBModel.Instance.GetXBInfoByType(treasureType);
+        if (xbTypeInfo == null) return;
+
+        bool canChooseHero = !manager.IsSingleHero(act);
+        bool isChooseHero = manager.LoadCallChooseHeroStateKey(act);
+        chooseHeroBgImage.SetActive(canChooseHero && !isChooseHero);
+        chooseHeroButton.SetActive(canChooseHero && !isChooseHero);
+        chooseHeroImage1.SetActive(canChooseHero && !isChooseHero);
+        chooseHeroImage2.SetActive(canChooseHero && !isChooseHero);
+        lhTransform.SetActive(!canChooseHero || isChooseHero);
+        heroCallTransform.SetActive(!canChooseHero || isChooseHero);
+        topTransform.SetActive(!canChooseHero || isChooseHero);
+        heroInfoTransform.SetActive(!canChooseHero || isChooseHero);
+
+        bgImage.SetSprite(artConfig.MainBgImage);
+
+        lhController.Create(skinID, 1, motionName: "", isLh: true);
+        uiHeroController.Create(skinID, modleSize);
+        uiHeroController.transform.localScale = new Vector3(modleSize, modleSize, modleSize);
+
+        ownItemCell.itemID = treasureSetConfig.CostItemID;
+        skipToggle.isOn = manager.LoadCallSkipData(config.CfgID, act.startDate, act.endDate);
+
+        xbButton1.Display(config.ActTreasureType, 0);
+        xbButton10.Display(config.ActTreasureType, 1);
+        resMoneyCallCntText.text = Language.Get("HeroDebut24", Mathf.Max(treasureSetConfig.DailyMaxCountMoney - xbTypeInfo.treasureCountTodayGold, 0));
+
+        var needCount = GetNextXBCountForBigAward(treasureType);
+        nextBigAwardCntText.text = Language.Get("HeroDebut08", needCount.ToString());
+
+        heroQualityText.text = Language.Get($"heroCallQaulity{heroConfig.Quality}");
+        manager.SetheroQaulityColor(heroQualityText, heroConfig.Quality);
+
+        nameText.text = heroConfig.Name;
+        nameText.color = UIHelper.GetUIColorByFunc(heroConfig.Quality);
+        descText.text = heroConfig.Desc;
+        countryImage.SetSprite(HeroUIManager.Instance.GetCountryIconName(heroConfig.Country));
+        jobImage.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
+
+        heroNameText.text = heroConfig.Name;
+        manager.SetGradientTextColor(heroNameText, artConfig.HeroNameColor);
+
+        for (int i = 0; i < bubbleCell.Length; i++)
+        {
+            if (i < artConfig.CallBubbleItems.Length)
+            {
+                bubbleCell[i].SetActive(true);
+                bubbleCell[i].Display(artConfig.CallBubbleItems[i][0], artConfig.CallBubbleItems[i][1]);
+            }
+            else
+            {
+                bubbleCell[i].SetActive(false);
+            }
+        }
+
+        ShowTop3();
+        OnSecondEvent();
+    }
+
+    public int GetNextXBCountForBigAward(int type)
+    {
+        XBTypeInfo typeInfo = HappyXBModel.Instance.GetXBInfoByType(type);
+        if (typeInfo == null) return 0;
+
+        var xbConfig = HappyXBModel.Instance.GetXBItemConfigByType(type);
+        var luckList = xbConfig.LuckyItemRateInfo.Keys.ToList();
+        luckList.Sort();
+        for (int i = 0; i < luckList.Count; i++)
+        {
+            var luckyValue = typeInfo.luckValue;
+            if (luckyValue < luckList[i])
+            {
+                return luckList[i] - luckyValue;
+            }
+        }
+        return 0;
+    }
+    void ShowTop3()
+    {
+        for (int i = 0; i < top3NameText.Length; i++)
+        {
+            var rankData = RankModel.Instance.GetRankDataByRank(manager.loadRankType, i + 1);
+            top3NameText[i].text = rankData == null ? Language.Get("L1124") : rankData.name1;
+        }
+        int billTempID = config.BillTempID;
+        rankTipText.text = Language.Get("HeroDebut27", ActBillboardAwardConfig.GetTop3MinCalNeedValue(billTempID));
+    }
+    public List<HeroReturnGameRec> list;
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnCallHistoryOutCell;
+        _cell.Display(cell.index, list);
+    }
+
+    float autoScrollInterval = 2f;
+    private float autoScrollTimer = 0f;
+    private int currentScrollerIndex = 0;
+    private bool isScrollerReady = false; // 鍒ゅ畾鏍囧織
+    void CreateScroller()
+    {
+        list = manager.GetGameRecList();
+        scroller.Refresh();
+
+        int listCount = list?.Count ?? 0;
+        if (list != null)
+        {
+            for (int i = 0; i < listCount; i++)
+            {
+                scroller.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+
+
+        bool canScroll = listCount > 4;// 鍙湁鏁伴噺 > 4 鏃舵墠寮�鍚� Loop 鍜岃鏃跺櫒
+        scroller.m_Scorller.Loop = canScroll;
+        isScrollerReady = canScroll;
+
+        scroller.vertical = false;
+        scroller.horizontal = false;
+        scroller.Restart();
+
+        // 濡傛灉鏄惊鐜ā寮忥紝纭繚鍒濆浣嶇疆姝g‘
+        if (canScroll)
+        {
+            scroller.m_Scorller.JumpToDataIndex(0,
+            tweenType: EnhancedScroller.TweenType.immediate);
+        }
+        autoScrollTimer = 0f;
+        currentScrollerIndex = 0;
+    }
+
+    private void LateUpdate()
+    {
+        // 鍙湁鍦ㄦ暟鎹氨缁笖瓒呰繃 4 涓椂锛屾墠鎵ц璁℃椂閫昏緫
+        if (isScrollerReady)
+        {
+            autoScrollTimer += Time.deltaTime;
+            if (autoScrollTimer >= autoScrollInterval)
+            {
+                autoScrollTimer = 0f;
+                AutoScrollNext();
+            }
+        }
+    }
+
+    private void AutoScrollNext()
+    {
+        if (list?.Count <= 4)
+        {
+            isScrollerReady = false;
+            return;
+        }
+
+        // 妫�鏌� scroller 鐨� GameObject 鏄惁澶勪簬婵�娲荤姸鎬�
+        if (scroller == null || scroller.m_Scorller == null || !scroller.m_Scorller.gameObject.activeInHierarchy)
+        {
+            return;
+        }
+
+        currentScrollerIndex++;
+        // 鍦� Loop 妯″紡涓嬭繘琛屽钩婊戣烦杞�
+        scroller.m_Scorller.JumpToDataIndex(
+            currentScrollerIndex % list.Count,
+            tweenType: EnhancedScroller.TweenType.easeInOutQuad,
+            tweenTime: 0.5f);
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnCallWin.cs.meta b/Main/System/HeroReturn/HeroReturnCallWin.cs.meta
new file mode 100644
index 0000000..80fc047
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCallWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0774834d6226ea848adedc229e82552f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCell.cs b/Main/System/HeroReturn/HeroReturnCell.cs
new file mode 100644
index 0000000..dd5cb13
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCell.cs
@@ -0,0 +1,30 @@
+using UnityEngine;
+public class HeroReturnCell : MonoBehaviour
+{
+    [SerializeField] ButtonEx clickButton;
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] ImageEx heroImage;
+    [SerializeField] GradientText titleText;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display()
+    {
+        clickButton.SetListener(() =>
+        {
+            UIManager.Instance.OpenWindow<HeroReturnWin>();
+        });
+
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        int skinID = manager.GetDefaultSkinID(heroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        bgImage.SetSprite(artConfig.EntryBgImage);
+        manager.SetHeroSquareIcon(heroImage, skinConfig.SquareIcon);
+        titleText.text = artConfig.EntryTitleText;
+    }
+
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnCell.cs.meta b/Main/System/HeroReturn/HeroReturnCell.cs.meta
new file mode 100644
index 0000000..263cbfe
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dc2b313f9675a0644bd1a684fe9bad47
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCheckInCell.cs b/Main/System/HeroReturn/HeroReturnCheckInCell.cs
new file mode 100644
index 0000000..b4ffe02
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCheckInCell.cs
@@ -0,0 +1,60 @@
+using UnityEngine;
+
+public class HeroReturnCheckInCell : MonoBehaviour
+{
+    [SerializeField] ButtonEx clickButton;
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] TextEx dayText;
+    [SerializeField] TextEx itemNameText;
+    [SerializeField] ItemCell itemCell;
+    [SerializeField] UIEffectPlayer uiEffectPlayer;
+    [SerializeField] Transform imgMask;
+
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    private int currentItemId;
+    private int currentState;
+
+    public void Display(int templateID, int dayNum)
+    {
+        uiEffectPlayer.Stop();
+
+        var config = ActSignAwardConfig.GetConfig(templateID, dayNum);
+        if (config == null) return;
+        if (config.SignAwardItemList.IsNullOrEmpty()) return;
+
+        currentItemId = config.SignAwardItemList[0][0];
+        int count = config.SignAwardItemList[0][1];
+
+        var itemConfig = ItemConfig.Get(currentItemId);
+        if (itemConfig == null) return;
+
+        currentState = manager.GetCheckInState(dayNum);
+        imgMask.SetActive(currentState == 2);
+        bgImage.SetSprite(currentState == 1 ? "HeroDebutCheckInDayBG1" : "HeroDebutCheckInDayBG2");
+        if (currentState == 1)
+        {
+            uiEffectPlayer.Play();
+        }
+
+        dayText.text = Language.Get($"SignDay{dayNum}");
+        itemNameText.text = itemConfig.ItemName;
+
+        itemCell.Init(new ItemCellModel(currentItemId, false, count));
+        itemCell.button.AddListener(OnItemClicked);
+
+        clickButton.SetListener(() => manager.SendGetCheckInReward());
+    }
+
+    private void OnItemClicked()
+    {
+        if (currentState == 1)
+        {
+            manager.SendGetCheckInReward();
+        }
+        else
+        {
+            ItemTipUtility.Show(currentItemId);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnCheckInCell.cs.meta b/Main/System/HeroReturn/HeroReturnCheckInCell.cs.meta
new file mode 100644
index 0000000..72d343f
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCheckInCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7dc473ad41cdeb049b5ff9072138f709
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnCheckInWin.cs b/Main/System/HeroReturn/HeroReturnCheckInWin.cs
new file mode 100644
index 0000000..261207f
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCheckInWin.cs
@@ -0,0 +1,81 @@
+using UnityEngine;
+
+public class HeroReturnCheckInWin : UIBase
+{
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] UIHeroController rolelhShow;
+    [SerializeField] TextEx timeText;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] HeroReturnCheckInCell[] cells;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+    }
+
+    protected override void OnPreOpen()
+    {
+        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
+        TimeMgr.Instance.OnDayEvent += OnDayEvent;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        Display();
+    }
+    protected override void OnPreClose()
+    {
+        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
+        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+    }
+    private void OnDayEvent()
+    {
+        Display();
+    }
+    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
+    {
+        Display();
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+    private void Display()
+    {
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        var heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null) return;
+
+        int skinID = manager.GetDefaultSkinID(heroID);
+
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int templateID = config.SignTempID;
+        var list = ActSignAwardConfig.GetDayNumSortList(templateID);
+        if (list == null) return;
+
+        bgImage.SetSprite(artConfig.CheckInBgImage);
+
+        for (int i = 0; i < cells.Length; i++)
+        {
+            if (i < list.Count)
+            {
+                cells[i].SetActive(true);
+                cells[i].Display(templateID, list[i]);
+            }
+            else
+            {
+                cells[i].SetActive(false);
+            }
+        }
+
+        rolelhShow.Create(skinID, 1, motionName: "", isLh: true);
+        OnSecondEvent();
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnCheckInWin.cs.meta b/Main/System/HeroReturn/HeroReturnCheckInWin.cs.meta
new file mode 100644
index 0000000..2879871
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnCheckInWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d4ec9226f50edd6408ce3f2bdb9821ca
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnGiftCell.cs b/Main/System/HeroReturn/HeroReturnGiftCell.cs
new file mode 100644
index 0000000..bd1fc9a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnGiftCell.cs
@@ -0,0 +1,165 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnGiftCell : MonoBehaviour
+{
+    [SerializeField] ImageEx vipImage;
+    [SerializeField] TextEx vipText;
+    [SerializeField] OutlineEx vipTextOutline;
+    [SerializeField] ImageEx rateImage;
+    [SerializeField] TextEx rateText;
+
+    [SerializeField] ItemCell[] itemCells;
+    [SerializeField] TextEx titleText;
+    [SerializeField] ButtonEx buyButton;
+    [SerializeField] ImageEx buyImage;
+    [SerializeField] TextEx buyText;
+    [SerializeField] TextEx buyText1;
+    [SerializeField] ImageEx moneyIconImage;
+    [SerializeField] TextEx limitCountText;
+    [SerializeField] ImageEx redImage;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    StoreModel storeModel => StoreModel.Instance;
+
+    public void Display(int index, List<HeroReturnGiftItem> giftItems)
+    {
+        if (giftItems.IsNullOrEmpty() || index < 0 || index >= giftItems.Count) return;
+
+        HeroReturnGiftItem item = giftItems[index];
+        if (item.type == 0)
+        {
+            DisplayStore(item.id);
+            return;
+        }
+
+        DisplayCTG(item.id);
+    }
+
+    private void DisplayCTG(int ctgId)
+    {
+        redImage.SetActive(false);
+        buyText.SetActive(true);
+        buyText1.SetActive(false);
+        moneyIconImage.SetActive(false);
+        rateImage.SetActive(true);
+
+        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
+        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
+        if (!CTGConfig.HasKey(ctgId)) return;
+        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
+
+        CTGConfig config = CTGConfig.Get(ctgId);
+        vipImage.SetActive(config.VipLevel > 0);
+        if (config.VipLevel > 0)
+        {
+            vipImage.SetSprite($"VipLevel{config.VipLevel}");
+            vipText.text = Language.Get($"VipLevelInfo{config.VipLevel}");
+            vipText.color = InvestModel.Instance.GetTextColor(config.VipLevel);
+            vipTextOutline.OutlineColor = InvestModel.Instance.GetOutlineColor(config.VipLevel);
+        }
+
+        rateImage.SetActive(true);
+        rateText.text = Language.Get("DailySpecials07", config.Percentage);
+
+        bool isCanBuy = manager.IsCanBuyToday(ctgId);
+        titleText.text = config.Title;
+        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
+        buyText.text = !isCanBuy ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
+        limitCountText.SetActive(config.DailyBuyCount > 0);
+        limitCountText.text = Language.Get("HeroDebut39", UIHelper.AppendColor(rechargeCount.todayCount >= config.DailyBuyCount ? TextColType.Red : TextColType.LightGreen, Mathf.Max(0, config.DailyBuyCount - rechargeCount.todayCount).ToString()));
+        buyButton.interactable = isCanBuy;
+        buyButton.SetListener(() =>
+        {
+            if (config.VipLevel > 0 && !FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.PrivilegeCard))
+            {
+                SysNotifyMgr.Instance.ShowTip("MinggeAuto8");
+                return;
+            }
+            if (config.VipLevel == 1 && !InvestModel.Instance.IsInvested(InvestModel.monthCardType))
+            {
+                SysNotifyMgr.Instance.ShowTip("MinggeAuto5");
+                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
+                return;
+            }
+            if (config.VipLevel == 2 && !InvestModel.Instance.IsInvested(InvestModel.foreverCardType))
+            {
+                SysNotifyMgr.Instance.ShowTip("MinggeAuto7");
+                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
+                return;
+            }
+            RechargeManager.Instance.CTG(ctgId);
+        });
+
+        for (int i = 0; i < itemCells.Length; i++)
+        {
+            var itemBaisc = itemCells[i];
+            if (i < rechargeItemList.Count)
+            {
+                var itemInfo = rechargeItemList[i];
+                itemBaisc.SetActive(true);
+                itemBaisc.Init(new ItemCellModel((int)itemInfo.id, false, itemInfo.countEx));
+                itemBaisc.button.AddListener(() =>
+                {
+                    ItemTipUtility.Show((int)itemInfo.id);
+                });
+            }
+            else
+            {
+                itemBaisc.SetActive(false);
+            }
+        }
+    }
+
+    private void DisplayStore(int id)
+    {
+        rateImage.SetActive(false);
+        vipImage.SetActive(false);
+        if (!StoreConfig.HasKey(id)) return;
+
+        StoreConfig storeConfig = StoreConfig.Get(id);
+        int remainNum;
+        storeModel.TryGetIsSellOut(storeConfig, out remainNum);
+
+        bool isFree = manager.IsFreeShop(id);
+        titleText.text = storeConfig.Name;
+
+        limitCountText.SetActive(!isFree);
+        limitCountText.text = Language.Get("TimeRush08", UIHelper.AppendColor(remainNum == 0 ? TextColType.Red : TextColType.LightGreen, Mathf.Max(0, remainNum).ToString(), true));
+
+        bool isCanBuy = manager.IsNoSellOutShopID(id);
+
+        redImage.SetActive(isFree && isCanBuy);
+        buyText.SetActive(isFree || !isCanBuy);
+        buyText.text = isFree ? Language.Get("L1127") : Language.Get("storename11");
+        buyText1.SetActive(!isFree && isCanBuy);
+        buyText1.text = UIHelper.GetMoneyFormat(storeConfig.MoneyNum);
+        moneyIconImage.SetActive(!isFree && isCanBuy);
+        moneyIconImage.SetIconWithMoneyType(1);
+        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
+        buyButton.interactable = isCanBuy;
+        buyButton.SetListener(() =>
+        {
+            storeModel.SendBuyShopItemWithPopCheck(storeConfig, 1, (int)BuyStoreItemCheckType.ActGift);
+        });
+
+        var items = storeModel.GetShopItemlistByIndex(storeConfig);
+        for (int i = 0; i < itemCells.Length; i++)
+        {
+            var itemBaisc = itemCells[i];
+            if (i < items.Count)
+            {
+                var itemInfo = items[i];
+                itemBaisc.SetActive(true);
+                itemBaisc.Init(new ItemCellModel(itemInfo.itemId, false, itemInfo.count));
+                itemBaisc.button.AddListener(() =>
+                {
+                    ItemTipUtility.Show(itemInfo.itemId);
+                });
+            }
+            else
+            {
+                itemBaisc.SetActive(false);
+            }
+        }
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnGiftCell.cs.meta b/Main/System/HeroReturn/HeroReturnGiftCell.cs.meta
new file mode 100644
index 0000000..abca963
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnGiftCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4a5a9f2a5a389d24b8e9b1847cf53d35
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnGiftWin.cs b/Main/System/HeroReturn/HeroReturnGiftWin.cs
new file mode 100644
index 0000000..4e7244c
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnGiftWin.cs
@@ -0,0 +1,86 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnGiftWin : UIBase
+{
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] ImageEx heroImage;
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] TextEx timeText;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    StoreModel storeModel => StoreModel.Instance;
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+    }
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
+        storeModel.RefreshBuyShopLimitEvent += RefreshBuyShopLimitEvent;
+
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        bgImage.SetSprite(artConfig.GiftBgImage);
+        heroImage.SetNativeSize();
+
+        heroImage.SetSprite(artConfig.GiftHeroImage);
+        heroImage.SetNativeSize();
+
+        OnSecondEvent();
+        CreateGiftScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
+        storeModel.RefreshBuyShopLimitEvent -= RefreshBuyShopLimitEvent;
+    }
+    private void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<HeroReturnGiftCell>();
+        _cell?.Display(cell.index, giftItems);
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+
+    private void OnRechargeCountEvent(int obj)
+    {
+        RefreshAll();
+    }
+
+    private void RefreshBuyShopLimitEvent()
+    {
+        RefreshAll();
+    }
+
+    List<HeroReturnGiftItem> giftItems;
+    private void CreateGiftScroller()
+    {
+        giftItems = manager.GetGiftItemList(true);
+        scroller.Refresh();
+        if (!giftItems.IsNullOrEmpty())
+        {
+            for (int i = 0; i < giftItems.Count; i++)
+            {
+                scroller.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+        scroller.Restart();
+    }
+
+    void RefreshAll()
+    {
+        scroller.m_Scorller.RefreshActiveCellViews();
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnGiftWin.cs.meta b/Main/System/HeroReturn/HeroReturnGiftWin.cs.meta
new file mode 100644
index 0000000..18811ae
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnGiftWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7cc0cd7de844ca946be560af29b6a17c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnManager.cs b/Main/System/HeroReturn/HeroReturnManager.cs
new file mode 100644
index 0000000..7de130a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnManager.cs
@@ -0,0 +1,1152 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using LitJson;
+using UnityEngine;
+
+public class HeroReturnManager : GameSystemManager<HeroReturnManager>, IOpenServerActivity
+{
+    public int[] xbGridArr;
+    public Dictionary<int, int[][]> heroQaulityColor;
+    public int[][] seeArr;
+    public override void Init()
+    {
+        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
+        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
+        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
+        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
+        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
+        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
+        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
+        StoreModel.Instance.RefreshBuyShopLimitEvent += RefreshBuyShopLimitEvent;
+        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
+        HeroManager.Instance.onHeroChangeEvent += OnHeroChangeEvent;
+        TimeMgr.Instance.OnDayEvent += OnDayEvent;
+
+        var config = FuncConfigConfig.Get("HeroAppear");
+        xbGridArr = JsonMapper.ToObject<int[]>(config.Numerical1);
+
+        config = FuncConfigConfig.Get("HeroReturn");
+        heroQaulityColor = ConfigParse.ParseIntArray2Dict(config.Numerical1);
+        seeArr = JsonMapper.ToObject<int[][]>(config.Numerical2);
+
+        InitRedPointId();
+    }
+
+    public void SetheroQaulityColor(GradientText text, int qaulity)
+    {
+        if (!heroQaulityColor.TryGetValue(qaulity, out var colors)) return;
+        if (colors?.Length < 2) return;
+        text.SetVerticalGradient(ParseColor32(colors[0]), ParseColor32(colors[1]));
+    }
+
+    public override void Release()
+    {
+        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
+        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
+        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
+        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
+        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
+        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
+        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
+        StoreModel.Instance.RefreshBuyShopLimitEvent -= RefreshBuyShopLimitEvent;
+        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
+        HeroManager.Instance.onHeroChangeEvent -= OnHeroChangeEvent;
+        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
+    }
+
+    private void OnDayEvent()
+    {
+        UpdateRedpoint();
+    }
+
+    private void OnHeroChangeEvent(HeroInfo info)
+    {
+        UpdateRedpoint();
+    }
+
+    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
+    {
+        UpdateRedpoint();
+    }
+
+    private void RefreshBuyShopLimitEvent()
+    {
+        UpdateRedpoint();
+    }
+
+    private void OnBeforePlayerDataInitializeEventOnRelogin()
+    {
+        isSendFirst = true;
+        starHeroIndex = 0;
+        callHeroIndex = 0;
+        starFreeAwardDict.Clear();
+    }
+
+    private void OnPlayerLoginOk()
+    {
+        TryPopWin();
+    }
+
+    private void OnFuncStateChangeEvent(int obj)
+    {
+        if (obj != (int)FuncOpenEnum.HeroReturn)
+            return;
+        TryPopWin();
+    }
+    public readonly int sendRankType = 6;
+    public int loadRankType => actNum * 1000 + sendRankType;
+    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
+    public const int activityID = (int)NewDayActivityID.HeroReturnAct;
+    public static OperationType operaType = OperationType.HeroReturn;
+    public Redpoint redPoint = new Redpoint(MainRedDot.HeroReturnRepoint);
+
+    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
+
+    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
+
+    public bool priorityOpen => redPoint.state == RedPointState.Simple;
+    public readonly int actNum = 11;
+    public event Action<int> onStateUpdate;
+
+    private void OperationTimeUpdateEvent(OperationType type)
+    {
+        if (type == operaType)
+        {
+            if (UIManager.Instance.IsOpened<HeroReturnPopWin>())
+                UIManager.Instance.CloseWindow<HeroReturnPopWin>();
+            if (UIManager.Instance.IsOpened<HeroReturnWin>())
+                UIManager.Instance.CloseWindow<HeroReturnWin>();
+            UpdateRedpoint();
+        }
+    }
+
+    private void OperationStartEvent(OperationType type, int state)
+    {
+        if (type == operaType && state == 0)
+        {
+            onStateUpdate?.Invoke(activityID);
+            TryPopWin();
+            UpdateRedpoint();
+        }
+    }
+
+    private void OperationEndEvent(OperationType type, int state)
+    {
+        if (type == operaType)
+        {
+            onStateUpdate?.Invoke(activityID);
+            if (UIManager.Instance.IsOpened<HeroReturnPopWin>())
+                UIManager.Instance.CloseWindow<HeroReturnPopWin>();
+            if (UIManager.Instance.IsOpened<HeroReturnWin>())
+                UIManager.Instance.CloseWindow<HeroReturnWin>();
+            UpdateRedpoint();
+        }
+    }
+    private void OperationAdvanceEvent(OperationType type)
+    {
+        if (type == operaType)
+        {
+            onStateUpdate?.Invoke(activityID);
+            UpdateRedpoint();
+        }
+    }
+
+    public OperationHeroAppearInfo GetOperationHeroAppearInfo()
+    {
+        OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationHeroAppearInfo act);
+        return act;
+    }
+
+    public void SetHeroSquareIcon(ImageEx image, string name)
+    {
+        var sprite = UILoader.LoadSprite("HeroHead", name);
+        if (sprite != null)
+        {
+            image.overrideSprite = sprite;
+            return;
+        }
+
+        image.SetSprite("herohead_default");
+    }
+
+    public void GetActTimeStr(TextEx timeText, string key = "TimeRush05")
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null)
+        {
+            timeText.text = Language.Get("OSActivity6");
+            return;
+        }
+        timeText.text = Language.Get(key, TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
+    }
+
+    public void SetGradientTextColor(GradientText text, int[][] colors)
+    {
+        if (colors?.Length < 4) return;
+        text.topLeftColor = ParseColor32(colors[0]);
+        text.topRightColor = ParseColor32(colors[1]);
+        text.bottomLeftColor = ParseColor32(colors[2]);
+        text.bottomRightColor = ParseColor32(colors[3]);
+        text.SetVerticesDirty();
+    }
+
+    public Color32 ParseColor32(int[] colorArr)
+    {
+        return new Color32()
+        {
+            r = (byte)(colorArr.Length > 0 ? colorArr[0] : 0),
+            g = (byte)(colorArr.Length > 1 ? colorArr[1] : 0),
+            b = (byte)(colorArr.Length > 2 ? colorArr[2] : 0),
+            a = (byte)(colorArr.Length > 3 ? colorArr[3] : 255),
+        };
+    }
+
+
+    public int GetDefaultSkinID(int heroID)
+    {
+        HeroConfig heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null || heroConfig.SkinIDList.IsNullOrEmpty()) return 0;
+        return heroConfig.SkinIDList[0];
+    }
+
+    public bool IsHeroReturnOpen()
+    {
+        if (!IsOpen) return false;
+        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.HeroReturn)) return false;
+        return true;
+    }
+
+
+    public int GetHeroIdIndex(int cfgID, int heroID)
+    {
+        var config = ActHeroAppearConfig.Get(cfgID);
+        if (config == null) return 0;
+
+        var heroArr = config.ActHeroIDList;
+        if (heroArr.IsNullOrEmpty()) return 0;
+
+        int index = Array.IndexOf(heroArr, heroID);
+        return index;
+    }
+
+
+
+    public event Action OnNowCallChooseHeroIDChangeEvent;
+    private int m_heroAppearActNum = 0;
+    public int nowCallChooseHeroID
+    {
+        get { return m_heroAppearActNum; }
+        set
+        {
+            if (m_heroAppearActNum == value) return;
+            m_heroAppearActNum = value;
+            OnNowCallChooseHeroIDChangeEvent?.Invoke();
+        }
+    }
+
+    public event Action OnNowStarUpChooseHeroIDChangeEvent;
+    private int m_nowStarUpChooseHeroID = 0;
+    public int nowStarUpChooseHeroID
+    {
+        get { return m_nowStarUpChooseHeroID; }
+        set
+        {
+            if (m_nowStarUpChooseHeroID == value) return;
+            m_nowStarUpChooseHeroID = value;
+            OnNowStarUpChooseHeroIDChangeEvent?.Invoke();
+        }
+    }
+
+    public int starHeroIndex = 0;
+    public int callHeroIndex = 0;
+    //<鍗囨槦璁″垝閫夋嫨鐨勬灏咺D绱㈠紩,鍗囨槦璁″垝鍏嶈垂濂栧姳璁板綍>
+    Dictionary<int, uint> starFreeAwardDict = new();
+
+    public event Action OnUpdateHeroAppearPlayerInfoEvent;
+    public void UpdateHeroAppearPlayerInfo(HAA22_tagSCActHeroAppearPlayerInfo vNetData)
+    {
+        if (vNetData == null) return;
+        if (vNetData.ActNum != this.actNum) return;
+
+        int actNum = vNetData.ActNum;
+        starHeroIndex = vNetData.StarHeroIndex;
+        callHeroIndex = vNetData.CallHeroIndex;
+        starFreeAwardDict[starHeroIndex] = vNetData.StarFreeAward;
+        UpdateRedpoint();
+        OnUpdateHeroAppearPlayerInfoEvent?.Invoke();
+    }
+
+    public void SendHeroAppearStarHeroSelect(int actNum, int starHeroIndex)
+    {
+        var pack = new CAA01_tagCSActHeroAppearStarHeroSelect();
+        pack.ActNum = (byte)actNum;                 // 娲诲姩缂栧彿
+        pack.StarHeroIndex = (byte)starHeroIndex;   // 鍗囨槦璁″垝閫夋嫨鐨勬灏咺D绱㈠紩
+        GameNetSystem.Instance.SendInfo(pack);
+    }
+
+    public void SnedHeroAppearCallHeroSelect(int actNum, int callHeroIndex)
+    {
+        var pack = new CAA02_tagCSActHeroAppearCallHeroSelect();
+        pack.ActNum = (byte)actNum;                 // 娲诲姩缂栧彿
+        pack.CallHeroIndex = (byte)callHeroIndex;   // 鎷涘嫙閫夋嫨鐨勬灏咺D绱㈠紩
+        GameNetSystem.Instance.SendInfo(pack);
+    }
+
+    public void SendGetStarReward()
+    {
+        var pack = new CA504_tagCMPlayerGetReward();
+        pack.RewardType = 10;
+        pack.DataEx = (uint)actNum;
+        GameNetSystem.Instance.SendInfo(pack);
+    }
+
+    #region 绾㈢偣
+    public int GetRedPointId(HeroReturnRedPointType type)
+    {
+        return MainRedDot.HeroReturnRepoint * 10 + (int)type;
+    }
+    public Redpoint checkInRedpoint;
+    public Redpoint starUpRedpoint;
+    public Redpoint shopRedpoint;
+    public Redpoint giftRedpoint;
+    public void InitRedPointId()
+    {
+        checkInRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.CheckIn));
+        starUpRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.StarUp));
+        shopRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.Shop));
+        giftRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.Gift));
+    }
+
+    public void UpdateRedpoint()
+    {
+        redPoint.state = RedPointState.None;
+        checkInRedpoint.state = RedPointState.None;
+        starUpRedpoint.state = RedPointState.None;
+        shopRedpoint.state = RedPointState.None;
+        giftRedpoint.state = RedPointState.None;
+
+        if (!IsHeroReturnOpen()) return;
+
+        if (HasCheckInCanHave()) //绛惧埌璧犵ぜ 
+        {
+            checkInRedpoint.state = RedPointState.Simple;
+        }
+
+        if (HasStarUpCanHave())//鏄熺骇鎻愬崌 
+        {
+            starUpRedpoint.state = RedPointState.Simple;
+        }
+
+        //鍏戞崲鍟嗗簵姣忓ぉ0鐐规樉绀虹孩鐐癸紝鐐瑰嚮杩涘叆涓�娆$晫闈㈠悗娑堝け
+        if (!IsShopVisitedToday) //鍏戞崲鍟嗗簵
+        {
+            shopRedpoint.state = RedPointState.Simple;
+        }
+
+        if (HasGiftCanHave())//鐨囨潈绀煎寘
+        {
+            giftRedpoint.state = RedPointState.Simple;
+        }
+    }
+    #endregion
+
+    #region 鎷嶈劯鐣岄潰
+    public bool IsTodayPop
+    {
+        get
+        {
+            int lastPopTime = LoadPopTimeData();
+            int todayStartTime = TimeUtility.GetTodayStartTick();
+            return lastPopTime < todayStartTime;
+        }
+    }
+    private string PopTimeDataKey { get { return $"HeroReturnManager_PopTimeData_{PlayerDatas.Instance.PlayerId}"; } }
+
+    private int LoadPopTimeData()
+    {
+        return LocalSave.GetInt(PopTimeDataKey);
+    }
+
+    public void SavePopTimeData()
+    {
+        LocalSave.SetInt(PopTimeDataKey, TimeUtility.AllSeconds);
+    }
+
+    private void TryPopWin()
+    {
+        if (!IsHeroReturnOpen()) return;
+        if (!IsTodayPop) return;
+        if (UIManager.Instance.IsOpened<HeroReturnPopWin>()) return;
+        if (UIManager.Instance.IsOpened<HeroReturnWin>()) return;
+        PopupWindowsProcessor.Instance.Add("HeroReturnPopWin");
+    }
+    #endregion
+
+    #region 绛惧埌
+    private int GetNowDayNum()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return 0;
+
+        int dayNum = act.IndexOfDays(TimeUtility.ServerNow);
+        return dayNum < 0 ? 0 : dayNum + 1;
+    }
+
+    private bool IsCheckInGridUnlock(int gridDayNum)
+    {
+        int nowDayNum = GetNowDayNum();
+        if (nowDayNum <= 0) return false;
+
+        return nowDayNum >= gridDayNum;
+    }
+
+    /// <summary>
+    /// 0-鏈В閿� 1-鍙 2-宸茬
+    /// </summary>
+    public int GetCheckInState(int gridDayNum)
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return 0;
+
+        int actType = act.ActType;
+        if (GeneralActInfoManager.Instance.IsDaySigned(actType, actNum, gridDayNum)) return 2;
+        if (IsCheckInGridUnlock(gridDayNum)) return 1;
+        return 0;
+    }
+
+    public void SendGetCheckInReward()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        int actType = act.ActType;
+        GeneralActInfoManager.Instance.SendGetSignReward(actType, actNum);
+    }
+
+    public bool HasCheckInCanHave()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return false;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return false;
+
+        int templateID = config.SignTempID;
+        var list = ActSignAwardConfig.GetDayNumSortList(templateID);
+        if (list == null) return false;
+
+        for (int i = 0; i < list.Count; i++)
+        {
+            int dayNum = list[i];
+            int state = GetCheckInState(dayNum);
+            if (state == 1) return true;
+        }
+        return false;
+    }
+    #endregion
+
+    #region 鍗囨槦璁″垝
+
+    public bool IsSingleHero(OperationHeroAppearInfo act)
+    {
+        var appearConfig = ActHeroAppearConfig.Get(act.CfgID);
+        return appearConfig?.ActHeroIDList?.Length == 1;
+    }
+
+    public bool IsLockStarHero(OperationHeroAppearInfo act)
+    {
+        // 濡傛灉鍙湁涓�涓彲閫夋灏嗭紝瑙嗕负閿佸畾
+        if (IsSingleHero(act)) return true;
+        if (!starFreeAwardDict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
+        //棰嗗彇浜嗕换鎰忎竴妗e厤璐瑰鍔辫涓洪攣瀹�
+        if (freeAward > 0) return true;
+        //璐拱浜嗕换鎰忎竴妗gぜ鍖呰涓洪攣瀹�
+        if (IsAnyStarGiftPurchased(act)) return true;
+        return LoadStarUpLockState(act);
+    }
+
+    /// <summary>
+    /// 妫�鏌ユ槸鍚﹁喘涔颁簡浠绘剰涓�妗e崌鏄熺ぜ鍖�
+    /// </summary>
+    private bool IsAnyStarGiftPurchased(OperationHeroAppearInfo act)
+    {
+        var appearConfig = ActHeroAppearConfig.Get(act.CfgID);
+        if (appearConfig == null) return false;
+
+        int starGiftTempID = appearConfig.StarGiftTempID;
+        var list = ActHeroAppearStarConfig.GetHeroReturnAwardIndexSortList(starGiftTempID);
+        if (list.IsNullOrEmpty()) return false;
+
+        for (int i = 0; i < list.Count; i++)
+        {
+            var config = ActHeroAppearStarConfig.GetConfig(starGiftTempID, list[i]);
+            if (config == null) continue;
+
+            if (RechargeManager.Instance.TryGetRechargeCount(config.StarGiftCTGID, out var rechargeCount))
+            {
+                if (rechargeCount.totalCount > 0)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private string GetStarUpChooseHeroStateKey(OperationHeroAppearInfo act)
+    {
+        if (act == null) return string.Empty;
+        return string.Concat("HeroReturnManager_StarUpChooseHero_", act.CfgID, "_", ToInt(act.startDate), "_", ToInt(act.startDate), "_", PlayerDatas.Instance.PlayerId);
+    }
+
+    public bool LoadStarUpChooseHeroStateKey(OperationHeroAppearInfo act)
+    {
+        return LocalSave.GetBool(GetStarUpChooseHeroStateKey(act));
+    }
+
+    public void SaveStarUpChooseHeroStateKey(OperationHeroAppearInfo act)
+    {
+        LocalSave.SetBool(GetStarUpChooseHeroStateKey(act), true);
+    }
+
+    private string GetStarUpLockStateKey(OperationHeroAppearInfo act)
+    {
+        if (act == null) return string.Empty;
+        return string.Concat("HeroReturnManager_StarUpLockState_", act.CfgID, "_", ToInt(act.startDate), "_", ToInt(act.startDate), "_", PlayerDatas.Instance.PlayerId);
+    }
+
+    public bool LoadStarUpLockState(OperationHeroAppearInfo act)
+    {
+        return LocalSave.GetBool(GetStarUpLockStateKey(act));
+    }
+
+    public void SaveStarUpLockState(OperationHeroAppearInfo act)
+    {
+        LocalSave.SetBool(GetStarUpLockStateKey(act), true);
+    }
+
+    /// <summary>
+    /// 褰撳墠鍗囨槦璁″垝閫変腑鐨勬灏咺D
+    /// </summary>
+    public int GetCurrentDisplayStarUpHeroId()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return 0;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null || config.ActHeroIDList?.Length <= starHeroIndex) return 0;
+
+        return config.ActHeroIDList[starHeroIndex];
+    }
+
+    private Dictionary<int, Dictionary<int, int[][]>> showHeroGiftItemInfoDict = new();
+    public bool TryGetStarUpAwardArr(int id, int heroID, out int[][] arr)
+    {
+        arr = null;
+        var config = ActHeroAppearStarConfig.Get(id);
+        if (config == null) return false;
+
+        var ctgConfig = CTGConfig.Get(config.StarGiftCTGID);
+        if (ctgConfig == null) return false;
+
+        if (!showHeroGiftItemInfoDict.TryGetValue(id, out var dict))
+        {
+            dict = new Dictionary<int, int[][]>();
+            showHeroGiftItemInfoDict[id] = dict;
+        }
+
+        if (!dict.TryGetValue(heroID, out arr))
+        {
+            // 濡傛灉缂撳瓨閲屾病鏈夊綋鍓嶆灏嗙殑鏁版嵁锛屾墠杩涜瑙f瀽
+            var giftdict = ConfigParse.ParseIntArray2Dict(config.HeroGiftItemInfo);
+            int[][] ctgArray = ctgConfig.GainItemList;
+
+            foreach (var kvp in giftdict)
+            {
+                int hId = kvp.Key;
+                int[][] hGift = kvp.Value ?? Array.Empty<int[]>();
+                dict[hId] = hGift.Concat(ctgArray).ToArray();
+            }
+
+            // 濡傛灉閬嶅巻瀹屽彂鐜伴厤琛ㄩ噷鏍规湰娌℃湁杩欎釜 heroID
+            if (!dict.TryGetValue(heroID, out arr))
+            {
+                arr = ctgArray;
+                dict[heroID] = arr;
+            }
+        }
+
+        return true;
+    }
+
+    /// <summary>
+    /// 0 - 鏈В閿� 1 - 鍙鍙� 2 - 宸查鍙�
+    /// </summary>
+    public int GetStarUpFreeState(int id)
+    {
+        var config = ActHeroAppearStarConfig.Get(id);
+        if (config == null) return 0;
+
+        int heroId = GetCurrentDisplayStarUpHeroId();
+        var heroConfig = HeroConfig.Get(heroId);
+        if (heroConfig == null) return 0;
+        // 娌¢攣瀹氱殑姝﹀皢瑙嗕负鏈В閿�
+        if (!IsLockStarHero(GetOperationHeroAppearInfo())) return 0;
+
+        // 娌¤幏寰楁灏嗘湰浣撲笉鍙鍙�
+        if (!HeroManager.Instance.HasHero(heroId)) return 0;
+        if (IsStarUpFreeHave(starHeroIndex, config.AwardIndex)) return 2;
+        if (IsHeroStarCntOk(heroConfig.HeroID, config.NeedStar)) return 1;
+        return 0;
+    }
+
+    private bool IsStarUpFreeHave(int starHeroIndex, int awardIndex)
+    {
+        if (!starFreeAwardDict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
+        return ((freeAward >> awardIndex) & 1u) == 1u;
+    }
+
+    public bool IsHeroStarCntOk(int heroId, int needStar)
+    {
+        return GetNowHeroMaxStarCnt(heroId) >= needStar;
+    }
+
+    public int GetNowHeroMaxStarCnt(int heroId)
+    {
+        int res = 0;
+        foreach (var item in HeroManager.Instance.GetHeroList())
+        {
+            if (item == null) continue;
+            if (item.heroId == heroId)
+            {
+                if (res < item.heroStar)
+                    res = item.heroStar;
+            }
+        }
+        return res;
+    }
+
+    public bool TryGetStarUpStateIndex(int starGiftTempID, int tarState, out int index)
+    {
+        index = 0;
+        var list = ActHeroAppearStarConfig.GetHeroReturnAwardIndexSortList(starGiftTempID);
+        if (list == null) return false;
+
+        for (int i = 0; i < list.Count; i++)
+        {
+            var awardIndex = list[i];
+            var config = ActHeroAppearStarConfig.GetConfig(starGiftTempID, awardIndex);
+            if (config == null) continue;
+
+            int state = GetStarUpFreeState(config.ID);
+            if (state == tarState)
+            {
+                index = i;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public int GetStarUpJumpIndex(int starGiftTempID)
+    {
+        // 浼樺厛鏌ユ壘鍙鍙栫殑濂栧姳
+        if (TryGetStarUpStateIndex(starGiftTempID, 1, out int index)) return index;
+
+        // 鑻ユ病鏈夊彲棰嗗彇鐨勶紝鍒欐煡鎵炬湭杈惧埌鏉′欢鐨勫鍔�
+        if (TryGetStarUpStateIndex(starGiftTempID, 0, out index)) return index;
+
+        // 閮芥病鏈�
+        return 0;
+    }
+
+    public bool HasStarUpCanHave()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return false;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return false;
+
+        int starGiftTempID = config.StarGiftTempID;
+        return TryGetStarUpStateIndex(starGiftTempID, 1, out _);
+    }
+    #endregion
+
+    #region 鍏戞崲鍟嗗簵
+
+
+    private string ShopVisitTimeDataKey { get { return $"HeroReturnManager_ShopVisitTime_{PlayerDatas.Instance.PlayerId}"; } }
+
+    private int LoadShopVisitTimeData()
+    {
+        return LocalSave.GetInt(ShopVisitTimeDataKey);
+    }
+
+    public void SaveShopVisitTimeData()
+    {
+        LocalSave.SetInt(ShopVisitTimeDataKey, TimeUtility.AllSeconds);
+    }
+    public bool IsShopVisitedToday
+    {
+        get
+        {
+            int lastVisitTime = LoadShopVisitTimeData();
+            int todayStartTime = TimeUtility.GetTodayStartTick();
+            return lastVisitTime >= todayStartTime;
+        }
+    }
+    #endregion
+
+    #region 鐨囨潈绀煎寘
+    //娌″敭缃�
+    public bool IsCanBuyToday(int ctgID)
+    {
+        CTGConfig config = CTGConfig.Get(ctgID);
+        if (config == null) return false;
+        if (!RechargeManager.Instance.TryGetRechargeCount(ctgID, out var rechargeCount)) return false;
+
+        if (config.DailyBuyCount == 0) return true;
+        return rechargeCount.todayCount < config.DailyBuyCount;
+    }
+
+    public bool IsNoSellOutCTGID(int ctgID)
+    {
+        CTGConfig config = CTGConfig.Get(ctgID);
+        if (config == null) return false;
+        if (!RechargeManager.Instance.TryGetRechargeCount(ctgID, out var rechargeCount)) return false;
+        return rechargeCount.totalCount < config.TotalBuyCount;
+    }
+
+    // 鍏嶈垂鍟嗗搧
+    public bool IsFreeShop(int shopID)
+    {
+        StoreConfig config = StoreConfig.Get(shopID);
+        if (config == null) return false;
+        return config.MoneyNum == 0;
+    }
+
+    //娌″敭缃�
+    public bool IsNoSellOutShopID(int shopID)
+    {
+        StoreConfig config = StoreConfig.Get(shopID);
+        if (config == null) return false;
+
+        StoreModel.Instance.TryGetIsSellOut(config, out int remainNum);
+        return remainNum > 0;
+    }
+
+    public List<HeroReturnGiftItem> GetGiftItemList(bool isSort = false)
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return null;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return null;
+
+        List<HeroReturnGiftItem> res = new List<HeroReturnGiftItem>();
+
+        var list = StoreModel.Instance.storeTypeDict[config.GiftShopType];
+        if (!list.IsNullOrEmpty())
+        {
+            for (int i = 0; i < list.Count; i++)
+            {
+                var item = list[i];
+                if (item.storeConfig == null)
+                    continue;
+                res.Add(new HeroReturnGiftItem
+                {
+                    type = 0,
+                    id = item.storeConfig.ID,
+                });
+            }
+        }
+
+        if (config.GiftCTGIDList != null)
+        {
+            for (int i = 0; i < config.GiftCTGIDList.Length; i++)
+            {
+                var item = config.GiftCTGIDList[i];
+                res.Add(new HeroReturnGiftItem
+                {
+                    type = 1,
+                    id = item,
+                });
+            }
+        }
+
+        if (isSort)
+        {
+            res = res.OrderBy(item =>
+            {
+                bool isCanBuy = item.type == 0 ? IsNoSellOutShopID(item.id) : IsCanBuyToday(item.id);
+                return !isCanBuy;
+            })
+            .ThenBy(item => item.type)
+            .ThenBy(item => item.id)
+            .ToList();
+        }
+
+        return res;
+    }
+
+    public bool HasGiftCanHave()
+    {
+        var list = GetGiftItemList(false);
+        if (list.IsNullOrEmpty())
+            return false;
+
+        for (int i = 0; i < list.Count; i++)
+        {
+            var item = list[i];
+            if (item.type == 0)
+            {
+                bool isFree = IsFreeShop(item.id);
+                bool isCanBuy = IsNoSellOutShopID(item.id);
+                if (isFree && isCanBuy)
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    #endregion
+    #region 鎷涘嫙
+    public int ToInt(OperationDate date)
+    {
+        return date.year * 10000 + date.month * 100 + date.day;
+    }
+    private string GetCallSkipKey(int cfgID, OperationDate startDate, OperationDate endDate)
+    {
+        return string.Concat("HeroReturnManager_CallSkip_", cfgID, "_", ToInt(startDate), "_", ToInt(endDate), "_", PlayerDatas.Instance.PlayerId);
+    }
+
+    public bool LoadCallSkipData(int cfgID, OperationDate startDate, OperationDate endDate)
+    {
+        return LocalSave.GetBool(GetCallSkipKey(cfgID, startDate, endDate));
+    }
+
+    public void SaveCallSkipData(int cfgID, OperationDate startDate, OperationDate endDate, bool value)
+    {
+        LocalSave.SetBool(GetCallSkipKey(cfgID, startDate, endDate), value);
+    }
+
+
+    /// <summary>
+    /// 褰撳墠鎷涘嫙閫変腑鐨勬灏咺D
+    /// </summary>
+    public int GetCurrentDisplayCallHeroId()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return 0;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null || config.ActHeroIDList?.Length <= callHeroIndex) return 0;
+
+        return config.ActHeroIDList[callHeroIndex];
+    }
+
+    public int GetFirstHeroId()
+    {
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return 0;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null || config.ActHeroIDList.IsNullOrEmpty()) return 0;
+
+        return config.ActHeroIDList.First();
+    }
+
+    private string GetCallChooseHeroStateKey(OperationHeroAppearInfo act)
+    {
+        if (act == null) return string.Empty;
+        return string.Concat("HeroReturnManager_CallChooseHero_", act.CfgID, "_", ToInt(act.startDate), "_", ToInt(act.startDate), "_", PlayerDatas.Instance.PlayerId);
+    }
+
+    public bool LoadCallChooseHeroStateKey(OperationHeroAppearInfo act)
+    {
+        return LocalSave.GetBool(GetCallChooseHeroStateKey(act));
+    }
+
+    public void SaveCallChooseHeroStateKey(OperationHeroAppearInfo act)
+    {
+        LocalSave.SetBool(GetCallChooseHeroStateKey(act), true);
+    }
+
+    #endregion
+
+    #region 鏃惰鐗瑰崠
+
+    public event Action OnCurrentChooseSkinIDChangeEevent;
+    private int m_currentChooseSkinID = 0;
+
+    public int currentChooseSkinID
+    {
+        get
+        {
+            return m_currentChooseSkinID;
+        }
+        set
+        {
+            if (m_currentChooseSkinID == value) return;
+            m_currentChooseSkinID = value;
+            OnCurrentChooseSkinIDChangeEevent?.Invoke();
+        }
+    }
+
+    /// <summary>
+    /// 閫氳繃skinID鑾峰彇瀵瑰簲鐨刪eroID
+    /// </summary>
+    public int GetHeroIDBySkinID(int skinID)
+    {
+        foreach (var heroConfig in HeroConfig.GetValues())
+        {
+            if (heroConfig.SkinIDList != null && heroConfig.SkinIDList.Contains(skinID))
+            {
+                return heroConfig.HeroID;
+            }
+        }
+        return 0;
+    }
+
+    /// <summary>
+    /// 鑾峰彇skinID鍦℉eroConfig.SkinIDList涓殑绱㈠紩
+    /// </summary>
+    public int GetSkinIndexInHeroConfig(int heroID, int skinID)
+    {
+        var heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig?.SkinIDList == null) return int.MaxValue;
+
+        for (int i = 0; i < heroConfig.SkinIDList.Length; i++)
+        {
+            if (heroConfig.SkinIDList[i] == skinID)
+                return i;
+        }
+        return int.MaxValue;
+    }
+
+    //<skinID,ctgID>
+    Dictionary<int, int> ctgDict = new();
+    public int GetCtgIDBySkinID(int skinID)
+    {
+        if (ctgDict.IsNullOrEmpty())
+        {
+            GetSkinIDToCtgIDDict();
+        }
+
+        int ctgID;
+        ctgDict.TryGetValue(skinID, out ctgID);
+        return ctgID;
+    }
+
+    Dictionary<int, int> GetSkinIDToCtgIDDict()
+    {
+        if (!ctgDict.IsNullOrEmpty())
+        {
+            return ctgDict;
+        }
+
+        foreach (var config in ActHeroAppearConfig.GetValues())
+        {
+            if (config == null || config.SkinCTGIDList == null) return null;
+
+            for (int i = 0; i < config.SkinCTGIDList.Length; i++)
+            {
+                var ctgID = config.SkinCTGIDList[i];
+                var ctgConfig = CTGConfig.Get(ctgID);
+                if (ctgConfig == null || ctgConfig.GainItemList == null) continue;
+
+                for (int j = 0; j < ctgConfig.GainItemList.Length; j++)
+                {
+                    var itemID = ctgConfig.GainItemList[j][0];
+                    var itemConfig = ItemConfig.Get(itemID);
+
+                    if (itemConfig == null) continue;
+                    if (!HeroSkinAttrConfig.TryGetSkinIDByItemID(itemID, out var skinID)) continue;
+                    if (ctgDict.ContainsKey(skinID)) continue;
+                    ctgDict[skinID] = ctgID;
+                }
+            }
+        }
+
+        return ctgDict;
+    }
+
+    public bool HasItemInSkinCTGIDList(int cfgID, int findItemID)
+    {
+        var config = ActHeroAppearConfig.Get(cfgID);
+        if (config == null || config.SkinCTGIDList == null) return false;
+
+        for (int i = 0; i < config.SkinCTGIDList.Length; i++)
+        {
+            var ctgID = config.SkinCTGIDList[i];
+            var ctgConfig = CTGConfig.Get(ctgID);
+            if (ctgConfig == null || ctgConfig.GainItemList == null) continue;
+
+            for (int j = 0; j < ctgConfig.GainItemList.Length; j++)
+            {
+                var itemID = ctgConfig.GainItemList[j][0];
+                if (itemID == findItemID) return true;
+            }
+        }
+        return false;
+    }
+
+
+    public List<int> GetSkinIDList(int cfgID, int heroID, int mainSkinID)
+    {
+        var config = ActHeroAppearConfig.Get(cfgID);
+        if (config == null || config.SkinCTGIDList == null) return null;
+
+        var res = new List<int>();
+        for (int i = 0; i < config.SkinCTGIDList.Length; i++)
+        {
+            var ctgID = config.SkinCTGIDList[i];
+            var ctgConfig = CTGConfig.Get(ctgID);
+            if (ctgConfig == null || ctgConfig.GainItemList == null) continue;
+
+            for (int j = 0; j < ctgConfig.GainItemList.Length; j++)
+            {
+                var itemID = ctgConfig.GainItemList[j][0];
+                var itemConfig = ItemConfig.Get(itemID);
+
+                if (itemConfig == null) continue;
+                if (!HeroSkinAttrConfig.TryGetSkinIDByItemID(itemID, out var skinID)) continue;
+                if (res.Contains(skinID)) continue;
+
+                res.Add(skinID);
+            }
+        }
+        // 鑷畾涔夋帓搴�
+        res.Sort((a, b) =>
+        {
+            // 1. 鍒ゆ柇鏄惁鏄紶鍏eroID鐨勭毊鑲わ紝浼樺厛鎺掑墠闈�
+            int heroIDA = GetHeroIDBySkinID(a);
+            int heroIDB = GetHeroIDBySkinID(b);
+
+            bool isPriorityA = (heroIDA == heroID);
+            bool isPriorityB = (heroIDB == heroID);
+
+            if (isPriorityA != isPriorityB)
+                return isPriorityA ? -1 : 1;
+
+            // 2. 鐩稿悓姝﹀皢鐨勫涓毊鑲よ繛缁尐鍦ㄤ竴璧�
+            if (heroIDA != heroIDB)
+                return heroIDA.CompareTo(heroIDB);
+
+            // 3. 濡傛灉heroid鐩稿悓锛屽拰MainSkinID鐩稿悓鐨勬帓鍦ㄦ渶鍓嶉潰
+            if (a == mainSkinID) return -1;
+            if (b == mainSkinID) return 1;
+
+            // 4. 鍏朵粬鎸塖kinIDList绱㈠紩鎺掑簭
+            int indexA = GetSkinIndexInHeroConfig(heroIDA, a);
+            int indexB = GetSkinIndexInHeroConfig(heroIDB, b);
+
+            return indexA.CompareTo(indexB);
+        });
+        return res;
+    }
+
+    #endregion
+
+    #region 鑾峰璁板綍
+    public static readonly int RecordType = 311;
+
+    public void SendViewGameRecPack(int treasureType)
+    {
+        CA008_tagCSViewGameRec pack = new CA008_tagCSViewGameRec();
+        pack.RecType = (ushort)RecordType;
+        pack.RecID = (uint)treasureType;
+        GameNetSystem.Instance.SendInfo(pack);
+    }
+
+    public bool isSendFirst = true;
+
+    List<HeroReturnGameRec> gameRecDict = new();
+
+    public List<HeroReturnGameRec> GetGameRecList()
+    {
+        return gameRecDict;
+    }
+
+    public event Action OnUpdateGameRecInfo;
+    public void UpdateGameRecInfo(HA009_tagSCGameRecInfo vNetData)
+    {
+
+        var act = GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int treasureType = config.ActTreasureType;
+        if (vNetData.RecType != RecordType || treasureType != (int)vNetData.RecID) return;
+
+        if (vNetData.RecList.IsNullOrEmpty()) return;
+
+        if (isSendFirst)
+        {
+            gameRecDict.Clear();
+        }
+
+        foreach (var rec in vNetData.RecList)
+        {
+            try
+            {
+                var playerName = JsonMapper.ToObject(rec.UserData)["Name"].ToString();
+                var arenaGameRec = new HeroReturnGameRec
+                {
+                    Time = (int)rec.Time,
+                    ItemID = (int)rec.Value1,
+                    ItemCount = rec.Value2,
+                    PlayerID = (int)rec.Value3,
+                    ServerID = (int)rec.Value4,
+                    PlayerName = playerName,
+                };
+                gameRecDict.Add(arenaGameRec);
+            }
+            catch (Exception ex)
+            {
+                Debug.LogError($"JSON瑙f瀽閿欒: {ex.Message}, UserData: {rec.UserData}");
+                continue;
+            }
+        }
+
+        if (isSendFirst)
+        {
+            isSendFirst = !isSendFirst;
+            gameRecDict.Sort((x, y) => x.Time.CompareTo(y.Time));
+        }
+
+        OnUpdateGameRecInfo?.Invoke();
+
+    }
+
+    #endregion
+}
+
+
+public class HeroReturnGiftItem
+{
+    public int type;//0 鍟嗗簵id 1 鍏呭�糹d
+    public int id;
+}
+
+public enum HeroReturnRedPointType
+{
+    CheckIn = 1,
+    StarUp = 2,
+    Shop = 3,
+    Gift = 4,
+}
+
+public class HeroReturnGameRec
+{
+    public int Time;
+    public int ItemID;
+    public long ItemCount;
+    public int PlayerID;
+    public int ServerID;
+    public string PlayerName;
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnManager.cs.meta b/Main/System/HeroReturn/HeroReturnManager.cs.meta
new file mode 100644
index 0000000..106f3a9
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b509add974a70944ea78b2739e505c32
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnPopWin.cs b/Main/System/HeroReturn/HeroReturnPopWin.cs
new file mode 100644
index 0000000..07524ae
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnPopWin.cs
@@ -0,0 +1,96 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnPopWin : UIBase
+{
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] UIHeroController rolelhShow;
+    [SerializeField] ImageEx qaulityBgImage;
+    [SerializeField] ImageEx qaulityImage;
+    [SerializeField] ButtonEx goButton;
+    [SerializeField] ImageEx titleBgImage;
+    [SerializeField] ImageEx titleImage;
+    [SerializeField] ImageEx infoBgImage;
+    [SerializeField] UIEffectPlayer uiEffectPlayer;
+    [SerializeField] TextEx infoText;
+    [SerializeField] TextEx timeText;
+    [SerializeField] Toggle todayPopToggle;
+    [SerializeField] ButtonEx closeButton;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        goButton.SetListener(() =>
+        {
+            UIManager.Instance.CloseWindow<HeroReturnPopWin>();
+            if (!UIManager.Instance.IsOpened<HeroReturnWin>())
+                UIManager.Instance.OpenWindow<HeroReturnWin>();
+        });
+        todayPopToggle.AddListener((bool value) =>
+        {
+            if (value)
+                manager.SavePopTimeData();
+        });
+    }
+
+    protected override void OnPreOpen()
+    {
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText, "HeroDebutPop02");
+    }
+
+    private void Display()
+    {
+        uiEffectPlayer.Stop();
+        todayPopToggle.isOn = !manager.IsTodayPop;
+
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        var heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null) return;
+
+        int skinID = manager.GetDefaultSkinID(heroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        uiEffectPlayer.effectId = artConfig.PopInfoBgUIEffectId;
+        uiEffectPlayer.Play();
+
+        bgImage.SetSprite(artConfig.PopBgImage);
+        bgImage.SetNativeSize();
+
+        qaulityBgImage.SetSprite($"HeroDebutPopQaulityBG{heroConfig.Quality}");
+        qaulityBgImage.SetNativeSize();
+
+        qaulityImage.SetSprite($"HeroDebutPopQaulity{heroConfig.Quality}");
+        qaulityImage.SetNativeSize();
+
+        titleBgImage.SetSprite(artConfig.PopTitleBgImage);
+        titleBgImage.SetNativeSize();
+
+        titleImage.SetSprite(artConfig.PopTitleImage);
+        titleImage.SetNativeSize();
+
+        infoBgImage.SetSprite(artConfig.PopInfoBgImage);
+        infoBgImage.SetNativeSize();
+
+        infoText.text = artConfig.PopInfoText;
+        infoText.color = manager.ParseColor32(artConfig.PopInfoColor);
+
+        rolelhShow.Create(skinID, 1, motionName: "", isLh: true);
+
+        OnSecondEvent();
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnPopWin.cs.meta b/Main/System/HeroReturn/HeroReturnPopWin.cs.meta
new file mode 100644
index 0000000..ccb00d2
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnPopWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2ec133afd45ed6548bf892a3179cba58
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnRankAwardCell.cs b/Main/System/HeroReturn/HeroReturnRankAwardCell.cs
new file mode 100644
index 0000000..493ad95
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankAwardCell.cs
@@ -0,0 +1,45 @@
+using UnityEngine;
+
+public class HeroReturnRankAwardCell : CellView
+{
+    [SerializeField] ImageEx imgRank;
+    [SerializeField] TextEx txtRank;
+    [SerializeField] ItemCell[] itemCells;
+    public void Display(int rankA, int templateID)
+    {
+        var config = ActBillboardAwardConfig.GetConfig(templateID, rankA);
+        if (config == null) return;
+
+
+        if (rankA <= 3)
+        {
+            imgRank.SetActive(true);
+            txtRank.SetActive(false);
+            imgRank.SetSprite(StringUtility.Concat("Rank", rankA.ToString()));
+            txtRank.text = rankA.ToString();
+        }
+        else
+        {
+            imgRank.SetActive(false);
+            txtRank.SetActive(true);
+            txtRank.text = Language.Get("Arena15", rankA, config.RankB);
+        }
+
+        int[][] rewardArr = config.AwardItemList;
+        for (int i = 0; i < itemCells.Length; i++)
+        {
+            var itemCell = itemCells[i];
+            if (!rewardArr.IsNullOrEmpty() && i < rewardArr.Length)
+            {
+                int itemCellIndex = i;
+                itemCell.SetActive(true);
+                itemCell.Init(new ItemCellModel(rewardArr[i][0], true, rewardArr[i][1]));
+                itemCell.button.SetListener(() => ItemTipUtility.Show(rewardArr[itemCellIndex][0], true));
+            }
+            else
+            {
+                itemCell.SetActive(false);
+            }
+        }
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnRankAwardCell.cs.meta b/Main/System/HeroReturn/HeroReturnRankAwardCell.cs.meta
new file mode 100644
index 0000000..291d287
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankAwardCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 31c2c107b8558ce4db4c8208a7019236
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnRankCell.cs b/Main/System/HeroReturn/HeroReturnRankCell.cs
new file mode 100644
index 0000000..2b748bb
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankCell.cs
@@ -0,0 +1,76 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnRankCell : MonoBehaviour
+{
+    [SerializeField] AvatarCell avatarCell;
+    [SerializeField] Text rankText;
+    [SerializeField] Text rankValueText;    //鎺掑悕姣旇緝鍐呭
+    [SerializeField] Text nameText;
+    [SerializeField] OfficialTitleCell officialTitleCell;
+    [SerializeField] Button queryPlayerBtn; //鍚庣画娣诲姞鐐瑰嚮鏌ョ湅鐜╁璇︽儏
+
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    // rank 涓�0 浠h〃鐜╁鑷繁
+    public void Display(int rankType, int rank, string valueFormat)
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int billTempID = config.BillTempID;
+        var awardConfig = ActBillboardAwardConfig.GetConfig(billTempID, rank);
+
+        RankData rankData = null;
+        int viewPlayerId = (int)PlayerDatas.Instance.baseData.PlayerID;
+        if (rank != 0)
+        {
+            rankData = RankModel.Instance.GetRankDataByRank(rankType, rank);
+        }
+        else
+        {
+            rankData = RankModel.Instance.GetMyRank(rankType);
+            if (rankData == null)
+            {
+                //鍙栫帺瀹惰嚜宸辩殑鏁版嵁
+                avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
+                                                PlayerDatas.Instance.baseData.face,
+                                                PlayerDatas.Instance.baseData.facePic));
+                rankText.text = Language.Get("L1045");
+                rankValueText.text = awardConfig == null || awardConfig.NeedValue == 0 ? "0" : Language.Get("HeroDebut27", awardConfig.NeedValue);
+                nameText.text = PlayerDatas.Instance.baseData.PlayerName;
+                officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID);
+                return;
+            }
+            rank = rankData.rank;
+        }
+        if (rankData == null)
+        {
+            officialTitleCell.SetActive(false);
+            avatarCell.SetActive(false);
+            nameText.text = Language.Get("L1124");
+            rankValueText.text = awardConfig == null || awardConfig.NeedValue == 0 ? "0" : Language.Get("HeroDebut27", awardConfig.NeedValue);
+        }
+        else
+        {
+            officialTitleCell.SetActive(true);
+            officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
+            avatarCell.SetActive(true);
+            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4));
+            viewPlayerId = (int)rankData.id;
+            nameText.text = rankData.name1;
+            rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
+        }
+
+        rankText.text = rank.ToString();
+        if (queryPlayerBtn != null)
+        {
+            queryPlayerBtn.AddListener(() =>
+            {
+                AvatarHelper.TryViewOtherPlayerInfo(viewPlayerId);
+            });
+        }
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnRankCell.cs.meta b/Main/System/HeroReturn/HeroReturnRankCell.cs.meta
new file mode 100644
index 0000000..da17daf
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a9a73b5eecf896f46a562a01b9102ba6
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnRankTop3Cell.cs b/Main/System/HeroReturn/HeroReturnRankTop3Cell.cs
new file mode 100644
index 0000000..4ec37af
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankTop3Cell.cs
@@ -0,0 +1,47 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnRankTop3Cell : MonoBehaviour
+{
+    //[SerializeField] Model 鏄剧ずNPC 姝﹀皢妯″瀷
+    [SerializeField] Text rankValueText;    //鎺掑悕姣旇緝鍐呭
+    [SerializeField] Text nameText;
+    [SerializeField] OfficialTitleCell officialTitleCell;
+    [SerializeField] Button queryPlayerBtn; //鍚庣画娣诲姞鐐瑰嚮鏌ョ湅鐜╁璇︽儏
+    [SerializeField] HorseController model;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int rankType, int rank, string valueFormat = "{0}")
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int billTempID = config.BillTempID;
+        var awardConfig = ActBillboardAwardConfig.GetConfig(billTempID, rank);
+
+
+        var rankData = RankModel.Instance.GetRankDataByRank(rankType, rank);
+        if (rankData == null)
+        {
+            rankValueText.text = awardConfig == null || awardConfig.NeedValue == 0 ? "0" : Language.Get("HeroDebut40", awardConfig.NeedValue);
+            nameText.text = Language.Get("L1124");
+            officialTitleCell.SetActive(false);
+            model.SetActive(false);
+            return;
+        }
+        officialTitleCell.SetActive(true);
+        rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
+        nameText.text = rankData.name1;
+        officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
+        model.SetActive(true);
+        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, rank == 1 ? 1f : 0.8f);
+        queryPlayerBtn.SetListener(() =>
+        {
+            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id);
+        });
+    }
+
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnRankTop3Cell.cs.meta b/Main/System/HeroReturn/HeroReturnRankTop3Cell.cs.meta
new file mode 100644
index 0000000..5a00fb5
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankTop3Cell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e3f3dcdd709d3ab4e918517695fb715a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnRankWin.cs b/Main/System/HeroReturn/HeroReturnRankWin.cs
new file mode 100644
index 0000000..d9a437f
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankWin.cs
@@ -0,0 +1,175 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnRankWin : FunctionsBaseWin
+{
+    [SerializeField] ButtonEx btnClose;
+    [SerializeField] RectTransform rankRect;
+    [SerializeField] RectTransform awardRect;
+    [SerializeField] TextEx timeText;
+
+
+
+    [Header("鎺掕")]
+    [SerializeField] ScrollerController rankScroller;
+    [SerializeField] List<HeroReturnRankTop3Cell> playerTop3Cells;
+    [SerializeField] HeroReturnRankCell myRankCell;
+    [HideInInspector] public string valueFormat = "{0}";
+    [Header("濂栧姳")]
+    // [SerializeField] TextEx txtCountdown;
+    [SerializeField] ScrollerController awardScroller;
+    [SerializeField] ImageEx heroImage;
+    [SerializeField] TextEx myRankNumText;
+    [SerializeField] TextEx myCallCntText;
+    [SerializeField] TextEx timeText1;
+
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnClose.SetListener(CloseWindow);
+    }
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        RankModel.Instance.ResetQueryParam();
+        RankModel.Instance.QueryRankByPage(manager.sendRankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID, groupValue1: manager.actNum);
+
+        RankModel.Instance.onRankRefresh += OnRankRefresh;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        rankScroller.OnRefreshCell += OnRefreshCell;
+        awardScroller.OnRefreshCell += OnRefreshAwardCell;
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        RankModel.Instance.onRankRefresh -= OnRankRefresh;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        rankScroller.OnRefreshCell -= OnRefreshCell;
+        awardScroller.OnRefreshCell -= OnRefreshAwardCell;
+    }
+
+    void OnRankRefresh(int type)
+    {
+        RankRefresh();
+    }
+
+    void RankRefresh()
+    {
+        ShowTop3();
+        rankScroller.m_Scorller.RefreshActiveCellViews();
+        DisplayMyRank();
+        DisplayAwardMyRank();
+    }
+
+    void CreateRankScroller()
+    {
+        rankScroller.Refresh();
+        var cnt = RankModel.Instance.GetRankShowMaxCnt(manager.sendRankType);
+        for (int i = 3; i < cnt; i++)
+        {
+            rankScroller.AddCell(ScrollerDataType.Header, i);
+        }
+        rankScroller.Restart();
+    }
+
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<HeroReturnRankCell>();
+        _cell.Display(manager.loadRankType, cell.index + 1, valueFormat);
+        RankModel.Instance.ListenRankPage(manager.sendRankType, cell.index, groupValue1: manager.actNum);
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+        manager.GetActTimeStr(timeText1);
+    }
+
+    protected override void OpenSubUIByTabIndex()
+    {
+        rankRect.SetActive(functionOrder == 0);
+        awardRect.SetActive(functionOrder == 1);
+        Display();
+    }
+
+    public void Display()
+    {
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        if (functionOrder == 0)
+        {
+            ShowTop3();
+            CreateRankScroller();
+            DisplayMyRank();
+        }
+        else
+        {
+            CreateAwardScroller();
+            heroImage.SetSprite(artConfig.RankAwardHeroImage);
+            heroImage.SetNativeSize();
+            DisplayAwardMyRank();
+        }
+        OnSecondEvent();
+    }
+
+    private void DisplayMyRank()
+    {
+        myRankCell.Display(manager.loadRankType, 0, valueFormat);
+    }
+
+    void ShowTop3()
+    {
+        for (int i = 0; i < playerTop3Cells.Count; i++)
+        {
+            playerTop3Cells[i].Display(manager.loadRankType, i + 1);
+        }
+    }
+
+    void DisplayAwardMyRank()
+    {
+
+        RankData rankData = RankModel.Instance.GetMyRank(manager.loadRankType);
+        if (rankData == null)
+        {
+            myRankNumText.text = Language.Get("L1045");
+            myCallCntText.text = "0";
+            return;
+        }
+        myRankNumText.text = Language.Get("WarlordPavilion12", rankData.rank);
+        myCallCntText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
+    }
+
+    int billTempID;
+    private void CreateAwardScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        billTempID = config.BillTempID;
+        var list = ActBillboardAwardConfig.GetRankASortList(billTempID);
+        if (list == null) return;
+
+        awardScroller.Refresh();
+        for (int i = 0; i < list.Count; i++)
+        {
+            awardScroller.AddCell(ScrollerDataType.Header, list[i]);
+        }
+        awardScroller.Restart();
+    }
+
+    private void OnRefreshAwardCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<HeroReturnRankAwardCell>();
+        _cell?.Display(cell.index, billTempID);
+    }
+}
\ No newline at end of file
diff --git a/Main/System/HeroReturn/HeroReturnRankWin.cs.meta b/Main/System/HeroReturn/HeroReturnRankWin.cs.meta
new file mode 100644
index 0000000..ea39169
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnRankWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 564897474a653594fbb6f294779e17c1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnShopCell.cs b/Main/System/HeroReturn/HeroReturnShopCell.cs
new file mode 100644
index 0000000..1dcedfb
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnShopCell.cs
@@ -0,0 +1,134 @@
+锘縰sing UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnShopCell : MonoBehaviour
+{
+    [SerializeField] Transform saleRect;
+    [SerializeField] Text saleText;
+    [SerializeField] Text itemName;
+    [SerializeField] ItemCell itemCell;
+    [SerializeField] Text limitText;
+    [SerializeField] Text lockTip;
+
+    [SerializeField] Transform priceRect;
+    [SerializeField] Image priceIcon;
+    [SerializeField] Text priceText;
+
+    [SerializeField] Transform priceRect1;//灞呬腑浣嶇疆鐨勪环鏍�
+    [SerializeField] Image priceIcon1;
+    [SerializeField] Text priceText1;
+
+    [SerializeField] Transform salePriceRect;
+    [SerializeField] Text salePriceText;
+    [SerializeField] Button buyButton;
+    [SerializeField] Image freeRedPoint;
+    [SerializeField] Text freeText;
+    [SerializeField] Image exclusiveImage;//涓撳睘
+    [SerializeField] Image sellOutImage;//鍞絼
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int index)
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ExShopType, out var list)) return;
+
+        var storeData = list[index];
+        int shopID = storeData.shopId;
+        var itemID = storeData.storeConfig.ItemID;
+        var itemCount = storeData.storeConfig.ItemCnt;
+        exclusiveImage.SetActive(storeData.storeConfig.IsExclusive == 1);
+        itemCell.Init(new ItemCellModel(itemID, false, itemCount));
+        itemCell.button.AddListener(() =>
+        {
+            ItemTipUtility.Show(itemID);
+        });
+        var itemConfig = ItemConfig.Get(itemID);
+        itemName.text = itemConfig.ItemName;
+
+        //鎶樻墸
+        if (storeData.storeConfig.MoneyOriginal != 0)
+        {
+            saleRect.SetActive(true);
+            saleText.text = Language.Get("storename5", (storeData.storeConfig.MoneyNum * 10 / (float)storeData.storeConfig.MoneyOriginal).ToString("0.#"));
+        }
+        else
+        {
+            saleRect.SetActive(false);
+        }
+
+
+        var buyCnt = StoreModel.Instance.GetShopLimitBuyCount(shopID);
+        string limitStr = "";
+        if (storeData.storeConfig.MoneyNum == 0)
+        {
+            //鍏嶈垂
+            limitStr = "";
+        }
+        else if (storeData.storeConfig.ResetType == 0)
+        {
+            //闄愯喘
+            limitStr = storeData.storeConfig.LimitCnt > 0 ? Language.Get("storename8", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt) : "";
+        }
+        else if (storeData.storeConfig.ResetType == 1)
+        {
+            //姣忔棩闄愯喘
+            limitStr = Language.Get("storename6", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt);
+        }
+        else if (storeData.storeConfig.ResetType == 2)
+        {
+            //姣忓懆闄愯喘
+            limitStr = Language.Get("storename7", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt);
+        }
+
+        limitText.text = buyCnt >= storeData.storeConfig.LimitCnt ? UIHelper.AppendColor(TextColType.Gray, limitStr) : limitStr;
+        buyButton.AddListener(() => { BuyGoods(shopID); });
+
+
+        //0鍙喘涔� 1宸插敭缃� 2鍏嶈垂 3鏈В閿�
+        var state = StoreModel.Instance.GetShopIDState(shopID);
+        sellOutImage.SetActive(state == 1);
+        freeRedPoint.SetActive(state == 2);
+        lockTip.text = state == 2 ? Language.Get("storename10", storeData.storeConfig.UnlockValue) : string.Empty;
+
+        priceRect.SetActive(state != 2 && storeData.storeConfig.MoneyOriginal != 0);
+        priceRect1.SetActive(state != 2 && storeData.storeConfig.MoneyOriginal == 0);
+        freeText.SetActive(state == 2);
+        salePriceRect.SetActive(state != 2 && storeData.storeConfig.MoneyOriginal != 0);
+
+        priceText.text = storeData.storeConfig.MoneyNum.ToString();
+        priceText1.text = storeData.storeConfig.MoneyNum.ToString();
+
+        if (storeData.storeConfig.MoneyType <= 0)
+        {
+            priceIcon.SetItemSprite(storeData.storeConfig.CostItemID);
+            priceIcon1.SetItemSprite(storeData.storeConfig.CostItemID);
+        }
+        else
+        {
+            priceIcon.SetIconWithMoneyType(storeData.storeConfig.MoneyType);
+            priceIcon1.SetIconWithMoneyType(storeData.storeConfig.MoneyType);
+        }
+
+        salePriceText.text = storeData.storeConfig.MoneyOriginal.ToString();
+    }
+
+    void BuyGoods(int shopID)
+    {
+        var state = StoreModel.Instance.GetShopIDState(shopID);
+        if (state == 1) return;
+
+        if (state == 2)
+        {
+            StoreModel.Instance.SendBuyShopItem(StoreConfig.Get(shopID), 1);
+        }
+        else
+        {
+            StoreModel.Instance.buyShopID = shopID;
+            UIManager.Instance.OpenWindow<BuyItemWin>();
+        }
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnShopCell.cs.meta b/Main/System/HeroReturn/HeroReturnShopCell.cs.meta
new file mode 100644
index 0000000..e2e7aa9
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnShopCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9f3fa1a06f369cd43bfeed05c9fc78da
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnShopLineCell.cs b/Main/System/HeroReturn/HeroReturnShopLineCell.cs
new file mode 100644
index 0000000..70c2d9b
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnShopLineCell.cs
@@ -0,0 +1,30 @@
+锘縰sing UnityEngine;
+
+public class HeroReturnShopLineCell : CellView
+{
+    [SerializeField] HeroReturnShopCell[] storeCells;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int index)
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ExShopType, out var list)) return;
+
+        for (int i = 0; i < storeCells.Length; i++)
+        {
+            if (index + i < list.Count)
+            {
+                storeCells[i].SetActive(true);
+                storeCells[i].Display(index + i);
+            }
+            else
+            {
+                storeCells[i].SetActive(false);
+            }
+        }
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnShopLineCell.cs.meta b/Main/System/HeroReturn/HeroReturnShopLineCell.cs.meta
new file mode 100644
index 0000000..72c39b5
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnShopLineCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7dbf46352446602458ece7d5acde3f20
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnShopWin.cs b/Main/System/HeroReturn/HeroReturnShopWin.cs
new file mode 100644
index 0000000..b0a13f5
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnShopWin.cs
@@ -0,0 +1,80 @@
+using UnityEngine;
+
+public class HeroReturnShopWin : UIBase
+{
+    [SerializeField] OwnItemCell ownItemCell;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] TextEx timeText;
+    [SerializeField] ScrollerController scroller;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+    }
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        StoreModel.Instance.RefreshShopEvent += CreateScroller;
+        StoreModel.Instance.RefreshBuyShopLimitEvent += CreateScroller;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        if (!manager.IsShopVisitedToday)
+        {
+            HeroReturnManager.Instance.SaveShopVisitTimeData();
+            manager.UpdateRedpoint();
+        }
+
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        ownItemCell.itemID = config.ExShopCostItemID;
+        CreateScroller();
+        OnSecondEvent();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        StoreModel.Instance.RefreshShopEvent -= CreateScroller;
+        StoreModel.Instance.RefreshBuyShopLimitEvent -= CreateScroller;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        StoreModel.Instance.selectStoreFuncType = StoreFunc.Normal;
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnShopLineCell;
+        _cell.Display(cell.index);
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+
+    void CreateScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ExShopType, out var list)) return;
+
+        scroller.Refresh();
+        for (int i = 0; i < list.Count; i++)
+        {
+            if (i % 3 == 0)
+            {
+                scroller.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+        scroller.Restart();
+        scroller.lockType = EnhanceLockType.KeepVertical;
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnShopWin.cs.meta b/Main/System/HeroReturn/HeroReturnShopWin.cs.meta
new file mode 100644
index 0000000..00eb07b
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnShopWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fceb72924bf0d6c418f2128afc294a52
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnSkinAwardCell.cs b/Main/System/HeroReturn/HeroReturnSkinAwardCell.cs
new file mode 100644
index 0000000..dfa3ffe
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnSkinAwardCell.cs
@@ -0,0 +1,18 @@
+using UnityEngine;
+
+public class HeroReturnSkinAwardCell : CellView
+{
+    [SerializeField] ItemCell itemCell;
+    public void Display(int index, int[][] arr)
+    {
+        if (arr == null || arr.Length <= index) return;
+        int itemID = arr[index][0];
+        long itemCount = arr[index][1];
+        
+        itemCell.Init(new ItemCellModel(itemID, false, itemCount));
+        itemCell.button.AddListener(() =>
+        {
+            ItemTipUtility.Show(itemID);
+        });
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnSkinAwardCell.cs.meta b/Main/System/HeroReturn/HeroReturnSkinAwardCell.cs.meta
new file mode 100644
index 0000000..acabbe0
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnSkinAwardCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f6b0d10c152793d4f81f3b5fe4182937
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnSkinTabCell.cs b/Main/System/HeroReturn/HeroReturnSkinTabCell.cs
new file mode 100644
index 0000000..6d8e777
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnSkinTabCell.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+public class HeroReturnSkinTabCell : CellView
+{
+    [SerializeField] ImageEx tabBgImage;
+    [SerializeField] ButtonEx tabButton;
+    [SerializeField] RectTransform chooseRect;
+    [SerializeField] RectTransform maskRect;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int index, List<int> list)
+    {
+        if (list?.Count <= index) return;
+
+        var skinID = list[index];
+        var skinArtConfig = ActHeroReturnSkinArtConfig.Get(skinID);
+        if (skinArtConfig == null) return;
+
+        tabBgImage.SetSprite(skinArtConfig.TabInfoImage);
+        tabBgImage.SetNativeSize();
+        maskRect.SetActive(manager.currentChooseSkinID != skinID);
+        chooseRect.SetActive(manager.currentChooseSkinID == skinID);
+        tabButton.SetListener(() =>
+        {
+            manager.currentChooseSkinID = skinID;
+        });
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnSkinTabCell.cs.meta b/Main/System/HeroReturn/HeroReturnSkinTabCell.cs.meta
new file mode 100644
index 0000000..88fa8b3
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnSkinTabCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4f356ffc491c15044879e4d6601e5726
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnSkinWin.cs b/Main/System/HeroReturn/HeroReturnSkinWin.cs
new file mode 100644
index 0000000..d5ccbf6
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnSkinWin.cs
@@ -0,0 +1,229 @@
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnSkinWin : UIBase
+{
+    [SerializeField] float modelScale = 1f;
+    [SerializeField] RawImage bgImage;
+    [SerializeField] ImageEx heroNameImage;
+    [SerializeField] ImageEx skinInfoImage;
+    [SerializeField] ImageEx awardBgImage;
+    [SerializeField] TextEx timeText;
+    [SerializeField] ButtonEx buyButton;
+    [SerializeField] ImageEx buyImage;
+    [SerializeField] ImageEx countryImage;
+    [SerializeField] TextEx buyText;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] UIHeroController uiHeroController;
+    [SerializeField] UIHeroController lhController;
+    [SerializeField] ScrollerController awardScroller;
+    [SerializeField] ScrollerController tabScroller;
+    [SerializeField] Color numColor;
+    [SerializeField] TextEx[] wearAttrText;
+    [SerializeField] TextEx[] roleAttrText;
+    [SerializeField] ButtonEx infoButton;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        infoButton.SetListener(() =>
+        {
+            int heroID = manager.GetHeroIDBySkinID(manager.currentChooseSkinID);
+            HeroUIManager.Instance.selectForPreviewHeroID = heroID;
+            HeroUIManager.Instance.selectSkinIndex = manager.GetSkinIndexInHeroConfig(heroID, manager.currentChooseSkinID);
+            UIManager.Instance.OpenWindow<HeroBestBaseWin>(1);
+        });
+    }
+
+    protected override void OnPreOpen()
+    {
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
+        awardScroller.OnRefreshCell += OnRefreshAwardCell;
+        tabScroller.OnRefreshCell += OnRefreshTabCell;
+        manager.OnCurrentChooseSkinIDChangeEevent += OnCurrentChooseSkinIDChange;
+        CreateTabScroller();
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
+        awardScroller.OnRefreshCell -= OnRefreshAwardCell;
+        tabScroller.OnRefreshCell -= OnRefreshTabCell;
+        manager.OnCurrentChooseSkinIDChangeEevent -= OnCurrentChooseSkinIDChange;
+    }
+
+    private void OnCurrentChooseSkinIDChange()
+    {
+        tabScroller.m_Scorller.RefreshActiveCellViews();
+        Display();
+    }
+
+    void OnRefreshTabCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnSkinTabCell;
+        _cell.Display(cell.index, skinIDList);
+    }
+
+    List<int> skinIDList;
+    void CreateTabScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        skinIDList = manager.GetSkinIDList(act.CfgID, heroID, artConfig.MainSkinID);
+        if (skinIDList.IsNullOrEmpty()) return;
+        manager.currentChooseSkinID = skinIDList[0];
+
+        tabScroller.Refresh();
+        for (int i = 0; i < skinIDList.Count; i++)
+        {
+            tabScroller.AddCell(ScrollerDataType.Header, i);
+        }
+        tabScroller.Restart();
+    }
+
+    int[][] arr = null;
+    void OnRefreshAwardCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnSkinAwardCell;
+        _cell.Display(cell.index, arr);
+    }
+
+    void CreateAwardScroller(int[][] sourceArr)
+    {
+        if (sourceArr == null) return;
+
+        // 1. 鑾峰彇宸叉嫢鏈夌殑 ID 闆嗗悎 (浣跨敤 LINQ 绠�娲佹槑浜�)
+        var ownedItems = HeroSkinAttrConfig.GetItemList();
+        var itemIds = ownedItems != null ? new HashSet<int>(ownedItems) : new HashSet<int>();
+
+        // 2. 杩囨护鎺� items 涓凡鏈夌殑椤癸紝骞剁洿鎺ヨ祴鍊肩粰鎴愬憳鍙橀噺
+        // arr[i][0] 鍋囪涓哄垽鏂槸鍚﹀瓨鍦ㄤ簬 items 涓殑 ID
+        this.arr = System.Array.FindAll(sourceArr, row => !itemIds.Contains(row[0]));
+
+        // 3. 鍒锋柊 UI
+        awardScroller.Refresh();
+        for (int i = 0; i < this.arr.Length; i++)
+        {
+            awardScroller.AddCell(ScrollerDataType.Header, i);
+        }
+        awardScroller.Restart();
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+
+    private void OnRechargeCountEvent(int obj)
+    {
+        Display();
+    }
+
+    public void Display()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        int heroID = manager.GetFirstHeroId();
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        var heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null) return;
+
+        int skinID = manager.currentChooseSkinID;
+        var skinArtConfig = ActHeroReturnSkinArtConfig.Get(skinID);
+        if (skinArtConfig == null) return;
+
+        var heroSkinAttrConfig = HeroSkinAttrConfig.Get(skinID);
+        if (heroSkinAttrConfig == null) return;
+        if (heroSkinAttrConfig.WearAttrIDList == null) return;
+        if (heroSkinAttrConfig.WearAttrValueList == null) return;
+        if (heroSkinAttrConfig.RoleAttrIDList == null) return;
+        if (heroSkinAttrConfig.RoleAttrValueList == null) return;
+
+        var skinIDList = manager.GetSkinIDList(act.CfgID, heroID, skinID);
+        if (skinIDList.IsNullOrEmpty()) return;
+
+        int ctgId = manager.GetCtgIDBySkinID(skinID);
+        var ctgConfig = CTGConfig.Get(ctgId);
+        if (ctgConfig == null) return;
+
+        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
+        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
+        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
+
+        bgImage.SetTexture2D(skinArtConfig.BGImage);
+
+        heroNameImage.SetSprite(skinArtConfig.HeroNameImage);
+        heroNameImage.SetNativeSize();
+
+        skinInfoImage.SetSprite(skinArtConfig.SkinInfoImage);
+        skinInfoImage.SetNativeSize();
+
+        awardBgImage.SetSprite(skinArtConfig.AwardBGImage);
+        awardBgImage.SetNativeSize();
+
+        uiHeroController.Create(skinID, modelScale);
+        lhController.Create(skinID, 1, motionName: "", isLh: true);
+        countryImage.SetSprite(HeroUIManager.Instance.GetCountryIconName(heroConfig.Country));
+        OnSecondEvent();
+
+        CreateAwardScroller(ctgConfig.GainItemList);
+
+        bool isCanBuy = manager.IsNoSellOutCTGID(ctgId);
+        //buyImage.gray = !isCanBuy;
+        buyText.text = !isCanBuy ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
+
+        buyButton.interactable = isCanBuy;
+        buyButton.SetListener(() =>
+        {
+            RechargeManager.Instance.CTG(ctgId);
+        });
+
+        for (int i = 0; i < wearAttrText.Length; i++)
+            SetAttrInfo(0, i, heroSkinAttrConfig, wearAttrText[i]);
+
+        for (int i = 0; i < roleAttrText.Length; i++)
+            SetAttrInfo(1, i, heroSkinAttrConfig, roleAttrText[i]);
+
+    }
+
+    // type 0 绌挎埓灞炴�у�� 1 涓诲叕灞炴��
+    public void SetAttrInfo(int type, int index, HeroSkinAttrConfig heroSkinAttrConfig, TextEx info)
+    {
+        if (heroSkinAttrConfig == null) return;
+
+        int[] arrID = type == 0 ? heroSkinAttrConfig.WearAttrIDList : heroSkinAttrConfig.RoleAttrIDList;
+        int[] arrValue = type == 0 ? heroSkinAttrConfig.WearAttrValueList : heroSkinAttrConfig.RoleAttrValueList;
+        if (arrID?.Length <= index || arrValue?.Length <= index)
+        {
+            info.text = string.Empty;
+            return;
+        }
+
+        info.text = GetFullDescription(arrID[index], arrValue[index]);
+    }
+
+    string GetFullDescription(int id, long value)
+    {
+        var config = PlayerPropertyConfig.Get(id);
+        if (config == null) return string.Empty;
+        return Language.Get("HeroDebut33", config.ShowName, PlayerPropertyConfig.GetValueDescription(id, value));
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnSkinWin.cs.meta b/Main/System/HeroReturn/HeroReturnSkinWin.cs.meta
new file mode 100644
index 0000000..c0d4190
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnSkinWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a583b7b333d69584792f6aef8834bfcd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnStarUpCell.cs b/Main/System/HeroReturn/HeroReturnStarUpCell.cs
new file mode 100644
index 0000000..5a56186
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpCell.cs
@@ -0,0 +1,126 @@
+using System.Linq;
+using UnityEngine;
+
+public class HeroReturnStarUpCell : CellView
+{
+    [SerializeField] ItemCell freeAwardItemCell;
+    [SerializeField] Transform freeAwardHaveTransform;//宸查鍙�
+    [SerializeField] Transform freeAwardCanHaveTransform;//鍙鍙�
+
+    [SerializeField] Transform upProcssBGTransform;
+    [SerializeField] Transform upProcessTransform;
+    [SerializeField] Transform downProcssBGTransform;
+    [SerializeField] Transform downProcessTransform;
+    [SerializeField] TextEx starCntText;
+    [SerializeField] TextEx limitText;
+    [SerializeField] ButtonEx buyButton;
+    [SerializeField] ImageEx buyImage;
+    [SerializeField] TextEx buyText;
+    [SerializeField] ImageEx rateImage;
+    [SerializeField] TextEx rateText;
+    [SerializeField] ScrollerController scroller;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    int id;
+    public void Display(int id, CellView cell)
+    {
+        this.id = id;
+
+        int heroID = cell.info.Value.infoInt1;
+        bool isFrist = cell.info.Value.infoInt2 == 1;
+        bool isEnd = cell.info.Value.infoInt3 == 1;
+
+        var config = ActHeroAppearStarConfig.Get(id);
+        if (config == null) return;
+
+        var heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null) return;
+
+        if (config.FreeAwardItemList.IsNullOrEmpty()) return;
+        int ctgId = config.StarGiftCTGID;
+        int awardIndex = config.AwardIndex;
+        if (!manager.TryGetStarUpAwardArr(id, heroID, out int[][] list)) return;
+        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
+        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
+        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
+        CTGConfig ctgConfig = CTGConfig.Get(ctgId);
+        if (ctgConfig == null) return;
+
+        rateImage.SetActive(true);
+        rateText.text = Language.Get("DailySpecials07", ctgConfig.Percentage);
+
+        int state = manager.GetStarUpFreeState(id);//0 - 鏈В閿� 1 - 鍙鍙� 2 - 宸查鍙�
+        freeAwardHaveTransform.SetActive(state == 2);
+        freeAwardCanHaveTransform.SetActive(state == 1);
+
+        bool isNoSellOut = manager.IsNoSellOutCTGID(ctgId);
+        buyButton.interactable = state != 0 && isNoSellOut;
+        buyButton.SetListener(() =>
+        {
+            if (isNoSellOut && state != 0)
+            {
+                RechargeManager.Instance.CTG(ctgId);
+            }
+        });
+        //buyImage.gray = state == 0 || !isNoSellOut;
+        buyText.text = !isNoSellOut ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
+        limitText.text = Language.Get("TimeRush08", UIHelper.AppendColor(rechargeCount.totalCount >= ctgConfig.TotalBuyCount ? TextColType.Red : TextColType.DarkGreen, $"{rechargeCount.totalCount}/{ctgConfig.TotalBuyCount}"));
+        bool isHeroStarOk = manager.IsHeroStarCntOk(heroConfig.HeroID, config.NeedStar) && HeroManager.Instance.HasHero(heroConfig.HeroID) && manager.IsLockStarHero(manager.GetOperationHeroAppearInfo());
+        upProcssBGTransform.SetActive(!isFrist);
+        downProcssBGTransform.SetActive(!isEnd);
+
+        upProcessTransform.SetActive(isHeroStarOk);
+        downProcessTransform.SetActive(isHeroStarOk);
+
+        CreateScroller(list);
+
+        int[] arr = config.FreeAwardItemList.First();
+        int itemID = arr[0];
+        int itemCount = arr[1];
+        freeAwardItemCell.SetActive(true);
+        freeAwardItemCell.Init(new ItemCellModel(itemID, false, itemCount));
+        freeAwardItemCell.button.AddListener(() =>
+        {
+            if (state == 1)
+            {
+                manager.SendGetStarReward();
+            }
+            else
+            {
+                ItemTipUtility.Show(itemID);
+            }
+        });
+
+        starCntText.text = Language.Get("HeroDebut20", config.NeedStar);
+    }
+
+    private void CreateScroller(int[][] list)
+    {
+        if (list == null) return;
+        var config = ActHeroAppearStarConfig.Get(id);
+        if (config == null) return;
+
+        scroller.OnRefreshCell += OnRefreshCell;
+        scroller.Refresh();
+        for (int i = 0; i < list.Length; i++)
+        {
+            var item = list[i];
+            var itemID = item[0];
+            var itemCount = item[1];
+            CellInfo cellInfo = new()
+            {
+                infoInt1 = itemID,
+                infoInt2 = itemCount,
+                infoInt3 = manager.IsNoSellOutCTGID(config.StarGiftCTGID) ? 1 : 0,
+            };
+            scroller.AddCell(ScrollerDataType.Header, i, cellInfo);
+        }
+        scroller.Restart();
+        scroller.OnRefreshCell -= OnRefreshCell;
+    }
+
+    private void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<HeroReturnStarUpPaidItemCell>();
+        _cell?.Display(cell.index, cell);
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnStarUpCell.cs.meta b/Main/System/HeroReturn/HeroReturnStarUpCell.cs.meta
new file mode 100644
index 0000000..c62b946
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 98c3340ec72bd5b46935ede657bae2b3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs b/Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs
new file mode 100644
index 0000000..1bcafcc
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+
+public class HeroReturnStarUpChangeCell : CellView
+{
+    [SerializeField] HeroReturnStarUpChangeItem[] items;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    public void Display(int rowIndex)
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var heroArr = config.ActHeroIDList;
+        if (heroArr.IsNullOrEmpty()) return;
+
+        for (int i = 0; i < items.Length; i++)
+        {
+            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
+            if (index < heroArr.Length)
+            {
+                items[i].SetActive(true);
+                items[i].Display(index, heroArr);
+            }
+            else
+            {
+                items[i].SetActive(false);
+            }
+        }
+    }
+
+}
diff --git a/Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs.meta b/Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs.meta
new file mode 100644
index 0000000..065806b
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 24e8dba4fdfc18547bd908c4906c29bc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs b/Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs
new file mode 100644
index 0000000..d5d9a2a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs
@@ -0,0 +1,41 @@
+using UnityEngine;
+using UnityEngine.UI;
+
+public class HeroReturnStarUpChangeItem : MonoBehaviour
+{
+
+    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
+    [SerializeField] Image jobImg;
+    [SerializeField] Text nameText;
+    [SerializeField] Transform select;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    HeroConfig heroConfig;
+    int index;
+    public void Display(int index, int[] heroIds)
+    {
+        this.index = index;
+        if (heroIds?.Length <= index) return;
+
+        int heroId = heroIds[index];
+        heroConfig = HeroConfig.Get(heroId);
+        if (heroConfig == null) return;
+        
+        int skinID = manager.GetDefaultSkinID(heroId);
+        var heroSkinConfig = HeroSkinConfig.Get(skinID);
+        if (heroSkinConfig == null) return;
+
+        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, OnClick);
+        nameText.text = heroConfig.Name;
+        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
+        bool isChoose = manager.nowStarUpChooseHeroID == heroId;
+        select?.SetActive(isChoose);
+    }
+
+    public void OnClick()
+    {
+        if (heroConfig == null) return;
+
+        manager.nowStarUpChooseHeroID = heroConfig.HeroID;
+
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs.meta b/Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs.meta
new file mode 100644
index 0000000..4440d4a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f8d8ae1944679f64abb94301a00e6938
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs b/Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs
new file mode 100644
index 0000000..664893a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs
@@ -0,0 +1,100 @@
+using UnityEngine;
+
+public class HeroReturnStarUpChangeWin : UIBase
+{
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] ButtonEx okButton;
+    [SerializeField] ButtonEx previewButton;
+    [SerializeField] UIHeroController uiHeroController;
+    public const int rowCountMax = 4;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        okButton.SetListener(() =>
+        {
+            var act = manager.GetOperationHeroAppearInfo();
+            if (act == null) return;
+
+            int index = manager.GetHeroIdIndex(act.CfgID, manager.nowStarUpChooseHeroID);
+            if (index < 0) return;
+
+            manager.SendHeroAppearStarHeroSelect(manager.actNum, index);
+            manager.SaveStarUpChooseHeroStateKey(act);
+            CloseWindow();
+
+        });
+        previewButton.SetListener(() =>
+        {
+            HeroUIManager.Instance.selectForPreviewHeroID = manager.nowStarUpChooseHeroID;
+            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
+        });
+    }
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        manager.OnNowStarUpChooseHeroIDChangeEvent += OnNowStarUpChooseHeroIDChangeEvent;
+        manager.nowStarUpChooseHeroID = manager.GetCurrentDisplayStarUpHeroId();
+        Display();
+        CreateScroller();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        manager.OnNowStarUpChooseHeroIDChangeEvent -= OnNowStarUpChooseHeroIDChangeEvent;
+        if (!UIManager.Instance.IsOpened<HeroReturnStarUpWin>() && manager.LoadStarUpChooseHeroStateKey(manager.GetOperationHeroAppearInfo()))
+        {
+            UIManager.Instance.OpenWindow<HeroReturnStarUpWin>();
+        }
+    }
+
+    private void OnNowStarUpChooseHeroIDChangeEvent()
+    {
+        Display();
+        scroller.m_Scorller.RefreshActiveCellViews();
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as HeroReturnStarUpChangeCell;
+        _cell.Display(cell.index);
+    }
+
+    void CreateScroller()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var arr = config.ActHeroIDList;
+        if (arr.IsNullOrEmpty()) return;
+
+
+        scroller.Refresh();
+        int rowCount = (int)Mathf.Ceil((float)arr.Length / rowCountMax);
+        for (int i = 0; i < rowCount; i++)
+        {
+            scroller.AddCell(ScrollerDataType.Header, i);
+        }
+        scroller.Restart();
+    }
+
+    void Display()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+
+        int skinID = manager.GetDefaultSkinID(manager.nowStarUpChooseHeroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        uiHeroController.Create(skinID, 1);
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs.meta b/Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs.meta
new file mode 100644
index 0000000..adca8da
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 509bac132ac2a424fbed7f0aa2ef09de
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs b/Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs
new file mode 100644
index 0000000..54d32aa
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs
@@ -0,0 +1,17 @@
+using UnityEngine;
+
+public class HeroReturnStarUpPaidItemCell : CellView
+{
+    [SerializeField] ItemCell itemCell;
+    [SerializeField] Transform soldOutTransform;
+    public void Display(int index, CellView cell)
+    {
+        int itemID = cell.info.Value.infoInt1;
+        int count = cell.info.Value.infoInt2;
+        bool isSoldOut = cell.info.Value.infoInt3 == 0;
+        soldOutTransform.SetActive(isSoldOut);
+        itemCell.SetActive(true);
+        itemCell.Init(new ItemCellModel((int)itemID, false, count));
+        itemCell.button.AddListener(() => ItemTipUtility.Show(itemID));
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs.meta b/Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs.meta
new file mode 100644
index 0000000..f912ba1
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dd781838fa949c54cafb8db9df042715
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnStarUpWin.cs b/Main/System/HeroReturn/HeroReturnStarUpWin.cs
new file mode 100644
index 0000000..7bc1420
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpWin.cs
@@ -0,0 +1,159 @@
+using UnityEngine;
+
+public class HeroReturnStarUpWin : UIBase
+{
+    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
+    [SerializeField] ImageEx jobImg;
+    [SerializeField] TextEx nameText;
+    [SerializeField] ButtonEx changeButton;
+    [SerializeField] ButtonEx lockButton;
+    [SerializeField] GradientText heroNameText;
+    [SerializeField] TextEx timeText;
+    [SerializeField] ImageEx heroImage;
+    [SerializeField] ButtonEx goCallButton;
+    [SerializeField] ButtonEx goInfoButton;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] ScrollerController scroller;
+    HeroReturnManager manager => HeroReturnManager.Instance;
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(CloseWindow);
+        goCallButton.SetListener(() =>
+        {
+            UIManager.Instance.CloseWindow<HeroReturnStarUpWin>();
+            UIManager.Instance.OpenWindow<HeroReturnCallWin>();
+        });
+        goInfoButton.SetListener(() =>
+        {
+            if (heroConfig == null) return;
+            UIManager.Instance.CloseWindow<HeroReturnStarUpWin>();
+            HeroUIManager.Instance.selectForPreviewHeroID = heroConfig.HeroID;
+            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
+        });
+        changeButton.SetListener(() =>
+        {
+            UIManager.Instance.OpenWindow<HeroReturnStarUpChangeWin>();
+        });
+        lockButton.SetListener(() =>
+        {
+            manager.SaveStarUpLockState(manager.GetOperationHeroAppearInfo());
+            Display();
+            manager.UpdateRedpoint();
+        });
+    }
+
+    protected override void OnPreOpen()
+    {
+        scroller.OnRefreshCell += OnRefreshCell;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
+        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        scroller.OnRefreshCell -= OnRefreshCell;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
+        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
+    }
+
+    private void OnUpdateHeroAppearPlayerInfoEvent()
+    {
+        scroller.m_Scorller.RefreshActiveCellViews();
+        Display();
+    }
+
+    private void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<HeroReturnStarUpCell>();
+        _cell?.Display(cell.index, cell);
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+
+    private void OnRechargeCountEvent(int obj)
+    {
+        scroller.m_Scorller.RefreshActiveCellViews();
+    }
+
+    HeroConfig heroConfig;
+    private void Display()
+    {
+        int heroID = manager.GetCurrentDisplayStarUpHeroId();
+        heroConfig = HeroConfig.Get(heroID);
+        if (heroConfig == null) return;
+
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null) return;
+
+        var heroArr = config.ActHeroIDList;
+        if (heroArr.Length <= manager.starHeroIndex) return;
+
+        int heroId = heroArr[manager.starHeroIndex];
+        heroConfig = HeroConfig.Get(heroId);
+        if (heroConfig == null) return;
+
+        int skinID = manager.GetDefaultSkinID(heroId);
+        var heroSkinConfig = HeroSkinConfig.Get(skinID);
+        if (heroSkinConfig == null) return;
+
+        bool isLockStarHero = manager.IsLockStarHero(act);
+        changeButton.SetActive(!isLockStarHero);
+        lockButton.interactable = !isLockStarHero;
+
+        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, () =>
+        {
+            if (isLockStarHero) return;
+            UIManager.Instance.OpenWindow<HeroReturnStarUpChangeWin>();
+        });
+        nameText.text = heroConfig.Name;
+        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
+
+
+        heroNameText.text = heroConfig.Name;
+        manager.SetGradientTextColor(heroNameText, artConfig.HeroNameColor);
+
+        heroImage.SetSprite(artConfig.StarUpHeroImage);
+        heroImage.SetNativeSize();
+
+        CreateScroller(config, heroConfig);
+    }
+
+    private void CreateScroller(ActHeroAppearConfig appearConfig, HeroConfig heroConfig)
+    {
+        if (appearConfig == null || heroConfig == null) return;
+        int starGiftTempID = appearConfig.StarGiftTempID;
+        var list = ActHeroAppearStarConfig.GetHeroReturnAwardIndexSortList(starGiftTempID);
+        if (list == null) return;
+
+        scroller.Refresh();
+        for (int i = 0; i < list.Count; i++)
+        {
+            var awardIndex = list[i];
+
+            var config = ActHeroAppearStarConfig.GetConfig(starGiftTempID, awardIndex);
+            if (config == null) continue;
+
+            CellInfo cellInfo = new()
+            {
+                infoInt1 = heroConfig.HeroID,
+                infoInt2 = i == 0 ? 1 : 0,
+                infoInt3 = i == list.Count - 1 ? 1 : 0
+            };
+            scroller.AddCell(ScrollerDataType.Header, config.ID, cellInfo);
+        }
+        scroller.Restart();
+        scroller.JumpIndex(manager.GetStarUpJumpIndex(starGiftTempID));
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnStarUpWin.cs.meta b/Main/System/HeroReturn/HeroReturnStarUpWin.cs.meta
new file mode 100644
index 0000000..8b82deb
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnStarUpWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dae38759f25f7eb4ab53165ca393cd2e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/HeroReturn/HeroReturnWin.cs b/Main/System/HeroReturn/HeroReturnWin.cs
new file mode 100644
index 0000000..715720a
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnWin.cs
@@ -0,0 +1,268 @@
+using System;
+using UnityEngine;
+using UnityEngine.UI;
+using DG.Tweening;
+
+public class HeroReturnWin : UIBase
+{
+    [SerializeField] RectTransform activeRect;
+    [SerializeField] RectTransform moveRect;
+    [SerializeField] RectTransform startRect;
+    [SerializeField] RectTransform endRect;
+
+    [SerializeField] ImageEx bgImage;
+    [SerializeField] ImageEx titleImage;
+    [SerializeField] TextEx timeText;
+    [SerializeField] ButtonEx animationButton;
+    [SerializeField] ButtonEx checkInButton; // 绛惧埌璧犵ぜ
+    [SerializeField] RedpointBehaviour checkInRedpoint;
+    [SerializeField] ButtonEx starUpButton; // 鍗囨槦璁″垝
+    [SerializeField] RedpointBehaviour starUpRedpoint;
+    [SerializeField] ButtonEx shopButton; // 鍏戞崲鍟嗗簵
+    [SerializeField] RedpointBehaviour shopRedpoint;
+    [SerializeField] ImageEx skinImage;
+    [SerializeField] ButtonEx skinButton; // 鏃惰鐗瑰崠
+    [SerializeField] ButtonEx giftButton; // 鐨囨潈绀煎寘
+    [SerializeField] RedpointBehaviour giftRedpoint;
+    [SerializeField] ButtonEx callButton; // 鐨囨潈鎷涘嫙
+    [SerializeField] UIHeroController uiHeroController;
+    [SerializeField] UIHeroController lhController;
+    [SerializeField] Image callRedImage;
+    [SerializeField] ButtonEx closeButton;
+    [SerializeField] float modleSize = 0.8f;
+
+    // 杞挱鐩稿叧
+    private const float CarouselInterval = 5f;       // 杞挱闂撮殧5绉�
+    private const float FadeDuration = 0.4f;          // 娓愬彉鏃堕暱
+    private int[] heroIdList;                         // 姝﹀皢ID鍒楄〃
+    private int currentHeroIndex;                      // 褰撳墠姝﹀皢绱㈠紩
+    private bool isCarouselActive;                    // 鏄惁姝e湪杞挱
+    private Tween carouselTween;                       // 杞挱娣″叆娣″嚭tween
+    private float carouselTimer;                       // 杞挱璁℃椂鍣�
+
+    HeroReturnManager manager => HeroReturnManager.Instance;
+
+    protected override void InitComponent()
+    {
+        closeButton.SetListener(() => UIManager.Instance.CloseWindow<HeroReturnWin>());
+        checkInButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCheckInWin>());
+        starUpButton.SetListener(() =>
+        {
+
+            if (manager.IsLockStarHero(manager.GetOperationHeroAppearInfo()))
+            {
+                UIManager.Instance.OpenWindow<HeroReturnStarUpWin>();
+                return;
+            }
+
+            if (!manager.LoadStarUpChooseHeroStateKey(manager.GetOperationHeroAppearInfo()))
+            {
+                UIManager.Instance.OpenWindow<HeroReturnStarUpChangeWin>();
+                return;
+            }
+            UIManager.Instance.OpenWindow<HeroReturnStarUpWin>();
+        });
+        shopButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnShopWin>());
+        skinButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnSkinWin>());
+        giftButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnGiftWin>());
+        callButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallWin>());
+    }
+
+    protected override void OnPreOpen()
+    {
+        InitRedpoint();
+
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
+        StoreModel.Instance.RefreshBuyShopLimitEvent += Display;
+        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        StopCarousel();
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
+        StoreModel.Instance.RefreshBuyShopLimitEvent -= Display;
+        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
+    }
+
+    private void OnUpdateHeroAppearPlayerInfoEvent()
+    {
+        Display();
+    }
+
+    private void OnRechargeCountEvent(int obj)
+    {
+        Display();
+    }
+
+    public void InitRedpoint()
+    {
+        checkInRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.CheckIn);
+        starUpRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.StarUp);
+        shopRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Shop);
+        giftRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Gift);
+    }
+
+    private void Display()
+    {
+        var act = manager.GetOperationHeroAppearInfo();
+        if (act == null) return;
+
+        var config = ActHeroAppearConfig.Get(act.CfgID);
+        if (config == null || config.ActHeroIDList.IsNullOrEmpty()) return;
+
+        // 鑾峰彇姝﹀皢鍒楄〃
+        heroIdList = config.ActHeroIDList;
+        currentHeroIndex = 0;
+
+        // 濡傛灉鍙湁涓�涓灏嗭紝涓嶈疆鎾紝鐩存帴鏄剧ず
+        if (heroIdList.Length <= 1)
+        {
+            StopCarousel();
+            DisplayHero(heroIdList[0], false);
+        }
+        else
+        {
+            // 澶氫釜姝﹀皢锛屽紑鍚疆鎾�
+            carouselTimer = 0f;
+            DisplayHero(heroIdList[currentHeroIndex], false);
+            StartCarousel();
+        }
+
+        callRedImage.SetActive(!manager.IsShopVisitedToday || manager.HasGiftCanHave());
+        OnSecondEvent();
+    }
+
+    private void LateUpdate()
+    {
+        if (!isCarouselActive) return;
+        if (heroIdList == null || heroIdList.Length <= 1) return;
+
+        // 妫�鏌ユ槸鍚﹀瓨鍦ㄦ洿楂樺眰绾х殑绐楀彛锛屽鏋滄湁鍒欎笉鎾斁杞挱
+        if (UIManager.Instance.ExistAnySameLevelWinHigherSortingOrder(uiLayer, uiName))
+        {
+            return;
+        }
+
+        carouselTimer += Time.deltaTime;
+        if (carouselTimer >= CarouselInterval)
+        {
+            carouselTimer = 0f;
+            // 鍒囨崲鍒颁笅涓�涓灏�
+            currentHeroIndex = (currentHeroIndex + 1) % heroIdList.Length;
+            int nextHeroID = heroIdList[currentHeroIndex];
+            // 甯﹀姩鐢诲垏鎹�
+            DisplayHero(nextHeroID, true);
+        }
+    }
+
+    /// <summary>
+    /// 鏄剧ず鎸囧畾姝﹀皢鐨勮儗鏅拰绔嬬粯
+    /// </summary>
+    private void DisplayHero(int heroID, bool withAnimation)
+    {
+        var artConfig = ActHeroReturnArtConfig.Get(heroID);
+        if (artConfig == null) return;
+
+        int skinID = manager.GetDefaultSkinID(heroID);
+        var skinConfig = HeroSkinConfig.Get(skinID);
+        if (skinConfig == null) return;
+
+        var skinArtConfig = ActHeroReturnSkinArtConfig.Get(artConfig.MainSkinID);
+        if (skinArtConfig == null) return;
+
+        if (withAnimation)
+        {
+            carouselTween?.Kill();
+
+            Sequence seq = DOTween.Sequence();
+            seq.Append(bgImage.DOFade(0.7f, FadeDuration));
+
+            CanvasGroup lhCanvasGroup = lhController.GetComponent<CanvasGroup>();
+            if (lhCanvasGroup == null)
+            {
+                lhCanvasGroup = lhController.gameObject.AddComponent<CanvasGroup>();
+            }
+            seq.Join(lhCanvasGroup.DOFade(0f, FadeDuration));
+
+            seq.OnComplete(() =>
+            {
+                UpdateHeroDisplay(heroID, skinID, artConfig, skinArtConfig);
+                // 娣″叆
+                bgImage.DOFade(1f, FadeDuration);
+                lhCanvasGroup.DOFade(1f, FadeDuration);
+            });
+
+            carouselTween = seq;
+        }
+        else
+        {
+            UpdateHeroDisplay(heroID, skinID, artConfig, skinArtConfig);
+            CanvasGroup lhCanvasGroup = lhController.GetComponent<CanvasGroup>();
+            if (lhCanvasGroup != null)
+            {
+                lhCanvasGroup.alpha = 1f;
+            }
+        }
+    }
+
+    /// <summary>
+    /// 鏇存柊姝﹀皢鏄剧ず璧勬簮
+    /// </summary>
+    private void UpdateHeroDisplay(int heroID, int skinID, ActHeroReturnArtConfig artConfig, ActHeroReturnSkinArtConfig skinArtConfig)
+    {
+        int chosenHeroSkinID = manager.GetDefaultSkinID(
+            manager.LoadCallChooseHeroStateKey(manager.GetOperationHeroAppearInfo()) ?
+            manager.GetCurrentDisplayCallHeroId() :
+            manager.GetFirstHeroId());
+        uiHeroController.Create(chosenHeroSkinID, modleSize);
+
+        uiHeroController.transform.localScale = new Vector3(-modleSize, modleSize, modleSize);
+        lhController.Create(skinID, 1, motionName: "", isLh: true);
+
+        // 鏇存柊鑳屾櫙
+        bgImage.SetSprite(artConfig.MainBgImage);
+        bgImage.SetNativeSize();
+
+        // 鏇存柊鏍囬
+        titleImage.SetSprite(artConfig.MainTitleImage);
+        titleImage.SetNativeSize();
+
+        // 鏇存柊鐨偆鍥剧墖
+        int firstHeroID = manager.GetFirstHeroId();
+        var firstHeroIDArtConfig = ActHeroReturnArtConfig.Get(firstHeroID);
+        if (firstHeroIDArtConfig == null) return;
+        var firstSkinArtConfig = ActHeroReturnSkinArtConfig.Get(firstHeroIDArtConfig.MainSkinID);
+        if (firstSkinArtConfig == null) return;
+        skinImage.SetSprite(firstSkinArtConfig.MainSkinBuyBgImage);
+    }
+
+    /// <summary>
+    /// 寮�濮嬭疆鎾�
+    /// </summary>
+    private void StartCarousel()
+    {
+        if (isCarouselActive) return;
+        isCarouselActive = true;
+        carouselTimer = 0f;
+    }
+
+    /// <summary>
+    /// 鍋滄杞挱
+    /// </summary>
+    private void StopCarousel()
+    {
+        isCarouselActive = false;
+        carouselTimer = 0f;
+        carouselTween?.Kill();
+        carouselTween = null;
+    }
+
+    private void OnSecondEvent()
+    {
+        manager.GetActTimeStr(timeText);
+    }
+}
diff --git a/Main/System/HeroReturn/HeroReturnWin.cs.meta b/Main/System/HeroReturn/HeroReturnWin.cs.meta
new file mode 100644
index 0000000..96415d9
--- /dev/null
+++ b/Main/System/HeroReturn/HeroReturnWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 264e7ec58915d6243902eadabc46eee9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Main/HomeWin.cs b/Main/System/Main/HomeWin.cs
index 086ec0c..1356e65 100644
--- a/Main/System/Main/HomeWin.cs
+++ b/Main/System/Main/HomeWin.cs
@@ -73,6 +73,7 @@
     [SerializeField] Button osMinggeBtn;
     [SerializeField] TimeRushCell timeRushCell;
     [SerializeField] HeroDebutCell heroDebutCell;
+    [SerializeField] HeroReturnCell heroReturnCell;
 
     //鍧愰獞
     [SerializeField] Image horseBGImg;
@@ -296,6 +297,7 @@
 
         DisplayTimeRush();
         DisplayHeroDebut();
+        DisplayHeroReturn();
         DelayPlayMusic().Forget();
 
     }
@@ -336,6 +338,10 @@
         {
             DisplayHeroDebut();
         }
+        else if (type == OperationType.HeroReturn)
+        {
+            DisplayHeroReturn();
+        }
 
     }
 
@@ -343,6 +349,7 @@
     {
         DisplayTimeRush();
         DisplayHeroDebut();
+        DisplayHeroReturn();
     }
 
     private void OnShowGiftIdListAddEvent()
@@ -820,8 +827,8 @@
             DisplayHorse();
         }
         else if (funcId == (int)FuncOpenEnum.OSMainLevl || funcId == (int)FuncOpenEnum.OSHeroCall
-        || funcId == (int)FuncOpenEnum.OSGala|| funcId == (int)FuncOpenEnum.OSHeroTrain
-        || funcId == (int)FuncOpenEnum.OSBeautyMM  || funcId == (int)FuncOpenEnum.OSMingge)
+        || funcId == (int)FuncOpenEnum.OSGala || funcId == (int)FuncOpenEnum.OSHeroTrain
+        || funcId == (int)FuncOpenEnum.OSBeautyMM || funcId == (int)FuncOpenEnum.OSMingge)
         {
             DisplayOSActivity();
         }
@@ -840,6 +847,10 @@
         else if (funcId == (int)FuncOpenEnum.HeroDebut)
         {
             DisplayHeroDebut();
+        }
+        else if (funcId == (int)FuncOpenEnum.HeroReturn)
+        {
+            DisplayHeroReturn();
         }
     }
 
@@ -917,6 +928,15 @@
             return;
         heroDebutCell.Display();
     }
+
+    void DisplayHeroReturn()
+    {
+        bool isOpen = HeroReturnManager.Instance.IsHeroReturnOpen();
+        heroReturnCell.SetActive(isOpen);
+        if (!isOpen)
+            return;
+        heroReturnCell.Display();
+    }
 }
 
 
diff --git a/Main/System/OpenServerActivity/OperationTimeHepler.cs b/Main/System/OpenServerActivity/OperationTimeHepler.cs
index b4ef7bc..18a98ec 100644
--- a/Main/System/OpenServerActivity/OperationTimeHepler.cs
+++ b/Main/System/OpenServerActivity/OperationTimeHepler.cs
@@ -469,9 +469,9 @@
             case 10:
                 opreationType = OperationType.HeroDebut;
                 break;
-            // case 11:
-            //     opreationType = OperationType.HeroBack;
-            //     break;
+            case 11:
+                opreationType = OperationType.HeroReturn;
+                break;
         }
 
         if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
@@ -1084,5 +1084,6 @@
 {
     TimeRush = 1,  //鏃ユ湡鍨嬫椿鍔� - 杞洖娈�
     HeroDebut = 2,  //鏃ユ湡鍨嬫椿鍔� - 姝﹀皢鐧诲満
+    HeroReturn = 3, //鏃ユ湡鍨嬫椿鍔� - 姝﹀皢杩斿満
     max,
 }
\ No newline at end of file
diff --git a/Main/System/Redpoint/MainRedDot.cs b/Main/System/Redpoint/MainRedDot.cs
index 645f78e..2365d68 100644
--- a/Main/System/Redpoint/MainRedDot.cs
+++ b/Main/System/Redpoint/MainRedDot.cs
@@ -155,6 +155,7 @@
     public const int RedPoint_OSHeroTrain = 481;
     public const int RedPoint_OSBeautyMM = 482;
     public const int RedPoint_OSMingge = 483;
+    public const int HeroReturnRepoint = 484; //姝﹀皢杩斿満
     public void Register()
     {
 
diff --git a/Main/System/UIBase/UIJumpManager.cs b/Main/System/UIBase/UIJumpManager.cs
index 4b63ee1..88b98a0 100644
--- a/Main/System/UIBase/UIJumpManager.cs
+++ b/Main/System/UIBase/UIJumpManager.cs
@@ -61,10 +61,9 @@
 				}
 			}
 		}
-		else if (config.WinName == "HeroDebutCallWin" ||
-				config.WinName == "HeroDebutSkinWin" ||
-				config.WinName == "HeroDebutCheckInWin" ||
-				config.WinName == "HeroDebutGiftWin" ||
+		//姝﹀皢鐧诲満鐩稿叧
+		else if (config.WinName == "HeroDebutCallWin" || config.WinName == "HeroDebutSkinWin" ||
+				config.WinName == "HeroDebutCheckInWin" || config.WinName == "HeroDebutGiftWin" ||
 				config.WinName == "HeroDebutShopWin")
 		{
 			var heroDebutAct = HeroDebutManager.Instance.GetOperationHeroAppearInfo();
@@ -96,6 +95,40 @@
 				UIManager.Instance.OpenWindow(config.WinName);
 			}
 		}
+		//姝﹀皢杩斿満鐩稿叧
+		else if (config.WinName == "HeroReturnCallWin" || config.WinName == "HeroReturnSkinWin" ||
+				config.WinName == "HeroReturnCheckInWin" || config.WinName == "HeroReturnGiftWin" ||
+				config.WinName == "HeroReturnShopWin")
+		{
+			var heroDebutAct = HeroReturnManager.Instance.GetOperationHeroAppearInfo();
+			if (heroDebutAct == null)
+			{
+				SysNotifyMgr.Instance.ShowTip("ActivityNoOpen");
+				return;
+			}
+			var actHeroAppearConfig = ActHeroAppearConfig.Get(heroDebutAct.CfgID);
+			if (actHeroAppearConfig == null)
+			{
+				SysNotifyMgr.Instance.ShowTip("ActivityNoOpen");
+				return;
+			}
+
+			// 鐨偆鍟嗗簵闇�瑕佸垽鏂墿鍝両D
+			if (config.WinName == "HeroReturnSkinWin")
+			{
+				if (!HeroReturnManager.Instance.HasItemInSkinCTGIDList(heroDebutAct.CfgID, int.Parse(config.Extra)))
+				{
+					SysNotifyMgr.Instance.ShowTip("ActivityNoOpen");
+					return;
+				}
+			}
+
+			if (UIManager.Instance.IsOpened(config.WinName))
+			{
+				UIManager.Instance.CloseWindow(config.WinName);
+				UIManager.Instance.OpenWindow(config.WinName);
+			}
+		}
 
 		if (!UIManager.Instance.IsOpened(config.WinName))
 		{
diff --git a/Main/Utility/EnumHelper.cs b/Main/Utility/EnumHelper.cs
index af301c5..4096fc4 100644
--- a/Main/Utility/EnumHelper.cs
+++ b/Main/Utility/EnumHelper.cs
@@ -858,6 +858,7 @@
     OSMingge = 61, //寮�鏈嶅懡鏍煎煿鍏绘娲诲姩
     Qunying = 62, //缇よ嫳姒�
     HeroDebut = 63,//姝﹀皢鐧诲満
+    HeroReturn = 64,  //姝﹀皢杩斿満
 }
 
 
@@ -1813,6 +1814,7 @@
 {
     TimeRushAct = 200,  //杞洖娈�(姝﹀皢鍐插埡)
     HeroDebutAct = 201,  //鑻遍泟鐧诲満娲诲姩
+    HeroReturnAct = 202,  //鑻遍泟杩斿満娲诲姩
 }
 
 //浠欑帀璐拱鐨勪簩娆$‘璁ゆ绫诲瀷

--
Gitblit v1.8.0