fix: auto repair bugs #83
This commit is contained in:
parent
ce249058f2
commit
67ec658bad
@ -163,5 +163,34 @@ GoRouter goRouter(Ref ref) {
|
||||
},
|
||||
),
|
||||
],
|
||||
observers: [_BusinessRouteObserver(ref)],
|
||||
);
|
||||
}
|
||||
|
||||
/// 监听路由变化,进入业务页时自动保存到 SharedPreferences
|
||||
class _BusinessRouteObserver extends NavigatorObserver {
|
||||
final Ref _ref;
|
||||
_BusinessRouteObserver(this._ref);
|
||||
|
||||
void _saveIfBusiness(Route<dynamic>? route) {
|
||||
final name = route?.settings.name;
|
||||
if (name != null && _validBusinessRoutes.contains(name)) {
|
||||
final productType = _ref.read(currentProductTypeProvider);
|
||||
debugPrint('[Router] 保存业务页: $name, productType=${productType.name}');
|
||||
SharedPreferences.getInstance().then((prefs) {
|
||||
prefs.setString(_lastRouteKey, name);
|
||||
prefs.setString(_lastProductTypeKey, productType.name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
_saveIfBusiness(route);
|
||||
}
|
||||
|
||||
@override
|
||||
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
|
||||
_saveIfBusiness(newRoute);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../../core/network/api_config.dart';
|
||||
import '../../../../core/network/api_client.dart';
|
||||
import '../../../../pages/profile/profile_page.dart';
|
||||
import '../../../../theme/product_theme.dart';
|
||||
import '../../../../widgets/animated_gradient_background.dart';
|
||||
@ -53,25 +50,16 @@ class _BadgeBasicControlPageState extends ConsumerState<BadgeBasicControlPage>
|
||||
|
||||
Future<void> _loadLastImage() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final token = prefs.getString('access_token');
|
||||
final resp = await http.get(
|
||||
Uri.parse('${ApiConfig.fullBaseUrl}/badge/history/'),
|
||||
headers: {if (token != null) 'Authorization': 'Bearer $token'},
|
||||
).timeout(const Duration(seconds: 10));
|
||||
|
||||
if (resp.statusCode == 200) {
|
||||
final body = jsonDecode(resp.body) as Map<String, dynamic>;
|
||||
final data = body['data'] as Map<String, dynamic>? ?? {};
|
||||
final images = (data['images'] as List<dynamic>? ?? [])
|
||||
.cast<Map<String, dynamic>>()
|
||||
.where((img) =>
|
||||
img['generation_status'] == 'completed' &&
|
||||
(img['image_url'] as String?)?.isNotEmpty == true)
|
||||
.toList();
|
||||
if (images.isNotEmpty && mounted) {
|
||||
setState(() => _lastImageUrl = images.first['image_url'] as String);
|
||||
}
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final data = await apiClient.get('/badge/history/');
|
||||
final images = ((data as Map<String, dynamic>)['images'] as List<dynamic>? ?? [])
|
||||
.cast<Map<String, dynamic>>()
|
||||
.where((img) =>
|
||||
img['generation_status'] == 'completed' &&
|
||||
(img['image_url'] as String?)?.isNotEmpty == true)
|
||||
.toList();
|
||||
if (images.isNotEmpty && mounted) {
|
||||
setState(() => _lastImageUrl = images.first['image_url'] as String);
|
||||
}
|
||||
} catch (_) {}
|
||||
if (mounted) setState(() => _loading = false);
|
||||
|
||||
@ -23,12 +23,11 @@ class DeviceController extends _$DeviceController {
|
||||
Future<String?> bindDevice(String sn, {int? spiritId}) async {
|
||||
final repository = ref.read(deviceRepositoryProvider);
|
||||
final result = await repository.bindDevice(sn, spiritId: spiritId);
|
||||
if (!ref.mounted) return '组件已卸载';
|
||||
if (!ref.mounted) return null; // 组件已卸载,绑定请求已发出,视为成功
|
||||
return result.fold(
|
||||
(failure) => failure.message,
|
||||
(bindingId) {
|
||||
if (!ref.mounted) return '组件已卸载';
|
||||
ref.invalidateSelf();
|
||||
if (ref.mounted) ref.invalidateSelf();
|
||||
return null;
|
||||
},
|
||||
);
|
||||
|
||||
@ -289,23 +289,18 @@ class _BluetoothPageState extends ConsumerState<BluetoothPage>
|
||||
debugPrint('[Bluetooth] 设备已就绪: $mac → $displayName');
|
||||
} catch (e) {
|
||||
debugPrint('[Bluetooth] queryByMac 失败($mac): $e');
|
||||
// API 查询失败时,用 BLE 名作为 fallback 也显示出来
|
||||
if (!mounted) return;
|
||||
final bleDevice = _pendingBleDevices[mac];
|
||||
setState(() {
|
||||
if (!_devices.any((d) => d.macAddress == mac)) {
|
||||
_devices.add(MockDevice(
|
||||
sn: '',
|
||||
name: '${_airhubPrefix}设备',
|
||||
macAddress: mac,
|
||||
type: DeviceType.plush,
|
||||
hasAI: true,
|
||||
bleDevice: bleDevice,
|
||||
));
|
||||
}
|
||||
_isSearching = false;
|
||||
});
|
||||
// 查询失败 → 停止扫描,提示用户
|
||||
setState(() => _isSearching = false);
|
||||
try { await FlutterBluePlus.stopScan(); } catch (_) {}
|
||||
_macInfoCache.remove(mac); // 移除占位,允许重新扫描时再查
|
||||
showGlassDialog(
|
||||
context: context,
|
||||
title: '设备查询失败',
|
||||
description: '无法验证设备信息,请检查网络后重试。',
|
||||
confirmText: '确定',
|
||||
onConfirm: () => Navigator.of(context).pop(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,6 +439,16 @@ class _BluetoothPageState extends ConsumerState<BluetoothPage>
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[Bluetooth] bindDevice 异常: $e');
|
||||
if (!mounted) return;
|
||||
setState(() => _isConnecting = false);
|
||||
showGlassDialog(
|
||||
context: context,
|
||||
title: '绑定失败',
|
||||
description: '$e',
|
||||
confirmText: '确定',
|
||||
onConfirm: () => Navigator.of(context).pop(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
setState(() => _isConnecting = false);
|
||||
@ -564,7 +569,13 @@ class _BluetoothPageState extends ConsumerState<BluetoothPage>
|
||||
children: [
|
||||
// 返回按钮 - CSS: border-radius: 12px, bg: rgba(255,255,255,0.6), no border
|
||||
GestureDetector(
|
||||
onTap: () => context.pop(),
|
||||
onTap: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/');
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
@ -902,7 +913,13 @@ class _BluetoothPageState extends ConsumerState<BluetoothPage>
|
||||
children: [
|
||||
// 取消按钮 - HTML: frosted glass with border
|
||||
GestureDetector(
|
||||
onTap: () => context.pop(),
|
||||
onTap: () {
|
||||
if (context.canPop()) {
|
||||
context.pop();
|
||||
} else {
|
||||
context.go('/');
|
||||
}
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(25),
|
||||
child: Container(
|
||||
|
||||
@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import '../core/services/ble_provisioning_service.dart';
|
||||
import '../features/device/data/datasources/device_remote_data_source.dart';
|
||||
import '../features/device/presentation/controllers/device_controller.dart';
|
||||
import '../widgets/animated_gradient_background.dart';
|
||||
import '../widgets/gradient_button.dart';
|
||||
@ -133,6 +134,30 @@ class _WifiConfigPageState extends ConsumerState<WifiConfigPage>
|
||||
if (_isBinding) return;
|
||||
setState(() => _isBinding = true);
|
||||
|
||||
// 绑定前再次检查设备归属(防止 BLE 扫描时检查遗漏)
|
||||
final mac = _deviceInfo['mac'] as String? ?? '';
|
||||
if (mac.isNotEmpty) {
|
||||
try {
|
||||
final dataSource = ref.read(deviceRemoteDataSourceProvider);
|
||||
final macData = await dataSource.queryByMac(mac);
|
||||
final bindStatus = macData['bind_status'] as String? ?? 'unbound';
|
||||
if (bindStatus == 'bound_by_other') {
|
||||
if (!mounted) return;
|
||||
setState(() => _isBinding = false);
|
||||
showGlassDialog(
|
||||
context: context,
|
||||
title: '无法绑定',
|
||||
description: '该设备已被其他用户绑定,无法使用。如需解绑请联系设备所有者。',
|
||||
confirmText: '确定',
|
||||
onConfirm: () => Navigator.of(context).pop(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[WiFi Config] 检查设备归属失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
final sn = _deviceInfo['sn'] as String? ?? '';
|
||||
if (sn.isNotEmpty) {
|
||||
try {
|
||||
@ -152,6 +177,16 @@ class _WifiConfigPageState extends ConsumerState<WifiConfigPage>
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[WiFi Config] bindDevice 异常: $e');
|
||||
if (!mounted) return;
|
||||
setState(() => _isBinding = false);
|
||||
showGlassDialog(
|
||||
context: context,
|
||||
title: '绑定失败',
|
||||
description: '$e',
|
||||
confirmText: '确定',
|
||||
onConfirm: () => Navigator.of(context).pop(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!mounted) return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user