导航栏
BIN
ln_jq_app/assets/images/ic_car@2x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ln_jq_app/assets/images/ic_car_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ln_jq_app/assets/images/ic_h2@2x.png
Normal file
|
After Width: | Height: | Size: 914 B |
BIN
ln_jq_app/assets/images/ic_h2_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
ln_jq_app/assets/images/ic_mall@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
ln_jq_app/assets/images/ic_mall_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
ln_jq_app/assets/images/ic_map@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ln_jq_app/assets/images/ic_map_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
ln_jq_app/assets/images/ic_user@2x.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
ln_jq_app/assets/images/ic_user_select@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:getx_scaffold/common/index.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:getx_scaffold/getx_scaffold.dart';
|
import 'package:getx_scaffold/getx_scaffold.dart';
|
||||||
|
import 'package:ln_jq_app/common/login_util.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/car_info/view.dart';
|
import 'package:ln_jq_app/pages/c_page/car_info/view.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/map/view.dart';
|
import 'package:ln_jq_app/pages/c_page/map/view.dart';
|
||||||
import 'package:ln_jq_app/pages/c_page/mine/view.dart';
|
import 'package:ln_jq_app/pages/c_page/mine/view.dart';
|
||||||
@@ -9,9 +10,10 @@ import 'package:ln_jq_app/pages/c_page/reservation/view.dart';
|
|||||||
import 'index.dart';
|
import 'index.dart';
|
||||||
|
|
||||||
class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
||||||
BaseWidgetsPage({super.key});
|
BaseWidgetsPage({super.key});
|
||||||
|
|
||||||
final PageController _pageController = PageController();
|
final PageController _pageController = PageController();
|
||||||
|
|
||||||
// 主视图
|
// 主视图
|
||||||
Widget _buildView() {
|
Widget _buildView() {
|
||||||
return PageView(
|
return PageView(
|
||||||
@@ -20,54 +22,68 @@ class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
|||||||
onPageChanged: (index) {
|
onPageChanged: (index) {
|
||||||
jumpTabAndPage(index);
|
jumpTabAndPage(index);
|
||||||
},
|
},
|
||||||
children: _buildPages(), // 页面的列表
|
children: _buildPages(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void jumpTabAndPage(int index) {
|
void jumpTabAndPage(int index) {
|
||||||
controller.pageIndex = index; // 更新页面索引
|
controller.pageIndex = index;
|
||||||
controller.updateUi(); // 更新 UI
|
controller.updateUi();
|
||||||
_pageController.jumpToPage(controller.pageIndex);
|
_pageController.jumpToPage(controller.pageIndex);
|
||||||
}
|
}
|
||||||
// 对应的页面
|
|
||||||
List<Widget> _buildPages() {
|
List<Widget> _buildPages() {
|
||||||
return [
|
return [ReservationPage(), MapPage(), CarInfoPage(), MinePage()];
|
||||||
ReservationPage(),
|
|
||||||
MapPage(),
|
|
||||||
CarInfoPage(),
|
|
||||||
MinePage(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//导航栏
|
// 自定义导航栏 (悬浮胶囊样式)
|
||||||
Widget _buildNavigationBar() {
|
Widget _buildNavigationBar() {
|
||||||
return NavigationX(
|
return SafeArea(
|
||||||
currentIndex: controller.pageIndex, // 当前选中的tab索引
|
child: Container(
|
||||||
onTap: (index) {
|
height: 50.h,
|
||||||
jumpTabAndPage(index);
|
margin: const EdgeInsets.fromLTRB(24, 0, 24, 10), // 悬浮边距
|
||||||
}, // 切换tab事件
|
decoration: BoxDecoration(
|
||||||
items: [
|
color: Color.fromRGBO(240, 244, 247, 1), // 浅灰色背景
|
||||||
NavigationItemModel(
|
borderRadius: BorderRadius.circular(30),
|
||||||
label: '加氢预约',
|
boxShadow: [
|
||||||
icon: AntdIcon.orderedlist,
|
BoxShadow(
|
||||||
selectedIcon: AntdIcon.calendar_fill,
|
color: Colors.black.withOpacity(0.05),
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
NavigationItemModel(
|
child: Row(
|
||||||
label: '地图',
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
icon: AntdIcon.location,
|
children: [
|
||||||
selectedIcon: AntdIcon.location_fill,
|
_buildNavItem(0, "ic_h2_select@2x", "ic_h2@2x"),
|
||||||
|
_buildNavItem(1, "ic_map_select@2x", "ic_map@2x"),
|
||||||
|
_buildNavItem(2, "ic_car_select@2x", "ic_car@2x"),
|
||||||
|
_buildNavItem(3, "ic_user_select@2x", "ic_user@2x"),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
NavigationItemModel(
|
),
|
||||||
label: '车辆信息',
|
);
|
||||||
icon: AntdIcon.car,
|
}
|
||||||
selectedIcon: AntdIcon.car_fill,
|
|
||||||
|
// 构建单个导航项
|
||||||
|
Widget _buildNavItem(int index, String icon, String selectedIcon) {
|
||||||
|
bool isSelected = controller.pageIndex == index;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => jumpTabAndPage(index),
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isSelected ? const Color(0xFF006633) : Colors.transparent, // 选中时的深绿色背景
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
NavigationItemModel(
|
child: SizedBox(
|
||||||
label: '我的',
|
height: 24,
|
||||||
icon: AntdIcon.user,
|
width: 24,
|
||||||
selectedIcon: AntdIcon.user,
|
child: LoginUtil.getAssImg(isSelected ? selectedIcon : icon),),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,10 +94,10 @@ class BaseWidgetsPage extends GetView<BaseWidgetsController> {
|
|||||||
id: 'baseWidgets',
|
id: 'baseWidgets',
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
extendBody: false,
|
extendBody: true, // 重要:让 body 延伸到导航栏后面
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
bottomNavigationBar: _buildNavigationBar(),
|
bottomNavigationBar: _buildNavigationBar(),
|
||||||
body: SafeArea(child: _buildView()),
|
body: _buildView(), // 移除 SafeArea 以获得更好的全屏沉浸感
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class CarInfoPage extends GetView<CarInfoController> {
|
|||||||
children: [
|
children: [
|
||||||
_buildUserInfoCard(),
|
_buildUserInfoCard(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 20.w,right: 20.w),
|
padding: EdgeInsets.only(left: 20.w, right: 20.w),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
@@ -35,6 +35,7 @@ class CarInfoPage extends GetView<CarInfoController> {
|
|||||||
_buildCertificatesCard(context),
|
_buildCertificatesCard(context),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildSafetyReminderCard(),
|
_buildSafetyReminderCard(),
|
||||||
|
SizedBox(height: 95.h),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -60,7 +61,7 @@ class CarInfoPage extends GetView<CarInfoController> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 16, top: 40),
|
padding: EdgeInsets.only(left: 20.w, right: 20.w, bottom: 16, top: 50),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Stack(
|
Stack(
|
||||||
@@ -344,7 +345,7 @@ class CarInfoPage extends GetView<CarInfoController> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 9),
|
const SizedBox(height: 9),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 343.h, // 给定一个高度,或者使用别的方式布局
|
height: 333.h, // 给定一个高度,或者使用别的方式布局
|
||||||
child: TabBarView(
|
child: TabBarView(
|
||||||
children: [
|
children: [
|
||||||
_buildCertificateContent('行驶证', controller.drivingAttachments),
|
_buildCertificateContent('行驶证', controller.drivingAttachments),
|
||||||
@@ -362,66 +363,55 @@ class CarInfoPage extends GetView<CarInfoController> {
|
|||||||
/// 构建单个证件的展示内容
|
/// 构建单个证件的展示内容
|
||||||
Widget _buildCertificateContent(String title, RxList<String> attachments) {
|
Widget _buildCertificateContent(String title, RxList<String> attachments) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
if (attachments.isEmpty) {
|
|
||||||
return const Center(child: Text('暂无相关证件信息'));
|
|
||||||
}
|
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: attachments.isEmpty
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
? const Center(child: Text('暂无相关证件信息'))
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
Row(
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
children: [
|
||||||
children: [
|
Row(
|
||||||
_buildCertDetailItem('所有人', '上海羚牛氢运物联网科技有限公司', isFull: true),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
_buildCertDetailItem('车辆识别代号', controller.vin),
|
children: [
|
||||||
],
|
_buildCertDetailItem('所有人', '上海羚牛氢运物联网科技有限公司', isFull: true),
|
||||||
),
|
_buildCertDetailItem('车辆识别代号', controller.vin),
|
||||||
const SizedBox(height: 16),
|
],
|
||||||
Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
const SizedBox(height: 16),
|
||||||
children: [
|
Row(
|
||||||
_buildCertDetailItem(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
'有效期至',
|
children: [
|
||||||
'2028-08-14',
|
_buildCertDetailItem(
|
||||||
valueColor: const Color(0xFF52C41A),
|
'有效期至',
|
||||||
),
|
'2028-08-14',
|
||||||
_buildCertDetailItem('使用性质', '货运'),
|
valueColor: const Color(0xFF52C41A),
|
||||||
],
|
),
|
||||||
),
|
_buildCertDetailItem('使用性质', '货运'),
|
||||||
const SizedBox(height: 20),
|
],
|
||||||
// 附件预览部分
|
),
|
||||||
Expanded(
|
const SizedBox(height: 16),
|
||||||
child: ListView.builder(
|
// 附件预览部分
|
||||||
scrollDirection: Axis.vertical,
|
GestureDetector(
|
||||||
itemCount: attachments.length,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final url = attachments[index];
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
controller.openAttachment(url);
|
controller.navigateToCertificateViewer(title, attachments);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 184.h,
|
height: 184.h,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
border: Border.all(color: Color.fromRGBO(226, 232, 240, 1)),
|
border: Border.all(color: Color.fromRGBO(226, 232, 240, 1)),
|
||||||
color: Color.fromRGBO(248, 250, 252, 1)
|
color: Color.fromRGBO(248, 250, 252, 1),
|
||||||
),
|
),
|
||||||
child: Center(child: _buildAttachmentPreview(url)),
|
child: Center(child: _buildAttachmentPreview(attachments[0])),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class MinePage extends GetView<MineController> {
|
|||||||
_buildSafetyReminderCard(),
|
_buildSafetyReminderCard(),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
_buildLogoutButton(),
|
_buildLogoutButton(),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 95.h),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
_buildReservationFormCard(context),
|
_buildReservationFormCard(context),
|
||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
_buildTipsCard(),
|
_buildTipsCard(),
|
||||||
|
SizedBox(height: 95.h),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -474,7 +475,7 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => DropdownButtonHideUnderline(
|
() => DropdownButtonHideUnderline(
|
||||||
child: DropdownButton2<String>(
|
child: DropdownButton2<String>(
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
hint: const Text(
|
hint: const Text(
|
||||||
@@ -485,15 +486,15 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
items: controller.stationOptions
|
items: controller.stationOptions
|
||||||
.map(
|
.map(
|
||||||
(station) => DropdownMenuItem<String>(
|
(station) => DropdownMenuItem<String>(
|
||||||
value: station.hydrogenId, // value 是站点的唯一ID
|
value: station.hydrogenId, // value 是站点的唯一ID
|
||||||
enabled: station.isSelect == 1,
|
enabled: station.isSelect == 1,
|
||||||
child: _buildDropdownItem(station), // child 是自定义的 Widget
|
child: _buildDropdownItem(station), // child 是自定义的 Widget
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
value:
|
value:
|
||||||
// 当前的站点 处理默认
|
// 当前的站点 处理默认
|
||||||
controller.selectedStationId.value ??
|
controller.selectedStationId.value ??
|
||||||
(controller.stationOptions.isNotEmpty
|
(controller.stationOptions.isNotEmpty
|
||||||
? controller.stationOptions.first.hydrogenId
|
? controller.stationOptions.first.hydrogenId
|
||||||
: null),
|
: null),
|
||||||
@@ -506,15 +507,15 @@ class ReservationPage extends GetView<C_ReservationController> {
|
|||||||
customButton: Obx(() {
|
customButton: Obx(() {
|
||||||
// 优先从已选中的 ID 查找
|
// 优先从已选中的 ID 查找
|
||||||
var selectedStation = controller.stationOptions.firstWhereOrNull(
|
var selectedStation = controller.stationOptions.firstWhereOrNull(
|
||||||
(s) => s.hydrogenId == controller.selectedStationId.value,
|
(s) => s.hydrogenId == controller.selectedStationId.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 如果找不到已选中的(比如 ID 为空或列表里没有),并且列表不为空,则取第一个作为默认
|
// 如果找不到已选中的(比如 ID 为空或列表里没有),并且列表不为空,则取第一个作为默认
|
||||||
final stationToShow =
|
final stationToShow =
|
||||||
selectedStation ??
|
selectedStation ??
|
||||||
(controller.stationOptions.isNotEmpty
|
(controller.stationOptions.isNotEmpty
|
||||||
? controller.stationOptions.first
|
? controller.stationOptions.first
|
||||||
: null);
|
: null);
|
||||||
|
|
||||||
// 如果有要显示的站点,就构建按钮
|
// 如果有要显示的站点,就构建按钮
|
||||||
if (stationToShow != null) {
|
if (stationToShow != null) {
|
||||||
|
|||||||