import 'dart:async'; import 'package:ef/ef.dart'; import 'package:flutter/material.dart'; import 'package:flutterflow_ui/flutterflow_ui.dart'; import 'package:intl/intl.dart'; import 'package:vbvs_app/common/color/ServiceConstant.dart'; import 'package:vbvs_app/common/pojo/city.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; import 'package:vbvs_app/common/util/MyUtils.dart'; import 'package:vbvs_app/common/util/requestWithLog.dart'; import 'package:vbvs_app/component/tool/CustomCard.dart'; import 'package:vbvs_app/component/tool/TopSlideNotification.dart'; import 'package:vbvs_app/controller/mh_controller/people_info_controller.dart'; import 'package:vbvs_app/pages/common/selectDialog.dart'; import 'package:vbvs_app/pages/mh_page/device/controller/mht_bluetooth_controller.dart'; import 'package:vbvs_app/pages/mh_page/homepage/controller/mht_home_controller.dart'; import 'package:vbvs_app/pages/person/select_city.dart'; import 'package:vbvs_app/pages/person/select_disease.dart'; // 导入疾病选择 //保存人员信息 class MHTPeopleInfoPage extends StatefulWidget { const MHTPeopleInfoPage({Key? key}) : super(key: key); @override State createState() => _MHTPeopleInfoPageState(); } class _MHTPeopleInfoPageState extends State { final MHTBlueToothController bluetoothController = Get.find(); final CityModelController cityController = Get.find(); final List _nameControllers = []; final List _contactControllers = []; List> peopleList = []; List cityModels = []; // 存储每个person的城市数据 List> diseaseIdsList = []; // 存储每个person的疾病ID列表 bool isLoading = true; late Future> cityDataFuture; // 添加疾病数据(这里需要根据实际情况获取,可以先设为空列表) List diseaseList = []; @override void initState() { super.initState(); _initializeData(); } void _initializeData() async { // 先加载城市数据 cityDataFuture = cityController.loadAndSetCityData().then((success) { return cityController.cityList; }); // 等待城市数据加载完成后再初始化其他数据 await cityDataFuture; final device = bluetoothController.currentFullDevice; //todo 初始化传感器id // Initialize person A peopleList.add({ 'mac': device?.macA, 'gender': 1, 'id': device!.macAID, }); // Initialize person B if exists if (device?.macB != null && device!.macB!.isNotEmpty) { peopleList.add({ 'mac': device.macB, 'gender': 1, 'id': device!.macBID, }); } // 初始化城市模型列表 cityModels = List.filled(peopleList.length, CityModel()); // 初始化疾病ID列表 diseaseIdsList = List.generate(peopleList.length, (index) => []); // 加载疾病数据(这里需要实现获取疾病数据的方法) await _loadDiseaseData(); // Initialize controllers after data is loaded _initializeControllers(); setState(() => isLoading = false); } // 加载疾病数据的方法 Future _loadDiseaseData() async { try { PeopleInfoController controller = Get.find(); await controller.getDiseaseData(); diseaseList = controller.diseaseList.value; } catch (e) { print("加载疾病数据失败: $e"); diseaseList = []; } } void _initializeControllers() { for (var person in peopleList) { _nameControllers.add(TextEditingController(text: person["name"] ?? "")); _contactControllers .add(TextEditingController(text: person["contact"] ?? "")); } } @override void dispose() { for (var controller in _nameControllers) { controller.dispose(); } for (var controller in _contactControllers) { controller.dispose(); } super.dispose(); } Widget getLine() { return Divider( color: Color(0XFF929699), thickness: 0.5.rpx, height: 0, ); } String time_08_Formatter_pattern(dynamic date, String pattern) { if (date == null || date.toString().isEmpty) return "-"; try { String normalized = date.toString().replaceAll("/", "-"); DateTime dt = DateTime.parse(normalized); return DateFormat(pattern).format(dt); } catch (e) { return "-"; } } // 获取已选择的慢病名称 String getSelectedDiseaseNames(List selectedIds) { if (selectedIds.isEmpty) return "请选择慢病".tr; final selectedNames = diseaseList .where((disease) => selectedIds.contains(disease['_id'].toString())) .map((disease) => disease['disease_type_name'].toString()) .toList(); String displayText = selectedNames.join('、'); if (displayText.length > 10) { displayText = '${displayText.substring(0, 10)}...'; } return displayText; } Future _savePersonData( Map personData, BuildContext context) async { String serviceAddress = ServiceConstant.service_address; String serviceName = ServiceConstant.server_service; String serviceApi = ServiceConstant.personnel_info; String queryUrl = "${serviceAddress}${serviceName}${serviceApi}"; try { var body = { 'mac': personData['mac'], 'name': personData['name'], 'gender': personData['gender'], 'height': personData['height'], 'weight': personData['weight'], 'birthday': personData['birthday'] is DateTime ? DateFormat('yyyy-MM-dd').format(personData['birthday']) : personData['birthday'], 'contact': personData['contact'], 'id': personData['id'], 'UTC': personData['UTC'], 'city_id': personData['city_id'], 'disease_ids': personData['disease_ids'], // 添加疾病ID字段 }; await requestWithLog( logTitle: "保存用户信息".tr, method: MyHttpMethod.put, queryUrl: queryUrl, data: body, onSuccess: (res) { print(res); }, onFailure: (res) { TopSlideNotification.show(context, text: res.msg!, textColor: themeController.currentColor.sc9); print(res); }, ); } catch (e) { print("Error saving person data: $e"); } } // 根据城市ID查找完整的城市数据 CityModel? findCompleteCityDataById(int? id, List cityData) { if (id == null) return null; try { // 遍历三级数据结构查找匹配的ID for (var country in cityData) { // 检查国家节点是否有ID匹配 if (country.id == id) { return CityModel( id: country.id, value: country.value, label: country.label, country: country.value ?? country.country, province: null, city: null, UTC: country.UTC, children: country.children, ); } // 检查省份节点 for (var province in country.children ?? []) { if (province.id == id) { return CityModel( id: province.id, value: province.value, label: province.label, country: country.value ?? country.country, province: province.value ?? province.province, city: null, UTC: province.UTC, children: province.children, ); } // 检查城市节点 for (var city in province.children ?? []) { if (city.id == id) { return CityModel( id: city.id, value: city.value, label: city.label, country: country.value ?? country.country, province: province.value ?? province.province, city: city.value ?? city.city, UTC: city.UTC, children: city.children, ); } } } } return null; } catch (e) { print("根据ID查找完整城市数据失败:$e"); return null; } } @override Widget build(BuildContext context) { if (isLoading) { return Center( child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( themeController.currentColor.sc1, ), ), ); } return LayoutBuilder( builder: (context, boxConstraints) => GestureDetector( onTap: () { FocusScope.of(context).requestFocus(FocusNode()); }, child: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/new_background.png'), fit: BoxFit.fill, ), ), child: Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( elevation: 0, surfaceTintColor: Colors.transparent, backgroundColor: Colors.transparent, automaticallyImplyLeading: false, iconTheme: IconThemeData(color: Colors.white), titleSpacing: 0, title: SizedBox( width: double.infinity, height: 180.rpx, child: Stack( alignment: Alignment.center, children: [ Text( '人员资料'.tr, textAlign: TextAlign.center, style: TextStyle( color: Colors.white, fontSize: 30.rpx, ), ), Positioned( left: 20.rpx, child: returnIconButtomNew(), ), Positioned( right: 30.rpx, child: CustomCard( borderRadius: 16.rpx, gradientDirection: GradientDirection.vertical, onTap: () async { // 数据验证 bool isValid = true; for (int i = 0; i < peopleList.length; i++) { var person = peopleList[i]; // 验证身高 if (person['height'] != null && person['height'].toString().isNotEmpty && int.tryParse(person['height'].toString()) == null) { TopSlideNotification.show(context, text: "请选择身高".tr, textColor: Color(0xFFFF7159)); isValid = false; break; } // 验证体重 if (person['weight'] != null && person['weight'].toString().isNotEmpty && int.tryParse(person['weight'].toString()) == null) { TopSlideNotification.show(context, text: "请选择体重".tr, textColor: Color(0xFFFF7159)); isValid = false; break; } // 验证联系方式 if (person['contact'] != null && person['contact'].toString().isNotEmpty && !MyUtils.isValidPhoneNumber( person['contact'].toString())) { TopSlideNotification.show(context, text: "请输入正确的联系人电话".tr, textColor: Color(0xFFFF7159)); isValid = false; break; } // 验证城市选择 // final cityModel = cityModels[i]; // if (cityModel.id == null) { // TopSlideNotification.show(context, // text: "请选择城市".tr, // textColor: Color(0xFFFF7159)); // isValid = false; // break; // } } if (isValid) { // 保存所有人员数据 for (int i = 0; i < peopleList.length; i++) { final person = peopleList[i]; final cityModel = cityModels[i]; final diseaseIds = diseaseIdsList[i]; // 添加城市信息到person数据 person['UTC'] = cityModel.UTC; person['city_id'] = cityModel.id; person['disease_ids'] = diseaseIds; // 添加疾病ID await _savePersonData(person, context); } TopSlideNotification.show(context, text: "保存成功".tr); MHTHomeController mhtHomeController = Get.find(); mhtHomeController.getPersonList(); // 跳转到下一页 Map data = {}; final device = bluetoothController.currentFullDevice; data['_id'] = device!.deviceID; data['isNextStep'] = true; Get.toNamed("/editBedPage", arguments: data); } }, colors: const [ Color(0xFFFCFCFC), Color(0xFFF8FAF9), Color(0XFFECF6F3), Color(0XFFD9F0E9), Color(0xFFCEECE3) ], child: Container( width: 120.rpx, height: 60.rpx, alignment: Alignment.center, child: Text( "下一步".tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0XFF011D33), letterSpacing: 0, fontSize: 30.rpx, ), ), ), ), ) ], ), ), centerTitle: false, ), body: SafeArea( top: true, child: Container( padding: EdgeInsets.only(left: 30.rpx, right: 30.rpx), width: MediaQuery.sizeOf(context).width, height: MediaQuery.sizeOf(context).height * 1.123, child: SingleChildScrollView( child: Column( children: [ ...List.generate(peopleList.length, (index) { final person = peopleList[index]; return Column( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( margin: EdgeInsets.only( left: 18.rpx, top: index == 0 ? 30.rpx : 90.rpx, bottom: 20.rpx), child: Text( index == 0 ? 'person_info_A'.tr : 'person_info_B'.tr, style: TextStyle( color: Colors.white, fontSize: 30.rpx), ), ), Container( child: Column( children: [ getLine(), Container( width: double.infinity, height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), decoration: BoxDecoration(), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '姓名'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Container( width: 300.rpx, child: TextField( controller: _nameControllers[index], obscureText: false, textAlign: TextAlign.right, style: TextStyle( fontSize: 30.rpx, color: Colors.white), decoration: InputDecoration( fillColor: Colors.transparent, filled: true, hintText: "请输入姓名".tr, hintStyle: TextStyle( color: themeController .currentColor.sc4, ), border: InputBorder.none, contentPadding: EdgeInsets.all(0)), onChanged: (value) { setState(() { peopleList[index]["name"] = value; }); }, ), ), ], ), ), getLine(), Container( margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), width: double.infinity, height: 90.rpx, decoration: BoxDecoration(), child: InkWell( onTap: () { FocusScope.of(context) .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { showOneSelectionDialog(context, title: "选择性别".tr, arr: ["女".tr, "男".tr], checkIndex: peopleList[index] ['gender'], checkChange: (sindex) { setState(() { peopleList[index]['gender'] = sindex; }); }).then((d) {}); }); }, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '性别'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Row( mainAxisSize: MainAxisSize.max, children: [ Container( width: 200.rpx, child: Text( '${peopleList[index]['gender'] == 1 ? '男'.tr : '女'.tr}', textAlign: TextAlign.right, style: TextStyle( fontFamily: 'Readex Pro', color: Colors.white, fontSize: 30.rpx, letterSpacing: 0, ), ), ), SizedBox(width: 16.rpx), Icon( Icons.expand_more, color: Colors.white, size: 48.rpx, ), ], ), ], ), ), ), getLine(), Container( width: double.infinity, height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), decoration: BoxDecoration(), child: InkWell( onTap: () { FocusScope.of(context) .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { showHeightPickerDialog( context, title: "选择身高".tr, initialHeight: int.tryParse( peopleList[index]['height'] ?? '170') ?? 170, onConfirm: (int selectedHeight) { setState(() { peopleList[index]['height'] = selectedHeight.toString(); }); }, ); }); }, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '身高(cm)'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Row( children: [ Text( peopleList[index]['height'] != null ? "${peopleList[index]['height']} cm" : '', style: TextStyle( fontFamily: 'Readex Pro', color: Colors.white, fontSize: 30.rpx, ), ), SizedBox(width: 16.rpx), Icon(Icons.expand_more, color: Colors.white, size: 48.rpx), ], ), ], ), ), ), getLine(), Container( width: double.infinity, height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), decoration: BoxDecoration(), child: InkWell( onTap: () { FocusScope.of(context) .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { showWeightPickerDialog( context, title: "选择体重".tr, initialWeight: "50", onConfirm: (int selectedWeight) { setState(() { peopleList[index]['weight'] = selectedWeight.toString(); }); }, ); }); }, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '体重(kg)'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Row( children: [ Text( peopleList[index]['weight'] != null ? "${peopleList[index]['weight']} kg" : '', style: TextStyle( fontFamily: 'Readex Pro', color: Colors.white, fontSize: 30.rpx, ), ), SizedBox(width: 16.rpx), Icon(Icons.expand_more, color: Colors.white, size: 48.rpx), ], ), ], ), ), ), getLine(), Container( width: double.infinity, height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), decoration: BoxDecoration(), child: InkWell( onTap: () { FocusScope.of(context) .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { showDateSelectionDialog(context, title: "选择生日".tr, checkDate: peopleList[index] ['birthday'] is DateTime ? peopleList[index]['birthday'] : DateTime.tryParse( peopleList[index] ['birthday'] ?? '') ?? DateTime.now(), checkChange: (DateTime d) { setState(() { peopleList[index]['birthday'] = d; }); }).then((d) {}); }); }, child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '生日'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Row( mainAxisSize: MainAxisSize.max, children: [ Container( constraints: BoxConstraints( minWidth: 200.rpx), child: Text( peopleList[index]['birthday'] != null ? time_08_Formatter_pattern( peopleList[index] ['birthday'], "yyyy年MM月dd日".tr) : '', textAlign: TextAlign.right, style: TextStyle( fontFamily: 'Readex Pro', color: Colors.white, fontSize: 30.rpx, letterSpacing: 0, ), ), ), SizedBox(width: 16.rpx), Icon( Icons.expand_more, color: Colors.white, size: 48.rpx, ), ], ), ], ), ), ), getLine(), Container( width: double.infinity, height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), decoration: BoxDecoration(), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '联系方式'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Container( width: 300.rpx, child: TextField( controller: _contactControllers[index], obscureText: false, keyboardType: TextInputType.number, textInputAction: TextInputAction.done, textAlign: TextAlign.right, style: TextStyle( fontSize: 30.rpx, color: Colors.white), decoration: InputDecoration( fillColor: Colors.transparent, filled: true, hintText: "请输入联系方式".tr, hintStyle: TextStyle( color: themeController .currentColor.sc4, ), border: InputBorder.none, contentPadding: EdgeInsets.all(0)), onChanged: (value) { setState(() { peopleList[index]['contact'] = value; }); }, ), ), ], ), ), getLine(), // 城市选择部分 Container( height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), child: InkWell( onTap: () { FocusScope.of(context) .requestFocus(FocusNode()); Future.delayed( const Duration(milliseconds: 250), () { showCitySelectionDialog( context, selectedCity: cityModels[index], onCityChanged: (CityModel newCity) { setState(() { cityModels[index] = newCity; }); }, title: "选择城市".tr, cityDataFuture: cityDataFuture, colors: CitySelectionColors( pickerBackgroundColor: stringToColor("#003058"), confirmTextColor: stringToColor("#84F5FF"), selectedCityColor: stringToColor("#84F5FF"), selectedTextColor: stringToColor("#011D33"), ), ); }); }, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '请选择城市'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Row( children: [ Text( cityModels[index].id != null ? MyUtils .getDetailedCityDisplayText( cityModels[index]) : "请选择城市".tr, style: TextStyle( color: cityModels[index].id != null ? Colors.white : themeController .currentColor.sc4, fontSize: 30.rpx, ), ), SizedBox(width: 16.rpx), Icon(Icons.expand_more, color: Colors.white, size: 48.rpx), ], ), ], ), ), ), getLine(), // 慢病管理部分 Container( height: 90.rpx, margin: EdgeInsets.only( left: 40.rpx, right: 35.rpx), child: InkWell( onTap: () { FocusScope.of(context) .requestFocus(FocusNode()); Future.delayed( Duration(milliseconds: 250), () { // 获取当前已选择的慢病ID列表 final currentDiseaseIds = List.from( diseaseIdsList[index]); showDiseaseSelectionDialog( context, selectedIds: currentDiseaseIds, diseaseList: diseaseList, onDiseasesChanged: (List newDiseaseIds) { setState(() { diseaseIdsList[index] = newDiseaseIds; }); }, title: "选择慢病".tr, colors: DiseaseSelectionColors( pickerBackgroundColor: stringToColor("#003058"), confirmTextColor: stringToColor("#84F5FF"), selectedDiseaseColor: stringToColor("#84F5FF"), ), ); }); }, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '慢病管理'.tr, style: TextStyle( fontFamily: 'Readex Pro', color: Color(0xFF9EA4B7), fontSize: 30.rpx, letterSpacing: 0, ), ), Row( children: [ Text( getSelectedDiseaseNames( diseaseIdsList[index]), style: TextStyle( color: diseaseIdsList[index] .isNotEmpty ? Colors.white : themeController .currentColor.sc4, fontSize: 30.rpx, ), ), SizedBox(width: 16.rpx), Icon(Icons.expand_more, color: Colors.white, size: 48.rpx), ], ), ], ), ), ), getLine(), ], )) ], ); }), SizedBox(height: 100.rpx), ], ), ), ), ), ), ), ), ); } }