feat: 新增第三方登录绑定密码功能,优化OTA超时和WiFi提示

1. 新增用户数据结构,支持第三方绑定时设置密码
2. 新增第三方绑定密码设置UI流程,更新多语言文案
3. 调整BLE默认响应超时为3秒,OTA时临时延长至10秒
4. 添加WiFi配置页面的2.4GHz频段提示
This commit is contained in:
“虞渠成” 2026-08-14 10:07:53 +08:00
parent e11d67df32
commit da357a030b
8 changed files with 291 additions and 67 deletions

View File

@ -1106,8 +1106,8 @@
},
{
"key": "100222",
"zh": "WiFi配置成功",
"en": "Wi-Fi configuration successful"
"zh": "WiFi配置成功,请等待设备上线",
"en": "WiFi configuration succeeded. Please wait for the device to come online."
},
{
"key": "100223",
@ -1593,6 +1593,11 @@
"key": "100319",
"zh": "重置密码成功",
"en": "Reset password successfully"
},
{
"key": "100320",
"zh": "*仅支持 2.4GHz Wi-Fi",
"en": "*Only 2.4GHz Wi-Fi is supported"
}

View File

@ -415,6 +415,99 @@ MonoBehaviour:
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &4694359929881063008
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8113684184675763967}
- component: {fileID: 8340398492869491780}
- component: {fileID: 5788126856848396414}
- component: {fileID: 3030358004855797205}
m_Layer: 5
m_Name: tip
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8113684184675763967
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4694359929881063008}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8895813539220665191}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 30, y: -194.7}
m_SizeDelta: {x: 300, y: 30}
m_Pivot: {x: 0, y: 0.5}
--- !u!222 &8340398492869491780
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4694359929881063008}
m_CullTransparentMesh: 1
--- !u!114 &5788126856848396414
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4694359929881063008}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.5411765, g: 0.54901963, b: 0.54509807, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 24
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 2
m_MaxSize: 40
m_Alignment: 6
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "*\u4EC5\u652F\u6301 2.4GHz Wi\u2011Fi"
--- !u!114 &3030358004855797205
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4694359929881063008}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 89f1d49b50a31514787b4e268b1c73bb, type: 3}
m_Name:
m_EditorClassIdentifier:
textKey: 100320
--- !u!1 &4797642664822797758
GameObject:
m_ObjectHideFlags: 0
@ -452,7 +545,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -201}
m_AnchoredPosition: {x: 0, y: -231}
m_SizeDelta: {x: -60, y: 100}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &5544399545256808103
@ -768,7 +861,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -325}
m_AnchoredPosition: {x: 0, y: -355}
m_SizeDelta: {x: -60, y: 100}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &3367125048176631317
@ -923,6 +1016,7 @@ RectTransform:
- {fileID: 7112136920545491980}
- {fileID: 8726634204092568047}
- {fileID: 7198707897839895149}
- {fileID: 8113684184675763967}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}

View File

@ -1343,7 +1343,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -325}
m_AnchoredPosition: {x: 0, y: -355}
m_SizeDelta: {x: -60, y: 100}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &7944886465916672701
@ -1501,7 +1501,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -201}
m_AnchoredPosition: {x: 0, y: -231}
m_SizeDelta: {x: -60, y: 100}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &721363789362909868
@ -2835,6 +2835,99 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
textKey: 100077
--- !u!1 &3316152303714664431
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4066361047121763592}
- component: {fileID: 7645982901015283803}
- component: {fileID: 8788364806159699153}
- component: {fileID: 5690301613137539711}
m_Layer: 5
m_Name: tip
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4066361047121763592
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3316152303714664431}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4343486803298895729}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 30, y: -195}
m_SizeDelta: {x: 300, y: 30}
m_Pivot: {x: 0, y: 0.5}
--- !u!222 &7645982901015283803
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3316152303714664431}
m_CullTransparentMesh: 1
--- !u!114 &8788364806159699153
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3316152303714664431}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.5411765, g: 0.54901963, b: 0.54509807, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 24
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 2
m_MaxSize: 40
m_Alignment: 6
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "*\u4EC5\u652F\u6301 2.4GHz Wi\u2011Fi"
--- !u!114 &5690301613137539711
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3316152303714664431}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 89f1d49b50a31514787b4e268b1c73bb, type: 3}
m_Name:
m_EditorClassIdentifier:
textKey: 100320
--- !u!1 &3325804653976541888
GameObject:
m_ObjectHideFlags: 0
@ -5498,6 +5591,7 @@ RectTransform:
- {fileID: 3732513664857003842}
- {fileID: 7881411939462652630}
- {fileID: 1518021257232439107}
- {fileID: 4066361047121763592}
m_Father: {fileID: 8470092863222596142}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}

View File

@ -58,8 +58,8 @@ namespace Kill.Bluetooth
public bool IsWaitingResponse { get; private set; }
public byte LastCommand { get; private set; }
// 响应超时设置 (OTA传输需要更长时间增加到10秒)
public float ResponseTimeout = 10f;
// 响应超时设置普通指令3秒OTA传输需要更长时间由OTAManager临时延长到10秒
public float ResponseTimeout = 3f;
// 数据接收缓冲区
private List<byte> _receiveBuffer = new List<byte>();

View File

@ -387,55 +387,67 @@ namespace Kill.Bluetooth
/// </summary>
public IEnumerator PerformFullUpgrade(byte[] firmwareData, uint firmwareVersion, Action<bool> callback = null)
{
// 0. 先取消可能存在的未完成升级
bool cancelSuccess = false;
yield return CancelUpgradeCoroutine((success) => cancelSuccess = success);
if (cancelSuccess)
// OTA 分包传输需要更长的设备响应时间,临时延长超时,结束后恢复默认值
var comm = BLECommunicationManager.Instance;
float originalTimeout = comm != null ? comm.ResponseTimeout : 10f;
if (comm != null) comm.ResponseTimeout = 10f;
try
{
yield return new WaitForSeconds(1f);
// 0. 先取消可能存在的未完成升级
bool cancelSuccess = false;
yield return CancelUpgradeCoroutine((success) => cancelSuccess = success);
if (cancelSuccess)
{
yield return new WaitForSeconds(1f);
}
// 1. 查询版本信息
OTAVersionInfo versionInfo = null;
yield return QueryVersionInfoCoroutine((info) => versionInfo = info);
if (versionInfo == null)
{
callback?.Invoke(false);
yield break;
}
// 2. 开始升级
bool startSuccess = false;
yield return StartUpgradeCoroutine(firmwareData, firmwareVersion, (success) => startSuccess = success);
if (!startSuccess)
{
callback?.Invoke(false);
yield break;
}
// 3. 传输数据
bool transferSuccess = false;
yield return TransferFirmware((success) => transferSuccess = success);
if (!transferSuccess)
{
callback?.Invoke(false);
yield break;
}
// 4. 结束传输
bool endSuccess = false;
yield return EndTransferCoroutine((success) => endSuccess = success);
if (!endSuccess)
{
callback?.Invoke(false);
yield break;
}
callback?.Invoke(true);
}
// 1. 查询版本信息
OTAVersionInfo versionInfo = null;
yield return QueryVersionInfoCoroutine((info) => versionInfo = info);
if (versionInfo == null)
finally
{
callback?.Invoke(false);
yield break;
// 恢复默认响应超时
if (comm != null) comm.ResponseTimeout = originalTimeout;
}
// 2. 开始升级
bool startSuccess = false;
yield return StartUpgradeCoroutine(firmwareData, firmwareVersion, (success) => startSuccess = success);
if (!startSuccess)
{
callback?.Invoke(false);
yield break;
}
// 3. 传输数据
bool transferSuccess = false;
yield return TransferFirmware((success) => transferSuccess = success);
if (!transferSuccess)
{
callback?.Invoke(false);
yield break;
}
// 4. 结束传输
bool endSuccess = false;
yield return EndTransferCoroutine((success) => endSuccess = success);
if (!endSuccess)
{
callback?.Invoke(false);
yield break;
}
callback?.Invoke(true);
}
#endregion

View File

@ -125,6 +125,9 @@ namespace Kill.Managers
{
public string email;
public string temp_token;
// 第三方登录未绑定场景:绑定同时设置密码(可选)
public string password;
public int password_type;
}
/// <summary>

View File

@ -639,18 +639,13 @@ namespace Kill.UI.Pages
onError: (code, message) =>
{
Debug.Log(message);
// 未绑定过第三方帐号 → 使用第三方邮箱直接绑定登录,无需验证码
BindFireBase("",
onSuccess: (data) =>
{
Debug.Log(data.token);
UIManager.Instance.OpenPage(UIManager.PageName.homePage, null, true);
},
onError: (bindCode, bindMessage) =>
{
Debug.LogError($"第三方绑定失败: {bindMessage}");
ToastUI.Show("100042"); // 登录失败提示
});
// 未绑定过第三方帐号 → 进入设置密码流程,绑定同时设置密码(无需验证码)
var setPasswordPanel = GetSubPage(SubPageType.SetPassword) as SetPasswordPanel;
if (setPasswordPanel != null)
{
setPasswordPanel.SetMode(SetPasswordPanel.SetPasswordMode.ThirdPartyBind);
}
ClearHistoryAndShow(SubPageType.SetPassword);
});
}
@ -658,7 +653,7 @@ namespace Kill.UI.Pages
#endregion
#region
public async Task BindFireBase(string code, Action<LoginData> onSuccess, Action<int, string> onError)
public async Task BindFireBase(string code, Action<LoginData> onSuccess, Action<int, string> onError, string password = null, int password_type = 0)
{
LoadingUI.Show();
var requestData = new BindFireBaseRequest
@ -666,6 +661,12 @@ namespace Kill.UI.Pages
temp_token = currentFireBaseId,
email = currentEmail
};
// 第三方登录未绑定场景:绑定同时设置密码
if (!string.IsNullOrEmpty(password))
{
requestData.password = password;
requestData.password_type = password_type;
}
try
{
var response = await NetworkCtrl.Instance.Post<LoginResponse>("/api/v1/auth/firebase/bind", requestData);

View File

@ -48,7 +48,8 @@ namespace Kill.UI.Pages
public enum SetPasswordMode
{
Register, // 注册设置密码
ResetPassword // 忘记密码重置密码
ResetPassword, // 忘记密码重置密码
ThirdPartyBind // 第三方登录绑定设置密码
}
protected override void OnInitialize()
{
@ -258,6 +259,20 @@ namespace Kill.UI.Pages
}
);
}
else if (currentMode == SetPasswordMode.ThirdPartyBind)
{
// 第三方登录绑定模式 - 设置密码并绑定第三方账号,无需验证码
LoginPageCtrl.Instance.BindFireBase("",
onSuccess: (data) =>
{
UIManager.Instance.OpenPage(UIManager.PageName.homePage, null, true);
},
onError: (code, msg) =>
{
ToastUI.ShowText(code.ToString());
},
newPwd, passwordType);
}
else
{
// 重置密码模式 - 调用重置密码接口