初始化项目

This commit is contained in:
wyf
2025-04-11 08:47:46 +08:00
parent e0e1055d65
commit 9396f18d09
199 changed files with 6516 additions and 216 deletions

View File

@@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:vbvs_app/common/util/MyUtils.dart';
class AppColors {
// 定义颜色常量
static const Color text_selected_color = Color(0xFFD3B684); //选中文本
static const Color text_default_color = Color(0xFFFFFFFF); //默认文本
static const Color button_active_color = Color(0xFFD3B684); //可点击按钮
static const Color button_inactive_color = Color(0xFFD3D3D3); //不可点击按钮
static const Color bg_color = Color(0xFF000750); //背景色
static const Color input_bg_color = Color(0xFFF3F5F6); //输入框背景色
static const Color input_hint_text_color = Color(0xFFF3F5F6); //hinttext
static const Color input_split_color = Color(0xFFF3F5F6); //分隔符
static const Color textColor = Color(0xFF333333); //普通文本
static const Color buttonColor = Color(0xFF03A9F4);
static const Color borderColor = Color(0xFFE0E0E0);
static const Color errorColor = Color(0xFFB00020);
Color check_Color = stringToColor('#409EFF');
Color repair_Color = stringToColor('#409EFF');
Color finish_Color = stringToColor('#71E2A3');
Color unOp_Color = stringToColor('#FF4949');
Color press_color = stringToColor("#eaeaea");
}

View File

@@ -0,0 +1,24 @@
import 'package:vbvs_app/common/util/FitTool.dart';
class AppConstants {
// App-related constants
static const int code_time = 60; //验证码倒计时
static const int limit = 10; //分页数量
static const double list_end_height = 26; //列表结尾空白高度
static const double list_ano_end_height = 100; //列表结尾空白高度
static const double list_start_height = 13; //列表开头空白高度
static const double page_button_bottom_padding = 45; //页面底部按钮距离底部距离
double main_left_right_padding = 30.rpx; //页面左右布局间距
double content_left_right_padding = 15.rpx; //页面左右内容间距
double normal_container_radius = 24.rpx; //普通容器圆角
double button_container_radius = 100.rpx; //按钮容器圆角
double text_padding_up_dowm_p = 5.rpx; //段落文字上下间距
double normal_text_fontSize = 26.rpx; //普通文字字号
double title_text_fontSize = 30.rpx; //标题文字字号
}

View File

@@ -0,0 +1,10 @@
import 'package:vbvs_app/common/util/FitTool.dart';
class AppFontsize {
// 定义文字常量
static double title_size = 15.px; //标题
static double normal_text_size = 13.px; //普通文本
static double small_text_size = 11.px; //小号文本
static double smaller_text_size = 9.px; //小号文本
static double explain_size = 8.px; //说明文本
}

View File

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

View File

@@ -0,0 +1,19 @@
// lib/http_status_codes.dart
class HttpStatusCodes {
// Success codes
static const int ok = 1;
static const int created = 201;
static const int accepted = 202;
// Client error codes
static const int badRequest = 400;
static const int unauthorized = 401;
static const int forbidden = 403;
static const int notFound = 404;
// Server error codes
static const int internalServerError = 500;
static const int notImplemented = 501;
static const int serviceUnavailable = 503;
}

View File

@@ -0,0 +1,9 @@
class DeliveryStatus {
// 私有构造函数,防止实例化
const DeliveryStatus._();
// 物流状态常量
static const String no_de = '待发货';//下单之后待发货
static const String has_de = '已发货';//确认发货
static const String completed = '已签收';//签收
}

View File

@@ -0,0 +1,37 @@
class OrderStatus {
// 私有构造函数,防止实例化
const OrderStatus._();
// 订单状态常量值
static const int noPay = 1; // 已下单,待支付(both)
static const int paid = 2; // 已支付(app),待确认(web)
static const int toBeShipped = 3; // 已确认(web),待发货(app)
static const int toBeReceived = 4; // 已发货(web),待签收(app)
static const int received = 5; // 已签收(app),待完成(web)
static const int closed = 6; // 已关闭(both)
static const int completed = 7; // 已完成(web),已签收(app)
// 订单状态编号与描述的映射
static const Map<int, String> statuses = {
1: '待支付', // 已下单,待支付(both)
2: '已支付', // 已支付(app),待确认(web)
3: '待发货', // 已确认(web),待发货(app)
4: '待签收', // 已发货(web),待签收(app)
5: '已签收', // 已签收(app),待完成(web)
6: '已关闭', // 已关闭(both)
7: '已签收', // 已完成(web),已签收(app)
};
// 根据编号获取状态名称的描述
static String getDescriptionByCode(int code) {
return statuses[code] ?? '未知状态';
}
// 根据状态名称获取编号
static int getCodeByDescription(String description) {
return statuses.entries
.firstWhere((element) => element.value == description,
orElse: () => MapEntry(0, '未知状态'))
.key;
}
}

View File

@@ -0,0 +1,10 @@
class PayStatus {
// 私有构造函数,防止实例化
const PayStatus._();
// 支付状态常量
static const String no_pay = '待支付';
static const String have_pay = '已支付';
static const String close = '已关闭';
}

View File

@@ -0,0 +1,9 @@
class RepairStatus {
// 私有构造函数,防止实例化
const RepairStatus._();
// 维修状态常量
static const String pending = '审核中';
static const String approved = '审核通过';
static const String completed = '已完成';
}

View File

@@ -0,0 +1,35 @@
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";
// 企业微信ID
static String wxCorpId = "ww51feda6026280cd0";
//ICP备案号
static String ICPRightCode = "皖ICP备2024068219号-1A";
//公司名称
static String enterpriseName = "合肥眠花糖家具有限责任公司";
//备案时间
static String ICPTime = "2022-2025";
// 分享复制文字信息
static String shareText = "您的朋友邀请您使用《智慧眠花糖》APP请复制后面链接在浏览器中打开 " +
shoph5Url +
"/#/pages/download/download";
}

View File

@@ -0,0 +1,43 @@
class FitTool {
static double rpx = 0;
static bool isInit = false;
static init(double v) {
if (v < 1) {
return;
}
if (isInit == false) {
isInit = true;
rpx = v / 750.0;
}
}
static double getPx(double size) {
return rpx * size * 2.0;
}
static double getRpx(double size) {
return rpx * size;
}
}
extension FitInt on int {
double get px {
return FitTool.getPx(this.toDouble());
}
double get rpx {
return FitTool.getRpx(this.toDouble());
}
}
extension FitDouble on double {
double get px {
return FitTool.getPx(this);
}
double get rpx {
return FitTool.getRpx(this);
}
}

View File

@@ -0,0 +1,327 @@
import 'dart:async';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:vbvs_app/common/util/CommonVariables.dart';
import 'package:vbvs_app/common/util/FitTool.dart';
import 'package:url_launcher/url_launcher.dart';
Future<void> initDataEf({String key = ""}) async {
await ef.init(
'${CommonVariables.supabaseUrl}/',
key,
nosqlEnableWebsocket: false,
);
}
class MyUtils {
static String timestampToDateString(int timestamp) {
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp);
String formattedDate =
'${dateTime.year}-${dateTime.month.toString().padLeft(2, '0')}-${dateTime.day.toString().padLeft(2, '0')} '
'${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}:${dateTime.second.toString().padLeft(2, '0')}';
return formattedDate;
}
static String hidePhoneNumber(String phoneNumber) {
if (phoneNumber.length != 11) {
// 检查手机号是否为11位
throw Exception("手机号格式不正确");
}
// 将中间四位替换为星号
return phoneNumber.replaceRange(3, 7, '****');
}
static double initialScrollOffset = 0.0;
// 判断手机号格式是否正确的方法
static bool isValidPhoneNumber(String phoneNumber) {
final RegExp phoneRegExp = RegExp(r'^1[3-9]\d{9}$');
return phoneRegExp.hasMatch(phoneNumber);
}
static Future<void> makePhoneCall(String phoneNumber) async {
final Uri launchUri = Uri(
scheme: 'tel',
path: phoneNumber,
);
if (await canLaunchUrl(launchUri)) {
await launchUrl(launchUri);
} else {
throw '无法拨打电话';
}
}
static String formatDateTime(DateTime dateTime) {
// 定义日期格式
// dateTime.toLocal();
final DateFormat formatter = DateFormat('yyyy-MM-dd HH:mm');
// 返回格式化后的字符串
return formatter.format(dateTime);
}
static void scrollToFocusedInput(FocusNode focusNode, _scrollController) {
// 获取输入框相对于整个页面的偏移量
RenderObject? object = focusNode.context?.findRenderObject();
if (object != null) {
final RenderBox box = object as RenderBox;
final Offset position = box.localToGlobal(Offset.zero);
// 将页面滚动到使输入框显示在屏幕上的位置
_scrollController.animateTo(
position.dy - MediaQuery.of(focusNode.context!).size.height / 4,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
}
static void resetScrollPosition(_scrollController) {
_scrollController.animateTo(
initialScrollOffset,
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
}
Color stringToColor(String hexColor) {
String formattedColor = hexColor.replaceAll("#", "");
int colorValue = int.parse("0xFF$formattedColor");
return Color(colorValue);
}
//字节转16进制
String ab2str(List<int> buffer) {
return buffer.map((x) => x.toRadixString(16).padLeft(2, '0')).join('');
}
enum ToastColor { success, error, warn }
ToastColor color_success = ToastColor.success;
ToastColor color_warning = ToastColor.warn;
ToastColor color_error = ToastColor.error;
showToast(String msg,
{ToastColor color = ToastColor.error, int closeTime = 3}) {
// Fluttertoast.showToast(
// msg: msg,
// toastLength: Toast.LENGTH_LONG,
// gravity: ToastGravity.CENTER,
// timeInSecForIosWeb: 1,
// backgroundColor: color == null ? color_error : color,
// textColor: Colors.white,
// fontSize: 14.0,
// );
final context = Get.overlayContext; // 获取 Overlay 的上下文
Color background = Colors.red;
Color color_text = stringToColor("#FA5A4C");
String icon = "";
if (color == color_success) {
background = stringToColor("#DBF1E1");
icon = "success";
color_text = stringToColor("#31CA79");
} else if (color == color_warning) {
background = stringToColor("#FDF6EC");
icon = "warn";
color_text = stringToColor("#F8AE00");
} else if (color == color_error) {
background = stringToColor("#FEF0F0");
icon = "error";
color_text = stringToColor("#FA5A4C");
}
if (context == null) return;
OverlayEntry overlayEntry = OverlayEntry(
builder: (context) => Positioned(
top: MediaQuery.of(context).size.height * 0.10,
left: MediaQuery.of(context).size.width * 0.5 - 225.rpx,
child: Material(
color: Colors.transparent,
child: Container(
width: 450.rpx,
padding: EdgeInsets.only(top: 20.rpx, bottom: 20.rpx),
decoration: BoxDecoration(
color: background,
borderRadius: BorderRadius.circular(10.rpx),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
"assets/images/toast/${icon}_.png",
width: 30.rpx,
height: 30.rpx,
),
SizedBox(
width: 18.rpx,
),
Container(
constraints: BoxConstraints(maxWidth: 380.rpx),
child: Text(
msg,
maxLines: 9,
style: TextStyle(
color: color_text,
fontSize: 28.rpx,
fontWeight: FontWeight.w400),
),
)
],
),
),
),
),
);
Overlay.of(context)?.insert(overlayEntry);
Future.delayed(Duration(seconds: closeTime), () {
overlayEntry.remove();
});
}
var closeIcon = GestureDetector(
onTapDown: (f) {
Get.back();
},
child: Container(
padding: EdgeInsets.fromLTRB(10.rpx, 18.rpx, 10.rpx, 10.rpx),
child: Container(
height: 42.rpx,
width: 42.rpx,
alignment: Alignment.center,
child: Icon(
Icons.close,
),
),
),
);
var closeIconWhite = GestureDetector(
onTapDown: (f) {
Get.back();
},
child: Container(
padding: EdgeInsets.all(10.rpx),
child: Container(
height: 42.rpx,
width: 42.rpx,
alignment: Alignment.center,
child: Icon(
Icons.close,
color: Colors.white,
),
),
),
);
var returnIconButtom = IconButton(
// padding: EdgeInsets.zero, // 去除默认 padding
// constraints: BoxConstraints(), // 去除最小尺寸限制
onPressed: () => Get.back(),
icon: Icon(Icons.navigate_before, size: 60.rpx),
);
var returnIconButtomAddCallback = (returnCallBack) {
return IconButton(
onPressed: () {
returnCallBack?.call();
Get.back();
},
icon: Icon(Icons.navigate_before, size: 60.rpx),
);
};
String time_08_Formatter(String time) {
if (time == null || time == "") {
return "";
}
return DateFormat("yyyy-MM-dd HH:mm:ss")
.format(DateTime.parse(time).toLocal());
}
String time_08_Formatter_pattern(String time, String pattern) {
if (time == null || time == "") {
return "";
}
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 }
class LoadingDialog {
static show(String name, {LoadingDialogIcon icon = LoadingDialogIcon.none}) {
String iconUrl = "";
if (icon == LoadingDialogIcon.wifi) {
iconUrl = "wifi";
} else if (icon == LoadingDialogIcon.ble) {
iconUrl = "ble";
}
Get.dialog(
PopScope(
canPop: false,
child: Container(
// color: Colors.transparent,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
constraints:
BoxConstraints(minWidth: 300.rpx, maxWidth: 500.rpx),
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(8)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (iconUrl.isNotEmpty)
Container(
width: 120.rpx,
height: 120.rpx,
margin: EdgeInsets.only(bottom: 60.rpx),
child:
Image.asset("assets/images/toast/${iconUrl}.png"),
),
Text(
textAlign: TextAlign.center,
name,
style: const TextStyle(
fontSize: 16,
color: Colors.white,
decoration: TextDecoration.none),
),
SizedBox(
height: 30.rpx,
),
const CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.white,
),
),
],
),
)
],
),
),
),
barrierDismissible: false,
barrierColor: Color.fromRGBO(0, 0, 0, 0.8));
}
static hide() {
Get.back();
}
}

View File

@@ -0,0 +1,113 @@
import 'dart:async';
import 'dart:convert';
import 'package:ef/ef.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
class WebsocketProp {
late WebSocketChannel channel;
bool isConnecting = false;
bool isOpen = false;
bool isClose = false; //是否关闭
late String url;
late Map fun;
WebsocketProp initState(String url_, Map funn) {
print(url_);
fun = funn;
url = url_;
isConnecting = false;
_connect();
return this;
}
void _connect() {
isOpen = false;
channel = IOWebSocketChannel.connect(
"$url?token=${Get.find<UserInfoController>().model.token}");
channel.stream.listen((message) {
// print('Received message: $message');
// Handle incoming messages here
heartCheck();
if (isOpen == false) {
fun['open']?.call();
print('Received message: $message');
isOpen = true;
isConnecting = false;
// Get.find<BedController>().websocketSend(1);
return;
}
if (message == "ht") {
print('Received message: $message');
return;
}
fun["message"]?.call(message);
}, onError: (error) {
// Handle connection error and initiate reconnection
print('Error: $error');
isOpen = false;
_reconnect();
}, onDone: () {
// Handle connection closed
print('Connection closed');
isOpen = false;
_reconnect();
});
}
Timer? timeoutObj;
Timer? serverTimeoutObj;
int timeout = 10;
void heartCheck() {
timeoutObj?.cancel();
serverTimeoutObj?.cancel();
timeoutObj = Timer(Duration(seconds: timeout), () {
sendMessage("ht");
serverTimeoutObj = Timer(Duration(seconds: timeout), () {
dispose();
});
});
}
void _reconnect() {
if (isClose) {
return;
}
if (!isConnecting) {
isConnecting = true;
_connect();
Timer(const Duration(seconds: 5), () {
isConnecting = false;
if (isOpen == false) {
_reconnect();
}
});
}
}
void sendMessage(data) {
if (isOpen == false) {
// showToast("websocket 已断开");
return;
}
if (data is String) {
channel.sink.add(data);
} else {
String s = jsonEncode(data);
// print("发送 $s");
channel.sink.add(s);
}
}
sendWebSocketMessageCodeN(code, data) {
sendMessage({"code": code, "data": data});
}
void dispose() {
isClose = true;
channel.sink.close();
}
}

View File

@@ -0,0 +1,86 @@
import 'dart:async';
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'my_dialog_controller.dart';
class MyDialog extends GetView<MyDialogController> {
final String message;
final int seconds;
final Color? textColor; // 可选参数
MyDialog({
required this.message,
required this.seconds,
this.textColor, // 可选参数的赋值
});
@override
Widget build(BuildContext context) {
// 设置弹窗在2秒后自动关闭
Timer(Duration(seconds: seconds), () {
if (Navigator.canPop(context)) {
Navigator.of(context).pop();
}
});
return Dialog(
backgroundColor: Colors.transparent, // 使弹窗背景透明
elevation: 0, // 去除阴影
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: 232,
maxHeight: 400,
minHeight: 47,
maxWidth: 400,
),
child: Opacity(
opacity: 1, // 设置容器的透明度为80%
child: Container(
decoration: BoxDecoration(
// color: Color(0xFF182B7C),
color: Color(0xFFffebe9),
border: Border.all(
// color: Color(0xFFe60012), // 边框颜色
color: textColor ?? Color(0xFFe60012),
width: 1, // 边框宽度
),
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 8),
Text(
message,
style: TextStyle(
fontSize: 13,
// color: Color(0xFFe60012), // 边框颜色
color: textColor ?? Color(0xFFe60012),
),
textAlign: TextAlign.center,
),
],
),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,71 @@
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';
class ConfirmDialog extends GetView {
ConfirmDialog();
Future showConfirmCustomDialog(BuildContext context,
{String name = "是否确认取消?"}) async {
// Completer<String> completer = Completer<String>();
TextEditingController textEditingController = TextEditingController();
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: Container(
width: 340,
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(alignment: Alignment.centerRight, child: closeIcon),
Center(
child: Text(
'${name}',
style: TextStyle(fontSize: 16),
),
),
SizedBox(height: 30),
Container(
margin: EdgeInsets.only(top: 50.rpx, bottom: 40.rpx),
alignment: Alignment.center,
child: InkWell(
onTap: () {
Get.back(result: "confirm");
},
child: Container(
width: 280.rpx,
height: 60.rpx,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: stringToColor("#D3B684")),
child: Text(
'确定',
style: TextStyle(color: Colors.white, fontSize: 30.rpx),
),
),
),
)
],
),
),
);
},
);
// return completer.future;
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container();
}
}

View File

@@ -0,0 +1,44 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
import 'MyDialog.dart';
part 'my_dialog_controller.g.dart';
@JsonSerializable()
class MyDialogModel {
//版本id
String? title_name = "标题"; //标题
String? message = "消息内容";
MyDialogModel();
static MyDialogModel fromJson(Map<String, dynamic> json) =>
_$MyDialogModelFromJson(json);
Map<String, dynamic> toJson() => _$MyDialogModelToJson(this);
}
class MyDialogController extends GetControllerEx<MyDialogModel> {
MyDialogController() {
attr = GetModel(MyDialogModel()).obs;
}
Future<void> showCustomDialog(
BuildContext context,
String message, {
Color? textColor, // 可选参数
}) async {
await showDialog(
barrierColor: Colors.transparent, // 设置上级页面不变暗
context: context,
builder: (BuildContext context) {
return MyDialog(
message: message,
seconds: 2,
textColor: textColor,
);
},
);
}
}

View File

@@ -0,0 +1,18 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'my_dialog_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MyDialogModel _$MyDialogModelFromJson(Map<String, dynamic> json) =>
MyDialogModel()
..title_name = json['title_name'] as String?
..message = json['message'] as String?;
Map<String, dynamic> _$MyDialogModelToJson(MyDialogModel instance) =>
<String, dynamic>{
'title_name': instance.title_name,
'message': instance.message,
};

View File

@@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
class CustomCard extends StatefulWidget {
final double borderRadius; // 圆角
final VoidCallback onTap; // 点击回调
final List<Color> colors; // 背景颜色列表
final Widget child; // 子组件
final String title;
const CustomCard({
Key? key,
required this.borderRadius,
required this.onTap,
required this.colors,
required this.child,
required this.title,
}) : super(key: key);
@override
State<CustomCard> createState() => _CustomCardState();
}
class _CustomCardState extends State<CustomCard>
with SingleTickerProviderStateMixin {
double _scale = 1.0;
final Duration _animationDuration = Duration(milliseconds: 50);
final GlobalKey _inkKey = GlobalKey();
Future<void> _handleTap(TapDownDetails details) async {
setState(() {
_scale = 0.95;
});
await Future.delayed(_animationDuration);
setState(() {
_scale = 1.0;
});
await Future.delayed(_animationDuration);
// 手动触发水波纹
final RenderBox? box =
_inkKey.currentContext?.findRenderObject() as RenderBox?;
if (box != null) {
final Offset localPosition = box.globalToLocal(details.globalPosition);
InkRipple.splashFactory.create(
controller: Material.of(_inkKey.currentContext!)!,
referenceBox: box,
position: localPosition,
color: widget.colors.first.withOpacity(0.2),
containedInkWell: true,
borderRadius: BorderRadius.circular(widget.borderRadius),
textDirection: Directionality.of(context),
);
}
widget.onTap();
}
@override
Widget build(BuildContext context) {
final bool isGradient = widget.colors.length > 1;
final Color baseColor = widget.colors.first;
return Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(widget.borderRadius),
child: GestureDetector(
onTapDown: _handleTap,
behavior: HitTestBehavior.translucent, // 关键:让空白区域也能点击
child: AnimatedScale(
scale: _scale,
duration: _animationDuration,
curve: Curves.easeInOut,
child: Ink(
key: _inkKey,
decoration: BoxDecoration(
color: isGradient ? null : baseColor,
gradient: isGradient
? LinearGradient(
colors: widget.colors,
begin: Alignment.topLeft,
end: Alignment.bottomRight,
)
: null,
borderRadius: BorderRadius.circular(widget.borderRadius),
),
child: widget.child,
),
),
),
);
}
}

View File

@@ -0,0 +1,31 @@
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
part 'blueteeth_bind_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class BlueteethBindModel {
int read = 1;//是否不再提示教程 0 不再提示 1 需要提示
BlueteethBindModel();
// 从JSON反序列化时的异常处理
factory BlueteethBindModel.fromJson(Map<String, dynamic> json) {
try {
return _$BlueteethBindModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return BlueteethBindModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$BlueteethBindModelToJson(this);
}
class BlueteethBindController extends GetControllerEx<BlueteethBindModel> {
BlueteethBindController() {
attr = GetModel(BlueteethBindModel()).obs;
}
}

View File

@@ -0,0 +1,15 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'blueteeth_bind_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BlueteethBindModel _$BlueteethBindModelFromJson(Map<String, dynamic> json) =>
BlueteethBindModel()..read = (json['read'] as num).toInt();
Map<String, dynamic> _$BlueteethBindModelToJson(BlueteethBindModel instance) =>
<String, dynamic>{
'read': instance.read,
};

View File

@@ -0,0 +1,172 @@
import 'dart:async';
import 'package:ef/ef.dart';
import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class GlobalModel {
List deviceList = [];
Map deviceMain = {};
Map useBedController = {}; //之前控制的设备
List deviceType = [];
List homeImgList = []; //轮播图
bool hideBottomNavigationBar = false;
get deviceMainIsShare {
if (deviceMain != null && deviceMain["type"] == 2) {
return true;
} else {
return false;
}
}
// get JunheDevices {
// List arr = [];
// deviceList.forEach((d) {
// d?["personnelInfo"]?.forEach((item) {
// if (item["mac"] == d["bindMacA"] &&
// arr.indexWhere((a) => a["mac"] == item["mac"]) == -1) {
// arr.add(item);
// }
// });
// if (d["bindMacB"] != null && d["bindMacB"] != "") {
// d["personnelInfo"].forEach((item) {
// if (item["mac"] == d["bindMacB"] &&
// arr.indexWhere((a) => a["mac"] == item["mac"]) == -1) {
// arr.add(item);
// }
// });
// }
// });
// return arr;
// }
get JunheDevices {
List arr = [];
try {
if (deviceList != null) {
deviceList.forEach((d) {
if (d?["personnelInfo"] != null) {
d["personnelInfo"].forEach((item) {
if (item["mac"] == d["bindMacA"] &&
arr.indexWhere((a) => a["mac"] == item["mac"]) == -1) {
arr.add(item);
}
});
}
if (d["bindMacB"] != null && d["bindMacB"] != "") {
if (d["personnelInfo"] != null) {
d["personnelInfo"].forEach((item) {
if (item["mac"] == d["bindMacB"] &&
arr.indexWhere((a) => a["mac"] == item["mac"]) == -1) {
arr.add(item);
}
});
}
}
});
}
} catch (e) {
print(e);
}
return arr;
}
get mainDevicePeople {
if (deviceMain == null || deviceMain["mac"] == null) {
return [{}, {}];
}
List arr = [{}, {}];
if (deviceMain["personnelInfo"] != null) {
if (deviceMain["bindMacA"] != null) {
deviceMain["personnelInfo"]?.forEach((d) {
if (d["mac"] == deviceMain["bindMacA"]) {
arr[0] = d;
}
});
}
if (deviceMain["bindMacB"] != null) {
deviceMain["personnelInfo"]?.forEach((d) {
if (d["mac"] == deviceMain["bindMacB"]) {
arr[1] = d;
}
});
}
}
return arr;
}
GlobalModel();
}
class GlobalController extends GetControllerEx<GlobalModel> {
GlobalController() {
attr = GetModel(GlobalModel()).obs;
}
get userInfoController => Get.find<UserInfoController>();
Timer? getDeviceListTimer;
@override
void onInit() {
super.onInit();
}
resetParmAll() {
resetParm();
Get.find<MainPageController>().resetParm();
}
resetParm() {
getDeviceListTimer?.cancel();
getDeviceListTimer = null;
model.deviceList = [];
model.deviceMain = {};
model.useBedController = {};
model.deviceType = [];
model.homeImgList = [];
model.hideBottomNavigationBar = false;
}
deviceUpdateTimerCreated() {
if (getDeviceListTimer == null) {
getDeviceListTimer = Timer.periodic(const Duration(seconds: 10), (t) {
if (userInfoController.model.token != null) {
}
});
}
}
getDeviceGroupName(device) {
return "${device['roomName']}/${device["deviceType"]?["name"]}/${device["name"]}";
}
getDeviceGroupName2(device) {
return "${device["deviceType"]?["name"]}/${device["name"]}";
}
getUpperCaseMac(mac) {
if (mac == null || mac == "") {
return "";
}
return "$mac".toUpperCase();
}
getDeviceType() async {
var rs =
await ef.from("app_device_type").select().order("id", ascending: true);
model.deviceType = rs.where((d) => d["page"] != null).toList();
updateAll();
}
}

View File

@@ -0,0 +1,34 @@
import 'package:ef/ef.dart';
import 'package:json_annotation/json_annotation.dart';
part 'main_page_controller.g.dart'; // 由json_serializable自动生成的部分
@JsonSerializable()
class MainPageModel {
int currentIndex = 0;
MainPageModel();
// 从JSON反序列化时的异常处理
factory MainPageModel.fromJson(Map<String, dynamic> json) {
try {
return _$MainPageModelFromJson(json);
} catch (e) {
// 在实际应用中,应该有更细致的异常处理策略和错误日志
return MainPageModel(); // 或者返回一个带有错误信息的特定DeviceInfoModel实例
}
}
// 序列化为JSON时的异常处理
Map<String, dynamic> toJson() => _$MainPageModelToJson(this);
}
class MainPageController extends GetControllerEx<MainPageModel> {
MainPageController() {
attr = GetModel(MainPageModel()).obs;
}
resetParm() {
model.currentIndex = 0;
}
}

View File

@@ -0,0 +1,15 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'main_page_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MainPageModel _$MainPageModelFromJson(Map<String, dynamic> json) =>
MainPageModel()..currentIndex = (json['currentIndex'] as num).toInt();
Map<String, dynamic> _$MainPageModelToJson(MainPageModel instance) =>
<String, dynamic>{
'currentIndex': instance.currentIndex,
};

View File

@@ -0,0 +1,18 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:vbvs_app/model/CustomThemeColor.dart';
class ThemeController extends GetControllerEx {
//todo 数据库查询的颜色等于这个
CustomThemeColor currentColor = CustomThemeColor.light;
ThemeData currentTheme = ThemeData();
void changeTheme(CustomThemeColor color) {
currentColor = color;
currentTheme = ThemeData(
primaryColor: color.sc1,
scaffoldBackgroundColor: color.sc2,
);
update();
}
}

View File

@@ -0,0 +1,50 @@
import 'dart:io';
import 'package:ef/ef.dart';
import 'package:get_storage/get_storage.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:path/path.dart' as p;
import 'package:uuid/uuid.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/MyUtils.dart';
import 'package:vbvs_app/model/api_response.dart';
import 'package:vbvs_app/model/user_data.dart';
part 'user_info_controller.g.dart';
@JsonSerializable()
class UserInfoModel {
int? message = 0; //消息数量
UserModel? user; //用户信息
String? token; //token值
String? runSystem; //运行系统
String? phoneVersion; //手机版本
String? deviceId; //手机唯一
String? deviceModel; //设备可见型号(如 "iPhone""iPad"
String? appVersion; //app版本信息
@JsonKey(ignore: true)
Session? superbase_session;
@JsonKey(ignore: true)
User? superbase_user;
String? img_bucket = 'user';
int? login = 0; //是否登录0未登录 1已登录
UserInfoModel();
static UserInfoModel fromJson(Map<String, dynamic> json) =>
_$UserInfoModelFromJson(json);
Map<String, dynamic> toJson() => _$UserInfoModelToJson(this);
}
class UserInfoController extends GetControllerEx<UserInfoModel> {
// 初始化实例
UserInfoController() {
attr = GetModel(UserInfoModel()).obs;
}
}

View File

@@ -0,0 +1,36 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_info_controller.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
UserInfoModel _$UserInfoModelFromJson(Map<String, dynamic> json) =>
UserInfoModel()
..message = (json['message'] as num?)?.toInt()
..user = json['user'] == null
? null
: UserModel.fromJson(json['user'] as Map<String, dynamic>)
..token = json['token'] as String?
..runSystem = json['runSystem'] as String?
..phoneVersion = json['phoneVersion'] as String?
..deviceId = json['deviceId'] as String?
..deviceModel = json['deviceModel'] as String?
..appVersion = json['appVersion'] as String?
..img_bucket = json['img_bucket'] as String?
..login = (json['login'] as num?)?.toInt();
Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
<String, dynamic>{
'message': instance.message,
'user': instance.user,
'token': instance.token,
'runSystem': instance.runSystem,
'phoneVersion': instance.phoneVersion,
'deviceId': instance.deviceId,
'deviceModel': instance.deviceModel,
'appVersion': instance.appVersion,
'img_bucket': instance.img_bucket,
'login': instance.login,
};

View File

@@ -0,0 +1,63 @@
import 'dart:convert';
import 'package:ef/ef.dart';
import 'package:flutter/services.dart';
class AppLanguage extends Translations {
// 私有构造函数
AppLanguage._internal();
// 单例实例
static final AppLanguage _instance = AppLanguage._internal();
factory AppLanguage() => _instance;
// 缓存翻译数据
final Map<String, Map<String, String>> _localizedValues = {};
@override
Map<String, Map<String, String>> get keys => _localizedValues;
// 动态加载语言文件
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);
} catch (e) {
print('Error loading $languageCode language file: $e');
}
}
// 扁平化嵌套 JSON 数据
Map<String, String> _flattenJson(Map<String, dynamic> json,
[String prefix = '']) {
final Map<String, String> flatMap = {};
json.forEach((key, value) {
final newKey = prefix.isEmpty ? key : '$prefix.$key';
if (value is Map<String, dynamic>) {
flatMap.addAll(_flattenJson(value, newKey));
} else {
flatMap[newKey] = value.toString();
}
});
return flatMap;
}
// 清理语言缓存
void clearLanguage(String languageCode) {
_localizedValues.remove(languageCode);
}
}

View File

@@ -1,125 +1,161 @@
import 'package:ef/ef.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_storage/get_storage.dart';
import 'package:vbvs_app/common/util/FitTool.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/main_bottom/main_page_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/language/AppLanguage.dart';
import 'package:vbvs_app/model/CustomThemeColor.dart';
import 'package:vbvs_app/model/user_data.dart';
import 'controller/user_info_controller.dart';
import 'routers/routers.dart';
void main() {
runApp(const MyApp());
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:syncfusion_localizations/syncfusion_localizations.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await AppLanguage().loadLanguage("zh_CN");
WidgetsFlutterBinding.ensureInitialized();
// ApiService.init();
// await GetStorage.init();
// 初始化登录
await initLogin();
// 检查网络
// Checknetwork.checkNetwork();
// 微信开放平台注册
// initWX();
// // 初始化 flutter_xupdate android app 更新
// initXUpdate();
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(MyApp());
});
// runApp(const MyApp());
}
Future<void> initLogin() async {
// 初始化控制器
Get.put(UserInfoController());
// Get.put(SettingController());
// 获取设备信息,需要用户点击确认隐私协议与用户协议选择框时才能获取
// Deviceconfig.initPlatformState();
// 获取app版本号
// SettingController settingController = Get.find();
// settingController.model.appVersion = await Deviceconfig.getAppVersion();
final box = GetStorage();
UserInfoController userInfoController = Get.find();
String? token = box.read('token');
// print('Token: $token');
Map<String, dynamic>? userMap = box.read('user');
if (userMap != null) {
UserModel user = UserModel.fromJson(userMap);
userInfoController.model.user = user;
}
if (token != null) {
// userInfoController.model.login = 1;
//根据token去请求
// await userInfoController.autoLogin(token);
} else {
// 如果没有 token则将用户标记为未登录
userInfoController.model.login = 0;
}
}
// 初始化微信开放平台注册
// 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 {
const MyApp({super.key});
MyApp({super.key});
final ThemeController themeController = Get.put(ThemeController());
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// TRY THIS: Try running your application with "flutter run". You'll see
// the application has a purple toolbar. Then, without quitting the app,
// try changing the seedColor in the colorScheme below to Colors.green
// and then invoke "hot reload" (save your changes or press the "hot
// reload" button in a Flutter-supported IDE, or press "r" if you used
// the command line to start the app).
//
// Notice that the counter didn't reset back to zero; the application
// state is not lost during the reload. To reset the state, use hot
// restart instead.
//
// This works for code too, not just values: Most code changes can be
// tested with just a hot reload.
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
themeController.changeTheme(CustomThemeColor.dark);
UserInfoController userInfoController = Get.find();
return LayoutBuilder(builder: (contxt, cons) {
double width = cons.maxWidth;
double height = cons.maxHeight;
if (width < 1) {
return Container();
}
FitTool.init(width < height ? width : height);
return GetMaterialApp(
translations: AppLanguage(),
locale: const Locale("zh", "CN"),
fallbackLocale: const Locale("zh", "CN"),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
SfGlobalLocalizations.delegate,
],
supportedLocales: [
const Locale('zh', 'CN'), // 中文
// 其他支持的语言
],
debugShowCheckedModeBanner: false,
title: '',
theme: themeController.currentTheme,
// home: const MyHomePage(title: '智慧眠花糖 Home Page'),
initialRoute: "/mianPageBottomChange",
onGenerateRoute: onGenerateRoute,
initialBinding: BindingsBuilder(() => [
Get.lazyPut(() => UserInfoController()),
Get.put(GlobalController()),
Get.lazyPut(() => MainPageController()),
Get.lazyPut(() => BlueteethBindController()),
]));
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// TRY THIS: Try changing the color here to a specific color (to
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
// change color while the other colors stay the same.
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
//
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
// action in the IDE, or press "p" in the console), to see the
// wireframe for each widget.
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

View File

@@ -0,0 +1,283 @@
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
@JsonSerializable()
class CustomThemeColor {
final String color1;//
final String color2;
final String color3;
final String color4;
final String color5;
final String color6;
final String color7;
final String color8;
final String color9;
final String color10;
final String color11;
final String color12;
final String color13;
final String color14;
final String color15;
final String color16;
final String color17;
final String color18;
final String color19;
final String color20;
final String color21;
final String color25;
final String color26;
final String color27;
final String color28;
final String color29;
final String color30;
final String color31;
final String color32;
final String color33;
final String color34;
final String color38;
final String color39;
final String color40;
CustomThemeColor({
required this.color1,
required this.color2,
required this.color3,
required this.color4,
required this.color5,
required this.color6,
required this.color7,
required this.color8,
required this.color9,
required this.color10,
required this.color11,
required this.color12,
required this.color13,
required this.color14,
required this.color15,
required this.color16,
required this.color17,
required this.color18,
required this.color19,
required this.color20,
required this.color21,
required this.color25,
required this.color26,
required this.color27,
required this.color28,
required this.color29,
required this.color30,
required this.color31,
required this.color32,
required this.color33,
required this.color34,
required this.color38,
required this.color39,
required this.color40,
});
//浅色模式
static final light = CustomThemeColor(
color1: '#FFFFFF',
color2: "#f7f8fa",
color3: "#4AD8FA",
color4: "#4AD8FA",
color5: "#4AD8FA",
color6: "#4AD8FA",
color7: "#333333",
color8: "#333333",
color9: "#333333",
color10: "#f7f8fa",
color11: "#f7f8fa",
color12: "#DBF8FD",
color13: "#d3d3d3",
color14: "#333333",
color15: "#FF7159",
color16: "#d3d3d3",
color17: "#FFFFFF",
color18: "#4AD8FA",
color19: "#4AD8FA",
color20: "#f7f8fa",
color21: "#5EE00A",
color25: "#FF7159",
color26: "#4AD8FA",
color27: "#f7f8fa",
color28: "#4E8408",
color29: "#79BC31",
color30: "#E55E92",
color31: "#FF1D25",
color32: "#7bbb33",
color33: "#fe15b8d",
color34: "#EE0000",
color38: "#E3E4E5",
color39: "#F3F5F6",
color40: "#333333");
//深色模式
static final dark = CustomThemeColor(
color1: '#242835',
color2: "#f7f8fa",
color3: "#4AD8FA",
color4: "#4AD8FA",
color5: "#4AD8FA",
color6: "#4AD8FA",
color7: "#333333",
color8: "#333333",
color9: "#333333",
color10: "#f7f8fa",
color11: "#f7f8fa",
color12: "#DBF8FD",
color13: "#d3d3d3",
color14: "#333333",
color15: "#FF7159",
color16: "#d3d3d3",
color17: "#FFFFFF",
color18: "#4AD8FA",
color19: "#4AD8FA",
color20: "#f7f8fa",
color21: "#5EE00A",
color25: "#FF7159",
color26: "#4AD8FA",
color27: "#f7f8fa",
color28: "#4E8408",
color29: "#79BC31",
color30: "#E55E92",
color31: "#FF1D25",
color32: "#7bbb33",
color33: "#fe15b8d",
color34: "#EE0000",
color38: "#E3E4E5",
color39: "#F3F5F6",
color40: "#333333");
//获取颜色1 菜单栏颜色
Color get sc1 => getColor(color1);
//获取颜色2
Color get sc2 => getColor(color2);
//获取颜色3
Color get sc3 => getColor(color3);
//获取颜色4
Color get sc4 => getColor(color4);
//获取颜色5
Color get sc5 => getColor(color5);
//获取颜色6
Color get sc6 => getColor(color6);
//获取颜色7
Color get sc7 => getColor(color7);
//获取颜色8
Color get sc8 => getColor(color8);
//获取颜色9
Color get sc9 => getColor(color9);
//获取颜色10
Color get sc10 => getColor(color10);
Color get sc11 => getColor(color11);
Color get sc12 => getColor(color12);
Color get sc13 => getColor(color13);
Color get sc14 => getColor(color14);
Color get sc15 => getColor(color15);
Color get sc16 => getColor(color16);
Color get sc17 => getColor(color17);
Color get sc18 => getColor(color18);
Color get sc19 => getColor(color19);
Color get sc20 => getColor(color20);
Color get sc21 => getColor(color21);
Color get sc25 => getColor(color25);
Color get sc26 => getColor(color26);
Color get sc27 => getColor(color27);
Color get sc28 => getColor(color28);
Color get sc29 => getColor(color29);
Color get sc30 => getColor(color30);
Color get sc31 => getColor(color31);
Color get sc32 => getColor(color32);
Color get sc33 => getColor(color33);
Color get sc34 => getColor(color34);
Color get sc38 => getColor(color38);
Color get sc39 => getColor(color39);
Color get sc40 => getColor(color40);
Color getColor(String color) {
color = color.replaceAll("#", "");
if (color.length == 6) {
color = "0xFF$color";
} else {
color = "0x$color";
}
return Color(int.parse(color));
}
//序列化反序列化
factory CustomThemeColor.fromJson(Map<String, dynamic> json) =>
CustomThemeColor(
color1: json['color1'],
color2: json['color2'],
color3: json['color3'],
color4: json['color4'],
color5: json['color5'],
color6: json['color6'],
color7: json['color7'],
color8: json['color8'],
color9: json['color9'],
color10: json['color10'],
color11: json['color11'],
color12: json['color12'],
color13: json['color13'],
color14: json['color14'],
color15: json['color15'],
color16: json['color16'],
color17: json['color17'],
color18: json['color18'],
color19: json['color19'],
color20: json['color20'],
color21: json['color21'],
color25: json['color25'],
color26: json['color26'],
color27: json['color27'],
color28: json['color28'],
color29: json['color29'],
color30: json['color30'],
color31: json['color31'],
color32: json['color32'],
color33: json['color33'],
color34: json['color34'],
color38: json['color38'],
color39: json['color39'],
color40: json['color40']);
Map<String, dynamic> toJson() => {
'color1': color1,
'color2': color2,
'color3': color3,
'color4': color4,
'color5': color5,
'color6': color6,
'color7': color7,
'color8': color8,
'color9': color9,
'color10': color10,
'color11': color11,
'color12': color12,
'color13': color13,
'color14': color14,
'color15': color15,
'color16': color16,
'color17': color17,
'color18': color18,
'color19': color19,
'color20': color20,
'color21': color21,
'color25': color25,
'color26': color26,
'color27': color27,
'color28': color28,
'color29': color29,
'color30': color30,
'color31': color31,
'color32': color32,
'color33': color33,
'color34': color34,
'color38': color38,
'color39': color39,
'color40': color40,
};
}

View File

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

22
lib/model/device.dart Normal file
View File

@@ -0,0 +1,22 @@
import 'package:json_annotation/json_annotation.dart';
import 'device_share.dart';
part 'device.g.dart';
@JsonSerializable()
class DeviceModel {
String? name; //设备名称
String? id; //设备id
String? status; //设备状态
String? roomName; //设备所属房间
String? shareNum; //设备已分享数量
@JsonKey(ignore: true)
List<DeviceShareModel> shareInfo = []; //设备分享信息
DeviceModel();
static DeviceModel fromJson(Map<String, dynamic> json) =>
_$DeviceModelFromJson(json);
Map<String, dynamic> toJson() => _$DeviceModelToJson(this);
}

23
lib/model/device.g.dart Normal file
View File

@@ -0,0 +1,23 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceModel _$DeviceModelFromJson(Map<String, dynamic> json) => DeviceModel()
..name = json['name'] as String?
..id = json['id'] as String?
..status = json['status'] as String?
..roomName = json['roomName'] as String?
..shareNum = json['shareNum'] as String?;
Map<String, dynamic> _$DeviceModelToJson(DeviceModel instance) =>
<String, dynamic>{
'name': instance.name,
'id': instance.id,
'status': instance.status,
'roomName': instance.roomName,
'shareNum': instance.shareNum,
};

View File

@@ -0,0 +1,15 @@
import 'package:json_annotation/json_annotation.dart';
part 'device_share.g.dart';
@JsonSerializable()
class DeviceShareModel {
String? name; //设备名称
String? phone; //被分享手机号
DateTime? share_time; //分享时间
DeviceShareModel();
static DeviceShareModel fromJson(Map<String, dynamic> json) =>
_$DeviceShareModelFromJson(json);
Map<String, dynamic> toJson() => _$DeviceShareModelToJson(this);
}

View File

@@ -0,0 +1,22 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device_share.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeviceShareModel _$DeviceShareModelFromJson(Map<String, dynamic> json) =>
DeviceShareModel()
..name = json['name'] as String?
..phone = json['phone'] as String?
..share_time = json['share_time'] == null
? null
: DateTime.parse(json['share_time'] as String);
Map<String, dynamic> _$DeviceShareModelToJson(DeviceShareModel instance) =>
<String, dynamic>{
'name': instance.name,
'phone': instance.phone,
'share_time': instance.share_time?.toIso8601String(),
};

View File

@@ -0,0 +1,19 @@
import 'package:json_annotation/json_annotation.dart';
part 'experience_store.g.dart';
//体验店
@JsonSerializable()
class ExperienceStoreModel {
String? name; //设备名称
String? phone; //店铺电话
String? address; //店铺地址
ExperienceStoreModel();
static ExperienceStoreModel fromJson(Map<String, dynamic> json) =>
_$ExperienceStoreModelFromJson(json);
Map<String, dynamic> toJson() => _$ExperienceStoreModelToJson(this);
}

View File

@@ -0,0 +1,22 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'experience_store.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ExperienceStoreModel _$ExperienceStoreModelFromJson(
Map<String, dynamic> json) =>
ExperienceStoreModel()
..name = json['name'] as String?
..phone = json['phone'] as String?
..address = json['address'] as String?;
Map<String, dynamic> _$ExperienceStoreModelToJson(
ExperienceStoreModel instance) =>
<String, dynamic>{
'name': instance.name,
'phone': instance.phone,
'address': instance.address,
};

14
lib/model/issue.dart Normal file
View File

@@ -0,0 +1,14 @@
import 'package:json_annotation/json_annotation.dart';
part 'issue.g.dart';
@JsonSerializable()
class IssueModel {
String? title;
String? title_content;
IssueModel();
static IssueModel fromJson(Map<String, dynamic> json) =>
_$IssueModelFromJson(json);
Map<String, dynamic> toJson() => _$IssueModelToJson(this);
}

17
lib/model/issue.g.dart Normal file
View File

@@ -0,0 +1,17 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'issue.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
IssueModel _$IssueModelFromJson(Map<String, dynamic> json) => IssueModel()
..title = json['title'] as String?
..title_content = json['title_content'] as String?;
Map<String, dynamic> _$IssueModelToJson(IssueModel instance) =>
<String, dynamic>{
'title': instance.title,
'title_content': instance.title_content,
};

19
lib/model/message.dart Normal file
View File

@@ -0,0 +1,19 @@
import 'package:json_annotation/json_annotation.dart';
part 'message.g.dart';
@JsonSerializable()
class MessageModel {
String? title;//消息名称
String? did;//消息设备id
String? userId;//消息用户id
String? userName;//消息用户名称
DateTime? createTime;//消息创建时间
int? type;//消息类型
MessageModel();
static MessageModel fromJson(Map<String, dynamic> json) =>
_$MessageModelFromJson(json);
Map<String, dynamic> toJson() => _$MessageModelToJson(this);
}

27
lib/model/message.g.dart Normal file
View File

@@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'message.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
MessageModel _$MessageModelFromJson(Map<String, dynamic> json) => MessageModel()
..title = json['title'] as String?
..did = json['did'] as String?
..userId = json['userId'] as String?
..userName = json['userName'] as String?
..createTime = json['createTime'] == null
? null
: DateTime.parse(json['createTime'] as String)
..type = (json['type'] as num?)?.toInt();
Map<String, dynamic> _$MessageModelToJson(MessageModel instance) =>
<String, dynamic>{
'title': instance.title,
'did': instance.did,
'userId': instance.userId,
'userName': instance.userName,
'createTime': instance.createTime?.toIso8601String(),
'type': instance.type,
};

32
lib/model/order.dart Normal file
View File

@@ -0,0 +1,32 @@
import 'package:json_annotation/json_annotation.dart';
part 'order.g.dart';
@JsonSerializable()
class OrderModel {
String? goods_name; //商品名称
String? goods_id; //商品id
String? id; //订单id
double? price; //支付金额
String? tel; //电话号码
String? addition_address; //详细地址
// DateTime? create_time; //创建时间
int? create_time; //创建时间
String? desc; //审核意见
String? create_user_id; //下单用户id
String? create_user_name; //下单用户名称
int? order_status; //订单状态
String? delivery_status; //物流状态
int? order_num; //商品数量
String? province; //省份
String? city; //城市
String? county; //区域
String? street; //街道
double? goods_price; //商品单价
String? pay_status; //支付状态
OrderModel();
static OrderModel fromJson(Map<String, dynamic> json) =>
_$OrderModelFromJson(json);
Map<String, dynamic> toJson() => _$OrderModelToJson(this);
}

51
lib/model/order.g.dart Normal file
View File

@@ -0,0 +1,51 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'order.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
OrderModel _$OrderModelFromJson(Map<String, dynamic> json) => OrderModel()
..goods_name = json['goods_name'] as String?
..goods_id = json['goods_id'] as String?
..id = json['id'] as String?
..price = (json['price'] as num?)?.toDouble()
..tel = json['tel'] as String?
..addition_address = json['addition_address'] as String?
..create_time = (json['create_time'] as num?)?.toInt()
..desc = json['desc'] as String?
..create_user_id = json['create_user_id'] as String?
..create_user_name = json['create_user_name'] as String?
..order_status = (json['order_status'] as num?)?.toInt()
..delivery_status = json['delivery_status'] as String?
..order_num = (json['order_num'] as num?)?.toInt()
..province = json['province'] as String?
..city = json['city'] as String?
..county = json['county'] as String?
..street = json['street'] as String?
..goods_price = (json['goods_price'] as num?)?.toDouble()
..pay_status = json['pay_status'] as String?;
Map<String, dynamic> _$OrderModelToJson(OrderModel instance) =>
<String, dynamic>{
'goods_name': instance.goods_name,
'goods_id': instance.goods_id,
'id': instance.id,
'price': instance.price,
'tel': instance.tel,
'addition_address': instance.addition_address,
'create_time': instance.create_time,
'desc': instance.desc,
'create_user_id': instance.create_user_id,
'create_user_name': instance.create_user_name,
'order_status': instance.order_status,
'delivery_status': instance.delivery_status,
'order_num': instance.order_num,
'province': instance.province,
'city': instance.city,
'county': instance.county,
'street': instance.street,
'goods_price': instance.goods_price,
'pay_status': instance.pay_status,
};

View File

@@ -0,0 +1,18 @@
import 'package:json_annotation/json_annotation.dart';
part 'repair_process.g.dart';
@JsonSerializable()
class RepairProcessModel {
String? status; //审核状态
DateTime? create_time; //审核时间
String? desc; //审核意见
int? record_id; //归属记录
int? deal_user; //处理人
RepairProcessModel();
static RepairProcessModel fromJson(Map<String, dynamic> json) =>
_$RepairProcessModelFromJson(json);
Map<String, dynamic> toJson() => _$RepairProcessModelToJson(this);
}

View File

@@ -0,0 +1,26 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'repair_process.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
RepairProcessModel _$RepairProcessModelFromJson(Map<String, dynamic> json) =>
RepairProcessModel()
..status = json['status'] as String?
..create_time = json['create_time'] == null
? null
: DateTime.parse(json['create_time'] as String)
..desc = json['desc'] as String?
..record_id = (json['record_id'] as num?)?.toInt()
..deal_user = (json['deal_user'] as num?)?.toInt();
Map<String, dynamic> _$RepairProcessModelToJson(RepairProcessModel instance) =>
<String, dynamic>{
'status': instance.status,
'create_time': instance.create_time?.toIso8601String(),
'desc': instance.desc,
'record_id': instance.record_id,
'deal_user': instance.deal_user,
};

20
lib/model/user_data.dart Normal file
View File

@@ -0,0 +1,20 @@
import 'package:json_annotation/json_annotation.dart';
part 'user_data.g.dart';
@JsonSerializable()
class UserModel {
String? uid;
String? userName;
String? nickName;
String? tel;
String? exp1;
String? head;
String? tmpHead;
String? tmpNickName;
UserModel();
static UserModel fromJson(Map<String, dynamic> json) =>
_$UserModelFromJson(json);
Map<String, dynamic> toJson() => _$UserModelToJson(this);
}

View File

@@ -0,0 +1,28 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel()
..uid = json['uid'] as String?
..userName = json['userName'] as String?
..nickName = json['nickName'] as String?
..tel = json['tel'] as String?
..exp1 = json['exp1'] as String?
..head = json['head'] as String?
..tmpHead = json['tmpHead'] as String?
..tmpNickName = json['tmpNickName'] as String?;
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
'uid': instance.uid,
'userName': instance.userName,
'nickName': instance.nickName,
'tel': instance.tel,
'exp1': instance.exp1,
'head': instance.head,
'tmpHead': instance.tmpHead,
'tmpNickName': instance.tmpNickName,
};

View File

@@ -0,0 +1,366 @@
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/CustomCard.dart';
import 'package:vbvs_app/controller/device/blueteeth_bind_controller.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class DeviceTypePage extends StatefulWidget {
const DeviceTypePage({super.key});
@override
State<DeviceTypePage> createState() => _EPageState();
}
class _EPageState extends State<DeviceTypePage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
BlueteethBindController blueteethBindController = Get.find();
@override
void initState() {
super.initState();
// 延迟到 build 完成后执行弹窗逻辑
WidgetsBinding.instance.addPostFrameCallback((_) {
if (blueteethBindController.model.read == 1) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
backgroundColor: Colors.transparent,
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(30.rpx, 0, 30.rpx, 0),
child: Container(
width: double.infinity,
constraints: BoxConstraints(
maxHeight: MediaQuery.sizeOf(context).height * 0.656,
),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Container(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 26.rpx, 0, 0),
child: Container(
width: MediaQuery.sizeOf(context).width,
decoration: BoxDecoration(
color: Color(0xFFFBF5D5),
borderRadius: BorderRadius.circular(
AppConstants()
.normal_container_radius), // 圆角半径
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
25.rpx, 25.rpx, 25.rpx, 25.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Icon(
Icons.volume_mute,
color:
FlutterFlowTheme.of(context)
.primaryText,
size: 30.rpx,
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'绑定引导.说明标题'.tr,
style: FlutterFlowTheme.of(
context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
fontWeight:
FontWeight.w500,
color:
Colors.orange),
),
Text(
'绑定引导.说明正文'.tr,
style: FlutterFlowTheme.of(
context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
height: AppConstants()
.text_padding_up_dowm_p)),
),
),
].divide(SizedBox(width: 20.rpx)),
),
),
),
),
Container(
width: double.infinity,
height: MediaQuery.sizeOf(context).height *
0.26,
constraints: BoxConstraints(
minHeight: 421.rpx,
),
child: ClipRRect(
borderRadius:
BorderRadius.circular(20.rpx),
child: Image.network(
'https://picsum.photos/seed/861/600',
fit: BoxFit.cover,
),
),
),
].divide(SizedBox(height: 25.rpx)),
),
),
),
),
Flexible(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 210.rpx, 0, 0),
child: Container(
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(
Icons.arrow_back,
color: FlutterFlowTheme.of(context)
.primaryText,
size: 24.rpx,
),
Text(
'绑定引导.不再提示'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
color: Colors.white),
),
].divide(SizedBox(width: 22.rpx)),
),
),
CustomCard(
borderRadius: 50.rpx,
onTap: () async {
await Future.delayed(
Duration(seconds: 1));
Get.back(); // 关闭当前弹窗或页面
},
colors: [
Colors.yellow,
Colors.green
], // 单色背景也用渐变写法
title: '',
child: Container(
width: MediaQuery.sizeOf(context).width *
0.66,
height:
MediaQuery.sizeOf(context).height *
0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
alignment: Alignment.center, // 居中对齐
child: Text(
'绑定引导.跳过'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
)
].divide(SizedBox(height: 42.rpx)),
),
),
),
),
],
),
),
));
},
);
}
});
}
@override
Widget build(BuildContext context) {
int read = blueteethBindController.model.read;
if (blueteethBindController.model.read == 1) {
//需要弹窗显示教程
}
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: stringToColor("#242835"),
// backgroundColor: Colors.transparent,
automaticallyImplyLeading: false,
// iconTheme: IconThemeData(color: Colors.white),
titleSpacing: 0,
// leading: returnIconButtom,
title: Container(
// color: Colors.grey,
width: double.infinity,
height: 180.rpx,
child: Stack(
alignment: Alignment.center,
children: [
/// 居中标题
Text(
'设备列表',
style: FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Readex Pro',
color: Colors.white,
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: [
_buildDeviceCard(
context,
title: '设备类型.体征监测设备'.tr,
imageUrl: 'assets/img/device.png',
),
_buildDeviceCard(
context,
title: '设备类型.智能床/床垫'.tr,
imageUrl: 'assets/img/bed.png',
),
_buildDeviceCard(
context,
title: '设备类型.摄像头'.tr,
imageUrl: 'assets/img/camera.png',
),
]
.divide(SizedBox(height: 26.rpx))
.addToStart(SizedBox(height: 26.rpx))
.addToEnd(SizedBox(height: 26.rpx)),
),
),
),
),
),
),
),
);
}
Widget _buildDeviceCard(BuildContext context,
{required String title, required String imageUrl}) {
return CustomCard(
borderRadius: 20.rpx, // 圆角大小
onTap: () {
print('点击了 $title');
},
// colors: [Colors.white.withOpacity(0.06)], // 背景色
colors: [stringToColor("45D989"), stringToColor("00C1AA")], // 背景色
title: title,
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,
),
),
],
),
),
);
}
}

276
lib/pages/login/login.dart Normal file
View File

@@ -0,0 +1,276 @@
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/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _EPageState();
}
class _EPageState extends State<LoginPage> {
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: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
35.rpx, 66.rpx, 0, 0),
child: Icon(
Icons.arrow_back,
color: FlutterFlowTheme.of(context).primaryText,
size: 24.rpx,
),
),
),
),
Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 141.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'欢迎使用太和e护',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 48.rpx,
letterSpacing: 0.0,
),
),
),
),
),
),
Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 15.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'科技睡眠 洞悉万千',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 30.rpx,
letterSpacing: 0.0,
),
),
),
),
),
),
Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 95.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'139****0733',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 48.rpx,
letterSpacing: 0.0,
),
),
),
),
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 35.rpx, 0, 0),
child: Container(
width: MediaQuery.sizeOf(context).width * 0.8,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
decoration: BoxDecoration(
color: Color(0xFFF01515),
borderRadius: BorderRadius.circular(50.rpx),
),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'本机号码一键登录/注册',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
),
),
Align(
alignment: AlignmentDirectional(-1, 0),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 32.rpx, 0, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Align(
alignment: AlignmentDirectional(0, 0),
child: Text(
'其他手机号码',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
110.rpx, 136.rpx, 110.rpx, 0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.arrow_back,
color:
FlutterFlowTheme.of(context).primaryText,
size: 24.rpx,
),
Expanded(
// 👈 让文本自动换行
child: Text(
'登录时将自动注册,且代表您同意《用户协议》和 《隐私政策》以及《用户使用条款》',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
fontSize: 24.rpx, // 可选:字体稍小点更适配
),
),
),
].divide(SizedBox(width: 26.rpx)),
),
),
),
],
),
),
),
Container(
width: double.infinity,
height: MediaQuery.sizeOf(context).height * 0.136,
constraints: BoxConstraints(
minHeight: 220.rpx,
),
decoration: BoxDecoration(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 0, 0, 36.rpx),
child: Text(
'其他登录方式',
style:
FlutterFlowTheme.of(context).bodyMedium.override(
fontFamily: 'Inter',
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.network(
'https://picsum.photos/seed/301/600',
fit: BoxFit.cover,
),
),
Container(
width: 91.rpx,
height: 91.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.network(
'https://picsum.photos/seed/301/600',
fit: BoxFit.cover,
),
),
].divide(SizedBox(width: 35.rpx)),
),
],
),
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,85 @@
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 EPage extends StatefulWidget {
const EPage({super.key});
@override
State<EPage> createState() => _EPageState();
}
class _EPageState extends State<EPage> {
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(
// appBar: AppBar(
// backgroundColor: AppColors.bg_color,
// automaticallyImplyLeading: false,
// title: Container(
// width: double.infinity,
// height: 70.rpx,
// child: Obx(
// () => InkWell(
// onTap: () {
// Get.toNamed("/editUserInfoPage");
// },
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 56.rpx,
// height: 56.rpx,
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// ),
// Container(
// width: 20.rpx,
// height: 0,
// decoration: BoxDecoration(
// color: Colors.white,
// shape: BoxShape.rectangle,
// ),
// ),
// Text(
// userInfoController.model.user!.nickName ?? '匿名',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Readex Pro',
// color: Colors.white,
// letterSpacing: 0,
// fontSize: 30.rpx),
// ),
// ],
// ),
// ],
// ),
// ),
// ),
// ),
// actions: [],
// centerTitle: false,
// ),
body: SafeArea(
top: true,
child: Text("小e"),
),
),
),
);
}
}

View File

@@ -0,0 +1,396 @@
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/CustomCard.dart';
import 'package:vbvs_app/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
ThemeController themeController = Get.find();
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
// appBar: AppBar(
// backgroundColor: AppColors.bg_color,
// automaticallyImplyLeading: false,
// title: Container(
// width: double.infinity,
// height: 70.rpx,
// child: Obx(
// () => InkWell(
// onTap: () {
// Get.toNamed("/editUserInfoPage");
// },
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 56.rpx,
// height: 56.rpx,
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// ),
// Container(
// width: 20.rpx,
// height: 0,
// decoration: BoxDecoration(
// color: Colors.white,
// shape: BoxShape.rectangle,
// ),
// ),
// Text(
// userInfoController.model.user!.nickName ?? '匿名',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Readex Pro',
// color: Colors.white,
// letterSpacing: 0,
// fontSize: 30.rpx),
// ),
// ],
// ),
// ],
// ),
// ),
// ),
// ),
// actions: [],
// centerTitle: false,
// ),
body: SafeArea(
top: true,
// child: Text("首页"),
child: Container(
height: bodySize.maxHeight,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgImage.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
AppConstants().main_left_right_padding,
47.rpx,
AppConstants().main_left_right_padding,
0),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
AppConstants().content_left_right_padding,
0,
AppConstants().content_left_right_padding,
0),
child: Container(
width: double.infinity,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomCard(
borderRadius: 20.rpx,
onTap: () async {
Get.toNamed("/loginPage");
},
title: '首页.登录'
.tr, // 虽然 title 传入了,但当前组件里没用它(可忽略或用于调试)
colors: [
stringToColor("#45D989"),
stringToColor("#00C1AA"),
],
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: Colors.white,
letterSpacing: 0.0,
),
),
),
),
Icon(
Icons.add_circle_outline_outlined,
color: FlutterFlowTheme.of(context).primaryText,
size: 38.rpx,
),
// Lottie.asset(
// 'assets/img/loading.json',
// width: 200,
// height: 200,
// fit: BoxFit.contain,
// )
],
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
19.rpx, 13.rpx, 0, 13.rpx),
child: Container(
width: double.infinity,
child: Row(
children: [
Text(
'首页.已关联体征监测设备'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize:
AppConstants().title_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
' 0',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize:
AppConstants().title_text_fontSize,
letterSpacing: 0.0,
),
),
],
)),
),
Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height * 0.277,
constraints: BoxConstraints(
minWidth: 690.rpx,
minHeight: 450.rpx,
),
decoration: BoxDecoration(
color: stringToColor("#242835"),
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius), // 圆角半径
),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: MediaQuery.sizeOf(context).width * 0.66,
height: MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.red, Colors.orange], // 渐变颜色数组
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(
AppConstants()
.button_container_radius), // 圆角半径
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.arrow_back,
color: FlutterFlowTheme.of(context)
.primaryText,
size: 28.rpx,
),
Text(
'首页.扫一扫绑定'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
width: 17.rpx,
)),
),
),
CustomCard(
borderRadius: AppConstants()
.button_container_radius, // 圆角半径
onTap: () {
print('Button pressed ...');
Get.toNamed("/deviceType");
},
colors: [
stringToColor("45D989"),
stringToColor("00C1AA")
], // 渐变色是同一个色,也可以根据需要调整
title: '首页.蓝牙绑定'.tr, // 可选,虽然这个 title 没用,但可以作为调试用
child: Container(
width: MediaQuery.sizeOf(context).width * 0.66,
height:
MediaQuery.sizeOf(context).height * 0.055,
constraints: BoxConstraints(
minWidth: 500.rpx,
minHeight: 90.rpx,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.arrow_back,
color: FlutterFlowTheme.of(context)
.primaryText,
size: 28.rpx,
),
Text(
'首页.蓝牙绑定'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
width: 17.rpx,
)),
),
),
)
],
),
),
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 26.rpx, 0, 0),
child: Container(
width: MediaQuery.sizeOf(context).width,
decoration: BoxDecoration(
color: Color(0xFFFBF5D5),
borderRadius: BorderRadius.circular(
AppConstants().normal_container_radius), // 圆角半径
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
25.rpx, 25.rpx, 25.rpx, 25.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.volume_mute,
color:
FlutterFlowTheme.of(context).primaryText,
size: 30.rpx,
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
'首页.提示标题'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
fontWeight: FontWeight.w500,
color: Colors.orange),
),
Text(
'首页.提示内容1'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
'首页.提示内容2'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
'首页.提示内容3'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(
height: AppConstants()
.text_padding_up_dowm_p)),
),
)
].divide(SizedBox(width: 20.rpx)),
),
),
),
),
],
),
),
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,192 @@
import 'dart:async';
import 'dart:io';
import 'package:ef/ef.dart';
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/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/main_bottom/main_page_controller.dart';
import 'package:vbvs_app/controller/theme_controller/ThemeController.dart';
import 'package:vbvs_app/pages/main_bottom/e_page.dart';
import 'package:vbvs_app/pages/main_bottom/home_page.dart';
import 'package:vbvs_app/pages/main_bottom/message_page.dart';
import 'package:vbvs_app/pages/main_bottom/mine_page.dart';
import 'package:vbvs_app/pages/main_bottom/sleep_report_page.dart';
class MainPageBottomChange extends GetView<MainPageController> {
GlobalController globalController = Get.find();
ThemeController themeController = Get.find();
getBottomNavigationBarItem(String svgPath, String actSvgPath, String label,
{double size = 0, bool isEmpty = false}) {
if (size == 0) {
size = 36.rpx;
}
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,
// color: stringToColor("#D3B684"),
// width: size,
// height: size,
// ),
// ),
activeIcon: Padding(
padding: EdgeInsets.only(bottom: 6.rpx),
child: isEmpty
? Container()
: SvgPicture.asset(
svgPath,
width: size,
height: size,
),
),
label: label);
}
List arr = [
HomePage(),
SleepReportPage(),
EPage(),
MessagePage(),
MinePage(),
];
DateTime? _lastBackPressedTime; // 记录上一次返回的时间
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvokedWithResult: (disposition, result) async {
if (Platform.isAndroid) {
var flag = await _handleBackPressed(context); // 自定义返回逻辑
if (flag) {
SystemNavigator.pop();
}
}
},
child: Obx(
() {
if (globalController.model.hideBottomNavigationBar == true) {
return Scaffold(
body: arr[controller.model.currentIndex],
floatingActionButtonAnimator:
FloatingActionButtonAnimator.noAnimation,
floatingActionButton: Container(),
);
} else {
return Scaffold(
body: arr[controller.model.currentIndex],
floatingActionButtonAnimator:
FloatingActionButtonAnimator.noAnimation,
// floatingActionButton: Stack(
// alignment: Alignment.center,
// children: [
// Positioned(
// bottom: 10.rpx,
// child: InkWell(
// onTap: () {
// print("index 3");
// if (globalController.model.deviceList.length == 0) {
// showToast("请先绑定设备");
// return;
// }
// if (globalController.model.deviceMain == null ||
// globalController.model.deviceMain["mac"] == null) {
// globalController.model.deviceMain =
// globalController.model.deviceList[0];
// globalController.updateAll();
// }
// controller.model.currentIndex = 2;
// controller.updateAll();
// },
// child: Image.asset(
// gaplessPlayback: true,
// excludeFromSemantics: true,
// controller.model.currentIndex == 2
// ? "assets/images/icon_sleep_light.png"
// : "assets/images/icon_sleep_dark.png",
// width: 120.rpx,
// height: 120.rpx,
// ),
// )),
// ],
// ),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: Theme(
data: ThemeData(
splashFactory: NoSplash.splashFactory,
highlightColor: Colors.transparent),
child: BottomNavigationBar(
unselectedItemColor: Colors.white,
selectedItemColor: stringToColor("#D3B684"),
backgroundColor: themeController.currentColor.sc5,
selectedFontSize: 26.rpx,
unselectedFontSize: 26.rpx,
type: BottomNavigationBarType.fixed,
currentIndex: controller.model.currentIndex,
onTap: (index) {
// if(controller.model.currentIndex == 2) {
// arr[2].closeBefore();
// }
Future.delayed(const Duration(milliseconds: 500), () {
if (controller.model.currentIndex != 1) {
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),
],
),
),
);
}
},
),
);
}
Future<bool> _handleBackPressed(BuildContext context) async {
final currentTime = DateTime.now();
// 如果上次点击返回键时间为空,或者间隔超过 1 秒
if (_lastBackPressedTime == null ||
currentTime.difference(_lastBackPressedTime!) > Duration(seconds: 2)) {
_lastBackPressedTime = currentTime;
showToast("再按一次退出程序", color: color_warning, closeTime: 2);
return false; // 阻止退出程序
} else {
return true; // 允许退出程序
}
}
}

View File

@@ -0,0 +1,85 @@
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 MessagePage extends StatefulWidget {
const MessagePage({super.key});
@override
State<MessagePage> createState() => _MessagePageState();
}
class _MessagePageState extends State<MessagePage> {
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(
// appBar: AppBar(
// backgroundColor: AppColors.bg_color,
// automaticallyImplyLeading: false,
// title: Container(
// width: double.infinity,
// height: 70.rpx,
// child: Obx(
// () => InkWell(
// onTap: () {
// Get.toNamed("/editUserInfoPage");
// },
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 56.rpx,
// height: 56.rpx,
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// ),
// Container(
// width: 20.rpx,
// height: 0,
// decoration: BoxDecoration(
// color: Colors.white,
// shape: BoxShape.rectangle,
// ),
// ),
// Text(
// userInfoController.model.user!.nickName ?? '匿名',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Readex Pro',
// color: Colors.white,
// letterSpacing: 0,
// fontSize: 30.rpx),
// ),
// ],
// ),
// ],
// ),
// ),
// ),
// ),
// actions: [],
// centerTitle: false,
// ),
body: SafeArea(
top: true,
child: Text("消息"),
),
),
),
);
}
}

View File

@@ -0,0 +1,374 @@
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/controller/main_bottom/global_controller.dart';
import 'package:vbvs_app/controller/user_info_controller.dart';
class MinePage extends StatefulWidget {
const MinePage({super.key});
@override
State<MinePage> createState() => _MinePageState();
}
class _MinePageState extends State<MinePage> {
GlobalController globalController = Get.find();
UserInfoController userInfoController = Get.find();
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, bodySize) => GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
body: SafeArea(
top: true,
child: Container(
height: bodySize.maxHeight,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/img/bgImage.png'), // 本地图片
fit: BoxFit.fill, // 填满整个 Container
),
),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF242835),
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(
AppConstants().normal_container_radius),
bottomRight: Radius.circular(
AppConstants().normal_container_radius),
topLeft: Radius.circular(0.rpx),
topRight: Radius.circular(0.rpx),
),
),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(64.rpx, 0, 37.rpx, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0, 65.rpx, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
SvgPicture.asset(
'assets/img/icon/earphone.svg',
width: 29.rpx,
height: 29.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
SvgPicture.asset(
'assets/img/icon/setting.svg',
width: 29.rpx,
height: 29.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
].divide(SizedBox(width: 60.rpx)),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0, 50.rpx, 0, 66.rpx),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 120.rpx,
height: 120.rpx,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Image.network(
'https://picsum.photos/seed/270/600',
fit: BoxFit.cover,
),
),
Column(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'Hello World',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFEFF3F8),
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
Text(
'Hello World',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFEAEFF3),
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(height: 20.rpx)),
),
].divide(SizedBox(width: 35.rpx)),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'我的.个人信息'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE0E4E6),
fontSize: AppConstants()
.normal_text_fontSize,
letterSpacing: 0.0,
),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 14.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
].divide(SizedBox(width: 16.rpx)),
),
],
),
),
],
),
),
),
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(
40.rpx, 0, 40.rpx, 0),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
SvgPicture.asset(
'assets/img/icon/my_device.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
Text(
'我的.我的设备'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE0E2E4),
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 15.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
SvgPicture.asset(
'assets/img/icon/device_repair.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
Text(
'我的.设备报修'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE0E2E4),
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 15.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
SvgPicture.asset(
'assets/img/icon/op_ex.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
Text(
'我的.操作说明'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE0E2E4),
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 14.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
SvgPicture.asset(
'assets/img/icon/like.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
Text(
'关注我们'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE0E2E4),
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 15.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
SvgPicture.asset(
'assets/img/icon/version.svg',
width: 25.rpx,
height: 25.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
Text(
'我的.当前版本'.tr,
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFE0E2E4),
fontSize: AppConstants()
.title_text_fontSize,
letterSpacing: 0.0,
),
),
].divide(SizedBox(width: 22.rpx)),
),
Row(
mainAxisSize: MainAxisSize.max,
children: [
Text(
'3.61.0',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFD9E3EB),
fontSize: 26.rpx,
letterSpacing: 0.0,
),
),
SvgPicture.asset(
'assets/img/icon/arrow_right.svg',
width: 8.rpx,
height: 15.rpx, // 如果 SVG 中没有固定颜色,可以这样设置
),
].divide(SizedBox(width: 28.rpx)),
),
],
),
]
.divide(SizedBox(height: 60.rpx))
.addToStart(SizedBox(height: 60.rpx))
.addToEnd(SizedBox(height: 60.rpx)),
),
),
),
),
],
),
),
),
),
),
);
}
}

View File

@@ -0,0 +1,85 @@
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});
@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(
// appBar: AppBar(
// backgroundColor: AppColors.bg_color,
// automaticallyImplyLeading: false,
// title: Container(
// width: double.infinity,
// height: 70.rpx,
// child: Obx(
// () => InkWell(
// onTap: () {
// Get.toNamed("/editUserInfoPage");
// },
// child: Row(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Container(
// width: 56.rpx,
// height: 56.rpx,
// clipBehavior: Clip.antiAlias,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// ),
// ),
// Container(
// width: 20.rpx,
// height: 0,
// decoration: BoxDecoration(
// color: Colors.white,
// shape: BoxShape.rectangle,
// ),
// ),
// Text(
// userInfoController.model.user!.nickName ?? '匿名',
// style: FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily: 'Readex Pro',
// color: Colors.white,
// letterSpacing: 0,
// fontSize: 30.rpx),
// ),
// ],
// ),
// ],
// ),
// ),
// ),
// ),
// actions: [],
// centerTitle: false,
// ),
body: SafeArea(
top: true,
child: Text("睡眠报告"),
),
),
),
);
}
}

View File

@@ -0,0 +1,21 @@
import 'package:ef/ef.dart';
//问题与帮助
class HelpRepository {
//查询记录
Future findHelpInfos({int limit = 10, int offset = 0}) async {
try {
var response = await ef.client
.from('app_help_list')
.select()
// .eq('deleted', 0)
.eq('status', 1)
.order("priority", ascending: true)
.order("created_at", ascending: false);
return response as List<dynamic>;
} catch (e) {
print('Error fetching repairs: $e');
return [];
}
}
}

47
lib/routers/routers.dart Normal file
View File

@@ -0,0 +1,47 @@
import 'package:flutter/cupertino.dart';
import 'package:vbvs_app/pages/device_bind/device_type.dart';
import 'package:vbvs_app/pages/login/login.dart';
import 'package:vbvs_app/pages/main_bottom/e_page.dart';
import 'package:vbvs_app/pages/main_bottom/home_page.dart';
import 'package:vbvs_app/pages/main_bottom/main_page_bottom_change.dart';
import 'package:vbvs_app/pages/main_bottom/message_page.dart';
import 'package:vbvs_app/pages/main_bottom/mine_page.dart';
import 'package:vbvs_app/pages/main_bottom/sleep_report_page.dart';
var routes = {
"/homePage": (contxt) => HomePage(),
"/sleepReportPage": (contxt) => SleepReportPage(),
"/ePage": (contxt) => EPage(),
"/messagePage": (contxt) => MessagePage(),
"/minePage": (contxt) => MinePage(),
"/mianPageBottomChange": (contxt) => MainPageBottomChange(),
"/loginPage": (contxt) => LoginPage(),
"/deviceType": (contxt) => DeviceTypePage(),
};
//2、配置onGenerateRoute 固定写法 这个方法也相当于一个中间件,这里可以做权限判断
var onGenerateRoute = (RouteSettings settings) {
final String? name = settings.name; // /news 或者 /search
final Function? pageContentBuilder =
routes[name]; // Function = (contxt) { return const NewsPage()}
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));
return route;
}
}
return null;
};