更新
This commit is contained in:
@@ -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 = "";//提交报修
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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; //标题文字字号
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
99
lib/common/util/CheckNetwork.dart
Normal file
99
lib/common/util/CheckNetwork.dart
Normal 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,
|
||||
),));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = {};
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
105
lib/common/util/requestWithLog.dart
Normal file
105
lib/common/util/requestWithLog.dart
Normal 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';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
264
lib/component/base/SleepCalendarWidget.dart
Normal file
264
lib/component/base/SleepCalendarWidget.dart
Normal 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(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
39
lib/component/base/SleepdateWidget.dart
Normal file
39
lib/component/base/SleepdateWidget.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
461
lib/component/base/THFlutterFlowDropDown.dart
Normal file
461
lib/component/base/THFlutterFlowDropDown.dart
Normal 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);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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'],
|
||||
|
||||
32
lib/controller/device/device_calibration_controller.dart
Normal file
32
lib/controller/device/device_calibration_controller.dart
Normal 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.双人
|
||||
}
|
||||
15
lib/controller/device/device_calibration_controller.g.dart
Normal file
15
lib/controller/device/device_calibration_controller.g.dart
Normal 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>{};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
135
lib/controller/device/device_share_list_controller.dart
Normal file
135
lib/controller/device/device_share_list_controller.dart
Normal 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
|
||||
}
|
||||
}
|
||||
20
lib/controller/device/device_share_list_controller.g.dart
Normal file
20
lib/controller/device/device_share_list_controller.g.dart
Normal 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,
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 =
|
||||
|
||||
108
lib/controller/repair/repair_controller.dart
Normal file
108
lib/controller/repair/repair_controller.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
lib/controller/repair/repair_controller.g.dart
Normal file
21
lib/controller/repair/repair_controller.g.dart
Normal 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,
|
||||
};
|
||||
94
lib/controller/setting/language/language_controller.dart
Normal file
94
lib/controller/setting/language/language_controller.dart
Normal 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, // 默认语言为选中状态
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
lib/controller/setting/language/language_controller.g.dart
Normal file
18
lib/controller/setting/language/language_controller.g.dart
Normal 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,
|
||||
};
|
||||
24
lib/controller/setting/pdf/PdfController.dart
Normal file
24
lib/controller/setting/pdf/PdfController.dart
Normal 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 路径
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
11
lib/enum/MessageStatus.dart
Normal file
11
lib/enum/MessageStatus.dart
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
110
lib/main.dart
110
lib/main.dart
@@ -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()),
|
||||
]));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
123
lib/pages/device_bind/componnet/DeviceShareInfoWidget.dart
Normal file
123
lib/pages/device_bind/componnet/DeviceShareInfoWidget.dart
Normal 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,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
617
lib/pages/device_bind/device_calibration.dart
Normal file
617
lib/pages/device_bind/device_calibration.dart
Normal 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,
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
461
lib/pages/device_bind/device_share_list_page.dart
Normal file
461
lib/pages/device_bind/device_share_list_page.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
101
lib/pages/main_bottom/follow_page.dart
Normal file
101
lib/pages/main_bottom/follow_page.dart
Normal 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
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
129
lib/pages/main_bottom/help_page.dart
Normal file
129
lib/pages/main_bottom/help_page.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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()),
|
||||
|
||||
@@ -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; // 允许退出程序
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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("睡眠报告"),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
538
lib/pages/repair/apply_repair_page.dart
Normal file
538
lib/pages/repair/apply_repair_page.dart
Normal 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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
250
lib/pages/repair/component/RepairHistoryInfoWidget.dart
Normal file
250
lib/pages/repair/component/RepairHistoryInfoWidget.dart
Normal 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)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
435
lib/pages/repair/component/RepairModelWidget.dart
Normal file
435
lib/pages/repair/component/RepairModelWidget.dart
Normal 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)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
136
lib/pages/repair/repair_list_page.dart
Normal file
136
lib/pages/repair/repair_list_page.dart
Normal 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) {
|
||||
// //请求维修列表
|
||||
// }
|
||||
}
|
||||
}
|
||||
272
lib/pages/setting/language_setting.dart
Normal file
272
lib/pages/setting/language_setting.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user