优化路径规划和 退出登录逻辑

This commit is contained in:
mmc
2026-03-24 15:23:52 +08:00
parent 95c7d02415
commit c4d085cb45
3 changed files with 299 additions and 241 deletions

View File

@@ -23,12 +23,11 @@ class UserInfoCard extends StatefulWidget {
class _UserInfoCardState extends State<UserInfoCard> {
late TextEditingController _nicknameController;
final GetIt _getIt = GetIt.I;
MyCubit? _myCubit; // 可空类型
MyCubit? _myCubit;
@override
void initState() {
super.initState();
// 优先从 BlocProvider 获取,获取失败则从 GetIt 兜底
try {
_myCubit = BlocProvider.of<MyCubit>(context);
} catch (e) {
@@ -48,9 +47,35 @@ class _UserInfoCardState extends State<UserInfoCard> {
super.dispose();
}
// 打开修改昵称的底部抽屉
// ✅ 登录失效提示弹窗 + 2秒后跳登录
void _showSessionExpiredDialog() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => WillPopScope(
onWillPop: () async => false,
child: AlertDialog(
title: const Text('提示'),
content: const Text('登录状态失效,请重新登录!'),
actions: [
Center(
child: TextButton(onPressed: () {}, child: const Text('确定')),
),
],
),
),
);
// 2秒后关闭弹窗并跳登录
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
Navigator.pop(context); // 关闭弹窗
context.go(RoutePaths.login);
}
});
}
void _openEditNicknameBottomSheet() {
// 修复1:先校验 _myCubit 是否为 null,避免空断言
final myCubit = _myCubit;
if (myCubit == null) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Cubit 初始化失败,无法修改昵称'), backgroundColor: Colors.red));
@@ -64,13 +89,14 @@ class _UserInfoCardState extends State<UserInfoCard> {
backgroundColor: Colors.transparent,
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.8),
builder: (context) => BlocProvider.value(
// 使用非空的局部变量,无需空断言
value: myCubit,
child: BlocBuilder<MyCubit, MyState>(
builder: (context, myState) {
final cubit = context.read<MyCubit>();
// ==================== ✅ 核心修复 ====================
if (myState.errorMessage == '登录状态失效,请重新登录') {
context.go(RoutePaths.login);
WidgetsBinding.instance.addPostFrameCallback((_) {
_showSessionExpiredDialog(); // 弹窗提示,不直接跳转
});
}
return Padding(
@@ -96,16 +122,12 @@ class _UserInfoCardState extends State<UserInfoCard> {
TextField(
controller: _nicknameController,
style: const TextStyle(fontSize: 16),
decoration: InputDecoration(
border: const OutlineInputBorder(),
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
),
decoration: const InputDecoration(border: OutlineInputBorder(), contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 10)),
autofocus: true,
enabled: !myState.isLoading,
),
const SizedBox(height: 20),
// 核心:根据 MyState 显示加载/按钮/错误提示
if (myState.isLoading)
const Center(
child: Column(
@@ -119,14 +141,11 @@ class _UserInfoCardState extends State<UserInfoCard> {
else
Column(
children: [
// 修复2:使用 ?. 和 ?? 避免空断言,安全判断错误信息
if (myState.errorMessage?.isNotEmpty ?? false)
Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Text(myState.errorMessage ?? "修改失败", style: const TextStyle(color: Colors.red, fontSize: 14)),
),
// 确定修改按钮
SizedBox(
width: double.infinity,
child: ElevatedButton(
@@ -152,7 +171,6 @@ class _UserInfoCardState extends State<UserInfoCard> {
);
}
// 提交新昵称的业务逻辑
Future<void> _submitNewNickname(BuildContext context) async {
final newNickname = _nicknameController.text.trim();
if (newNickname.isEmpty) {
@@ -169,25 +187,19 @@ class _UserInfoCardState extends State<UserInfoCard> {
return;
}
// 移除重复的加载弹窗(由 BlocBuilder 显示加载状态)
await myCubit.updateName(newNickname);
// 成功后由 BlocBuilder 监听状态并处理弹窗关闭和提示
if (context.mounted && myCubit.state.errorMessage!.isEmpty ?? true) {
if (context.mounted && (myCubit.state.errorMessage?.isEmpty ?? true)) {
setState(() {
_nicknameController.text = newNickname;
});
Navigator.pop(context);
// 触发 AuthCubit 重新获取用户信息
}
}
// 扫码绑定设备逻辑(保留)
// 扫码绑定设备逻辑(修复版)
Future<void> _handleScanAndBind(BuildContext context) async {
bool isScanned = false;
// 1. 扫码逻辑 (保持不变)
final String? deviceCode = await Navigator.push<String>(
context,
MaterialPageRoute(
@@ -196,10 +208,7 @@ class _UserInfoCardState extends State<UserInfoCard> {
appBar: AppBar(
title: const Text('扫码绑定设备'),
backgroundColor: Colors.black54,
leading: IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
leading: IconButton(icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context)),
),
body: MobileScanner(
onDetect: (BarcodeCapture capture) {
@@ -226,7 +235,6 @@ class _UserInfoCardState extends State<UserInfoCard> {
return;
}
// 2. 确认对话框 (保持不变)
final bool? confirmBind = await showDialog<bool>(
context: context,
barrierDismissible: false,
@@ -235,19 +243,10 @@ class _UserInfoCardState extends State<UserInfoCard> {
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('设备信息:'),
const SizedBox(height: 8),
Text('设备编码:$deviceCode'),
const Text('设备状态:未绑定'),
const Text('设备类型:智能设备'),
],
children: [const Text('设备信息:'), const SizedBox(height: 8), Text('设备编码:$deviceCode'), const Text('设备状态:未绑定'), const Text('设备类型:智能设备')],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('取消'),
),
TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('取消')),
ElevatedButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('确定绑定'),
@@ -261,13 +260,12 @@ class _UserInfoCardState extends State<UserInfoCard> {
return;
}
// 3. 显示加载框:保存加载弹窗的 BuildContext
BuildContext? loadingContext; // 新增:保存加载弹窗的上下文
BuildContext? loadingContext;
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
loadingContext = context; // 保存这个 context
loadingContext = context;
return const Center(child: CircularProgressIndicator());
},
);
@@ -276,30 +274,22 @@ class _UserInfoCardState extends State<UserInfoCard> {
final devicesCubit = GetIt.I<DevicesCubit>();
await devicesCubit.bindDevice(deviceCode, '');
// ✅ 成功:用 loadingContext 关闭弹窗
if (loadingContext != null && Navigator.canPop(loadingContext!)) {
Navigator.pop(loadingContext!);
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green),
);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('设备绑定成功!'), backgroundColor: Colors.green));
}
} catch (e) {
// ❌ 失败:用 loadingContext 关闭弹窗
if (loadingContext != null && Navigator.canPop(loadingContext!)) {
Navigator.pop(loadingContext!);
}
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('绑定失败:${e.toString()}'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 4),
),
);
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('绑定失败:${e.toString()}'), backgroundColor: Colors.red, duration: const Duration(seconds: 4)));
}
debugPrint('设备绑定失败详情:$e');
}
@@ -314,7 +304,7 @@ class _UserInfoCardState extends State<UserInfoCard> {
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(image: NetworkImage('https://pic4.zhimg.com/v2-c34c61a90095abb8713de9d1dca7ec7b_r.jpg'), fit: BoxFit.cover),
image: const DecorationImage(image: NetworkImage('https://pic4.zhimg.com/v2-c34c61a90095abb8713de9d1dca7ec7b_r.jpg'), fit: BoxFit.cover),
),
),
const SizedBox(width: 12),