This commit is contained in:
wyf
2025-05-13 11:59:04 +08:00
parent eae7a2284d
commit fb5c3864a3
101 changed files with 8427 additions and 1953 deletions

View File

@@ -16,8 +16,14 @@ class ServiceConstant {
static String sleep_report = "/api/device/sleep/data";//睡眠报告
static String device_share = "/api/device/share";//分享设备
static String message_list = "/api/mesasge/list";//消息列表
static String message_read = "/api/mesasge/read";//消息未读数量
static String device_show = "/api/device/bind";//更新设备绑定
static String disease_list = "/api/personnel/disease/list";//获取疾病类型
static String share_deleted = "";//删除分享
static String start_calibration = "";//开始校准
static String calibration_process = "";//校准进度
static String submit_repair = "";//提交报修

View File

@@ -23,4 +23,8 @@ class AppConstants {
double small_text_fontSize = 20.rpx; //普通文字字号
double normal_text_fontSize = 26.rpx; //普通文字字号
double title_text_fontSize = 30.rpx; //标题文字字号
double dropdown_height = 90.rpx; //标题文字字号
}

View File

@@ -1,32 +0,0 @@
// lib/api_endpoints.dart
import 'package:vbvs_app/common/util/CommonVariables.dart';
class ApiEndpoints {
// Base URL of the API
static String baseUrl = '${CommonVariables.apiUrl}/api';
// Endpoints
static String signIn = '$baseUrl/auth/account/info/signIn'; //登录
static String getUserInfo = '$baseUrl/user/info'; //获取用户信息
static String updateProfile = '$baseUrl/user/updateProfile'; //更新用户信息
static String login_code = '$baseUrl/auth/msg/signIn'; //登录验证码
static String wx_auth_code = '$baseUrl/auth/msg/wxAuth'; //微信授权验证码
static String register = '$baseUrl/auth/account/info/signUp'; //注册
static String reset_code = '$baseUrl/auth/msg/restore'; //重置验证码
static String reset_pd = '$baseUrl/auth/account/info/restore/pw'; //重置密码
static String updateUserInfo =
'$baseUrl/auth/account/info/nameAndHead'; //更新用户资料
static String autoLogin = '$baseUrl/auth/account/info/autoLogin'; //自动登录
//订单管理
static String orderList = "/api/order/info/list"; //订单列表
static String orderQianshou = "/api/order/info/get"; //签收
//分享设备
static String deviceInvite = '$baseUrl/api/device/info/share'; //分享设备
// Add more endpoints as needed
//添加/床垫控制日志
static String addLog = '$baseUrl/oplog/add';
}

View File

@@ -0,0 +1,99 @@
import 'dart:async';
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:ef/ef.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class Checknetwork {
static final Connectivity _connectivity = Connectivity();
static StreamSubscription<List<ConnectivityResult>>? subscription;
static bool isShowDialog = false;
static connectivityResultChange(connectivityResult) {
if (connectivityResult.contains(ConnectivityResult.mobile)) {
print("ConnectivityResult:Mobile network available.");
// Mobile network available.
toInitData();
} else if (connectivityResult.contains(ConnectivityResult.wifi)) {
print("ConnectivityResult:Wi-fi is available.");
toInitData();
// Wi-fi is available.
// Note for Android:
// When both mobile and Wi-Fi are turned on system will return Wi-Fi only as active network type
} else if (connectivityResult.contains(ConnectivityResult.ethernet)) {
print("ConnectivityResult:Ethernet connection available.");
toInitData();
// Ethernet connection available.
} else if (connectivityResult.contains(ConnectivityResult.vpn)) {
print("ConnectivityResult:Vpn connection active.");
toInitData();
// Vpn connection active.
// Note for iOS and macOS:
// There is no separate network interface type for [vpn].
// It returns [other] on any device (also simulator)
} else if (connectivityResult.contains(ConnectivityResult.bluetooth)) {
// Bluetooth connection available.
} else if (connectivityResult.contains(ConnectivityResult.other)) {
// Connected to a network which is not in the above mentioned networks.
print(
"ConnectivityResult:Connected to a network which is not in the above mentioned networks");
toInitData();
} else if (connectivityResult.contains(ConnectivityResult.none)) {
// No available network types
print("ConnectivityResult:No available network types");
}
}
static toInitData() async {
CommonVariables.isNetWorkOn = true;
if (isShowDialog) {
Get.back();
isShowDialog = false;
}
}
static checkNetwork() async {
// Platform messages may fail, so we use a try/catch PlatformException.
try {
connectivityResultChange(await (_connectivity.checkConnectivity()));
} on PlatformException catch (e) {
print("Couldn't check connectivity status:Error:$e");
}
// 网络状态变化监听,登录成功后移出监听
subscription = _connectivity.onConnectivityChanged
.listen((List<ConnectivityResult> connectivityResult) {
connectivityResultChange(connectivityResult);
});
if (CommonVariables.isNetWorkOn == false) {
int index = 0;
Timer.periodic(const Duration(seconds: 1), (t) {
index++;
if (index > 40 || CommonVariables.isNetWorkOn == true) {
t.cancel();
} else if (index > 20 && isShowDialog == false) {
t.cancel();
var context = Get.context;
String name = "";
if (Platform.isAndroid) {
name = "安卓启用网络提示".tr;
} else {
name = "ios启用网络提示".tr;
}
// isShowDialog = true;
// showCustomConfirmDialog(context!, name).then((d) {
// isShowDialog = false;
// });
showTipDialog(context!,Text(name,style: TextStyle(
color: themeController.currentColor.sc3,
),));
}
});
}
}
}

View File

@@ -1,21 +1,6 @@
class CommonVariables {
static bool isNetWorkOn = false;
static bool test = false;
static String supabaseUrl = "https://mht1.he-info.cn";
// static String wsUrl = "ws://mht-server.he-info.cn/ws";
// static String apiUrl = "https://mht-server.he-info.cn";
// static String shoph5Url = "https://mht-web.he-info.cn";
// static String supabaseUrl = "https://zhmht.swes.com.cn:3443";
// static String wsUrl = "wss://zhmht.swes.com.cn:8089/ws";
// static String apiUrl = "https://zhmht.swes.com.cn:8089";
static String wsUrl = "ws://192.168.1.129:8088/ws";
static String apiUrl = "http://192.168.1.129:8088";
static String shoph5Url = "https://zhmht.swes.com.cn:1443";
static String sleepUrl = "https://alltoone.he-info.cn";
static String efKey = "ef_key";
// // android app 内部更新地址
// static String androidInternalUpgradeUrl = "http://192.168.0.112:1234";
// 企业微信客服拉起的url地址
static String wxKfUrl = "https://work.weixin.qq.com/kfid/kfc7d2337b9c07b1269";
@@ -28,10 +13,5 @@ class CommonVariables {
//备案时间
static String ICPTime = "2022-2025";
// 分享复制文字信息
static String shareText = "您的朋友邀请您使用《智慧眠花糖》APP请复制后面链接在浏览器中打开 " +
shoph5Url +
"/#/pages/download/download";
static Map<String, Function(dynamic)> callMap = {};
}

View File

@@ -3,22 +3,15 @@ import 'dart:async';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:vbvs_app/common/color/app_uri_status.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/controller/setting/language/language_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/model/api_response.dart';
ThemeController themeController = Get.find();
Future<void> initDataEf({String key = ""}) async {
await ef.init(
'${CommonVariables.supabaseUrl}/',
key,
nosqlEnableWebsocket: false,
);
}
LanguageController languageController = Get.find();
class MyUtils {
static ApiResponse formatResponse(
@@ -330,15 +323,6 @@ String time_08_Formatter_pattern(String time, String pattern) {
return DateFormat(pattern).format(DateTime.parse(time).toLocal());
}
String storagePubSrc =
"${CommonVariables.supabaseUrl}/storage/v1/object/public/";
getStorageResourceUrl(String v) {
if (v.contains('http')) {
return v;
}
return storagePubSrc + v;
}
enum LoadingDialogIcon { ble, wifi, none }

View File

@@ -0,0 +1,105 @@
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.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';
Future<ApiResponse> requestWithLog({
required String logTitle,
required MyHttpMethod method,
required String queryUrl,
Map<String, dynamic>? data,
String successMsg = "操作成功",
String errorMsg = "操作失败",
void Function(ApiResponse res)? onSuccess,
void Function(ApiResponse res)? onFailure,
}) async {
EasyDartModule.logger.info(logTitle);
DailyLogUtils.writeLog(logTitle);
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
try {
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
successMsg = successMsg.tr;
errorMsg = errorMsg.tr;
var response;
switch (method) {
case MyHttpMethod.get:
response = await EasyDartModule.dio.get(queryUrl);
break;
case MyHttpMethod.post:
response = data != null
? await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data))
: await EasyDartModule.dio.post(queryUrl);
break;
case MyHttpMethod.put:
response = data != null
? await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data))
: await EasyDartModule.dio.put(queryUrl);
break;
case MyHttpMethod.delete:
response = data != null
? await EasyDartModule.dio.delete(queryUrl, data: jsonEncode(data))
: await EasyDartModule.dio.delete(queryUrl);
break;
}
if (response != null) {
final responseData =
response.data is String ? jsonDecode(response.data) : response.data;
apiResponse = ApiResponse.fromJson(responseData, (object) => object);
if (apiResponse.code == HttpStatusCodes.ok) {
MyUtils.formatResponse(apiResponse, successMsg, errorMsg);
onSuccess?.call(apiResponse);
} else {
apiResponse.msg = responseData['msg'] ?? errorMsg;
onFailure?.call(apiResponse);
}
return apiResponse;
} else {
apiResponse = ApiResponse(code: -1, msg: "服务器.失败".tr);
onFailure?.call(apiResponse);
return apiResponse;
}
} catch (e) {
EasyDartModule.logger.error("$logTitle 失败->$e");
DailyLogUtils.writeError("$logTitle 失败->$e");
onFailure?.call(apiResponse);
return apiResponse;
}
}
enum MyHttpMethod { get, post, put, delete }
extension HttpMethodExtension on MyHttpMethod {
String get name {
switch (this) {
case MyHttpMethod.get:
return 'GET';
case MyHttpMethod.post:
return 'POST';
case MyHttpMethod.put:
return 'PUT';
case MyHttpMethod.delete:
return 'DELETE';
}
}
}

View File

@@ -43,7 +43,7 @@ class _TestWidgetState extends State<NullDataWidget> {
child: SvgPicture.asset(
'assets/img/icon/nulldata.svg',
fit: BoxFit.cover,
color: themeController.currentColor.sc4,
color: themeController.currentColor.sc4.withOpacity(0.5),
),
),
),

View File

@@ -0,0 +1,264 @@
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/common/util/MyUtils.dart'; // 假设你自己扩展的 .rpx
import 'SleepdateWidget.dart'; // 导入你自定义的 SleepdateWidget
class SleepCalendarWidget extends StatefulWidget {
final int? timestamp; // 可选时间戳
const SleepCalendarWidget({super.key, this.timestamp});
@override
State<SleepCalendarWidget> createState() => _SleepCalendarWidgetState();
}
class _SleepCalendarWidgetState extends State<SleepCalendarWidget> {
late DateTime _currentDate;
@override
void initState() {
super.initState();
_currentDate = widget.timestamp != null
? DateTime.fromMillisecondsSinceEpoch(widget.timestamp!)
: DateTime.now();
}
List<DateTime> getDaysInMonth(DateTime date) {
// 获取当前月份的第一天
DateTime firstDayOfMonth = DateTime(date.year, date.month, 1);
// 获取当前月份的最后一天
DateTime lastDayOfMonth = DateTime(date.year, date.month + 1, 0);
List<DateTime> days = [];
// 获取该月的所有日期
for (int i = 0; i < lastDayOfMonth.day; i++) {
days.add(firstDayOfMonth.add(Duration(days: i)));
}
return days;
}
List<List<DateTime>> getCalendarRows(List<DateTime> daysInMonth) {
// 获取该月所有日期后,处理为 7 列的格式
List<List<DateTime>> calendarRows = [];
int firstWeekday = daysInMonth.first.weekday; // 获取该月第一天是周几
int emptyDays = (firstWeekday == 7 ? 0 : firstWeekday) - 1; // 调整为空白天数
List<DateTime> row = [];
for (int i = 0; i < emptyDays; i++) {
row.add(DateTime(0)); // 填充空白日期
}
for (var day in daysInMonth) {
row.add(day);
if (row.length == 7) {
// 如果当前行满了 7 个日期,则添加到 calendarRows 中,并重置 row
calendarRows.add(List.from(row));
row.clear();
}
}
if (row.isNotEmpty) {
// 如果最后一行的日期不足 7 个,则补充空白日期
while (row.length < 7) {
row.add(DateTime(0)); // 填充空白日期
}
calendarRows.add(List.from(row)); // 添加最后一行
}
return calendarRows;
}
@override
Widget build(BuildContext context) {
List<Map<String, dynamic>> showLabel = [
{
"level": 1,
"name": "优秀",
"color": Color(0xFF4CAF50), // 绿色
},
{
"level": 2,
"name": "良好",
"color": Color(0xFF8BC34A), // 浅绿
},
{
"level": 3,
"name": "合格",
"color": Color(0xFFFFC107), // 黄色
},
{
"level": 4,
"name": "注意",
"color": Color(0xFFF44336), // 红色
},
{
"level": 5,
"name": "无报告",
"color": Color(0xFF9E9E9E), // 灰色
},
];
List sleepData = [];
// 获取当前月的所有日期
List<DateTime> daysInMonth = getDaysInMonth(_currentDate);
// 获取按行排列的日期
List<List<DateTime>> calendarRows = getCalendarRows(daysInMonth);
return Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(0),
bottomRight: Radius.circular(0),
topLeft: Radius.circular(20.rpx),
topRight: Radius.circular(20.rpx),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: double.infinity,
// height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minHeight: 90.rpx,
),
decoration: BoxDecoration(
color: const Color(0xFF313541),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(0),
bottomRight: Radius.circular(0),
topLeft: Radius.circular(20.rpx),
topRight: Radius.circular(20.rpx),
),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
65.rpx,
0.rpx,
65.rpx,
0.rpx,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
Icons.arrow_back_ios_new,
color: const Color(0xFF6D6F73),
size: 24.rpx,
),
Text(
'${_currentDate.year}${_currentDate.month}',
style: TextStyle(
color: Colors.white,
fontSize: 30.rpx,
letterSpacing: 0.0,
),
),
Icon(
Icons.arrow_forward_ios,
color: const Color(0xFF6D6F73),
size: 24.rpx,
),
],
),
),
),
Container(
width: double.infinity,
constraints: BoxConstraints(
minHeight: 720.rpx,
),
decoration: const BoxDecoration(
color: Color(0xFF242835),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
65.rpx,
13.rpx,
65.rpx,
38.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// Weekdays Header
Container(
constraints: BoxConstraints(minHeight: 90.rpx),
child: Row(
children: [
for (var day in ["", "", "", "", "", "", ""])
Expanded(
child: Center(
child: Text(
day,
style: TextStyle(
color: stringToColor("#FFFFFF"),
fontSize: AppConstants().normal_text_fontSize,
),
),
),
),
],
),
),
// 日历显示部分
Column(
children: calendarRows.map((week) {
return Row(
mainAxisAlignment: MainAxisAlignment.start, // 保证每一行左对齐
children: week.map((date) {
return Expanded(
child: Padding(
padding: EdgeInsets.all(4.rpx),
child: date.year != 0 // 如果是空白日期就不显示
? SleepdateWidget(date: date)
: SizedBox.shrink(),
),
);
}).toList(),
);
}).toList(),
),
SizedBox(
height: 55.rpx,
),
Wrap(
direction: Axis.horizontal, // 默认是水平排列的,可以去掉这行
spacing: 20.rpx, // 水平间距
runSpacing: 20.rpx, // 垂直间距
children: showLabel.map<Widget>((item) {
return Container(
padding: EdgeInsets.all(5.rpx), // 可选,添加一点间距
child: Row(
mainAxisSize: MainAxisSize.min, // 确保 Row 不会占满整个宽度
children: [
Container(
width: 20.rpx,
height: 20.rpx,
decoration: BoxDecoration(
color: item["color"],
borderRadius:
BorderRadius.circular(10.rpx), // 圆形效果
),
),
SizedBox(width: 8.rpx), // 标签和文本之间的间距
Text(
item["name"],
style: TextStyle(
color: Colors.white,
fontSize: 24.rpx,
),
),
],
),
);
}).toList(),
),
],
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
class SleepdateWidget extends StatelessWidget {
final DateTime date;
const SleepdateWidget({super.key, required this.date});
@override
Widget build(BuildContext context) {
return Container(
width: 90.rpx,
height: 90.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(10.rpx, 10.rpx, 10.rpx, 10.rpx),
child: Container(
decoration: BoxDecoration(
color: Color(0xFFDC1C1C), // 默认红色
shape: BoxShape.circle,
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'${date.day}',
style: TextStyle(
color: Colors.white,
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,461 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
/// A dropdown widget that allows the user to select an option from a list of options.
class THFlutterFlowDropDown<T> extends StatefulWidget {
const THFlutterFlowDropDown({
super.key,
this.controller,
this.multiSelectController,
this.hintText,
this.searchHintText,
required this.options,
this.optionLabels,
this.onChanged,
this.onMenuStateChange,
this.onMultiSelectChanged,
this.icon,
this.width,
this.height,
this.maxHeight,
this.fillColor,
this.searchHintTextStyle,
this.hintTextStyle,
this.searchTextStyle,
this.searchCursorColor,
required this.textStyle,
required this.elevation,
required this.borderWidth,
required this.borderRadius,
required this.borderColor,
required this.margin,
this.hidesUnderline = false,
this.disabled = false,
this.isOverButton = false,
this.menuOffset,
this.isSearchable = false,
this.isMultiSelect = false,
this.labelText,
this.labelTextStyle,
this.allowEmpty = true, // 新增参数,默认值为 true
}) : assert(
isMultiSelect
? (controller == null &&
onChanged == null &&
multiSelectController != null &&
onMultiSelectChanged != null)
: (controller != null &&
onChanged != null &&
multiSelectController == null &&
onMultiSelectChanged == null),
);
/// The controller for the dropdown field.
final FormFieldController<T?>? controller;
/// The controller for the multi-select dropdown field.
final FormFieldController<List<T>?>? multiSelectController;
/// The text to display as a hint when no option is selected.
final String? hintText;
/// The text to display as a hint in the search field.
final String? searchHintText;
/// The list of options to display in the dropdown.
final List<T> options;
/// The list of labels corresponding to the options.
final List<String>? optionLabels;
/// A callback function that is called when the selected option changes.
final Function(T?)? onChanged;
final Function(bool)? onMenuStateChange;
/// A callback function that is called when the selected options change in multi-select mode.
final Function(List<T>?)? onMultiSelectChanged;
/// The icon to display in the dropdown field.
final Widget? icon;
/// The width of the dropdown field.
final double? width;
/// The height of the dropdown field.
final double? height;
/// The maximum height of the dropdown menu.
final double? maxHeight;
/// The background color of the dropdown field.
final Color? fillColor;
/// The text style for the search hint text.
final TextStyle? searchHintTextStyle;
final TextStyle? hintTextStyle;
/// The text style for the search text.
final TextStyle? searchTextStyle;
/// The color of the search cursor.
final Color? searchCursorColor;
/// The text style for the dropdown field.
final TextStyle textStyle;
/// The elevation of the dropdown menu.
final double elevation;
/// The width of the dropdown field's border.
final double borderWidth;
/// The border radius of the dropdown field.
final double borderRadius;
/// The color of the dropdown field's border.
final Color borderColor;
/// The margin around the dropdown field.
final EdgeInsetsGeometry margin;
/// Whether to hide the underline of the dropdown field.
final bool hidesUnderline;
/// Whether the dropdown is disabled.
final bool disabled;
/// Whether the dropdown menu is displayed over the button.
final bool isOverButton;
/// The offset of the dropdown menu.
final Offset? menuOffset;
/// Whether the dropdown is searchable.
final bool isSearchable;
/// Whether the dropdown is in multi-select mode.
final bool isMultiSelect;
/// The label text for the dropdown field.
final String? labelText;
/// The text style for the label text.
final TextStyle? labelTextStyle;
/// Whether the dropdown allows empty selection.
final bool allowEmpty;
@override
State<THFlutterFlowDropDown<T>> createState() =>
_FlutterFlowDropDownState<T>();
}
class _FlutterFlowDropDownState<T> extends State<THFlutterFlowDropDown<T>> {
bool get isMultiSelect => widget.isMultiSelect;
FormFieldController<T?> get controller => widget.controller!;
FormFieldController<List<T>?> get multiSelectController =>
widget.multiSelectController!;
T? get currentValue {
final value = isMultiSelect
? multiSelectController.value?.firstOrNull
: controller.value;
return widget.options.contains(value) ? value : null;
}
Set<T> get currentValues {
if (!isMultiSelect || multiSelectController.value == null) {
return {};
}
return widget.options
.toSet()
.intersection(multiSelectController.value!.toSet());
}
Map<T, String> get optionLabels => Map.fromEntries(
widget.options.asMap().entries.map(
(option) => MapEntry(
option.value,
widget.optionLabels == null ||
widget.optionLabels!.length < option.key + 1
? option.value.toString()
: widget.optionLabels![option.key],
),
),
);
EdgeInsetsGeometry get horizontalMargin => widget.margin.clamp(
EdgeInsetsDirectional.zero,
const EdgeInsetsDirectional.symmetric(horizontal: double.infinity),
);
late void Function() _listener;
final TextEditingController _textEditingController = TextEditingController();
List<T>? _previousSelectedValues;
@override
void initState() {
super.initState();
if (isMultiSelect) {
_listener = () {
if (!widget.allowEmpty &&
(multiSelectController.value == null ||
multiSelectController.value!.isEmpty) &&
(widget.options != null && widget.options.isNotEmpty)) {
// showToast("请至少选择一项", color: color_warning);
multiSelectController.value = _previousSelectedValues;
} else {
_previousSelectedValues = List.from(multiSelectController.value!);
}
widget.onMultiSelectChanged!(multiSelectController.value);
};
multiSelectController.addListener(_listener);
} else {
_listener = () {
setState(() {});
widget.onChanged!(controller.value);
};
controller.addListener(_listener);
}
}
@override
void dispose() {
if (isMultiSelect) {
multiSelectController.removeListener(_listener);
} else {
controller.removeListener(_listener);
}
super.dispose();
}
@override
Widget build(BuildContext context) {
final dropdownWidget = _buildDropdownWidget();
return SizedBox(
width: widget.width,
height: widget.height,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(widget.borderRadius),
border: Border.all(
color: widget.borderColor,
width: widget.borderWidth,
),
color: widget.fillColor,
),
child: Padding(
padding: _useDropdown2() ? EdgeInsets.zero : widget.margin,
child: widget.hidesUnderline
? DropdownButtonHideUnderline(child: dropdownWidget)
: dropdownWidget,
),
),
);
}
bool _useDropdown2() =>
widget.isMultiSelect ||
widget.isSearchable ||
!widget.isOverButton ||
widget.maxHeight != null;
Widget _buildDropdownWidget() =>
_useDropdown2() ? _buildDropdown() : _buildLegacyDropdown();
Widget _buildLegacyDropdown() {
return DropdownButtonFormField<T>(
value: currentValue,
hint: _createHintText(),
items: _createMenuItems(),
elevation: widget.elevation.toInt(),
onChanged: widget.disabled ? null : (value) => controller.value = value,
icon: widget.icon,
isExpanded: true,
dropdownColor: widget.fillColor,
focusColor: Colors.transparent,
decoration: InputDecoration(
labelText: widget.labelText == null || widget.labelText!.isEmpty
? null
: widget.labelText,
labelStyle: widget.labelTextStyle,
border: widget.hidesUnderline
? InputBorder.none
: const UnderlineInputBorder(),
),
);
}
Text? _createHintText() => widget.hintText != null
? Text(
widget.hintText!,
style: widget.hintTextStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis, // 超出部分显示省略号
)
: null;
List<DropdownMenuItem<T>> _createMenuItems() => widget.options
.map(
(option) => DropdownMenuItem<T>(
value: option,
child: Padding(
padding: _useDropdown2() ? horizontalMargin : EdgeInsets.zero,
child: Text(optionLabels[option] ?? '', style: widget.textStyle),
),
),
)
.toList();
List<DropdownMenuItem<T>> _createMultiselectMenuItems() => widget.options
.map(
(item) => DropdownMenuItem<T>(
value: item,
// Disable default onTap to avoid closing menu when selecting an item
enabled: false,
child: StatefulBuilder(
builder: (context, menuSetState) {
final isSelected =
multiSelectController.value?.contains(item) ?? false;
return InkWell(
onTap: () {
multiSelectController.value ??= [];
isSelected
? multiSelectController.value!.remove(item)
: multiSelectController.value!.add(item);
multiSelectController.update();
// This rebuilds the StatefulWidget to update the button's text.
setState(() {});
// This rebuilds the dropdownMenu Widget to update the check mark.
menuSetState(() {});
},
child: Container(
height: double.infinity,
padding: horizontalMargin,
child: Row(
children: [
if (isSelected)
const Icon(Icons.check_box_outlined)
else
const Icon(Icons.check_box_outline_blank),
const SizedBox(width: 16),
Expanded(
child: Text(
optionLabels[item]!,
style: widget.textStyle,
),
),
],
),
),
);
},
),
),
)
.toList();
Widget _buildDropdown() {
final overlayColor = WidgetStateProperty.resolveWith<Color?>((states) =>
states.contains(WidgetState.focused) ? Colors.transparent : null);
final iconStyleData = widget.icon != null
? IconStyleData(icon: widget.icon!)
: const IconStyleData();
return DropdownButton2<T>(
value: currentValue,
hint: _createHintText(),
items: isMultiSelect ? _createMultiselectMenuItems() : _createMenuItems(),
iconStyleData: iconStyleData,
buttonStyleData: ButtonStyleData(
elevation: widget.elevation.toInt(),
overlayColor: WidgetStateProperty.all(Colors.transparent),
padding: widget.margin,
),
menuItemStyleData: MenuItemStyleData(
overlayColor: WidgetStateProperty.all(Colors.transparent),
padding: EdgeInsets.zero,
),
dropdownStyleData: DropdownStyleData(
elevation: widget.elevation.toInt(),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
color: widget.fillColor,
),
isOverButton: widget.isOverButton,
offset: widget.menuOffset ?? Offset.zero,
maxHeight: widget.maxHeight,
padding: EdgeInsets.zero,
),
onChanged: widget.disabled
? null
: (isMultiSelect ? (_) {} : (val) => widget.controller!.value = val),
isExpanded: true,
selectedItemBuilder: (context) => widget.options
.map(
(item) => Align(
alignment: AlignmentDirectional.centerStart,
child: Text(
isMultiSelect
? currentValues
.where((v) => optionLabels.containsKey(v))
.map((v) => optionLabels[v])
.join(', ')
: optionLabels[item]!,
style: widget.textStyle,
maxLines: 1,
),
),
)
.toList(),
dropdownSearchData: widget.isSearchable
? DropdownSearchData<T>(
searchController: _textEditingController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding: const EdgeInsets.only(
top: 8,
bottom: 4,
right: 8,
left: 8,
),
child: TextFormField(
expands: true,
maxLines: null,
controller: _textEditingController,
cursorColor: widget.searchCursorColor,
style: widget.searchTextStyle,
decoration: InputDecoration(
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 8,
),
hintText: widget.searchHintText,
hintStyle: widget.searchHintTextStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
searchMatchFn: (item, searchValue) {
return (optionLabels[item.value] ?? '')
.toLowerCase()
.contains(searchValue.toLowerCase());
},
)
: null,
// This is to clear the search value when you close the menu
onMenuStateChange: (isOpen) {
if (widget.isSearchable && !isOpen) {
_textEditingController.clear();
}
if (widget.onMenuStateChange != null) {
widget.onMenuStateChange!(isOpen);
}
},
);
}
}

View File

@@ -149,7 +149,7 @@ class DynamicReportDetailWidget extends StatelessWidget {
style: FlutterFlowTheme.of(Get.context!).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 28.rpx,
color: themeController.currentColor.sc3,
color: themeController.currentColor.sc4,
),
),
);

View File

@@ -44,7 +44,8 @@ class _SleepDataModuleWidgetState extends State<SleepDataModuleWidget> {
print('点击了离床次数卡片');
},
child: Container(
width: MediaQuery.sizeOf(context).width * 0.27,
// width: MediaQuery.sizeOf(context).width * 0.267,
width: MediaQuery.sizeOf(context).width * 0.267,
constraints: BoxConstraints(
minWidth: 200.rpx,
minHeight: 161.rpx,

View File

@@ -42,8 +42,9 @@ class _SleepDateWidgetState extends State<SleepDateWidget> {
String day = MyUtils.formatDateTimeDay(widget.date);
// 选中时背景色为黑色,否则为透明
Color backgroundColor =
widget.isSelected == true ? Colors.black : Colors.transparent;
Color backgroundColor = widget.isSelected == true
? Colors.black.withOpacity(0.3)
: Colors.transparent;
return ClickableContainer(
backgroundColor: backgroundColor,

View File

@@ -20,23 +20,20 @@ class ClickableContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(splashFactory: InkRipple.splashFactory),
child: Material(
color: Colors.transparent,
child: Ink(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(borderRadius),
),
child: InkWell(
borderRadius: BorderRadius.circular(borderRadius),
onTap: onTap,
splashColor: highlightColor.withOpacity(0.2),
child: Padding(
padding: padding,
child: child,
),
return Material(
color: Colors.transparent,
child: Ink(
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(borderRadius),
),
child: InkWell(
borderRadius: BorderRadius.circular(borderRadius),
onTap: onTap,
splashColor: highlightColor.withOpacity(0.5),
child: Padding(
padding: padding,
child: child,
),
),
),

View File

@@ -21,10 +21,151 @@ class TopSlideNotification extends StatefulWidget {
this.duration = const Duration(seconds: 2),
});
static OverlayEntry? _currentEntry; // 单例 OverlayEntry
static bool _isShowing = false;
static void show(
BuildContext context, {
String text = '操作成功!',
double fontSize = 16,
Color? textColor,
double slideOffset = 300.0,
Duration duration = const Duration(seconds: 2),
}) {
// 如果已有弹窗,先移除
_removeCurrentEntry();
final overlay = Overlay.of(context);
final entry = OverlayEntry(
builder: (_) => TopSlideNotification(
text: text,
fontSize: fontSize,
textColor: textColor,
slideOffset: slideOffset,
duration: duration,
),
);
_currentEntry = entry;
_isShowing = true;
overlay.insert(entry);
// 自动移除
Future.delayed(duration + const Duration(milliseconds: 500), () {
_removeCurrentEntry();
});
}
static void _removeCurrentEntry() {
if (_currentEntry != null && _isShowing) {
_currentEntry!.remove();
_currentEntry = null;
_isShowing = false;
}
}
@override
State<TopSlideNotification> createState() => _TopSlideNotificationState();
}
/// 工具方法:调用时直接加进 Overlay 上
class _TopSlideNotificationState extends State<TopSlideNotification>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<Offset> _animation;
bool _isAnimating = false; // 标志位,控制是否正在动画中
@override
void initState() {
super.initState();
// 初始化 AnimationController
_controller = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
// 动画初始化完成后调用
SchedulerBinding.instance.addPostFrameCallback((_) {
_startAnimation(); // 调用动画启动方法
});
}
@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(
child: Text(
widget.text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: widget.fontSize,
color: _textColor,
),
),
),
),
),
),
);
}
// 执行动画
Future<void> _startAnimation() async {
if (_isAnimating) return; // 如果正在动画中,则不执行新的动画
_isAnimating = true; // 标记动画开始
try {
await _controller.forward();
await Future.delayed(widget.duration);
// 只有在组件仍然挂载时才执行 reverse 动作
if (mounted) {
await _controller.reverse();
}
} finally {
_isAnimating = false; // 动画完成后,标记动画结束
}
}
// 工具方法:调用时直接加进 Overlay 上
static void show(
BuildContext context, {
String text = '操作成功!',
@@ -50,81 +191,3 @@ class TopSlideNotification extends StatefulWidget {
});
}
}
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

@@ -1,51 +1,79 @@
// import 'package:flutter/material.dart';
// import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
// class WebViewWidget extends StatefulWidget {
// final String url;
// const WebViewWidget({Key? key, required this.url}) : super(key: key);
class MyWebView extends StatefulWidget {
final String url;
final Function()? onLoad;
final Function(MyWebView view, String msg)? onMessage;
// @override
// _WebViewWidgetState createState() => _WebViewWidgetState();
// }
const MyWebView({
Key? key,
required this.url,
this.onLoad,
this.onMessage,
}) : super(key: key);
// class _WebViewWidgetState extends State<WebViewWidget> {
// late WebViewController _webViewController;
@override
State<MyWebView> createState() => _MyWebViewState();
}
// @override
// void initState() {
// super.initState();
// // 初始化 WebView 控件
// WebView.platform = SurfaceAndroidWebView();
// }
class _MyWebViewState extends State<MyWebView> {
late final WebViewController _controller;
// @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, // 启用手势返回
// ),
// );
// }
// }
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (url) {
widget.onLoad?.call();
},
onWebResourceError: (error) {
print("WebView 加载错误: ${error.description}");
},
onNavigationRequest: (NavigationRequest request) {
final url = request.url;
if (url.startsWith('http') || url.startsWith('https')) {
return NavigationDecision.navigate;
}
if (url.startsWith('weixin://')) {
_launchWeChatUrl(url);
return NavigationDecision.prevent;
}
print('拦截未知协议: $url');
return NavigationDecision.prevent;
},
),
)
..addJavaScriptChannel(
'FlutterChannel',
onMessageReceived: (msg) {
widget.onMessage?.call(widget, msg.message);
},
)
..loadRequest(Uri.parse(widget.url));
}
void _launchWeChatUrl(String url) async {
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
print('⚠️ 无法跳转微信: $url');
}
}
// 提供方法给外部调用 JS
void sendData(String data) {
_controller.runJavaScript("window.postMessage('$data')");
}
@override
Widget build(BuildContext context) {
return WebViewWidget(controller: _controller);
}
}

View File

@@ -66,6 +66,8 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
RxMap connect_wifi = {}.obs;
RxString scanMac = "".obs;
String? currentDeviceMac;
// 安全展示 TopSlideNotification
void safeShowNotification(String msg) {
try {
@@ -97,7 +99,7 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
});
if (_statusTimer == null) {
_statusTimer = Timer.periodic(Duration(seconds: 10), (timer) {
_statusTimer = Timer.periodic(Duration(seconds: 2), (timer) {
updateDeviceStatus().then((res) {
if (res.code == HttpStatusCodes.ok) {
updateAll();
@@ -138,6 +140,17 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
} else {
queryUrl += '?$macParams';
}
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
var responseData =
@@ -177,7 +190,7 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
model.betDevicelist = [];
}
print("获取设备状态成功");
updateAll();
return res;
}
@@ -198,6 +211,17 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "$serviceAddress$serviceName$serviceApi";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var data = {
"deviceType": 1,
"mac": d.mac,
@@ -209,7 +233,7 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
MyUtils.formatResponse(res, "绑定成功.绑定成功".tr, "绑定成功.绑定成功".tr);
if (res.code == HttpStatusCodes.ok) {
PersonController personController = Get.find();
personController.currentPersonId.value = res.data['id'];
@@ -242,6 +266,17 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "$serviceAddress$serviceName$serviceApi";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var data = {
"deviceType": 1,
"mac": mac,
@@ -253,7 +288,7 @@ class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
response.data is String ? jsonDecode(response.data) : response.data;
ApiResponse res =
ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(res, "蓝牙绑定.绑定成功".tr, "蓝牙绑定.绑定成功".tr);
MyUtils.formatResponse(res, "绑定成功.绑定成功".tr, "绑定成功.绑定成功".tr);
if (res.code == HttpStatusCodes.ok) {
return res;
}

View File

@@ -52,6 +52,17 @@ class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
String serviceApi = ServiceConstant.device_list;
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?bindNum=1";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
@@ -83,6 +94,17 @@ class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
String serviceApi = ServiceConstant.device_list;
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?bindType=${model.type}${key != null ? '&key=$key' : ''}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
@@ -114,6 +136,17 @@ class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_bind;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
final data = {
"mac": device['mac'],
};
@@ -171,6 +204,17 @@ class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
"$serviceAddress$serviceName$serviceApi?mac=$mac&time=${DateTime.now().millisecondsSinceEpoch}";
try {
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData = response.data is String
@@ -228,6 +272,17 @@ class BodyDeviceController extends GetControllerEx<BodyDeviceModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_show;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var data = {
"id": device['_id'],
"show": !device['show'],

View File

@@ -0,0 +1,32 @@
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
part 'device_calibration_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class DeviceCalibrationModel {
DeviceCalibrationModel();
factory DeviceCalibrationModel.fromJson(Map<String, dynamic> json) {
try {
return _$DeviceCalibrationModelFromJson(json);
} catch (e) {
return DeviceCalibrationModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$DeviceCalibrationModelToJson(this);
}
class DeviceCalibrationController
extends GetControllerEx<DeviceCalibrationModel> {
DeviceCalibrationController() {
attr = GetModel(DeviceCalibrationModel()).obs;
}
RxInt process = 0.obs; //校准流程 0.离床校准 1.位置校准
RxInt bed_calibration = 0.obs; //0.未完成 1.完成
RxInt position_calibration = 0.obs; //0.未完成 1.完成
RxInt bed_type = 0.obs; //0.单人 1.双人
}

View File

@@ -0,0 +1,15 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_calibration_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceCalibrationModel _$DeviceCalibrationModelFromJson(
Map<String, dynamic> json) =>
DeviceCalibrationModel();
Map<String, dynamic> _$DeviceCalibrationModelToJson(
DeviceCalibrationModel instance) =>
<String, dynamic>{};

View File

@@ -46,11 +46,22 @@ class DeviceShareController extends GetControllerEx<DeviceShareModel> {
RxInt code = 0.obs;
Future<ApiResponse> getDeviceType() async {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备类型.请求失败".tr);
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}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
@@ -87,6 +98,17 @@ class DeviceShareController extends GetControllerEx<DeviceShareModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_share;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var data = {"type": 1, "userName": account.value, "mac": mac};
var response =
await EasyDartModule.dio.post(queryUrl, data: jsonEncode(data));
@@ -104,7 +126,9 @@ class DeviceShareController extends GetControllerEx<DeviceShareModel> {
res.msg = "操作成功".tr;
}
}
msg.value = res.msg!;
if (res.code != HttpStatusCodes.ok) {
msg.value = res.msg!;
}
code.value = res.code!;
updateAll();
return res;
@@ -117,4 +141,56 @@ class DeviceShareController extends GetControllerEx<DeviceShareModel> {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
//确认接受设备分享
Future<ApiResponse> confirmShare(String shareCode) async {
EasyDartModule.logger.info("确认消息分享");
DailyLogUtils.writeLog("确认消息分享");
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
if (shareCode == null || shareCode.isEmpty) {
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}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
final data = {
"code": shareCode,
};
var response =
await EasyDartModule.dio.put(queryUrl, data: jsonEncode(data));
if (response != null) {
if (response.data['code'] != HttpStatusCodes.ok) {
apiResponse.msg = response.data['msg'];
apiResponse.code = response.data['code'];
return apiResponse;
}
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);
}
}
}

View File

@@ -0,0 +1,135 @@
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_list_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class DeviceShareListModel {
String? key; //关键字搜索
int? all = 0; //是否全选 0不全选 1全选
DeviceShareListModel();
// 从JSON反序列化时的异常处理
factory DeviceShareListModel.fromJson(Map<String, dynamic> json) {
try {
return _$DeviceShareListModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return DeviceShareListModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$DeviceShareListModelToJson(this);
}
class DeviceShareListController extends GetControllerEx<DeviceShareListModel> {
DeviceShareListController() {
attr = GetModel(DeviceShareListModel()).obs;
}
RxList shareInfoList = [].obs;
RxList selectedShareInfo = [].obs;
//查询分享信息
Future<ApiResponse> getDeviceShareList(String mac, {String? key}) async {
try {
EasyDartModule.logger.info("设备设备分享列表");
DailyLogUtils.writeLog("设备设备分享列表");
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.device_share;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}"
"${key != null ? '?key=$key&' : '?'}mac=$mac";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
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) {
shareInfoList.value = res.data!;
updateAll();
return res;
}
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
return apiResponse;
} catch (e) {
EasyDartModule.logger.error("设备请求列表: $e");
DailyLogUtils.writeError("设备请求列表: $e");
}
return ApiResponse(code: -1, msg: "未知错误".tr);
}
//删除分享
Future<ApiResponse> deleteShareDevice() async {
try {
EasyDartModule.logger.info("删除分享设备");
DailyLogUtils.writeLog("删除分享设备");
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.share_deleted;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
final data = {
"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.error("删除分享设备: $e");
DailyLogUtils.writeError("删除分享设备: $e");
} finally {
EasyDartModule.logger.info("用户操作:删除分享设备");
DailyLogUtils.writeLog("用户操作:删除分享设备");
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
}

View File

@@ -0,0 +1,20 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_share_list_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceShareListModel _$DeviceShareListModelFromJson(
Map<String, dynamic> json) =>
DeviceShareListModel()
..key = json['key'] as String?
..all = (json['all'] as num?)?.toInt();
Map<String, dynamic> _$DeviceShareListModelToJson(
DeviceShareListModel instance) =>
<String, dynamic>{
'key': instance.key,
'all': instance.all,
};

View File

@@ -6,6 +6,7 @@ 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/controller/setting/language/language_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
part 'device_type_controller.g.dart'; // 由json_serializable自动生成的部分
@@ -38,28 +39,46 @@ class DeviceTypeController extends GetControllerEx<DeviceTypeModel> {
attr = GetModel(DeviceTypeModel()).obs;
}
RxList deviceTypeList = [].obs;
LanguageController languageController = Get.find();
Future<ApiResponse> getDeviceType() async {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "设备类型.请求失败".tr);
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;
}
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
deviceTypeList.value = res.data;
queryUrl += "?lang=$language";
}
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
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) {
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);
}
} catch (e) {
return apiResponse;
}
}
}

View File

@@ -4,12 +4,15 @@ import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get_storage/get_storage.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/MyUtils.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/time/countdown_controller.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';
@@ -46,9 +49,9 @@ class LoginModel {
class LoginController extends GetControllerEx<LoginModel> {
// 初始化实例
// final Fluwx fluwx = Fluwx();
final Fluwx fluwx = Fluwx();
// 微信监听返回值
// FluwxCancelable? fluwxCancelable;
FluwxCancelable? fluwxCancelable;
// final UserRepository repository = UserRepository();
LoginController() {
@@ -70,6 +73,17 @@ class LoginController extends GetControllerEx<LoginModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.login;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var data = {
"type": 1,
"userName": model.phone,
@@ -83,6 +97,8 @@ class LoginController extends GetControllerEx<LoginModel> {
ApiResponse res = ApiResponse.fromJson(responseData, (object) => object);
MyUtils.formatResponse(apiResponse, "其他手机登录页.登陆成功".tr, "其他手机登录页.登陆失败".tr);
if (res.code == HttpStatusCodes.ok) {
CountdownController countdownController = Get.find();
countdownController.countdown.value = 0;
UserInfoController userInfoController = Get.find();
userInfoController.model.login = 1;
userInfoController.model.user = UserModel.fromJson(res.data);
@@ -118,6 +134,17 @@ class LoginController extends GetControllerEx<LoginModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.send_code;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var data = {
"userName": model.phone,
};
@@ -147,32 +174,34 @@ class LoginController extends GetControllerEx<LoginModel> {
}
//微信登录
// Future<void> wxLoginSendAuth() async {
// /*
// 1、目前移动应用上微信登录只提供原生的登录方式需要用户安装微信客户端才能配合使用。
// 2、对于Android应用建议总是显示微信登录按钮当用户手机没有安装微信客户端时请引导用户下载安装微信客户端。
// 3、对于iOS应用考虑到iOS应用商店审核指南中的相关规定建议开发者接入微信登录时先检测用户手机是否已安装微信客户端
// 使用sdk中isWXAppInstalled函数 ),对未安装的用户隐藏微信登录按钮,只提供其他登录方式(比如手机号注册登录、游客登录等)
// */
// if (isAndroid) {
// bool isWeChatInstalled = await fluwx.isWeChatInstalled;
// debugPrint('is wechat installed: $isWeChatInstalled');
// if (!isWeChatInstalled) {
// showToast("请先安装微信APP再使用微信登录");
// return;
// }
// }
// fluwx
// .authBy(
// which: NormalAuth(
// scope: 'snsapi_userinfo',
// state: 'wechat_sdk_zhmht_wxlogin',
// ))
// .then((data) {
// //返回true表示成功或者false表示失败这边没有意义从login_controller页面构造函数监听中去处理
// debugPrint('msg:$data');
// });
// }
Future<void> wxLoginSendAuth(BuildContext context) async {
/*
1、目前移动应用上微信登录只提供原生的登录方式需要用户安装微信客户端才能配合使用。
2、对于Android应用建议总是显示微信登录按钮当用户手机没有安装微信客户端时请引导用户下载安装微信客户端。
3、对于iOS应用考虑到iOS应用商店审核指南中的相关规定建议开发者接入微信登录时先检测用户手机是否已安装微信客户端
使用sdk中isWXAppInstalled函数 ),对未安装的用户隐藏微信登录按钮,只提供其他登录方式(比如手机号注册登录、游客登录等)
*/
if (isAndroid) {
bool isWeChatInstalled = await fluwx.isWeChatInstalled;
if (!isWeChatInstalled) {
TopSlideNotification.show(context,
text: "微信安装提示".tr, textColor: themeController.currentColor.sc9);
return;
}
}
fluwx
.authBy(
which: NormalAuth(
scope: 'snsapi_userinfo',
state: 'wechat_sdk_theh_wxlogin',
))
.then((data) {
//返回true表示成功或者false表示失败这边没有意义从login_controller页面构造函数监听中去处理
debugPrint('msg:$data');
});
}
loginByWechatCode(String code) {}
//退出登录
// Future<void> logout() async {

View File

@@ -15,6 +15,8 @@ part 'message_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class MessageModel {
int? type = 1; //设备类型 1:体征消息 2.系统消息
int? body_message_read = 0; //体征消息 0已读 1未读
int? system_message_read = 0; //系统消息 0已读 1未读
MessageModel();
@@ -38,7 +40,7 @@ class MessageController extends GetControllerEx<MessageModel> {
attr = GetModel(MessageModel()).obs;
}
RxList msssageList = [].obs;
RxList messageList = [].obs;
Future<ApiResponse> getMessageList({String? key}) async {
try {
@@ -53,7 +55,18 @@ class MessageController extends GetControllerEx<MessageModel> {
messageType = "app_system";
}
String queryUrl =
"${serviceAddress}${serviceName}${serviceApi}?type=${messageType}'}";
"${serviceAddress}${serviceName}${serviceApi}?type=${messageType}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
@@ -63,6 +76,7 @@ class MessageController extends GetControllerEx<MessageModel> {
MyUtils.formatResponse(res, "请求成功".tr, "请求失败".tr);
if (res.code == HttpStatusCodes.ok) {
updateAll();
messageList.value = res.data;
return res;
}
} else {
@@ -75,4 +89,110 @@ class MessageController extends GetControllerEx<MessageModel> {
}
return ApiResponse(code: -1, msg: "未知错误".tr); // Default return statement
}
//获取消息已读未读
Future<ApiResponse> getMessageStatus() async {
try {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "请求失败".tr);
// return apiResponse;
String serviceAddress = ServiceConstant.service_address;
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.message_read;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
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();
List dataList = res.data;
// 查找 type 为 app_vsm 的项
var vsmItem = dataList.firstWhere(
(e) => e['type'] == 'app_vsm',
orElse: () => null,
);
model.body_message_read = vsmItem?['count'] ?? 0;
// 查找 type 为 app_system 的项
var systemItem = dataList.firstWhere(
(e) => e['type'] == 'app_system',
orElse: () => null,
);
model.system_message_read = systemItem?['count'] ?? 0;
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> updateMessageStatus({String? type}) 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.message_read;
// 拼接 URL添加 type 参数
String queryUrl = "$serviceAddress$serviceName$serviceApi";
if (type != null && type.isNotEmpty) {
queryUrl += "?type=$type";
}
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.post(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);
return res;
} else {
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
} catch (e) {
EasyDartModule.logger.info("更新消息已读状态->$e");
DailyLogUtils.writeLog("更新消息已读状态->$e");
return ApiResponse(code: -1, msg: "服务器.失败".tr);
}
}
}

View File

@@ -6,10 +6,14 @@ part of 'message_controller.dart';
// JsonSerializableGenerator
// **************************************************************************
MessageModel _$MessageModelFromJson(Map<String, dynamic> json) =>
MessageModel()..type = (json['type'] as num?)?.toInt();
MessageModel _$MessageModelFromJson(Map<String, dynamic> json) => MessageModel()
..type = (json['type'] as num?)?.toInt()
..body_message_read = (json['body_message_read'] as num?)?.toInt()
..system_message_read = (json['system_message_read'] as num?)?.toInt();
Map<String, dynamic> _$MessageModelToJson(MessageModel instance) =>
<String, dynamic>{
'type': instance.type,
'body_message_read': instance.body_message_read,
'system_message_read': instance.system_message_read,
};

View File

@@ -76,6 +76,17 @@ class PersonController extends GetControllerEx<PersonModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.person_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
if (name.value.isEmpty) {
apiResponse.msg = "请输入姓名".tr;
return apiResponse;
@@ -126,10 +137,25 @@ class PersonController extends GetControllerEx<PersonModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.person_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
if (name.value.isEmpty) {
apiResponse.msg = "请输入姓名".tr;
return apiResponse;
}
if (person == null) {
person = {};
}
person['name'] = name.value;
person['id'] = deviceId;
var response =
@@ -161,6 +187,17 @@ class PersonController extends GetControllerEx<PersonModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.disease_list;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =

View File

@@ -0,0 +1,108 @@
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
import 'package:ef/ef.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/util/DailyLogUtils.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:dio/dio.dart' as dio;
part 'repair_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class RepairModel {
String? id; //设备id
String? param; //设备参数
String? issue; //问题描述
String? fileUrl; //文件地址
RepairModel();
factory RepairModel.fromJson(Map<String, dynamic> json) {
try {
return _$RepairModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return RepairModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$RepairModelToJson(this);
}
class RepairController extends GetControllerEx<RepairModel> {
RepairController() {
attr = GetModel(RepairModel()).obs;
}
RxString device_type = "".obs;
RxList repairList = [].obs;
RxString name = "".obs;
RxString phone = "".obs;
List<String>? deviceListId = [];
List<String>? deviceListName = [];
RxList repairHistory = [].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 * 5) {
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}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
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(res, "我的.上传成功".tr, "我的.头像上传失败".tr);
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);
}
}
}

View File

@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'repair_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
RepairModel _$RepairModelFromJson(Map<String, dynamic> json) => RepairModel()
..id = json['id'] as String?
..param = json['param'] as String?
..issue = json['issue'] as String?
..fileUrl = json['fileUrl'] as String?;
Map<String, dynamic> _$RepairModelToJson(RepairModel instance) =>
<String, dynamic>{
'id': instance.id,
'param': instance.param,
'issue': instance.issue,
'fileUrl': instance.fileUrl,
};

View File

@@ -0,0 +1,94 @@
import 'dart:convert';
import 'package:ef/ef.dart';
import 'package:flutter/services.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:path/path.dart' as path;
import 'package:vbvs_app/language/AppLanguage.dart';
part 'language_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class LanguageModel {
String? filename; // 语言文件名称
String? language_name; // 语言名称
bool? selected; // 是否选中
String? language_code;//语言简称
LanguageModel();
factory LanguageModel.fromJson(Map<String, dynamic> json) {
try {
return _$LanguageModelFromJson(json);
} catch (e) {
return LanguageModel(); // 或者返回一个带有错误信息的特定实例
}
}
Map<String, dynamic> toJson() => _$LanguageModelToJson(this);
}
class LanguageController extends GetControllerEx<LanguageModel> {
LanguageController() {
attr = GetModel(LanguageModel()).obs;
}
RxList languageList = [].obs;
var selectLanguage = Rx<LanguageModel?>(null);
Future<void> initLanuageList() async {
try {
String currentLanguageCode = AppLanguage().getCurrentLanguageCode();
languageList.clear(); // 清空现有列表
// 1. 获取 assets/langs/ 目录下所有 .json 文件
final manifestContent = await rootBundle.loadString('AssetManifest.json');
final Map<String, dynamic> manifestMap = json.decode(manifestContent);
// 筛选出 langs 目录下的 .json 文件
final langFiles = manifestMap.keys
.where((String key) =>
key.startsWith('assets/langs/') && key.endsWith('.json'))
.toList();
// 2. 遍历所有语言文件
for (final filePath in langFiles) {
try {
// 加载 JSON 文件内容
final jsonString = await rootBundle.loadString(filePath);
final jsonMap = json.decode(jsonString);
// 提取语言名称(假设 JSON 文件中有 "语言名称" 字段)
final languageName = jsonMap['语言名称'] as String? ??
path.basenameWithoutExtension(filePath);
// 3. 构造 LanguageModel 并添加到列表
final languageModel = LanguageModel()
..filename = path.basename(filePath) // 如 "zh-CN.json"
..language_name = languageName // 如 "简体中文"
..selected =
(path.basename(filePath) == '$currentLanguageCode.json')
..language_code =
path.basenameWithoutExtension(filePath); // 如 "zh-CN"
if (languageModel.selected == true) {
selectLanguage.value = languageModel;
}
languageList.add(languageModel);
} catch (e) {
print('加载语言文件失败: $filePath, 错误: $e');
}
}
print("object");
} catch (e) {
print('初始化语言列表失败: $e');
// 可选:添加默认语言(如英文)作为后备
languageList.add(
LanguageModel()
..filename = 'en-US.json'
..language_name = 'English'
..selected = true, // 默认语言为选中状态
);
}
}
}

View File

@@ -0,0 +1,18 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'language_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
LanguageModel _$LanguageModelFromJson(Map<String, dynamic> json) =>
LanguageModel()
..filename = json['filename'] as String?
..language_name = json['language_name'] as String?;
Map<String, dynamic> _$LanguageModelToJson(LanguageModel instance) =>
<String, dynamic>{
'filename': instance.filename,
'language_name': instance.language_name,
};

View File

@@ -0,0 +1,24 @@
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
class PdfController extends GetxController {
var localPdfPath = Rx<String?>(null);
// 加载 PDF 文件
Future<void> loadPdf() async {
final byteData = await rootBundle.load('assets/img/test.pdf');
final tempDir = await getTemporaryDirectory();
// 使用 path 包拼接路径
final filePath = p.join(tempDir.path, 'test.pdf');
final file = File(filePath);
// 保存文件到临时目录
await file.writeAsBytes(byteData.buffer.asUint8List());
localPdfPath.value = filePath; // 更新 PDF 路径
}
}

View File

@@ -11,6 +11,9 @@ 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/controller/login/login_controller.dart';
import 'package:vbvs_app/controller/message/message_controller.dart';
import 'package:vbvs_app/controller/time/countdown_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/model/user_data.dart';
@@ -64,7 +67,7 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
ApiResponse apiResponse = ApiResponse(code: -1, msg: "我的.头像上传失败".tr);
if (image != null) {
int fileSize = await image.length(); // 获取图片大小,单位为字节
if (fileSize > 1048576) {
if (fileSize > 1048576 * 5) {
apiResponse.msg = "我的.头像限制".tr;
return apiResponse;
}
@@ -72,6 +75,17 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.upload_file;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var formData = dio.FormData.fromMap({
"type": 1,
"file": await dio.MultipartFile.fromFile(
@@ -119,6 +133,17 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
final data = {
"nickName": user.tmpNickName,
if (user.tmpHead != null && user.tmpHead!.isNotEmpty)
@@ -154,6 +179,17 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
String serviceName = ServiceConstant.server_service;
String serviceApi = ServiceConstant.user_info;
String queryUrl = "${serviceAddress}${serviceName}${serviceApi}";
String? language = "";
if (languageController.selectLanguage != null) {
language = languageController.selectLanguage.value!.language_code;
}
if (language != null && language.isNotEmpty) {
if (queryUrl.contains("?")) {
queryUrl += "&lang=$language";
} else {
queryUrl += "?lang=$language";
}
}
var response = await EasyDartModule.dio.get(queryUrl);
if (response != null) {
var responseData =
@@ -192,8 +228,14 @@ class UserInfoController extends GetControllerEx<UserInfoModel> {
bodyDeviceController.bindDeviceNum.value = 0;
HomeController homeController = Get.find();
homeController.sleepNum.value = 0;
LoginController loginController = Get.find();
loginController.model.register_agree = null;
bodyDeviceController.sleepReportData.value = {};
MessageController messageController = Get.find();
messageController.model.body_message_read = 0;
messageController.model.system_message_read = 0;
CountdownController countdownController = Get.find();
countdownController.countdown.value = 0;
return apiResponse;
}
}

View File

@@ -0,0 +1,11 @@
enum MessageStatus {
noNeed(0, '无需处理'),
pending(1, '待处理'),
completed(2, '已处理'),
timeout(3, '已超时');
final int code;
final String description;
const MessageStatus(this.code, this.description);
}

View File

@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:ui';
import 'package:ef/ef.dart';
import 'package:flutter/services.dart';
@@ -7,6 +8,9 @@ class AppLanguage extends Translations {
// 私有构造函数
AppLanguage._internal();
// 当前语言
String _currentLanguageCode = 'zh_CN'; //
// 单例实例
static final AppLanguage _instance = AppLanguage._internal();
@@ -19,23 +23,47 @@ class AppLanguage extends Translations {
Map<String, Map<String, String>> get keys => _localizedValues;
// 动态加载语言文件
Future<void> loadLanguage(String languageCode) async {
if (_localizedValues.containsKey(languageCode)) {
return; // 如果语言已经加载,无需重复加载
}
// Future<void> loadLanguage(String languageCode) async {
// if (_localizedValues.containsKey(languageCode)) {
// return; // 如果语言已经加载,无需重复加载
// }
// try {
// // 加载 JSON 文件
// final jsonString =
// await rootBundle.loadString('assets/langs/$languageCode.json');
// final Map<String, dynamic> jsonMap = json.decode(jsonString);
// // 扁平化 JSON 数据并存储到缓存
// _localizedValues[languageCode] = _flattenJson(jsonMap);
// // 通知 GetX 更新 keys
// // Get.forceAppUpdate();
// Get.appendTranslations(keys);
// _currentLanguageCode = languageCode;
// Get.updateLocale(Locale(languageCode));
// } catch (e) {
// print('Error loading $languageCode language file: $e');
// }
// }
Future<void> loadLanguage(String languageCode) async {
try {
// 加载 JSON 文件
final jsonString =
await rootBundle.loadString('assets/langs/$languageCode.json');
final Map<String, dynamic> jsonMap = json.decode(jsonString);
// 扁平化 JSON 数据并存储到缓存
_localizedValues[languageCode] = _flattenJson(jsonMap);
// 扁平化 JSON 数据
final Map<String, String> translations = _flattenJson(jsonMap);
// 通知 GetX 更新 keys
// Get.forceAppUpdate();
Get.appendTranslations(keys);
// 加载并设置翻译
Get.clearTranslations(); // 清除之前加载的翻译,确保切换时不混乱
Get.addTranslations({languageCode: translations});
Get.updateLocale(Locale(languageCode)); // 切换语言
_currentLanguageCode = languageCode; // 可选:记录当前语言码
} catch (e) {
print('Error loading $languageCode language file: $e');
}
@@ -60,4 +88,14 @@ class AppLanguage extends Translations {
void clearLanguage(String languageCode) {
_localizedValues.remove(languageCode);
}
// 获取当前使用的语言
String getCurrentLanguageCode() {
return _currentLanguageCode;
}
Locale get currentLocale {
final parts = _currentLanguageCode.split('-');
return Locale(parts[0], parts.length > 1 ? parts[1] : null);
}
}

View File

@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:EasyDartModule/EasyDartModule.dart';
@@ -7,15 +8,19 @@ import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:fluwx/fluwx.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/CheckNetwork.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_calibration_controller.dart';
import 'package:vbvs_app/controller/device/device_share_controller.dart';
import 'package:vbvs_app/controller/device/device_share_list_controller.dart';
import 'package:vbvs_app/controller/device/device_type_controller.dart';
import 'package:vbvs_app/controller/home/home_controller.dart';
import 'package:vbvs_app/controller/login/login_controller.dart';
@@ -23,6 +28,9 @@ 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/repair/repair_controller.dart';
import 'package:vbvs_app/controller/setting/language/language_controller.dart';
import 'package:vbvs_app/controller/setting/pdf/PdfController.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';
@@ -34,7 +42,12 @@ import 'routers/routers.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final Locale? deviceLocale = Get.deviceLocale;
print('系统语言: ${deviceLocale?.languageCode}');
// await AppLanguage().loadLanguage("en_US");
await AppLanguage().loadLanguage("zh_CN");
await initLanguageSetting();
WidgetsFlutterBinding.ensureInitialized();
// ApiService.init();
@@ -44,10 +57,12 @@ Future<void> main() async {
initEasyDartModule();
await initLogin();
await initLog();
await messageStatus();
startMessagePolling();
// 检查网络
// Checknetwork.checkNetwork();
Checknetwork.checkNetwork();
// 微信开放平台注册
// initWX();
initWX();
// // 初始化 flutter_xupdate android app 更新
// initXUpdate();
@@ -58,6 +73,45 @@ Future<void> main() async {
});
}
initLanguageSetting() {
Get.put(LanguageController());
LanguageController languageController = Get.find();
languageController.initLanuageList();
}
// 初始化微信开放平台注册
Future<void> initWX() async {
Fluwx fluwx = Fluwx();
fluwx.registerApi(
//请填写自己的微信appid
appId: "wxeb2688220799e2c5",
doOnAndroid: true,
doOnIOS: true,
);
}
Timer? _messageTimer;
void startMessagePolling() {
// 避免重复启动
_messageTimer?.cancel();
_messageTimer = Timer.periodic(Duration(seconds: 5), (timer) async {
try {
MessageController messageController = Get.find();
messageController.getMessageStatus();
// print("轮询消息状态成功");
} catch (e) {
print("轮询消息状态失败: $e");
}
});
}
messageStatus() async {
Get.put(MessageController());
MessageController messageController = Get.find();
await messageController.getMessageStatus();
}
void initEasyDartModule() {
try {
EasyDartModule.init(
@@ -129,49 +183,6 @@ Future<void> initLogin() async {
}
}
// 初始化微信开放平台注册
// Future<void> initWX() async {
// Fluwx fluwx = Fluwx();
// fluwx.registerApi(
// //请填写自己的微信appid
// appId: "wx929c548fea6af9c7",
// doOnAndroid: true,
// doOnIOS: true,
// universalLink: "https://zhmht.swes.com.cn/app/");
// }
// // 初始化 flutter_xupdate android app 更新
// Future<void> initXUpdate() async {
// if (Platform.isAndroid) {
// FlutterXUpdate.init(
// // 是否输出日志
// debug: true,
// // 是否使用post请求
// isPost: true,
// // post请求是否是上传json
// isPostJson: false,
// // 请求响应超时时间
// timeout: 25000,
// // 是否开启自动模式
// isWifiOnly: false,
// // 是否开启自动模式
// isAutoMode: false,
// // 需要设置的公共参数
// supportSilentInstall: false,
// // 在下载过程中,如果点击了取消的话,是否弹出切换下载方式的重试提示弹窗
// enableRetry: false)
// .then((value) {
// print('初始化成功: $value');
// }).catchError((error) {
// print(error);
// });
// FlutterXUpdate.setUpdateHandler(onUpdateError: (message) async {
// print('onUpdateError: $message');
// });
// }
// }
class MyApp extends StatelessWidget {
MyApp({super.key});
final ThemeController themeController = Get.put(ThemeController());
@@ -190,7 +201,8 @@ class MyApp extends StatelessWidget {
FitTool.init(width < height ? width : height);
return GetMaterialApp(
translations: AppLanguage(),
locale: const Locale("zh", "CN"),
// locale: const Locale("zh", "CN"),
locale: AppLanguage().currentLocale, // ✅ 动态读取当前语言
fallbackLocale: const Locale("zh", "CN"),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
@@ -200,6 +212,7 @@ class MyApp extends StatelessWidget {
],
supportedLocales: [
const Locale('zh', 'CN'), // 中文
const Locale('en', 'US'), // ⚠️ 添加你支持的语言
],
debugShowCheckedModeBanner: false,
title: '',
@@ -219,7 +232,10 @@ class MyApp extends StatelessWidget {
Get.lazyPut(() => BodyDeviceController()),
Get.lazyPut(() => HomeController()),
Get.lazyPut(() => DeviceShareController()),
Get.lazyPut(() => MessageController()),
Get.lazyPut(() => DeviceShareListController()),
Get.lazyPut(() => DeviceCalibrationController()),
Get.lazyPut(() => RepairController()),
Get.lazyPut(() => PdfController()),
]));
});
}

View File

@@ -1,8 +1,10 @@
import 'package:ef/ef.dart';
import 'package:flutter/cupertino.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/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
getOnePicker(context, List arr, int checkIndex, Function onSelectedItemChanged,
@@ -780,3 +782,133 @@ void showPermissionInfoDialog(BuildContext context, List data) {
},
);
}
void showProgressDialog(
BuildContext context,
ValueNotifier<double> progressNotifier,
ValueNotifier<bool> failureNotifier,
) {
ThemeController themeController = Get.find();
showDialog(
context: context,
barrierDismissible: false, // 点击对话框外部不可关闭
builder: (BuildContext dialogContext) {
return Stack(
children: [
Positioned(
top: MediaQuery.of(context).size.height * 0.4,
left: MediaQuery.of(context).size.width * 0.05,
right: MediaQuery.of(context).size.width * 0.05,
child: Material(
color: Colors.transparent,
child: Dialog(
backgroundColor: Colors.transparent,
insetPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: ValueListenableBuilder<double>(
valueListenable: progressNotifier,
builder: (context, progress, _) {
return ValueListenableBuilder<bool>(
valueListenable: failureNotifier,
builder: (context, isFailure, __) {
// 关闭弹窗的逻辑
if (isFailure) {
// 延迟关闭弹窗和提示错误
Future.delayed(Duration(milliseconds: 300), () {
if (Navigator.canPop(dialogContext)) {
Navigator.of(dialogContext).pop();
}
TopSlideNotification.show(
context,
text: "设备校准失败".tr,
textColor: Colors.red,
);
});
} else if (progress >= 1.0) {
// 延迟关闭弹窗和提示成功(可选)
Future.delayed(Duration(milliseconds: 300), () {
if (Navigator.canPop(dialogContext)) {
Navigator.of(dialogContext).pop();
}
TopSlideNotification.show(
context,
text: "设备校准完成".tr,
textColor: themeController.currentColor.sc3,
);
});
}
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
isFailure
? '失败'.tr
: '${(progress * 100).toStringAsFixed(0)}%',
style: TextStyle(
fontSize: 26.rpx,
color: isFailure
? Colors.red
: themeController.currentColor.sc3,
),
),
SizedBox(height: 40.rpx),
Stack(
children: [
Container(
width: double.infinity,
height: 21.rpx,
decoration: BoxDecoration(
color: stringToColor("#D9D9D9"),
borderRadius: BorderRadius.circular(
AppConstants().button_container_radius,
),
),
),
Container(
width: progress *
MediaQuery.of(context).size.width *
0.8,
height: 10.rpx,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: isFailure
? [themeController.currentColor.sc9]
: [
themeController
.currentColor.sc1,
themeController
.currentColor.sc2,
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
borderRadius:
BorderRadius.circular(5.rpx),
),
),
],
),
],
);
},
);
},
),
),
),
),
),
],
);
},
);
}

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
@@ -26,6 +28,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
final BodyDeviceController bodyDeviceController = Get.find();
final GlobalKey addIconKey = GlobalKey();
OverlayEntry? _popupEntry;
Timer? _timer;
void _showPopup() {
final renderBox =
@@ -95,7 +98,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
width: double.infinity,
child: Center(
child: Text(
'扫一扫'.tr,
'扫一扫.标题'.tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
@@ -119,7 +122,7 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
width: double.infinity,
child: Center(
child: Text(
'蓝牙绑定'.tr,
'蓝牙绑定.标题'.tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
@@ -151,6 +154,16 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
void initState() {
bodyDeviceController.keyWord.value = "";
super.initState();
// 初次请求一次
_fetchDeviceList();
// 每 5 秒定时请求一次
_timer = Timer.periodic(Duration(seconds: 5), (timer) {
_fetchDeviceList();
});
}
void _fetchDeviceList() {
bodyDeviceController.getDeviceList().then((apiResponse) {
if (apiResponse.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
@@ -162,6 +175,12 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
});
}
@override
void dispose() {
_timer?.cancel(); // 页面销毁时取消定时器
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
@@ -265,127 +284,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
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: [
@@ -520,7 +418,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
}),
],
),
Container(
width:
MediaQuery.sizeOf(context).width * 0.38,
@@ -661,20 +558,6 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
.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,
@@ -722,27 +605,26 @@ class _BodyDevicePageState extends State<BodyDeviceWidget> {
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)),
return Expanded(
child: isEmpty
? 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)),
),
),
),
);
);
}),
],
),

File diff suppressed because it is too large Load Diff

View File

@@ -281,15 +281,6 @@ class _DeviceDetailPageState extends State<DeviceDetailPage> {
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,
@@ -320,7 +311,7 @@ class _DeviceDetailPageState extends State<DeviceDetailPage> {
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['person']['name'] ?? '未命名'.tr}',
'${widget.device['person']?['name'] ?? '未命名'.tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -446,7 +437,7 @@ class _DeviceDetailPageState extends State<DeviceDetailPage> {
child: Align(
alignment: AlignmentDirectional(-1.rpx, 0.rpx),
child: Text(
'${widget.device['update_time'] ?? '-'.tr}',
'${widget.device['status']?['updateTime'] == null ? '-'.tr : MyUtils.timestampToDateString(widget.device['status']?['updateTime'])}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(

View File

@@ -226,7 +226,7 @@ class _InstantBodyPageState extends State<InstantBodyPage> {
CrossAxisAlignment.start,
children: [
Text(
'${device['person']['name'] ?? '未命名'.tr}',
'${device['person']?['name'] ?? '未命名'.tr}',
style:
FlutterFlowTheme.of(context)
.bodyMedium
@@ -239,7 +239,7 @@ class _InstantBodyPageState extends State<InstantBodyPage> {
),
),
Text(
'${MyUtils.getAgeByDate(MyUtils.formatBirthdayTime(device['person']['birthday'])) ?? '未知数据'.tr}',
'${MyUtils.getAgeByDate(MyUtils.formatBirthdayTime(device['person']?['birthday'])) ?? '未知数据'.tr}',
style:
FlutterFlowTheme.of(context)
.bodyMedium
@@ -306,8 +306,8 @@ class _InstantBodyPageState extends State<InstantBodyPage> {
CrossAxisAlignment.start,
children: [
Text(
// '${device['_id']??'未知数据'.tr}',
"D11250300003",
'${device['code'] ?? '未知数据'.tr}',
// "D11250300003",
style:
FlutterFlowTheme.of(context)
.bodyMedium
@@ -320,7 +320,7 @@ class _InstantBodyPageState extends State<InstantBodyPage> {
),
),
Text(
'${device['person']['weight'] ?? '未知数据'.tr}kg',
'${device['person']?['weight'] ?? '未知数据'.tr}kg',
style:
FlutterFlowTheme.of(context)
.bodyMedium

View File

@@ -69,7 +69,6 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
}
Future<void> _requestBluetoothPermission() async {
// Android 13+ 使用新的蓝牙权限
Map<Permission, PermissionStatus> statuses = await [
Permission.bluetoothScan,
Permission.bluetoothConnect,
@@ -113,7 +112,9 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
// 开始扫描蓝牙设备
void _startScanning() async {
if (!mounted) return;
if (!mounted || isScanning) return;
_scanSubscription?.cancel();
var bluetoothState = await FlutterBluePlus.isOn;
if (!bluetoothState && !_isDialogShowing) {
_isDialogShowing = true;
@@ -131,6 +132,7 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
// await FlutterBluePlus.startScan(timeout: Duration(minutes: 30));
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
if (!mounted) return; // 确保页面未销毁
final signalThreshold = blueteethBindController.model.singal!;
final filteredResults = results
.where((r) =>
@@ -334,7 +336,7 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
mainAxisSize: MainAxisSize.max,
children: [
Text(
'最小信号强度',
'最小信号强度'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -415,7 +417,7 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
Expanded(
child: Container(
width: 100.rpx,
height: 100.rpx,
height: 80.rpx,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context)
.secondaryBackground,
@@ -519,7 +521,7 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
),
),
Text(
'搜索',
'搜索'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -547,7 +549,8 @@ class _BlueteethDevicePageState extends State<BlueteethDevicePage> {
EdgeInsetsDirectional.fromSTEB(19.rpx, 0, 0, 0),
child: Obx(() {
return Text(
'匹配出的外围设备${blueteethBindController.model.betDevicelist!.length}',
'匹配出的外围设备'.tr +
"${blueteethBindController.model.betDevicelist!.length}",
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(

View File

@@ -0,0 +1,123 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutterflow_ui/flutterflow_ui.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/device_share_list_controller.dart';
import 'package:vbvs_app/controller/message/message_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
class DeviceShareInfoWidget extends StatefulWidget {
final data;
const DeviceShareInfoWidget({super.key, required this.data});
@override
State<DeviceShareInfoWidget> createState() => _DeviceShareInfoWidgetState();
}
class _DeviceShareInfoWidgetState extends State<DeviceShareInfoWidget> {
ThemeController themeController = Get.find();
MessageController messageController = Get.find();
DeviceShareListController deviceShareListController = Get.find();
@override
Widget build(BuildContext context) {
bool selected = false;
return ClickableContainer(
backgroundColor: themeController.currentColor.sc5,
highlightColor: themeController.currentColor.sc3,
borderRadius: 20.rpx,
padding: EdgeInsetsDirectional.fromSTEB(0.rpx, 33.rpx, 0.rpx, 33.rpx),
onTap: () {},
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Obx(() {
return Theme(
data: ThemeData(
checkboxTheme: CheckboxThemeData(
visualDensity: VisualDensity.compact,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(64),
),
),
unselectedWidgetColor: Color(0xFFD3D3D3),
),
child: Checkbox(
value: deviceShareListController.selectedShareInfo.value
.contains(widget.data[0]['k']),
onChanged: (newValue) async {
if (newValue != null) {
if (newValue == true) {
deviceShareListController.selectedShareInfo.value
.add(widget.data[0]['k']);
} else {
deviceShareListController.selectedShareInfo.value
.remove(widget.data[0]['k']);
}
}
final selectedCount =
deviceShareListController.selectedShareInfo.length;
final totalCount =
deviceShareListController.shareInfoList.length;
deviceShareListController.model.all =
(selectedCount == totalCount) ? 1 : 0;
deviceShareListController.selectedShareInfo
.refresh(); // ✅ 关键代码
deviceShareListController.updateAll();
},
side: BorderSide(
width: 1.5,
color: FlutterFlowTheme.of(context).secondaryText,
),
activeColor: stringToColor("#16C89F"),
checkColor: FlutterFlowTheme.of(context).info,
),
);
}),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
constraints: BoxConstraints(
minWidth: 30.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(widget.data.length, (index) {
final item = widget.data[index];
return Container(
constraints: BoxConstraints(
minHeight: 62.rpx,
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
"${item['k']}" + ":" + "${item['v']}",
style:
FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
),
),
);
}),
),
),
].divide(SizedBox(width: 50.rpx)),
),
].divide(SizedBox(
width: 10.rpx,
)),
),
);
}
}

View File

@@ -41,6 +41,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
deviceData.rssi = widget.bleDevice.rssi;
deviceData.mac = deviceData.deviceId.replaceAll(':', '');
BleDeviceData device = deviceData;
blueteethBindController.currentDeviceMac = device.mac;
device = blueteethBindController.model.betDevicelist!.firstWhere(
(d) => d.mac == device.mac,
orElse: () => device,
@@ -208,7 +209,7 @@ class _SingleBlueteethDeviceCompoentWidgetState
],
),
Text(
'版本:${device.version ?? '-'}',
"版本".tr + '${device.version ?? '-'}',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
color: const Color(0xFFF6FAFD),

View File

@@ -708,3 +708,133 @@ void showWifiDialog(
},
);
}
void showTipDialog(
BuildContext context,
Widget widget,
// String title,
) {
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, 93.rpx, 0, 74.rpx),
// child: Text(
// title,
// style: FlutterFlowTheme.of(context).bodyMedium.override(
// fontFamily: 'Inter',
// fontSize: 30.rpx,
// letterSpacing: 0.0,
// color: themeController.currentColor.sc3,
// ),
// ),
// ),
// ),
Align(
alignment: AlignmentDirectional(0, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 93.rpx, 0, 74.rpx),
child: widget,
),
),
// widget,
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0, 19.rpx, 0, 60.rpx),
child: CustomCard(
borderRadius: AppConstants().button_container_radius,
onTap: () {
Get.back();
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: MediaQuery.sizeOf(context).width,
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

@@ -0,0 +1,617 @@
import 'dart:async';
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/common/util/requestWithLog.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/device/device_calibration_controller.dart';
import 'package:vbvs_app/pages/common/selectDialog.dart';
class CalibrationPage extends StatefulWidget {
int? type; //1.绑定时 2.绑定后
CalibrationPage({super.key, required this.type});
@override
State<CalibrationPage> createState() => _CalibrationPageState();
}
class _CalibrationPageState extends State<CalibrationPage> {
DeviceCalibrationController deviceCalibrationController = Get.find();
@override
void initState() {
super.initState();
deviceCalibrationController.process.value = 0;
deviceCalibrationController.bed_calibration.value = 0;
deviceCalibrationController.position_calibration.value = 0;
}
@override
void dispose() {
super.dispose();
}
@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,
),
),
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,
),
if (widget.type == 1)
Positioned(
right: 20.rpx,
child: CustomCard(
borderRadius: 20.rpx,
onTap: () async {
Get.toNamed("/personPage");
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: 100.rpx,
height: 60.rpx,
alignment: Alignment.center,
padding: EdgeInsetsDirectional.fromSTEB(
16.rpx, 0, 16.rpx, 0),
child: Text(
'跳过'.tr,
style: TextStyle(
fontFamily: 'Inter Tight',
color: themeController.currentColor.sc3,
letterSpacing: 0.0,
),
),
),
),
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
// child: Container(),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
30.rpx, 0.rpx, 30.rpx, 0.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0.rpx, 30.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
borderRadius: BorderRadius.circular(16.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
10.rpx, 20.rpx, 34.rpx, 20.rpx),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc21,
borderRadius: 0, // 可按需设置圆角
padding: EdgeInsets.symmetric(
vertical: 10.rpx), // 可自定义内边距
onTap: () {
deviceCalibrationController.process.value = 0;
deviceCalibrationController.updateAll();
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Obx(() {
return Visibility(
maintainState: true,
maintainAnimation: true,
maintainSize: true,
visible: deviceCalibrationController
.process.value ==
0,
child: SvgPicture.asset(
'assets/img/icon/select_arrow.svg',
width: 17.rpx,
height: 17.rpx,
color: themeController
.currentColor.sc9,
),
);
}),
SizedBox(width: 8.rpx),
Text(
'离床校准'.tr,
style: TextStyle(
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
],
),
Obx(() {
return Text(
deviceCalibrationController
.bed_calibration.value ==
0
? '未完成'.tr
: "已完成".tr,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
color: deviceCalibrationController
.bed_calibration.value ==
0
? themeController.currentColor.sc3
: themeController
.currentColor.sc1,
),
);
}),
],
),
),
SizedBox(height: 41.rpx),
ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc21,
borderRadius: 0, // 可根据需要设为圆角
padding: EdgeInsets.symmetric(
vertical: 10.rpx), // 可根据需要调整上下内边距
onTap: () {
deviceCalibrationController.process.value = 1;
deviceCalibrationController.updateAll();
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Obx(() {
return Visibility(
maintainState: true,
maintainAnimation: true,
maintainSize: true,
visible: deviceCalibrationController
.process.value ==
1,
child: SvgPicture.asset(
'assets/img/icon/select_arrow.svg',
width: 17.rpx,
height: 17.rpx,
color: themeController
.currentColor.sc9,
),
);
}),
SizedBox(width: 8.rpx),
Text(
'位置校准'.tr,
style: TextStyle(
fontSize: 30.rpx,
letterSpacing: 0.0,
color: themeController
.currentColor.sc3,
),
),
],
),
Obx(() {
return Text(
deviceCalibrationController
.position_calibration
.value ==
0
? '未完成'.tr
: "已完成".tr,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
color: deviceCalibrationController
.position_calibration
.value ==
0
? themeController.currentColor.sc3
: themeController
.currentColor.sc1,
),
);
}),
],
),
),
],
),
),
),
),
Obx(() {
return Expanded(
child: SizedBox(
width: double.infinity,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 55.rpx, 100.rpx, 0),
child: Stack(
clipBehavior: Clip.none,
children: [
Container(
width:
MediaQuery.sizeOf(context).width * 0.65,
height:
MediaQuery.sizeOf(context).height * 0.3,
child: Stack(
children: [
// Image.asset(
// deviceCalibrationController
// .bed_type.value ==
// 0
// ? "assets/img/single_pillow.png"
// : "assets/img/double_pillow.png",
// width: double.infinity,
// height: double.infinity,
// fit: BoxFit.contain,
// ),
Image.asset(
deviceCalibrationController
.process.value ==
1 &&
deviceCalibrationController
.position_calibration
.value ==
1
? (deviceCalibrationController
.bed_type.value ==
0
? "assets/img/single_person.png"
: "assets/img/double_person.png")
: (deviceCalibrationController
.bed_type.value ==
0
? "assets/img/single_pillow.png"
: "assets/img/double_pillow.png"),
width: double.infinity,
height: double.infinity,
fit: BoxFit.contain,
),
// 床头文字
Positioned(
top: 23.rpx,
left:
(MediaQuery.sizeOf(context).width *
0.65) /
2 -
26.rpx,
child: Text(
'床头'.tr,
style: TextStyle(
fontSize: 26.rpx,
color: themeController
.currentColor.sc4,
),
),
),
],
),
),
Obx(() {
final double centerLeft =
(bodySize.maxWidth * 0.56) / 2;
if (deviceCalibrationController
.bed_type.value ==
0 &&
deviceCalibrationController
.process.value ==
1) {
//单人床位置校准
return Positioned(
top: -40.rpx,
left: centerLeft - 0.rpx,
child: Container(
width: bodySize.maxWidth * 0.087,
height: bodySize.maxHeight * 0.06,
constraints: BoxConstraints(
minWidth: 65.rpx,
minHeight: 76.rpx,
),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/img/tip_arrow.gif'),
fit: BoxFit.cover,
),
),
),
);
}
if (deviceCalibrationController
.bed_type.value ==
1 &&
deviceCalibrationController
.process.value ==
1) {
//双人人床位置校准
return Positioned(
top: -40.rpx,
left: (MediaQuery.sizeOf(context).width *
0.65) *
0.22 -
0.rpx,
child: Container(
width: bodySize.maxWidth * 0.087,
height: bodySize.maxHeight * 0.06,
constraints: BoxConstraints(
minWidth: 65.rpx,
minHeight: 76.rpx,
),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/img/tip_arrow.gif'),
fit: BoxFit.cover,
),
),
),
);
}
return Container();
}),
Positioned(
top: MediaQuery.sizeOf(context).height * 0.3 +
82.rpx,
left: 0,
right: 0,
child: Obx(() {
return Column(
children: [
Text(
(deviceCalibrationController
.process.value ==
0 &&
deviceCalibrationController
.bed_calibration
.value ==
1) ||
(deviceCalibrationController
.process.value ==
1 &&
deviceCalibrationController
.position_calibration
.value ==
1)
? '校准完成'.tr
: deviceCalibrationController
.process.value ==
0
? '离床校准提示'.tr
: '位置校准提示'.tr,
style: TextStyle(
fontSize: 38.rpx,
letterSpacing: 0.0,
color: ((deviceCalibrationController
.process
.value ==
0 &&
deviceCalibrationController
.bed_calibration
.value ==
1) ||
(deviceCalibrationController
.process
.value ==
1 &&
deviceCalibrationController
.position_calibration
.value ==
1))
? themeController
.currentColor.sc1
: themeController
.currentColor.sc9,
),
),
],
);
}),
),
],
),
),
),
);
}),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 0.rpx, 100.rpx, 60.rpx),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () async {
BlueteethBindController blueteethBindController =
Get.find();
requestWithLog(
logTitle: "设备校准",
method: MyHttpMethod.post,
queryUrl: ServiceConstant.start_calibration,
data: {
"deviceId":
blueteethBindController.currentDeviceMac
},
onSuccess: (res) {
final ValueNotifier<double> progressNotifier =
ValueNotifier<double>(0.0);
final ValueNotifier<bool> failureNotifier =
ValueNotifier<bool>(false);
Timer? pollingTimer;
// 定义请求函数
void requestCalibrationProgress() {
requestWithLog(
logTitle: "设备校准进度",
method: MyHttpMethod.post,
queryUrl: ServiceConstant.calibration_process,
data: {
"deviceId":
blueteethBindController.currentDeviceMac
},
onSuccess: (res) {
double process =
(res.data['process'] ?? 0).toDouble();
progressNotifier.value = process;
if (process >= 100) {
if (deviceCalibrationController
.process.value ==
0) {
deviceCalibrationController
.bed_calibration.value = 1;
deviceCalibrationController.updateAll();
}
if (deviceCalibrationController
.process.value ==
1) {
deviceCalibrationController
.position_calibration.value = 1;
deviceCalibrationController.updateAll();
}
pollingTimer?.cancel();
}
},
onFailure: (res) {
pollingTimer?.cancel();
failureNotifier.value = true;
TopSlideNotification.show(
context,
text: res.msg ?? "服务器.失败".tr,
textColor:
themeController.currentColor.sc9,
);
},
);
}
// 启动轮询
pollingTimer =
Timer.periodic(Duration(seconds: 2), (timer) {
requestCalibrationProgress();
});
// 初始调用一次
requestCalibrationProgress();
// 显示进度弹窗
showProgressDialog(
context, progressNotifier, failureNotifier);
},
onFailure: (res) {
TopSlideNotification.show(
context,
text: res.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
},
);
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
width: 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(
//todo 颜色
color: themeController.currentColor.sc3,
fontFamily: 'Inter',
fontSize:
AppConstants().normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
width: 17.rpx,
)),
),
),
),
),
],
),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,461 @@
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/NullDataComponentWidget.dart';
import 'package:vbvs_app/component/tool/ClickableContainer.dart';
import 'package:vbvs_app/controller/device/device_share_list_controller.dart';
import 'package:vbvs_app/model/BleDeviceData.dart';
import 'package:vbvs_app/pages/device_bind/componnet/DeviceShareInfoWidget.dart';
class DeviceShareListPage extends StatefulWidget {
String device = "";
DeviceShareListPage({super.key, required this.device});
@override
State<DeviceShareListPage> createState() => _DeviceShareListPageState();
}
class _DeviceShareListPageState extends State<DeviceShareListPage> {
DeviceShareListController deviceShareListController = Get.find();
@override
void initState() {
deviceShareListController.model.key = null;
deviceShareListController.shareInfoList.value = [];
deviceShareListController.selectedShareInfo.value = [];
deviceShareListController.getDeviceShareList(widget.device);
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, boxConstraints) => 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(
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
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,
),
),
//todo 返回刷新列表
Positioned(
left: 0,
child: returnIconButtom,
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
height: 40.rpx,
),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc3,
borderRadius: BorderRadius.circular(20.rpx),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
35.rpx, 0, 35.rpx, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 0.rpx, 0, 0),
child: Container(
width: 25.rpx,
height: 25.rpx,
// width: double.infinity,
decoration: BoxDecoration(),
child: SvgPicture.asset(
'assets/img/icon/query.svg',
fit: BoxFit.cover,
color: stringToColor("#333333"), //固定
),
),
),
Expanded(
child: Container(
width: 100.rpx,
height: 80.rpx,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context)
.secondaryBackground,
),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: TextFormField(
onChanged: (value) {
deviceShareListController
.model.key = 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,
),
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: themeController
.currentColor.sc22,
),
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
cursorColor:
FlutterFlowTheme.of(context)
.primaryText,
),
),
),
),
].divide(SizedBox(width: 6.rpx)),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
26.rpx, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
height: 50.rpx,
child: VerticalDivider(
thickness: 2.rpx,
color: stringToColor("#333333"), //固定
),
),
ClickableContainer(
onTap: () async {
// ApiResponse apiResponse =
// await deviceShareListController
// .getDeviceShareList(
// key: deviceShareListController
// .model.key);
// if (apiResponse.code ==
// HttpStatusCodes.ok) {
// TopSlideNotification.show(
// context,
// text: apiResponse.msg!,
// textColor:
// themeController.currentColor.sc2,
// );
// deviceShareListController.updateAll();
// } else {
// TopSlideNotification.show(
// context,
// text: apiResponse.msg!,
// textColor:
// themeController.currentColor.sc9,
// );
// }
},
padding: EdgeInsets.symmetric(
horizontal: 10.rpx, vertical: 6.rpx),
borderRadius: 12.rpx,
backgroundColor: Colors.transparent,
highlightColor: stringToColor("#333333")
.withOpacity(0.08), // 可选点击反馈色
child: Text(
'搜索'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
color:
stringToColor("#333333"), //固定
),
),
),
].divide(SizedBox(width: 26.rpx)),
),
),
],
),
),
),
Container(
constraints: BoxConstraints(
minHeight: 100.rpx,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Theme(
data: ThemeData(
checkboxTheme: CheckboxThemeData(
visualDensity: VisualDensity.compact,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(64),
),
),
unselectedWidgetColor: Color(0xFFD3D3D3),
),
child: Obx(
() => Checkbox(
value:
deviceShareListController.model.all ==
0
? false
: true,
onChanged: (newValue) async {
if (newValue == true) {
// 设置为全选
deviceShareListController.model.all =
1;
deviceShareListController
.selectedShareInfo.value =
deviceShareListController
.shareInfoList
.map((e) => e['id'] as String)
.toList();
} else {
// 取消全选
deviceShareListController.model.all =
0;
deviceShareListController
.selectedShareInfo
.clear();
}
deviceShareListController
.selectedShareInfo
.refresh();
deviceShareListController.updateAll();
},
side: BorderSide(
width: 1.5,
color: FlutterFlowTheme.of(context)
.secondaryText,
),
activeColor: stringToColor("#16C89F"),
checkColor:
FlutterFlowTheme.of(context).info,
),
)),
Text(
"全选".tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(
width: 10.rpx,
)),
),
ClickableContainer(
onTap: () async {
//todo 删除分享
// ApiResponse apiResponse =
// await deviceShareListController
// .deleteShareDevice();
// if (apiResponse.code == HttpStatusCodes.ok) {
// TopSlideNotification.show(context,
// text: apiResponse.msg!);
// } else {
// TopSlideNotification.show(context,
// text: apiResponse.msg!,
// textColor:
// themeController.currentColor.sc9);
// }
},
padding: EdgeInsets.symmetric(
horizontal: 20.rpx, vertical: 10.rpx),
borderRadius: 20.rpx,
backgroundColor: Colors.transparent,
highlightColor: themeController.currentColor.sc3
.withOpacity(0.1),
child: Text(
"删除".tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
),
),
),
],
),
),
Expanded(
child: deviceShareListController
.shareInfoList.value.isNotEmpty
? SingleChildScrollView(
child: Obx(() {
var selected = deviceShareListController
.selectedShareInfo.value;
return Column(
children: deviceShareListController
.shareInfoList.value
.map((item) =>
DeviceShareInfoWidget(data: item))
.toList()
.divide(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(
height: 30.rpx,
)),
);
}),
)
: NullDataWidget(),
),
].divide(SizedBox(height: 30.rpx)),
),
),
),
),
),
),
);
}
}
BleDeviceData parseBleData(List<int> data) {
if (data.length < 18) {
throw Exception('BLE广播数据长度不足18字节');
}
int type = data[0];
int sn = data[1];
// 设备唯一ID (6字节),格式化为 MAC 地址样式
String deviceId =
List.generate(6, (i) => data[2 + i].toRadixString(16).padLeft(2, '0'))
.join(":")
.toUpperCase();
int bre = data[8];
int ht = data[9];
int active = data[10];
int flag = data[11];
// version 是4字节 uint大端字节序
int version =
(data[12] << 24) | (data[13] << 16) | (data[14] << 8) | data[15];
// qsn 是2字节 ushort大端字节序
int qsn = (data[16] << 8) | data[17];
return BleDeviceData(
type: type,
sn: sn,
deviceId: deviceId,
bre: bre,
ht: ht,
active: active,
flag: flag,
version: version,
qsn: qsn,
);
}

View File

@@ -276,7 +276,7 @@ class _DeviceSharePageState extends State<DeviceSharePage> {
children: [
TextSpan(
text:
'${deviceShareController.code == 1 ? "邀请成功".tr : "邀请失败".tr}',
'${deviceShareController.code.value == 1 ? "邀请成功".tr : "邀请失败".tr}',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -284,7 +284,7 @@ class _DeviceSharePageState extends State<DeviceSharePage> {
fontSize: 26.rpx,
letterSpacing: 0.0,
color: deviceShareController
.code ==
.code.value ==
1
? themeController
.currentColor.sc2

View File

@@ -35,8 +35,9 @@ class _EPageState extends State<DeviceTypePage> {
super.initState();
deviceTypeController.getDeviceType().then((response) {
if (response.code != HttpStatusCodes.ok) {
// 延迟到 widget 构建后再执行 show
TopSlideNotification.show(
Get.context!,
context, // 用当前页面 context 替代 Get.context!
text: response.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
@@ -273,7 +274,7 @@ class _EPageState extends State<DeviceTypePage> {
),
alignment: Alignment.center, // 居中对齐
child: Text(
'绑定引导.跳过'.tr,
'确认'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -332,7 +333,7 @@ class _EPageState extends State<DeviceTypePage> {
children: [
/// 居中标题
Text(
'设备列表',
'设备列表'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
@@ -429,7 +430,7 @@ class _EPageState extends State<DeviceTypePage> {
title,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
color: const Color(0xFFC2CED7),
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
letterSpacing: 0.0,
),

View File

@@ -30,11 +30,13 @@ class _DeviceTypeListPageState extends State<DeviceTypeListPage> {
super.initState();
deviceTypeController.getDeviceType().then((response) {
if (response.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: response.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
WidgetsBinding.instance.addPostFrameCallback((_) {
TopSlideNotification.show(
context,
text: response.msg ?? "服务器.失败".tr,
textColor: themeController.currentColor.sc9,
);
});
}
});
}
@@ -68,7 +70,7 @@ class _DeviceTypeListPageState extends State<DeviceTypeListPage> {
children: [
/// 居中标题
Text(
'设备列表',
'设备列表'.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: themeController.currentColor.sc3,
@@ -165,7 +167,7 @@ class _DeviceTypeListPageState extends State<DeviceTypeListPage> {
title,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
color: const Color(0xFFC2CED7),
color: themeController.currentColor.sc3,
fontSize: 30.rpx,
letterSpacing: 0.0,
),

View File

@@ -19,7 +19,6 @@ import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class WifiPage extends StatefulWidget {
WifiPage({super.key});
// WifiPage({super.key});
@override
State<WifiPage> createState() => _WifiPageState();
@@ -32,8 +31,6 @@ class _WifiPageState extends State<WifiPage> {
PersonController personController = Get.find();
ThemeController themeController = Get.find();
var lisObj;
// List<String> _logBuffer = [];
// bool _isCollecting = false;
@override
void initState() {
@@ -106,7 +103,8 @@ class _WifiPageState extends State<WifiPage> {
textColor: themeController.currentColor.sc9,
);
}
Get.toNamed("/personPage");
Get.toNamed("/calibrationPage",arguments: 1);
// Get.toNamed("/personPage");
// Get.toNamed("/bindDeviceSuccess");
},
colors: [
@@ -686,7 +684,7 @@ class _WifiPageState extends State<WifiPage> {
),
),
Text(
'刷新',
'刷新'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -779,13 +777,13 @@ class _WifiPageState extends State<WifiPage> {
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;
}
}
// 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) {

View File

@@ -2,7 +2,10 @@ 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:fluwx/fluwx.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/common/util/CheckNetwork.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';
@@ -26,6 +29,58 @@ class _EPageState extends State<LoginPage> {
LoginController loginController = Get.find();
ThemeController themeController = Get.find();
@override
void initState() {
super.initState();
LoginController loginController = Get.find();
Fluwx fluwx = loginController.fluwx;
if (isiOS) {
loginController.model.isIos = true;
fluwx.isWeChatInstalled.then((isWeChatInstalled) {
debugPrint('is wechat installed: $isWeChatInstalled');
if (!isWeChatInstalled) {
// TODO ios未安装微信 隐藏微信一键登录按钮
loginController.model.isWeChatNotInstalled = false;
} else {
loginController.model.isWeChatNotInstalled = true;
}
loginController.updateAll();
});
}
// 微信监听回调
loginController.fluwxCancelable = fluwx.addSubscriber((response) async {
if (response is WeChatAuthResponse) {
debugPrint('state :${response.state} \n code:${response.code}');
int errCode = response.errCode ?? -9999;
if (errCode == 0) {
// TODO 微信登录成功 传递code给后台 再操作逻辑
String code = response.code ?? "";
//把微信登录返回的code传给后台剩下的事就交给后台处理
//首次未注册的用户引导去手机号填写页面
//已注册的用户直接跳转首页
if (CommonVariables.isNetWorkOn == false) {
showToast("网络未连接,请开启设备网络后重试");
return;
}
String msg = await loginController.loginByWechatCode(code);
if (msg.isEmpty) {
// TODO 操作全部跳转页面前成功以后移除监听,防止重复监听,其他方式登录成功也需要移出监听
loginController.fluwxCancelable?.cancel();
// 登录成功移出网络检查监听
Checknetwork.subscription?.cancel();
Get.offAndToNamed("/mianPageBottomChange");
}
// TODO 操作全部跳转页面前成功以后移除监听,防止重复监听,其他方式登录成功也需要移出监听
// fluwxCancelable?.cancel();
} else if (errCode == -4) {
showToast("用户拒绝授权");
} else if (errCode == -2) {
showToast("用户取消授权");
}
}
});
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
@@ -186,9 +241,7 @@ class _EPageState extends State<LoginPage> {
], // 渐变色是同一个色,也可以根据需要调整
child: Container(
width:
// MediaQuery.sizeOf(context).width * 0.66,
bodysize.maxWidth,
width: bodysize.maxWidth,
height: MediaQuery.sizeOf(context).height *
0.055,
constraints: BoxConstraints(
@@ -200,19 +253,24 @@ class _EPageState extends State<LoginPage> {
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
'登录页.本机号码一键登录/注册'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
//todo 颜色
color: themeController
.currentColor.sc3,
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
Expanded(
child: Text(
textAlign: TextAlign.center,
'登录页.本机号码一键登录/注册'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
//todo 颜色
color: themeController
.currentColor.sc3,
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
].divide(SizedBox(
width: 17.rpx,
@@ -241,6 +299,8 @@ class _EPageState extends State<LoginPage> {
fontSize: 26.rpx,
color: themeController.currentColor.sc3,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
Padding(
@@ -433,43 +493,97 @@ class _EPageState extends State<LoginPage> {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wechat.png",
width: 30.rpx,
height: 30.rpx,
ClickableContainer(
backgroundColor: Colors.white, // 背景色
highlightColor: Colors.grey, // 点击水波纹颜色
borderRadius: 999.rpx,
padding: EdgeInsets.zero,
// onTap: () {
// TopSlideNotification.show(context,
// text: "待开发功能".tr);
// },
onTap: () async {
if (loginController.model.isIos == true &&
loginController
.model.isWeChatNotInstalled !=
true) {
} else {
if (loginController
.model.register_agree ==
null ||
loginController
.model.register_agree !=
true) {
TopSlideNotification.show(
context,
text: "登录页.未同意协议".tr,
textColor:
themeController.currentColor.sc9,
);
return;
}
await loginController
.wxLoginSendAuth(context);
}
},
child: Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wechat.png",
width: 30.rpx,
height: 30.rpx,
),
),
),
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/tel.png",
width: 30.rpx,
height: 30.rpx,
ClickableContainer(
backgroundColor: Colors.white,
highlightColor: Colors.grey,
borderRadius: 999.rpx,
padding: EdgeInsets.zero,
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/tel.png",
width: 30.rpx,
height: 30.rpx,
),
),
),
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/google.png",
width: 30.rpx,
height: 30.rpx,
ClickableContainer(
backgroundColor: Colors.white,
highlightColor: Colors.grey,
borderRadius: 999.rpx,
padding: EdgeInsets.zero,
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/google.png",
width: 30.rpx,
height: 30.rpx,
),
),
),
].divide(SizedBox(width: 35.rpx)),

View File

@@ -1,11 +1,8 @@
import 'dart:io';
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: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';
@@ -575,6 +572,10 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
.currentColor.sc9,
);
} else {
CountdownController
countdownController = Get.find();
countdownController.countdown.value =
0;
// 登录成功,跳转到主页面
TopSlideNotification.show(
context,
@@ -821,43 +822,73 @@ class _OtherLoginPageState extends State<OtherLoginPage> {
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wechat.png",
width: 30.rpx,
height: 30.rpx,
ClickableContainer(
backgroundColor: Colors.white, // 背景色
highlightColor: Colors.grey, // 点击水波纹颜色
borderRadius: 999.rpx,
padding: EdgeInsets.zero,
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/wechat.png",
width: 30.rpx,
height: 30.rpx,
),
),
),
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/tel.png",
width: 30.rpx,
height: 30.rpx,
ClickableContainer(
backgroundColor: Colors.white,
highlightColor: Colors.grey,
borderRadius: 999.rpx,
padding: EdgeInsets.zero,
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/tel.png",
width: 30.rpx,
height: 30.rpx,
),
),
),
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/google.png",
width: 30.rpx,
height: 30.rpx,
ClickableContainer(
backgroundColor: Colors.white,
highlightColor: Colors.grey,
borderRadius: 999.rpx,
padding: EdgeInsets.zero,
onTap: () {
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.asset(
"assets/img/google.png",
width: 30.rpx,
height: 30.rpx,
),
),
),
].divide(SizedBox(width: 35.rpx)),

View File

@@ -2,13 +2,22 @@ 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/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/device_share_controller.dart';
import 'package:vbvs_app/controller/message/message_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/enum/MessageStatus.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/device_bind/componnet/bind_dialog.dart';
class MessageWidgetWidget extends StatefulWidget {
const MessageWidgetWidget({super.key});
final data;
const MessageWidgetWidget({super.key, required this.data});
@override
State<MessageWidgetWidget> createState() => _MessageWidgetWidgetState();
@@ -16,9 +25,12 @@ class MessageWidgetWidget extends StatefulWidget {
class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
ThemeController themeController = Get.find();
MessageController messageController = Get.find();
DeviceShareController deviceShareController = Get.find();
@override
Widget build(BuildContext context) {
var messageInfo = widget.data;
return Stack(
children: [
ClickableContainer(
@@ -39,7 +51,8 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
'实时监测结果通知'.tr,
// '实时监测结果通知'.tr,
"${messageInfo['data']['title']}",
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
@@ -55,18 +68,15 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
Container(
constraints: BoxConstraints(
minWidth: 30.rpx,
maxWidth: 120.rpx,
maxWidth: 140.rpx,
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoItem(context, '设备ID'),
_buildInfoItem(context, '使用人员'),
_buildInfoItem(context, '消息类型'),
_buildInfoItem(context, '检测数值'),
_buildInfoItem(context, '发生时间'),
],
children: messageInfo['data']['val']
.map<Widget>((mapItem) =>
_buildInfoItem(context, mapItem['k'] ?? ''))
.toList(),
),
),
Container(
@@ -76,13 +86,10 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildValueItem(context, '设备ID'),
_buildValueItem(context, '使用人员'),
_buildValueItem(context, '消息类型'),
_buildValueItem(context, '检测数值'),
_buildValueItem(context, '发生时间'),
],
children: messageInfo['data']['val']
.map<Widget>((mapItem) =>
_buildValueItem(context, mapItem['v'] ?? ''))
.toList(),
),
),
].divide(SizedBox(width: 35.rpx)),
@@ -92,25 +99,49 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
),
Positioned(
bottom: 46.rpx,
right: 20.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
], // 单色背景
colors: messageInfo['status'] == 1
? [
themeController.currentColor.sc1,
themeController.currentColor.sc2
]
: [themeController.currentColor.sc4], // 单色背景
enableAnimation: true, // 有点击缩放动画
enableGradient: false, // 不用渐变
onTap: () {
// 点击处理逻辑
print('处理按钮点击了');
if (messageInfo['status'] == 1) {
showConfirmDialog(context, Container(), "是否确认接受该设备".tr,
onConfirm: () async {
ApiResponse apiResponse = await deviceShareController
.confirmShare(messageInfo['data']['shareCode']);
if (apiResponse.code == HttpStatusCodes.ok) {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: themeController.currentColor.sc2,
);
messageController.getMessageList();
messageController.updateAll();
} else {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: themeController.currentColor.sc9,
);
messageController.getMessageList();
messageController.updateAll();
}
}, onCancel: () {});
}
},
child: Center(
child: Text(
'处理'.tr,
getMessageStatus(messageInfo['status']),
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
@@ -134,6 +165,8 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
overflow: TextOverflow.ellipsis,
maxLines: 1,
label.tr,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
@@ -154,6 +187,8 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Text(
overflow: TextOverflow.ellipsis,
maxLines: 1,
value,
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
@@ -165,4 +200,23 @@ class _MessageWidgetWidgetState extends State<MessageWidgetWidget> {
),
);
}
String getMessageStatus(int status) {
if (status == null) {
return '未知数据'.tr;
}
if (status == MessageStatus.noNeed.code) {
return '无需处理'.tr;
}
if (status == MessageStatus.pending.code) {
return "待处理".tr;
}
if (status == MessageStatus.completed.code) {
return "已处理".tr;
}
if (status == MessageStatus.timeout.code) {
return "已超时".tr;
}
return '未知数据'.tr;
}
}

View File

@@ -1,5 +1,6 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/color/appConstants.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
@@ -19,10 +20,13 @@ class _EPageState extends State<EPage> {
builder: (context, boxConstraints) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
top: true,
child: Text("小e"),
child: Text("小e",
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: Colors.white)),
),
),
),

View File

@@ -0,0 +1,101 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/WebViewWidget.dart';
class FollowPage extends StatefulWidget {
late MyWebView webView;
FollowPage({super.key});
@override
State<FollowPage> createState() => _FollowPageState();
}
class _FollowPageState extends State<FollowPage> {
@override
void initState() {
super.initState();
// widget.webView = MyWebView(
// // url: "assets/map/index.html",
// url: "https://mp.weixin.qq.com/s/LvDtjFSI1au4o0eNrxLHwg",
// onLoad: () {
// print('网页载入完毕');
// },
// );
}
@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/followus.png'), // 本地图片
// fit: BoxFit.contain, // 填满整个 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: Padding(
padding: EdgeInsets.symmetric(horizontal: 0.rpx),
child: Column(children: [
Expanded(
child: Container(
// child: widget.webView,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/followus.png'), // 本地图片
fit: BoxFit.cover, // 填满整个 Container
),
),
),
),
]),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,129 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
import 'package:vbvs_app/component/tool/WebViewWidget.dart';
import 'package:vbvs_app/controller/setting/pdf/PdfController.dart';
class HelpPage extends StatefulWidget {
late MyWebView webView;
HelpPage({super.key});
@override
State<HelpPage> createState() => _HelpPageState();
}
class _HelpPageState extends State<HelpPage> {
PdfController pdfController = Get.find();
@override
void initState() {
super.initState();
// pdfController.loadPdf();
widget.webView = MyWebView(
url: "https://mp.weixin.qq.com/s/hBo0FMYrpe04I2WV6wbcxQ",
onLoad: () {
print('网页载入完毕');
},
);
}
@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: Padding(
// padding: EdgeInsets.symmetric(horizontal: 30.rpx),
// child: Column(
// children: [
// Expanded(
// child: Obx(() {
// if (pdfController.localPdfPath.value == null) {
// return Center(child: CircularProgressIndicator());
// } else {
// return PDFView(
// filePath: pdfController.localPdfPath.value!,
// autoSpacing: false,
// enableSwipe: true,
// swipeHorizontal: false,
// pageSnap: true,
// fitEachPage: true,
// defaultPage: 0,
// onRender: (pages) => print('PDF 渲染完成,共 $pages 页'),
// onError: (error) => print('PDF 加载错误: $error'),
// );
// }
// }),
// ),
// ],
// ),
// ),
// ),
body: SafeArea(
top: true,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 30.rpx),
child: Column(children: [
Expanded(
child: Container(
child: widget.webView,
),
),
]),
),
),
),
),
),
);
}
}

View File

@@ -44,7 +44,7 @@ class _HomePageState extends State<HomePage> {
final position = renderBox.localToGlobal(Offset.zero);
final size = renderBox.size;
double popupWidth = 190.rpx; // 弹窗宽度(可以改)
double popupWidth = 190.rpx;
_popupEntry?.remove(); // 清除旧弹窗
_popupEntry = OverlayEntry(
@@ -106,7 +106,7 @@ class _HomePageState extends State<HomePage> {
width: double.infinity,
child: Center(
child: Text(
'扫一扫'.tr,
'扫一扫.标题'.tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
@@ -131,7 +131,7 @@ class _HomePageState extends State<HomePage> {
width: double.infinity,
child: Center(
child: Text(
'蓝牙绑定'.tr,
'蓝牙绑定.标题'.tr,
style: TextStyle(
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc3,
@@ -254,7 +254,7 @@ class _HomePageState extends State<HomePage> {
themeController.currentColor.sc2,
],
child: Container(
width: 100.rpx,
// width: 100.rpx,
height: 60.rpx,
alignment: Alignment.center,
padding: EdgeInsetsDirectional
@@ -314,13 +314,6 @@ class _HomePageState extends State<HomePage> {
),
);
}),
// SvgPicture.asset(
// 'assets/img/icon/add.svg',
// width: 39.rpx,
// height: 39.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
// //todo 颜色
// color: themeController.currentColor.sc16,
// ),
ClickableContainer(
key: addIconKey,
backgroundColor: Colors.transparent,
@@ -553,10 +546,41 @@ class _HomePageState extends State<HomePage> {
CustomCard(
borderRadius: AppConstants()
.button_container_radius, // 圆角半径
onTap: () {
onTap: () async {
if (userInfoController.model.login ==
LoginStatus.LOGIN.code) {
Get.toNamed("/deviceType");
await Get.toNamed("/deviceType");
homeController.getSleepReport();
deviceController
.getDeviceNum()
.then((apiResponse) {
if (apiResponse.code !=
HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: apiResponse.msg!,
textColor: themeController
.currentColor.sc9,
);
}
});
deviceController
.getDeviceList()
.then((apiResponse) {
if (apiResponse.code !=
HttpStatusCodes.ok) {
TopSlideNotification.show(
Get.context!,
text: apiResponse.msg!,
textColor: themeController
.currentColor.sc9,
);
} else {
//请求睡眠报告
deviceController
.getSleepReport();
}
});
} else {
TopSlideNotification.show(
context,
@@ -681,7 +705,7 @@ class _HomePageState extends State<HomePage> {
.normal_text_fontSize,
letterSpacing: 0.0,
fontWeight:
FontWeight.w900,
FontWeight.w600,
color: stringToColor(
"#916D46"), //固定
),
@@ -763,19 +787,22 @@ class _HomePageState extends State<HomePage> {
backgroundColor:
themeController.currentColor.sc5,
highlightColor:
themeController.currentColor.sc3,
themeController.currentColor.sc21,
borderRadius: AppConstants()
.normal_container_radius,
padding: EdgeInsets
.zero, // 原始Container没有padding
onTap: () {
onTap: () async {
// BodyDeviceController
// bodyDeviceController = Get.find();
// bodyDeviceController.model.type = 1;
// Get.toNamed("/bodyDevice");
homeController.model.type = 1;
deviceController.model.type = 1;
deviceController.getDeviceList();
await deviceController
.getDeviceList();
await deviceController
.getSleepReport();
homeController.updateAll();
},
child: Container(
@@ -823,19 +850,17 @@ class _HomePageState extends State<HomePage> {
backgroundColor:
themeController.currentColor.sc5,
highlightColor:
themeController.currentColor.sc3,
themeController.currentColor.sc21,
borderRadius: AppConstants()
.normal_container_radius,
padding: EdgeInsets
.zero, // 原本的Container没有 padding这里设置为 zero
onTap: () {
// BodyDeviceController
// bodyDeviceController = Get.find();
// bodyDeviceController.model.type = 2;
// Get.toNamed("/bodyDevice");
padding: EdgeInsets.zero,
onTap: () async {
homeController.model.type = 2;
deviceController.model.type = 2;
deviceController.getDeviceList();
await deviceController
.getDeviceList();
await deviceController
.getSleepReport();
homeController.updateAll();
},
child: Container(
@@ -903,7 +928,6 @@ class _HomePageState extends State<HomePage> {
if (reportData.isEmpty) {
return Expanded(child: NullDataWidget());
}
List<String> macList = reportData.keys.toList();
macList = macList
.where(
@@ -911,8 +935,6 @@ class _HomePageState extends State<HomePage> {
.any((device) => device['mac'] == mac),
)
.toList();
// ⛔️防止 macList 长度和 deviceList.length 不对应导致崩溃
if (macList.length != deviceList.length) {
return Expanded(
child: Center(child: CircularProgressIndicator()),

View File

@@ -6,10 +6,10 @@ import 'package:flutter/material.dart';
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/message/message_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';
@@ -21,33 +21,48 @@ import 'package:vbvs_app/pages/main_bottom/mine_page.dart';
class MainPageBottomChange extends GetView<MainPageController> {
GlobalController globalController = Get.find();
ThemeController themeController = Get.find();
MessageController messageController = Get.find();
getBottomNavigationBarItem(String svgPath, String actSvgPath, String label,
{double size = 0, bool isEmpty = false}) {
{double size = 0, bool isEmpty = false, bool showBadge = false}) {
if (size == 0) {
size = 36.rpx;
}
Widget buildIcon(String path) {
return Padding(
padding: EdgeInsets.only(bottom: 6.rpx),
child: isEmpty
? Container()
: Stack(
clipBehavior: Clip.none,
children: [
SvgPicture.asset(
path,
width: size,
height: size,
),
if (showBadge)
Positioned(
right: -20.rpx,
top: -2.rpx,
child: Container(
width: 14.rpx,
height: 14.rpx,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
)
],
),
);
}
return BottomNavigationBarItem(
icon: Padding(
padding: EdgeInsets.only(bottom: 6.rpx),
child: isEmpty
? Container()
: SvgPicture.asset(
actSvgPath,
width: size,
height: size,
),
),
activeIcon: Padding(
padding: EdgeInsets.only(bottom: 6.rpx),
child: isEmpty
? Container()
: SvgPicture.asset(
svgPath,
width: size,
height: size,
),
),
label: label);
icon: buildIcon(actSvgPath),
activeIcon: buildIcon(svgPath),
label: label,
);
}
List arr = [
@@ -82,83 +97,98 @@ class MainPageBottomChange extends GetView<MainPageController> {
);
} else {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgImage.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: arr[controller.model.currentIndex],
floatingActionButtonAnimator:
FloatingActionButtonAnimator.noAnimation,
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: Theme(
data: ThemeData(
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent),
child: BottomNavigationBar(
unselectedItemColor: themeController.currentColor.sc4,
selectedItemColor: themeController.currentColor.sc1,
backgroundColor: themeController.currentColor.sc5,
selectedFontSize: 26.rpx,
unselectedFontSize: 26.rpx,
type: BottomNavigationBarType.fixed,
currentIndex: controller.model.currentIndex,
onTap: (index) {
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();
});
},
items: [
getBottomNavigationBarItem("assets/img/menu/home.svg",
"assets/img/menu/n_home.svg", "菜单.首页".tr),
// getBottomNavigationBarItem("assets/img/menu/report.svg",
// "assets/img/menu/n_report.svg", "菜单.报告".tr),
getBottomNavigationBarItem("assets/img/menu/e.svg",
"assets/img/menu/n_e.svg", "菜单.小e".tr),
getBottomNavigationBarItem("assets/img/menu/message.svg",
"assets/img/menu/n_message.svg", "菜单.消息".tr),
getBottomNavigationBarItem("assets/img/menu/mine.svg",
"assets/img/menu/n_mine.svg", "菜单.我的".tr),
],
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgImage.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
),
);
child: Scaffold(
backgroundColor: Colors.transparent,
body: arr[controller.model.currentIndex],
floatingActionButtonAnimator:
FloatingActionButtonAnimator.noAnimation,
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: Theme(
data: Theme.of(context).copyWith(
splashFactory: NoSplash.splashFactory,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: themeController.currentColor.sc4
.withOpacity(0.5),
width: 0.5,
),
),
),
child: BottomNavigationBar(
unselectedItemColor: themeController.currentColor.sc4,
selectedItemColor: themeController.currentColor.sc1,
backgroundColor: themeController.currentColor.sc5,
selectedFontSize: 26.rpx,
unselectedFontSize: 26.rpx,
type: BottomNavigationBarType.fixed,
currentIndex: controller.model.currentIndex,
onTap: (index) {
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;
}
if (controller.model.currentIndex != index) {
globalController.model.hideBottomNavigationBar =
false;
globalController.updateAll();
}
controller.model.currentIndex = index;
controller.updateAll();
});
},
items: [
getBottomNavigationBarItem("assets/img/menu/home.svg",
"assets/img/menu/n_home.svg", "菜单.首页".tr),
getBottomNavigationBarItem("assets/img/menu/e.svg",
"assets/img/menu/n_e.svg", "菜单.小e".tr),
getBottomNavigationBarItem(
"assets/img/menu/message.svg",
"assets/img/menu/n_message.svg",
"菜单.消息".tr,
showBadge: (messageController
.model.body_message_read ==
1 ||
messageController.model.system_message_read ==
1)),
getBottomNavigationBarItem("assets/img/menu/mine.svg",
"assets/img/menu/n_mine.svg", "菜单.我的".tr),
],
),
),
),
));
}
},
),
@@ -172,7 +202,8 @@ class MainPageBottomChange extends GetView<MainPageController> {
if (_lastBackPressedTime == null ||
currentTime.difference(_lastBackPressedTime!) > Duration(seconds: 2)) {
_lastBackPressedTime = currentTime;
showToast("再按一次退出程序", color: color_warning, closeTime: 2);
// showToast("再按一次退出程序", color: color_warning, closeTime: 2);
TopSlideNotification.show(context,text: "滑动退出提醒".tr);
return false; // 阻止退出程序
} else {
return true; // 允许退出程序

View File

@@ -5,6 +5,7 @@ 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/NullDataComponentWidget.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';
@@ -21,9 +22,20 @@ class MessagePage extends StatefulWidget {
class _MessagePageState extends State<MessagePage> {
ThemeController themeController = Get.find();
MessageController messageController = Get.find();
late PageController _pageController;
@override
void initState() {
super.initState();
_pageController =
PageController(initialPage: messageController.model.type == 1 ? 0 : 1);
messageController.getMessageStatus();
_fetchMessageData();
}
void _fetchMessageData() {
String type = messageController.model.type == 1 ? "app_vsm" : "app_system";
messageController.updateMessageStatus(type: type);
messageController.getMessageList().then((response) {
if (response.code != HttpStatusCodes.ok) {
TopSlideNotification.show(
@@ -35,44 +47,61 @@ class _MessagePageState extends State<MessagePage> {
});
}
void _onTabChanged(int index) {
messageController.model.type = index == 0 ? 1 : 2;
messageController.updateAll();
_fetchMessageData();
_pageController.animateToPage(index,
duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
}
void _onPageChanged(int index) {
int newType = index == 0 ? 1 : 2;
if (messageController.model.type != newType) {
messageController.model.type = newType;
messageController.updateAll();
_fetchMessageData();
}
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // 这里设置你希望的颜色
statusBarIconBrightness: Brightness.light, // 状态栏图标的亮度
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.light,
));
return LayoutBuilder(
builder: (context, boxConstraints) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Container(
decoration: BoxDecoration(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgNoImg.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
image: AssetImage('assets/img/bgNoImg.png'),
fit: BoxFit.fill,
),
),
child: Scaffold(
appBar: AppBar(
backgroundColor: themeController.currentColor.sc17,
automaticallyImplyLeading: false,
iconTheme: IconThemeData(
color: themeController.currentColor.sc3,
),
iconTheme: IconThemeData(color: themeController.currentColor.sc3),
toolbarHeight: 140.rpx,
titleSpacing: 0,
title: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx,
0.rpx,
0.rpx,
0.rpx,
),
padding: EdgeInsetsDirectional.fromSTEB(40.rpx, 0, 0, 0),
child: Container(
width: double.infinity,
height: 140.rpx, // 👈 明确告诉 Flutter 高度
height: 140.rpx,
child: Column(
children: [
SizedBox(height: 40.rpx), // 上边距
SizedBox(height: 40.rpx),
Expanded(
child: Stack(
alignment: Alignment.bottomLeft,
@@ -82,89 +111,129 @@ class _MessagePageState extends State<MessagePage> {
children: [
Obx(() {
return ClickableContainer(
padding: EdgeInsets.all(0),
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc3,
themeController.currentColor.sc21,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
messageController.model.type = 1;
await messageController.getMessageList();
messageController.updateAll();
},
onTap: () => _onTabChanged(0),
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,
),
child: Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Text(
'体征消息'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
color:
messageController
.model.type ==
2
? themeController
.currentColor.sc3
: themeController
.currentColor.sc2,
),
),
Obx(() {
return messageController.model
.body_message_read ==
1
? Positioned(
top: -4,
right: -14,
child: Container(
width: 8,
height: 8,
decoration:
const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
)
: const SizedBox.shrink();
}),
],
),
),
);
}),
Obx(() {
return ClickableContainer(
padding: EdgeInsets.all(0),
backgroundColor: Colors.transparent,
highlightColor:
themeController.currentColor.sc3,
themeController.currentColor.sc21,
borderRadius: 8.rpx,
padding: EdgeInsets.all(0),
onTap: () async {
messageController.model.type = 2;
await messageController.getMessageList();
messageController.updateAll();
},
onTap: () => _onTabChanged(1),
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,
),
child: Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Text(
'系统消息'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.title_text_fontSize,
color:
messageController
.model.type ==
1
? themeController
.currentColor.sc3
: themeController
.currentColor.sc2,
),
),
Obx(() {
return messageController.model
.system_message_read ==
1
? Positioned(
top: -4,
right: -14,
child: Container(
width: 8,
height: 8,
decoration:
const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
),
)
: const SizedBox.shrink();
}),
],
),
),
);
}),
],
].divide(SizedBox(width: 10.rpx)),
),
Obx(() {
double lineWidth = 160.rpx;
double lineWidth = 170.rpx;
return AnimatedPositioned(
duration: Duration(milliseconds: 300),
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
bottom: 0, // 👈 现在 Stack 够大,线能放得下
bottom: 0,
left: messageController.model.type == 1
? 0
: 160.rpx,
: 170.rpx,
child: Container(
width: lineWidth,
height: 4.rpx,
@@ -178,47 +247,33 @@ class _MessagePageState extends State<MessagePage> {
],
),
),
SizedBox(height: 17.rpx), // 上边距
SizedBox(height: 17.rpx),
],
),
),
),
actions: [],
actions: const [],
centerTitle: false,
),
backgroundColor: Colors.transparent,
body: SafeArea(
top: true,
child: Column(
mainAxisSize: MainAxisSize.max,
child: PageView(
controller: _pageController,
onPageChanged: _onPageChanged,
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)),
),
),
),
),
),
Obx(() {
final list = messageController.messageList.value;
return list.isEmpty
? const NullDataWidget()
: _buildMessageListView(list);
}),
Obx(() {
final list = messageController.messageList.value;
return list.isEmpty
? const NullDataWidget()
: _buildMessageListView(list);
}),
],
),
),
@@ -227,4 +282,23 @@ class _MessagePageState extends State<MessagePage> {
),
);
}
Widget _buildMessageListView(List dataList) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 30.rpx),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 30.rpx),
...dataList
.map((item) => MessageWidgetWidget(data: item))
.toList()
.divide(SizedBox(height: 30.rpx)),
SizedBox(height: 30.rpx),
],
),
),
);
}
}

View File

@@ -6,6 +6,7 @@ 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/base/SleepCalendarWidget.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';
@@ -157,89 +158,99 @@ class _MinePageState extends State<MinePage> {
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 120.rpx,
height: 120.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
Obx(() {
var userInfo =
userInfoController.model.user;
return Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 120.rpx,
height: 120.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
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,
),
),
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,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
login == 1
? (userInfoController.model
.user!.nick_name ??
'未命名'.tr)
: "我的.未登录".tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
login == 1
? (userInfoController.model
.user!.email !=
null
? userInfoController
.model.user!.email!
: MyUtils.hidePhoneNumber(
userInfoController.model
.user!.phone!))
: "我的.未登录".tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(height: 20.rpx)),
),
].divide(SizedBox(width: 35.rpx)),
),
Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
login == 1
? (userInfoController.model
.user!.nick_name ??
'未命名'.tr)
: "我的.未登录".tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
login == 1
? (userInfoController.model
.user!.email !=
null
? userInfoController
.model.user!.email!
: MyUtils.hidePhoneNumber(
userInfoController
.model
.user!
.phone!))
: "我的.未登录".tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: themeController
.currentColor.sc4,
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(height: 20.rpx)),
),
].divide(SizedBox(width: 35.rpx)),
);
}),
CustomCard(
borderRadius: 0,
onTap: () {
onTap: () async {
if (login == 1) {
Get.toNamed("/updateUserPage");
await Get.toNamed("/updateUserPage");
await userInfoController.getUserInfo();
userInfoController.updateAll();
} else {
Get.toNamed("/loginPage");
}
@@ -250,9 +261,7 @@ class _MinePageState extends State<MinePage> {
mainAxisSize: MainAxisSize.max,
children: [
Text(
login == 1
? '我的.个人信息'.tr
: '我的.去登录'.tr,
login == 1 ? '编辑'.tr : '我的.去登录'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
@@ -328,7 +337,7 @@ class _MinePageState extends State<MinePage> {
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
0.rpx, 30.rpx, 0.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -392,18 +401,19 @@ class _MinePageState extends State<MinePage> {
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
// TopSlideNotification.show(
// context,
// text: "待开发.提示".tr,
// textColor:
// themeController.currentColor.sc2,
// );
Get.toNamed("/applyRepairPage");
}
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
40.rpx, 30.rpx, 40.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -467,18 +477,19 @@ class _MinePageState extends State<MinePage> {
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
// TopSlideNotification.show(
// context,
// text: "待开发.提示".tr,
// textColor:
// themeController.currentColor.sc2,
// );
Get.toNamed("/helpPage");
}
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
40.rpx, 30.rpx, 40.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -542,18 +553,19 @@ class _MinePageState extends State<MinePage> {
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
);
// TopSlideNotification.show(
// context,
// text: "待开发.提示".tr,
// textColor:
// themeController.currentColor.sc2,
// );
Get.toNamed("/followPage");
}
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
0.rpx, 30.rpx, 0.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -570,7 +582,7 @@ class _MinePageState extends State<MinePage> {
color: stringToColor("#00C1AA"),
),
Text(
'关注我们'.tr,
'我的.关注我们'.tr,
style:
FlutterFlowTheme.of(context)
.bodyMedium
@@ -617,18 +629,38 @@ class _MinePageState extends State<MinePage> {
);
Get.toNamed("/loginPage");
} else {
TopSlideNotification.show(
context,
text: "待开发.提示".tr,
textColor:
themeController.currentColor.sc2,
// TopSlideNotification.show(
// context,
// text: "待开发.提示".tr,
// textColor:
// themeController.currentColor.sc2,
// );
showModalBottomSheet(
context: context,
isScrollControlled: false, // 不需要滚动全屏
backgroundColor:
Colors.transparent, // 为了圆角和美观
builder: (context) {
return Container(
decoration: BoxDecoration(
color: const Color(
0xFF242835), // 你组件的底色
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.rpx),
topRight: Radius.circular(20.rpx),
),
),
child:
SleepCalendarWidget(), // 显示日历组件
);
},
);
}
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
0.rpx, 30.rpx, 0.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:

View File

@@ -1,31 +1,30 @@
// 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(
// body: SafeArea(
// top: true,
// child: Text("睡眠报告"),
// ),
// ),
// ),
// );
// }
// }
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("睡眠报告"),
),
),
),
);
}
}

View File

@@ -34,6 +34,17 @@ class _EPageState extends State<PersonPage> {
@override
void initState() {
super.initState();
personController.getDiseaseData().then((apiResponse) {
WidgetsBinding.instance.addPostFrameCallback((_) {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: apiResponse.code != HttpStatusCodes.ok
? themeController.currentColor.sc9
: themeController.currentColor.sc2,
);
});
});
personController.selectedDiseaseIds.value = [];
personController.name.value = '';
personController.gender.value = 1;

View File

@@ -3,7 +3,6 @@ import 'package:flutter/cupertino.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/common/util/MyUtils.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
Future showDateSelectionDialog(BuildContext context,

View File

@@ -15,11 +15,13 @@ import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/person/person_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/enum/BindType.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/person/select_time.dart';
class UpdatePersonPage extends StatefulWidget {
const UpdatePersonPage({super.key});
var status;
UpdatePersonPage({super.key, required this.status});
@override
State<UpdatePersonPage> createState() => _UpdatePageState();
@@ -38,7 +40,7 @@ class _UpdatePageState extends State<UpdatePersonPage> {
super.initState();
personController.getDiseaseData().then((apiResponse) {
TopSlideNotification.show(
Get.context!,
context,
text: apiResponse.msg!,
textColor: apiResponse.code != HttpStatusCodes.ok
? themeController.currentColor.sc9
@@ -49,6 +51,8 @@ class _UpdatePageState extends State<UpdatePersonPage> {
@override
Widget build(BuildContext context) {
print(widget.status);
print(widget.status);
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
@@ -85,7 +89,6 @@ class _UpdatePageState extends State<UpdatePersonPage> {
fontSize: 30.rpx,
),
),
/// 左边返回按钮
Positioned(
left: 0,
@@ -94,41 +97,44 @@ class _UpdatePageState extends State<UpdatePersonPage> {
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,
),
Visibility(
visible: widget.status == BindType.active.code,
child: 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,
),
),
),
),
),
@@ -670,6 +676,7 @@ class _UpdatePageState extends State<UpdatePersonPage> {
),
);
}),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 152.rpx, 0, 0),

View File

@@ -0,0 +1,538 @@
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/common/util/requestWithLog.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/device/device_type_controller.dart';
import 'package:vbvs_app/controller/repair/repair_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/pages/repair/component/RepairModelWidget.dart';
class ApplyRepairPage extends StatefulWidget {
const ApplyRepairPage({super.key});
@override
State<ApplyRepairPage> createState() => _ApplyRepairPageState();
}
class _ApplyRepairPageState extends State<ApplyRepairPage> {
final ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
RepairController repairController = Get.find();
BodyDeviceController bodyDeviceController = Get.find();
final List<GlobalKey> repairItemKeys = [];
final GlobalKey contactKey = GlobalKey();
final GlobalKey phoneKey = GlobalKey();
@override
void initState() {
super.initState();
_loadData();
repairItemKeys.addAll(List.generate(
repairController.repairList.length, (index) => GlobalKey()));
}
void _updateRepairItemKeys() {
try {
final int currentLength = repairController.repairList.length;
if (repairItemKeys.length != currentLength) {
repairItemKeys.clear();
repairItemKeys.addAll(
List.generate(currentLength, (index) => GlobalKey()),
);
}
} catch (e) {
print(e);
}
}
Future<void> _loadData() async {
repairController.repairList = [{}].obs;
repairController.name.value = "";
repairController.phone.value = "";
await deviceTypeController.getDeviceType(); // 等待数据加载
if (deviceTypeController.deviceTypeList.isNotEmpty) {
repairController.device_type.value =
deviceTypeController.deviceTypeList.first['_id'];
}
await bodyDeviceController.getDeviceList();
WidgetsBinding.instance.addPostFrameCallback((_) {
_updateRepairItemKeys();
});
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
if (deviceTypeController.deviceTypeList.isNotEmpty) {
repairController.device_type.value =
deviceTypeController.deviceTypeList.first['_id'];
}
if (bodyDeviceController.deviceList.isNotEmpty) {
repairController.deviceListId = bodyDeviceController.deviceList
.map((e) => e['_id'] as String)
.toList();
}
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,
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(() {}),
),
Positioned(
right: 20.rpx,
child: ClickableContainer(
backgroundColor: Colors.transparent,
highlightColor: themeController.currentColor.sc16,
padding: EdgeInsets.all(8.rpx),
onTap: () {
Get.toNamed("/repairListPage");
},
child: SvgPicture.asset(
'assets/img/icon/history.svg',
width: 39.rpx,
height: 39.rpx,
color: themeController.currentColor.sc16,
),
),
),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(30.rpx, 29.rpx, 30.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Obx(() {
return Row(
mainAxisSize: MainAxisSize.max,
children: deviceTypeController.deviceTypeList.value
.map(
(deviceType) => CustomCard(
borderRadius:
AppConstants().button_container_radius,
onTap: () async {
repairController.device_type.value =
deviceType['_id'];
repairController.repairList
.clear(); // 清空旧数据
repairController.repairList
.add({}); // 添加新数据
await bodyDeviceController
.getDeviceList(); // 等待数据加载
_updateRepairItemKeys(); // 清空后更新 keys
repairController
.updateAll(); // 手动触发更新(如果未自动更新)
},
colors: deviceType['_id'] ==
repairController.device_type.value
? [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
]
: [themeController.currentColor.sc5],
child: Container(
width: (MediaQuery.sizeOf(context).width *
0.284)
.rpx,
constraints: BoxConstraints(
minWidth: 213.rpx,
minHeight: 91.rpx,
),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(20.rpx),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
deviceType[
'name'], // 假设 deviceType 有 name 字段
style: TextStyle(
letterSpacing: 0.0,
color:
themeController.currentColor.sc3,
fontSize: AppConstants()
.normal_text_fontSize,
),
),
),
),
),
)
.toList()
.divide(SizedBox(width: 25.rpx)),
);
}),
Obx(() {
return Column(
children: repairController.repairList
.map((item) {
final int index =
repairController.repairList.indexOf(item);
return RepairModelWidget(
widgetKey:
repairItemKeys[index], // 确保 index 有效
model: item,
onTap: () {
repairController.repairList.remove(item);
_updateRepairItemKeys(); // 删除后更新 keys
},
length: repairController.repairList.length,
);
})
.toList()
.divide(SizedBox(
height: 25.rpx,
)),
);
}),
ClickableContainer(
backgroundColor: themeController.currentColor.sc5,
highlightColor: themeController.currentColor.sc21,
borderRadius: 20.rpx,
padding: EdgeInsets.zero,
onTap: () {
repairController.repairList.add({});
_updateRepairItemKeys(); // 初始化 keys
repairController.updateAll();
},
child: SizedBox(
width: double.infinity,
height: 90.rpx,
child: Center(
child: Image.asset(
"assets/img/addItem.png",
width: 39.rpx,
height: 39.rpx,
),
),
),
),
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: [
_buildParamRow(
context,
"联系人".tr,
"名称输入提示".tr,
(value) {
repairController.name.value = value;
},
key: contactKey,
),
_buildParamRow(
context,
"手机号".tr,
"手机号输入提示".tr,
(value) {
repairController.phone.value = value;
},
key: phoneKey,
),
].divide(SizedBox(height: 30.rpx)),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 0.rpx, 100.rpx, 60.rpx),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: () async {
// TopSlideNotification.show(context,
// text: "提交成功",
// textColor: themeController.currentColor.sc1);
// Future.delayed(const Duration(seconds: 1), () {
// Get.offAllNamed("/mianPageBottomChange");
// });
String msg = checkRepairParam();
if (msg.isNotEmpty) {
TopSlideNotification.show(context,
text: msg,
textColor: themeController.currentColor.sc9);
} else {
String serviceAddress =
ServiceConstant.service_address;
String serviceName =
ServiceConstant.server_service;
String serviceApi = ServiceConstant.submit_repair;
String queryUrl =
"$serviceAddress$serviceName$serviceApi";
var data = {
"repairList": repairController.repairList,
"type": repairController.device_type.value,
};
ApiResponse apiResponse = await requestWithLog(
logTitle: "提交报修信息",
method: MyHttpMethod.post,
queryUrl: queryUrl,
data: data,
);
Get.back();
}
},
colors: [
themeController.currentColor.sc1,
themeController.currentColor.sc2,
],
child: Container(
color: Colors.transparent,
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,
)),
),
),
),
),
]
.divide(SizedBox(
height: 25.rpx,
))
.addToEnd(SizedBox(
height: 25.rpx,
)),
),
),
),
),
),
),
),
);
}
Widget _buildParamRow(BuildContext context, String text, String hinttext,
void Function(String) onChanged,
{Key? key} // 新增可选参数
) {
return Row(
key: key, // 使用传入的 key
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 110.rpx,
child: Text(
text,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
),
overflow: TextOverflow.ellipsis,
softWrap: false,
maxLines: 1,
),
),
Expanded(
child: Container(
width: 200.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.rpx),
color: Colors.transparent,
),
child: TextFormField(
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle: TextStyle(
letterSpacing: 0.0,
fontWeight:
FlutterFlowTheme.of(context).labelMedium.fontWeight,
fontStyle: FlutterFlowTheme.of(context).labelMedium.fontStyle,
),
hintText: hinttext,
hintStyle: TextStyle(
letterSpacing: 0.0,
fontSize: AppConstants().normal_text_fontSize,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.transparent,
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,
fillColor: themeController.currentColor.sc15,
),
style: TextStyle(
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
fontSize: AppConstants().normal_text_fontSize,
),
cursorColor: themeController.currentColor.sc3,
onChanged: onChanged,
),
),
),
].divide(SizedBox(width: 24.rpx)),
);
}
String checkRepairParam() {
String errormsg = "";
// 检查报修项
for (var i = 0; i < repairController.repairList.length; i++) {
final item = repairController.repairList[i];
if (item["path"] == null || item["path"].toString().isEmpty) {
_scrollToKey(repairItemKeys[i]);
// return "第 ${i + 1} 项图片未上传";
return "图片未上传".tr;
}
if (item["id"] == null || item["id"].toString().isEmpty) {
_scrollToKey(repairItemKeys[i]);
// return "第 ${i + 1} 项设备未选择";
return "设备未选择".tr;
}
if (item["param"] == null || item["param"].toString().isEmpty) {
_scrollToKey(repairItemKeys[i]);
// return "第 ${i + 1} 项参数未填写";
return "参数未填写".tr;
}
if (item["issue"] == null || item["issue"].toString().isEmpty) {
_scrollToKey(repairItemKeys[i]);
// return "第 ${i + 1} 项问题描述未填写";
return "问题描述未填写".tr;
}
}
// 检查联系人
if (repairController.name.trim().isEmpty) {
_scrollToKey(contactKey);
return "联系人不能为空";
}
if (repairController.phone.trim().isEmpty) {
_scrollToKey(phoneKey);
return "联系电话不能为空";
}
return errormsg;
}
// 新增滚动方法
void _scrollToKey(GlobalKey key) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Scrollable.ensureVisible(
key.currentContext!,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
});
}
}

View File

@@ -0,0 +1,250 @@
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/component/tool/CustomCard.dart';
import 'package:vbvs_app/routers/routers.dart';
class RepairHistoryInfoWidget extends StatefulWidget {
const RepairHistoryInfoWidget({super.key});
@override
State<RepairHistoryInfoWidget> createState() =>
_RepairHistoryInfoWidgetState();
}
class _RepairHistoryInfoWidgetState extends State<RepairHistoryInfoWidget> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return CustomCard(
borderRadius: AppConstants().normal_container_radius,
onTap: () {
//跳转详情
},
colors: [
themeController.currentColor.sc5,
],
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, 36.rpx, 0.rpx, 36.rpx),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(
maxWidth: 130.rpx,
),
decoration: BoxDecoration(),
child: Text(
'设备类型'.tr,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle: FlutterFlowTheme.of(context)
.bodyMedium
.fontStyle,
color: themeController.currentColor.sc4,
),
),
),
Text(
'智能床',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle:
FlutterFlowTheme.of(context).bodyMedium.fontStyle,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 33.rpx)),
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(
maxWidth: 130.rpx,
),
decoration: BoxDecoration(),
child: Text(
'设备ID'.tr,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle: FlutterFlowTheme.of(context)
.bodyMedium
.fontStyle,
color: themeController.currentColor.sc4,
),
),
),
Text(
'15561651',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle:
FlutterFlowTheme.of(context).bodyMedium.fontStyle,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 33.rpx)),
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(
maxWidth: 130.rpx,
),
decoration: BoxDecoration(),
child: Text(
'联系人'.tr,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle: FlutterFlowTheme.of(context)
.bodyMedium
.fontStyle,
color: themeController.currentColor.sc4,
),
),
),
Text(
'王明',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle:
FlutterFlowTheme.of(context).bodyMedium.fontStyle,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 33.rpx)),
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.14,
constraints: BoxConstraints(
maxWidth: 130.rpx,
),
decoration: BoxDecoration(),
child: Text(
'发生时间'.tr,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle: FlutterFlowTheme.of(context)
.bodyMedium
.fontStyle,
color: themeController.currentColor.sc4,
),
),
),
Text(
'2022-08-01 15:05',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.bodyMedium
.fontWeight,
fontStyle:
FlutterFlowTheme.of(context).bodyMedium.fontStyle,
color: themeController.currentColor.sc3,
),
),
].divide(SizedBox(width: 33.rpx)),
),
),
].divide(SizedBox(height: 34.rpx)),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,435 @@
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/component/base/THFlutterFlowDropDown.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/repair/repair_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/routers/routers.dart';
class RepairModelWidget extends StatefulWidget {
var model;
final VoidCallback onTap; // 添加回调函数
int length;
final GlobalKey widgetKey; // 新增
RepairModelWidget({
super.key,
required this.model,
required this.onTap,
required this.length,
required this.widgetKey,
});
@override
State<RepairModelWidget> createState() => _RepairModelWidgetState();
}
class _RepairModelWidgetState extends State<RepairModelWidget> {
FormFieldController<String> _deviceController =
FormFieldController<String>(null);
RepairController repairController = Get.find();
UserInfoController userInfoController = Get.find();
@override
void setState(VoidCallback callback) {
super.setState(callback);
}
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
// _deviceController.value = "";
return Container(
key: widget.widgetKey, // 使用传入的 key
width: double.infinity,
decoration: BoxDecoration(
color: themeController.currentColor.sc5,
borderRadius:
BorderRadius.circular(AppConstants().normal_container_radius),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 35.rpx, 30.rpx, 35.rpx),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 110.rpx,
decoration: BoxDecoration(),
child: Text(
'设备ID'.tr,
style: TextStyle(
fontSize: 26.rpx,
color: themeController.currentColor.sc3,
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: themeController.currentColor.sc15,
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius),
),
height: AppConstants().dropdown_height,
child: THFlutterFlowDropDown<String>(
onChanged: (val) {
widget.model['id'] = val;
},
width: 200.rpx,
height: 40.rpx,
textStyle: TextStyle(
color: themeController.currentColor.sc3,
fontSize: AppConstants().normal_text_fontSize,
),
hintText: '选择设备'.tr,
hintTextStyle: TextStyle(
color: themeController.currentColor.sc4,
fontSize: AppConstants().normal_text_fontSize,
),
icon: Icon(
Icons.keyboard_arrow_down_rounded,
color: FlutterFlowTheme.of(context).secondaryText,
size: 24.rpx,
),
fillColor: themeController.currentColor.sc15,
elevation: 0,
borderColor: Colors.transparent,
borderWidth: 0,
borderRadius: 20.rpx,
margin: EdgeInsetsDirectional.fromSTEB(
20.rpx, 0, 20.rpx, 0),
hidesUnderline: true,
isOverButton: false,
isSearchable: false,
isMultiSelect: false,
controller: _deviceController,
options: repairController.deviceListId!,
optionLabels: repairController.deviceListId!,
),
),
),
].divide(SizedBox(width: 24.rpx)),
),
),
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 110.rpx,
decoration: BoxDecoration(),
child: Text(
'设备参数'.tr,
style: TextStyle(
fontSize: 26.rpx,
color: themeController.currentColor.sc3,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: Container(
width: 200.rpx,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.rpx),
color: Colors.transparent,
),
child: TextFormField(
controller: repairController.onReDraw(
TextEditingController(
text: widget.model['param']),
(textEditingController) {
textEditingController.text = widget.model['param'];
}),
// initialValue: widget.model['param'],
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle: TextStyle(
letterSpacing: 0.0,
fontWeight: FlutterFlowTheme.of(context)
.labelMedium
.fontWeight,
fontStyle: FlutterFlowTheme.of(context)
.labelMedium
.fontStyle,
),
hintText: "设备参数提示".tr,
hintStyle: TextStyle(
letterSpacing: 0.0,
fontSize: AppConstants().normal_text_fontSize,
color: themeController.currentColor.sc4,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1.rpx,
),
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.transparent,
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,
fillColor: themeController.currentColor.sc15,
),
style: TextStyle(
letterSpacing: 0.0,
color: themeController.currentColor.sc3,
fontSize: AppConstants().normal_text_fontSize,
),
cursorColor: themeController.currentColor.sc3,
onChanged: (value) {
widget.model['param'] = value;
},
),
),
),
].divide(SizedBox(width: 24.rpx)),
),
),
Container(
width: double.infinity,
height: 151.rpx,
decoration: BoxDecoration(
color: themeController.currentColor.sc15,
borderRadius: BorderRadius.circular(20.rpx),
),
child: Container(
width: 200.rpx,
child: TextFormField(
onChanged: (value) {
widget.model['issue'] = value;
},
maxLines: null, // 👈 支持无限行
controller: TextEditingController(),
autofocus: false,
obscureText: false,
decoration: InputDecoration(
isDense: true,
labelStyle: TextStyle(
letterSpacing: 0.0,
fontWeight:
FlutterFlowTheme.of(context).labelMedium.fontWeight,
fontStyle:
FlutterFlowTheme.of(context).labelMedium.fontStyle,
),
hintText: '问题描述'.tr,
hintStyle: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0x00000000),
width: 1,
),
borderRadius: BorderRadius.circular(8.rpx),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 1,
),
borderRadius: BorderRadius.circular(8.rpx),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: FlutterFlowTheme.of(context).error,
width: 1,
),
borderRadius: BorderRadius.circular(8.rpx),
),
filled: false,
contentPadding: EdgeInsets.symmetric(
vertical: 20.rpx, horizontal: 20.rpx),
),
style: TextStyle(
color: themeController.currentColor.sc3,
fontSize: AppConstants().normal_text_fontSize,
),
cursorColor: FlutterFlowTheme.of(context).primaryText,
),
),
),
ClickableContainer(
backgroundColor: themeController.currentColor.sc15,
highlightColor: themeController.currentColor.sc21,
borderRadius: 20.rpx,
padding: EdgeInsets.zero, // 原来没有额外 padding这里保持一致
onTap: () async {
ApiResponse apiResponse = await repairController.uploadImg();
print(apiResponse);
if (apiResponse.code == HttpStatusCodes.ok) {
print(widget.model);
// setState(() {
// widget.model['path'] = apiResponse.data['path'];
// });
widget.model['path'] = apiResponse.data['path'];
repairController.repairList
.refresh(); // 通知 Obx 更新(如果用了 GetX
print(widget.model);
} else {
TopSlideNotification.show(
context,
text: apiResponse.msg!,
textColor: apiResponse.code == HttpStatusCodes.ok
? themeController.currentColor.sc2
: themeController.currentColor.sc9,
);
}
},
child: SizedBox(
width: double.infinity,
height: MediaQuery.sizeOf(context).height * 0.203,
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: 151.rpx,
),
child: Obx(() {
var list = repairController.repairList;
print(list);
if (widget.model['path'] == null ||
widget.model['path'] == "") {
return Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 60.rpx,
height: 53.rpx,
child: SvgPicture.asset(
'assets/img/icon/camera.svg',
width: 24.rpx,
height: 24.rpx,
color: themeController.currentColor.sc4,
),
),
Text(
'上传提示'.tr,
style: TextStyle(
fontSize: 26.rpx,
letterSpacing: 0.0,
color: themeController.currentColor.sc4,
),
),
].divide(SizedBox(height: 28.rpx)),
);
}
return Container(
// clipBehavior: Clip.antiAlias,
child: Image.network(
widget.model['path'],
fit: BoxFit.cover,
),
);
})),
),
),
if (widget.length > 1)
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
100.rpx, 0.rpx, 100.rpx, 0.rpx),
child: CustomCard(
borderRadius:
AppConstants().button_container_radius, // 圆角半径
onTap: widget.onTap,
colors: [
Colors.transparent,
],
child: Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(
AppConstants().button_container_radius),
),
width: MediaQuery.sizeOf(context).width * 0.216,
height: MediaQuery.sizeOf(context).height * 0.038,
constraints: BoxConstraints(
minHeight: 62.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,
)),
),
),
),
),
].divide(SizedBox(height: 29.rpx)),
),
),
),
);
}
}

View File

@@ -0,0 +1,136 @@
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/controller/device/body_device_controller.dart';
import 'package:vbvs_app/controller/device/device_type_controller.dart';
import 'package:vbvs_app/controller/repair/repair_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/pages/repair/component/RepairHistoryInfoWidget.dart';
class RepairListPage extends StatefulWidget {
const RepairListPage({super.key});
@override
State<RepairListPage> createState() => _RepairListPageState();
}
class _RepairListPageState extends State<RepairListPage> {
@override
void initState() {
super.initState();
loadData();
}
@override
void dispose() {
super.dispose();
}
@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,
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(() {}),
),
// Positioned(
// right: 20.rpx,
// child: ClickableContainer(
// backgroundColor: Colors.transparent,
// highlightColor: themeController.currentColor.sc16,
// padding: EdgeInsets.all(8.rpx),
// onTap: () {},
// child: SvgPicture.asset(
// 'assets/img/icon/history.svg',
// width: 39.rpx,
// height: 39.rpx,
// color: themeController.currentColor.sc16,
// ),
// ),
// ),
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(30.rpx, 29.rpx, 30.rpx, 0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
RepairHistoryInfoWidget(),
RepairHistoryInfoWidget(),
RepairHistoryInfoWidget(),
RepairHistoryInfoWidget(),
RepairHistoryInfoWidget(),
RepairHistoryInfoWidget(),
RepairHistoryInfoWidget(),
]
.divide(SizedBox(
height: 25.rpx,
))
.addToEnd(SizedBox(
height: 25.rpx,
)),
),
),
),
),
),
),
),
);
}
Future<void> loadData() async {
// repairController.repairHistory.value = [{}];
// ApiResponse apiResponse = await requestWithLog(
// logTitle: "请求维修列表", method: MyHttpMethod.get, queryUrl: "");
// if (apiResponse.code == HttpStatusCodes.ok) {
// //请求维修列表
// }
}
}

View File

@@ -0,0 +1,272 @@
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/component/tool/CustomCard.dart';
import 'package:vbvs_app/controller/setting/language/language_controller.dart';
import 'package:vbvs_app/language/AppLanguage.dart';
import 'package:vbvs_app/pages/device_bind/componnet/FancyCircleCheckbox.dart';
class LanguageSetting extends StatefulWidget {
const LanguageSetting({super.key});
@override
State<LanguageSetting> createState() => _LanguageSettingState();
}
class _LanguageSettingState extends State<LanguageSetting> {
LanguageController languageController = Get.find();
@override
void initState() {
// languageController.initLanuageList();
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: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
child: Obx(() {
return Column(
children: languageController.languageList
.map<Widget>((language) {
return ClickableContainer(
backgroundColor:
Colors.transparent, // 背景透明
highlightColor: themeController
.currentColor.sc21, // 点击时的背景色
padding: EdgeInsets.symmetric(
vertical: 10.rpx,
horizontal: 16.rpx),
onTap: () async {
// 点击事件逻辑
print('点击了语言项');
for (var lang
in languageController
.languageList) {
lang.selected = (lang ==
language); // 根据选择更新状态
}
languageController
.selectLanguage
.value = language;
await AppLanguage()
.loadLanguage(language
.language_code); // 加载语言
languageController
.updateAll(); // 更新操作
},
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Expanded(
child: Text(
language.language_name ??
'语言名称', // 显示语言名称
style: FlutterFlowTheme
.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color:
themeController
.currentColor
.sc3,
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
maxLines: 1,
overflow: TextOverflow
.ellipsis, // 省略号处理
),
),
FancyCircleCheckbox(
borderColor: themeController
.currentColor.sc3,
fillColor: themeController
.currentColor.sc2,
value: language.selected ??
false, // 根据 selected 状态显示选中或未选中
onChanged: (value) async {
// 保持原有的状态更改逻辑
for (var lang
in languageController
.languageList) {
lang.selected = (lang ==
language); // 更新选中状态
}
languageController
.selectLanguage
.value = language;
await AppLanguage()
.loadLanguage(language
.language_code); // 加载语言
languageController
.updateAll(); // 更新操作
},
),
].divide(SizedBox(
width: 28.rpx)), // 为每个项添加间隔
),
);
})
.toList()
.divide(SizedBox(
height: 30.rpx,
)),
);
}),
),
// ClickableContainer(
// backgroundColor: Colors.transparent, // 容器背景色
// highlightColor: themeController
// .currentColor.sc21, // 点击时的背景色
// padding: EdgeInsetsDirectional.fromSTEB(
// 40.rpx, 0.rpx, 40.rpx, 0.rpx),
// onTap: () {},
// child: Container(),
// ),
]
.divide(SizedBox(height: 0.rpx))
.addToStart(SizedBox(height: 30.rpx))
.addToEnd(SizedBox(height: 30.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

@@ -5,7 +5,6 @@ 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';
@@ -27,11 +26,21 @@ class _SleepReportPageState extends State<SleepReportPage> {
ThemeController themeController = Get.find();
DeviceTypeController deviceTypeController = Get.find();
// 使用 ValueNotifier 来管理加载状态
ValueNotifier<bool> isPageLoading = ValueNotifier<bool>(true);
@override
void initState() {
super.initState();
}
@override
void dispose() {
// 清理 ValueNotifier
isPageLoading.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
@@ -45,14 +54,12 @@ class _SleepReportPageState extends State<SleepReportPage> {
),
),
child: Scaffold(
backgroundColor: Colors.transparent, // 加上这一行
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,
@@ -78,50 +85,35 @@ class _SleepReportPageState extends State<SleepReportPage> {
],
),
),
actions: [],
centerTitle: false,
),
body: SafeArea(
top: true,
child: InAppWebView(
key: UniqueKey(),
initialUrlRequest: URLRequest(url: WebUri(widget.sleepUri)),
child: Stack(
children: [
InAppWebView(
key: UniqueKey(),
initialUrlRequest: URLRequest(url: WebUri(widget.sleepUri)),
onLoadStart: (controller, url) {
// 页面开始加载时显示加载指示器
isPageLoading.value = true;
},
onLoadStop: (controller, url) {
// 页面加载完成后隐藏加载指示器
isPageLoading.value = false;
},
),
ValueListenableBuilder<bool>(
valueListenable: isPageLoading,
builder: (context, isLoading, child) {
return isLoading
? Center(
child: CircularProgressIndicator(), // 加载指示器
)
: SizedBox.shrink();
},
),
],
),
// 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), // 结束的间隔
// ],
// );
// }),
// ],
// ),
// ),
// ),
),
),
),
@@ -170,14 +162,8 @@ class _SleepReportPageState extends State<SleepReportPage> {
),
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

@@ -11,6 +11,7 @@ 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/setting/language/language_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';
@@ -27,9 +28,11 @@ class _SettingPageState extends State<SettingPage> {
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
ThemeController themeController = Get.find();
LanguageController languageController = Get.find();
@override
void initState() {
languageController.initLanuageList();
super.initState();
}
@@ -115,12 +118,13 @@ class _SettingPageState extends State<SettingPage> {
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
0.rpx, 30.rpx, 0.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -183,12 +187,14 @@ class _SettingPageState extends State<SettingPage> {
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
// TopSlideNotification.show(context,
// text: "待开发功能".tr);
Get.toNamed("/languageSetting");
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
0.rpx, 30.rpx, 0.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -216,19 +222,24 @@ class _SettingPageState extends State<SettingPage> {
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'中文',
style:
FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color:
Color(0xFFD9E3EB),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
Obx(() {
return Text(
languageController
.selectLanguage
.value!
.language_name!,
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,
@@ -257,7 +268,7 @@ class _SettingPageState extends State<SettingPage> {
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
40.rpx, 30.rpx, 40.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -302,12 +313,13 @@ class _SettingPageState extends State<SettingPage> {
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 0.rpx, 40.rpx, 0.rpx),
onTap: () {
print('点击了容器');
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 20.rpx, 0.rpx, 20.rpx),
0.rpx, 30.rpx, 0.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
@@ -352,12 +364,13 @@ class _SettingPageState extends State<SettingPage> {
padding: EdgeInsetsDirectional.fromSTEB(
0.rpx, 0.rpx, 0.rpx, 0.rpx),
onTap: () {
print('点击了容器');
TopSlideNotification.show(context,
text: "待开发功能".tr);
},
child: Container(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
40.rpx, 20.rpx, 40.rpx, 20.rpx),
40.rpx, 30.rpx, 40.rpx, 30.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:

View File

@@ -102,6 +102,7 @@ class _UpdateUserPageState extends State<UpdateUserPage> {
userInfoController.model.user!.tmpHead = null;
userInfoController.model.user!.tmpNickName = null;
await userInfoController.getUserInfo();
userInfoController.updateAll();
Get.back();
}
},

View File

@@ -1,10 +1,17 @@
import 'package:ef/ef.dart';
import 'package:flutter/cupertino.dart';
import 'package:vbvs_app/component/tool/TopSlideNotification.dart';
import 'package:vbvs_app/controller/login/login_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/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_calibration.dart';
import 'package:vbvs_app/pages/device_bind/device_share_list_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';
@@ -12,23 +19,28 @@ 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';
import 'package:vbvs_app/pages/main_bottom/e_page.dart';
import 'package:vbvs_app/pages/main_bottom/follow_page.dart';
import 'package:vbvs_app/pages/main_bottom/help_page.dart';
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/person/person_page.dart';
import 'package:vbvs_app/pages/person/update_person_page.dart';
import 'package:vbvs_app/pages/repair/apply_repair_page.dart';
import 'package:vbvs_app/pages/repair/repair_list_page.dart';
import 'package:vbvs_app/pages/setting/language_setting.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';
ThemeController themeController = Get.find();
var routes = {
"/homePage": (contxt) => HomePage(),
"/sleepReportPage": (contxt,{arguments}) => SleepReportPage(sleepUri:arguments),
"/sleepReportPage": (contxt, {arguments}) =>
SleepReportPage(sleepUri: arguments),
"/ePage": (contxt) => EPage(),
"/messagePage": (contxt) => MessagePage(),
"/minePage": (contxt) => MinePage(),
@@ -45,33 +57,73 @@ var routes = {
"/aboutUsPage": (contxt) => AboutUsPage(),
"/bodyDevice": (contxt) => BodyDeviceWidget(),
"/deviceTypeList": (contxt) => DeviceTypeListPage(),
"/deviceDetail": (contxt,{arguments}) => DeviceDetailPage(device:arguments),
"/instantBodyPage": (contxt,{arguments}) => InstantBodyPage(personInfo:arguments),
"/deviceDetail": (contxt, {arguments}) => DeviceDetailPage(device: arguments),
"/instantBodyPage": (contxt, {arguments}) =>
InstantBodyPage(personInfo: arguments),
"/qrView": (contxt) => MobileScannerTestPage(),
"/updatePersonPage": (contxt) => UpdatePersonPage(),
"/deviceSharePage": (contxt,{arguments}) => DeviceSharePage(device:arguments),
"/updatePersonPage": (contxt, {arguments}) =>
UpdatePersonPage(status: arguments),
"/deviceSharePage": (contxt, {arguments}) =>
DeviceSharePage(device: arguments),
"/deviceShareListPage": (contxt, {arguments}) =>
DeviceShareListPage(device: arguments),
"/calibrationPage": (contxt, {arguments}) => CalibrationPage(type: arguments),
"/applyRepairPage": (contxt) => ApplyRepairPage(),
"/languageSetting": (contxt) => LanguageSetting(),
"/helpPage": (contxt) => HelpPage(),
"/followPage": (contxt) => FollowPage(),
"/repairListPage": (contxt) => RepairListPage(),
};
//2、配置onGenerateRoute 固定写法 这个方法也相当于一个中间件,这里可以做权限判断
var onGenerateRoute = (RouteSettings settings) {
final String? name = settings.name; // /news 或 /search
final Function? pageContentBuilder =
routes[name]; // Function = (contxt) { return const NewsPage()}
final String? name = settings.name; // 获取路由名称,如 /news 或 /search
final Function? pageContentBuilder = routes[name]; // 根据路由名称获取对应的页面构建器
if (pageContentBuilder != null) {
if (settings.arguments != null) {
final Route route = CupertinoPageRoute(
settings: settings,
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
final Route route = CupertinoPageRoute(
settings: settings,
builder: (context) => pageContentBuilder(context));
UserInfoController userInfoController = Get.find();
int loginStatus = userInfoController.model.login!;
return route;
// 检查用户是否已登录,如果未登录且路由不是登录相关页面,跳转到登录页面
if (loginStatus != 1) {
// 如果用户未登录且访问的不是登录页面等,展示提示并重定向
if (settings.name != "/loginPage" &&
settings.name != "/otherLoginPage" &&
settings.name != "/mianPageBottomChange") {
TopSlideNotification.show(
Get.context!,
text: "必须登录提示".tr,
textColor: themeController.currentColor.sc9,
);
// 创建新的 RouteSettings并修改 name 为 /loginPage
final updatedSettings = RouteSettings(
name: "/loginPage",
arguments: settings.arguments,
);
// 创建一个新的路由,跳转到登录页面
return CupertinoPageRoute(
settings: updatedSettings,
builder: (context) => pageContentBuilder!(context),
);
}
}
// 如果有路由参数,传递参数
if (settings.arguments != null) {
return CupertinoPageRoute(
settings: settings,
builder: (context) =>
pageContentBuilder!(context, arguments: settings.arguments),
);
} else {
// 没有路由参数时,直接构建页面
return CupertinoPageRoute(
settings: settings,
builder: (context) => pageContentBuilder!(context),
);
}
}
return null;
return null; // 如果路由名称没有匹配的页面,返回 null
};