Files
tuiche/lib/pages/person/update_person_page.dart
2025-11-21 10:34:18 +08:00

886 lines
45 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.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/SelectableTagButton.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/person/person_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/enum/BindType.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/person/select_city.dart';
import 'package:vbvs_app/pages/person/select_time.dart';
class UpdatePersonPage extends StatefulWidget {
var status;
UpdatePersonPage({super.key, required this.status});
@override
State<UpdatePersonPage> createState() => _UpdatePageState();
}
class _UpdatePageState extends State<UpdatePersonPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
PersonController personController = Get.find();
BodyDeviceController bodyDeviceController = Get.find();
ThemeController themeController = Get.find();
final CityModelController cityController = Get.find<CityModelController>();
late Future<List<CityModel>> cityDataFuture;
@override
void initState() {
super.initState();
// personController.dateTime = null;
personController.getDiseaseData().then((apiResponse) {
if (apiResponse.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
context,
text: apiResponse.msg ?? '',
textColor: themeController.currentColor.sc9,
);
}
});
cityDataFuture = cityController.loadAndSetCityData().then((success) {
return cityController.cityList;
});
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
// onTap: () => FocusScope.of(context).unfocus(),,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(
color: themeController.currentColor.sc3,
),
titleSpacing: 0,
// leading: returnIconButtom,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
/// 居中标题
Text(
'人员资料.标题'.tr,
style: TextStyle(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
child: returnIconButtomAddCallback(() {
bodyDeviceController.getDeviceList();
bodyDeviceController.updateAll();
}),
),
Visibility(
// visible: widget.status == BindType.active.code,
visible: true,
child: Positioned(
right: 20.rpx,
child: CustomCard(
borderRadius: 20.rpx,
onTap: () async {
ApiResponse apiRespons =
await personController.savePersonData();
if (apiRespons.code == HttpStatusCodes.ok) {
updateDeviceBindStatus(
personController.update_person_mac.value);
TopSlideNotification.show(context,
text: apiRespons.msg!);
} else {
TopSlideNotification.show(context,
text: apiRespons.msg!,
textColor: themeController.currentColor.sc9);
}
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: 100.rpx,
height: 60.rpx,
alignment: Alignment.center,
padding: EdgeInsetsDirectional.fromSTEB(
16.rpx, 0, 16.rpx, 0),
child: Text(
'完成'.tr,
style: TextStyle(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
),
),
),
),
),
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: Column(
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 141.rpx, 70.rpx, 0),
child: Container(
width: double.infinity,
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: AppConstants().border_width,
),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: TextFormField(
// controller: _model.textController1,
// focusNode: _model.textFieldFocusNode1,
initialValue: personController.name.value,
onChanged: (Value) {
personController.name.value = Value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
fillColor: Colors.transparent,
isDense: true,
labelStyle: TextStyle(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
hintText: '人员资料.名字输入提示'.tr,
hintStyle: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
filled: true,
),
style: TextStyle(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
textAlign: TextAlign.center,
cursorColor:
themeController.currentColor.sc3,
// validator: _model.textController1Validator
// .asValidator(context),
),
),
),
),
Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 90.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Obx(
() {
bool isMaleGreyed =
personController.gender.value ==
0; // gender == 0 时男生部分变灰
return GestureDetector(
onTap: () {
if (widget.status ==
BindType.share.code) {
TopSlideNotification.show(
context,
text: "被分享用户只能修改用户名称",
textColor: themeController
.currentColor.sc9);
return;
}
personController.gender.value =
1; // 点击时将 gender 设置为 1女生部分被选中
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
child: ClipOval(
child: Opacity(
opacity: isMaleGreyed
? 0.4
: 1.0, // 控制透明度
child: Image.asset(
"assets/img/man.png",
fit: BoxFit.cover,
),
),
),
),
Text(
''.tr,
style: TextStyle(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: isMaleGreyed
? themeController
.currentColor.sc4
: themeController
.currentColor.sc3,
),
),
].divide(
SizedBox(height: 14.rpx)),
),
);
},
),
// 女性部分
Obx(
() {
bool isFemaleGreyed =
personController.gender.value ==
1; // gender == 1 时女生部分变灰
return GestureDetector(
onTap: () {
if (widget.status ==
BindType.share.code) {
TopSlideNotification.show(
context,
text: "被分享用户只能修改用户名称",
textColor: themeController
.currentColor.sc9);
return;
}
personController.gender.value =
0; // 点击时将 gender 设置为 0男生部分被选中
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
child: ClipOval(
child: Opacity(
opacity: isFemaleGreyed
? 0.4
: 1.0, // 控制透明度
child: Image.asset(
"assets/img/man.png",
fit: BoxFit.cover,
),
),
),
),
Text(
''.tr,
style: TextStyle(
fontFamily: 'Inter',
color: isFemaleGreyed
? themeController
.currentColor.sc4
: themeController
.currentColor.sc3,
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
].divide(
SizedBox(height: 14.rpx)),
),
);
},
),
].divide(SizedBox(width: 170.rpx)),
),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 50.rpx, 70.rpx, 0),
child: Container(
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: AppConstants().border_width,
),
),
child: InkWell(
onTap: () {
if (widget.status == BindType.share.code) {
TopSlideNotification.show(context,
text: "被分享用户只能修改用户名称",
textColor:
themeController.currentColor.sc9);
return;
}
FocusScope.of(context)
.requestFocus(FocusNode());
Future.delayed(Duration(milliseconds: 250),
() {
showDateSelectionDialog(
context,
checkDate: personController.dateTime ??
DateTime.now(),
checkChange: (DateTime d) {
personController.birthday.value =
MyUtils.formatBindTime(d);
personController.dateTime = d;
personController.updateAll();
},
title: "选择生日".tr,
);
});
},
child: Center(
child: Text(
personController.dateTime != null
? DateFormat("yyyy/MM/dd").format(
personController.dateTime!)
: '人员资料.生日输入提示'.tr,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Readex Pro',
color: personController.dateTime != null
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0,
),
),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 50.rpx, 70.rpx, 0),
child: Container(
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: AppConstants().border_width,
),
),
child: InkWell(
onTap: () {
if (widget.status == BindType.share.code) {
TopSlideNotification.show(context,
text: "被分享用户只能修改用户名称",
textColor:
themeController.currentColor.sc9);
return;
}
final currentHeight =
personController.height.value;
final initialHeight = currentHeight != null
? int.tryParse(
currentHeight.toString()) ??
170
: 170;
FocusScope.of(context)
.requestFocus(FocusNode());
Future.delayed(
const Duration(milliseconds: 250), () {
showHeightPickerDialog(
context,
title: "选择身高".tr,
initialHeight: initialHeight,
onConfirm: (int selectedHeight) {
personController.height.value =
selectedHeight.toString();
personController.updateAll();
print("身高: $selectedHeight cm");
},
);
});
},
child: Center(
child: Text(
personController.height.value != ""
? personController.height.value +
"cm".tr
: '身高输入提示'.tr,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Readex Pro',
color: personController.height.value !=
""
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0,
),
),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 50.rpx, 70.rpx, 0),
child: Container(
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: AppConstants().border_width,
),
),
child: InkWell(
onTap: () {
if (widget.status == BindType.share.code) {
TopSlideNotification.show(context,
text: "被分享用户只能修改用户名称",
textColor:
themeController.currentColor.sc9);
return;
}
FocusScope.of(context)
.requestFocus(FocusNode());
Future.delayed(
const Duration(milliseconds: 250), () {
showWeightPickerDialog(
context,
title: "选择体重".tr,
initialWeight:
personController.weight.value ?? "",
onConfirm: (int selectedWeight) {
personController.weight.value =
selectedWeight
.toString(); // ✅ 转成字符串
personController.updateAll();
},
);
});
},
child: Center(
child: Text(
personController.weight.value != ""
? personController.weight.value +
"kg".tr
: '人员资料.体重输入提示'.tr,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Readex Pro',
color: personController.weight.value !=
""
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0,
),
),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 50.rpx, 70.rpx, 0),
child: Container(
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: AppConstants().border_width,
),
),
child: InkWell(
onTap: () {
if (widget.status == BindType.share.code) {
TopSlideNotification.show(context,
text: "被分享用户只能修改用户名称",
textColor:
themeController.currentColor.sc9);
return;
}
FocusScope.of(context)
.requestFocus(FocusNode());
Future.delayed(Duration(milliseconds: 250),
() {
// 使用当前选中的城市数据,如果没有则创建默认
CityModel currentCity =
personController.cityModel ??
CityModel();
showCitySelectionDialog(
context,
selectedCity: currentCity,
onCityChanged: (CityModel newCity) {
// 处理城市选择变化
print(
'Selected city: ${newCity.toJson()}');
personController.cityModel = newCity;
personController.updateAll();
},
title: "选择城市".tr,
cityDataFuture:
cityDataFuture, // 传入预加载的数据
);
});
},
child: Center(
child: Text(
_getDetailedCityDisplayText(
personController.cityModel),
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Readex Pro',
color: personController.cityModel !=
null
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0,
),
),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 117.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'人员资料.疾病标题'.tr,
style: TextStyle(
fontFamily: 'Inter',
color: Color(0xFFF3F4F5),
fontSize: 30.rpx,
letterSpacing: 0.0,
),
),
),
),
),
Obx(() {
final selectedIds =
personController.selectedDiseaseIds;
final diseases = personController.diseaseList;
return Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 70.rpx, 70.rpx, 0),
child: Wrap(
spacing: 20.rpx,
runSpacing: 20.rpx,
children: diseases.map<Widget>((disease) {
final id = disease['_id'];
final name = disease['disease_type_name'];
final isSelected = selectedIds.contains(id);
return SelectableTagButton(
label: name,
selected: isSelected,
onTap: () {
if (widget.status ==
BindType.share.code) {
TopSlideNotification.show(context,
text: "被分享用户只能修改用户名称",
textColor: themeController
.currentColor.sc9);
return;
}
if (isSelected) {
selectedIds.remove(id);
} else {
selectedIds.add(id);
}
personController.model.read = 0;
personController.updateAll();
//切换语言
// Get.updateLocale(Locale("en", "us"));
},
);
}).toList(),
),
);
}),
],
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 52.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.rpx),
border: Border.all(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: AppConstants().border_width,
),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 30.rpx, 30.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 8.rpx, 0, 0),
child: Container(
width: 23.rpx,
height: 23.rpx,
// width: double.infinity,
decoration: BoxDecoration(),
child: SvgPicture.asset(
'assets/img/icon/tips.svg',
fit: BoxFit.cover,
color: themeController.currentColor.sc4,
),
),
),
Expanded(
child: Text(
'人员资料.提示'.tr,
style: TextStyle(
fontFamily: 'Inter',
color: themeController.currentColor.sc4,
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
].divide(SizedBox(width: 23.rpx)),
),
),
),
),
SizedBox(
height: 20.rpx,
),
],
),
),
),
),
),
),
);
}
Widget _buildDeviceCard(BuildContext context,
{required String title, required String imageUrl, required String type}) {
return CustomCard(
borderRadius: 20.rpx, // 圆角大小
onTap: () {
if (type != null) {
if (type == '1') {
Get.toNamed("/blueteethDevice");
}
}
},
colors: [themeController.currentColor.sc17], // 背景色
child: Container(
width: double.infinity,
height: MediaQuery.sizeOf(context).height * 0.135,
constraints: BoxConstraints(
minHeight: 220.rpx,
),
padding: EdgeInsetsDirectional.fromSTEB(77.rpx, 0, 21.rpx, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: TextStyle(
fontFamily: 'Inter',
color: const Color(0xFFC2CED7),
fontSize: 30.rpx,
letterSpacing: 0.0,
),
),
ClipRRect(
borderRadius: BorderRadius.circular(8.rpx),
child: Image.asset(
imageUrl,
width: 212.rpx,
height: 168.rpx,
),
),
],
),
),
);
}
void updateDeviceBindStatus(String mac) {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_setting;
String type = "device_bind_status_$mac";
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${type}";
requestWithLog(
logTitle: "查询绑定流程",
method: MyHttpMethod.get,
queryUrl: queryUrl,
onSuccess: (res) {
print(res);
Map<String, dynamic> data = {
"type": type,
"mac": mac,
"wifi": res.data['wifi'],
"celibration": res.data['celibration'],
"person_info": true,
"time": DateTime.now().millisecondsSinceEpoch,
};
requestWithLog(
logTitle: "更新绑定流程",
method: MyHttpMethod.put,
queryUrl: queryUrl,
data: data,
onSuccess: (res) {},
onFailure: (res) {},
);
},
onFailure: (res) {},
);
}
// 获取城市显示文本
// 更详细的显示逻辑(可选)
String _getDetailedCityDisplayText(CityModel? cityModel) {
if (cityModel == null) {
return '选择城市'.tr;
}
// 根据数据层级显示不同的格式
if (cityModel.city != null && cityModel.city!.isNotEmpty) {
// 三级数据:国家-省份-城市
return '${cityModel.country ?? ''}-${cityModel.province ?? ''}-${cityModel.city ?? cityModel.value ?? ''}';
} else if (cityModel.province != null && cityModel.province!.isNotEmpty) {
// 二级数据:国家-省份
return '${cityModel.country ?? ''}-${cityModel.province ?? cityModel.value ?? ''}';
} else if (cityModel.country != null && cityModel.country!.isNotEmpty) {
// 一级数据:国家
return cityModel.country!;
} else if (cityModel.value != null && cityModel.value!.isNotEmpty) {
// 只有 value 字段
return cityModel.value!;
} else {
return '选择城市'.tr;
}
}
}