更新样式
This commit is contained in:
@@ -414,8 +414,8 @@
|
|||||||
"呼吸数据介绍": "Respiration data refers to basic respiration metrics during sleep, serving as core indicators for evaluating sleep respiration quality and screening sleep breathing disorders.",
|
"呼吸数据介绍": "Respiration data refers to basic respiration metrics during sleep, serving as core indicators for evaluating sleep respiration quality and screening sleep breathing disorders.",
|
||||||
"心率散点图": "Heart rate scatter plot",
|
"心率散点图": "Heart rate scatter plot",
|
||||||
"心率散点图介绍": "The ECG scatter plot is a nonlinear graphical method for recording continuous heart rate RR interval diagrams, also called scatter plots as they consist of scattered points.",
|
"心率散点图介绍": "The ECG scatter plot is a nonlinear graphical method for recording continuous heart rate RR interval diagrams, also called scatter plots as they consist of scattered points.",
|
||||||
"今日数据": "yesterday",
|
"今日数据": "today",
|
||||||
"昨日数据": "today",
|
"昨日数据": "yesterday",
|
||||||
"次": "times",
|
"次": "times",
|
||||||
"秒": "sec",
|
"秒": "sec",
|
||||||
"暂无": "None",
|
"暂无": "None",
|
||||||
|
|||||||
@@ -221,6 +221,39 @@ class CityModelController extends GetControllerEx<CityModel> {
|
|||||||
// 检查是否已加载数据
|
// 检查是否已加载数据
|
||||||
bool get isDataLoaded => cityList.isNotEmpty;
|
bool get isDataLoaded => cityList.isNotEmpty;
|
||||||
|
|
||||||
|
// void searchCities(String keyword) {
|
||||||
|
// model.keyword = keyword;
|
||||||
|
// searchResults?.clear();
|
||||||
|
|
||||||
|
// if (keyword.isEmpty) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// final keywordLower = keyword.toLowerCase();
|
||||||
|
|
||||||
|
// // 遍历所有城市数据
|
||||||
|
// for (var country in cityList) {
|
||||||
|
// final countryName = country.value ?? country.country ?? '';
|
||||||
|
|
||||||
|
// for (var province in country.children ?? []) {
|
||||||
|
// final provinceName = province.value ?? province.province ?? '';
|
||||||
|
|
||||||
|
// for (var city in province.children ?? []) {
|
||||||
|
// final cityName = city.value ?? city.city ?? '';
|
||||||
|
// final displayName = '$countryName-$provinceName-$cityName';
|
||||||
|
|
||||||
|
// // 模糊匹配
|
||||||
|
// if (countryName.toLowerCase().contains(keywordLower) ||
|
||||||
|
// provinceName.toLowerCase().contains(keywordLower) ||
|
||||||
|
// cityName.toLowerCase().contains(keywordLower) ||
|
||||||
|
// displayName.toLowerCase().contains(keywordLower)) {
|
||||||
|
// searchResults?.add(displayName);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
void searchCities(String keyword) {
|
void searchCities(String keyword) {
|
||||||
model.keyword = keyword;
|
model.keyword = keyword;
|
||||||
searchResults?.clear();
|
searchResults?.clear();
|
||||||
@@ -231,23 +264,43 @@ class CityModelController extends GetControllerEx<CityModel> {
|
|||||||
|
|
||||||
final keywordLower = keyword.toLowerCase();
|
final keywordLower = keyword.toLowerCase();
|
||||||
|
|
||||||
// 遍历所有城市数据
|
|
||||||
for (var country in cityList) {
|
for (var country in cityList) {
|
||||||
final countryName = country.value ?? country.country ?? '';
|
final countryName = country.value ?? country.country ?? '';
|
||||||
|
|
||||||
for (var province in country.children ?? []) {
|
// 如果该国家没有 children(一级结构)
|
||||||
|
if (country.children == null || country.children!.isEmpty) {
|
||||||
|
final name = countryName;
|
||||||
|
if (name.toLowerCase().contains(keywordLower)) {
|
||||||
|
searchResults?.add(name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 二层循环:省份或城市
|
||||||
|
for (var province in country.children!) {
|
||||||
final provinceName = province.value ?? province.province ?? '';
|
final provinceName = province.value ?? province.province ?? '';
|
||||||
|
final level2Name = '$countryName-$provinceName';
|
||||||
|
|
||||||
for (var city in province.children ?? []) {
|
// 省本身是否匹配(适用于 国家→省 二级结构)
|
||||||
|
if (province.children == null || province.children!.isEmpty) {
|
||||||
|
if (countryName.toLowerCase().contains(keywordLower) ||
|
||||||
|
provinceName.toLowerCase().contains(keywordLower) ||
|
||||||
|
level2Name.toLowerCase().contains(keywordLower)) {
|
||||||
|
searchResults?.add(level2Name);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有第三级城市 → 遍历城市
|
||||||
|
for (var city in province.children!) {
|
||||||
final cityName = city.value ?? city.city ?? '';
|
final cityName = city.value ?? city.city ?? '';
|
||||||
final displayName = '$countryName-$provinceName-$cityName';
|
final level3Name = '$countryName-$provinceName-$cityName';
|
||||||
|
|
||||||
// 模糊匹配
|
|
||||||
if (countryName.toLowerCase().contains(keywordLower) ||
|
if (countryName.toLowerCase().contains(keywordLower) ||
|
||||||
provinceName.toLowerCase().contains(keywordLower) ||
|
provinceName.toLowerCase().contains(keywordLower) ||
|
||||||
cityName.toLowerCase().contains(keywordLower) ||
|
cityName.toLowerCase().contains(keywordLower) ||
|
||||||
displayName.toLowerCase().contains(keywordLower)) {
|
level3Name.toLowerCase().contains(keywordLower)) {
|
||||||
searchResults?.add(displayName);
|
searchResults?.add(level3Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,27 +308,77 @@ class CityModelController extends GetControllerEx<CityModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 根据显示名称获取对应的 CityModel
|
// 根据显示名称获取对应的 CityModel
|
||||||
|
// CityModel? getCityByDisplayName(String displayName) {
|
||||||
|
// final parts = displayName.split('-');
|
||||||
|
// if (parts.length != 3) return null;
|
||||||
|
|
||||||
|
// final countryName = parts[0];
|
||||||
|
// final provinceName = parts[1];
|
||||||
|
// final cityName = parts[2];
|
||||||
|
|
||||||
|
// for (var country in cityList) {
|
||||||
|
// if ((country.value ?? country.country ?? '') == countryName) {
|
||||||
|
// for (var province in country.children ?? []) {
|
||||||
|
// if ((province.value ?? province.province ?? '') == provinceName) {
|
||||||
|
// for (var city in province.children ?? []) {
|
||||||
|
// if ((city.value ?? city.city ?? '') == cityName) {
|
||||||
|
// return city;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
CityModel? getCityByDisplayName(String displayName) {
|
CityModel? getCityByDisplayName(String displayName) {
|
||||||
final parts = displayName.split('-');
|
final parts = displayName.split('-');
|
||||||
if (parts.length != 3) return null;
|
|
||||||
|
if (parts.isEmpty) return null;
|
||||||
|
|
||||||
final countryName = parts[0];
|
final countryName = parts[0];
|
||||||
final provinceName = parts[1];
|
final provinceName = parts.length >= 2 ? parts[1] : null;
|
||||||
final cityName = parts[2];
|
final cityName = parts.length >= 3 ? parts[2] : null;
|
||||||
|
|
||||||
for (var country in cityList) {
|
for (var country in cityList) {
|
||||||
if ((country.value ?? country.country ?? '') == countryName) {
|
final cName = country.value ?? country.country ?? '';
|
||||||
for (var province in country.children ?? []) {
|
if (cName != countryName) continue;
|
||||||
if ((province.value ?? province.province ?? '') == provinceName) {
|
|
||||||
for (var city in province.children ?? []) {
|
// 一级结构:直接 return 国家
|
||||||
if ((city.value ?? city.city ?? '') == cityName) {
|
if (provinceName == null) {
|
||||||
|
return country;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有 children,就不可能有省或市
|
||||||
|
if (country.children == null || country.children!.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 二级匹配:省或城市
|
||||||
|
for (var province in country.children!) {
|
||||||
|
final pName = province.value ?? province.province ?? '';
|
||||||
|
if (pName != provinceName) continue;
|
||||||
|
|
||||||
|
// 二级结构:国家-省
|
||||||
|
if (cityName == null) {
|
||||||
|
return province;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有城市才继续
|
||||||
|
if (province.children == null || province.children!.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 三级结构:国家-省-市
|
||||||
|
for (var city in province.children!) {
|
||||||
|
final ciName = city.value ?? city.city ?? '';
|
||||||
|
if (ciName == cityName) {
|
||||||
return city;
|
return city;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
|
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
|
||||||
import '../../common/util/MyUtils.dart';
|
import '../../common/util/MyUtils.dart';
|
||||||
|
|
||||||
class ListSearchWidget extends GetView {
|
class ListSearchWidget extends GetView {
|
||||||
@@ -38,7 +39,8 @@ class ListSearchWidget extends GetView {
|
|||||||
children: [
|
children: [
|
||||||
// 搜索框部分
|
// 搜索框部分
|
||||||
Padding(
|
Padding(
|
||||||
padding: padding ?? EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
|
padding:
|
||||||
|
padding ?? EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -46,7 +48,7 @@ class ListSearchWidget extends GetView {
|
|||||||
borderRadius: BorderRadius.circular(16.rpx),
|
borderRadius: BorderRadius.circular(16.rpx),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(35.rpx, 0, 35.rpx, 0),
|
padding: EdgeInsetsDirectional.fromSTEB(35.rpx, 0, 0.rpx, 0),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
@@ -139,7 +141,9 @@ class ListSearchWidget extends GetView {
|
|||||||
},
|
},
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// 点击输入框时显示结果列表(如果开启了显示功能且有搜索结果)
|
// 点击输入框时显示结果列表(如果开启了显示功能且有搜索结果)
|
||||||
if (showResultList && searchResults != null && searchResults!.isNotEmpty) {
|
if (showResultList &&
|
||||||
|
searchResults != null &&
|
||||||
|
searchResults!.isNotEmpty) {
|
||||||
_showResults.value = true;
|
_showResults.value = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -151,8 +155,12 @@ class ListSearchWidget extends GetView {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(26.rpx, 0, 0, 0),
|
padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 0, 0, 0),
|
||||||
child: InkWell(
|
child: ClickableContainer(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
highlightColor:
|
||||||
|
themeController.currentColor.sc4.withOpacity(0.8),
|
||||||
|
padding: EdgeInsets.fromLTRB(0, 0, 35.rpx, 0),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
findCallback?.call();
|
findCallback?.call();
|
||||||
// 点击搜索按钮后显示结果列表(如果开启了显示功能)
|
// 点击搜索按钮后显示结果列表(如果开启了显示功能)
|
||||||
@@ -192,7 +200,9 @@ class ListSearchWidget extends GetView {
|
|||||||
// 搜索结果列表(可选显示)
|
// 搜索结果列表(可选显示)
|
||||||
if (showResultList) ...[
|
if (showResultList) ...[
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (!_showResults.value || searchResults == null || searchResults!.isEmpty) {
|
if (!_showResults.value ||
|
||||||
|
searchResults == null ||
|
||||||
|
searchResults!.isEmpty) {
|
||||||
return SizedBox.shrink();
|
return SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
46
lib/controller/home/Dio.dart
Normal file
46
lib/controller/home/Dio.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:get_storage/get_storage.dart';
|
||||||
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
|
import 'package:vbvs_app/controller/login/login_controller.dart';
|
||||||
|
import 'package:vbvs_app/pages/common/selectDialog.dart';
|
||||||
|
|
||||||
|
class ApiService {
|
||||||
|
static Dio dio = Dio();
|
||||||
|
|
||||||
|
static Dio request = Dio();
|
||||||
|
static Dio requestNoInfo = Dio();
|
||||||
|
static Dio requestNoError = Dio(); //不处理错误的请求,用于设备操作上报
|
||||||
|
|
||||||
|
static Dio reservation = Dio();
|
||||||
|
|
||||||
|
static void init() {
|
||||||
|
|
||||||
|
reservationInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reservationInit() {
|
||||||
|
reservation.options.baseUrl = "https://crm-api.swes.com.cn";
|
||||||
|
reservation.options.connectTimeout = const Duration(seconds: 15);
|
||||||
|
reservation.options.receiveTimeout = const Duration(seconds: 10);
|
||||||
|
reservation.options.sendTimeout = const Duration(seconds: 10);
|
||||||
|
reservation.interceptors.add(InterceptorsWrapper(
|
||||||
|
onRequest: (options, handler) {
|
||||||
|
print("---> ${options.method}, ${options.path}, ${options.data}");
|
||||||
|
options.headers['token'] =
|
||||||
|
"bMAQVR1x48t66u8EDYSftAJGo17r0rIB3z15JgyyoGz1rAEZHs1htHOCorYFJ2RT";
|
||||||
|
return handler.next(options);
|
||||||
|
},
|
||||||
|
onResponse: (response, ResponseInterceptorHandler handler) {
|
||||||
|
print("<--- ${response.statusCode} ${response.data}");
|
||||||
|
return handler.next(response);
|
||||||
|
},
|
||||||
|
onError: (e, handler) {
|
||||||
|
// 错误处理,例如打印错误信息
|
||||||
|
showToast("网络异常或服务连接异常,请稍候再试", color: color_error);
|
||||||
|
print("DioError: $e");
|
||||||
|
return handler.reject(e);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ import 'package:vbvs_app/common/pojo/city.dart';
|
|||||||
import 'package:vbvs_app/common/util/CheckNetwork.dart';
|
import 'package:vbvs_app/common/util/CheckNetwork.dart';
|
||||||
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
import 'package:vbvs_app/common/util/CommonVariables.dart';
|
||||||
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
|
||||||
import 'package:vbvs_app/common/util/Dio.dart';
|
// import 'package:vbvs_app/common/util/Dio.dart';
|
||||||
import 'package:vbvs_app/common/util/FitTool.dart';
|
import 'package:vbvs_app/common/util/FitTool.dart';
|
||||||
import 'package:vbvs_app/common/util/JPushUtil.dart';
|
import 'package:vbvs_app/common/util/JPushUtil.dart';
|
||||||
import 'package:vbvs_app/common/util/MyUtils.dart';
|
import 'package:vbvs_app/common/util/MyUtils.dart';
|
||||||
@@ -32,6 +32,7 @@ import 'package:vbvs_app/controller/device/device_calibration_controller.dart';
|
|||||||
import 'package:vbvs_app/controller/device/device_share_controller.dart';
|
import 'package:vbvs_app/controller/device/device_share_controller.dart';
|
||||||
import 'package:vbvs_app/controller/device/device_share_list_controller.dart';
|
import 'package:vbvs_app/controller/device/device_share_list_controller.dart';
|
||||||
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
import 'package:vbvs_app/controller/device/device_type_controller.dart';
|
||||||
|
import 'package:vbvs_app/controller/home/Dio.dart';
|
||||||
import 'package:vbvs_app/controller/home/home_controller.dart';
|
import 'package:vbvs_app/controller/home/home_controller.dart';
|
||||||
import 'package:vbvs_app/controller/login/login_controller.dart';
|
import 'package:vbvs_app/controller/login/login_controller.dart';
|
||||||
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
|
||||||
@@ -94,6 +95,12 @@ Future<void> main() async {
|
|||||||
final ThemeController themeController = Get.put(ThemeController());
|
final ThemeController themeController = Get.put(ThemeController());
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
||||||
|
statusBarColor: Colors.transparent, // 状态栏透明
|
||||||
|
statusBarIconBrightness: Brightness.light, // Android:白色图标
|
||||||
|
statusBarBrightness: Brightness.dark, // iOS:白色图标
|
||||||
|
));
|
||||||
|
|
||||||
final Locale? deviceLocale = Get.deviceLocale;
|
final Locale? deviceLocale = Get.deviceLocale;
|
||||||
print('系统语言: ${deviceLocale?.languageCode}');
|
print('系统语言: ${deviceLocale?.languageCode}');
|
||||||
|
|
||||||
|
|||||||
@@ -64,12 +64,15 @@ Widget getOnePickers(
|
|||||||
bool looping = false,
|
bool looping = false,
|
||||||
void Function(int)? onChanged,
|
void Function(int)? onChanged,
|
||||||
bool isMonthName = false,
|
bool isMonthName = false,
|
||||||
|
Key? pickerKey,
|
||||||
}) {
|
}) {
|
||||||
ThemeController themeController = Get.find();
|
ThemeController themeController = Get.find();
|
||||||
final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false;
|
final bool isEn = Get.locale?.languageCode.startsWith('en') ?? false;
|
||||||
|
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
|
final dynamicKey = ValueKey('picker_${arr.length}_${selectedIndex.value}');
|
||||||
return CupertinoPicker.builder(
|
return CupertinoPicker.builder(
|
||||||
|
key: pickerKey ?? dynamicKey,
|
||||||
itemExtent: 90.rpx,
|
itemExtent: 90.rpx,
|
||||||
useMagnifier: false,
|
useMagnifier: false,
|
||||||
magnification: 1,
|
magnification: 1,
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
final BodyDeviceController bodyDeviceController = Get.find();
|
final BodyDeviceController bodyDeviceController = Get.find();
|
||||||
HomeController homeController = Get.find();
|
HomeController homeController = Get.find();
|
||||||
final GlobalKey addIconKey = GlobalKey();
|
final GlobalKey addIconKey = GlobalKey();
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _myDeviceScrollController = ScrollController();
|
||||||
|
final ScrollController _cloudDeviceScrollController = ScrollController();
|
||||||
OverlayEntry? _popupEntry;
|
OverlayEntry? _popupEntry;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
|
late PageController _pageController;
|
||||||
|
|
||||||
void _showPopup() {
|
void _showPopup() {
|
||||||
final renderBox =
|
final renderBox =
|
||||||
@@ -42,20 +44,16 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
final size = renderBox.size;
|
final size = renderBox.size;
|
||||||
double popupWidth = 190.rpx;
|
double popupWidth = 190.rpx;
|
||||||
|
|
||||||
// 移除之前的弹窗
|
|
||||||
_popupEntry?.remove();
|
_popupEntry?.remove();
|
||||||
|
|
||||||
// 创建新的OverlayEntry
|
|
||||||
_popupEntry = OverlayEntry(
|
_popupEntry = OverlayEntry(
|
||||||
builder: (context) => Stack(
|
builder: (context) => Stack(
|
||||||
children: [
|
children: [
|
||||||
// 半透明背景,点击后关闭弹窗
|
|
||||||
ModalBarrier(
|
ModalBarrier(
|
||||||
dismissible: true,
|
dismissible: true,
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
onDismiss: _hidePopup,
|
onDismiss: _hidePopup,
|
||||||
),
|
),
|
||||||
// 弹窗内容
|
|
||||||
Positioned(
|
Positioned(
|
||||||
top: position.dy + size.height + 26.rpx,
|
top: position.dy + size.height + 26.rpx,
|
||||||
left: position.dx + size.width - popupWidth - 40.rpx,
|
left: position.dx + size.width - popupWidth - 40.rpx,
|
||||||
@@ -81,36 +79,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 11.rpx),
|
SizedBox(height: 11.rpx),
|
||||||
// ClickableContainer(
|
|
||||||
// padding: EdgeInsets.symmetric(vertical: 10.rpx),
|
|
||||||
// backgroundColor: Colors.transparent,
|
|
||||||
// highlightColor:
|
|
||||||
// themeController.currentColor.sc16.withOpacity(0.1),
|
|
||||||
// borderRadius: 0.rpx,
|
|
||||||
// onTap: () {
|
|
||||||
// print('点击扫一扫');
|
|
||||||
// _hidePopup();
|
|
||||||
// TopSlideNotification.show(
|
|
||||||
// context,
|
|
||||||
// text: "待开发.提示".tr,
|
|
||||||
// textColor: themeController.currentColor.sc2,
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// child: Container(
|
|
||||||
// width: double.infinity,
|
|
||||||
// child: Center(
|
|
||||||
// child: Text(
|
|
||||||
// '扫一扫.标题'.tr,
|
|
||||||
// style: TextStyle(
|
|
||||||
// fontSize: AppConstants().normal_text_fontSize,
|
|
||||||
// color: themeController.currentColor.sc3,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// SizedBox(height: 35.rpx),
|
|
||||||
|
|
||||||
ClickableContainer(
|
ClickableContainer(
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.rpx),
|
padding: EdgeInsets.symmetric(vertical: 10.rpx),
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
@@ -147,7 +115,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 插入新的OverlayEntry
|
|
||||||
Overlay.of(context)!.insert(_popupEntry!);
|
Overlay.of(context)!.insert(_popupEntry!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +128,10 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
bodyDeviceController.keyWord.value = "";
|
bodyDeviceController.keyWord.value = "";
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
// 初始化PageController,根据当前类型设置初始页面
|
||||||
|
_pageController = PageController(
|
||||||
|
initialPage: bodyDeviceController.model.type == 1 ? 0 : 1);
|
||||||
|
|
||||||
// 处理传入的type参数
|
// 处理传入的type参数
|
||||||
if (widget.type != null && widget.type is Map) {
|
if (widget.type != null && widget.type is Map) {
|
||||||
final bindType = widget.type['bind_type'];
|
final bindType = widget.type['bind_type'];
|
||||||
@@ -169,23 +140,22 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
if (bindType != null) {
|
if (bindType != null) {
|
||||||
bodyDeviceController.model.type = bindType;
|
bodyDeviceController.model.type = bindType;
|
||||||
homeController.model.type = bindType;
|
homeController.model.type = bindType;
|
||||||
|
// 更新PageController到正确的位置
|
||||||
|
_pageController = PageController(
|
||||||
|
initialPage: bodyDeviceController.model.type == 1 ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初次请求设备列表
|
|
||||||
_fetchDeviceList().then((_) {
|
_fetchDeviceList().then((_) {
|
||||||
if (mac != null) {
|
if (mac != null) {
|
||||||
// 延迟执行以确保列表已渲染
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollToDeviceWithMac(mac);
|
_scrollToDeviceWithMac(mac);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 没有传入type时的默认逻辑
|
|
||||||
_fetchDeviceList();
|
_fetchDeviceList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 每5秒定时请求一次
|
|
||||||
_timer = Timer.periodic(Duration(seconds: 5), (timer) {
|
_timer = Timer.periodic(Duration(seconds: 5), (timer) {
|
||||||
_fetchDeviceList();
|
_fetchDeviceList();
|
||||||
});
|
});
|
||||||
@@ -209,28 +179,54 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
final deviceList = bodyDeviceController.deviceList.value;
|
final deviceList = bodyDeviceController.deviceList.value;
|
||||||
final index = deviceList.indexWhere((device) => device['mac'] == mac);
|
final index = deviceList.indexWhere((device) => device['mac'] == mac);
|
||||||
|
|
||||||
if (index != -1 && _scrollController.hasClients) {
|
if (index != -1) {
|
||||||
// 动态计算高度:最小为 501.rpx,最大为 26.6% 屏幕高度
|
|
||||||
final screenHeight = MediaQuery.of(Get.context!).size.height;
|
final screenHeight = MediaQuery.of(Get.context!).size.height;
|
||||||
final dynamicItemHeight = (screenHeight * 0.266).rpx;
|
final dynamicItemHeight = (screenHeight * 0.266).rpx;
|
||||||
final itemHeight =
|
final itemHeight =
|
||||||
dynamicItemHeight < 501.rpx ? 501.rpx : dynamicItemHeight;
|
dynamicItemHeight < 501.rpx ? 501.rpx : dynamicItemHeight;
|
||||||
|
|
||||||
final spacing = 25.rpx;
|
final spacing = 25.rpx;
|
||||||
final targetPosition = index * (itemHeight + spacing);
|
final targetPosition = index * (itemHeight + spacing);
|
||||||
|
|
||||||
_scrollController.animateTo(
|
// 根据当前类型选择对应的ScrollController
|
||||||
|
final currentScrollController =
|
||||||
|
bodyDeviceController.model.type == 1
|
||||||
|
? _myDeviceScrollController
|
||||||
|
: _cloudDeviceScrollController;
|
||||||
|
|
||||||
|
if (currentScrollController.hasClients) {
|
||||||
|
currentScrollController.animateTo(
|
||||||
targetPosition,
|
targetPosition,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签切换回调
|
||||||
|
void _onTabChanged(int index) {
|
||||||
|
_pageController.animateToPage(index,
|
||||||
|
duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面切换回调
|
||||||
|
void _onPageChanged(int index) {
|
||||||
|
int newType = index == 0 ? 1 : 2;
|
||||||
|
if (bodyDeviceController.model.type != newType) {
|
||||||
|
bodyDeviceController.model.type = newType;
|
||||||
|
homeController.model.type = newType;
|
||||||
|
bodyDeviceController.updateAll();
|
||||||
|
homeController.updateAll();
|
||||||
|
_fetchDeviceList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_timer?.cancel(); // 页面销毁时取消定时器
|
_timer?.cancel();
|
||||||
_scrollController.dispose();
|
_myDeviceScrollController.dispose();
|
||||||
|
_cloudDeviceScrollController.dispose();
|
||||||
|
_pageController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +234,10 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, bodysize) => GestureDetector(
|
builder: (context, bodysize) => GestureDetector(
|
||||||
// onTap: () => FocusScope.of(context).unfocus(),,
|
onTap: () {
|
||||||
|
_hidePopup();
|
||||||
|
FocusScope.of(context).unfocus();
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
@@ -262,7 +261,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
/// 居中标题
|
|
||||||
Text(
|
Text(
|
||||||
'体征检测设备.标题'.tr,
|
'体征检测设备.标题'.tr,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -288,7 +286,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
highlightColor: themeController.currentColor.sc16,
|
highlightColor: themeController.currentColor.sc16,
|
||||||
padding: EdgeInsets.all(8.rpx),
|
padding: EdgeInsets.all(8.rpx),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// 点击图标时,展示弹窗
|
|
||||||
if (_popupEntry == null) {
|
if (_popupEntry == null) {
|
||||||
_showPopup();
|
_showPopup();
|
||||||
} else {
|
} else {
|
||||||
@@ -310,7 +307,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
),
|
),
|
||||||
body: GestureDetector(
|
body: GestureDetector(
|
||||||
onTap: _hidePopup, // 点击空白处自动关闭弹窗
|
onTap: _hidePopup,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
top: true,
|
top: true,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -335,6 +332,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
// 标签切换部分 - 保持原有样式
|
||||||
Stack(
|
Stack(
|
||||||
alignment: Alignment.bottomLeft,
|
alignment: Alignment.bottomLeft,
|
||||||
children: [
|
children: [
|
||||||
@@ -348,19 +346,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
.currentColor.sc3,
|
.currentColor.sc3,
|
||||||
borderRadius: 8.rpx,
|
borderRadius: 8.rpx,
|
||||||
padding: EdgeInsets.all(0),
|
padding: EdgeInsets.all(0),
|
||||||
onTap: () async {
|
onTap: () => _onTabChanged(0),
|
||||||
bodyDeviceController.model.type =
|
|
||||||
1;
|
|
||||||
homeController.model.type = 1;
|
|
||||||
await bodyDeviceController
|
|
||||||
.getDeviceList();
|
|
||||||
await bodyDeviceController
|
|
||||||
.getDeviceList();
|
|
||||||
await bodyDeviceController
|
|
||||||
.getSleepReport();
|
|
||||||
bodyDeviceController.updateAll();
|
|
||||||
homeController.updateAll();
|
|
||||||
},
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
@@ -400,19 +386,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
.currentColor.sc3,
|
.currentColor.sc3,
|
||||||
borderRadius: 8.rpx,
|
borderRadius: 8.rpx,
|
||||||
padding: EdgeInsets.all(0),
|
padding: EdgeInsets.all(0),
|
||||||
onTap: () async {
|
onTap: () => _onTabChanged(1),
|
||||||
homeController.model.type = 2;
|
|
||||||
bodyDeviceController.model.type =
|
|
||||||
2;
|
|
||||||
await bodyDeviceController
|
|
||||||
.getDeviceList();
|
|
||||||
await bodyDeviceController
|
|
||||||
.getDeviceList();
|
|
||||||
await bodyDeviceController
|
|
||||||
.getSleepReport();
|
|
||||||
bodyDeviceController.updateAll();
|
|
||||||
homeController.updateAll();
|
|
||||||
},
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
@@ -451,7 +425,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
// 横线宽度固定为180.rpx
|
// 保持原有的横线宽度180.rpx
|
||||||
double lineWidth = 180.rpx;
|
double lineWidth = 180.rpx;
|
||||||
return AnimatedPositioned(
|
return AnimatedPositioned(
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
@@ -475,6 +449,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
// 搜索框部分保持不变
|
||||||
Container(
|
Container(
|
||||||
width:
|
width:
|
||||||
MediaQuery.sizeOf(context).width * 0.38,
|
MediaQuery.sizeOf(context).width * 0.38,
|
||||||
@@ -636,21 +611,27 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// 使用PageView替换原来的单一列表
|
||||||
|
Expanded(
|
||||||
|
child: PageView(
|
||||||
|
controller: _pageController,
|
||||||
|
onPageChanged: _onPageChanged,
|
||||||
|
children: [
|
||||||
|
// 我的e护页面
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final isEmpty =
|
final myDeviceList = bodyDeviceController.deviceList.value
|
||||||
bodyDeviceController.deviceList.value.isEmpty;
|
.where((device) => device['type'] == 1 || device['bind_type'] == 1)
|
||||||
return Expanded(
|
.toList();
|
||||||
child: isEmpty
|
return myDeviceList.isEmpty
|
||||||
? NullDataWidget()
|
? NullDataWidget()
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
30.rpx, 26.rpx, 30.rpx, 0),
|
30.rpx, 26.rpx, 30.rpx, 0),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: _scrollController,
|
controller: _myDeviceScrollController,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: bodyDeviceController
|
children: myDeviceList
|
||||||
.deviceList.value
|
|
||||||
.map((device) =>
|
.map((device) =>
|
||||||
DeviceDataComponentWidget(
|
DeviceDataComponentWidget(
|
||||||
device: device))
|
device: device))
|
||||||
@@ -658,12 +639,38 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
|
|||||||
.divide(SizedBox(height: 25.rpx)),
|
.divide(SizedBox(height: 25.rpx)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
// 云关爱页面
|
||||||
|
Obx(() {
|
||||||
|
final cloudDeviceList = bodyDeviceController.deviceList.value
|
||||||
|
.where((device) => device['type'] == 2 || device['bind_type'] == 2)
|
||||||
|
.toList();
|
||||||
|
return cloudDeviceList.isEmpty
|
||||||
|
? NullDataWidget()
|
||||||
|
: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
30.rpx, 26.rpx, 30.rpx, 0),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: _cloudDeviceScrollController,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: cloudDeviceList
|
||||||
|
.map((device) =>
|
||||||
|
DeviceDataComponentWidget(
|
||||||
|
device: device))
|
||||||
|
.toList()
|
||||||
|
.divide(SizedBox(height: 25.rpx)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class _CalibrationPageState extends State<CalibrationPage> {
|
|||||||
Timer? _pollingTimer;
|
Timer? _pollingTimer;
|
||||||
|
|
||||||
bool exit = false;
|
bool exit = false;
|
||||||
bool start = false;//是否开始进行校准
|
bool start = false; //是否开始进行校准
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -691,6 +691,10 @@ class _CalibrationPageState extends State<CalibrationPage> {
|
|||||||
progressApi, isSecondStep);
|
progressApi, isSecondStep);
|
||||||
},
|
},
|
||||||
onFailure: (res) {
|
onFailure: (res) {
|
||||||
|
deviceCalibrationController
|
||||||
|
.process.value = 0;
|
||||||
|
deviceCalibrationController
|
||||||
|
.bed_calibration.value = 0;
|
||||||
deviceCalibrationController.flag.value =
|
deviceCalibrationController.flag.value =
|
||||||
0;
|
0;
|
||||||
blueteethBindController.cid!.value = "";
|
blueteethBindController.cid!.value = "";
|
||||||
@@ -757,6 +761,10 @@ class _CalibrationPageState extends State<CalibrationPage> {
|
|||||||
progressApi, isSecondStep);
|
progressApi, isSecondStep);
|
||||||
},
|
},
|
||||||
onFailure: (res) {
|
onFailure: (res) {
|
||||||
|
deviceCalibrationController
|
||||||
|
.process.value = 0;
|
||||||
|
deviceCalibrationController
|
||||||
|
.bed_calibration.value = 0;
|
||||||
deviceCalibrationController.flag.value =
|
deviceCalibrationController.flag.value =
|
||||||
0;
|
0;
|
||||||
blueteethBindController.cid!.value = "";
|
blueteethBindController.cid!.value = "";
|
||||||
@@ -935,7 +943,7 @@ class _CalibrationPageState extends State<CalibrationPage> {
|
|||||||
} else {
|
} else {
|
||||||
deviceCalibrationController.statusContext.value = "";
|
deviceCalibrationController.statusContext.value = "";
|
||||||
//当前步骤执行失败
|
//当前步骤执行失败
|
||||||
deviceCalibrationController.bed_calibration.value == 0;
|
deviceCalibrationController.bed_calibration.value = 0;
|
||||||
_pollingTimer?.cancel();
|
_pollingTimer?.cancel();
|
||||||
blueteethBindController.cid?.value = "";
|
blueteethBindController.cid?.value = "";
|
||||||
deviceCalibrationController.process.value = 0;
|
deviceCalibrationController.process.value = 0;
|
||||||
@@ -985,6 +993,8 @@ class _CalibrationPageState extends State<CalibrationPage> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFailure: (res) {
|
onFailure: (res) {
|
||||||
|
deviceCalibrationController.process.value = 0;
|
||||||
|
deviceCalibrationController.bed_calibration.value = 0;
|
||||||
deviceCalibrationController.flag.value = 0;
|
deviceCalibrationController.flag.value = 0;
|
||||||
_pollingTimer?.cancel();
|
_pollingTimer?.cancel();
|
||||||
blueteethBindController.cid!.value = "";
|
blueteethBindController.cid!.value = "";
|
||||||
|
|||||||
@@ -685,6 +685,10 @@ class _CalibrationPersonPageState extends State<CalibrationPersonPage> {
|
|||||||
progressApi, isSecondStep);
|
progressApi, isSecondStep);
|
||||||
},
|
},
|
||||||
onFailure: (res) {
|
onFailure: (res) {
|
||||||
|
deviceCalibrationController
|
||||||
|
.process.value = 0;
|
||||||
|
deviceCalibrationController
|
||||||
|
.bed_calibration.value = 0;
|
||||||
deviceCalibrationController.flag.value =
|
deviceCalibrationController.flag.value =
|
||||||
0;
|
0;
|
||||||
blueteethBindController.cid!.value = "";
|
blueteethBindController.cid!.value = "";
|
||||||
@@ -751,6 +755,10 @@ class _CalibrationPersonPageState extends State<CalibrationPersonPage> {
|
|||||||
progressApi, isSecondStep);
|
progressApi, isSecondStep);
|
||||||
},
|
},
|
||||||
onFailure: (res) {
|
onFailure: (res) {
|
||||||
|
deviceCalibrationController
|
||||||
|
.process.value = 0;
|
||||||
|
deviceCalibrationController
|
||||||
|
.bed_calibration.value = 0;
|
||||||
deviceCalibrationController.flag.value =
|
deviceCalibrationController.flag.value =
|
||||||
0;
|
0;
|
||||||
blueteethBindController.cid!.value = "";
|
blueteethBindController.cid!.value = "";
|
||||||
@@ -934,7 +942,7 @@ class _CalibrationPersonPageState extends State<CalibrationPersonPage> {
|
|||||||
} else {
|
} else {
|
||||||
deviceCalibrationController.statusContext.value = "";
|
deviceCalibrationController.statusContext.value = "";
|
||||||
//当前步骤执行失败
|
//当前步骤执行失败
|
||||||
deviceCalibrationController.bed_calibration.value == 0;
|
deviceCalibrationController.bed_calibration.value = 0;
|
||||||
_pollingTimer?.cancel();
|
_pollingTimer?.cancel();
|
||||||
blueteethBindController.cid?.value = "";
|
blueteethBindController.cid?.value = "";
|
||||||
deviceCalibrationController.process.value = 0;
|
deviceCalibrationController.process.value = 0;
|
||||||
@@ -984,6 +992,8 @@ class _CalibrationPersonPageState extends State<CalibrationPersonPage> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFailure: (res) {
|
onFailure: (res) {
|
||||||
|
deviceCalibrationController.process.value = 0;
|
||||||
|
deviceCalibrationController.bed_calibration.value = 0;
|
||||||
deviceCalibrationController.flag.value = 0;
|
deviceCalibrationController.flag.value = 0;
|
||||||
_pollingTimer?.cancel();
|
_pollingTimer?.cancel();
|
||||||
blueteethBindController.cid!.value = "";
|
blueteethBindController.cid!.value = "";
|
||||||
|
|||||||
@@ -275,6 +275,43 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
|
|||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceBetween,
|
MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
26.rpx, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
InkWell(
|
||||||
|
onTap: () async {},
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
// constraints: BoxConstraints(
|
||||||
|
// minWidth: 150.rpx,
|
||||||
|
// ),
|
||||||
|
child: Text(
|
||||||
|
"+86",
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Readex Pro',
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc4,
|
||||||
|
fontSize: AppConstants()
|
||||||
|
.middler_text_fontSize,
|
||||||
|
letterSpacing: 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 30.rpx,
|
||||||
|
child: VerticalDivider(
|
||||||
|
thickness: 2.rpx,
|
||||||
|
color: themeController
|
||||||
|
.currentColor.sc4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(SizedBox(width: 10.rpx)),
|
||||||
|
),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
child: Align(
|
child: Align(
|
||||||
|
|||||||
@@ -690,7 +690,7 @@ class _MinePageState extends State<MinePage> {
|
|||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'V1.0.2511.18',
|
'V1.0.2511.21',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: 'Inter',
|
fontFamily: 'Inter',
|
||||||
// color: Color(0xFFD9E3EB),
|
// color: Color(0xFFD9E3EB),
|
||||||
|
|||||||
@@ -281,476 +281,6 @@ Future showCitySelectionDialog(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载中弹窗
|
|
||||||
Widget _buildLoadingDialog(ThemeController themeController) {
|
|
||||||
return Stack(
|
|
||||||
children: [
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Dialog(
|
|
||||||
backgroundColor: themeController.currentColor.sc17,
|
|
||||||
insetPadding: EdgeInsets.zero,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: EdgeInsets.fromLTRB(30.rpx, 40.rpx, 30.rpx, 90.rpx),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
CircularProgressIndicator(
|
|
||||||
color: themeController.currentColor.sc2,
|
|
||||||
),
|
|
||||||
SizedBox(height: 20.rpx),
|
|
||||||
Text(
|
|
||||||
"加载中...".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
fontSize: 28.rpx,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 错误弹窗
|
|
||||||
Widget _buildErrorDialog(
|
|
||||||
ThemeController themeController, BuildContext context) {
|
|
||||||
return Stack(
|
|
||||||
children: [
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Dialog(
|
|
||||||
backgroundColor: themeController.currentColor.sc17,
|
|
||||||
insetPadding: EdgeInsets.zero,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: EdgeInsets.fromLTRB(30.rpx, 40.rpx, 30.rpx, 90.rpx),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"数据加载失败".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
fontSize: 28.rpx,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 20.rpx),
|
|
||||||
ClickableContainer(
|
|
||||||
onTap: () => Navigator.of(context).pop(),
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
highlightColor: Colors.transparent,
|
|
||||||
padding: EdgeInsets.all(0),
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(
|
|
||||||
horizontal: 30.rpx, vertical: 15.rpx),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: themeController.currentColor.sc2,
|
|
||||||
borderRadius: BorderRadius.circular(8.rpx),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
"关闭".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 28.rpx,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 城市选择器弹窗
|
|
||||||
Widget _buildCityPickerDialog(
|
|
||||||
BuildContext context,
|
|
||||||
ThemeController themeController,
|
|
||||||
bool isChinese,
|
|
||||||
String title,
|
|
||||||
List<CityModel> cityData,
|
|
||||||
Function? onCityChanged, {
|
|
||||||
required RxList<String> countries,
|
|
||||||
required RxList<String> provinces,
|
|
||||||
required RxList<String> cities,
|
|
||||||
required RxInt countryIndex,
|
|
||||||
required RxInt provinceIndex,
|
|
||||||
required RxInt cityIndex,
|
|
||||||
}) {
|
|
||||||
// 内部更新方法
|
|
||||||
void updateCities() {
|
|
||||||
try {
|
|
||||||
if (provinces.isEmpty || countries.isEmpty) return;
|
|
||||||
|
|
||||||
final selectedCountry = countries[countryIndex.value];
|
|
||||||
final selectedProvince = provinces[provinceIndex.value];
|
|
||||||
|
|
||||||
for (var country in cityData) {
|
|
||||||
if (country.value == selectedCountry) {
|
|
||||||
for (var province in country.children ?? []) {
|
|
||||||
if (province.value == selectedProvince) {
|
|
||||||
// 安全地处理城市列表
|
|
||||||
final cityList = (province.children ?? [])
|
|
||||||
.map((city) => city?.value ?? city?.city ?? '')
|
|
||||||
.where((cityName) =>
|
|
||||||
(cityName as String).isNotEmpty) // 明确转换为 String
|
|
||||||
.toList()
|
|
||||||
.cast<String>();
|
|
||||||
|
|
||||||
cities.value = cityList;
|
|
||||||
cityIndex.value = cities.isNotEmpty ? 0 : 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cities.value = [];
|
|
||||||
cityIndex.value = 0;
|
|
||||||
} catch (e) {
|
|
||||||
ef.log("更新城市列表失败:$e");
|
|
||||||
cities.value = [];
|
|
||||||
cityIndex.value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateProvinces() {
|
|
||||||
try {
|
|
||||||
if (countries.isEmpty) return;
|
|
||||||
|
|
||||||
final selectedCountry = countries[countryIndex.value];
|
|
||||||
|
|
||||||
for (var country in cityData) {
|
|
||||||
if (country.value == selectedCountry) {
|
|
||||||
// 安全地处理省份列表
|
|
||||||
final provinceList = (country.children ?? [])
|
|
||||||
.map((province) => province?.value ?? province?.province ?? '')
|
|
||||||
.where((provinceName) => provinceName.isNotEmpty)
|
|
||||||
.toList()
|
|
||||||
.cast<String>();
|
|
||||||
|
|
||||||
provinces.value = provinceList;
|
|
||||||
provinceIndex.value = provinces.isNotEmpty ? 0 : 0;
|
|
||||||
|
|
||||||
// 更新城市
|
|
||||||
updateCities();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
provinces.value = [];
|
|
||||||
provinceIndex.value = 0;
|
|
||||||
cities.value = [];
|
|
||||||
cityIndex.value = 0;
|
|
||||||
} catch (e) {
|
|
||||||
ef.log("更新省份列表失败:$e");
|
|
||||||
provinces.value = [];
|
|
||||||
provinceIndex.value = 0;
|
|
||||||
cities.value = [];
|
|
||||||
cityIndex.value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CityModel? getSelectedCityData() {
|
|
||||||
try {
|
|
||||||
if (countries.isEmpty) return null;
|
|
||||||
|
|
||||||
final selectedCountry = countries[countryIndex.value];
|
|
||||||
|
|
||||||
// 查找匹配的国家
|
|
||||||
for (var country in cityData) {
|
|
||||||
final countryName = country.value ?? country.country;
|
|
||||||
if (countryName == selectedCountry) {
|
|
||||||
// 情况1: 只有国家一级(没有省份和城市)
|
|
||||||
if ((country.children == null || country.children!.isEmpty) &&
|
|
||||||
(country.city != null || country.value != null)) {
|
|
||||||
return country; // 直接返回国家数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// 情况2: 有省份但没有城市数据
|
|
||||||
if (provinces.isNotEmpty && provinceIndex.value < provinces.length) {
|
|
||||||
final selectedProvince = provinces[provinceIndex.value];
|
|
||||||
|
|
||||||
for (var province in country.children ?? []) {
|
|
||||||
final provinceName = province.value ?? province.province;
|
|
||||||
if (provinceName == selectedProvince) {
|
|
||||||
// 情况2.1: 省份有城市数据
|
|
||||||
if (cities.isNotEmpty && cityIndex.value < cities.length) {
|
|
||||||
final selectedCityName = cities[cityIndex.value];
|
|
||||||
|
|
||||||
for (var city in province.children ?? []) {
|
|
||||||
final cityName = city.value ?? city.city;
|
|
||||||
if (cityName == selectedCityName) {
|
|
||||||
return city; // 返回城市数据
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 情况2.2: 省份没有城市数据,但省份本身有信息
|
|
||||||
if ((province.children == null || province.children!.isEmpty) &&
|
|
||||||
(province.city != null || province.value != null)) {
|
|
||||||
return province; // 返回省份数据
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 情况3: 有省份但没有选择具体省份,返回国家数据
|
|
||||||
return country;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
} catch (e) {
|
|
||||||
ef.log("获取选中城市数据失败:$e");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
resizeToAvoidBottomInset: false, // 在这里也设置
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Positioned(
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Dialog(
|
|
||||||
backgroundColor: themeController.currentColor.sc17,
|
|
||||||
insetPadding: EdgeInsets.zero,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(0),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: EdgeInsets.fromLTRB(30.rpx, 10.rpx, 30.rpx, 0.rpx),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
ClickableContainer(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
highlightColor: Colors.transparent,
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
onTap: () => Navigator.of(context).pop(),
|
|
||||||
child: Container(
|
|
||||||
width: 110.rpx,
|
|
||||||
height: 60.rpx,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Text("取消".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 30.rpx, color: Colors.white)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontFamily: 'Readex Pro',
|
|
||||||
color: themeController.currentColor.sc3,
|
|
||||||
fontSize: 30.rpx,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Obx(() {
|
|
||||||
CityModelController cityModelController = Get.find();
|
|
||||||
cityModelController.tmp;
|
|
||||||
ef.log("${cityModelController.tmp.value}");
|
|
||||||
return ClickableContainer(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
highlightColor: Colors.transparent,
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
// onTap: () {
|
|
||||||
// final selectedCityData = getSelectedCityData();
|
|
||||||
// if (selectedCityData != null) {
|
|
||||||
// onCityChanged?.call(selectedCityData);
|
|
||||||
// }
|
|
||||||
// Navigator.of(context).pop();
|
|
||||||
// },
|
|
||||||
onTap: () {
|
|
||||||
final selectedCityData = getSelectedCityData();
|
|
||||||
if (selectedCityData != null) {
|
|
||||||
// 根据ID查找完整的层级数据并补全
|
|
||||||
final fullCityData = findCompleteCityDataById(
|
|
||||||
selectedCityData.id, cityData);
|
|
||||||
if (fullCityData != null) {
|
|
||||||
// 使用完整的数据
|
|
||||||
onCityChanged?.call(fullCityData);
|
|
||||||
} else {
|
|
||||||
// 如果没有找到完整数据,使用当前选中的数据
|
|
||||||
onCityChanged?.call(selectedCityData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
width: 110.rpx,
|
|
||||||
height: 60.rpx,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Text("确定".tr,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 30.rpx,
|
|
||||||
color: themeController.currentColor.sc2,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
|
|
||||||
child: ListSearchWidget(
|
|
||||||
keyword: cityModelController.model.keyword,
|
|
||||||
color: cityModelController.model.color,
|
|
||||||
hint: "输入国家、省份或城市".tr,
|
|
||||||
onChange: (d) {
|
|
||||||
cityModelController.model.keyword = d;
|
|
||||||
// 实时搜索
|
|
||||||
cityModelController.searchCities(d);
|
|
||||||
},
|
|
||||||
findCallback: () {
|
|
||||||
// 点击搜索按钮时搜索
|
|
||||||
cityModelController.searchCities(
|
|
||||||
cityModelController.model.keyword ?? "");
|
|
||||||
},
|
|
||||||
padding: EdgeInsets.fromLTRB(
|
|
||||||
0.rpx,
|
|
||||||
30.rpx,
|
|
||||||
0.rpx,
|
|
||||||
10.rpx,
|
|
||||||
),
|
|
||||||
showResultList: true, // 开启结果列表
|
|
||||||
searchResults:
|
|
||||||
cityModelController.searchResults, // 搜索结果
|
|
||||||
onResultTap: (result) {
|
|
||||||
// 处理选择结果
|
|
||||||
final selectedCity =
|
|
||||||
cityModelController.getCityByDisplayName(result);
|
|
||||||
|
|
||||||
if (selectedCity != null) {
|
|
||||||
final fullCityData = findCompleteCityDataById(
|
|
||||||
selectedCity.id, cityData);
|
|
||||||
// 更新选中的城市
|
|
||||||
PersonController personController = Get.find();
|
|
||||||
personController.cityModel = fullCityData;
|
|
||||||
personController.updateAll();
|
|
||||||
ef.log("选择了城市: ${selectedCity.displayName}");
|
|
||||||
|
|
||||||
// 关闭弹窗(如果是在弹窗中使用)
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 20.rpx),
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
Positioned.fill(
|
|
||||||
child: IgnorePointer(
|
|
||||||
child: Center(
|
|
||||||
child: Container(
|
|
||||||
height: 90.rpx,
|
|
||||||
margin: EdgeInsets.symmetric(horizontal: 0.rpx),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: themeController.currentColor.sc2,
|
|
||||||
borderRadius: BorderRadius.circular(16.rpx),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(20.rpx, 0, 20.rpx, 0),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Obx(() {
|
|
||||||
CityModelController cityModelController =
|
|
||||||
Get.find();
|
|
||||||
cityModelController.tmp;
|
|
||||||
ef.log("${cityModelController.tmp.value}");
|
|
||||||
return getOnePickers(
|
|
||||||
context,
|
|
||||||
countries,
|
|
||||||
countryIndex,
|
|
||||||
unit: "",
|
|
||||||
onChanged: (_) => updateProvinces(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Obx(() {
|
|
||||||
CityModelController cityModelController =
|
|
||||||
Get.find();
|
|
||||||
cityModelController.tmp;
|
|
||||||
ef.log("${cityModelController.tmp.value}");
|
|
||||||
return getOnePickers(
|
|
||||||
context,
|
|
||||||
provinces,
|
|
||||||
provinceIndex,
|
|
||||||
unit: "",
|
|
||||||
onChanged: (_) => updateCities(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Obx(() {
|
|
||||||
CityModelController cityModelController =
|
|
||||||
Get.find();
|
|
||||||
cityModelController.tmp;
|
|
||||||
ef.log("${cityModelController.tmp.value}");
|
|
||||||
return getOnePickers(
|
|
||||||
context,
|
|
||||||
cities,
|
|
||||||
cityIndex,
|
|
||||||
unit: "",
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据ID查找完整的城市数据(包含国家、省份、城市信息)
|
// 根据ID查找完整的城市数据(包含国家、省份、城市信息)
|
||||||
CityModel? findCompleteCityDataById(int? id, List<CityModel> cityData) {
|
CityModel? findCompleteCityDataById(int? id, List<CityModel> cityData) {
|
||||||
if (id == null) return null;
|
if (id == null) return null;
|
||||||
@@ -1095,6 +625,8 @@ Widget _buildCityPickerContent(
|
|||||||
countryIndex,
|
countryIndex,
|
||||||
unit: "",
|
unit: "",
|
||||||
onChanged: (_) => updateProvinces(),
|
onChanged: (_) => updateProvinces(),
|
||||||
|
pickerKey: ValueKey(
|
||||||
|
'country_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -1110,6 +642,8 @@ Widget _buildCityPickerContent(
|
|||||||
provinceIndex,
|
provinceIndex,
|
||||||
unit: "",
|
unit: "",
|
||||||
onChanged: (_) => updateCities(),
|
onChanged: (_) => updateCities(),
|
||||||
|
pickerKey: ValueKey(
|
||||||
|
'province_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -1124,6 +658,8 @@ Widget _buildCityPickerContent(
|
|||||||
cities,
|
cities,
|
||||||
cityIndex,
|
cityIndex,
|
||||||
unit: "",
|
unit: "",
|
||||||
|
pickerKey: ValueKey(
|
||||||
|
'city_${DateTime.now().millisecondsSinceEpoch}'), // 添加动态 key
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ class _LineChartByRangePainter extends CustomPainter {
|
|||||||
for (var item in data) {
|
for (var item in data) {
|
||||||
int start = item['startTime'];
|
int start = item['startTime'];
|
||||||
int end = item['endTime'];
|
int end = item['endTime'];
|
||||||
|
// int times = item['times'];
|
||||||
int times = item['times'];
|
int times = item['times'];
|
||||||
|
|
||||||
double startX = xStart * 2 +
|
double startX = xStart * 2 +
|
||||||
|
|||||||
@@ -29,13 +29,71 @@ class SleepRadarChart extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Widget _buildRadarChart() {
|
||||||
|
// return AspectRatio(
|
||||||
|
// aspectRatio: 1.3,
|
||||||
|
// child: RadarChart(
|
||||||
|
// RadarChartData(
|
||||||
|
// dataSets: [
|
||||||
|
// // 今日数据
|
||||||
|
// RadarDataSet(
|
||||||
|
// dataEntries: data
|
||||||
|
// .map((e) => RadarEntry(value: (e['t'] as num).toDouble()))
|
||||||
|
// .toList(),
|
||||||
|
// borderColor: stringToColor("#00C1AA"),
|
||||||
|
// borderWidth: 2,
|
||||||
|
// fillColor: Colors.transparent,
|
||||||
|
// entryRadius: 0,
|
||||||
|
// ),
|
||||||
|
// // 昨日数据
|
||||||
|
// RadarDataSet(
|
||||||
|
// dataEntries: data
|
||||||
|
// .map((e) => RadarEntry(value: (e['y'] as num).toDouble()))
|
||||||
|
// .toList(),
|
||||||
|
// borderColor: stringToColor("#FFD251"),
|
||||||
|
// borderWidth: 2,
|
||||||
|
// fillColor: Colors.transparent,
|
||||||
|
// entryRadius: 0,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// radarBackgroundColor: stringToColor("#343844").withOpacity(0.6),
|
||||||
|
// radarBorderData: BorderSide(
|
||||||
|
// color: themeController.currentColor.sc4, width: 0.5.rpx),
|
||||||
|
// radarShape: RadarShape.polygon,
|
||||||
|
// titlePositionPercentageOffset: 0.2,
|
||||||
|
// titleTextStyle: TextStyle(
|
||||||
|
// fontSize: AppConstants().normal_text_fontSize,
|
||||||
|
// color: themeController.currentColor.sc3),
|
||||||
|
// getTitle: (index, angle) {
|
||||||
|
// return RadarChartTitle(text: data[index]['name'] ?? '未知'.tr);
|
||||||
|
// },
|
||||||
|
// tickCount: 5,
|
||||||
|
// ticksTextStyle:
|
||||||
|
// const TextStyle(color: Colors.transparent, fontSize: 10),
|
||||||
|
// gridBorderData: BorderSide(color: Colors.transparent, width: 1),
|
||||||
|
// tickBorderData: BorderSide(
|
||||||
|
// color: themeController.currentColor.sc4, width: 0.5.rpx),
|
||||||
|
// ),
|
||||||
|
// swapAnimationDuration: const Duration(milliseconds: 400),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
Widget _buildRadarChart() {
|
Widget _buildRadarChart() {
|
||||||
return AspectRatio(
|
// 判断 t 是否全为 0(今日)
|
||||||
aspectRatio: 1.3,
|
final bool isTodayAllZero =
|
||||||
child: RadarChart(
|
data.every((e) => (e['t'] as num).toDouble() == 0);
|
||||||
RadarChartData(
|
|
||||||
dataSets: [
|
// 判断 y 是否全为 0(昨日)
|
||||||
// 今日数据
|
final bool isYesterdayAllZero =
|
||||||
|
data.every((e) => (e['y'] as num).toDouble() == 0);
|
||||||
|
|
||||||
|
// 构建 dataSets
|
||||||
|
final List<RadarDataSet> dataSets = [];
|
||||||
|
|
||||||
|
// 今日数据(非全 0 才加入)
|
||||||
|
if (!isTodayAllZero) {
|
||||||
|
dataSets.add(
|
||||||
RadarDataSet(
|
RadarDataSet(
|
||||||
dataEntries: data
|
dataEntries: data
|
||||||
.map((e) => RadarEntry(value: (e['t'] as num).toDouble()))
|
.map((e) => RadarEntry(value: (e['t'] as num).toDouble()))
|
||||||
@@ -45,7 +103,12 @@ class SleepRadarChart extends StatelessWidget {
|
|||||||
fillColor: Colors.transparent,
|
fillColor: Colors.transparent,
|
||||||
entryRadius: 0,
|
entryRadius: 0,
|
||||||
),
|
),
|
||||||
// 昨日数据
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 昨日数据(非全 0 才加入)
|
||||||
|
if (!isYesterdayAllZero) {
|
||||||
|
dataSets.add(
|
||||||
RadarDataSet(
|
RadarDataSet(
|
||||||
dataEntries: data
|
dataEntries: data
|
||||||
.map((e) => RadarEntry(value: (e['y'] as num).toDouble()))
|
.map((e) => RadarEntry(value: (e['y'] as num).toDouble()))
|
||||||
@@ -55,7 +118,14 @@ class SleepRadarChart extends StatelessWidget {
|
|||||||
fillColor: Colors.transparent,
|
fillColor: Colors.transparent,
|
||||||
entryRadius: 0,
|
entryRadius: 0,
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AspectRatio(
|
||||||
|
aspectRatio: 1.3,
|
||||||
|
child: RadarChart(
|
||||||
|
RadarChartData(
|
||||||
|
dataSets: dataSets,
|
||||||
radarBackgroundColor: stringToColor("#343844").withOpacity(0.6),
|
radarBackgroundColor: stringToColor("#343844").withOpacity(0.6),
|
||||||
radarBorderData: BorderSide(
|
radarBorderData: BorderSide(
|
||||||
color: themeController.currentColor.sc4, width: 0.5.rpx),
|
color: themeController.currentColor.sc4, width: 0.5.rpx),
|
||||||
@@ -63,7 +133,8 @@ class SleepRadarChart extends StatelessWidget {
|
|||||||
titlePositionPercentageOffset: 0.2,
|
titlePositionPercentageOffset: 0.2,
|
||||||
titleTextStyle: TextStyle(
|
titleTextStyle: TextStyle(
|
||||||
fontSize: AppConstants().normal_text_fontSize,
|
fontSize: AppConstants().normal_text_fontSize,
|
||||||
color: themeController.currentColor.sc3),
|
color: themeController.currentColor.sc3,
|
||||||
|
),
|
||||||
getTitle: (index, angle) {
|
getTitle: (index, angle) {
|
||||||
return RadarChartTitle(text: data[index]['name'] ?? '未知'.tr);
|
return RadarChartTitle(text: data[index]['name'] ?? '未知'.tr);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -83,8 +83,13 @@ class _BreatheCardState extends State<BreatheCard>
|
|||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List data = widget.sleepReport['brs'] ?? [];
|
||||||
List data = widget.sleepReport['brs'] ?? [];
|
List data = widget.sleepReport['brs'] ?? [];
|
||||||
|
|
||||||
|
data = data.where((item) {
|
||||||
|
return item['show'] != false; // 只保留 show 不为 false 的元素
|
||||||
|
}).toList(); // 添加 .toList()
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ Widget DailyDataWidget(
|
|||||||
GlobalKey breatheCardKey,
|
GlobalKey breatheCardKey,
|
||||||
dynamic data,
|
dynamic data,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
List<Widget> _buildSectionList() {
|
List<Widget> _buildSectionList() {
|
||||||
EdgeInsetsDirectional padding =
|
EdgeInsetsDirectional padding =
|
||||||
EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 25.rpx);
|
EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 25.rpx);
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ class HeartRateCard extends StatefulWidget {
|
|||||||
State<HeartRateCard> createState() => _HeartRateCardState();
|
State<HeartRateCard> createState() => _HeartRateCardState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HeartRateCardState extends State<HeartRateCard> with TickerProviderStateMixin {
|
class _HeartRateCardState extends State<HeartRateCard>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
final GlobalKey _highlightKey = GlobalKey();
|
final GlobalKey _highlightKey = GlobalKey();
|
||||||
AnimationController? _animationController;
|
AnimationController? _animationController;
|
||||||
bool _shouldAnimate = false;
|
bool _shouldAnimate = false;
|
||||||
@@ -32,7 +33,8 @@ class _HeartRateCardState extends State<HeartRateCard> with TickerProviderStateM
|
|||||||
}
|
}
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (widget.highlightItem != null && _highlightKey.currentContext != null) {
|
if (widget.highlightItem != null &&
|
||||||
|
_highlightKey.currentContext != null) {
|
||||||
Scrollable.ensureVisible(
|
Scrollable.ensureVisible(
|
||||||
_highlightKey.currentContext!,
|
_highlightKey.currentContext!,
|
||||||
duration: Duration(milliseconds: 500),
|
duration: Duration(milliseconds: 500),
|
||||||
@@ -86,8 +88,16 @@ class _HeartRateCardState extends State<HeartRateCard> with TickerProviderStateM
|
|||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List data = widget.sleepReport['hrs'] ?? [];
|
||||||
|
|
||||||
|
// data = data.where((item) {
|
||||||
|
// return item['show'] != false; // 只保留 show 不为 false 的元素
|
||||||
|
// });
|
||||||
List data = widget.sleepReport['hrs'] ?? [];
|
List data = widget.sleepReport['hrs'] ?? [];
|
||||||
|
|
||||||
|
data = data.where((item) {
|
||||||
|
return item['show'] != false; // 只保留 show 不为 false 的元素
|
||||||
|
}).toList(); // 添加 .toList()
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -104,8 +114,8 @@ class _HeartRateCardState extends State<HeartRateCard> with TickerProviderStateM
|
|||||||
children: List.generate(data.length, (index) {
|
children: List.generate(data.length, (index) {
|
||||||
final item = data[index];
|
final item = data[index];
|
||||||
item['showTip'] = true;
|
item['showTip'] = true;
|
||||||
final bool isHighlighted = _shouldAnimate &&
|
final bool isHighlighted =
|
||||||
item['id'] == _highlightedId;
|
_shouldAnimate && item['id'] == _highlightedId;
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: (MediaQuery.of(context).size.width - 160.rpx) / 3,
|
width: (MediaQuery.of(context).size.width - 160.rpx) / 3,
|
||||||
@@ -118,7 +128,8 @@ class _HeartRateCardState extends State<HeartRateCard> with TickerProviderStateM
|
|||||||
? BoxDecoration(
|
? BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: themeController.currentColor.sc2
|
color: themeController.currentColor.sc2
|
||||||
.withOpacity(_animationController?.value ?? 0),
|
.withOpacity(
|
||||||
|
_animationController?.value ?? 0),
|
||||||
width: 1.rpx,
|
width: 1.rpx,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
|||||||
@@ -843,39 +843,6 @@ class _NewSleepReportPageState extends State<NewSleepReportPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Obx(() {
|
|
||||||
// if (sleepReportController.isLoading.value) {
|
|
||||||
// return Center(
|
|
||||||
// child: CircularProgressIndicator(
|
|
||||||
// strokeWidth: 2,
|
|
||||||
// valueColor: AlwaysStoppedAnimation<Color>(
|
|
||||||
// themeController.currentColor.sc1,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// switch (sleepReportController.model.type) {
|
|
||||||
// case 1:
|
|
||||||
// return DailyDataWidget(
|
|
||||||
// sleepReport,
|
|
||||||
// sleepCardKey,
|
|
||||||
// heartRateCardKey,
|
|
||||||
// breatheCardKey,
|
|
||||||
// widget.data);
|
|
||||||
// case 2:
|
|
||||||
// return WeekDataWidget(
|
|
||||||
// sleepReport,
|
|
||||||
// widget.data,
|
|
||||||
// );
|
|
||||||
// case 3:
|
|
||||||
// return MonthDataWidget(
|
|
||||||
// sleepReport,
|
|
||||||
// widget.data,
|
|
||||||
// );
|
|
||||||
// default:
|
|
||||||
// return NullDataWidget();
|
|
||||||
// }
|
|
||||||
// }),
|
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if (sleepReportController.isLoading.value) {
|
if (sleepReportController.isLoading.value) {
|
||||||
return Center(
|
return Center(
|
||||||
|
|||||||
Reference in New Issue
Block a user