diff --git a/ln_jq_app/lib/pages/c_page/car_info/view.dart b/ln_jq_app/lib/pages/c_page/car_info/view.dart index ccc0bd6..d47e95c 100644 --- a/ln_jq_app/lib/pages/c_page/car_info/view.dart +++ b/ln_jq_app/lib/pages/c_page/car_info/view.dart @@ -345,7 +345,7 @@ class CarInfoPage extends GetView { ), const SizedBox(height: 9), SizedBox( - height: 333.h, // 给定一个高度,或者使用别的方式布局 + height: 336.h, // 给定一个高度,或者使用别的方式布局 child: TabBarView( children: [ _buildCertificateContent('行驶证', controller.drivingAttachments), @@ -375,11 +375,12 @@ class CarInfoPage extends GetView { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ + //证件文字 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildCertDetailItem('所有人', '上海羚牛氢运物联网科技有限公司', isFull: true), - _buildCertDetailItem('车辆识别代号', controller.vin), + _buildCertDetailItem('所属公司', '上海羚牛氢运物联网科技有限公司', isFull: true), + _buildCertDetailItem('运营城市', controller.vin), ], ), const SizedBox(height: 16), @@ -387,11 +388,11 @@ class CarInfoPage extends GetView { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildCertDetailItem( - '有效期至', + '车辆颜色', '2028-08-14', valueColor: const Color(0xFF52C41A), ), - _buildCertDetailItem('使用性质', '货运'), + _buildCertDetailItem('氢瓶容量', '货运'), ], ), const SizedBox(height: 16), diff --git a/ln_jq_app/lib/pages/c_page/reservation/controller.dart b/ln_jq_app/lib/pages/c_page/reservation/controller.dart index a197682..5371a09 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/controller.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/controller.dart @@ -2,17 +2,11 @@ import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:getx_scaffold/common/common.dart'; -import 'package:getx_scaffold/common/services/http.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; -import 'package:intl/intl.dart'; import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/common/model/station_model.dart'; import 'package:ln_jq_app/common/model/vehicle_info.dart'; import 'package:ln_jq_app/pages/b_page/site/controller.dart'; -import 'package:ln_jq_app/pages/c_page/reservation_edit/controller.dart'; -import 'package:ln_jq_app/pages/c_page/reservation_edit/view.dart'; import 'package:ln_jq_app/pages/qr_code/view.dart'; import 'package:ln_jq_app/storage_service.dart'; @@ -395,7 +389,6 @@ class C_ReservationController extends GetxController with BaseControllerMixin { ); var result = BaseModel.fromJson(responseData?.data); - if (responseData == null || result.code != 0) { dismissLoading(); showToast(result.error); @@ -555,6 +548,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin { super.onInit(); getUserBindCarInfo(); getSiteList(); + _msgNotice(); if (!init) { _setupListener(); @@ -562,6 +556,28 @@ class C_ReservationController extends GetxController with BaseControllerMixin { } } + bool isNotice = false; + + Future _msgNotice() async { + final Map requestData = { + 'appFlag': 1, + 'isRead': 1, + 'pageNum': 1, + 'pageSize': 5, + }; + final response = await HttpService.to.get( + 'appointment/unread_notice/page', + params: requestData, + ); + if (response != null) { + final result = BaseModel.fromJson(response.data); + if (result.code == 0 && result.data != null) { + String total = result.data["total"].toString(); + isNotice = int.parse(total) > 0; + } + } + } + @override void dispose() { _sheetWorker?.dispose(); @@ -691,7 +707,9 @@ class C_ReservationController extends GetxController with BaseControllerMixin { try { showLoading("加氢站数据加载中"); - var responseData = await HttpService.to.get("appointment/station/queryHydrogenSiteInfo"); + var responseData = await HttpService.to.get( + "appointment/station/queryHydrogenSiteInfo", + ); if (responseData == null || responseData.data == null) { showToast('暂时无法获取站点信息'); diff --git a/ln_jq_app/lib/pages/c_page/reservation/view.dart b/ln_jq_app/lib/pages/c_page/reservation/view.dart index e6c8da7..80a3330 100644 --- a/ln_jq_app/lib/pages/c_page/reservation/view.dart +++ b/ln_jq_app/lib/pages/c_page/reservation/view.dart @@ -2,7 +2,10 @@ import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; +import 'package:ln_jq_app/common/login_util.dart'; import 'package:ln_jq_app/common/model/station_model.dart'; +import 'package:ln_jq_app/common/styles/theme.dart'; +import 'package:ln_jq_app/pages/c_page/message/view.dart'; import 'package:ln_jq_app/pages/qr_code/view.dart'; import 'package:ln_jq_app/storage_service.dart'; @@ -20,26 +23,45 @@ class ReservationPage extends GetView { id: 'reservation', builder: (_) { return Scaffold( - backgroundColor: Colors.grey[100], + backgroundColor: Color.fromRGBO(247, 249, 251, 1), body: GestureDetector( onTap: () { - FocusScope.of(context).unfocus(); + hideKeyboard(); }, - child: SingleChildScrollView( - padding: const EdgeInsets.all(12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - _buildUserInfoCard(), - const SizedBox(height: 5), - _buildCarInfoCard(), - const SizedBox(height: 5), - _buildReservationFormCard(context), - const SizedBox(height: 5), - _buildTipsCard(), - SizedBox(height: 95.h), - ], - ), + child: Stack( + children: [ + Positioned( + left: 0, + right: 0, + bottom: 10.h, + top: 0, + child: SingleChildScrollView( + child: Column( + children: [ + _buildUserInfoCard(), + Padding( + padding: EdgeInsets.only(left: 20.w, right: 20.w), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: 16.h), + _buildCarInfoCard(), + SizedBox(height: 5), + _buildReservationFormCard(context), + ], + ), + ), + ], + ), + ), + ), + Positioned( + left: 20.w, + right: 20.w, + bottom: 90.h, + child: _buildReservationItem(context), + ), + ], ), ), ); @@ -47,105 +69,125 @@ class ReservationPage extends GetView { ); } - Widget _buildTipsCard() { - return Card( - elevation: 2, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - _buildTipItem(Icons.info_outline, '请提前30分钟到达加氢站'), - const SizedBox(height: 10), - _buildTipItem(Icons.rule, '请确保车辆证件齐全'), - const SizedBox(height: 10), - _buildTipItem(Icons.headset_mic_outlined, '如有疑问请联系客服: 400-021-1773'), - ], - ), - ), - ); - } - - // 提示信息卡片中的列表项 - Widget _buildTipItem(IconData icon, String text) { - return Row( - children: [ - Icon(icon, color: Colors.blue, size: 20), - const SizedBox(width: 10), - Expanded( - child: Text(text, style: const TextStyle(fontSize: 12, color: Colors.black54)), - ), - ], - ); - } - /// 构建用户信息卡片 Widget _buildUserInfoCard() { return Card( - elevation: 2, // 轻微的阴影 + elevation: 1, + color: Colors.white, margin: EdgeInsets.zero, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20), + bottomRight: Radius.circular(20), + ), + ), child: Column( children: [ Padding( - padding: const EdgeInsets.all(16.0), + padding: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 16, top: 50), child: Row( children: [ - const CircleAvatar( - radius: 20, - backgroundColor: Colors.blue, - child: Icon(Icons.person, color: Colors.white, size: 34), + Stack( + children: [ + CircleAvatar( + radius: 25, + backgroundColor: Colors.white, + child: LoginUtil.getAssImg('ic_user_logo@2x'), + ), + Positioned( + right: 0, + bottom: 0, + child: SizedBox( + height: 16.h, + width: 16.w, + child: LoginUtil.getAssImg('ic_logo@2x'), + ), + ), + ], ), - const SizedBox(width: 12), + SizedBox(width: 8.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "${StorageService.to.name}", - style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + Row( + children: [ + Text( + "${StorageService.to.name}", + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 8.w), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: const Color.fromRGBO(236, 255, 234, 1), + border: Border.all(color: const Color(0xFFB7E19F)), + borderRadius: BorderRadius.circular(12), + ), + child: const Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.eco, size: 12, color: Color(0xFF52C41A)), + SizedBox(width: 4), + Text( + "绿色先锋", + style: TextStyle( + color: Color(0xFF52C41A), + fontSize: 10, + ), + ), + ], + ), + ), + ], ), - SizedBox(height: 6), + const SizedBox(height: 4), Text( - "${StorageService.to.phone}", - style: TextStyle(color: Colors.grey, fontSize: 11), + "羚牛ID:${StorageService.to.phone}", + style: const TextStyle(color: Colors.grey, fontSize: 11), ), ], ), ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: Colors.blue[50], - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.blue, width: 0.5), + IconButton( + onPressed: () { + Get.to(() => const MessagePage()); + }, + style: IconButton.styleFrom( + backgroundColor: Colors.grey[100], + padding: const EdgeInsets.all(8), ), - child: const Row( - children: [ - Icon(Icons.shield_outlined, color: Colors.blue, size: 14), - SizedBox(width: 4), - Text( - '已认证', - style: TextStyle( - color: Colors.blue, - fontSize: 10, - fontWeight: FontWeight.bold, - ), - ), - ], + icon: Badge( + smallSize: 8, + backgroundColor: controller.isNotice + ? Colors.red + : Colors.transparent, + child: const Icon( + Icons.notifications_outlined, + color: Colors.black87, + size: 30, + ), ), ), ], ), ), - const Divider(height: 1, indent: 16, endIndent: 16), Padding( - padding: const EdgeInsets.symmetric(vertical: 11.0), + padding: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 20), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildStatItem(controller.fillingWeight, '累计加氢'), - _buildStatItem(controller.fillingTimes, '加氢次数'), + _buildModernStatItem('累计加氢量', '', controller.fillingWeight, ''), + const SizedBox(width: 8), + _buildModernStatItem('总加氢次数', '', controller.fillingTimes, ''), + const SizedBox(width: 8), + _buildModernStatItem('今日里程', '', "7kg", ''), ], ), ), @@ -154,6 +196,48 @@ class ReservationPage extends GetView { ); } + Widget _buildModernStatItem(String title, String subtitle, String value, String unit) { + return Expanded( + child: Container( + padding: const EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + Text(subtitle, style: const TextStyle(fontSize: 9, color: Colors.grey)), + const SizedBox(height: 8), + Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + children: [ + Text( + value, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + Text(unit, style: const TextStyle(fontSize: 10, color: Colors.black54)), + ], + ), + ], + ), + ), + ); + } + // 用户信息卡片中的小统计项 Widget _buildStatItem(String value, String label) { return Column( @@ -279,50 +363,6 @@ class ReservationPage extends GetView { ),*/ _buildStationSelector(), const SizedBox(height: 20), - Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: controller.submitReservation, - style: ElevatedButton.styleFrom( - minimumSize: const Size(double.infinity, 38), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - ), - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - ), - child: const Text( - '提交预约', - style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold), - ), - ), - ), - const SizedBox(width: 16), - Expanded( - child: OutlinedButton( - onPressed: () { - controller.getReservationList(showPopup: true, addStatus: ''); - }, - style: OutlinedButton.styleFrom( - minimumSize: const Size(double.infinity, 38), // 高度与另一个按钮保持一致 - side: const BorderSide(color: Colors.blue), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24), - ), - ), - child: const Text( - '查看预约', - style: TextStyle( - color: Colors.blue, - fontSize: 13, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ], - ), ], ), ), @@ -330,6 +370,52 @@ class ReservationPage extends GetView { ); } + Widget _buildReservationItem(BuildContext context) { + return Row( + children: [ + Expanded( + flex: 1, + child: OutlinedButton( + onPressed: () { + controller.getReservationList(showPopup: true, addStatus: ''); + }, + style: OutlinedButton.styleFrom( + minimumSize: Size(double.infinity, 40.h), // 高度与另一个按钮保持一致 + side: const BorderSide(color: Color.fromRGBO(226, 232, 240, 1)), + backgroundColor: Colors.white, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + ), + child: const Text( + '查看预约', + style: TextStyle( + color: Color.fromRGBO(119, 119, 119, 1), + fontSize: 13, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(width: 16), + Expanded( + flex: 2, + child: ElevatedButton( + onPressed: controller.submitReservation, + style: ElevatedButton.styleFrom( + minimumSize: Size(double.infinity, 40.h), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + backgroundColor: AppTheme.themeColor, + foregroundColor: Colors.white, + ), + child: const Text( + '提交预约', + style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold), + ), + ), + ), + ], + ); + } + // 表单中的可点击行 (用于日期和时间选择) Widget _buildPickerRow({ required String label,