更新分享

This commit is contained in:
wyf
2025-04-28 15:37:58 +08:00
parent 850c34b408
commit eae7a2284d
116 changed files with 12143 additions and 3017 deletions

View File

@@ -0,0 +1,29 @@
class ServiceConstant {
static const String baseHost = "vsbs-test.he-info.cn";//服务地址
static const String service_address = "http://$baseHost";
static String server_service = "/vsbs_app_server";//服务名称
static String send_code = "/api/verifycode/send";//发送验证码
static String login = "/api/user/login";//登录
static String get_bluetooth_device_status = "/api/device/status/info";//设备绑定状态
static String device_bind = "/api/device/bind";//设备绑定
static String device_type = "/api/device/type/list";//设备类型
static String upload_file = "/api/file/info";//上传文件
static String user_info = "/api/user/info";//更新用户资料,查询用户信息
static String device_list = "/api/device/list";//绑定设备列表
static String person_info = "/api/personnel/info";//用户资料
static String sleep_report = "/api/device/sleep/data";//睡眠报告
static String device_share = "/api/device/share";//分享设备
static String message_list = "/api/mesasge/list";//消息列表
static String device_show = "/api/device/bind";//更新设备绑定
static String disease_list = "/api/personnel/disease/list";//获取疾病类型
static String logService = "$service_address/vsbs_log";
static const String webSocketService = "wss://$baseHost/vsbs_ws_gateway/ws";
static const String sleep_token = "HdAMjzqiYQKsmHRyEFKhfRGQ";
static const String sleep_report_url = "https://alltoone.he-info.cn/h5/#/mattress/sleep/sleep";
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:intl/intl.dart';
class DailyLogUtils {
// 获取日志文件路径(按日期命名)
static Future<File> _getLogFile() async {
final dir = await getApplicationDocumentsDirectory();
final date = DateFormat('yyyy-MM-dd').format(DateTime.now());
final filePath = '${dir.path}/$date.log';
final file = File(filePath);
if (!await file.exists()) {
await file.create(recursive: true);
}
return file;
}
// 写入日志核心方法,带日志等级
static Future<void> _writeLogWithLevel(String level, String content) async {
final file = await _getLogFile();
final now = DateTime.now();
final time = DateFormat('HH:mm:ss').format(now);
final logLine = '[$time][$level] $content\n';
await file.writeAsString(logLine, mode: FileMode.append);
}
// 写入 info 日志(原 writeLog 保留)
static Future<void> writeLog(String content) async {
await _writeLogWithLevel('INFO', content);
}
// 写入 warning 日志
static Future<void> writeWarning(String content) async {
await _writeLogWithLevel('WARNING', content);
}
// 写入 error 日志
static Future<void> writeError(String content) async {
await _writeLogWithLevel('ERROR', content);
}
// 写入 debug 日志
static Future<void> writeDebug(String content) async {
await _writeLogWithLevel('DEBUG', content);
}
// 读取当天日志
static Future<String> readTodayLog() async {
final file = await _getLogFile();
return await file.readAsString();
}
// 获取所有日志文件(返回 File 列表)
static Future<List<FileSystemEntity>> listLogFiles() async {
final dir = await getApplicationDocumentsDirectory();
final files = dir.listSync();
return files.where((f) => f.path.endsWith('.log')).toList();
}
// 清除所有日志
static Future<void> clearAllLogs() async {
final files = await listLogFiles();
for (final f in files) {
await File(f.path).delete();
}
}
/// 获取指定日期范围内的日志文件(包含起止日期)
static Future<List<File>> getLogsBetween(
DateTime fromDate, DateTime toDate) async {
final dir = await getApplicationDocumentsDirectory();
final logFiles = <File>[];
final dateFormat = DateFormat('yyyy-MM-dd');
for (DateTime date = fromDate;
!date.isAfter(toDate);
date = date.add(Duration(days: 1))) {
final fileName = '${dateFormat.format(date)}.log';
final file = File('${dir.path}/$fileName');
if (await file.exists()) {
logFiles.add(file);
}
}
return logFiles;
}
}

View File

@@ -118,6 +118,57 @@ class MyUtils {
curve: Curves.easeInOut,
);
}
static String formatBindTime(DateTime d) {
final DateFormat formatter = DateFormat('yyyy/MM/dd');
return formatter.format(d);
}
static DateTime? formatBirthdayTime(String? device) {
if (device == null || device.isEmpty) return null;
try {
return DateTime.parse(device.replaceAll('/', '-')); // 替换为标准格式
} catch (e) {
return null; // 解析失败时返回 null
}
}
static int getAgeByDate(DateTime? formatBirthdayTime) {
if (formatBirthdayTime == null) return 0;
final now = DateTime.now();
int age = now.year - formatBirthdayTime.year;
// 如果还没到今年生日,减一岁
if (now.month < formatBirthdayTime.month ||
(now.month == formatBirthdayTime.month &&
now.day < formatBirthdayTime.day)) {
age--;
}
return age;
}
static String formatDateTimeWeek(DateTime date) {
DateTime now = DateTime.now();
// 去除时间部分,仅比较年月日
DateTime today = DateTime(now.year, now.month, now.day);
DateTime target = DateTime(date.year, date.month, date.day);
if (target == today) {
return '今日';
}
const List<String> weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
return weekdays[date.weekday % 7]; // Dart中星期日是7要映射到索引0
}
/// 返回 MM/dd 格式
static String formatDateTimeDay(DateTime date) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
return '${twoDigits(date.month)}/${twoDigits(date.day)}';
}
}
Color stringToColor(String hexColor) {

View File

@@ -0,0 +1,77 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class NullDataWidget extends StatefulWidget {
const NullDataWidget({super.key});
@override
State<NullDataWidget> createState() => _TestWidgetState();
}
class _TestWidgetState extends State<NullDataWidget> {
final scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
ThemeController themeController = Get.find();
return GestureDetector(
child: Scaffold(
backgroundColor: Colors.transparent,
key: scaffoldKey,
body: SafeArea(
top: true,
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
),
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height * 1,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0.rpx, 0, 0),
child: Container(
width: 56.rpx,
height: 69.rpx,
// width: double.infinity,
decoration: BoxDecoration(),
child: SvgPicture.asset(
'assets/img/icon/nulldata.svg',
fit: BoxFit.cover,
color: themeController.currentColor.sc4,
),
),
),
Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height * 0.04,
constraints: BoxConstraints(
minHeight: 40,
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'暂无数据'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
useGoogleFonts: false,
fontFamily: "PingFangSC",
letterSpacing: 0.0,
fontSize: 26.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,172 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.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/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/home_page/SleepDataModuleWidget.dart';
import 'package:vbvs_app/component/home_page/SleepDateWidget.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class DynamicReportDetailWidget extends StatelessWidget {
final List<SleepDateWidget> sleepDateWidgets;
final List<SleepDataModuleWidget> sleepDataModuleWidgets;
final ThemeController themeController = Get.find();
final Map targetDevice;
DynamicReportDetailWidget({
required this.sleepDateWidgets,
required this.sleepDataModuleWidgets,
required this.targetDevice,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 25.rpx, 0, 25.rpx),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
borderRadius:
BorderRadius.circular(AppConstants().normal_container_radius),
),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(30.rpx, 30.rpx, 30.rpx, 30.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
_buildHeader(context),
_buildSleepDateWidgets(),
SizedBox(height: 20.rpx),
_buildSleepDataModuleWidgets(),
],
),
),
),
);
}
Widget _buildHeader(BuildContext context) {
return Container(
width: double.infinity,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${targetDevice['person']?['name'] == null ? '未命名'.tr : targetDevice['person']['name']}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: themeController.currentColor.sc3,
borderRadius: 0,
padding: EdgeInsets.zero,
onTap: () {
String mac = targetDevice['mac'];
List<SleepDateWidget> selectedWidgets = sleepDateWidgets
.where(
(widget) => widget.isSelected == true,
)
.toList();
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
int.parse(selectedWidgets[0].time!));
String time = MyUtils.formatBindTime(dateTime);
String sleepReportUrl =
"${ServiceConstant.sleep_report_url}?mac=${mac}&token=${ServiceConstant.sleep_token}&date=${time}";
Get.toNamed("/sleepReportPage", arguments: sleepReportUrl);
},
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'首页.报告详情'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 6.rpx, 0, 0.rpx),
child: SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 14.rpx,
height: 14.rpx,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 22.rpx)),
),
),
],
),
);
}
Widget _buildSleepDateWidgets() {
return Container(
width: double.infinity,
decoration: BoxDecoration(),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisSize: MainAxisSize.max,
children: sleepDateWidgets
.map((widget) => widget)
.toList()
.divide(SizedBox(width: 20.rpx)),
),
),
);
}
Widget _buildSleepDataModuleWidgets() {
// bool hasData = sleepDataModuleWidgets.any((w) {
// final data = w.data;
// return data['state'] != null &&
// data['state'].toString().trim().isNotEmpty;
// });
bool hasData = sleepDataModuleWidgets.length > 0;
if (!hasData) {
return Container(
height: 100.rpx,
alignment: Alignment.center,
child: Text(
'暂无数据'.tr,
style: FlutterFlowTheme.of(Get.context!).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 28.rpx,
color: themeController.currentColor.sc3,
),
),
);
}
return Container(
width: double.infinity,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisSize: MainAxisSize.max,
children: sleepDataModuleWidgets
.map((widget) => widget)
.toList()
.divide(SizedBox(width: 14.rpx)),
),
),
);
}
}

View File

@@ -1,14 +1,16 @@
import 'package:ef/base/widget/flutterflow/FlutterFlowTheme.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class SleepDataModuleWidget extends StatefulWidget {
const SleepDataModuleWidget({super.key});
final Map<String, dynamic> data;
const SleepDataModuleWidget({super.key, required this.data});
@override
State<SleepDataModuleWidget> createState() => _SleepDataModuleWidgetState();
@@ -33,111 +35,137 @@ class _SleepDataModuleWidgetState extends State<SleepDataModuleWidget> {
@override
Widget build(BuildContext context) {
ThemeController themeController = Get.find();
return Container(
width: MediaQuery.sizeOf(context).width * 0.27,
constraints: BoxConstraints(
minWidth: 200.rpx,
),
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
borderRadius: BorderRadius.circular(20.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(18.rpx, 18.rpx, 18.rpx, 22.rpx),
child: Container(
decoration: BoxDecoration(),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'离床次数',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
return ClickableContainer(
backgroundColor: themeController.currentColor.sc5,
highlightColor: themeController.currentColor.sc3,
borderRadius: 20.rpx,
padding: EdgeInsetsDirectional.fromSTEB(18.rpx, 18.rpx, 18.rpx, 22.rpx),
onTap: () {
print('点击了离床次数卡片');
},
child: Container(
width: MediaQuery.sizeOf(context).width * 0.27,
constraints: BoxConstraints(
minWidth: 200.rpx,
minHeight: 161.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'${widget.data['name']}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'${widget.data['value']}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 40.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
// SizedBox(
// height: 21.rpx,
// ),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'4',
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 10.rpx),
child: Text(
'${widget.data['unit'] ?? ''}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 40.rpx,
fontSize: AppConstants().small_text_fontSize,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0, 0.rpx, 10.rpx),
child: Text(
'',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants().small_text_fontSize,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
],
),
],
),
// Container(
// width: MediaQuery.sizeOf(context).width * 0.07,
// height: MediaQuery.sizeOf(context).height * 0.014,
// constraints: BoxConstraints(
// minWidth: 43.rpx,
// minHeight: 36.rpx,
// ),
// child: FFButtonWidget(
// onPressed: () {
// print('Button pressed ...');
// },
// // text: '${widget.data['level']}',
// text: '${widget.data['level']}',
// options: FFButtonOptions(
// height: 40.rpx,
// padding: EdgeInsets.zero,
// // color: themeController.currentColor.sc14,
// color: stringToColor('${widget.data['color']}'),
// textStyle:
// FlutterFlowTheme.of(context).titleSmall.override(
// fontFamily: 'Inter Tight',
// color: themeController.currentColor.sc3,
// // color: stringToColor('${widget.data['color']}'),
// letterSpacing: 0.0,
// fontSize: 15.rpx,
// ),
// elevation: 0,
// borderRadius: BorderRadius.circular(8.rpx),
// ),
// ),
// ),
ClickableContainer(
backgroundColor: stringToColor('${widget.data['color']}'),
highlightColor: themeController.currentColor.sc3,
padding: EdgeInsets.symmetric(
horizontal: 0.rpx,
vertical: 0.rpx,
),
Container(
width: MediaQuery.sizeOf(context).width * 0.07,
height: MediaQuery.sizeOf(context).height * 0.014,
borderRadius: 8.rpx,
onTap: () {
print('Button pressed ...');
},
child: Container(
alignment: Alignment.center,
constraints: BoxConstraints(
minWidth: 43.rpx,
minHeight: 36.rpx,
),
decoration: BoxDecoration(),
child: FFButtonWidget(
onPressed: () {
print('Button pressed ...');
},
text: '异常',
options: FFButtonOptions(
height: 40.rpx,
padding:
EdgeInsetsDirectional.fromSTEB(0.rpx, 0, 0.rpx, 0),
color: themeController.currentColor.sc14,
textStyle:
FlutterFlowTheme.of(context).titleSmall.override(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
fontSize: 15.rpx,
),
elevation: 0,
borderRadius: BorderRadius.circular(8.rpx),
),
child: Text(
'${widget.data['level']}',
style: FlutterFlowTheme.of(context).titleSmall.override(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
fontSize: 15.rpx,
),
),
),
],
),
Text(
'正常值:0~2',
style: FlutterFlowTheme.of(context).bodyMedium.override(
),
].divide(SizedBox(width: 0.rpx)),
),
Text(
'${widget.data['range']}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: AppConstants().small_text_fontSize,
letterSpacing: 0.0,
color: themeController.currentColor.sc4),
),
],
),
color: themeController.currentColor.sc4,
),
),
],
),
),
);

View File

@@ -6,10 +6,28 @@ import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class SleepDateWidget extends StatefulWidget {
const SleepDateWidget({super.key});
final String? mac;
final String? time; // 必传:日期,例如 "07/15"
final DateTime date; // 必传:日期,例如 "07/15"
final String? score; // 可选:分数,默认为 "--"
final String? comment; // 可选:评价,默认为 "暂无".tr
final Color? textColor; // 可选:文字颜色,默认为灰色
final bool? isSelected; // 是否选中
const SleepDateWidget({
super.key,
this.mac,
this.time,
required this.date,
this.score = '--',
this.comment = '暂无',
this.textColor,
this.isSelected = false, // 新增参数,默认不选中
});
@override
State<SleepDateWidget> createState() => _SleepDateWidgetState();
@@ -19,14 +37,35 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
@override
Widget build(BuildContext context) {
ThemeController themeController = Get.find();
BodyDeviceController bodyDeviceController = Get.find();
String week = MyUtils.formatDateTimeWeek(widget.date);
String day = MyUtils.formatDateTimeDay(widget.date);
// 选中时背景色为黑色,否则为透明
Color backgroundColor =
widget.isSelected == true ? Colors.black : Colors.transparent;
return ClickableContainer(
backgroundColor: Colors.transparent, // 原 BoxDecoration 为空
highlightColor:
themeController.currentColor.sc3.withOpacity(0.1), // 自定义点击波纹颜色
borderRadius: AppConstants().normal_container_radius, // 原来没设置圆角
backgroundColor: backgroundColor,
// highlightColor: themeController.currentColor.sc3.withOpacity(0.1),
highlightColor: Colors.transparent,
borderRadius: AppConstants().normal_container_radius,
padding: EdgeInsets.zero,
onTap: () {
print("今日评分卡片点击");
final mac = widget.mac;
final time = widget.time;
if (bodyDeviceController.sleepReportData.value.containsKey(mac)) {
final list = bodyDeviceController.sleepReportData.value[mac];
for (var item in list!) {
item['selected'] = (item['time'] == time);
}
bodyDeviceController.sleepReportData.value = {
...bodyDeviceController.sleepReportData.value,
};
bodyDeviceController.updateAll();
}
},
child: Container(
width: MediaQuery.sizeOf(context).width * 0.19,
@@ -36,54 +75,55 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(10.rpx, 25.rpx, 10.rpx, 22.rpx),
child: Container(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 14.rpx),
child: Text(
'今日',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: AppConstants().title_text_fontSize,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 33.rpx),
child: Text(
'07/15',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 20.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 16.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'70',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 48.rpx,
letterSpacing: 0.0,
color: stringToColor("#00C1AA")),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 14.rpx),
child: Text(
'${week}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: AppConstants().title_text_fontSize,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 33.rpx),
child: Text(
'${day}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 20.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 16.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
(widget.score?.isEmpty ?? true) ? '--' : widget.score!,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 48.rpx,
letterSpacing: 0.0,
color: widget.textColor ??
themeController.currentColor.sc4),
),
if ((widget.score?.trim().isNotEmpty ?? false))
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 16.rpx, 0, 0.rpx),
child: Text(
'',
''.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -94,40 +134,40 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
),
),
),
],
],
),
),
Container(
width: 0.2.rpx,
height: 2.4.rpx,
constraints: BoxConstraints(
minWidth: 123.rpx,
minHeight: 47.rpx,
),
child: FFButtonWidget(
onPressed: () {
print('合格按钮点击');
},
text: (widget.comment?.trim().isEmpty ?? true)
? '暂无'.tr
: widget.comment!,
options: FFButtonOptions(
height: 40.rpx,
padding:
EdgeInsetsDirectional.fromSTEB(16.rpx, 0, 16.rpx, 0),
iconPadding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
color: widget.textColor ?? themeController.currentColor.sc4,
textStyle: FlutterFlowTheme.of(context).titleSmall.override(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
),
elevation: 0,
borderRadius: BorderRadius.circular(50.rpx),
),
),
Container(
width: 0.2.rpx,
height: 2.4.rpx,
constraints: BoxConstraints(
minWidth: 123.rpx,
minHeight: 47.rpx,
),
child: FFButtonWidget(
onPressed: () {
print('合格按钮点击');
},
text: '合格',
options: FFButtonOptions(
height: 40.rpx,
padding:
EdgeInsetsDirectional.fromSTEB(16.rpx, 0, 16.rpx, 0),
iconPadding: EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
color: stringToColor("#00C1AA"),
textStyle:
FlutterFlowTheme.of(context).titleSmall.override(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
),
elevation: 0,
borderRadius: BorderRadius.circular(50.rpx),
),
),
),
],
),
),
],
),
),
),

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
class CustomCard extends StatefulWidget {
final double borderRadius; // 圆角
@@ -15,7 +16,7 @@ class CustomCard extends StatefulWidget {
required this.colors,
required this.child,
this.enableAnimation = true, // 默认启用动画效果
this.enableGradient = true, // 默认启用渐变效果
this.enableGradient = true, // 默认启用渐变效果
}) : super(key: key);
@override
@@ -25,36 +26,19 @@ class CustomCard extends StatefulWidget {
class _CustomCardState extends State<CustomCard>
with SingleTickerProviderStateMixin {
double _scale = 1.0;
final Duration _animationDuration = Duration(milliseconds: 50);
final GlobalKey _inkKey = GlobalKey();
final Duration _animationDuration = const Duration(milliseconds: 50);
Future<void> _handleTap(TapDownDetails details) async {
setState(() {
_scale = 0.95;
});
Future<void> _handleTap() async {
if (widget.enableAnimation) {
setState(() {
_scale = 0.95;
});
await Future.delayed(_animationDuration);
await Future.delayed(_animationDuration);
setState(() {
_scale = 1.0;
});
await Future.delayed(_animationDuration);
// 手动触发水波纹
final RenderBox? box =
_inkKey.currentContext?.findRenderObject() as RenderBox?;
if (box != null) {
final Offset localPosition = box.globalToLocal(details.globalPosition);
InkRipple.splashFactory.create(
controller: Material.of(_inkKey.currentContext!)!,
referenceBox: box,
position: localPosition,
color: widget.colors.first.withOpacity(0.2),
containedInkWell: true,
borderRadius: BorderRadius.circular(widget.borderRadius),
textDirection: Directionality.of(context),
);
setState(() {
_scale = 1.0;
});
}
widget.onTap();
@@ -62,51 +46,44 @@ class _CustomCardState extends State<CustomCard>
@override
Widget build(BuildContext context) {
final bool isGradient = widget.enableGradient && widget.colors.length > 1; // 只有启用渐变时,才使用渐变
final bool isGradient = widget.enableGradient && widget.colors.length > 1;
final Color baseColor = widget.colors.first;
return Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(widget.borderRadius),
child: GestureDetector(
onTapDown: _handleTap,
behavior: HitTestBehavior.translucent, // 关键:让空白区域也能点击
child: widget.enableAnimation // 判断是否启用动画
child: InkWell(
onTap: _handleTap,
borderRadius: BorderRadius.circular(widget.borderRadius),
splashColor: widget.colors.first.withOpacity(0.2),
child: widget.enableAnimation
? AnimatedScale(
scale: _scale,
duration: _animationDuration,
curve: Curves.easeInOut,
child: Ink(
key: _inkKey,
decoration: BoxDecoration(
color: isGradient ? null : baseColor,
gradient: isGradient
? LinearGradient(
colors: widget.colors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
borderRadius: BorderRadius.circular(widget.borderRadius),
),
child: widget.child,
),
child: _buildContent(isGradient, baseColor),
)
: Ink(
key: _inkKey,
decoration: BoxDecoration(
color: isGradient ? null : baseColor,
gradient: isGradient
? LinearGradient(
colors: widget.colors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
borderRadius: BorderRadius.circular(widget.borderRadius),
),
child: widget.child,
),
: _buildContent(isGradient, baseColor),
),
);
}
Widget _buildContent(bool isGradient, Color baseColor) {
return Container(
decoration: BoxDecoration(
color: isGradient ? null : baseColor,
gradient: isGradient
? LinearGradient(
colors: widget.colors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
borderRadius: BorderRadius.circular(widget.borderRadius),
),
child: Padding(
padding: EdgeInsets.fromLTRB(0.rpx, 0.rpx, 0.rpx, 5.rpx),
child: widget.child,
),
);
}

View File

@@ -0,0 +1,79 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'CustomCard.dart';
class SelectableTagButton extends StatelessWidget {
final String label;
final bool selected;
final VoidCallback onTap;
final double minWidth; // 最小宽度单位dp会转 rpx
final double maxWidth; // 最大宽度单位dp会转 rpx
ThemeController themeController = Get.find();
SelectableTagButton({
Key? key,
required this.label,
required this.selected,
required this.onTap,
this.minWidth = 132, // 默认最小宽度
this.maxWidth = 500, // 默认最大宽度
}) : super(key: key);
@override
Widget build(BuildContext context) {
final double minWidthRpx = minWidth.rpx;
final double maxWidthRpx = maxWidth.rpx;
final double horizontalPadding = 28.rpx * 2; // 左右各 28总 56
// 估算文本宽度:每个字符按 14.rpx 字号估一个宽度
final double estimatedTextWidth = label.length * 33.rpx;
// 总宽度 = 文本宽度 + padding
final double totalWidth = estimatedTextWidth + horizontalPadding;
// 限制在 min 和 max 之间
final double constrainedWidth = totalWidth.clamp(minWidthRpx, maxWidthRpx);
return CustomCard(
onTap: onTap,
borderRadius: AppConstants().normal_container_radius,
colors: selected
? [themeController.currentColor.sc1, themeController.currentColor.sc2]
: [Colors.transparent],
// colors: [Colors.transparent],
enableGradient: true,
child: Container(
decoration: BoxDecoration(
border: selected
? null
: Border.all(
color: themeController.currentColor.sc4,
width: 1.rpx,
), // 未选中时无边框
borderRadius: BorderRadius.circular(12.0), // 如果需要圆角
),
padding: EdgeInsets.symmetric(horizontal: 28.rpx),
constraints: BoxConstraints(
minHeight: 61.rpx,
maxWidth: constrainedWidth,
),
alignment: Alignment.center,
child: Text(
label,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
color: selected
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize: AppConstants().normal_text_fontSize, // 字体也用 rpx 控制
),
),
),
);
}
}

View File

@@ -0,0 +1,130 @@
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:get/get.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class TopSlideNotification extends StatefulWidget {
final String text;
double? fontSize = 26.rpx;
Color? textColor;
double? slideOffset = 200;
final Duration duration;
TopSlideNotification({
super.key,
this.text = '操作成功!',
this.fontSize,
this.textColor,
this.slideOffset,
this.duration = const Duration(seconds: 2),
});
@override
State<TopSlideNotification> createState() => _TopSlideNotificationState();
/// 工具方法:调用时直接加进 Overlay 上
static void show(
BuildContext context, {
String text = '操作成功!',
double fontSize = 16,
Color? textColor,
double slideOffset = 300.0,
Duration duration = const Duration(seconds: 2),
}) {
final overlay = Overlay.of(context);
final entry = OverlayEntry(
builder: (_) => TopSlideNotification(
text: text,
fontSize: fontSize,
textColor: textColor,
slideOffset: slideOffset,
duration: duration,
),
);
overlay.insert(entry);
Future.delayed(duration + const Duration(milliseconds: 500), () {
entry.remove();
});
}
}
class _TopSlideNotificationState extends State<TopSlideNotification>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Offset> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
SchedulerBinding.instance.addPostFrameCallback((_) async {
await _controller.forward();
await Future.delayed(widget.duration);
await _controller.reverse();
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final screenHeight = MediaQuery.of(context).size.height;
final offsetValue = widget.slideOffset! / screenHeight;
_animation = Tween<Offset>(
begin: const Offset(0, -1),
end: Offset(0, offsetValue),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
reverseCurve: Curves.easeIn,
));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Color get _textColor {
return widget.textColor ?? Get.find<ThemeController>().currentColor.sc2;
}
@override
Widget build(BuildContext context) {
return Positioned(
top: 0,
left: 0,
right: 0,
child: SlideTransition(
position: _animation,
child: Material(
color: stringToColor("#000000").withOpacity(0.8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Container(
// color: Colors.red,
child: Text(
widget.text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: widget.fontSize,
color: _textColor,
),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,51 @@
// import 'package:flutter/material.dart';
// import 'package:webview_flutter/webview_flutter.dart';
// class WebViewWidget extends StatefulWidget {
// final String url;
// const WebViewWidget({Key? key, required this.url}) : super(key: key);
// @override
// _WebViewWidgetState createState() => _WebViewWidgetState();
// }
// class _WebViewWidgetState extends State<WebViewWidget> {
// late WebViewController _webViewController;
// @override
// void initState() {
// super.initState();
// // 初始化 WebView 控件
// WebView.platform = SurfaceAndroidWebView();
// }
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(
// title: Text('WebView'),
// ),
// body: WebView(
// initialUrl: widget.url, // 设置要打开的网页地址
// javascriptMode: JavascriptMode.unrestricted, // 启用 JavaScript
// onWebViewCreated: (WebViewController webViewController) {
// _webViewController = webViewController;
// },
// onPageStarted: (String url) {
// print("页面开始加载:$url");
// },
// onPageFinished: (String url) {
// print("页面加载完成:$url");
// },
// navigationDelegate: (NavigationRequest request) {
// if (request.url.startsWith('https://www.google.com/')) {
// print('拦截了URL请求: ${request.url}');
// return NavigationDecision.prevent; // 拦截特定的请求
// }
// return NavigationDecision.navigate;
// },
// gestureNavigationEnabled: true, // 启用手势返回
// ),
// );
// }
// }

166
lib/component/tool/cmd.dart Normal file
View File

@@ -0,0 +1,166 @@
//蓝牙指令
// wifi列表指令
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
import 'package:easydevice/src/app/thapp.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
getWifiList(THapp tHapp) async {
try {
edm.EasyDartModule.logger.info("发送请求网络列表指令");
DailyLogUtils.writeLog("发送请求网络列表指令");
List data = [];
var wifilist = await tHapp.send("wscan scan", true, (log) {
print("[bles]${log.log}");
if (log.log.contains("SCAN RESULT OVER!")) {
final wifiList = <Map<String, dynamic>>[];
final items = log.log.split('[wifi]: SCAN RESULT ITEM:');
final reg =
RegExp(r'SSID=([^\t\r\n]+)\s+RSSI=(-?\d+)\s*,\s*auth\s*=\s*(\d+)');
for (var item in items) {
final match = reg.firstMatch(item);
if (match != null) {
wifiList.add({
'ssid': match.group(1),
'rssi': int.parse(match.group(2)!),
'auth': int.parse(match.group(3)!),
});
}
}
print('解析得到 Wi-Fi 列表: $wifiList');
if (wifiList.length != 0) {
log.result = wifiList;
data = wifiList;
log.over = true;
return true;
}
}
return false;
}, 10);
return wifilist;
} catch (e) {
print(e);
}
return [];
}
getWifiStatus(THapp tHapp) async {
edm.EasyDartModule.logger.info("发送请求设备网络状态指令");
DailyLogUtils.writeLog("发送请求设备网络状态指令");
var result = await tHapp.send(
"wl show",
true,
(ss) {
var log = ss.log;
final match = RegExp(r'status=([^\s]+)').firstMatch(log);
final status = match?.group(1);
if (status != null) {
print('提取到的 status: $status');
if (status == 'connect') {
ss.result = true;
ss.over = true;
return true;
} else {
ss.result = false;
ss.over = true;
return false;
}
} else {
return false;
}
},
);
return result;
}
Future<bool> sendWifiSetting(wifiItem, String password, THapp tHapp) async {
try {
edm.EasyDartModule.logger.info("发送wifi配置指令");
DailyLogUtils.writeLog("发送wifi配置指令->");
String cmd = "vtouch save update -a -i .wifi.sta.auth=${wifiItem['auth']} "
".wifi.sta.ssid=${wifiItem['ssid']} .wifi.sta.pwd=$password";
final success = await tHapp.send(cmd, true, (log) {
if (log.log.contains("update parm is successful")) {
print("[wifi456]:" + log.log);
edm.EasyDartModule.logger.info("WiFi配置成功-》log:$log");
DailyLogUtils.writeLog("WiFi配置成功->log:$log");
log.result = true;
log.over = true;
return true;
}
return false;
}, 10);
if (!success) {
edm.EasyDartModule.logger.error("WiFi配置超时或失败");
DailyLogUtils.writeLog("WiFi配置超时或失败");
}
return success;
} catch (e) {
edm.EasyDartModule.logger.error("发送wifi配置指令异常: ${e.toString()}");
DailyLogUtils.writeLog("发送wifi配置指令异常-> ${e.toString()}");
return false;
}
}
getDeviceWifiStatus(THapp tHapp) async {
edm.EasyDartModule.logger.info("发送请求设备已配置网络状态指令");
DailyLogUtils.writeLog("发送请求设备已配置网络状态指令");
var result = await tHapp.send(
"at+system info",
true,
(ss) {
var log = ss.log;
// 匹配设备状态
final statusMatch = RegExp(r'status=([^\s]+)').firstMatch(log);
final status = statusMatch?.group(1);
if (status != null) {
print('提取到的 status: $status');
// 如果设备连接状态是 "connect",继续检测
if (status == 'connect') {
ss.result = true;
ss.over = true;
// 匹配 Wi-Fi 连接信息
final wifiInfoMatch = RegExp(
r'WIFI CONNECTED INFO:SSID=([^\s]+),RSSI=([-0-9]+),AUTH=([0-9]+),CH=([0-9]+),BSSID=([A-F0-9]+)')
.firstMatch(log);
if (wifiInfoMatch != null) {
final ssid = wifiInfoMatch.group(1);
final rssi = wifiInfoMatch.group(2);
final auth = wifiInfoMatch.group(3);
final ch = wifiInfoMatch.group(4);
final bssid = wifiInfoMatch.group(5);
// 打印并返回 Wi-Fi 信息
print(
'Wi-Fi 信息: SSID=$ssid, RSSI=$rssi, AUTH=$auth, CH=$ch, BSSID=$bssid');
// 停止监听并返回信息
ss.result = {
'ssid': ssid,
'rssi': rssi,
'auth': auth,
'ch': ch,
'bssid': bssid,
};
ss.over = true;
return ss.result;
}
}
}
// 未找到状态或Wi-Fi信息时返回 false
return false;
},
);
return result;
}

View File

@@ -2,54 +2,54 @@ import 'dart:async';
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:easydevice/src/ble_device.dart';
import 'package:easydevice/easydevice.dart';
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/person/person_controller.dart';
import 'package:vbvs_app/model/BleDeviceData.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'blueteeth_bind_controller.g.dart'; // 由json_serializable自动生成的部分
part 'blueteeth_bind_controller.g.dart';
@JsonSerializable()
class BlueteethBindModel {
int? read = 1; //是否不再提示教程 0 不再提示 1 需要提示
double? singal = -70; //扫描信号强度
int? read = 1;
double? singal = -70;
List<BleDeviceData>? devicelist = []; //蓝牙扫描到的设备数据列表
List<BleDeviceData>? betDevicelist = []; //请求的
List? blelist = []; //蓝牙扫描到的设备数据列表
List? wifiList = [];
@JsonKey(ignore: true)
List<BleDeviceData>? devicelist = [];//蓝牙扫描
@JsonKey(ignore: true)
List<BleDeviceData>? betDevicelist = [];//网络状态
@JsonKey(ignore: true)
List? blelist = [];
List bindArr = ["", "", ""];
String connectedWifiName = "";
int connectedRssi = 0;
String deviceName = "";
bool? deviceIndex0 = true;
bool? deviceIndex1 = false;
bool? deviceIndex2 = false;
BlueteethBindModel();
bool wifiPassShow = false;
String? wifiPass;
// 从JSON反序列化时的异常处理
BlueteethBindModel();
factory BlueteethBindModel.fromJson(Map<String, dynamic> json) {
try {
return _$BlueteethBindModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return BlueteethBindModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
return BlueteethBindModel();
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$BlueteethBindModelToJson(this);
}
@@ -60,30 +60,73 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
Timer? _statusTimer;
BLEDevice? currentDevice;
THapp? currentDevice;
RxInt wifiStatus = 0.obs;
RxList wifiList = [].obs;
RxMap connect_wifi = {}.obs;
RxString scanMac = "".obs;
// 安全展示 TopSlideNotification
void safeShowNotification(String msg) {
try {
final ctx = Get.context;
if (ctx != null && ctx.mounted) {
TopSlideNotification.show(
ctx,
text: msg,
textColor: themeController.currentColor.sc9,
);
} else {
print("TopSlideNotification 未显示context 不可用或未挂载");
}
} catch (e, stack) {
// print("TopSlideNotification 显示异常: $e\n$stack");
}
}
// 启动每10秒获取设备状态
void startStatusPolling() {
updateDeviceStatus().then((res) {
if (res.code == HttpStatusCodes.ok) {
updateAll();
} else {
safeShowNotification(res.msg ?? "获取设备状态异常");
EasyDartModule.logger.info("获取设备状态异常: $res");
DailyLogUtils.writeLog("获取设备状态异常: $res");
}
});
if (_statusTimer == null) {
_statusTimer = Timer.periodic(Duration(seconds: 10), (timer) {
updateDeviceStatus();
updateDeviceStatus().then((res) {
if (res.code == HttpStatusCodes.ok) {
updateAll();
} else {
safeShowNotification(res.msg ?? "获取设备状态异常");
EasyDartModule.logger.info("获取设备状态异常: $res");
DailyLogUtils.writeLog("获取设备状态异常: $res");
}
}).catchError((e, stack) {
print("updateDeviceStatus 执行异常: $e\n$stack");
safeShowNotification("设备状态请求失败");
EasyDartModule.logger.info("设备状态异常: $e");
DailyLogUtils.writeLog("设备状态异常: $e");
});
});
}
}
// 停止轮询
void stopStatusPolling() {
_statusTimer?.cancel();
_statusTimer = null;
}
// 你的已有方法
Future<void> updateDeviceStatus() async {
Future<ApiResponse> updateDeviceStatus() async {
try {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.get_bluetooth_device_status;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String queryUrl = "$serviceAddress$serviceName$serviceApi";
if (model.devicelist != null && model.devicelist!.isNotEmpty) {
final macParams = model.devicelist!
@@ -97,13 +140,16 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
}
var response = await EasyDartModule.dio.get(queryUrl);
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) return res;
if (response.data['data'] != null && response.data['data'] is List) {
List<dynamic> responseList = response.data['data'];
Map<String, BleDeviceData> deviceMap = {
for (var d in model.devicelist!)
if (d.mac != null) d.mac!: d
for (var d in model.devicelist!) if (d.mac != null) d.mac!: d
};
List<String> slaveMacsToRemove = [];
@@ -123,17 +169,26 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
}
}
}
model.devicelist!
.removeWhere((device) => slaveMacsToRemove.contains(device.mac));
model.betDevicelist = model.devicelist!;
} else {
model.betDevicelist = [];
}
print("获取设备状态成功");
updateAll();
return res;
}
} catch (e) {
print("获取设备状态异常: $e");
EasyDartModule.logger.info("获取设备状态异常: $e");
DailyLogUtils.writeLog("获取设备状态异常: $e");
return ApiResponse(code: -1, msg: "请求失败".tr);
}
return ApiResponse(code: -1, msg: "未知错误".tr);
}
Future<ApiResponse> bindDeviceAndMAC(BleDeviceData d) async {
@@ -142,7 +197,7 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String queryUrl = "$serviceAddress$serviceName$serviceApi";
var data = {
"deviceType": 1,
"mac": d.mac,
@@ -154,10 +209,55 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(apiResponse, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
MyUtils.formatResponse(res, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
if (res.code == HttpStatusCodes.ok) {
PersonController personController = Get.find();
personController.currentPersonId.value = res.data['id'];
return res;
} else {
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} catch (e) {
EasyDartModule.logger.info("蓝牙绑定.绑定异常: $e");
DailyLogUtils.writeLog("蓝牙绑定.绑定异常: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr);
}
@override
void onClose() {
stopStatusPolling();
super.onClose();
}
bindDevice(Map<String, dynamic> map) {}
Future<ApiResponse> bindDeviceByScan(String mac) async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "蓝牙绑定.绑定失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "$serviceAddress$serviceName$serviceApi";
var data = {
"deviceType": 1,
"mac": mac,
};
var response =
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
if (res.code == HttpStatusCodes.ok) {
return res;
}
apiResponse.msg = res.msg ?? apiResponse.msg;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
@@ -166,14 +266,6 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
EasyDartModule.logger.info("蓝牙绑定.绑定异常: $e");
DailyLogUtils.writeLog("蓝牙绑定.绑定异常: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
return ApiResponse(code: -1, msg: "未知错误".tr);
}
@override
void onClose() {
stopStatusPolling(); // 控制器销毁时停止轮询
super.onClose();
}
bindDevice(Map<String, dynamic> map) {}
}

View File

@@ -7,9 +7,30 @@ part of 'blueteeth_bind_controller.dart';
// **************************************************************************
BlueteethBindModel _$BlueteethBindModelFromJson(Map<String, dynamic> json) =>
BlueteethBindModel()..read = (json['read'] as num).toInt();
BlueteethBindModel()
..read = (json['read'] as num?)?.toInt()
..singal = (json['singal'] as num?)?.toDouble()
..bindArr = json['bindArr'] as List<dynamic>
..connectedWifiName = json['connectedWifiName'] as String
..connectedRssi = (json['connectedRssi'] as num).toInt()
..deviceName = json['deviceName'] as String
..deviceIndex0 = json['deviceIndex0'] as bool?
..deviceIndex1 = json['deviceIndex1'] as bool?
..deviceIndex2 = json['deviceIndex2'] as bool?
..wifiPassShow = json['wifiPassShow'] as bool
..wifiPass = json['wifiPass'] as String?;
Map<String, dynamic> _$BlueteethBindModelToJson(BlueteethBindModel instance) =>
<String, dynamic>{
'read': instance.read,
'singal': instance.singal,
'bindArr': instance.bindArr,
'connectedWifiName': instance.connectedWifiName,
'connectedRssi': instance.connectedRssi,
'deviceName': instance.deviceName,
'deviceIndex0': instance.deviceIndex0,
'deviceIndex1': instance.deviceIndex1,
'deviceIndex2': instance.deviceIndex2,
'wifiPassShow': instance.wifiPassShow,
'wifiPass': instance.wifiPass,
};

View File

@@ -0,0 +1,256 @@
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'body_device_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class BodyDeviceModel {
int? type = 1; //设备类型 1:我的e护 2.云关爱
BodyDeviceModel();
// 从JSON反序列化时的异常处理
factory BodyDeviceModel.fromJson(Map<String, dynamic> json) {
try {
return _$BodyDeviceModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return BodyDeviceModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$BodyDeviceModelToJson(this);
}
class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
BodyDeviceController() {
attr = GetModel(BodyDeviceModel()).obs;
}
RxInt bindDeviceNum = 0.obs;
RxList deviceList = [].obs;
RxMap<String, List<dynamic>> sleepReportData = <String, List<dynamic>>{}.obs;
RxString keyWord = "".obs;
Future<ApiResponse> getDeviceNum() async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_list;
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?bindNum=1";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "设备.设备列表请求成功".tr, "设备.设备列表请求失败".tr);
if (res.code == HttpStatusCodes.ok) {
bindDeviceNum.value = res.total!;
updateAll();
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("设备请求列表: $e");
DailyLogUtils.writeLog("设备请求列表: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
Future<ApiResponse> getDeviceList({String? key}) async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备.设备列表请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_list;
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?bindType=${model.type}${key != null ? '&key=$key' : ''}";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "设备.设备列表请求成功".tr, "设备.设备列表请求失败".tr);
if (res.code == HttpStatusCodes.ok) {
// bindDeviceNum.value = res.total!;
deviceList.value = res.data!;
updateAll();
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("设备请求列表: $e");
DailyLogUtils.writeLog("设备请求列表: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
Future<ApiResponse> deleteDevice(Map<String, dynamic> device) async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
final data = {
"mac": device['mac'],
};
var response =
await EasyDartModule.dio.delete(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
if (res.code == HttpStatusCodes.ok) {
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("解绑设备: $e");
DailyLogUtils.writeLog("解绑设备: $e");
} finally {
EasyDartModule.logger.info("用户操作:解绑设备");
DailyLogUtils.writeLog("用户操作:解绑设备");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
Future<ApiResponse> getSleepReport() async {
try {
sleepReportData.value = {};
ApiResponse<Map<String, List<dynamic>>> apiResponse = ApiResponse(
code: -1,
msg: "请求失败".tr,
);
if (deviceList.value.isEmpty) {
return ApiResponse(
code: HttpStatusCodes.ok,
msg: "请求成功".tr,
);
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.sleep_report;
for (var device in deviceList.value) {
String mac = device['mac'] ?? "";
if (mac.isEmpty) continue;
sleepReportData[mac] = []; // 初始化当前设备的数据列表
String queryUrl =
"$serviceAddress$serviceName$serviceApi?mac=$mac&time=${DateTime.now().millisecondsSinceEpoch}";
try {
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData = response.data is String
? jsonDecode(response.data)
: response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
if (res.code == HttpStatusCodes.ok && res.data != null) {
// 确保数据是一个列表
if (res.data is List) {
sleepReportData[mac] = List.from(res.data);
} else {
sleepReportData[mac] = [res.data];
}
}
}
} catch (e) {
EasyDartModule.logger.warning("请求设备 $mac 的睡眠数据失败: $e");
}
}
if (sleepReportData.value.isNotEmpty) {
// 遍历 Map 中的每一个键值对
sleepReportData.value.forEach((key, report) {
// 确保 report 列表不为空
if (report.isNotEmpty) {
// 获取该列表的最后一个元素
var lastElement = report.last;
// 给最后一个元素添加 selected 属性
lastElement['selected'] = true; // 假设每个元素是一个 Map 类型
}
});
}
updateAll();
return ApiResponse(
code: HttpStatusCodes.ok,
msg: "请求成功".tr,
data: sleepReportData,
);
} catch (e) {
EasyDartModule.logger.info("设备请求列表异常: $e");
DailyLogUtils.writeLog("设备请求列表异常: $e");
return ApiResponse(code: -1, msg: "未知错误".tr, data: {});
}
}
updateDeviceShow(device) async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "操作失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_show;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {
"id": device['_id'],
"show": !device['show'],
};
var response =
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
if (res.code == HttpStatusCodes.ok) {
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("更新显示异常: $e");
DailyLogUtils.writeLog("更新显示异常: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
}

View File

@@ -0,0 +1,15 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'body_device_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BodyDeviceModel _$BodyDeviceModelFromJson(Map<String, dynamic> json) =>
BodyDeviceModel()..type = (json['type'] as num?)?.toInt();
Map<String, dynamic> _$BodyDeviceModelToJson(BodyDeviceModel instance) =>
<String, dynamic>{
'type': instance.type,
};

View File

@@ -0,0 +1,120 @@
import 'dart:async';
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'device_share_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class DeviceShareModel {
String? _id; // 设备类型
String? name; // 设备类型
int? type; // 设备类型
String? image; // 设备类型
DeviceShareModel();
// 从JSON反序列化时的异常处理
factory DeviceShareModel.fromJson(Map<String, dynamic> json) {
try {
return _$DeviceShareModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return DeviceShareModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$DeviceShareModelToJson(this);
}
class DeviceShareController extends GetControllerEx<DeviceShareModel> {
DeviceShareController() {
attr = GetModel(DeviceShareModel()).obs;
}
RxList deviceTypeList = [].obs;
RxString account = "".obs;
RxString msg = "".obs;
RxInt code = 0.obs;
Future<ApiResponse> getDeviceType() async {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备类型.请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_type;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = apiResponse.msg;
}
} else {
deviceTypeList.value = res.data;
}
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
Future<ApiResponse> shareDevice(String mac) async {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
EasyDartModule.logger.info("分享设备");
DailyLogUtils.writeLog("分享设备");
try {
if (account.value == null || account.value.isEmpty) {
apiResponse.msg = "请输入手机号或者邮箱".tr;
return apiResponse;
}
if (!MyUtils.isValidPhoneNumber(account.value) &&
!MyUtils.isValidEmail(account.value)) {
apiResponse.msg = '请输入正确的手机号或者邮箱'.tr;
return apiResponse;
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_share;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {"type": 1, "userName": account.value, "mac": mac};
var response =
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = apiResponse.msg;
}
} else {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = "操作成功".tr;
}
}
msg.value = res.msg!;
code.value = res.code!;
updateAll();
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} catch (e) {
EasyDartModule.logger.info("分享设备失败:${e.toString()}");
DailyLogUtils.writeLog("分享设备失败:${e.toString()}");
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
}

View File

@@ -0,0 +1,20 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_share_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceShareModel _$DeviceShareModelFromJson(Map<String, dynamic> json) =>
DeviceShareModel()
..name = json['name'] as String?
..type = (json['type'] as num?)?.toInt()
..image = json['image'] as String?;
Map<String, dynamic> _$DeviceShareModelToJson(DeviceShareModel instance) =>
<String, dynamic>{
'name': instance.name,
'type': instance.type,
'image': instance.image,
};

View File

@@ -0,0 +1,65 @@
import 'dart:async';
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'device_type_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class DeviceTypeModel {
String? _id; // 设备类型
String? name; // 设备类型
int? type; // 设备类型
String? image; // 设备类型
DeviceTypeModel();
// 从JSON反序列化时的异常处理
factory DeviceTypeModel.fromJson(Map<String, dynamic> json) {
try {
return _$DeviceTypeModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return DeviceTypeModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$DeviceTypeModelToJson(this);
}
class DeviceTypeController extends GetControllerEx<DeviceTypeModel> {
DeviceTypeController() {
attr = GetModel(DeviceTypeModel()).obs;
}
RxList deviceTypeList = [].obs;
Future<ApiResponse> getDeviceType() async {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备类型.请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_type;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = apiResponse.msg;
}
} else {
deviceTypeList.value = res.data;
}
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
}

View File

@@ -0,0 +1,20 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_type_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceTypeModel _$DeviceTypeModelFromJson(Map<String, dynamic> json) =>
DeviceTypeModel()
..name = json['name'] as String?
..type = (json['type'] as num?)?.toInt()
..image = json['image'] as String?;
Map<String, dynamic> _$DeviceTypeModelToJson(DeviceTypeModel instance) =>
<String, dynamic>{
'name': instance.name,
'type': instance.type,
'image': instance.image,
};

View File

@@ -0,0 +1,50 @@
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
part 'home_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class HomeModel {
int? type = 1; //我的e护 2.云关爱
HomeModel();
// 从JSON反序列化时的异常处理
factory HomeModel.fromJson(Map<String, dynamic> json) {
try {
return _$HomeModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return HomeModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$HomeModelToJson(this);
}
class HomeController extends GetControllerEx<HomeModel> {
UserInfoController userInfoController = Get.find();
ThemeController themeController = Get.find();
BodyDeviceController deviceController = Get.find();
@override
void onInit() {
super.onInit();
}
HomeController() {
attr = GetModel(HomeModel()).obs;
}
RxInt sleepNum = 0.obs;
getSleepReport() {
sleepNum.value = 5;
updateAll();
}
}

View File

@@ -0,0 +1,14 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'home_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
HomeModel _$HomeModelFromJson(Map<String, dynamic> json) =>
HomeModel()..type = (json['type'] as num?)?.toInt();
Map<String, dynamic> _$HomeModelToJson(HomeModel instance) => <String, dynamic>{
'type': instance.type,
};

View File

@@ -12,6 +12,7 @@ import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/model/user_data.dart';
part 'login_controller.g.dart';
@JsonSerializable()
@@ -84,10 +85,12 @@ class LoginController extends GetControllerEx<LoginModel> {
if (res.code == HttpStatusCodes.ok) {
UserInfoController userInfoController = Get.find();
userInfoController.model.login = 1;
userInfoController.model.user = UserModel.fromJson(res.data);
String token = response.headers['token']!.first;
EasyDartModule.dio.token = token;
final box = GetStorage();
box.write('token', userInfoController.model.token); // 存储 token
box.write('token', token); // 存储 token
box.write('user', userInfoController.model.user!.toJson()); // 存储用户信息
}
return res;
} else {
@@ -97,43 +100,48 @@ class LoginController extends GetControllerEx<LoginModel> {
Future<ApiResponse> getCode(BuildContext context) async {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "其他手机登录页.发送失败".tr);
if (model.register_agree == null || model.register_agree != true) {
apiResponse.msg = "登录页.未同意协议".tr;
return apiResponse;
}
if (model.phone == null || model.phone!.isEmpty) {
apiResponse.msg = "其他手机登录页.请输入手机号".tr;
return apiResponse;
}
if (!MyUtils.isValidPhoneNumber(model.phone!) &&
!MyUtils.isValidEmail(model.phone!)) {
apiResponse.msg = '其他手机登录页.不正确手机号'.tr;
return apiResponse;
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.send_code;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {
"userName": model.phone,
};
var response =
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = apiResponse.msg;
}
} else {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = "其他手机登录页.发送成功".tr;
}
try {
if (model.register_agree == null || model.register_agree != true) {
apiResponse.msg = "登录页.未同意协议".tr;
return apiResponse;
}
return res;
} else {
if (model.phone == null || model.phone!.isEmpty) {
apiResponse.msg = "其他手机登录页.请输入手机号".tr;
return apiResponse;
}
if (!MyUtils.isValidPhoneNumber(model.phone!) &&
!MyUtils.isValidEmail(model.phone!)) {
apiResponse.msg = '其他手机登录页.不正确手机号'.tr;
return apiResponse;
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.send_code;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var data = {
"userName": model.phone,
};
var response =
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
if (res.code != HttpStatusCodes.ok) {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = apiResponse.msg;
}
} else {
if (res.msg == null || res.msg!.isEmpty) {
res.msg = "其他手机登录页.发送成功".tr;
}
}
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} catch (e) {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}

View File

@@ -16,7 +16,8 @@ LoginModel _$LoginModelFromJson(Map<String, dynamic> json) => LoginModel()
..showPd = json['showPd'] as bool?
..forceLogin = (json['forceLogin'] as num?)?.toInt()
..isIos = json['isIos'] as bool?
..isWeChatNotInstalled = json['isWeChatNotInstalled'] as bool?;
..isWeChatNotInstalled = json['isWeChatNotInstalled'] as bool?
..register_agree = json['register_agree'] as bool?;
Map<String, dynamic> _$LoginModelToJson(LoginModel instance) =>
<String, dynamic>{
@@ -30,4 +31,5 @@ Map<String, dynamic> _$LoginModelToJson(LoginModel instance) =>
'forceLogin': instance.forceLogin,
'isIos': instance.isIos,
'isWeChatNotInstalled': instance.isWeChatNotInstalled,
'register_agree': instance.register_agree,
};

View File

@@ -0,0 +1,78 @@
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'message_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class MessageModel {
int? type = 1; //设备类型 1:体征消息 2.系统消息
MessageModel();
// 从JSON反序列化时的异常处理
factory MessageModel.fromJson(Map<String, dynamic> json) {
try {
return _$MessageModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return MessageModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$MessageModelToJson(this);
}
class MessageController extends GetControllerEx<MessageModel> {
MessageController() {
attr = GetModel(MessageModel()).obs;
}
RxList msssageList = [].obs;
Future<ApiResponse> getMessageList({String? key}) async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.message_list;
String messageType = "app_system";
if (model.type == 1) {
messageType = "app_body";
} else {
messageType = "app_system";
}
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${messageType}'}";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
if (res.code == HttpStatusCodes.ok) {
updateAll();
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("设备请求列表: $e");
DailyLogUtils.writeLog("设备请求列表: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
}

View File

@@ -0,0 +1,15 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'message_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MessageModel _$MessageModelFromJson(Map<String, dynamic> json) =>
MessageModel()..type = (json['type'] as num?)?.toInt();
Map<String, dynamic> _$MessageModelToJson(MessageModel instance) =>
<String, dynamic>{
'type': instance.type,
};

View File

@@ -1,14 +1,20 @@
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'person_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class PersonModel {
int read = 1;
DateTime? birthday;
double? weight;
int? read = 1;
// String? name;
PersonModel();
@@ -30,5 +36,152 @@ class PersonModel {
class PersonController extends GetControllerEx<PersonModel> {
PersonController() {
attr = GetModel(PersonModel()).obs;
}
}
}
RxList selectedDiseaseIds = [].obs;
// RxList diseaseList = [
// {'id': 1, 'name': '高血压'},
// {'id': 2, 'name': '糖尿病'},
// {'id': 3, 'name': '冠心病'},
// {'id': 4, 'name': '哮喘'},
// {'id': 5, 'name': '脑卒中'},
// {'id': 6, 'name': '慢性肾病'},
// {'id': 7, 'name': '慢阻肺'},
// {'id': 8, 'name': '类风湿关节炎'},
// {'id': 9, 'name': '类风湿关节炎类风湿关节炎'},
// {'id': 10, 'name': '类风湿关节炎类风湿关节炎类风湿关节炎'},
// ].obs;
RxString currentPersonId = "".obs;
RxString name = "".obs;
RxInt gender = 1.obs;
RxString birthday = "".obs;
RxInt weight = 65.obs;
DateTime? dateTime; //选择时间
RxList diseaseList = [].obs;
//保存人员资料
// void savePersonData() {
// print("id->" + currentPersonId.value);
// print("name->" + name.value);
// print("gender->${gender.value}");
// print("生日->${birthday.value}");
// print("体重->${weight.value}");
// print("慢病->${selectedDiseaseIds.value}");
// }
Future<ApiResponse> savePersonData() async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "蓝牙绑定.绑定失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.person_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
if (name.value.isEmpty) {
apiResponse.msg = "请输入姓名".tr;
return apiResponse;
}
if (birthday.value.isEmpty) {
apiResponse.msg = "请选择生日".tr;
return apiResponse;
}
if (weight.value == 0) {
apiResponse.msg = "请输入体重".tr;
return apiResponse;
}
var data = {
"id": currentPersonId.value,
"name": name.value,
"gender": gender.value,
"birthday": birthday.value,
"weight": weight.value,
"disease": selectedDiseaseIds.value,
};
var response =
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
if (res.code == HttpStatusCodes.ok) {
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("保存人员资料异常: $e");
DailyLogUtils.writeLog("保存人员资料异常: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
Future<ApiResponse> updatePersonName(person, deviceId) async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.person_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
if (name.value.isEmpty) {
apiResponse.msg = "请输入姓名".tr;
return apiResponse;
}
person['name'] = name.value;
person['id'] = deviceId;
var response =
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(person));
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "操作成功".tr, "操作失败".tr);
if (res.code == HttpStatusCodes.ok) {
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("保存人员资料异常: $e");
DailyLogUtils.writeLog("保存人员资料异常: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
Future<ApiResponse> getDiseaseData() async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.disease_list;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
if (res.code == HttpStatusCodes.ok) {
// bindDeviceNum.value = res.total!;
diseaseList.value = res.data!;
updateAll();
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.info("疾病请求列表: $e");
DailyLogUtils.writeLog("疾病请求列表: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
}

View File

@@ -6,14 +6,10 @@ part of 'person_controller.dart';
// JsonSerializableGenerator
// **************************************************************************
PersonModel _$PersonModelFromJson(Map<String, dynamic> json) => PersonModel()
..read = (json['read'] as num).toInt()
..birthday = json['birthday'] == null
? null
: DateTime.parse(json['birthday'] as String);
PersonModel _$PersonModelFromJson(Map<String, dynamic> json) =>
PersonModel()..read = (json['read'] as num?)?.toInt();
Map<String, dynamic> _$PersonModelToJson(PersonModel instance) =>
<String, dynamic>{
'read': instance.read,
'birthday': instance.birthday?.toIso8601String(),
};

View File

@@ -1,5 +1,17 @@
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:dio/dio.dart' as dio;
import 'package:ef/ef.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:get_storage/get_storage.dart';
import 'package:img_picker/img_picker.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/home/home_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/model/user_data.dart';
part 'user_info_controller.g.dart';
@@ -24,11 +36,12 @@ class UserInfoModel {
String? img_bucket = 'user';
int? login = 0; //0未登录 1 登录
int? deviceBindNum = 0; //绑定设备数量
int? loginPhone = 0;//0 本机号码 1其他手机号
int? loginPhone = 0; //0 本机号码 1其他手机号
// String? nickname; //修改昵称
// String? avatar; //修改头像地址
UserInfoModel();
static UserInfoModel fromJson(Map<String, dynamic> json) =>
@@ -41,4 +54,146 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
UserInfoController() {
attr = GetModel(UserInfoModel()).obs;
}
Future<ApiResponse> uploadImg() async {
EasyDartModule.logger.info("请求上传图片");
DailyLogUtils.writeLog("请求上传图片");
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.头像上传失败".tr);
if (image != null) {
int fileSize = await image.length(); // 获取图片大小,单位为字节
if (fileSize > 1048576) {
apiResponse.msg = "我的.头像限制".tr;
return apiResponse;
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.upload_file;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var formData = dio.FormData.fromMap({
"type": 1,
"file": await dio.MultipartFile.fromFile(
image.path, // 确保 image 是 File 类型
filename: image.path.split('/').last,
),
});
var response = await EasyDartModule.dio.post(queryUrl, data: formData);
if (response != null) {
var responseData = response.data is String
? jsonDecode(response.data)
: response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(apiResponse, "我的.上传成功".tr, "我的.头像上传失败".tr);
model.user!.tmpHead = res.data['path'];
updateAll();
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} else {
apiResponse.msg = "我的.未选择图片".tr;
return apiResponse;
}
} catch (e) {
EasyDartModule.logger.error("上传图片失败->$e");
DailyLogUtils.writeError("上传图片失败->$e");
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
//更新用户信息
Future<ApiResponse> updateData() async {
EasyDartModule.logger.info("更新用户资料");
DailyLogUtils.writeLog("更新用户资料");
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.保存失败".tr);
UserModel user = model.user!;
if (user.tmpNickName == null || user.tmpNickName!.isEmpty) {
apiResponse.msg = "我的.昵称为空".tr;
return apiResponse;
}
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
final data = {
"nickName": user.tmpNickName,
if (user.tmpHead != null && user.tmpHead!.isNotEmpty)
"avatar": user.tmpHead,
};
var response =
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
if (apiResponse != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "我的.保存成功".tr, "我的.保存失败".tr);
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} catch (e) {
EasyDartModule.logger.info("更新用户资料失败->$e");
DailyLogUtils.writeLog("更新用户资料失败->$e");
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
//查询用户信息
Future<ApiResponse> getUserInfo() async {
EasyDartModule.logger.info("查询用户资料");
DailyLogUtils.writeLog("查询用户资料");
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.查询失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(apiResponse, "我的.保存成功".tr, "我的.保存失败".tr);
if (res.code == HttpStatusCodes.ok) {
UserInfoController userInfoController = Get.find();
userInfoController.model.user = UserModel.fromJson(res.data);
final box = GetStorage();
box.write('user', userInfoController.model.user!.toJson()); // 存储用户信息
userInfoController.updateAll();
}
return apiResponse;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} catch (e) {
EasyDartModule.logger.info("更新用户资料失败->$e");
DailyLogUtils.writeLog("更新用户资料失败->$e");
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
ApiResponse logOut() {
ApiResponse apiResponse = ApiResponse(code: 1, msg: "设置页.退出成功".tr);
EasyDartModule.logger.info("退出登录");
DailyLogUtils.writeLog("退出登录");
model.login = 0;
EasyDartModule.dio.token = null;
final box = GetStorage();
box.remove("user");
box.remove("token");
BodyDeviceController bodyDeviceController = Get.find();
bodyDeviceController.bindDeviceNum.value = 0;
HomeController homeController = Get.find();
homeController.sleepNum.value = 0;
bodyDeviceController.sleepReportData.value = {};
return apiResponse;
}
}

View File

@@ -19,7 +19,9 @@ UserInfoModel _$UserInfoModelFromJson(Map<String, dynamic> json) =>
..deviceModel = json['deviceModel'] as String?
..appVersion = json['appVersion'] as String?
..img_bucket = json['img_bucket'] as String?
..login = (json['login'] as num?)?.toInt();
..login = (json['login'] as num?)?.toInt()
..deviceBindNum = (json['deviceBindNum'] as num?)?.toInt()
..loginPhone = (json['loginPhone'] as num?)?.toInt();
Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
<String, dynamic>{
@@ -33,4 +35,6 @@ Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
'appVersion': instance.appVersion,
'img_bucket': instance.img_bucket,
'login': instance.login,
'deviceBindNum': instance.deviceBindNum,
'loginPhone': instance.loginPhone,
};

9
lib/enum/BindType.dart Normal file
View File

@@ -0,0 +1,9 @@
enum BindType {
active(1, '主动绑定'),
share(2, '分享绑定');
final int code;
final String description;
const BindType(this.code, this.description);
}

View File

@@ -0,0 +1,9 @@
enum LoginStatus {
LOGIN(1, '已登录'),
NOT_LOGIN(2, '未登录');
final int code;
final String description;
const LoginStatus(this.code, this.description);
}

View File

@@ -6,34 +6,39 @@ import 'package:EasyDartModule/base/websocket/WebSocket.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get_storage/get_storage.dart';
import 'package:localstorage/localstorage.dart';
import 'package:syncfusion_localizations/syncfusion_localizations.dart';
import 'package:vbvs_app/common/color/ServiceConstant.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/common/util/FitTool.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/device/device_share_controller.dart';
import 'package:vbvs_app/controller/device/device_type_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/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart';
import 'package:vbvs_app/controller/message/message_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/time/countdown_controller.dart';
import 'package:vbvs_app/language/AppLanguage.dart';
import 'package:vbvs_app/model/CustomThemeColor.dart';
import 'package:vbvs_app/model/user_data.dart';
import 'controller/user_info_controller.dart';
import 'routers/routers.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:syncfusion_localizations/syncfusion_localizations.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await AppLanguage().loadLanguage("zh_CN");
WidgetsFlutterBinding.ensureInitialized();
// ApiService.init();
// await GetStorage.init();
await GetStorage.init();
// 初始化登录
await initLocalStorage();
initEasyDartModule();
@@ -54,37 +59,37 @@ Future<void> main() async {
}
void initEasyDartModule() {
//初始化
EasyDartModule.init(
loggerConfig:
LoggerConfig(host: ServiceConstant.logService, serviceName: "web"),
webSocketConfig:
WebSocketConfig(ServiceConstant.webSocketService, (data) {
// 接收到服务消息
var json = jsonDecode(data);
if (json["path"] != null) {
var call = CommonVariables.callMap[json["path"]];
if (call != null) {
try {
call(json["data"]);
} catch (e) {
print(e);
try {
EasyDartModule.init(
loggerConfig:
LoggerConfig(host: ServiceConstant.logService, serviceName: "web"),
webSocketConfig:
WebSocketConfig(ServiceConstant.webSocketService, (data) {
// 接收到服务消息
var json = jsonDecode(data);
if (json["path"] != null) {
var call = CommonVariables.callMap[json["path"]];
if (call != null) {
try {
call(json["data"]);
} catch (e) {
print(e);
}
} else {
print("未找到当前路径: ${json["path"]} 回调函数");
}
} else {
print("未找到当前路径: ${json["path"]} 回调函数");
}
}
// print(data);
}, onOpen: () {
//连接建立完毕
// EasyDartModule.websocket
// .sendData(jsonEncode({"path": "/aa/bb", "type": 1}));
}));
EasyDartModule.dio.token = localStorage.getItem('token');
// document.onContextMenu.listen((event) {
// event.preventDefault();
// });
EasyDartModule.dio.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI2ODAxY2JmMzY5YjJhODQ5MWQwMDAwMDAiLCJ0aWQiOiI2N2Y1ZDk2ZTI2ZWYzMTA0NjMwMDAwMDAiLCJsZXZlbCI6NSwiaWF0IjoxNzQ0OTQ4MjExfQ._XXG3WzEHuOzWdj01NXJxLJpxe3SU20XQqShBZUHCUU";
// print(data);
}, onOpen: () {
// 连接建立完毕
// EasyDartModule.websocket
// .sendData(jsonEncode({"path": "/aa/bb", "type": 1}));
print("object");
}));
} catch (e) {
print(e);
}
//初始化
}
initLog() {}
@@ -103,12 +108,16 @@ Future<void> initLogin() async {
final box = GetStorage();
UserInfoController userInfoController = Get.find();
String? token = box.read('token');
// print('Token: $token');
Map<String, dynamic>? userMap = box.read('user');
if (userMap != null) {
UserModel user = UserModel.fromJson(userMap);
userInfoController.model.user = user;
try {
Map<String, dynamic>? userMap = box.read('user');
if (userMap != null) {
UserModel user = UserModel.fromJson(userMap);
userInfoController.model.user = user;
}
} catch (e) {
print(e);
}
if (token != null) {
userInfoController.model.login = 1;
// 根据token去请求
@@ -199,13 +208,18 @@ class MyApp extends StatelessWidget {
initialRoute: "/mianPageBottomChange",
onGenerateRoute: onGenerateRoute,
initialBinding: BindingsBuilder(() => [
Get.lazyPut(() => UserInfoController()),
// Get.lazyPut(() => UserInfoController()),
Get.put(GlobalController()),
Get.lazyPut(() => MainPageController()),
Get.lazyPut(() => BlueteethBindController()),
Get.lazyPut(() => PersonController()),
Get.lazyPut(() => CountdownController()),
Get.lazyPut(() => LoginController()),
Get.lazyPut(() => DeviceTypeController()),
Get.lazyPut(() => BodyDeviceController()),
Get.lazyPut(() => HomeController()),
Get.lazyPut(() => DeviceShareController()),
Get.lazyPut(() => MessageController()),
]));
});
}

View File

@@ -8,7 +8,7 @@ class BleDeviceData {
final int flag; // 设备属性
final int version; // 软件版本
final int qsn; // 广播帧序列号高16位
bool? bind = true; // 设备状态
bool? bind = false; // 设备状态
String? name; //设备名称
int? rssi;
String? mac; //mac地址

View File

@@ -0,0 +1,16 @@
import 'package:json_annotation/json_annotation.dart';
part 'WebSocketMessage.g.dart';
@JsonSerializable()
class WebSocketMessage {
String path;
int? type;
dynamic data;
WebSocketMessage({required this.path, this.type, this.data});
static WebSocketMessage fromJson(Map<String, dynamic> json) =>
_$WebSocketMessageFromJson(json);
Map<String, dynamic> toJson() => _$WebSocketMessageToJson(this);
}

View File

@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'WebSocketMessage.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
WebSocketMessage _$WebSocketMessageFromJson(Map<String, dynamic> json) =>
WebSocketMessage(
path: json['path'] as String,
type: (json['type'] as num?)?.toInt(),
data: json['data'],
);
Map<String, dynamic> _$WebSocketMessageToJson(WebSocketMessage instance) =>
<String, dynamic>{
'path': instance.path,
'type': instance.type,
'data': instance.data,
};

View File

@@ -1,17 +1,17 @@
class ApiResponse<T> {
int? code;
T? data;
String? msg;
int? total;
ApiResponse({required this.code, this.data, this.msg});
ApiResponse({required this.code, this.data, this.msg, this.total});
factory ApiResponse.fromJson(
Map<String, dynamic> json, T Function(Object?) fromJsonT) {
return ApiResponse<T>(
code: json['code'] as int,
data: json['data'] != null ? fromJsonT(json['data']) : null,
msg: json['msg'] as String?,
total: json['total'] as int?,
);
}
}

View File

@@ -6,12 +6,16 @@ part 'user_data.g.dart';
class UserModel {
String? uid;
String? userName;
String? nickName;
String? tel;
String? nick_name;
String? phone;
String? exp1;
String? head;
String? avatar;
String? tmpHead;
String? tmpNickName;
int? deleted;
String? status;
int? created_at;
String? email;
UserModel();
static UserModel fromJson(Map<String, dynamic> json) =>

View File

@@ -9,20 +9,28 @@ part of 'user_data.dart';
UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel()
..uid = json['uid'] as String?
..userName = json['userName'] as String?
..nickName = json['nickName'] as String?
..tel = json['tel'] as String?
..nick_name = json['nick_name'] as String?
..phone = json['phone'] as String?
..exp1 = json['exp1'] as String?
..head = json['head'] as String?
..avatar = json['avatar'] as String?
..tmpHead = json['tmpHead'] as String?
..tmpNickName = json['tmpNickName'] as String?;
..tmpNickName = json['tmpNickName'] as String?
..deleted = (json['deleted'] as num?)?.toInt()
..status = json['status'] as String?
..created_at = (json['created_at'] as num?)?.toInt()
..email = json['email'] as String?;
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
'uid': instance.uid,
'userName': instance.userName,
'nickName': instance.nickName,
'tel': instance.tel,
'nick_name': instance.nick_name,
'phone': instance.phone,
'exp1': instance.exp1,
'head': instance.head,
'avatar': instance.avatar,
'tmpHead': instance.tmpHead,
'tmpNickName': instance.tmpNickName,
'deleted': instance.deleted,
'status': instance.status,
'created_at': instance.created_at,
'email': instance.email,
};

View File

@@ -0,0 +1,803 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/NullDataComponentWidget.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/pages/device/component/DeviceDataComponentWidget.dart';
class BodyDeviceWidget extends StatefulWidget {
const BodyDeviceWidget({super.key});
@override
State<BodyDeviceWidget> createState() => _BodyDevicePageState();
}
class _BodyDevicePageState extends State<BodyDeviceWidget> {
final ThemeController themeController = Get.find();
final BodyDeviceController bodyDeviceController = Get.find();
final GlobalKey addIconKey = GlobalKey();
OverlayEntry? _popupEntry;
void _showPopup() {
final renderBox =
addIconKey.currentContext?.findRenderObject() as RenderBox?;
if (renderBox == null) return;
final position = renderBox.localToGlobal(Offset.zero);
final size = renderBox.size;
double popupWidth = 190.rpx;
// 移除之前的弹窗
_popupEntry?.remove();
// 创建新的 OverlayEntry
_popupEntry = OverlayEntry(
builder: (context) => Stack(
children: [
// 半透明背景,点击后关闭弹窗
ModalBarrier(
dismissible: true,
color: Colors.transparent,
onDismiss: _hidePopup,
),
// 弹窗内容
Positioned(
top: position.dy + size.height + 26.rpx,
left: position.dx + size.width - popupWidth - 40.rpx,
child: Material(
color: Colors.transparent,
child: Container(
width: popupWidth,
padding: EdgeInsets.all(20.rpx),
decoration: BoxDecoration(
color: themeController.currentColor.sc17,
borderRadius: BorderRadius.circular(12.rpx),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.5),
blurRadius: 12.rpx,
spreadRadius: 2.rpx,
offset: Offset(0, 6.rpx),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
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(
padding: EdgeInsets.symmetric(vertical: 10.rpx),
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc16.withOpacity(0.1),
borderRadius: 0.rpx,
onTap: () {
_hidePopup();
Get.toNamed("/deviceType");
},
child: Container(
width: double.infinity,
child: Center(
child: Text(
'蓝牙绑定'.tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
),
),
),
),
),
SizedBox(height: 13.rpx),
],
),
),
),
),
],
),
);
// 插入新的 OverlayEntry
Overlay.of(context)!.insert(_popupEntry!);
}
void _hidePopup() {
_popupEntry?.remove();
_popupEntry = null;
}
@override
void initState() {
bodyDeviceController.keyWord.value = "";
super.initState();
bodyDeviceController.getDeviceList().then((apiResponse) {
if (apiResponse.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: apiResponse.msg!,
textColor: themeController.currentColor.sc9,
);
}
});
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, bodysize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Container(
// width: bodysize.maxWidth,
// height: bodysize.maxHeight * 1,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(
color: themeController.currentColor.sc3,
),
titleSpacing: 0,
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: returnIconButtom,
child: returnIconButtomAddCallback(() {
bodyDeviceController.getDeviceNum();
bodyDeviceController.getDeviceList();
bodyDeviceController.updateAll();
}),
),
Positioned(
right: 20.rpx,
child: ClickableContainer(
key: addIconKey,
backgroundColor: Colors.transparent,
highlightColor: themeController.currentColor.sc16,
padding: EdgeInsets.all(8.rpx),
onTap: () {
// 点击图标时,展示弹窗
if (_popupEntry == null) {
_showPopup();
} else {
_hidePopup();
}
},
child: SvgPicture.asset(
'assets/img/icon/add.svg',
width: 39.rpx,
height: 39.rpx,
color: themeController.currentColor.sc16,
),
),
),
],
),
),
actions: [],
centerTitle: false,
),
body: GestureDetector(
onTap: _hidePopup, // 点击空白处自动关闭弹窗
child: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 0, 0.rpx, 0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
child: Container(
width: double.infinity,
constraints: BoxConstraints(
minHeight: 90.rpx,
),
decoration: BoxDecoration(
color: themeController.currentColor.sc5),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 15.rpx, 30.rpx, 15.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Obx(() {
// return ClickableContainer(
// backgroundColor:
// Colors.transparent, // 或者你想设置的背景色
// highlightColor: themeController
// .currentColor.sc3, // 点击涟漪颜色
// borderRadius: 8.rpx, // 自定义圆角
// padding: EdgeInsets.all(
// 0), // 外部已经排版,这里不用加内边距
// onTap: () async {
// // 点击事件处理逻辑
// bodyDeviceController.model.type = 1;
// await bodyDeviceController
// .getDeviceList();
// bodyDeviceController.updateAll();
// },
// child: Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '体征检测设备.我的e护'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: AppConstants()
// .title_text_fontSize,
// letterSpacing: 0.0,
// color:
// bodyDeviceController
// .model
// .type ==
// 2
// ? themeController
// .currentColor
// .sc3
// : themeController
// .currentColor
// .sc2,
// ),
// ),
// SizedBox(
// width: 100.rpx,
// child: Divider(
// height: 1.rpx,
// thickness: 2.rpx,
// color: bodyDeviceController
// .model.type ==
// 2
// ? Colors.transparent
// : themeController
// .currentColor.sc2,
// ),
// ),
// ].divide(SizedBox(height: 10.rpx)),
// ),
// );
// }),
// Obx(() {
// return ClickableContainer(
// backgroundColor: Colors.transparent,
// highlightColor:
// themeController.currentColor.sc3,
// borderRadius: 8.rpx,
// padding: EdgeInsets.all(0),
// onTap: () async {
// // 这里写你的点击逻辑
// bodyDeviceController.model.type = 2;
// await bodyDeviceController
// .getDeviceList();
// bodyDeviceController.updateAll();
// },
// child: Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '体征检测设备.云关爱'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color:
// bodyDeviceController
// .model
// .type ==
// 1
// ? themeController
// .currentColor
// .sc3
// : themeController
// .currentColor
// .sc2,
// ),
// ),
// SizedBox(
// width: 100.rpx,
// child: Divider(
// height: 1.rpx,
// thickness: 2.rpx,
// color: bodyDeviceController
// .model.type ==
// 1
// ? Colors.transparent
// : themeController
// .currentColor.sc2,
// ),
// ),
// ].divide(SizedBox(height: 10.rpx)),
// ),
// );
// }),
// ].divide(SizedBox(width: 60.rpx)),
// ),
Stack(
alignment: Alignment.bottomLeft,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Obx(() {
return ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: themeController
.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
bodyDeviceController.model.type =
1;
await bodyDeviceController
.getDeviceList();
bodyDeviceController.updateAll();
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width:
160.rpx, // 固定宽度为 160.rpx
alignment:
Alignment.center, // 文字居中
child: Text(
'体征检测设备.我的e护'.tr,
style: FlutterFlowTheme.of(
context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color: bodyDeviceController
.model
.type ==
2
? themeController
.currentColor
.sc3
: themeController
.currentColor
.sc2,
),
),
),
SizedBox(height: 10.rpx),
],
),
);
}),
Obx(() {
return ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: themeController
.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
bodyDeviceController.model.type =
2;
await bodyDeviceController
.getDeviceList();
bodyDeviceController.updateAll();
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width:
160.rpx, // 固定宽度为 160.rpx
alignment:
Alignment.center, // 文字居中
child: Text(
'体征检测设备.云关爱'.tr,
style: FlutterFlowTheme.of(
context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color: bodyDeviceController
.model
.type ==
1
? themeController
.currentColor
.sc3
: themeController
.currentColor
.sc2,
),
),
),
SizedBox(height: 10.rpx),
],
),
);
}),
],
),
Obx(() {
// 横线宽度固定为 160.rpx
double lineWidth = 160.rpx;
return AnimatedPositioned(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
bottom: 0,
left: bodyDeviceController.model.type ==
1
? 0
: 160.rpx, // 第二个按钮横线从 160.rpx 开始
child: Container(
width: lineWidth, // 横线宽度固定为 160.rpx
height: 4.rpx,
decoration: BoxDecoration(
color: themeController
.currentColor.sc2,
borderRadius:
BorderRadius.circular(2.rpx),
),
),
);
}),
],
),
Container(
width:
MediaQuery.sizeOf(context).width * 0.38,
constraints: BoxConstraints(
minWidth: 285.rpx,
),
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(20.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0, 20.rpx, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Container(
height: 80.rpx,
child: Align(
alignment:
AlignmentDirectional(-1, 0),
child: TextFormField(
onChanged: (value) {
bodyDeviceController
.keyWord.value = value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(
12.rpx, 0, 0.rpx, 0),
isDense: true,
labelStyle:
FlutterFlowTheme.of(
context)
.labelMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
hintText: '体征检测设备.输入关键词'.tr,
hintStyle: FlutterFlowTheme
.of(context)
.labelMedium
.override(
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(
color:
FlutterFlowTheme.of(
context)
.error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedErrorBorder:
OutlineInputBorder(
borderSide: BorderSide(
color:
FlutterFlowTheme.of(
context)
.error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
filled: false,
fillColor:
FlutterFlowTheme.of(
context)
.secondaryBackground,
),
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
cursorColor:
FlutterFlowTheme.of(context)
.primaryText,
),
),
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(
26.rpx, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
height: 40.rpx,
child: VerticalDivider(
thickness: 2.rpx,
color: themeController
.currentColor.sc2,
),
),
// Text(
// '体征检测设备.搜索'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: AppConstants()
// .normal_text_fontSize,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc2,
// ),
// ),
ClickableContainer(
backgroundColor:
Colors.transparent,
highlightColor: themeController
.currentColor.sc5,
borderRadius: 6.rpx,
padding: EdgeInsets.zero,
onTap: () async {
await bodyDeviceController
.getDeviceList(
key:
bodyDeviceController
.keyWord
.value);
bodyDeviceController
.updateAll();
},
child: Text(
'体征检测设备.搜索'.tr,
style: FlutterFlowTheme.of(
context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
color: themeController
.currentColor.sc2,
),
),
),
].divide(SizedBox(width: 14.rpx)),
),
),
],
),
),
),
],
),
),
),
),
Obx(() {
final isEmpty =
bodyDeviceController.deviceList.value.isEmpty;
return isEmpty
? Expanded(
child: NullDataWidget(),
)
: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 26.rpx, 30.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: bodyDeviceController
.deviceList.value
.map((device) =>
DeviceDataComponentWidget(
device: device))
.toList()
.divide(SizedBox(height: 25.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,
),
),
],
),
),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
import 'package:ef/base/widget/flutterflow/FlutterFlowTheme.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class DeviceStatusInfoWidget extends StatelessWidget {
final String title; // 标题,如“在床”
final String iconAsset; // SVG 路径,如 'assets/icons/bed.svg'
final String value; // 显示内容,如“在离床”
ThemeController themeController = Get.find();
DeviceStatusInfoWidget({
super.key,
required this.title,
required this.iconAsset,
required this.value,
});
@override
Widget build(BuildContext context) {
return ClickableContainer(
backgroundColor: themeController.currentColor.sc5,
highlightColor: themeController.currentColor.sc5,
borderRadius: AppConstants().normal_container_radius,
padding: EdgeInsets.zero,
onTap: () {
print('点击了 $title 模块');
},
child: Container(
width: MediaQuery.sizeOf(context).width * 0.32,
constraints: BoxConstraints(
minWidth: 201.rpx,
minHeight: 182.rpx,
),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(20.rpx, 29.rpx, 20.rpx, 39.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SvgPicture.asset(
iconAsset,
width: 38.rpx,
height: 38.rpx,
// colorFilter: ColorFilter.mode(
// FlutterFlowTheme.of(context).primaryText,
// BlendMode.srcIn,
// ),
),
Text(
value,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 48.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
]
.divide(SizedBox(width: 18.rpx))
.addToStart(SizedBox(width: 31.rpx)),
),
Text(
title,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(height: 39.rpx)),
),
),
),
);
}
}

View File

@@ -0,0 +1,477 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/device/device_type_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class DeviceDetailPage extends StatefulWidget {
var device;
DeviceDetailPage({super.key, required this.device});
@override
State<DeviceDetailPage> createState() => _DeviceDetailPageState();
}
class _DeviceDetailPageState extends State<DeviceDetailPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
@override
void initState() {
super.initState();
}
@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(
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
// backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
titleSpacing: 0.rpx,
// leading: returnIconButtom,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
/// 居中标题
Text(
'设备详情.标题'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0.rpx,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0.rpx,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 26.rpx, 30.rpx, 0.rpx),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
50.rpx, 0.rpx, 0.rpx, 0.rpx),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.267,
height: MediaQuery.sizeOf(context).width * 0.267,
constraints: BoxConstraints(
minWidth: 200.rpx,
minHeight: 200.rpx,
),
decoration: BoxDecoration(),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.设备名称'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.MAC'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.型号'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.版本'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.网络状态'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.故障状态'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.更新状态'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'设备详情.更新时间'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc4,
),
),
),
),
]
.divide(SizedBox(height: 34.rpx))
.addToStart(SizedBox(height: 92.rpx))
.addToEnd(SizedBox(height: 97.rpx)),
),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.267,
height: MediaQuery.sizeOf(context).width * 0.267,
constraints: BoxConstraints(
minWidth: 200.rpx,
minHeight: 200.rpx,
),
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context)
.secondaryBackground,
),
// child: ClipRRect(
// borderRadius: BorderRadius.circular(8.rpx),
// child: Image.network(
// 'https://picsum.photos/seed/851/600',
// width: 200.rpx,
// height: 200.rpx,
// fit: BoxFit.cover,
// ),
// ),
child: QrImageView(
data: '1234567890',
version: QrVersions.auto,
size: 200.0.rpx,
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'A35968956',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['person']['name'] ?? '未命名'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['mac'] ?? '-'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'-',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'-',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['status']['status'] == 1 ? '在线'.tr : '离线'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['status']['failure'] == 1 ? '有故障'.tr : '无故障'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['status']['upgrade'] == 1 ? '有更新'.tr : '无更新'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
Container(
height: 50.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['update_time'] ?? '-'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.rpx,
color: themeController.currentColor.sc3,
),
),
),
),
]
.divide(SizedBox(height: 34.rpx))
.addToStart(SizedBox(height: 92.rpx))
.addToEnd(SizedBox(height: 97.rpx)),
),
].divide(SizedBox(width: 34.rpx)),
),
),
),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,505 @@
import 'dart:async';
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/device/device_type_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/WebSocketMessage.dart';
import 'package:vbvs_app/pages/device/component/DeviceStatusInfoWidget.dart';
class InstantBodyPage extends StatefulWidget {
var personInfo;
InstantBodyPage({super.key, required this.personInfo});
@override
State<InstantBodyPage> createState() => _InstantBodyPageState();
}
class _InstantBodyPageState extends State<InstantBodyPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
int maxBodyMotion = 1;
String breathState = "";
String inBed = "离床".tr;
String onlineState = "离线".tr;
Timer? _onlineTimer; // 添加 Timer 引用
int bodyMotion = 0;
int breathrate = 0;
String snores = "".tr;
int heartrate = 0;
@override
void initState() {
edm.EasyDartModule.websocket.sendData(jsonEncode(WebSocketMessage(
path: "/vsbs/web/rt/marttress",
type: 1,
data: {"mac": widget.personInfo['mac']})));
_startOnlineTimer(); // 初始化时启动定时器
super.initState();
}
@override
void dispose() {
_onlineTimer?.cancel(); // 取消定时器,防止内存泄漏
edm.EasyDartModule.websocket.sendData(
jsonEncode(WebSocketMessage(path: "/vsbs/web/rt/marttress", type: 2)));
super.dispose();
}
void _startOnlineTimer() {
_onlineTimer?.cancel(); // 取消之前的定时器
_onlineTimer = Timer.periodic(Duration(seconds: 30), (timer) {
if (mounted) {
setState(() {
onlineState = "离线".tr; // 30 秒内没有接收到数据,设置为离线
});
}
});
}
@override
Widget build(BuildContext context) {
Map device = widget.personInfo;
CommonVariables.callMap["/vsbs/web/rt/marttress"] = (data) {
inBed = data["inBed"];
// 心率 呼吸 体动 呼吸暂停
if ("离床" == inBed) {
breathState = "";
data["breathRate"] = 0;
data["heartRate"] = 0;
data["bodyMotion"] = 0;
} else {
breathState = data["breathState"];
bodyMotion = data['bodyMotion'];
breathrate = data["breathRate"];
heartrate = data['heartRate'];
snores = data['snores'];
}
if (mounted) {
setState(() {
onlineState = "在线".tr; // 接收到数据,设置为在线
});
}
_startOnlineTimer(); // 重置定时器
};
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,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
titleSpacing: 0.rpx,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
RichText(
text: TextSpan(
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
letterSpacing: 0.0,
),
children: [
TextSpan(
text: '实时体征.标题'.tr,
),
TextSpan(
text: "${onlineState}",
style: TextStyle(
color: onlineState == '在线'
? themeController.currentColor.sc2
: themeController
.currentColor.sc9, // 👈 单独设置颜色
),
),
],
),
),
Positioned(
left: 0.rpx,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0.rpx, 29.rpx, 0.rpx, 0.rpx),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 0.rpx, 30.rpx, 120.rpx),
child: ClickableContainer(
backgroundColor: themeController.currentColor.sc5,
highlightColor:
themeController.currentColor.sc5, // 或你希望的点击水波纹颜色
borderRadius: AppConstants()
.normal_container_radius, // 如果你想加圆角可以设置 eg. 12.rpx
padding: EdgeInsets.zero,
onTap: () {
print('点击了体征卡片');
},
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Text(
'实时体征.姓名'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
Text(
'实时体征.年龄'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
].divide(SizedBox(height: 34.rpx)),
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'${device['person']['name'] ?? '未命名'.tr}',
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Text(
'${MyUtils.getAgeByDate(MyUtils.formatBirthdayTime(device['person']['birthday'])) ?? '未知数据'.tr}',
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
].divide(SizedBox(height: 34.rpx)),
),
]
.divide(SizedBox(width: 33.rpx))
.addToStart(SizedBox(width: 37.rpx)),
),
]
.addToStart(SizedBox(height: 36.rpx))
.addToEnd(SizedBox(height: 36.rpx)),
),
),
Expanded(
flex: 1,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Text(
'实时体征.设备ID'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
Text(
'实时体征.体重'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc4,
),
),
].divide(SizedBox(height: 34.rpx)),
),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
// '${device['_id']??'未知数据'.tr}',
"D11250300003",
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Text(
'${device['person']['weight'] ?? '未知数据'.tr}kg',
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
].divide(SizedBox(height: 34.rpx)),
),
]
.divide(SizedBox(width: 33.rpx))
.addToStart(SizedBox(width: 37.rpx)),
),
]
.addToStart(SizedBox(height: 36.rpx))
.addToEnd(SizedBox(height: 36.rpx)),
),
),
],
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
66.rpx, 0, 66.rpx, 0),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/img/body_black.gif'), // 本地图片
fit: BoxFit.cover,
),
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
DeviceStatusInfoWidget(
title: "在离床".tr,
iconAsset: "assets/img/icon/bed_status.svg",
value: inBed,
),
DeviceStatusInfoWidget(
title: "体动".tr,
iconAsset: "assets/img/icon/bodymotion.svg",
value: "${bodyMotion}" ?? "未知数据".tr,
),
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
DeviceStatusInfoWidget(
title: "心率".tr,
iconAsset: "assets/img/icon/heart.svg",
value: "${heartrate}",
),
DeviceStatusInfoWidget(
title: "打鼾".tr,
iconAsset: "assets/img/icon/snore.svg",
value: '${snores}'.tr,
),
],
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
DeviceStatusInfoWidget(
title: "呼吸".tr,
iconAsset: "assets/img/icon/breathe.svg",
value: '${breathrate}',
),
DeviceStatusInfoWidget(
title: "呼吸暂停".tr,
iconAsset:
"assets/img/icon/breathe_pause.svg",
value: '${breathState}',
),
],
),
].divide(SizedBox(height: 49.rpx)),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 67.rpx, 0.rpx, 0.rpx),
child: Container(
height: 40.rpx,
child: Text(
bodyMotion >= maxBodyMotion ? '请保持静止'.tr : "",
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc9,
),
),
),
),
SizedBox(
height: 207.rpx,
),
ClickableContainer(
backgroundColor: Colors.transparent, // 可自定义背景色
highlightColor: Colors.white, // 点击涟漪颜色
borderRadius: 16.rpx, // 圆角大小,可按需调整
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 0.rpx, 30.rpx, 0.rpx),
onTap: () {},
child: Container(
padding: EdgeInsetsDirectional.fromSTEB(
26.rpx, 26.rpx, 26.rpx, 26.rpx),
decoration: BoxDecoration(
// color: FlutterFlowTheme.of(context)
// .primaryBackground
// .withOpacity(0.6), // 半透明背景
borderRadius: BorderRadius.circular(16.rpx),
border: Border.all(
// 设置边框颜色和宽度
color: themeController.currentColor.sc4, // 边框颜色
width: 2.rpx, // 边框宽度
),
),
child: Row(
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.sc3,
),
),
),
Expanded(
child: Text(
'实时体征.提示'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
),
].divide(SizedBox(width: 23.rpx)),
),
),
),
SizedBox(
height: 26.rpx,
),
],
),
),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,255 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:img_picker/img_picker.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class MobileScannerTestPage extends StatefulWidget {
const MobileScannerTestPage({Key? key}) : super(key: key);
@override
State<MobileScannerTestPage> createState() => _MobileScannerTestPageState();
}
class _MobileScannerTestPageState extends State<MobileScannerTestPage>
with TickerProviderStateMixin {
String? scannedText;
bool isScanning = true;
late AnimationController _controller;
late Animation<double> _animation;
late MobileScannerController _scannerController;
BlueteethBindController blueteethBindController = Get.find();
final double scanAreaSize = 480.rpx;
@override
void initState() {
super.initState();
_scannerController = MobileScannerController();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
}
@override
void dispose() {
_controller.dispose();
_scannerController.dispose();
super.dispose();
}
void _onDetect(BarcodeCapture capture) {
if (!isScanning) return;
final Barcode? barcode = capture.barcodes.first;
final String? value = barcode?.rawValue;
if (value != null) {
setState(() {
scannedText = value;
isScanning = false;
if (scannedText != null && scannedText!.isNotEmpty) {
blueteethBindController.scanMac.value = scannedText!;
showConfirmDialog(
context,
Container(),
'蓝牙绑定.确定绑定提示'.tr,
onConfirm: () async {
ApiResponse response =
await blueteethBindController.bindDeviceByScan(scannedText!);
if (response.code == HttpStatusCodes.ok) {
TopSlideNotification.show(
context,
text: "蓝牙绑定.连接成功".tr,
textColor: themeController.currentColor.sc2,
);
} else {
TopSlideNotification.show(
context,
text: response.msg ?? "蓝牙绑定.连接异常".tr,
textColor: themeController.currentColor.sc9,
);
}
},
onCancel: () {
print('用户点击了取消');
// 执行取消后的处理逻辑
},
);
}
});
Future.delayed(const Duration(seconds: 2), () {
setState(() {
isScanning = true;
});
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
titleSpacing: 0,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
Text(
'扫一扫.标题'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
centerTitle: false,
),
body: Container(
child: Column(
children: [
Expanded(
child: Stack(
children: [
MobileScanner(
controller: _scannerController,
onDetect: _onDetect,
),
Align(
alignment: Alignment.topCenter, // 使扫描框位于顶部居中
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.only(top: 219.rpx), // 向上移动扫描框
child: SizedBox(
width: scanAreaSize,
height: scanAreaSize,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
),
),
AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Positioned(
top: scanAreaSize * _animation.value,
left: 0,
right: 0,
child: Container(
height: 2,
color: themeController.currentColor.sc2,
),
);
},
),
],
),
),
),
SizedBox(height: 31.rpx),
Text(
'扫一扫.提示'.tr,
style: TextStyle(
color: themeController.currentColor.sc2,
fontSize: 26.rpx,
),
),
],
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 83.rpx),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () async {
final picker = ImagePicker();
final pickedFile =
await picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
final bytes = await pickedFile.readAsBytes();
final image = await decodeImageFromList(bytes);
}
},
child: Column(
children: [
Icon(Icons.photo,
color: themeController.currentColor.sc2,
size: 60.rpx),
SizedBox(height: 10.rpx),
Text(
'扫一扫.相册'.tr,
style: TextStyle(
color: themeController.currentColor.sc2,
fontSize: 24.rpx,
),
),
],
),
),
SizedBox(width: 80.rpx),
GestureDetector(
onTap: () {
_scannerController.toggleTorch();
},
child: Column(
children: [
Icon(Icons.flashlight_on,
color: themeController.currentColor.sc2,
size: 60.rpx),
SizedBox(height: 10.rpx),
Text(
'扫一扫.手电筒'.tr,
style: TextStyle(
color: themeController.currentColor.sc2,
fontSize: 24.rpx,
),
),
],
),
),
],
),
),
],
),
),
);
}
}

View File

@@ -200,7 +200,7 @@ class _EPageState extends State<BindDeviceSuccess> {
'assets/img/icon/share.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController.currentColor.sc3,
color: Colors.white,
),
Text(
'绑定成功.立即分享'.tr,

View File

@@ -1,7 +1,6 @@
import 'dart:async';
import 'package:ef/ef.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:flutter_svg/svg.dart';
@@ -14,19 +13,17 @@ import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/BleDeviceData.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
import 'package:vbvs_app/pages/device_bind/componnet/SingleBlueteethDeviceCompoentWidget.dart';
import 'package:vbvs_app/common/util/Ble.dart' as ble;
class BlueteethDevicePage extends StatefulWidget {
int tid = -1;
BlueteethDevicePage({super.key, this.tid = -1});
@override
State<BlueteethDevicePage> createState() => _EPageState();
State<BlueteethDevicePage> createState() => _BlueteethDevicePageState();
}
class _EPageState extends State<BlueteethDevicePage> {
class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
@@ -49,6 +46,8 @@ class _EPageState extends State<BlueteethDevicePage> {
@override
void initState() {
super.initState();
blueteethBindController.model.devicelist = [];
blueteethBindController.model.betDevicelist = [];
flutterBlue = FlutterBluePlus(); // 初始化flutterBlue实例
_checkBluetoothPermission(); // 检查蓝牙权限
Get.find<BlueteethBindController>().startStatusPolling();
@@ -114,6 +113,7 @@ class _EPageState extends State<BlueteethDevicePage> {
// 开始扫描蓝牙设备
void _startScanning() async {
if (!mounted) return;
var bluetoothState = await FlutterBluePlus.isOn;
if (!bluetoothState && !_isDialogShowing) {
_isDialogShowing = true;
@@ -128,8 +128,9 @@ class _EPageState extends State<BlueteethDevicePage> {
});
await FlutterBluePlus.startScan(timeout: Duration(seconds: 10));
// await FlutterBluePlus.startScan(timeout: Duration(minutes: 30));
FlutterBluePlus.scanResults.listen((results) {
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
final signalThreshold = blueteethBindController.model.singal!;
final filteredResults = results
.where((r) =>
@@ -149,6 +150,9 @@ class _EPageState extends State<BlueteethDevicePage> {
deviceData.rssi = r.rssi;
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
parsedDeviceList.add(deviceData);
if (deviceData.mac!.toLowerCase() == 'b43a45c3dfa0') {
print('匹配设备数据: ${deviceData.mac}-->sn:${deviceData.sn}');
}
} catch (e) {
print("设备数据解析失败: $e");
}
@@ -188,13 +192,15 @@ class _EPageState extends State<BlueteethDevicePage> {
// 等待扫描完成
await Future.delayed(Duration(seconds: 10));
// await Future.delayed(Duration(minutes: 30));
await FlutterBluePlus.stopScan();
setState(() {
isScanning = false;
});
print("扫描完成");
if (mounted) {
setState(() {
isScanning = false;
});
}
// print("扫描完成");
}
}
@@ -210,10 +216,13 @@ class _EPageState extends State<BlueteethDevicePage> {
// 停止扫描
void _stopScanning() {
if (isScanning) {
FlutterBluePlus.stopScan(); // 停止扫描
setState(() {
isScanning = false; // 更新扫描状态
});
FlutterBluePlus.stopScan();
_scanSubscription?.cancel(); // 取消订阅
if (mounted) {
setState(() {
isScanning = false;
});
}
}
}
@@ -222,396 +231,15 @@ class _EPageState extends State<BlueteethDevicePage> {
_timer?.cancel();
}
StreamSubscription<List<ScanResult>>? _scanSubscription; // 添加扫描订阅变量
@override
void dispose() {
super.dispose();
_stopPeriodicScan(); // 停止定时扫描
_stopScanning(); // 确保离开页面时停止扫描
}
connectToDevice(device, {int time = 5}) {
ble.connectToDevice(
{
"device": device,
'success': (ble.ConnectedDeviceProp deviceProp) {
if (deviceProp.connectedDevicePropType ==
ble.ConnectedDevicePropType.JunHe) {
currentConnectedDeviceProp = deviceProp;
deviceProp.write3OfString("blog enable");
deviceProp.write3OfString("blog rlmax=128");
Timer(const Duration(microseconds: 100), () async {
String log = "";
Function logAdd = (l) {
log += l;
};
deviceProp.receiveLogArr.add(logAdd);
deviceProp.encodeType = 1;
deviceProp.deviceType = 1;
Timer.periodic(const Duration(milliseconds: 300), (timer) async {
if (timer.tick > 20) {
ble.disconnect(currentConnectedDeviceProp);
failSelectDialog();
timer.cancel();
}
if (log.contains("GB2312") || log.contains("UTF-8")) {
timer.cancel();
if (log.contains('CHARSET:UTF-8')) {
deviceProp.encodeType = 2;
}
if (log.contains('TARGET:ESPXX')) {
deviceProp.deviceType = 2;
}
log = "";
bool isSuccess = false;
for (var i = 0; i < 4; i++) {
deviceProp.write3OfString("at+system info");
await Future.delayed(const Duration(milliseconds: 400));
RegExp regExp = RegExp(r"Target Mac:(\S*)");
RegExpMatch? regExpMatch = regExp.firstMatch(log);
if (regExpMatch != null && regExpMatch.group(1) != null) {
String? mac = regExpMatch.group(1);
if (mac?.length == 12 && mac != "000000000000") {
bindArr[2] = "$mac".toUpperCase();
}
isSuccess = true;
break;
}
}
deviceProp.receiveLogArr.remove(logAdd);
print("$bindArr");
RegExp regExp = RegExp(
r"WIFI CONNECTED INFO:SSID=([^\t\n]*)\s*,RSSI=(\S*)\s*,");
RegExpMatch? regExpMatch = regExp.firstMatch(log);
if (regExpMatch != null && log.contains("Status=connect")) {
blueteethBindController.model.connectedWifiName =
regExpMatch.group(1) ?? "";
if (int.tryParse("${regExpMatch.group(2)}") != null) {
blueteethBindController.model.connectedRssi =
int.parse("${regExpMatch.group(2)}");
}
blueteethBindController.updateAll();
}
ble.bleParse();
if (bindArr[0] != null &&
bindArr[0] != "" &&
bindArr[1] != "") {
setState(() {
currentMsg = "绑定中...";
});
blueteethBindController.bindDevice({
"tid": widget.tid,
"name": blueteethBindController.model.deviceName,
"mac": bindArr[0],
"macA": bindArr[1],
"macB": bindArr[2]
}).then((d) {
blueteethBindController.model.bindArr = bindArr;
globalController.getDeviceList();
LoadingDialog.hide();
showCustomConfirmDialog(context, "设备添加成功!",
btnName: "打开WIFI配置",
icon: ConfirmDialogIcon.success)
.then((d) {
if (d == "confirm") {
Get.offAndToNamed("/wifi", arguments: deviceProp);
}
});
}).catchError((d) {
print("$d");
currentMsg = "绑定失败: ${d.message}";
ble.disconnect(currentConnectedDeviceProp);
failSelectDialog(title: "${d.message}");
});
} else {
LoadingDialog.hide();
Get.offAndToNamed("/wifi", arguments: deviceProp);
}
} else {
deviceProp.read6();
}
});
});
} else if (deviceProp.connectedDevicePropType ==
ble.ConnectedDevicePropType.QuanShi) {
List receive = [];
Function fun = (d) {
receive.add(d);
};
deviceProp.receiveLogArr.add(fun);
List<int> head = [
255,
255,
255,
255,
1,
0,
12,
17,
];
Timer.periodic(const Duration(seconds: 1), (timer) {
if (timer.tick > 20) {
timer.cancel();
currentMsg = "错误未能获取到MAC";
failSelectDialog();
}
deviceProp.write(
Uint8List.fromList([
0xFF,
0xFF,
0xFF,
0xFF,
0x01,
0x00,
0x0C,
0x0B,
0x0F,
0x23,
0x04
]),
null,
null);
if (receive.length > 0) {
receive.forEach((data) {
if (data.length != 17) {
return;
}
bool r = true;
for (var i = 0; i < head.length; i++) {
if (head[i] != data[i]) {
r = false;
}
}
if (r == false) {
return;
}
bindArr[1] = ble.ab2str(data.sublist(9, 15)).toUpperCase();
timer.cancel();
deviceProp.receiveLogArr.remove(fun);
blueteethBindController.model.deviceName =
deviceProp.connectDevice?.advName;
ble.disconnect(deviceProp);
toFindJunhe();
});
}
});
} else {
List receive = [];
Function fun = (d) {
receive.add(d);
};
deviceProp.receiveLogArr.add(fun);
List<int> head = [255, 255, 255, 255, 0x00, 0x08, 0x40, 0x01];
Timer.periodic(const Duration(seconds: 1), (timer) {
if (timer.tick > 20) {
timer.cancel();
currentMsg = "错误未能获取到MAC";
failSelectDialog();
}
deviceProp.write(
Uint8List.fromList([
255,
255,
255,
255,
0x00,
0x03,
0x40,
0x01,
0x01,
0x00,
0x45,
0xfd
]),
null,
null);
if (receive.length > 0) {
receive.forEach((data) {
if (data.length != 17) {
return;
}
bool r = true;
for (var i = 0; i < head.length; i++) {
if (head[i] != data[i]) {
r = false;
}
}
if (r == false) {
return;
}
bindArr[1] = ble.ab2str(data.sublist(8, 14)).toUpperCase();
print("$bindArr");
timer.cancel();
deviceProp.receiveLogArr.remove(fun);
blueteethBindController.model.deviceName =
deviceProp.connectDevice?.advName;
ble.disconnect(deviceProp);
toFindJunhe();
});
}
});
}
},
'fail': (e) {
print(e);
if (time > 0) {
connectToDevice(device, time: time - 1);
} else {
currentMsg = "蓝牙无法连接上设备";
failSelectDialog(title: currentMsg);
}
}
},
);
}
isBind() {
return !(blueteethBindController.model.bindArr[1]?.length == 12);
}
failSelectDialog({String title = ""}) {
LoadingDialog.hide();
setState(() {});
showCustomConfirmAndCancelDialog(
context, title == "" ? (isBind() ? "绑定失败" : "连接失败") : title,
confirmName: "重试", cancelName: "返回")
.then((d) {
if (d == "confirm") {
if (connectDeviceCurrent != null) {
ble.bleParse();
ble.start((List d) {
setState(() {
bleDevice = d;
});
}, bleOnCall: () {
LoadingDialog.show("连接中...\n靠近设备2米内",
icon:
isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
setState(() {
currentMsg = "连接设备中...";
});
connectToDevice(connectDeviceCurrent);
});
} else {
bleExec();
}
} else if (d == "cancel") {
Get.back();
}
});
}
bleExec() {
ble.bleParse();
connectTimer?.cancel();
int index = 0;
bool isCloseLoadingDialog = false;
isFind = false;
blueteethBindController.model.bindArr = bindArrBackup;
bindArr = ["", "", ""];
ble.start((List d) {
setState(() {
bleDevice = d;
});
if (isBind()) {
if (isCloseLoadingDialog == false &&
bleDevice.indexWhere((item) {
if (widget.tid == 1) {
return ble.isQuanShiDevice(item["name"]);
} else {
return ble.isMHTSWES(item["name"]);
}
}) !=
-1) {
isCloseLoadingDialog = true;
LoadingDialog.hide();
}
}
}, bleOnCall: () {
if (isBind()) {
LoadingDialog.show("搜索蓝牙设备中...\n请打开蓝牙开关、定位开关\n与设备距离在2米内",
icon: isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
Timer.periodic(const Duration(seconds: 1), (t) {
if (t.tick > 15) {
t.cancel();
isCloseLoadingDialog = true;
LoadingDialog.hide();
showCustomConfirmAndCancelDialog(context, "未发现设备",
confirmName: "重试", cancelName: "返回")
.then((d) {
if (d == "confirm") {
bleExec();
} else if (d == "cancel") {
Get.back();
}
});
} else {
if (isCloseLoadingDialog == true) {
t.cancel();
}
}
});
return;
}
LoadingDialog.show(
"${isBind() ? "绑定中...\n与设备距离在2米内" : "连接中...\n请打开蓝牙开关、定位开关\n与设备距离在2米内"}",
icon: isBind() ? LoadingDialogIcon.ble : LoadingDialogIcon.wifi);
connectTimer = Timer.periodic(const Duration(seconds: 1), (t) {
index++;
if (index > 15) {
connectTimer = null;
t.cancel();
failSelectDialog();
}
var d = bleDevice;
if (d != null && d.length > 0) {
if (isBind()) {
var deviceble = d.firstWhere((item) {
bool isFF = false;
if (widget.tid == 1) {
isFF = ble.isQuanShiDevice(item["name"]);
} else {
isFF = ble.isMHTSWES(item["name"]);
}
if (isFF) {
isFF = globalController.model.deviceList.indexWhere(
(d) => d["mac"] == item["adData"]["deviceId"]) ==
-1
? true
: false;
}
return isFF;
}, orElse: () => null);
if (!isFind && deviceble != null) {
print("quanshidevice");
isFind = true;
setState(() {
currentMsg = "连接设备中...";
});
t.cancel();
connectToDevice(deviceble["device"]);
bindArr[0] = deviceble["adData"]["deviceId"];
}
} else {
var deviceble = d.firstWhere(
(item) =>
item["adData"]["deviceId"] ==
blueteethBindController.model.bindArr[1],
orElse: () => null);
if (!isFind && deviceble != null) {
print("junhedevice");
isFind = true;
t.cancel();
setState(() {
currentMsg = "连接设备中...";
});
connectToDevice(deviceble["device"]);
bindArr[1] = deviceble["adData"]["deviceId"];
}
}
}
});
});
_stopScanning(); // 停止扫描
_scanSubscription?.cancel(); // 取消扫描订阅
connectTimer?.cancel(); // 取消连接定时器
blueteethBindController.stopStatusPolling(); // 停止状态轮询
super.dispose();
}
@override
@@ -679,7 +307,7 @@ class _EPageState extends State<BlueteethDevicePage> {
padding: EdgeInsetsDirectional.fromSTEB(
0, 30.rpx, 0, 30.rpx),
child: Text(
'蓝牙绑定.扫描蓝牙设备中…'.tr,
'蓝牙绑定.扫描'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -917,42 +545,48 @@ class _EPageState extends State<BlueteethDevicePage> {
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(19.rpx, 0, 0, 0),
child: Text(
'匹配出的外围设备(${blueteethBindController.model.devicelist!.length}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
child: Obx(() {
return Text(
'匹配出的外围设备(${blueteethBindController.model.betDevicelist!.length}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
);
}),
),
),
),
Obx(() {
return Expanded(
child: Container(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
...blueteethBindController.model.blelist!
.map((device) =>
SingleBlueteethDeviceCompoentWidget(
// device: device,
bleDevice: device,
))
.toList()
.divide(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(height: 30.rpx)),
],
if (blueteethBindController
.model.betDevicelist!.isNotEmpty) {
return Expanded(
child: Container(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
...blueteethBindController.model.blelist!
.map((device) =>
SingleBlueteethDeviceCompoentWidget(
// device: device,
bleDevice: device,
))
.toList()
.divide(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(height: 30.rpx)),
],
),
),
),
),
);
);
}
return Container();
}),
].divide(SizedBox(height: 30.rpx)),
),
@@ -979,38 +613,6 @@ class _EPageState extends State<BlueteethDevicePage> {
),
);
}
toFindJunhe() {
bool isSuccess = false;
int i = 0;
Timer.periodic(const Duration(seconds: 1), (t) async {
i++;
if (isSuccess) {
return;
}
if (i > 8) {
if (!isSuccess) {
currentMsg = "错误:未找到关联设备";
failSelectDialog(title: "绑定失败:未找到关联设备");
}
t.cancel();
return;
}
bleDevice.forEach((item) {
if (isSuccess) {
return;
}
if (item['adData']['deviceId'] == bindArr[1]) {
isSuccess = true;
t.cancel();
setState(() {
currentMsg = "寻找关联设备中...";
});
connectToDevice(item["device"]);
}
});
});
}
}
BleDeviceData parseBleData(List<int> data) {

View File

@@ -75,7 +75,7 @@ class _FancyCircleCheckboxState extends State<FancyCircleCheckbox>
child: ScaleTransition(
scale: _scaleAnimation,
child: Container(
margin: EdgeInsets.all(8.rpx),
margin: EdgeInsets.all(6.rpx),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: widget.fillColor,

View File

@@ -41,7 +41,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
deviceData.rssi = widget.bleDevice.rssi;
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
BleDeviceData device = deviceData;
device = blueteethBindController.model.devicelist!.firstWhere(
device = blueteethBindController.model.betDevicelist!.firstWhere(
(d) => d.mac == device.mac,
orElse: () => device,
);
@@ -64,15 +64,12 @@ class _SingleBlueteethDeviceCompoentWidgetState
onConfirm: () async {
ApiResponse response =
await blueteethBindController.bindDeviceAndMAC(device);
TopSlideNotification.show(context, text: response.msg!);
if (response.code == HttpStatusCodes.ok) {
showLoadingDialog(context); // 显示 loading
BLEDevice bledevice =
BLEDevice(device: widget.bleDevice.device);
var res1 = bledevice.isConnected;
print("res1: $res1");
THapp bledevice = THapp(device: widget.bleDevice.device);
await bledevice.device.connect();
var res2 = bledevice.isConnected;
print("res2: $res2");
if (res2) {
Navigator.pop(context);
TopSlideNotification.show(
@@ -94,7 +91,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
} else {
TopSlideNotification.show(
context,
text: "蓝牙绑定.连接异常".tr,
text: response.msg ?? "蓝牙绑定.连接异常".tr,
textColor: themeController.currentColor.sc9,
);
}
@@ -104,6 +101,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
// 执行取消后的处理逻辑
},
);
}
} catch (e) {
Navigator.pop(context);

View File

@@ -1,11 +1,14 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:loading_indicator/loading_indicator.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/FrostedDialog.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/model/BleDeviceData.dart';
@@ -248,7 +251,7 @@ void showHaveBindDialog(BuildContext context) {
);
}
void showLoadingDialog(BuildContext context) {
void showLoadingDialog(BuildContext context, {String? title}) {
ThemeController themeController = Get.find();
showDialog(
context: context,
@@ -310,7 +313,7 @@ void showLoadingDialog(BuildContext context) {
child: RichText(
text: TextSpan(children: [
TextSpan(
text: "连接中...".tr,
text: title ?? "连接中...".tr,
style: TextStyle(
color: themeController.currentColor.sc3,
fontSize: AppConstants().normal_text_fontSize,
@@ -433,6 +436,30 @@ void showConfirmDialog(
mainAxisSize: MainAxisSize.min,
children: [
// 标题
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor:
themeController.currentColor.sc21, // 点击时的背景色
padding: EdgeInsets.zero, // 这里去掉外部的 padding避免影响点击范围
onTap: () {
Get.back();
},
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 33.rpx, 0, 0.rpx),
child: SvgPicture.asset(
'assets/img/icon/close.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,使用 color 设置
color: themeController.currentColor.sc3,
),
),
),
],
),
Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
@@ -457,9 +484,10 @@ void showConfirmDialog(
children: [
CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
Get.back();
onTap: () async {
onConfirm();
// await Future.delayed(Duration(milliseconds: 300));
Get.back();
},
colors: [
themeController.currentColor.sc1,
@@ -542,3 +570,141 @@ void showConfirmDialog(
},
);
}
void showWifiDialog(
BuildContext context,
Widget widget,
String title, {
required VoidCallback onConfirm,
}) {
ThemeController themeController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
showDialog(
context: context,
barrierDismissible: true,
barrierColor: Colors.black.withOpacity(0.5), // 背景模糊色
builder: (BuildContext context) {
return FrostedDialog(
blurSigma: 3.0,
child: Container(
decoration: BoxDecoration(
color: themeController.currentColor.sc17,
borderRadius: BorderRadius.circular(20.0),
),
padding: EdgeInsetsDirectional.fromSTEB(64.rpx, 0, 64.rpx, 0),
child: Container(
width: double.infinity,
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.656,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 标题
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor:
themeController.currentColor.sc21, // 点击时的背景色
padding: EdgeInsets.zero, // 这里去掉外部的 padding避免影响点击范围
onTap: () {
Get.back();
},
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 33.rpx, 0, 0.rpx),
child: SvgPicture.asset(
'assets/img/icon/close.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,使用 color 设置
color: themeController.currentColor.sc3,
),
),
),
],
),
Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0.rpx, 40.rpx, 0, 0),
child: Text(
title,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
),
widget,
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 58.rpx, 0, 60.rpx),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
if (blueteethBindController.model.wifiPass == null ||
blueteethBindController.model.wifiPass!.isEmpty) {
TopSlideNotification.show(
context,
text: "wifi页.密码为空".tr,
textColor: themeController.currentColor.sc9,
);
} else {
Get.back();
onConfirm();
}
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: MediaQuery.sizeOf(context).width * 0.115,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 160.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"蓝牙绑定.连接".tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color: themeController.currentColor.sc3,
fontFamily: 'Inter',
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 17.rpx)),
),
),
),
].divide(SizedBox(
width: 70.rpx,
)),
),
),
],
),
),
),
);
},
);
}

View File

@@ -0,0 +1,421 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/device_share_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/device_bind/componnet/FancyCircleCheckbox.dart';
class DeviceSharePage extends StatefulWidget {
var device;
DeviceSharePage({super.key, required this.device});
@override
State<DeviceSharePage> createState() => _DeviceSharePageState();
}
class _DeviceSharePageState extends State<DeviceSharePage> {
DeviceShareController deviceShareController = Get.find();
@override
void initState() {
deviceShareController.msg = "".obs;
deviceShareController.code = 0.obs;
deviceShareController.account = "".obs;
super.initState();
}
@override
Widget build(BuildContext context) {
var device = widget.device;
RxBool flag1 = true.obs;
RxBool flag2 = false.obs;
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,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
titleSpacing: 0,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
Text(
'设备分享'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(47.rpx, 0, 47.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 28.rpx, 0, 0),
child: Container(
width: double.infinity,
child: Text(
'要分享的设备'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 62.rpx, 0, 62.rpx),
child: Container(
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() => FancyCircleCheckbox(
borderColor:
themeController.currentColor.sc3,
fillColor:
themeController.currentColor.sc2,
value: flag1.value,
onChanged: (value) {
flag1.value = !flag1.value;
deviceShareController.updateAll();
},
)),
Text(
'主设备'.tr +
"${device['person']?['name'] == null ? '未命名'.tr : device['person']['name']}",
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color:
themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 20.rpx)),
),
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Obx(() => FancyCircleCheckbox(
// borderColor:
// themeController.currentColor.sc3,
// fillColor:
// themeController.currentColor.sc2,
// value: true,
// onChanged: (value) {},
// )),
// Text(
// '主设备蓝盈盈A9876451',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// color:
// themeController.currentColor.sc3,
// ),
// ),
// ].divide(SizedBox(width: 20.rpx)),
// ),
].divide(SizedBox(height: 64.rpx)),
),
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 58.rpx, 0, 0),
child: Container(
width: MediaQuery.sizeOf(context).width * 0.66,
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: Color(0xFFF3EDED),
),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: TextFormField(
// controller: _model.textController1,
// focusNode: _model.textFieldFocusNode1,
initialValue: deviceShareController.account.value,
onChanged: (Value) {
deviceShareController.account.value = Value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
fillColor: Colors.transparent,
isDense: true,
labelStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
hintText: '请输入对方手机号或邮箱'.tr,
hintStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
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(
color: FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
filled: true,
),
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
textAlign: TextAlign.center,
cursorColor:
FlutterFlowTheme.of(context).primaryText,
// validator: _model.textController1Validator
// .asValidator(context),
),
),
),
),
Obx(() {
return Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 15.rpx, 0, 0),
child: Container(
width: double.infinity,
constraints: BoxConstraints(
minHeight: 30.rpx,
),
child: deviceShareController.code != 0
? Align(
alignment: AlignmentDirectional(0, 0),
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
children: [
TextSpan(
text:
'${deviceShareController.code == 1 ? "邀请成功".tr : "邀请失败".tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: deviceShareController
.code ==
1
? themeController
.currentColor.sc2
: themeController
.currentColor.sc9,
),
),
TextSpan(
text:
'${deviceShareController.msg}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc9,
),
),
],
),
),
)
: Container(),
),
);
}),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 58.rpx, 0, 0),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () async {
ApiResponse apiResponse =
await deviceShareController
.shareDevice(device['mac']);
if (apiResponse.code == HttpStatusCodes.ok) {
TopSlideNotification.show(context,
text: apiResponse.msg!);
} else {
TopSlideNotification.show(context,
text: apiResponse.msg!,
textColor: themeController.currentColor.sc9);
}
},
colors: [
// 渐变色
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: MediaQuery.sizeOf(context).width * 0.214,
height: MediaQuery.sizeOf(context).height * 0.037,
constraints: BoxConstraints(
minWidth: 160.rpx,
minHeight: 60.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'发送邀请'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color: themeController.currentColor.sc3,
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize, // 自定义字体大小
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 17.rpx)),
),
),
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 379.rpx, 0, 0),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
colors: [
// 渐变色
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: MediaQuery.sizeOf(context).width * 0.66,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'微信好友一键分享'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color: themeController.currentColor.sc3,
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize, // 自定义字体大小
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 17.rpx)),
),
),
),
),
],
),
),
),
),
),
),
),
);
}
}

View File

@@ -3,18 +3,21 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/FrostedDialog.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/device_type_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class DeviceTypePage extends StatefulWidget {
int type = 0;//0绑定设备 1.查询我的设备
DeviceTypePage({super.key,this.type = 0});
int type = 0; //0绑定设备 1.查询我的设备
DeviceTypePage({super.key, this.type = 0});
@override
State<DeviceTypePage> createState() => _EPageState();
@@ -25,10 +28,20 @@ class _EPageState extends State<DeviceTypePage> {
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
@override
void initState() {
super.initState();
deviceTypeController.getDeviceType().then((response) {
if (response.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: response.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
}
});
// 延迟到 build 完成后执行弹窗逻辑
WidgetsBinding.instance.addPostFrameCallback((_) {
if (blueteethBindController.model.read == 1 && widget.type == 0) {
@@ -349,28 +362,29 @@ class _EPageState extends State<DeviceTypePage> {
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
_buildDeviceCard(
context,
title: '设备类型.体征监测设备'.tr,
imageUrl: 'assets/img/device.png',
type: '1',
),
_buildDeviceCard(
context,
title: '设备类型.智能床/床垫'.tr,
imageUrl: 'assets/img/bed.png',
type: '2',
),
_buildDeviceCard(
context,
title: '设备类型.摄像头'.tr,
imageUrl: 'assets/img/camera.png',
type: '3',
),
]
.divide(SizedBox(height: 26.rpx))
.addToStart(SizedBox(height: 26.rpx))
.addToEnd(SizedBox(height: 26.rpx)),
// 使用 Obx 来监听 deviceTypeList 的变化
Obx(() {
return Column(
children: [
SizedBox(height: 26.rpx), // 开始的间隔
...deviceTypeController.deviceTypeList.value
.map((device) {
return Padding(
padding: EdgeInsets.only(
bottom: 26.rpx), // 添加每个设备之间的间隔
child: _buildDeviceCard(
context,
title: device['name'], // 这里假设 device 是一个 Map
imageUrl: device['image'],
type: device['type'],
),
);
}).toList(),
SizedBox(height: 26.rpx), // 结束的间隔
],
);
}),
],
),
),
),
@@ -382,16 +396,20 @@ class _EPageState extends State<DeviceTypePage> {
}
Widget _buildDeviceCard(BuildContext context,
{required String title, required String imageUrl, required String type}) {
{required String title, required String imageUrl, required double type}) {
return CustomCard(
borderRadius: 20.rpx, // 圆角大小
onTap: () {
if (type != null) {
if (type == '1') {
if (type == 1) {
Get.toNamed("/blueteethDevice");
}
if (type == '2') {
Get.toNamed("/wifiPage");
if (type == 2) {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor: themeController.currentColor.sc2,
);
}
}
},
@@ -418,8 +436,14 @@ class _EPageState extends State<DeviceTypePage> {
),
ClipRRect(
borderRadius: BorderRadius.circular(8.rpx),
child: Image.asset(
// child: Image.asset(
// imageUrl,
// width: 212.rpx,
// height: 168.rpx,
// ),
child: Image.network(
imageUrl,
// fit: BoxFit.cover,
width: 212.rpx,
height: 168.rpx,
),

View File

@@ -0,0 +1,192 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/CustomCard.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/device_type_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class DeviceTypeListPage extends StatefulWidget {
DeviceTypeListPage({super.key});
@override
State<DeviceTypeListPage> createState() => _DeviceTypeListPageState();
}
class _DeviceTypeListPageState extends State<DeviceTypeListPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
@override
void initState() {
super.initState();
deviceTypeController.getDeviceType().then((response) {
if (response.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: response.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
}
});
}
@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(
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
// backgroundColor: Colors.transparent,
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(
'设备列表',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// 使用 Obx 来监听 deviceTypeList 的变化
Obx(() {
return Column(
children: [
SizedBox(height: 26.rpx), // 开始的间隔
...deviceTypeController.deviceTypeList.value
.map((device) {
return Padding(
padding: EdgeInsets.only(
bottom: 26.rpx), // 添加每个设备之间的间隔
child: _buildDeviceCard(
context,
title: device['name'], // 这里假设 device 是一个 Map
imageUrl: device['image'],
type: device['type'],
),
);
}).toList(),
SizedBox(height: 26.rpx), // 结束的间隔
],
);
}),
],
),
),
),
),
),
),
),
);
}
Widget _buildDeviceCard(BuildContext context,
{required String title, required String imageUrl, required double type}) {
return CustomCard(
borderRadius: 20.rpx, // 圆角大小
onTap: () {
if (type != null) {
if (type == 1) {
Get.toNamed("/bodyDevice");
}
if (type == 2) {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor: themeController.currentColor.sc2,
);
}
}
},
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: FlutterFlowTheme.of(context).bodyMedium.override(
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,
// ),
child: Image.network(
imageUrl,
// fit: BoxFit.cover,
width: 212.rpx,
height: 168.rpx,
),
),
],
),
),
);
}
}

View File

@@ -1,23 +1,24 @@
import 'dart:async';
import 'package:easydevice/easydevice.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/component/tool/cmd.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_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/pages/common/selectDialog.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class WifiPage extends StatefulWidget {
BLEDevice bleDevice;
WifiPage({super.key, required this.bleDevice});
WifiPage({super.key});
// WifiPage({super.key});
@override
@@ -30,18 +31,29 @@ class _WifiPageState extends State<WifiPage> {
BlueteethBindController blueteethBindController = Get.find();
PersonController personController = Get.find();
ThemeController themeController = Get.find();
var lisObj;
// List<String> _logBuffer = [];
// bool _isCollecting = false;
@override
void initState() {
super.initState();
// connectedDeviceProp = widget.connectedDeviceProp;
Timer(const Duration(microseconds: 100), () {
getWifiList();
});
blueteethBindController.wifiList = [].obs;
initWifiStatusAndWifiList();
}
@override
void dispose() {
super.dispose();
if (lisObj != null) {
lisObj.cancel();
}
blueteethBindController.currentDevice!.disconnect();
}
@override
Widget build(BuildContext context) {
print("object");
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
@@ -87,11 +99,19 @@ class _WifiPageState extends State<WifiPage> {
child: CustomCard(
borderRadius: 20.rpx,
onTap: () async {
Get.offAllNamed("/bindDeviceSuccess");
if (blueteethBindController.wifiStatus.value != 1) {
TopSlideNotification.show(
context,
text: "wifi页.需配网".tr,
textColor: themeController.currentColor.sc9,
);
}
Get.toNamed("/personPage");
// Get.toNamed("/bindDeviceSuccess");
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: 100.rpx,
@@ -132,41 +152,87 @@ class _WifiPageState extends State<WifiPage> {
padding:
EdgeInsetsDirectional.fromSTEB(0, 30.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF242835),
borderRadius: BorderRadius.circular(20.rpx),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 30.rpx, 30.rpx, 30.rpx),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"wifi页.WLAN".tr,
style: TextStyle(
color: themeController.currentColor.sc3,
fontSize:
AppConstants().title_text_fontSize,
),
),
Text(
"wifi页.未连接".tr,
style: TextStyle(
color: themeController.currentColor.sc3,
fontSize:
AppConstants().normal_text_fontSize,
),
),
],
),
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF242835),
borderRadius: BorderRadius.circular(20.rpx),
),
),
),
child: Column(
children: [
Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 30.rpx, 30.rpx, 30.rpx),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"wifi页.WLAN".tr,
style: TextStyle(
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
),
),
Obx(() {
return Text(
blueteethBindController
.wifiStatus.value ==
0
? "wifi页.未连接".tr
: "wifi页.已连接".tr,
style: TextStyle(
color: blueteethBindController
.wifiStatus.value ==
0
? themeController
.currentColor.sc4
: themeController
.currentColor.sc2,
fontSize: AppConstants()
.normal_text_fontSize,
),
);
}),
],
),
),
),
Obx(() {
if (blueteethBindController
.connect_wifi.value ==
null ||
blueteethBindController
.connect_wifi.value.isEmpty) {
return Container();
} else {
return Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
blueteethBindController
.connect_wifi.value['ssid'] ??
'未命名'.tr,
style: TextStyle(
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
),
),
getWifiIconByRsso(
blueteethBindController
.connect_wifi.value),
],
);
}
})
],
)),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
@@ -190,7 +256,7 @@ class _WifiPageState extends State<WifiPage> {
mainAxisSize: MainAxisSize.max,
children: [
Text(
'可用WLAN',
'可用WLAN'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -203,157 +269,436 @@ class _WifiPageState extends State<WifiPage> {
),
],
),
Column(
mainAxisSize: MainAxisSize.max,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'6503',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
// Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// '6503',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc3,
// ),
// ),
// Icon(
// Icons.wifi_outlined,
// size: 30.rpx,
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// '6503',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc3,
// ),
// ),
// Icon(
// Icons.wifi_outlined,
// size: 30.rpx,
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// '6503',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc3,
// ),
// ),
// Icon(
// Icons.wifi_outlined,
// size: 30.rpx,
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// '6503',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc3,
// ),
// ),
// Icon(
// Icons.wifi_outlined,
// size: 30.rpx,
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Text(
// '6503',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color: themeController
// .currentColor.sc3,
// ),
// ),
// Icon(
// Icons.wifi_outlined,
// size: 30.rpx,
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// ].divide(SizedBox(height: 67.rpx)),
// ),
Obx(() {
final sortedList = [
...blueteethBindController.wifiList.value
]..sort((a, b) => b['rssi']
.compareTo(a['rssi'])); // 按 rssi 倒序
return Column(
mainAxisSize: MainAxisSize.max,
children: sortedList
.map((wifiItem) => ClickableContainer(
backgroundColor:
Colors.transparent,
highlightColor: themeController
.currentColor.sc3,
padding: EdgeInsets.symmetric(
vertical: 0.rpx,
horizontal: 20.rpx),
borderRadius: 16.rpx,
onTap: () {
showWifiDialog(
context,
Padding(
padding:
EdgeInsetsDirectional
.fromSTEB(
0.rpx,
41.rpx,
0.rpx,
0),
child: Container(
height: 80.rpx,
decoration:
BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius
.circular(12
.rpx), // 加圆角
),
child: Align(
alignment:
AlignmentDirectional(
-1, 0),
child: Obx(() {
return TextFormField(
onChanged:
(value) {
blueteethBindController
.model
.wifiPass =
value;
},
autofocus:
false,
obscureText:
blueteethBindController
.model
.wifiPassShow,
decoration:
InputDecoration(
isDense:
true,
labelStyle: FlutterFlowTheme.of(
context)
.labelMedium
.override(
fontFamily:
'Inter',
fontSize:
26.rpx,
letterSpacing:
0.0,
),
hintText:
'蓝牙绑定.输入wifi密码'
.tr,
hintStyle: FlutterFlowTheme.of(context).labelMedium.override(
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(
color: FlutterFlowTheme.of(context)
.error,
width: 1
.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedErrorBorder:
OutlineInputBorder(
borderSide:
BorderSide(
color: FlutterFlowTheme.of(context)
.error,
width: 1
.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
filled:
false,
fillColor: FlutterFlowTheme.of(
context)
.secondaryBackground,
suffixIcon:
InkWell(
onTap:
() {
blueteethBindController
.model
.wifiPassShow = !blueteethBindController.model.wifiPassShow;
blueteethBindController
.updateAll();
},
focusNode:
FocusNode(
skipTraversal: true),
child:
Icon(
blueteethBindController.model.wifiPassShow
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
size: 30
.rpx,
),
),
),
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily:
'Inter',
fontSize: 26
.rpx,
letterSpacing:
0.0,
color: Colors
.black),
cursorColor:
FlutterFlowTheme.of(
context)
.primaryText,
);
})),
),
),
wifiItem['ssid'] ??
'未命名'.tr,
onConfirm: () async {
showLoadingDialog(
context); // 显示 loading
bool flag = await sendWifiSetting(
wifiItem,
blueteethBindController
.model.wifiPass!,
blueteethBindController
.currentDevice!);
Navigator.pop(context);
if (flag) {
TopSlideNotification.show(
context,
text: "wifi页.配网成功".tr,
textColor:
themeController
.currentColor
.sc2,
);
blueteethBindController
.wifiStatus.value = 1;
blueteethBindController
.updateAll();
} else {
TopSlideNotification.show(
context,
text: "wifi页.配网失败".tr,
textColor:
themeController
.currentColor
.sc9,
);
blueteethBindController
.wifiStatus.value = 0;
blueteethBindController
.updateAll();
}
});
},
child: Row(
mainAxisSize:
MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Text(
wifiItem['ssid'] ?? '',
style: FlutterFlowTheme
.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color:
themeController
.currentColor
.sc3,
),
),
getWifiIconByRsso(wifiItem),
],
),
))
.toList()
.divide(SizedBox(height: 67.rpx)),
);
}),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 20.rpx, vertical: 10.rpx),
borderRadius: 20.rpx,
onTap: () async {
print("点击刷新");
await initWifiList();
TopSlideNotification.show(
context,
text: "获取wifi列表成功".tr,
textColor:
themeController.currentColor.sc2,
);
},
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Container(
width: 25.rpx,
height: 25.rpx,
decoration: BoxDecoration(),
child: SvgPicture.asset(
'assets/img/icon/refresh.svg',
fit: BoxFit.cover,
color: Colors.white, // 图标固定白色
),
Icon(
Icons.wifi_outlined,
size: 30.rpx,
color: themeController
.currentColor.sc3,
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'6503',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Icon(
Icons.wifi_outlined,
size: 30.rpx,
color: themeController
.currentColor.sc3,
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'6503',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Icon(
Icons.wifi_outlined,
size: 30.rpx,
color: themeController
.currentColor.sc3,
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'6503',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Icon(
Icons.wifi_outlined,
size: 30.rpx,
color: themeController
.currentColor.sc3,
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'6503',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
Icon(
Icons.wifi_outlined,
size: 30.rpx,
color: themeController
.currentColor.sc3,
),
],
),
].divide(SizedBox(height: 67.rpx)),
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.arrow_back,
color: themeController.currentColor.sc3,
size: 30.rpx,
),
Text(
'刷新',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
),
Text(
'刷新',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3),
),
].divide(SizedBox(width: 26.rpx)),
.currentColor.sc3,
),
),
].divide(SizedBox(width: 26.rpx)),
),
),
].divide(SizedBox(height: 65.rpx)),
),
@@ -419,42 +764,143 @@ class _WifiPageState extends State<WifiPage> {
);
}
getWifiList({int time = 3}) {
// LoadingDialog.show("扫描WIFI列表中...", icon: LoadingDialogIcon.wifi);
void initWifiStatusAndWifiList() {
if (lisObj != null) {
lisObj!.cancel();
}
lisObj = blueteethBindController.currentDevice!.statusStream
.listen((onData) async {
if (onData.status == BleEventType.recvLineLog) {
final line = onData.val;
print("[bleee]:" + line);
}
if (onData.status == BleEventType.ready) {
showLoadingDialog(context, title: "获取wifi列表中...".tr);
bool wifiStatus =
await getWifiStatus(blueteethBindController.currentDevice!);
blueteethBindController.wifiStatus.value = wifiStatus == true ? 1 : 0;
if (wifiStatus) {
Map connect_wifiInfo =
await getDeviceWifiStatus(blueteethBindController.currentDevice!);
if (connect_wifiInfo != null) {
blueteethBindController.connect_wifi.value = connect_wifiInfo;
}
}
List wifiList =
await getWifiList(blueteethBindController.currentDevice!);
if (wifiList.length > 0) {
Navigator.pop(context);
TopSlideNotification.show(
context,
text: "获取wifi列表成功".tr,
textColor: themeController.currentColor.sc2,
);
blueteethBindController.wifiList.value = wifiList;
blueteethBindController.updateAll();
} else {
Navigator.pop(context);
TopSlideNotification.show(
context,
text: "获取wifi列表失败".tr,
textColor: themeController.currentColor.sc9,
);
}
}
});
}
initWifiList() async {
try {
// var device = widget.bluetoothDevice;
// String log = "";
// Function logAdd = (l) {
// log += l;
// };
var wifiList = await getWifiList(blueteethBindController.currentDevice!);
print(wifiList);
if (wifiList.length > 0) {
blueteethBindController.wifiList.value = wifiList;
blueteethBindController.updateAll();
}
return wifiList;
} catch (e) {
print(e);
TopSlideNotification.show(
context,
text: "获取wifi列表失败".tr,
textColor: themeController.currentColor.sc9,
);
}
}
checkIsCalibration() {
// if (controller.model.bindArr[0] == "" ||
// controller.model.bindArr[0] == null) {
// return;
// }
// if (controller.model.bindArr[2] == "" ||
// controller.model.bindArr[2] == null) {
// return;
// }
// if (controller.model.connectedWifiName == "" ||
// controller.model.connectedWifiName == null) {
// return;
// }
showCustomConfirmAndCancelDialog(context, "是否进行设备校准?", confirmName: "去校准")
.then((d) async {
// if (d == "confirm") {
// await Get.offAndToNamed("/calibration", arguments: [
// controller.model.bindArr[1],
// controller.model.bindArr[2]
// ]);
// Get.find<GlobalController>().getDeviceList();
// }
});
getWifiIconByRsso(wifiItem) {
if (wifiItem['rssi'] >= -30) {
// return SvgPicture.asset(
// 'assets/img/icon/wifi4.svg',
// width: 25.rpx,
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController.currentColor.sc3,
// );
return Container(
width: 40.rpx,
height: 40.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wifi4.png",
),
);
} else if (wifiItem['rssi'] >= -45) {
// return SvgPicture.asset(
// 'assets/img/icon/wifi3.svg',
// width: 25.rpx,
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController.currentColor.sc3,
// );
return Container(
width: 40.rpx,
height: 40.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wifi3.png",
),
);
} else if (wifiItem['rssi'] >= -60) {
// return SvgPicture.asset(
// 'assets/img/icon/wifi2.svg',
// width: 25.rpx,
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController.currentColor.sc3,
// );
return Container(
width: 40.rpx,
height: 40.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wifi3.png",
),
);
} else {
// return SvgPicture.asset(
// 'assets/img/icon/wifi1.svg',
// width: 25.rpx,
// height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController.currentColor.sc3,
// );
return Container(
width: 40.rpx,
height: 40.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wifi1.png",
),
);
}
}
}

View File

@@ -7,6 +7,7 @@ import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.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/theme_controller/ThemeController.dart';
@@ -168,6 +169,8 @@ class _EPageState extends State<LoginPage> {
borderRadius: AppConstants()
.button_container_radius, // 圆角半径
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
bool agree =
loginController.model.register_agree!;
if (!agree) {

View File

@@ -5,6 +5,7 @@ import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:get_storage/get_storage.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
@@ -442,9 +443,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
return InkWell(
onTap: () async {
try {
await DailyLogUtils
.writeLog(
"点击获取验证码");
DailyLogUtils.writeLog(
"点击获取验证码");
if (countdownController
.countdown
.value !=
@@ -457,7 +457,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
.getCode(
context);
if (apiResponse.code !=
HttpStatusCodes.ok) {
HttpStatusCodes
.ok) {
TopSlideNotification
.show(
context,
@@ -551,7 +552,7 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
.button_container_radius, // 圆角半径
onTap: () async {
try {
await DailyLogUtils.writeLog("点击登录");
DailyLogUtils.writeLog("点击登录");
bool agree =
loginController.model.register_agree!;
if (!agree) {
@@ -565,7 +566,8 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
ApiResponse apiResponse =
await loginController
.login(context);
if (apiResponse.code != HttpStatusCodes.ok) {
if (apiResponse.code !=
HttpStatusCodes.ok) {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
@@ -580,7 +582,9 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
textColor: themeController
.currentColor.sc2,
);
Get.offAllNamed('/homePage');
// Get.offAllNamed('/homePage');
Get.offAllNamed(
"/mianPageBottomChange");
}
}
} catch (e) {

View File

@@ -0,0 +1,168 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class MessageWidgetWidget extends StatefulWidget {
const MessageWidgetWidget({super.key});
@override
State<MessageWidgetWidget> createState() => _MessageWidgetWidgetState();
}
class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
ThemeController themeController = Get.find();
@override
Widget build(BuildContext context) {
return Stack(
children: [
ClickableContainer(
backgroundColor: themeController.currentColor.sc5,
highlightColor: themeController.currentColor.sc3,
borderRadius: 20.rpx,
padding:
EdgeInsetsDirectional.fromSTEB(31.rpx, 33.rpx, 0.rpx, 33.rpx),
onTap: () {},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
constraints: BoxConstraints(
minHeight: 66.rpx,
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
'实时监测结果通知'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
constraints: BoxConstraints(
minWidth: 30.rpx,
maxWidth: 120.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoItem(context, '设备ID'),
_buildInfoItem(context, '使用人员'),
_buildInfoItem(context, '消息类型'),
_buildInfoItem(context, '检测数值'),
_buildInfoItem(context, '发生时间'),
],
),
),
Container(
constraints: BoxConstraints(
minWidth: 30.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildValueItem(context, '设备ID'),
_buildValueItem(context, '使用人员'),
_buildValueItem(context, '消息类型'),
_buildValueItem(context, '检测数值'),
_buildValueItem(context, '发生时间'),
],
),
),
].divide(SizedBox(width: 35.rpx)),
),
],
),
),
Positioned(
bottom: 46.rpx,
right: 20.rpx,
child: Container(
width: 123.rpx,
height: 47.rpx,
child: CustomCard(
borderRadius: AppConstants().button_container_radius, // 直角
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2
], // 单色背景
enableAnimation: true, // 有点击缩放动画
enableGradient: false, // 不用渐变
onTap: () {
// 点击处理逻辑
print('处理按钮点击了');
},
child: Center(
child: Text(
'处理'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: Colors.white,
),
),
),
),
),
),
],
);
}
Widget _buildInfoItem(BuildContext context, String label) {
return Container(
constraints: BoxConstraints(
minHeight: 62.rpx,
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
label.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
),
);
}
Widget _buildValueItem(BuildContext context, String value) {
return Container(
constraints: BoxConstraints(
minHeight: 62.rpx,
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
value,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -7,9 +7,12 @@ import 'package:flutter/services.dart';
import 'package:flutter_svg/svg.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/main_bottom/main_page_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/LoginStatus.dart';
import 'package:vbvs_app/pages/main_bottom/e_page.dart';
import 'package:vbvs_app/pages/main_bottom/home_page.dart';
import 'package:vbvs_app/pages/main_bottom/message_page.dart';
@@ -33,7 +36,7 @@ class MainPageBottomChange extends GetView<MainPageController> {
width: size,
height: size,
),
),
),
activeIcon: Padding(
padding: EdgeInsets.only(bottom: 6.rpx),
child: isEmpty
@@ -105,15 +108,40 @@ class MainPageBottomChange extends GetView<MainPageController> {
type: BottomNavigationBarType.fixed,
currentIndex: controller.model.currentIndex,
onTap: (index) {
Future.delayed(const Duration(milliseconds: 500), () {
if (controller.model.currentIndex != 1) {
Future.delayed(const Duration(milliseconds: 100), () {
UserInfoController userInfoController = Get.find();
bool isLoggedIn = userInfoController.model.login ==
LoginStatus.LOGIN.code;
// 需要登录的页面
if ((index == 1 || index == 2) && !isLoggedIn) {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor: themeController.currentColor.sc9,
);
Future.delayed(Duration(milliseconds: 50), () {
if (Get.currentRoute == '/ePage' ||
Get.currentRoute == '/messagePage') {
Get.back();
}
Future.delayed(Duration(milliseconds: 100), () {
Get.toNamed("/loginPage");
});
});
return;
}
// 已登录 或 index 是不需要登录的页面,正常跳转
if (controller.model.currentIndex != index) {
globalController.model.hideBottomNavigationBar =
false;
globalController.updateAll();
}
controller.model.currentIndex = index;
controller.updateAll();
});
controller.model.currentIndex = index;
controller.updateAll();
},
items: [
getBottomNavigationBarItem("assets/img/menu/home.svg",

View File

@@ -1,7 +1,15 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:flutter/services.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/message/message_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/pages/main_bottom/component/MessageWidgetWidget.dart';
class MessagePage extends StatefulWidget {
const MessagePage({super.key});
@@ -11,17 +19,209 @@ class MessagePage extends StatefulWidget {
}
class _MessagePageState extends State<MessagePage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
ThemeController themeController = Get.find();
MessageController messageController = Get.find();
@override
void initState() {
messageController.getMessageList().then((response) {
if (response.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: response.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
}
});
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // 这里设置你希望的颜色
statusBarIconBrightness: Brightness.light, // 状态栏图标的亮度
));
return LayoutBuilder(
builder: (context, boxConstraints) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
body: SafeArea(
top: true,
child: Text("消息"),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(
color: themeController.currentColor.sc3,
),
toolbarHeight: 140.rpx,
titleSpacing: 0,
title: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx,
0.rpx,
0.rpx,
0.rpx,
),
child: Container(
width: double.infinity,
height: 140.rpx, // 👈 明确告诉 Flutter 高度
child: Column(
children: [
SizedBox(height: 40.rpx), // 上边距
Expanded(
child: Stack(
alignment: Alignment.bottomLeft,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Obx(() {
return ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
messageController.model.type = 1;
await messageController.getMessageList();
messageController.updateAll();
},
child: Container(
width: 160.rpx,
alignment: Alignment.center,
child: Text(
'体征消息'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color:
messageController
.model.type ==
2
? themeController
.currentColor.sc3
: themeController
.currentColor.sc2,
),
),
),
);
}),
Obx(() {
return ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc3,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
messageController.model.type = 2;
await messageController.getMessageList();
messageController.updateAll();
},
child: Container(
width: 160.rpx,
alignment: Alignment.center,
child: Text(
'系统消息'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
color:
messageController
.model.type ==
1
? themeController
.currentColor.sc3
: themeController
.currentColor.sc2,
),
),
),
);
}),
],
),
Obx(() {
double lineWidth = 160.rpx;
return AnimatedPositioned(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
bottom: 0, // 👈 现在 Stack 够大,线能放得下
left: messageController.model.type == 1
? 0
: 160.rpx,
child: Container(
width: lineWidth,
height: 4.rpx,
decoration: BoxDecoration(
color: themeController.currentColor.sc2,
borderRadius: BorderRadius.circular(2.rpx),
),
),
);
}),
],
),
),
SizedBox(height: 17.rpx), // 上边距
],
),
),
),
actions: [],
centerTitle: false,
),
backgroundColor: Colors.transparent,
body: SafeArea(
top: true,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx,
0.rpx,
30.rpx,
0.rpx,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
MessageWidgetWidget(),
MessageWidgetWidget(),
MessageWidgetWidget(),
]
.divide(SizedBox(height: 30.rpx))
.addToStart(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(height: 30.rpx)),
),
),
),
),
),
],
),
),
),
),
),

View File

@@ -8,9 +8,11 @@ import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/main_bottom/global_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/LoginStatus.dart';
class MinePage extends StatefulWidget {
const MinePage({super.key});
@@ -30,6 +32,7 @@ class _MinePageState extends State<MinePage> {
statusBarColor: Colors.transparent, // 这里设置你希望的颜色
statusBarIconBrightness: Brightness.light, // 状态栏图标的亮度
));
int login = userInfoController.model.login!;
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
@@ -75,18 +78,6 @@ class _MinePageState extends State<MinePage> {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
SvgPicture.asset(
'assets/img/icon/earphone.svg',
width: 29.rpx,
height: 29.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController.currentColor.sc3,
),
// SvgPicture.asset(
// 'assets/img/icon/setting.svg',
// width: 29.rpx,
// height: 29.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController.currentColor.sc3,
// ),
ClickableContainer(
backgroundColor:
Colors.transparent, // 容器背景色
@@ -95,7 +86,53 @@ class _MinePageState extends State<MinePage> {
padding: EdgeInsets
.zero, // 这里去掉外部的 padding避免影响点击范围
onTap: () {
Get.toNamed("/settingPage");
if (userInfoController.model.login ==
LoginStatus.LOGIN.code) {
TopSlideNotification.show(
context,
text: "待开发功能".tr,
);
} else {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
}
},
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
child: SvgPicture.asset(
'assets/img/icon/earphone.svg',
width: 29.rpx,
height: 29.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController.currentColor.sc3,
),
),
),
ClickableContainer(
backgroundColor:
Colors.transparent, // 容器背景色
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsets
.zero, // 这里去掉外部的 padding避免影响点击范围
onTap: () {
if (userInfoController.model.login ==
LoginStatus.LOGIN.code) {
Get.toNamed("/settingPage");
} else {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
}
},
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
@@ -130,10 +167,25 @@ class _MinePageState extends State<MinePage> {
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.network(
'https://picsum.photos/seed/270/600',
fit: BoxFit.cover,
),
child: login == 1
? (userInfoController.model.user!
.avatar ==
null ||
userInfoController.model
.user!.avatar!.isEmpty
? Image.asset(
"assets/img/avatar.png",
fit: BoxFit.cover,
)
: Image.network(
userInfoController
.model.user!.avatar!,
fit: BoxFit.cover,
))
: Image.asset(
"assets/img/avatar.png",
fit: BoxFit.cover,
),
),
Column(
mainAxisSize: MainAxisSize.max,
@@ -141,7 +193,11 @@ class _MinePageState extends State<MinePage> {
CrossAxisAlignment.start,
children: [
Text(
'张天爱',
login == 1
? (userInfoController.model
.user!.nick_name ??
'未命名'.tr)
: "我的.未登录".tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -154,7 +210,16 @@ class _MinePageState extends State<MinePage> {
),
),
Text(
'账号135****2598',
login == 1
? (userInfoController.model
.user!.email !=
null
? userInfoController
.model.user!.email!
: MyUtils.hidePhoneNumber(
userInfoController.model
.user!.phone!))
: "我的.未登录".tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -173,7 +238,11 @@ class _MinePageState extends State<MinePage> {
CustomCard(
borderRadius: 0,
onTap: () {
Get.toNamed("/updateUserPage");
if (login == 1) {
Get.toNamed("/updateUserPage");
} else {
Get.toNamed("/loginPage");
}
},
// colors: [themeController.currentColor.sc5],
colors: [Colors.transparent],
@@ -181,7 +250,9 @@ class _MinePageState extends State<MinePage> {
mainAxisSize: MainAxisSize.max,
children: [
Text(
'我的.个人信息'.tr,
login == 1
? '我的.个人信息'.tr
: '我的.去登录'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -239,7 +310,20 @@ class _MinePageState extends State<MinePage> {
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
Get.toNamed("/deviceType",arguments:1);
UserInfoController userInfoController =
Get.find();
if (userInfoController.model.login !=
LoginStatus.LOGIN.code) {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
} else {
Get.toNamed("/deviceTypeList");
}
},
child: Container(
child: Padding(
@@ -296,7 +380,25 @@ class _MinePageState extends State<MinePage> {
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
onTap: () {
print('点击了容器');
UserInfoController userInfoController =
Get.find();
if (userInfoController.model.login !=
LoginStatus.LOGIN.code) {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
}
},
child: Container(
child: Padding(
@@ -353,7 +455,25 @@ class _MinePageState extends State<MinePage> {
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
onTap: () {
print('点击了容器');
UserInfoController userInfoController =
Get.find();
if (userInfoController.model.login !=
LoginStatus.LOGIN.code) {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
}
},
child: Container(
child: Padding(
@@ -410,7 +530,25 @@ class _MinePageState extends State<MinePage> {
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
UserInfoController userInfoController =
Get.find();
if (userInfoController.model.login !=
LoginStatus.LOGIN.code) {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
}
},
child: Container(
child: Padding(
@@ -467,7 +605,25 @@ class _MinePageState extends State<MinePage> {
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
UserInfoController userInfoController =
Get.find();
if (userInfoController.model.login !=
LoginStatus.LOGIN.code) {
TopSlideNotification.show(
context,
text: "必须登录提示".tr,
textColor:
themeController.currentColor.sc9,
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
}
},
child: Container(
child: Padding(
@@ -508,7 +664,7 @@ class _MinePageState extends State<MinePage> {
mainAxisSize: MainAxisSize.max,
children: [
Text(
'1.0.0',
'V1.0.2504.12',
style:
FlutterFlowTheme.of(context)
.bodyMedium

View File

@@ -1,31 +1,31 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
// import 'package:ef/ef.dart';
// import 'package:flutter/material.dart';
// import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
// import 'package:vbvs_app/controller/user_info_controller.dart';
class SleepReportPage extends StatefulWidget {
const SleepReportPage({super.key});
// class SleepReportPage extends StatefulWidget {
// const SleepReportPage({super.key});
@override
State<SleepReportPage> createState() => _SleepReportPageState();
}
// @override
// State<SleepReportPage> createState() => _SleepReportPageState();
// }
class _SleepReportPageState extends State<SleepReportPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, boxConstraints) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
// class _SleepReportPageState extends State<SleepReportPage> {
// GlobalController globalController = Get.find();
// UserInfoController userInfoController = Get.find();
// @override
// Widget build(BuildContext context) {
// return LayoutBuilder(
// builder: (context, boxConstraints) => GestureDetector(
// onTap: () => FocusScope.of(context).unfocus(),
// child: Scaffold(
body: SafeArea(
top: true,
child: Text("睡眠报告"),
),
),
),
);
}
}
// body: SafeArea(
// top: true,
// child: Text("睡眠报告"),
// ),
// ),
// ),
// );
// }
// }

View File

@@ -1,15 +1,20 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.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/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/model/api_response.dart';
import 'package:vbvs_app/pages/person/select_time.dart';
class PersonPage extends StatefulWidget {
@@ -29,6 +34,12 @@ class _EPageState extends State<PersonPage> {
@override
void initState() {
super.initState();
personController.selectedDiseaseIds.value = [];
personController.name.value = '';
personController.gender.value = 1;
personController.birthday.value = "";
personController.weight.value = 65;
personController.dateTime = null;
}
@override
@@ -45,7 +56,7 @@ class _EPageState extends State<PersonPage> {
),
child: Scaffold(
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(
@@ -80,7 +91,17 @@ class _EPageState extends State<PersonPage> {
child: CustomCard(
borderRadius: 20.rpx,
onTap: () async {
Get.offAllNamed("/bindDeviceSuccess");
ApiResponse apiRespons =
await personController.savePersonData();
if (apiRespons.code == HttpStatusCodes.ok) {
TopSlideNotification.show(context,
text: apiRespons.msg!);
Get.offAllNamed("/bindDeviceSuccess");
} else {
TopSlideNotification.show(context,
text: apiRespons.msg!,
textColor: themeController.currentColor.sc9);
}
},
colors: [
themeController.currentColor.sc1,
@@ -138,6 +159,10 @@ class _EPageState extends State<PersonPage> {
child: TextFormField(
// controller: _model.textController1,
// focusNode: _model.textFieldFocusNode1,
initialValue: personController.name.value,
onChanged: (Value) {
personController.name.value = Value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
@@ -218,69 +243,201 @@ class _EPageState extends State<PersonPage> {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/man.png",
fit: BoxFit.cover,
),
),
),
Text(
'',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: 26.rpx,
letterSpacing: 0.0,
// Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 90.rpx,
// height: 90.rpx,
// decoration: BoxDecoration(),
// child: Container(
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// child: ColorFiltered(
// colorFilter: ColorFilter.mode(
// Colors.grey.withOpacity(
// 0.6), // 这里控制灰色度的强度
// BlendMode.saturation, // 将图像变成灰度
// ),
// child: Image.asset(
// "assets/img/man.png",
// fit: BoxFit.cover,
// ),
// ),
// ),
// ),
// Text(
// '男'.tr,
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(height: 14.rpx)),
// ),
// Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 90.rpx,
// height: 90.rpx,
// decoration: BoxDecoration(),
// child: Container(
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// child: Image.asset(
// "assets/img/woman.png",
// fit: BoxFit.cover,
// ),
// ),
// ),
// Text(
// '女'.tr,
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(height: 14.rpx)),
// ),
Obx(
() {
bool isMaleGreyed =
personController.gender.value ==
0; // gender == 0 时男生部分变灰
return GestureDetector(
onTap: () {
personController.gender.value =
1; // 点击时将 gender 设置为 1女生部分被选中
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: ColorFiltered(
colorFilter: isMaleGreyed
? ColorFilter.mode(
Colors.grey
.withOpacity(0.6),
BlendMode.saturation)
: ColorFilter.mode(
Colors.transparent,
BlendMode.saturation),
child: Image.asset(
"assets/img/man.png",
fit: BoxFit.cover,
),
),
),
),
),
].divide(SizedBox(height: 14.rpx)),
Text(
''.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: isMaleGreyed
? themeController
.currentColor
.sc4
: themeController
.currentColor
.sc3,
),
),
].divide(SizedBox(height: 14.rpx)),
),
);
},
),
Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/woman.png",
fit: BoxFit.cover,
),
),
),
Text(
'',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: 26.rpx,
letterSpacing: 0.0,
// 女性部分
Obx(
() {
bool isFemaleGreyed =
personController.gender.value ==
1; // gender == 1 时女生部分变灰
return GestureDetector(
onTap: () {
personController.gender.value =
0; // 点击时将 gender 设置为 0男生部分被选中
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: ColorFiltered(
colorFilter: isFemaleGreyed
? ColorFilter.mode(
Colors.grey
.withOpacity(0.6),
BlendMode.saturation)
: ColorFilter.mode(
Colors.transparent,
BlendMode.saturation),
child: Image.asset(
"assets/img/woman.png",
fit: BoxFit.cover,
),
),
),
),
),
].divide(SizedBox(height: 14.rpx)),
Text(
''.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
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)),
),
@@ -303,10 +460,12 @@ class _EPageState extends State<PersonPage> {
Future.delayed(Duration(milliseconds: 250), () {
showDateSelectionDialog(
context,
checkDate: personController.model.birthday ??
checkDate: personController.dateTime ??
DateTime.now(),
checkChange: (DateTime d) {
personController.model.birthday = d;
personController.birthday.value =
MyUtils.formatBindTime(d);
personController.dateTime = d;
personController.updateAll();
},
);
@@ -314,17 +473,16 @@ class _EPageState extends State<PersonPage> {
},
child: Center(
child: Text(
personController.model.birthday != null
? DateFormat("yyyy年MM月dd日").format(
personController.model.birthday!)
personController.dateTime != null
? DateFormat("yyyy年MM月dd日")
.format(personController.dateTime!)
: '人员资料.生日输入提示'.tr,
textAlign: TextAlign.right,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Readex Pro',
color: personController.model.birthday !=
null
color: personController.dateTime != null
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize:
@@ -350,75 +508,103 @@ class _EPageState extends State<PersonPage> {
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: TextFormField(
// controller: _model.textController3,
// focusNode: _model.textFieldFocusNode3,
autofocus: false,
obscureText: false,
decoration: InputDecoration(
fillColor: Colors.transparent,
isDense: true,
labelStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
child: Stack(
alignment: Alignment.center,
children: [
// 实际输入框(输入逻辑保留)
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
initialValue:
personController.weight.value.toString(),
onChanged: (value) {
personController.weight.value =
int.tryParse(value) ?? 0;
},
autofocus: false,
obscureText: false,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Colors.transparent, // 隐藏输入文字
letterSpacing: 0.0,
),
textAlign: TextAlign.center,
cursorColor:
FlutterFlowTheme.of(context).primaryText,
decoration: InputDecoration(
fillColor: Colors.transparent,
isDense: true,
hintText: '人员资料.体重输入提示'.tr,
hintStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
color:
themeController.currentColor.sc4,
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
hintText: '人员资料.体重输入提示'.tr,
hintStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
color: personController.model.weight !=
null
? themeController.currentColor.sc3
: themeController.currentColor.sc4,
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0.0,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
filled: true,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
filled: true,
),
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
textAlign: TextAlign.center,
cursorColor:
FlutterFlowTheme.of(context).primaryText,
// validator: _model.textController3Validator
// .asValidator(context),
Obx(() {
final weight = personController.weight.value;
return weight == 0
? const SizedBox.shrink() // 不显示任何内容
: Text(
'${weight}kg',
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.normal_text_fontSize,
),
);
}),
],
),
),
),
@@ -445,14 +631,38 @@ class _EPageState extends State<PersonPage> {
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
70.rpx, 70.rpx, 70.rpx, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
),
),
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 (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, 152.rpx, 0, 0),

View File

@@ -0,0 +1,774 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.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/model/api_response.dart';
import 'package:vbvs_app/pages/person/select_time.dart';
class UpdatePersonPage extends StatefulWidget {
const UpdatePersonPage({super.key});
@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();
@override
void initState() {
super.initState();
personController.getDiseaseData().then((apiResponse) {
TopSlideNotification.show(
Get.context!,
text: apiResponse.msg!,
textColor: apiResponse.code != HttpStatusCodes.ok
? themeController.currentColor.sc9
: themeController.currentColor.sc2,
);
});
}
@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(
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: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
child: returnIconButtomAddCallback(() {
bodyDeviceController.getDeviceList();
bodyDeviceController.updateAll();
}),
),
Positioned(
right: 20.rpx,
child: CustomCard(
borderRadius: 20.rpx,
onTap: () async {
ApiResponse apiRespons =
await personController.savePersonData();
if (apiRespons.code == HttpStatusCodes.ok) {
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: FlutterFlowTheme.of(context)
.titleSmall
.override(
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: 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: Color(0xFFF3EDED),
),
),
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: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
hintText: '人员资料.名字输入提示'.tr,
hintStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
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(
color: FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius: BorderRadius.circular(8.rpx),
),
filled: true,
),
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
textAlign: TextAlign.center,
cursorColor:
FlutterFlowTheme.of(context).primaryText,
// 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: [
// Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 90.rpx,
// height: 90.rpx,
// decoration: BoxDecoration(),
// child: Container(
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// child: ColorFiltered(
// colorFilter: ColorFilter.mode(
// Colors.grey.withOpacity(
// 0.6), // 这里控制灰色度的强度
// BlendMode.saturation, // 将图像变成灰度
// ),
// child: Image.asset(
// "assets/img/man.png",
// fit: BoxFit.cover,
// ),
// ),
// ),
// ),
// Text(
// '男'.tr,
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(height: 14.rpx)),
// ),
// Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 90.rpx,
// height: 90.rpx,
// decoration: BoxDecoration(),
// child: Container(
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// child: Image.asset(
// "assets/img/woman.png",
// fit: BoxFit.cover,
// ),
// ),
// ),
// Text(
// '女'.tr,
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(height: 14.rpx)),
// ),
Obx(
() {
bool isMaleGreyed =
personController.gender.value ==
0; // gender == 0 时男生部分变灰
return GestureDetector(
onTap: () {
personController.gender.value =
1; // 点击时将 gender 设置为 1女生部分被选中
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: ColorFiltered(
colorFilter: isMaleGreyed
? ColorFilter.mode(
Colors.grey
.withOpacity(0.6),
BlendMode.saturation)
: ColorFilter.mode(
Colors.transparent,
BlendMode.saturation),
child: Image.asset(
"assets/img/man.png",
fit: BoxFit.cover,
),
),
),
),
Text(
''.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
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: () {
personController.gender.value =
0; // 点击时将 gender 设置为 0男生部分被选中
},
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: ColorFiltered(
colorFilter: isFemaleGreyed
? ColorFilter.mode(
Colors.grey
.withOpacity(0.6),
BlendMode.saturation)
: ColorFilter.mode(
Colors.transparent,
BlendMode.saturation),
child: Image.asset(
"assets/img/woman.png",
fit: BoxFit.cover,
),
),
),
),
Text(
''.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
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: Color(0xFFF3EDED)),
),
child: InkWell(
onTap: () {
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();
},
);
});
},
child: Center(
child: Text(
personController.dateTime != null
? DateFormat("yyyy年MM月dd日")
.format(personController.dateTime!)
: '人员资料.生日输入提示'.tr,
textAlign: TextAlign.right,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
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, 18.rpx, 70.rpx, 0),
child: Container(
width: double.infinity,
height: 100.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50.rpx),
border: Border.all(
color: Color(0xFFF3EDED),
),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Stack(
alignment: Alignment.center,
children: [
// 实际输入框(输入逻辑保留)
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
initialValue:
personController.weight.value.toString(),
onChanged: (value) {
personController.weight.value =
int.tryParse(value) ?? 0;
},
autofocus: false,
obscureText: false,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Colors.transparent, // 隐藏输入文字
letterSpacing: 0.0,
),
textAlign: TextAlign.center,
cursorColor:
FlutterFlowTheme.of(context).primaryText,
decoration: InputDecoration(
fillColor: Colors.transparent,
isDense: true,
hintText: '人员资料.体重输入提示'.tr,
hintStyle: FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
color:
themeController.currentColor.sc4,
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
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(
color:
FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
FlutterFlowTheme.of(context).error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(8.rpx),
),
filled: true,
),
),
Obx(() {
final weight = personController.weight.value;
return weight == 0
? const SizedBox.shrink() // 不显示任何内容
: Text(
'${weight}kg',
textAlign: TextAlign.center,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.normal_text_fontSize,
),
);
}),
],
),
),
),
),
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: FlutterFlowTheme.of(context)
.bodyMedium
.override(
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 (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, 152.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.rpx),
border: Border.all(
color: Color(0xFFE9E3E3),
),
),
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: Icon(
Icons.arrow_back,
color: Color(0xFFE4EBF0),
size: 24.rpx,
),
),
Expanded(
child: Text(
'人员资料.提示'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFEEF3F8),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
].divide(SizedBox(width: 23.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: FlutterFlowTheme.of(context).bodyMedium.override(
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,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,190 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/component/tool/WebViewWidget.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/device/device_type_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class SleepReportPage extends StatefulWidget {
var sleepUri;
SleepReportPage({super.key, required this.sleepUri});
@override
State<SleepReportPage> createState() => _SleepReportPageState();
}
class _SleepReportPageState extends State<SleepReportPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
@override
void initState() {
super.initState();
}
@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(
backgroundColor: Colors.transparent, // 加上这一行
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
// backgroundColor: Colors.transparent,
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: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: InAppWebView(
key: UniqueKey(),
initialUrlRequest: URLRequest(url: WebUri(widget.sleepUri)),
),
// child: WebViewWidget(url: "${widget.sleepUri}"),
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
// child: SingleChildScrollView(
// child: Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// // 使用 Obx 来监听 deviceTypeList 的变化
// Obx(() {
// return Column(
// children: [
// SizedBox(height: 26.rpx), // 开始的间隔
// ...deviceTypeController.deviceTypeList.value
// .map((device) {
// return Padding(
// padding: EdgeInsets.only(
// bottom: 26.rpx), // 添加每个设备之间的间隔
// child: _buildDeviceCard(
// context,
// title: device['name'], // 这里假设 device 是一个 Map
// imageUrl: device['image'],
// type: device['type'],
// ),
// );
// }).toList(),
// SizedBox(height: 26.rpx), // 结束的间隔
// ],
// );
// }),
// ],
// ),
// ),
// ),
),
),
),
),
);
}
Widget _buildDeviceCard(BuildContext context,
{required String title, required String imageUrl, required double type}) {
return CustomCard(
borderRadius: 20.rpx, // 圆角大小
onTap: () {
if (type != null) {
if (type == 1) {
Get.toNamed("/bodyDevice");
}
if (type == 2) {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor: themeController.currentColor.sc2,
);
}
}
},
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: FlutterFlowTheme.of(context).bodyMedium.override(
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,
// ),
child: Image.network(
imageUrl,
// fit: BoxFit.cover,
width: 212.rpx,
height: 168.rpx,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,470 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
// import 'package:easydevice/easydevice.dart';
class AboutUsPage extends StatefulWidget {
const AboutUsPage({super.key});
@override
State<AboutUsPage> createState() => _AboutUsPageState();
}
class _AboutUsPageState extends State<AboutUsPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
@override
void initState() {
super.initState();
}
@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(
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: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 30.rpx, 25.rpx, 30.rpx, 0),
// child: Container(
// width: double.infinity,
// decoration: BoxDecoration(
// color: Color(0xFF242835),
// borderRadius: BorderRadius.circular(
// AppConstants().normal_container_radius),
// ),
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 0, 0.rpx, 0),
// child: Column(
// mainAxisSize: MainAxisSize.max,
// children: [
// ClickableContainer(
// backgroundColor: Colors.transparent, // 容器背景色
// highlightColor: themeController
// .currentColor.sc21, // 点击时的背景色
// padding: EdgeInsetsDirectional.fromSTEB(
// 40.rpx, 0.rpx, 40.rpx, 0.rpx),
// onTap: () {
// print('点击了容器');
// },
// child: Container(
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 20.rpx, 0.rpx, 20.rpx),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '设置页.主题模式'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: AppConstants()
// .title_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(width: 22.rpx)),
// ),
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '深色',
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color:
// Color(0xFFD9E3EB),
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// ),
// ),
// SvgPicture.asset(
// 'assets/img/icon/arrow_right.svg',
// width: 8.rpx,
// height: 15
// .rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController
// .currentColor.sc3,
// ),
// ].divide(SizedBox(width: 28.rpx)),
// ),
// ],
// ),
// ),
// ),
// ),
// ClickableContainer(
// backgroundColor: Colors.transparent, // 容器背景色
// highlightColor: themeController
// .currentColor.sc21, // 点击时的背景色
// padding: EdgeInsetsDirectional.fromSTEB(
// 40.rpx, 0.rpx, 40.rpx, 0.rpx),
// onTap: () {
// print('点击了容器');
// },
// child: Container(
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 20.rpx, 0.rpx, 20.rpx),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '设置页.选择语言'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: AppConstants()
// .title_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(width: 22.rpx)),
// ),
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '中文',
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color:
// Color(0xFFD9E3EB),
// fontSize: 26.rpx,
// letterSpacing: 0.0,
// ),
// ),
// SvgPicture.asset(
// 'assets/img/icon/arrow_right.svg',
// width: 8.rpx,
// height: 15
// .rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController
// .currentColor.sc3,
// ),
// ].divide(SizedBox(width: 28.rpx)),
// ),
// ],
// ),
// ),
// ),
// ),
// ClickableContainer(
// backgroundColor: Colors.transparent, // 容器背景色
// highlightColor: themeController
// .currentColor.sc21, // 点击时的背景色
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 0.rpx, 0.rpx, 0.rpx),
// onTap: () {
// print('点击了容器');
// },
// child: Container(
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 40.rpx, 20.rpx, 40.rpx, 20.rpx),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '设置页.关于我们'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: AppConstants()
// .title_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(width: 22.rpx)),
// ),
// SvgPicture.asset(
// 'assets/img/icon/arrow_right.svg',
// width: 8.rpx,
// height:
// 14.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// ),
// ),
// ),
// ClickableContainer(
// backgroundColor: Colors.transparent, // 容器背景色
// highlightColor: themeController
// .currentColor.sc21, // 点击时的背景色
// padding: EdgeInsetsDirectional.fromSTEB(
// 40.rpx, 0.rpx, 40.rpx, 0.rpx),
// onTap: () {
// print('点击了容器');
// },
// child: Container(
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 20.rpx, 0.rpx, 20.rpx),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '设置页.用户协议'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: AppConstants()
// .title_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(width: 22.rpx)),
// ),
// SvgPicture.asset(
// 'assets/img/icon/arrow_right.svg',
// width: 8.rpx,
// height:
// 15.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// ),
// ),
// ),
// ClickableContainer(
// backgroundColor: Colors.transparent, // 容器背景色
// highlightColor: themeController
// .currentColor.sc21, // 点击时的背景色
// padding: EdgeInsetsDirectional.fromSTEB(
// 0.rpx, 0.rpx, 0.rpx, 0.rpx),
// onTap: () {
// print('点击了容器');
// },
// child: Container(
// child: Padding(
// padding: EdgeInsetsDirectional.fromSTEB(
// 40.rpx, 20.rpx, 40.rpx, 20.rpx),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Text(
// '设置页.隐私协议'.tr,
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Inter',
// color: themeController
// .currentColor.sc3,
// fontSize: AppConstants()
// .title_text_fontSize,
// letterSpacing: 0.0,
// ),
// ),
// ].divide(SizedBox(width: 22.rpx)),
// ),
// SvgPicture.asset(
// 'assets/img/icon/arrow_right.svg',
// width: 8.rpx,
// height:
// 14.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// color: themeController
// .currentColor.sc3,
// ),
// ],
// ),
// ),
// ),
// ),
// ]
// .divide(SizedBox(height: 0.rpx))
// .addToStart(SizedBox(height: 30.rpx))
// .addToEnd(SizedBox(height: 30.rpx)),
// ),
// ),
// ),
// ),
SizedBox(
height: 30.rpx,
),
Text(
"企业简介\n\n\n嘉兴太和信息技术有限公司成立于2013年是一家以传感技术、室内定位技术和人工智能技术为基础的国家高新技术企业AI非接触生命体征传感器、高精度室内外一体定位平台、AI视频分析系统、射频消融等技术成果目前已经拥有30多类知识产权证书多项专利技术处于行业领先水平。\n\n\n我司研发的“非接触式生命体征传感器”是一款基于BCG信号原理通过检测人体心脏搏动引起的微小振动的传感器系统。传感器系统通过将人体微弱的心跳、呼吸信号转换未电信号进行相关生命体征分析。该传感器可为用户提供高灵敏度和精确度检测结构适用于需要非接触式、高分辨率的监测场景。该系统的硬件、软件及生产维护均由我司自主开发和管理拥有完全自主知识产权并已申请多项国家专利可依据用户需求定制个性化方案。\n\n\n该产品置于床垫下方使用全程完全无感。采集的体征数据通过睡眠健康管理平台实时显示用户的健康状态并对每次的睡眠报告进行系统化归档管理支持长期查询。一旦用户在使用过程中出现异常情况系统可及时做出判断并反馈预警信息和建议。目前心率监测的准确度可达97%以上呼吸监测的准确度可达95%以上,其他生理指标的监测精度也显著优于同类产品。该产品主体材质均采用符合国家标准的环保材料,部分硅胶配件达到食品级安全标准。产品尺寸可根据需求进行定制,适用于单人床、双人床、婴儿床、椅子及枕头等多种场景。\n\n\n睡眠健康管理平台通过实时预警与远程管理,提升睡眠质量及慢病干预效率,助力养老院、月子中心、康复中心、智能寝具等行业降本增效,实现精准健康的科学管理。",
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3),
),
],
),
),
),
),
),
),
),
);
}
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: FlutterFlowTheme.of(context).bodyMedium.override(
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,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,623 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
class SettingPage extends StatefulWidget {
const SettingPage({super.key});
@override
State<SettingPage> createState() => _SettingPageState();
}
class _SettingPageState extends State<SettingPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
@override
void initState() {
super.initState();
}
@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(
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: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 25.rpx, 30.rpx, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF242835),
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0, 0.rpx, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'设置页.主题模式'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'深色',
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color:
Color(0xFFD9E3EB),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 15
.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController
.currentColor.sc3,
),
].divide(SizedBox(width: 28.rpx)),
),
],
),
),
),
),
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'设置页.选择语言'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'中文',
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color:
Color(0xFFD9E3EB),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 15
.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController
.currentColor.sc3,
),
].divide(SizedBox(width: 28.rpx)),
),
],
),
),
),
),
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
onTap: () {
print('点击了容器');
Get.toNamed("/aboutUsPage");
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'设置页.关于我们'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height:
14.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController
.currentColor.sc3,
),
],
),
),
),
),
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'设置页.用户协议'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height:
15.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController
.currentColor.sc3,
),
],
),
),
),
),
ClickableContainer(
backgroundColor: Colors.transparent, // 容器背景色
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
onTap: () {
print('点击了容器');
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'设置页.隐私协议'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height:
14.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
color: themeController
.currentColor.sc3,
),
],
),
),
),
),
]
.divide(SizedBox(height: 0.rpx))
.addToStart(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(height: 30.rpx)),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 360.rpx, 100.rpx, 0),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () {
ApiResponse apiResponse =
userInfoController.logOut();
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: apiResponse.code == HttpStatusCodes.ok
? themeController.currentColor.sc2
: themeController.currentColor.sc9,
);
if (apiResponse.code == HttpStatusCodes.ok) {
Get.offAllNamed("/mianPageBottomChange");
}
},
colors: [
themeController.currentColor.sc9,
], // 渐变色是同一个色,也可以根据需要调整
child: Container(
width:
// MediaQuery.sizeOf(context).width * 0.66,
bodySize.maxWidth,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'设置页.退出登录'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color: themeController.currentColor.sc3,
fontFamily: 'Inter',
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
width: 17.rpx,
)),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 20.rpx, 100.rpx, 0),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () {
TopSlideNotification.show(
context,
text: "待开发功能".tr,
);
},
colors: [
Colors.transparent,
], // 渐变色是同一个色,也可以根据需要调整
child: Container(
width:
// MediaQuery.sizeOf(context).width * 0.66,
bodySize.maxWidth,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'设置页.注销账号'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color: themeController.currentColor.sc9,
fontFamily: 'Inter',
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
width: 17.rpx,
)),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 100.rpx, 0.rpx, 0),
child: ClickableContainer(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () {},
backgroundColor:
Colors.transparent, // 渐变色是同一个色,也可以根据需要调整
highlightColor: themeController.currentColor.sc5,
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0),
child: Container(
width:
// MediaQuery.sizeOf(context).width * 0.66,
bodySize.maxWidth,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'ICP备案号:浙ICP备2023000785号-1'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color:
themeController.currentColor.sc4,
fontFamily: 'Inter',
fontSize: AppConstants()
.smaller_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
'Copyright © 202-2025 嘉兴太和信息技术有限责任公司 版权所有'
.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
color:
themeController.currentColor.sc4,
fontFamily: 'Inter',
fontSize: AppConstants()
.smaller_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
height: 17.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: FlutterFlowTheme.of(context).bodyMedium.override(
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,
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,367 @@
import 'dart:io';
import 'package:EasyDartModule/EasyDartModule.dart' as edm;
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/component/tool/CustomCard.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_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/model/api_response.dart';
class UpdateUserPage extends StatefulWidget {
const UpdateUserPage({super.key});
@override
State<UpdateUserPage> createState() => _UpdateUserPageState();
}
class _UpdateUserPageState extends State<UpdateUserPage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
PersonController personController = Get.find();
ThemeController themeController = Get.find();
@override
void initState() {
super.initState();
userInfoController.model.user!.tmpHead = null;
userInfoController.model.user!.tmpNickName = null;
userInfoController.model.user!.tmpHead =
userInfoController.model.user!.avatar;
userInfoController.model.user!.tmpNickName =
userInfoController.model.user!.nick_name;
}
@override
Widget build(BuildContext context) {
int login = userInfoController.model.login!;
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,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(
color: themeController.currentColor.sc3,
),
titleSpacing: 0,
title: Container(
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
Text(
'修改资料页.个人信息'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
letterSpacing: 0,
fontSize: 30.rpx,
),
),
Positioned(
left: 0,
child: returnIconButtom,
),
Positioned(
right: 20.rpx,
child: CustomCard(
borderRadius: 20.rpx,
onTap: () async {
ApiResponse apiResponse =
await userInfoController.updateData();
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: apiResponse.code == HttpStatusCodes.ok
? themeController.currentColor.sc2
: themeController.currentColor.sc9,
);
if (apiResponse.code == HttpStatusCodes.ok) {
userInfoController.model.user!.tmpHead = null;
userInfoController.model.user!.tmpNickName = null;
await userInfoController.getUserInfo();
Get.back();
}
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: 100.rpx,
height: 60.rpx,
alignment: Alignment.center,
padding: EdgeInsetsDirectional.fromSTEB(
16.rpx, 0.rpx, 16.rpx, 0.rpx),
child: Text(
'修改资料页.保存'.tr,
style: FlutterFlowTheme.of(context)
.titleSmall
.override(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
),
),
),
),
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
60.rpx, 0.rpx, 60.rpx, 0.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 76.rpx, 0.rpx, 0.rpx),
child: Container(
width: MediaQuery.sizeOf(context).width * 0.213,
height: MediaQuery.sizeOf(context).height * 0.098,
constraints: BoxConstraints(
minWidth: 160.rpx,
minHeight: 160.rpx,
),
decoration: BoxDecoration(),
child: Obx(() {
return getImageWidget(context);
})),
),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: themeController.currentColor.sc2,
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 44.rpx, 0.rpx, 44.rpx),
borderRadius: 0,
onTap: () async {
edm.EasyDartModule.logger
.info("${userInfoController.model.user!}点击上传头像");
DailyLogUtils.writeLog(
"${userInfoController.model.user!}点击上传头像");
ApiResponse apiResponse =
await userInfoController.uploadImg();
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: apiResponse.code == HttpStatusCodes.ok
? themeController.currentColor.sc2
: themeController.currentColor.sc9,
);
},
child: Center(
child: Text(
'修改资料页.点击更换头像'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc2,
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 79.rpx, 0.rpx, 0.rpx),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Color(0xFFF8F5F5),
width: 1.rpx,
),
bottom: BorderSide(
color: Color(0xFFF8F5F5),
width: 1.rpx,
),
),
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Container(
width: 100.rpx,
height: 100.rpx,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: TextFormField(
initialValue: userInfoController
.model.user!.nick_name,
onChanged: (value) {
userInfoController.model.user!
.tmpNickName = value;
},
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle:
FlutterFlowTheme.of(context)
.labelMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
hintText: '未命名'.tr,
hintStyle:
FlutterFlowTheme.of(context)
.labelMedium
.override(
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(
color: FlutterFlowTheme.of(
context)
.error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
focusedErrorBorder:
OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(
context)
.error,
width: 1.rpx,
),
borderRadius:
BorderRadius.circular(
8.rpx),
),
filled: false,
),
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
textAlign: TextAlign.center,
cursorColor:
FlutterFlowTheme.of(context)
.primaryText,
),
),
),
),
].divide(SizedBox(width: 27.rpx)),
),
),
],
),
),
),
],
),
),
),
),
),
),
),
);
}
Widget getImageWidget(BuildContext context) {
try {
UserInfoController controller = Get.find();
var head = controller.model.user!.tmpHead;
return Container(
width: 200.rpx,
height: 200.rpx,
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: head == null || head.isEmpty
? Image.asset(
'assets/img/avatar.png',
fit: BoxFit.cover,
)
: Image.network(
head,
fit: BoxFit.cover,
),
),
);
} catch (e) {
print(e);
}
return Container();
}
}

View File

@@ -1,7 +1,13 @@
import 'package:flutter/cupertino.dart';
import 'package:vbvs_app/pages/device/BodyDeviceWidget.dart';
import 'package:vbvs_app/pages/device/device_detail.dart';
import 'package:vbvs_app/pages/device/instant_body_page.dart';
import 'package:vbvs_app/pages/device_bind/MobileScannerTestPage.dart';
import 'package:vbvs_app/pages/device_bind/bind_device_success.dart';
import 'package:vbvs_app/pages/device_bind/blueteeth_device_page.dart';
import 'package:vbvs_app/pages/device_bind/device_share_page.dart';
import 'package:vbvs_app/pages/device_bind/device_type.dart';
import 'package:vbvs_app/pages/device_bind/device_type_list.dart';
import 'package:vbvs_app/pages/device_bind/wifi_page.dart';
import 'package:vbvs_app/pages/login/login.dart';
import 'package:vbvs_app/pages/login/other_login.dart';
@@ -10,8 +16,9 @@ import 'package:vbvs_app/pages/main_bottom/home_page.dart';
import 'package:vbvs_app/pages/main_bottom/main_page_bottom_change.dart';
import 'package:vbvs_app/pages/main_bottom/message_page.dart';
import 'package:vbvs_app/pages/main_bottom/mine_page.dart';
import 'package:vbvs_app/pages/main_bottom/sleep_report_page.dart';
import 'package:vbvs_app/pages/person/person_page.dart';
import 'package:vbvs_app/pages/person/update_person_page.dart';
import 'package:vbvs_app/pages/sleep_report/sleep_report_page.dart';
import 'package:vbvs_app/pages/user/about_us_page.dart';
import 'package:vbvs_app/pages/user/setting_page.dart';
import 'package:vbvs_app/pages/user/update_user_page.dart';
@@ -21,22 +28,28 @@ import 'package:vbvs_app/pages/user/update_user_page.dart';
var routes = {
"/homePage": (contxt) => HomePage(),
"/sleepReportPage": (contxt) => SleepReportPage(),
"/sleepReportPage": (contxt,{arguments}) => SleepReportPage(sleepUri:arguments),
"/ePage": (contxt) => EPage(),
"/messagePage": (contxt) => MessagePage(),
"/minePage": (contxt) => MinePage(),
"/mianPageBottomChange": (contxt) => MainPageBottomChange(),
"/loginPage": (contxt) => LoginPage(),
"/deviceType": (contxt, {arguments}) => DeviceTypePage(type: arguments??0,),
"/deviceType": (contxt, {arguments}) => DeviceTypePage(),
"/blueteethDevice": (contxt) => BlueteethDevicePage(),
"/personPage": (contxt) => PersonPage(),
"/bindDeviceSuccess": (contxt) => BindDeviceSuccess(),
"/wifiPage": (contxt, {arguments}) => WifiPage(bleDevice: arguments),
// "/wifiPage": (contxt) => WifiPage(),
"/wifiPage": (contxt) => WifiPage(),
"/otherLoginPage": (contxt) => OtherLoginPage(),
"/updateUserPage": (contxt) => UpdateUserPage(),
"/settingPage": (contxt) => SettingPage(),
"/aboutUsPage": (contxt) => AboutUsPage(),
"/bodyDevice": (contxt) => BodyDeviceWidget(),
"/deviceTypeList": (contxt) => DeviceTypeListPage(),
"/deviceDetail": (contxt,{arguments}) => DeviceDetailPage(device:arguments),
"/instantBodyPage": (contxt,{arguments}) => InstantBodyPage(personInfo:arguments),
"/qrView": (contxt) => MobileScannerTestPage(),
"/updatePersonPage": (contxt) => UpdatePersonPage(),
"/deviceSharePage": (contxt,{arguments}) => DeviceSharePage(device:arguments),
};
//2、配置onGenerateRoute 固定写法 这个方法也相当于一个中间件,这里可以做权限判断