Merge branch 'main' into dev

# Conflicts:
#	ln_jq_app/android/app/src/main/AndroidManifest.xml
#	ln_jq_app/pubspec.lock
同步线上
This commit is contained in:
2026-03-31 15:07:16 +08:00
9 changed files with 250 additions and 84 deletions

View File

@@ -1,9 +1,13 @@
import 'dart:io';
import 'package:flutter/gestures.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/pages/b_page/reservation/controller.dart';
import 'package:ln_jq_app/pages/c_page/message/view.dart';
import 'package:ln_jq_app/pages/common/webview/view.dart';
class ReservationPage extends GetView<ReservationController> {
const ReservationPage({super.key});
@@ -36,6 +40,30 @@ class ReservationPage extends GetView<ReservationController> {
_buildSystemTips(),
SizedBox(height: 24),
_buildLogoutButton(),
SizedBox(height: 15.h),
Text.rich(
TextSpan(
style: const TextStyle(color: Colors.grey, fontSize: 13),
children: [
TextSpan(
text: '《用户协议》',
style: TextStyle(color: Colors.blue, fontSize: 13),
recognizer: TapGestureRecognizer()
..onTap = () {
openPage("用户协议", "https://lnh2e.com/user_agreement.html");
},
),
TextSpan(
text: '《隐私政策》',
style: TextStyle(color: Colors.blue, fontSize: 13),
recognizer: TapGestureRecognizer()
..onTap = () {
openPage("隐私政策", "https://lnh2e.com/privacy_agreement.html");
},
),
],
),
),
SizedBox(height: 95.h),
],
),
@@ -48,6 +76,14 @@ class ReservationPage extends GetView<ReservationController> {
);
}
void openPage(String title, String url) {
if (Platform.isIOS) {
openWebPage(url);
return;
}
Get.to(() => const WebViewPage(), arguments: {'title': title, 'url': url});
}
/// 1. 顶部个人信息及统计栏
Widget _buildTopSection(BuildContext context) {
return Container(

View File

@@ -1,10 +1,15 @@
import 'dart:io';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:getx_scaffold/common/index.dart';
import 'package:getx_scaffold/common/widgets/index.dart';
import 'package:ln_jq_app/common/login_util.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/common/webview/view.dart';
import 'package:ln_jq_app/storage_service.dart';
import 'controller.dart';
@@ -38,6 +43,30 @@ class MinePage extends GetView<MineController> {
_buildSafetyReminderCard(),
SizedBox(height: 24.h),
_buildLogoutButton(),
SizedBox(height: 15.h),
Text.rich(
TextSpan(
style: const TextStyle(color: Colors.grey, fontSize: 13),
children: [
TextSpan(
text: '《用户协议》',
style: TextStyle(color: Colors.blue, fontSize: 13),
recognizer: TapGestureRecognizer()
..onTap = () {
openPage("用户协议", "https://lnh2e.com/user_agreement.html");
},
),
TextSpan(
text: '《隐私政策》',
style: TextStyle(color: Colors.blue, fontSize: 13),
recognizer: TapGestureRecognizer()
..onTap = () {
openPage("隐私政策", "https://lnh2e.com/privacy_agreement.html");
},
),
],
),
),
SizedBox(height: 95.h),
],
),
@@ -51,6 +80,15 @@ class MinePage extends GetView<MineController> {
);
}
void openPage(String title, String url) {
if (Platform.isIOS) {
openWebPage(url);
return;
}
Get.to(() => const WebViewPage(), arguments: {'title': title, 'url': url});
}
/// 构建顶部用户信息卡片
Widget _buildUserInfoCard() {
return Card(

View File

@@ -29,14 +29,6 @@ class HomeController extends GetxController with BaseControllerMixin {
@override
void onInit() {
super.onInit();
// 检查是否同意过隐私政策,只有同意后才初始化推送
if (StorageService.to.isPrivacyAgreed) {
requestPermission();
initAliyunPush();
addPushCallback();
}
FlutterNativeSplash.remove();
log('page-init');
@@ -159,6 +151,13 @@ class HomeController extends GetxController with BaseControllerMixin {
// 根据登录状态和登录渠道返回不同的首页
Widget getHomePage() {
if (StorageService.to.isLoggedIn) {
// 检查是否同意过隐私政策,只有同意后才初始化推送
if (StorageService.to.isPrivacyAgreed) {
requestPermission();
initAliyunPush();
addPushCallback();
}
if (StorageService.to.loginChannel == LoginChannel.station) {
return B_BaseWidgetsPage();
} else if (StorageService.to.loginChannel == LoginChannel.driver) {

View File

@@ -140,9 +140,29 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
children: [
const SizedBox(height: 30),
// 根据 Tab 显示不同的输入框
_tabController.index == 0
!_isAgreed
? GestureDetector(
onTap: () => _handleLogin(controller),
behavior: HitTestBehavior.opaque,
child: Container(
width: double.infinity,
height: 55.h,
padding: const EdgeInsets.symmetric(
horizontal: 24,
),
alignment: Alignment.centerLeft,
child: Text(
"请先阅读并同意用户协议和隐私政策",
style: TextStyle(
color: Colors.grey,
fontSize: 16,
),
),
),
)
: (_tabController.index == 0
? _buildDriverInputFields(controller)
: _buildStationInputFields(controller),
: _buildStationInputFields(controller)),
const SizedBox(height: 30),
// 统一登录按钮
@@ -150,7 +170,8 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
const SizedBox(height: 10),
buildAgreement(),
const SizedBox(height: 40),
const SizedBox(height: 80),
_buildFooterSlogan(),
],
),
),
@@ -159,7 +180,6 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
),
),
),
Positioned(left: 0, right: 0, bottom: 33.h, child: _buildFooterSlogan()),
if (AppTheme.is_show_host)
Positioned(
top: 40.h,
@@ -475,7 +495,6 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
}
}
_processLoginResponse(responseData, "station", account);
} catch (e) {
dismissLoading();
@@ -539,7 +558,6 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
Logger.d("暂时不处理 查询车辆信息失败的情况");
}
dismissLoading();
Get.offAll(() => BaseWidgetsPage());
} else {
@@ -596,9 +614,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
}
// 添加推送回调
_aliyunPush.addMessageReceiver(
onNotificationOpened: _onNotificationOpened,
);
_aliyunPush.addMessageReceiver(onNotificationOpened: _onNotificationOpened);
isPushInitialized = true;
Logger.d('推送服务初始化成功');

View File

@@ -1,16 +1,103 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:get/get.dart';
import 'package:getx_scaffold/common/components/index.dart';
import 'package:getx_scaffold/common/widgets/rich_text_x.dart';
import 'package:ln_jq_app/pages/home/view.dart';
import 'package:ln_jq_app/pages/login/view.dart';
import 'package:ln_jq_app/storage_service.dart';
import '../common/webview/view.dart';
class WelcomeController extends GetxController {
@override
void onReady() {
super.onReady();
// 移除原生闪屏页(如果有的话)
FlutterNativeSplash.remove();
_startTimer();
if (Platform.isAndroid) {
if (StorageService.to.isPrivacyAgreed) {
_startTimer();
} else {
showPrivacyDialog();
}
} else if (Platform.isIOS) {
_startTimer();
}
}
void showPrivacyDialog() {
DialogX.to.showConfirmDialog(
title: "个人信息保护提示",
content: _buildDialogContent(),
confirmText: '同意',
cancelText: '不同意',
onConfirm: () async {
await StorageService.to.savePrivacyAgreed(true);
Get.offAll(() => const HomePage());
},
onCancel: () {
DialogX.to.showConfirmDialog(
title: "温馨提示",
content: RichTextX(
children: [
TextSpanItem('如果您不同意'),
TextSpanItem(
'《隐私协议》',
onTap: () => openPage("隐私政策", "https://lnh2e.com/privacy_agreement.html"),
),
TextSpanItem(''),
TextSpanItem(
'《用户政策》',
onTap: () => openPage("用户协议", "https://lnh2e.com/user_agreement.html"),
),
TextSpanItem(
',很遗憾我们将无法为您提供服务。您需要同意以上协议后,才能使用本应用。\n\n我们将严格按照相关法律法规要求,坚决保护您的个人隐私和信息安全。',
),
TextSpanItem('\n点击“同意”按钮,表示您已知情并同意以上协议。'),
],
),
confirmText: '同意并继续',
cancelText: '不同意',
onConfirm: () async {
await StorageService.to.savePrivacyAgreed(true);
Get.offAll(() => const HomePage());
},
onCancel: () {
SystemNavigator.pop();
},
);
},
);
}
Widget _buildDialogContent() {
return RichTextX(
children: [
TextSpanItem('欢迎使用小羚羚!\n我们将通过'),
TextSpanItem(
'《隐私协议》',
onTap: () => openPage("隐私政策", "https://lnh2e.com/privacy_agreement.html"),
),
TextSpanItem(''),
TextSpanItem(
'《用户政策》',
onTap: () => openPage("用户协议", "https://lnh2e.com/user_agreement.html"),
),
TextSpanItem(
',帮助您了解我们为您提供的服务、我们如何处理个人信息以及您享有的权利。我们会严格按照相关法律法规要求,采取各种安全措施来保护您的个人信息。',
),
TextSpanItem('\n点击“同意”按钮,表示您已知情并同意以上协议。'),
],
);
}
void openPage(String title, String url) {
Get.to(() => const WebViewPage(), arguments: {'title': title, 'url': url});
}
void _startTimer() {