27 Commits

Author SHA1 Message Date
9b6f93ca95 隐私调整 2026-03-17 13:31:58 +08:00
eb41ecaec4 更新插件 2026-03-16 16:00:38 +08:00
384de27f2c Merge branch 'dev' 2026-03-13 17:18:43 +08:00
84b174c4a5 协议通知后注册推送 2026-03-13 17:09:30 +08:00
02e1946319 文字边界 2026-03-05 11:20:14 +08:00
d5083c1939 Merge branch 'dev'
v1.2.4
2026-03-04 14:58:45 +08:00
fe44848529 号码 2026-03-04 14:50:21 +08:00
572c416827 枪号回填,v1.2.4 2026-03-04 13:38:26 +08:00
8df16f0787 pdf查看 2026-03-03 17:51:06 +08:00
ce6bd3edd2 bugfix 2026-03-03 13:09:10 +08:00
6997b4ac9e 调整权限和库 2026-03-02 11:28:44 +08:00
a26d2478f3 样式 2026-02-28 17:31:28 +08:00
0dded3b928 ocr识别,历史新增类型 2026-02-28 17:15:42 +08:00
b7caf58adf 加氢站-查看证件 2026-02-28 15:00:56 +08:00
0df1902df2 无预约 2026-02-28 11:59:07 +08:00
a8314d8a7a 关闭弹窗 2026-02-27 10:55:55 +08:00
39cae906e9 加氢站-预约 2026-02-27 10:54:55 +08:00
14fd6c75d0 fix 2026-02-25 15:35:33 +08:00
1724852a39 司机-可上传证件 2026-02-25 15:35:02 +08:00
a05d4ebb9b 调整 2026-02-12 18:01:56 +08:00
600cea4379 进度条 2026-02-12 17:34:06 +08:00
3dfc1dfc2c 样式调整 2026-02-12 16:54:50 +08:00
35bd3a78a5 Merge branch 'dev' 2026-01-30 17:33:15 +08:00
032e60d362 Merge branch 'dev'
ui调整
# Conflicts:
#	ln_jq_app/lib/pages/login/view.dart
2026-01-30 17:08:49 +08:00
45f5035d1b 更换logo 2026-01-19 10:13:37 +08:00
f792915429 bugfix 2026-01-16 17:47:53 +08:00
edbacc502b 线上域名修改 2026-01-16 17:25:52 +08:00
53 changed files with 1685 additions and 493 deletions

View File

@@ -37,8 +37,8 @@ android {
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode = 6 versionCode = 7
versionName = "1.2.3" versionName = "1.2.4"
} }
signingConfigs { signingConfigs {

View File

@@ -1,47 +1,50 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" <uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" <uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" <uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" /> android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!--定位权限--> <!--定位权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application <application
android:label="小羚羚" android:requestLegacyExternalStorage="true"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/logo"> android:icon="@mipmap/logo"
android:label="小羚羚">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true" android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:taskAffinity="" android:taskAffinity=""
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. --> to determine the Window background behind the Flutter UI. -->
<meta-data <meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme" />
/>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
@@ -51,32 +54,13 @@
android:value="2" /> android:value="2" />
<!-- 请填写你自己的- appKey --> <!-- 请填写你自己的- appKey -->
<meta-data android:name="com.alibaba.app.appkey" android:value="335642645"/> <meta-data
android:name="com.alibaba.app.appkey"
android:value="335642645" />
<!-- 请填写你自己的appSecret --> <!-- 请填写你自己的appSecret -->
<meta-data android:name="com.alibaba.app.appsecret" android:value="39628204345a4240b5b645b68a5896c7"/> <meta-data
<!-- 华为通道的参数appid --> android:name="com.alibaba.app.appsecret"
<meta-data android:name="com.huawei.hms.client.appid" android:value="" /> android:value="39628204345a4240b5b645b68a5896c7" />
<!-- vivo通道的参数api_key为appkey -->
<meta-data android:name="com.vivo.push.api_key" android:value="" />
<meta-data android:name="com.vivo.push.app_id" android:value="" />
<!-- honor通道的参数-->
<meta-data android:name="com.hihonor.push.app_id" android:value="" />
<!-- oppo -->
<meta-data android:name="com.oppo.push.key" android:value="" />
<meta-data android:name="com.oppo.push.secret" android:value="" />
<!-- 小米-->
<meta-data android:name="com.xiaomi.push.id" android:value="id=2222222222222222222" />
<meta-data android:name="com.xiaomi.push.key" android:value="id=5555555555555" />
<!-- 魅族-->
<meta-data android:name="com.meizu.push.id" android:value="" />
<meta-data android:name="com.meizu.push.key" android:value="" />
<!-- 接收推送消息 --> <!-- 接收推送消息 -->
<receiver <receiver
@@ -99,6 +83,7 @@
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
@@ -117,8 +102,8 @@
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries> <queries>
<intent> <intent>
<action android:name="android.intent.action.PROCESS_TEXT"/> <action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain"/> <data android:mimeType="text/plain" />
</intent> </intent>
</queries> </queries>
</manifest> </manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -21,9 +21,7 @@
.amap-callamap, .amap-callamap,
.amap-lib-driving-callBtn, .amap-lib-driving-callBtn,
.amap-copyright, .amap-copyright,
.amap-logo { .amap-logo{bottom: 60px}
display: none !important;
}
/* 去除高德默认的 label 边框 and 背景 */ /* 去除高德默认的 label 边框 and 背景 */
.amap-marker-label { .amap-marker-label {
@@ -195,10 +193,10 @@
<div id="search-box"> <div id="search-box">
<div class="input-row"> <div class="input-row">
<input id="startInput" placeholder="起点: 请输入当前地点" /> <input id="startInput" placeholder="起点: 请输入当前地点" onfocus="this.select()" />
</div> </div>
<div class="input-row"> <div class="input-row">
<input id="endInput" placeholder="终点: 请输入目的地" /> <input id="endInput" placeholder="终点: 请输入目的地" onfocus="this.select()" />
<button onclick="startRouteSearch()">路径规划</button> <button onclick="startRouteSearch()">路径规划</button>
</div> </div>
</div> </div>
@@ -244,6 +242,11 @@
} }
}); });
// 点击地图空白处重置状态
map.on('click', function() {
resetSearchState();
});
// 添加基础控件 // 添加基础控件
map.addControl(new AMap.Scale()); map.addControl(new AMap.Scale());
map.addControl(new AMap.ToolBar({ map.addControl(new AMap.ToolBar({
@@ -285,6 +288,19 @@
}); });
} }
/**
* 重置搜索状态,隐藏面板和路线
*/
function resetSearchState() {
if (document.body.classList.contains('panel-active')) {
console.log("JS->: 重置地图状态");
document.body.classList.remove('panel-active');
var panel = document.getElementById('panel');
panel.style.display = 'none';
if (driving) driving.clear();
}
}
/** /**
* 核心功能 1: 接收 Flutter 传来的定位数据 * 核心功能 1: 接收 Flutter 传来的定位数据
* Flutter 端调用: webViewController.evaluateJavascript("updateMyLocation(...)") * Flutter 端调用: webViewController.evaluateJavascript("updateMyLocation(...)")
@@ -481,19 +497,25 @@
offset: new AMap.Pixel(-16, -32), offset: new AMap.Pixel(-16, -32),
title: station.name, title: station.name,
label: { label: {
content: '<div class="custom-bubble">' + station.name + '</div>', content: '<div class="custom-bubble">' + station.name +
'</div>',
direction: 'top' direction: 'top'
} }
}); });
// 3. 绑定点击事件:选中即为目的地,并开始规划 // 3. 绑定点击事件:选中即为目的地,并开始规划
sMarker.on('click', function() { sMarker.on('click', function () {
document.getElementById('endInput').value = station.address || station.name; var stationName = station.name || "目的地";
// 更新当前的 destMarker (如果需要) document.getElementById('endInput').value = station.address ||
if (destMarker) destMarker.setMap(null); stationName;
// 更新当前的 destMarker
if (destMarker && destMarker !== sMarker) destMarker.setMap(null);
destMarker = sMarker; destMarker = sMarker;
startRouteSearch(); // 直接传入坐标对象,避免关键字搜索失败
var loc = new AMap.LngLat(station.longitude, station.latitude);
startRouteSearch(loc);
}); });
stationMarkers.push(sMarker); stationMarkers.push(sMarker);
@@ -554,11 +576,12 @@
} }
} }
/** /**
* 路径规划 * 路径规划
* @param {AMap.LngLat} [destLoc] 可选的终点坐标
*/ */
function startRouteSearch() { function startRouteSearch(destLoc) {
// 获取输入框的文字
var startKw = document.getElementById('startInput').value; var startKw = document.getElementById('startInput').value;
var endKw = document.getElementById('endInput').value; var endKw = document.getElementById('endInput').value;
@@ -566,28 +589,21 @@
alert("请输入起点"); alert("请输入起点");
return; return;
} }
if (!endKw) { if (!endKw) {
alert("请输入终点"); alert("请输入终点");
return; return;
} }
// 清除旧路线
if (driving) driving.clear(); if (driving) driving.clear();
// 收起键盘
document.getElementById('startInput').blur(); document.getElementById('startInput').blur();
document.getElementById('endInput').blur(); document.getElementById('endInput').blur();
// --- 构造路径规划的点 ---
var points = []; var points = [];
// 1. 处理起点逻辑 // 1. 起点逻辑
if (!startKw || startKw === '我的位置' || startKw.includes('当前位置')) { if (!startKw || startKw === '我的位置' || startKw.includes('当前位置')) {
if (!currentLng || !currentLat) { if (!currentLng || !currentLat) {
if (window.flutter_inappwebview) { if (window.flutter_inappwebview) window.flutter_inappwebview.callHandler('requestLocation');
window.flutter_inappwebview.callHandler('requestLocation');
}
alert("正在获取定位,请稍后..."); alert("正在获取定位,请稍后...");
return; return;
} }
@@ -601,10 +617,17 @@
}); });
} }
// 2. 处理终点逻辑 // 2. 终点逻辑:如果有传入坐标,则直接使用坐标导航,成功率最高
points.push({ if (destLoc) {
keyword: endKw points.push({
}); keyword: endKw,
location: destLoc // 关键:使用精确坐标
});
} else {
points.push({
keyword: endKw
});
}
// 3. 发起搜索 // 3. 发起搜索
driving.search(points, function (status, result) { driving.search(points, function (status, result) {
@@ -613,10 +636,12 @@
var panel = document.getElementById('panel'); var panel = document.getElementById('panel');
panel.style.display = 'block'; panel.style.display = 'block';
document.body.classList.add('panel-active'); document.body.classList.add('panel-active');
} else {
console.log('JS: 规划失败', result);
alert("规划失败,请检查起终点名称");
} }
// else {
// console.error('JS: 规划失败', result);
// // 如果坐标规划都失败了,通常是由于起终点距离过近或政策限制(如货车禁行)
// alert("路径规划未成功,请尝试微调起终点");
// }
}); });
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 B

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -41,6 +41,8 @@ PODS:
- FlutterMacOS - FlutterMacOS
- permission_handler_apple (9.3.0): - permission_handler_apple (9.3.0):
- Flutter - Flutter
- saver_gallery (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@@ -62,6 +64,7 @@ DEPENDENCIES:
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- saver_gallery (from `.symlinks/plugins/saver_gallery/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@@ -103,6 +106,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple: permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios" :path: ".symlinks/plugins/permission_handler_apple/ios"
saver_gallery:
:path: ".symlinks/plugins/saver_gallery/ios"
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin" :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios: url_launcher_ios:
@@ -127,6 +132,7 @@ SPEC CHECKSUMS:
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
saver_gallery: af2d0c762dafda254e0ad025ef0dabd6506cd490
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b

View File

@@ -13,7 +13,7 @@
"size" : "20x20" "size" : "20x20"
}, },
{ {
"filename" : "Icon-App-29x29@1x.png", "filename" : "Icon-App-29x29 1.png",
"idiom" : "iphone", "idiom" : "iphone",
"scale" : "1x", "scale" : "1x",
"size" : "29x29" "size" : "29x29"
@@ -31,25 +31,25 @@
"size" : "29x29" "size" : "29x29"
}, },
{ {
"filename" : "Icon-App-80x80.jpg", "filename" : "Icon-App-80x80.png",
"idiom" : "iphone", "idiom" : "iphone",
"scale" : "2x", "scale" : "2x",
"size" : "40x40" "size" : "40x40"
}, },
{ {
"filename" : "Icon-App-120x120.jpg", "filename" : "Icon-App-120x120.png",
"idiom" : "iphone", "idiom" : "iphone",
"scale" : "3x", "scale" : "3x",
"size" : "40x40" "size" : "40x40"
}, },
{ {
"filename" : "Icon-App-120x120 1.jpg", "filename" : "Icon-App-120x120 1.png",
"idiom" : "iphone", "idiom" : "iphone",
"scale" : "2x", "scale" : "2x",
"size" : "60x60" "size" : "60x60"
}, },
{ {
"filename" : "Icon-App-180.jpg", "filename" : "Icon-App-180.png",
"idiom" : "iphone", "idiom" : "iphone",
"scale" : "3x", "scale" : "3x",
"size" : "60x60" "size" : "60x60"
@@ -61,19 +61,19 @@
"size" : "20x20" "size" : "20x20"
}, },
{ {
"filename" : "Icon-App-20x20@2x.png", "filename" : "Icon-App-20x20@2x 1.png",
"idiom" : "ipad", "idiom" : "ipad",
"scale" : "2x", "scale" : "2x",
"size" : "20x20" "size" : "20x20"
}, },
{ {
"filename" : "Icon-App-29x29@1x.png", "filename" : "Icon-App-29x29.png",
"idiom" : "ipad", "idiom" : "ipad",
"scale" : "1x", "scale" : "1x",
"size" : "29x29" "size" : "29x29"
}, },
{ {
"filename" : "Icon-App-29x29@2x.png", "filename" : "Icon-App-29x29@2x 1.png",
"idiom" : "ipad", "idiom" : "ipad",
"scale" : "2x", "scale" : "2x",
"size" : "29x29" "size" : "29x29"
@@ -91,7 +91,7 @@
"size" : "40x40" "size" : "40x40"
}, },
{ {
"filename" : "Icon-App-76x76@1x.png", "filename" : "Icon-App-76x76.png",
"idiom" : "ipad", "idiom" : "ipad",
"scale" : "1x", "scale" : "1x",
"size" : "76x76" "size" : "76x76"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -76,5 +76,11 @@
<string>en</string> <string>en</string>
</array> </array>
<key>UIFileSharingEnabled</key>
<true/>
<!-- 允许在“文件”App中直接打开文档 -->
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@@ -8,11 +8,11 @@ class AppTheme {
static const Color themeColor = Color(0xFF017137); static const Color themeColor = Color(0xFF017137);
//是否开放域名切换 //是否开放域名切换
static const bool is_show_host = true; static const bool is_show_host = false;
//http://192.168.110.222:8080/ //http://192.168.110.222:8080/
//http://192.168.110.44:8080/ //http://192.168.110.44:8080/
static String test_service_url = "https://beta-esg.api.lnh2e.com/"; static String test_service_url = "http://47.101.201.13:8443/api/";
static const String release_service_url = ""; static const String release_service_url = "";
//加氢站相关查询 //加氢站相关查询

View File

@@ -17,7 +17,7 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
WidgetsBinding widgetsBinding = await init( WidgetsBinding widgetsBinding = await init(
isDebug: true, isDebug: false,
logTag: '小羚羚', logTag: '小羚羚',
supportedLocales: [const Locale('zh', 'CN')], supportedLocales: [const Locale('zh', 'CN')],
); );
@@ -35,7 +35,7 @@ void main() async {
// 设计稿尺寸 单位dp // 设计稿尺寸 单位dp
designSize: const Size(390, 844), designSize: const Size(390, 844),
// Getx Log // Getx Log
enableLog: true, enableLog: false,
// 默认的跳转动画 // 默认的跳转动画
defaultTransition: Transition.rightToLeft, defaultTransition: Transition.rightToLeft,
// 主题模式 // 主题模式
@@ -71,6 +71,9 @@ void initHttpSet() {
HttpService.to.dio.interceptors.add(TokenInterceptor(tokenKey: 'asoco-token')); HttpService.to.dio.interceptors.add(TokenInterceptor(tokenKey: 'asoco-token'));
HttpService.to.setOnResponseHandler((response) async { HttpService.to.setOnResponseHandler((response) async {
try { try {
if (response.data == null) {
return null;
}
final baseModel = BaseModel.fromJson(response.data); final baseModel = BaseModel.fromJson(response.data);
if (baseModel.code == 0 || baseModel.code == 200) { if (baseModel.code == 0 || baseModel.code == 200) {
return null; return null;

View File

@@ -1,7 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:getx_scaffold/getx_scaffold.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/base_model.dart';
import 'package:ln_jq_app/pages/b_page/site/controller.dart'; // Reuse ReservationModel import 'package:ln_jq_app/pages/b_page/site/controller.dart'; // Reuse ReservationModel
@@ -25,12 +22,14 @@ class HistoryController extends GetxController with BaseControllerMixin {
final RxBool hasData = false.obs; final RxBool hasData = false.obs;
String get formattedStartDate => DateFormat('yyyy/MM/dd').format(startDate.value); String get formattedStartDate => DateFormat('yyyy/MM/dd').format(startDate.value);
String get formattedEndDate => DateFormat('yyyy/MM/dd').format(endDate.value); String get formattedEndDate => DateFormat('yyyy/MM/dd').format(endDate.value);
String stationName = ""; String stationName = "";
final Map<String, String> statusOptions = { final Map<String, String> statusOptions = {
'': '全部', '': '全部',
'100': '未预约加氢',
'0': '待加氢', '0': '待加氢',
'1': '已加氢', '1': '已加氢',
'2': '未加氢', '2': '未加氢',

View File

@@ -1,9 +1,13 @@
import 'dart:io';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.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/common/login_util.dart';
import 'package:ln_jq_app/pages/b_page/reservation/controller.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/c_page/message/view.dart';
import 'package:ln_jq_app/pages/common/webview/view.dart';
class ReservationPage extends GetView<ReservationController> { class ReservationPage extends GetView<ReservationController> {
const ReservationPage({super.key}); const ReservationPage({super.key});
@@ -36,6 +40,30 @@ class ReservationPage extends GetView<ReservationController> {
_buildSystemTips(), _buildSystemTips(),
SizedBox(height: 24), SizedBox(height: 24),
_buildLogoutButton(), _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), 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. 顶部个人信息及统计栏 /// 1. 顶部个人信息及统计栏
Widget _buildTopSection(BuildContext context) { Widget _buildTopSection(BuildContext context) {
return Container( return Container(
@@ -78,11 +114,15 @@ class ReservationPage extends GetView<ReservationController> {
children: [ children: [
Row( Row(
children: [ children: [
Text( Flexible(
controller.name, child: Text(
style: const TextStyle( controller.name,
fontSize: 18, style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 18,
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -98,12 +138,11 @@ class ReservationPage extends GetView<ReservationController> {
), ),
), ),
IconButton( IconButton(
onPressed: () async{ onPressed: () async {
var scanResult = await Get.to(() => const MessagePage()); var scanResult = await Get.to(() => const MessagePage());
if (scanResult == null) { if (scanResult == null) {
controller.msgNotice(); controller.msgNotice();
} }
}, },
style: IconButton.styleFrom( style: IconButton.styleFrom(
backgroundColor: Colors.grey[100], backgroundColor: Colors.grey[100],
@@ -111,9 +150,7 @@ class ReservationPage extends GetView<ReservationController> {
), ),
icon: Badge( icon: Badge(
smallSize: 8, smallSize: 8,
backgroundColor: controller.isNotice backgroundColor: controller.isNotice ? Colors.red : Colors.transparent,
? Colors.red
: Colors.transparent,
child: const Icon( child: const Icon(
Icons.notifications_outlined, Icons.notifications_outlined,
color: Colors.black87, color: Colors.black87,
@@ -232,12 +269,17 @@ class ReservationPage extends GetView<ReservationController> {
label, label,
style: TextStyle(color: Colors.grey, fontSize: 11.sp), style: TextStyle(color: Colors.grey, fontSize: 11.sp),
), ),
Text( Expanded(
value, child: Text(
style: TextStyle( value,
color: Color(0xFF333333), textAlign: TextAlign.right,
fontSize: 12.sp, overflow: TextOverflow.ellipsis,
fontWeight: FontWeight.bold, maxLines: 1,
style: TextStyle(
color: const Color(0xFF333333),
fontSize: 12.sp,
fontWeight: FontWeight.bold,
),
), ),
), ),
], ],
@@ -515,14 +557,15 @@ class ReservationPage extends GetView<ReservationController> {
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: kPrimaryColor, backgroundColor: kPrimaryColor,
minimumSize: const Size(double.infinity, 50), minimumSize: const Size(double.infinity, 50),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
), ),
child: const Text("发送广播", style: TextStyle(color: Colors.white)), child: const Text("发送广播", style: TextStyle(color: Colors.white)),
), ),
), ),
], ],
), ),
], ],
), ),
); );

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.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/common/login_util.dart';
import 'package:ln_jq_app/common/styles/theme.dart';
import 'package:ln_jq_app/pages/b_page/history/view.dart'; import 'package:ln_jq_app/pages/b_page/history/view.dart';
import 'package:ln_jq_app/pages/c_page/message/view.dart'; import 'package:ln_jq_app/pages/c_page/message/view.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
@@ -57,17 +56,33 @@ class SitePage extends GetView<SiteController> {
), ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
Get.to( // 手动录入
() => HistoryPage(), controller.confirmReservation("", isAdd: true);
arguments: {'stationName': controller.name},
);
}, },
child: Text( child: Container(
'历史记录', padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
style: TextStyle( decoration: BoxDecoration(
fontSize: 14.sp, color: Colors.white,
fontWeight: FontWeight.bold, borderRadius: BorderRadius.circular(20),
color: Color.fromRGBO(156, 163, 175, 1), border: Border.all(color: const Color(0xFFEEEEEE)),
),
child: Row(
children: [
const Icon(
Icons.add_circle_outline,
size: 18,
color: Color(0xFF666666),
),
const SizedBox(width: 4),
Text(
"无预约车辆加氢",
style: TextStyle(
color: Color.fromRGBO(51, 51, 51, 1),
fontSize: 13.sp,
fontWeight: FontWeight.w400
),
),
],
), ),
), ),
), ),
@@ -185,27 +200,7 @@ class SitePage extends GetView<SiteController> {
], ],
), ),
), ),
IconButton( _buildDropdownMenu(),
onPressed: () async {
var scanResult = await Get.to(() => const MessagePage());
if (scanResult == null) {
controller.msgNotice();
}
},
style: IconButton.styleFrom(
backgroundColor: Colors.grey[100],
padding: const EdgeInsets.all(8),
),
icon: Badge(
smallSize: 8,
backgroundColor: controller.isNotice ? Colors.red : Colors.transparent,
child: const Icon(
Icons.notifications_outlined,
color: Colors.black87,
size: 30,
),
),
),
], ],
), ),
const SizedBox(height: 25), const SizedBox(height: 25),
@@ -233,6 +228,40 @@ class SitePage extends GetView<SiteController> {
); );
} }
Widget _buildDropdownMenu() {
return PopupMenuButton<String>(
icon: Container(child: const Icon(Icons.grid_view_rounded, size: 24)),
onSelected: (value) async {
if (value == 'message') {
var scanResult = await Get.to(() => const MessagePage());
if (scanResult == null) {
controller.msgNotice();
}
} else if (value == 'history') {
Get.to(() => const HistoryPage(), arguments: {'stationName': controller.name});
}
},
itemBuilder: (context) => [
const PopupMenuItem(
value: 'message',
child: Row(
children: [
Icon(Icons.notifications_none, size: 20),
SizedBox(width: 8),
Text('消息中心'),
],
),
),
const PopupMenuItem(
value: 'history',
child: Row(
children: [Icon(Icons.history, size: 20), SizedBox(width: 8), Text('加氢历史')],
),
),
],
);
}
Widget _buildStatBox(String title, String enTitle, String value, String unit) { Widget _buildStatBox(String title, String enTitle, String value, String unit) {
return Expanded( return Expanded(
child: Container( child: Container(
@@ -466,7 +495,7 @@ class SitePage extends GetView<SiteController> {
/// 右侧具体数据卡片 /// 右侧具体数据卡片
Widget _buildInfoCard(ReservationModel item) { Widget _buildInfoCard(ReservationModel item) {
return Container( return Container(
padding: EdgeInsets.only(left: 16.w, top: 8.5, bottom: 8.5, right: 16.w), padding: EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
@@ -508,59 +537,82 @@ class SitePage extends GetView<SiteController> {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
// 联系信息 // 联系信息
Column( Text(
mainAxisAlignment: MainAxisAlignment.start, item.contactPerson.isEmpty || item.contactPhone.isEmpty
children: [ ? ""
Text( : "${item.contactPerson} | ${item.contactPhone}",
"${item.contactPerson} | ${item.contactPhone}", style: TextStyle(
style: TextStyle( color: Color(0xFF999999),
color: Color(0xFF999999), fontSize: 13.sp,
fontSize: 13.sp, fontWeight: FontWeight.w400,
fontWeight: FontWeight.w400, ),
),
),
],
), ),
SizedBox(height: 6.h),
//操作按钮(仅在待处理状态显示) Row(
if (item.status == ReservationStatus.pending) ...[ crossAxisAlignment: CrossAxisAlignment.end,
const SizedBox(height: 15), children: [
const Divider(height: 1, color: Color(0xFFF5F5F5)), if (item.hasDrivingAttachment)
const SizedBox(height: 12), controller.buildInfoTag('行驶证',item.drivingAttachments),
Row( if (item.hasHydrogenationAttachment) ...[
mainAxisAlignment: MainAxisAlignment.end, SizedBox(width: 8.w),
children: [ controller.buildInfoTag('加氢证',item.hydrogenationAttachments)
_buildSmallButton( ],
"拒绝", Spacer(),
isOutline: true, if (item.isEdit == "1") ...[
onTap: () { const SizedBox(height: 15),
controller.rejectReservation(item.id); const Divider(height: 1, color: Color(0xFFF5F5F5)),
}, const SizedBox(height: 12),
Align(
alignment: Alignment.centerRight,
child: _buildSmallButton(
"修改信息",
isOutline: true,
onTap: () {
controller.confirmReservation(item.id, isEdit: true);
},
),
), ),
const SizedBox(width: 12), ] else if (item.status == ReservationStatus.pending) ...[
_buildSmallButton( const SizedBox(height: 15),
"确认", const Divider(height: 1, color: Color(0xFFF5F5F5)),
isOutline: false, const SizedBox(height: 12),
onTap: () { Row(
controller.confirmReservation(item.id); mainAxisAlignment: MainAxisAlignment.end,
}, children: [
_buildSmallButton(
"拒绝",
isOutline: true,
onTap: () {
controller.rejectReservation(item.id);
},
),
const SizedBox(width: 12),
_buildSmallButton(
"确认",
isOutline: false,
onTap: () {
controller.confirmReservation(item.id);
},
),
],
), ),
], ],
), ],
], ),
], ],
), ),
); );
} }
/// 通用小按钮
Widget _buildSmallButton( Widget _buildSmallButton(
String text, { String text, {
required bool isOutline, required bool isOutline,
required VoidCallback onTap, required VoidCallback onTap,
}) { }) {
const kPrimaryGreen = Color(0xFF006D35); const kPrimaryGreen = Color(0xFF006D35);
const kDangerRed = Color(0xFFFF7D7D); var kDangerRed = text.contains('修改') ? Colors.red : Color.fromRGBO(255, 142, 98, 1);
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
@@ -634,139 +686,4 @@ class SitePage extends GetView<SiteController> {
), ),
); );
} }
/// 右侧操作按钮(拒绝/确认)
Widget _buildActionButtons(ReservationModel item) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
// 拒绝按钮(空心)
GestureDetector(
onTap: () => controller.rejectReservation(item.id),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: const Color(0xFFFF7D7D)),
),
child: const Text(
"拒绝",
style: TextStyle(
color: Color(0xFFFF7D7D),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 8),
// 确认按钮(实心深绿)
GestureDetector(
onTap: () => controller.confirmReservation(item.id),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFF006D35),
borderRadius: BorderRadius.circular(10),
),
child: const Text(
"确认",
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
),
],
);
}
/// 构建状态标签
Widget _buildStatusChip(ReservationStatus status) {
String text;
Color color;
switch (status) {
case ReservationStatus.pending:
text = '待加氢';
color = Colors.orange;
break;
case ReservationStatus.completed:
text = '已加氢';
color = Colors.greenAccent;
break;
case ReservationStatus.rejected:
text = '拒绝加氢';
color = Colors.red;
break;
case ReservationStatus.unadded:
text = '未加氢';
color = Colors.red;
break;
case ReservationStatus.cancel:
text = '已取消';
color = Colors.red;
break;
default:
text = '未知状态';
color = Colors.grey;
break;
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.circle, color: color, size: 8),
const SizedBox(width: 4),
Text(
text,
style: TextStyle(color: color, fontSize: 12, fontWeight: FontWeight.bold),
),
],
),
);
}
/// 构建信息详情行
Widget _buildDetailRow(
IconData icon,
String label,
String value, {
Color valueColor = Colors.black87,
}) {
return Row(
children: [
Icon(icon, color: Colors.grey, size: 20),
const SizedBox(width: 8),
Text('$label: ', style: const TextStyle(fontSize: 14, color: Colors.grey)),
Expanded(
child: Text(
value,
style: TextStyle(
fontSize: 14,
color: valueColor,
fontWeight: FontWeight.w500,
),
),
),
],
);
}
/// 底部构建带图标的提示信息行
Widget _buildInfoItem(IconData icon, String text) {
return Row(
children: [
Icon(icon, color: Colors.blue, size: 20),
const SizedBox(width: 8),
Text(text, style: const TextStyle(fontSize: 14, color: Colors.black54)),
],
);
}
} }

View File

@@ -41,7 +41,7 @@ class BaseWidgetsPage extends GetView<BaseWidgetsController> {
Widget _buildNavigationBar() { Widget _buildNavigationBar() {
return SafeArea( return SafeArea(
child: Container( child: Container(
height: 50.h, height: Get.height * 0.05,
margin: const EdgeInsets.fromLTRB(24, 0, 24, 10), // 悬浮边距 margin: const EdgeInsets.fromLTRB(24, 0, 24, 10), // 悬浮边距
decoration: BoxDecoration( decoration: BoxDecoration(
color: Color.fromRGBO(240, 244, 247, 1), // 浅灰色背景 color: Color.fromRGBO(240, 244, 247, 1), // 浅灰色背景

View File

@@ -1,5 +1,8 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:getx_scaffold/getx_scaffold.dart';
import 'package:getx_scaffold/getx_scaffold.dart' as dio;
import 'package:image_picker/image_picker.dart';
import 'package:image_picker_platform_interface/src/types/image_source.dart';
import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/common/model/base_model.dart';
import 'package:ln_jq_app/common/model/vehicle_info.dart'; import 'package:ln_jq_app/common/model/vehicle_info.dart';
import 'package:ln_jq_app/pages/c_page/car_info/attachment_viewer_page.dart'; import 'package:ln_jq_app/pages/c_page/car_info/attachment_viewer_page.dart';
@@ -89,6 +92,113 @@ class CarInfoController extends GetxController with BaseControllerMixin {
} }
} }
//上传证件照
void pickImage(String title, ImageSource source) async {
if (source == ImageSource.camera) {
takePhotoAndRecognize(title);
} else if (source == ImageSource.gallery) {
//相册选择逻辑
var status = await Permission.photos.request();
if (!status.isGranted) {
if (status.isPermanentlyDenied) openAppSettings();
showErrorToast("需要相册权限才能拍照上传");
return;
}
final XFile? image = await ImagePicker().pickImage(
source: ImageSource.gallery,
imageQuality: 80,
);
if (image != null) {
_uploadAndSaveCertificate(title, image.path);
}
}
}
void takePhotoAndRecognize(String title) async {
var status = await Permission.camera.request();
if (!status.isGranted) {
if (status.isPermanentlyDenied) openAppSettings();
showErrorToast("需要相机权限才能拍照上传");
return;
}
final XFile? photo = await ImagePicker().pickImage(
source: ImageSource.camera,
imageQuality: 80, // 压缩图片质量以加快上传
);
if (photo == null) return;
_uploadAndSaveCertificate(title, photo.path);
}
/// 提取共用的上传与关联证件逻辑
void _uploadAndSaveCertificate(String title, String filePath) async {
// 上传文件
String? imageUrl = await uploadFile(filePath);
if (imageUrl == null) return;
// 根据标题映射业务类型
String type = "";
switch (title) {
case "行驶证":
type = "9";
break;
case "营运证":
type = "10";
break;
case "加氢证":
type = "12";
break;
case "登记证":
type = "13";
break;
default:
return;
}
// 调用后台接口关联证件
var response = await HttpService.to.post(
"appointment/truck/uploadCertificatePic",
data: {
"plateNumber": plateNumber,
"imageUrl": imageUrl,
"type": type,
},
);
if (response != null) {
final result = BaseModel.fromJson(response.data);
if (result.code == 0) {
showSuccessToast("上传成功");
getUserBindCarInfo(); // 重新拉取数据更新UI
} else {
showErrorToast(result.error);
}
}
}
/// 上传图片
Future<String?> uploadFile(String filePath) async {
showLoading("正在上传...");
try {
dio.FormData formData = dio.FormData.fromMap({
'file': await dio.MultipartFile.fromFile(filePath, filename: 'ocr_identity.jpg'),
});
var response = await HttpService.to.post("appointment/ocr/upload", data: formData);
if (response != null) {
final result = BaseModel.fromJson(response.data);
if (result.code == 0) return result.data.toString();
showErrorToast(result.error);
}
} catch (e) {
showErrorToast("图片上传失败");
} finally {
dismissLoading();
}
return null;
}
void getUserBindCarInfo() async { void getUserBindCarInfo() async {
if (StorageService.to.hasVehicleInfo) { if (StorageService.to.hasVehicleInfo) {
VehicleInfo? bean = StorageService.to.vehicleInfo; VehicleInfo? bean = StorageService.to.vehicleInfo;
@@ -102,7 +212,7 @@ class CarInfoController extends GetxController with BaseControllerMixin {
// 获取证件信息 // 获取证件信息
final response = await HttpService.to.get( final response = await HttpService.to.get(
'appointment/vehicle/getPicInfoByVin?vin=$vin', 'appointment/vehicle/getPicInfoByVin?vin=$vin&plateNumber=$plateNumber',
); );
if (response != null && response.data != null) { if (response != null && response.data != null) {
@@ -134,10 +244,10 @@ class CarInfoController extends GetxController with BaseControllerMixin {
...registerAttachments, ...registerAttachments,
]; ];
color = data['color'].toString(); color = data['color'].toString();
hydrogenCapacity = data['hydrogenCapacity'].toString(); hydrogenCapacity = data['hydrogenCapacity'].toString();
rentFromCompany = data['rentFromCompany'].toString(); rentFromCompany = data['rentFromCompany'].toString();
address = data['address'].toString(); address = data['address'].toString();
loadAllPdfs(); loadAllPdfs();
} }

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart'; import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:getx_scaffold/getx_scaffold.dart';
import 'package:image_picker/image_picker.dart';
import 'package:ln_jq_app/common/login_util.dart'; import 'package:ln_jq_app/common/login_util.dart';
import 'package:ln_jq_app/pages/c_page/message/view.dart'; import 'package:ln_jq_app/pages/c_page/message/view.dart';
import 'package:ln_jq_app/storage_service.dart'; import 'package:ln_jq_app/storage_service.dart';
@@ -368,7 +369,7 @@ class CarInfoPage extends GetView<CarInfoController> {
children: [ children: [
_buildCertificateContent('行驶证', controller.drivingAttachments), _buildCertificateContent('行驶证', controller.drivingAttachments),
_buildCertificateContent('营运证', controller.operationAttachments), _buildCertificateContent('营运证', controller.operationAttachments),
_buildCertificateContent('加氢资格', controller.hydrogenationAttachments), _buildCertificateContent('加氢证', controller.hydrogenationAttachments),
_buildCertificateContent('登记证', controller.registerAttachments), _buildCertificateContent('登记证', controller.registerAttachments),
], ],
), ),
@@ -388,7 +389,7 @@ class CarInfoPage extends GetView<CarInfoController> {
child: Padding( child: Padding(
padding: EdgeInsets.all(16.0), padding: EdgeInsets.all(16.0),
child: attachments.isEmpty child: attachments.isEmpty
? const Center(child: Text('暂无相关证件信息')) ? _buildEmptyCertificateState(title)
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@@ -440,6 +441,158 @@ class CarInfoPage extends GetView<CarInfoController> {
}); });
} }
Widget _buildEmptyCertificateState(String title) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/ic_attention@2x.png', // 请替换为您的实际图片路径
width: 120,
height: 120,
),
const SizedBox(height: 16),
Text(
'您未上传“$title',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: Color.fromRGBO(51, 51, 51, 1),
),
),
const SizedBox(height: 8),
Text(
'上传后可提前通知加氢站报备\n大幅减少加氢站等待时间',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12.sp,
color: Color.fromRGBO(156, 163, 175, 1),
height: 1.5,
),
),
const SizedBox(height: 24),
SizedBox(
width: 200,
height: 44,
child: ElevatedButton.icon(
onPressed: () {
_showUploadDialog(title);
},
icon: const Text(
'立即上传',
style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
label: Image.asset(
'assets/images/ic_upload@2x.png',
height: 20.h,
width: 20.w,
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF017137),
foregroundColor: Colors.white,
shape: StadiumBorder(),
elevation: 0,
),
),
),
],
);
}
void _showUploadDialog(String title) {
Get.dialog(
Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
child: Container(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'上传$title',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
const SizedBox(height: 12),
Text(
'请确保拍摄证件清晰可见,关键文字无反光遮挡,这将有助于快速通过审核',
style: TextStyle(fontSize: 13, color: Colors.grey[400], height: 1.5),
),
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: _buildUploadOption(
icon: Icons.camera_alt_outlined,
label: '拍照上传',
onTap: () {
controller.pickImage(title, ImageSource.camera);
Get.back();
},
),
),
const SizedBox(width: 16),
Expanded(
child: _buildUploadOption(
icon: Icons.image_outlined,
label: '相册上传',
onTap: () {
controller.pickImage(title, ImageSource.gallery);
Get.back();
},
),
),
],
),
],
),
),
),
);
}
// 构建弹窗内的选择按钮
Widget _buildUploadOption({
required IconData icon,
required String label,
required VoidCallback onTap,
}) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 24),
decoration: BoxDecoration(
color: const Color(0xFFF2F9F7), // 浅绿色背景
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: const BoxDecoration(
color: Color(0xFF017137), // 深绿色圆圈
shape: BoxShape.circle,
),
child: Icon(icon, color: Colors.white, size: 28),
),
const SizedBox(height: 12),
Text(
label,
style: const TextStyle(
fontSize: 14,
color: Color(0xFF333333),
fontWeight: FontWeight.w500,
),
),
],
),
),
);
}
Widget _buildCertDetailItem( Widget _buildCertDetailItem(
String label, String label,
String value, { String value, {

View File

@@ -1,10 +1,15 @@
import 'dart:io';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:getx_scaffold/common/index.dart'; import 'package:getx_scaffold/common/index.dart';
import 'package:getx_scaffold/common/widgets/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/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/c_page/message/view.dart';
import 'package:ln_jq_app/pages/common/webview/view.dart';
import 'package:ln_jq_app/storage_service.dart'; import 'package:ln_jq_app/storage_service.dart';
import 'controller.dart'; import 'controller.dart';
@@ -38,6 +43,30 @@ class MinePage extends GetView<MineController> {
_buildSafetyReminderCard(), _buildSafetyReminderCard(),
SizedBox(height: 24.h), SizedBox(height: 24.h),
_buildLogoutButton(), _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), 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() { Widget _buildUserInfoCard() {
return Card( return Card(

View File

@@ -221,8 +221,14 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
stateName: '', stateName: '',
addStatus: '', addStatus: '',
addStatusName: '', addStatusName: '',
rejectReason: '',
hasEdit: true, hasEdit: true,
rejectReason: '',
isTruckAttachment: 0,
hasHydrogenationAttachment: true,
hasDrivingAttachment: true,
isEdit: '',
drivingAttachments: [],
hydrogenationAttachments: [], gunNumber: '',
); );
//打开预约列表 //打开预约列表
@@ -253,7 +259,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
if (_debounce?.isActive ?? false) { if (_debounce?.isActive ?? false) {
return; return;
} }
_debounce = Timer(const Duration(seconds: 1), () {}); _debounce = Timer(const Duration(milliseconds: 200), () {});
showLoading("加载中"); showLoading("加载中");
@@ -393,7 +399,7 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
// 创建一个每1分钟执行一次的周期性定时器 // 创建一个每1分钟执行一次的周期性定时器
_refreshTimer = Timer.periodic(const Duration(minutes: 1), (timer) { _refreshTimer = Timer.periodic(const Duration(minutes: 1), (timer) {
getSiteList(); getSiteList(showloading: false);
}); });
} }
@@ -521,8 +527,8 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
updateUi(); updateUi();
} }
void getSiteList() async { void getSiteList({showloading = true}) async {
if (StorageService.to.phone == "13888888888") { if (StorageService.to.phone == "13344444444") {
//该账号给stationOptions手动添加一个数据 //该账号给stationOptions手动添加一个数据
final testStation = StationModel( final testStation = StationModel(
hydrogenId: '1142167389150920704', hydrogenId: '1142167389150920704',
@@ -546,7 +552,9 @@ class C_ReservationController extends GetxController with BaseControllerMixin {
} }
try { try {
showLoading("加氢站数据加载中"); if (showloading) {
showLoading("加氢站数据加载中");
}
var responseData = await HttpService.to.get( var responseData = await HttpService.to.get(
"appointment/station/queryHydrogenSiteInfo", "appointment/station/queryHydrogenSiteInfo",

View File

@@ -49,7 +49,7 @@ class ReservationPage extends GetView<C_ReservationController> {
Positioned( Positioned(
left: 20.w, left: 20.w,
right: 20.w, right: 20.w,
bottom: 110.h, bottom: Get.height * (Get.height < 826 ? 0.08 : 0.11),
child: _buildReservationItem(context), child: _buildReservationItem(context),
), ),
], ],
@@ -457,27 +457,34 @@ class ReservationPage extends GetView<C_ReservationController> {
/// 时间 Slider 选择器 /// 时间 Slider 选择器
Widget _buildTimeSlider(BuildContext context) { Widget _buildTimeSlider(BuildContext context) {
return Obx(() { return Obx(() {
// 获取当前小时作为滑块值 (0-23) // 获取站点信息
int currentHour = controller.startTime.value.hour;
// 动态获取站点的营业范围限制
final station = controller.stationOptions.firstWhereOrNull( final station = controller.stationOptions.firstWhereOrNull(
(s) => s.hydrogenId == controller.selectedStationId.value, (s) => s.hydrogenId == controller.selectedStationId.value,
); );
// 解析营业时间
// 处理格式如 "09:00" 或 "09:00:00"
final startParts = (station?.startBusiness ?? "00:00").split(':');
final endParts = (station?.endBusiness ?? "23:59").split(':');
// 如果没有站点数据,默认隐藏
if (station == null) {
return const SizedBox(height: 100);
}
// 解析营业范围
final startParts = station.startBusiness.split(':');
final endParts = station.endBusiness.split(':');
int bizStartHour = int.tryParse(startParts[0]) ?? 0; int bizStartHour = int.tryParse(startParts[0]) ?? 0;
int bizEndHour = int.tryParse(endParts[0]) ?? 23; int bizEndHour = int.tryParse(endParts[0]) ?? 23;
int bizEndMinute = (endParts.length > 1) ? (int.tryParse(endParts[1]) ?? 0) : 0; int bizEndMinute = (endParts.length > 1) ? (int.tryParse(endParts[1]) ?? 0) : 0;
if (bizEndMinute == 0 && bizEndHour > bizStartHour) bizEndHour--;
// 优化结束小时逻辑 //确定当前滑块值
// 如果分钟为 0 (例如 18:00),说明该小时整点已关门,最大可选小时应减 1 int currentHour = controller.startTime.value.hour;
if (bizEndMinute == 0 && bizEndHour > 0) { double sliderValue = currentHour.toDouble().clamp(
bizEndHour--; bizStartHour.toDouble(),
} bizEndHour.toDouble(),
);
double minVal = bizStartHour.toDouble();
double maxVal = bizEndHour.toDouble();
if (minVal >= maxVal) maxVal = minVal + 1;
return Column( return Column(
children: [ children: [
@@ -526,12 +533,9 @@ class ReservationPage extends GetView<C_ReservationController> {
overlayColor: const Color(0xFF006633).withOpacity(0.1), overlayColor: const Color(0xFF006633).withOpacity(0.1),
), ),
child: Slider( child: Slider(
value: currentHour.toDouble().clamp( value: sliderValue,
bizStartHour.toDouble(), min: minVal,
bizEndHour.toDouble(), max: maxVal,
),
min: bizStartHour.toDouble(),
max: bizEndHour.toDouble(),
// divisions: bizEndHour - bizStartHour > 0 ? bizEndHour - bizStartHour : 1, // divisions: bizEndHour - bizStartHour > 0 ? bizEndHour - bizStartHour : 1,
onChanged: (val) { onChanged: (val) {
int hour = val.toInt(); int hour = val.toInt();

View File

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

View File

@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:getx_scaffold/getx_scaffold.dart'; import 'package:getx_scaffold/getx_scaffold.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:ln_jq_app/common/login_util.dart'; import 'package:ln_jq_app/common/login_util.dart';
import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/common/model/base_model.dart';
import 'package:ln_jq_app/common/model/vehicle_info.dart'; import 'package:ln_jq_app/common/model/vehicle_info.dart';
@@ -17,6 +18,8 @@ import 'package:ln_jq_app/pages/login/controller.dart';
import 'package:ln_jq_app/pages/url_host/view.dart'; import 'package:ln_jq_app/pages/url_host/view.dart';
import 'package:ln_jq_app/storage_service.dart'; import 'package:ln_jq_app/storage_service.dart';
import '../c_page/message/view.dart';
class LoginPage extends StatefulWidget { class LoginPage extends StatefulWidget {
const LoginPage({super.key}); const LoginPage({super.key});
@@ -30,6 +33,7 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
bool _obscureText = true; bool _obscureText = true;
bool _rememberPassword = true; bool _rememberPassword = true;
bool _credentialsLoaded = false; bool _credentialsLoaded = false;
bool isPushInitialized = false;
@override @override
void initState() { void initState() {
@@ -146,7 +150,8 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
const SizedBox(height: 10), const SizedBox(height: 10),
buildAgreement(), buildAgreement(),
const SizedBox(height: 40), const SizedBox(height: 80),
_buildFooterSlogan()
], ],
), ),
), ),
@@ -155,7 +160,6 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
), ),
), ),
), ),
Positioned(left: 0, right: 0, bottom: 33.h, child: _buildFooterSlogan()),
if (AppTheme.is_show_host) if (AppTheme.is_show_host)
Positioned( Positioned(
top: 40.h, top: 40.h,
@@ -388,13 +392,28 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
content: _buildDialogContent(), content: _buildDialogContent(),
confirmText: '同意', confirmText: '同意',
cancelText: '拒绝', cancelText: '拒绝',
onConfirm: () { onConfirm: () async {
_isAgreed = true; _isAgreed = true;
controller.updateUi(); controller.updateUi();
// 保存隐私政策同意状态
await StorageService.to.savePrivacyAgreed(true);
// 申请通知权限
await _requestNotificationPermission();
// 初始化阿里云推送
await _initPushService();
}, },
); );
return; return;
} }
// 如果已经同意过,但推送还没初始化,则初始化
if (!isPushInitialized) {
await _initPushService();
}
_tabController.index == 0 _tabController.index == 0
? _handleDriverLogin(controller) ? _handleDriverLogin(controller)
: _handleStationLogin(controller); : _handleStationLogin(controller);
@@ -536,6 +555,62 @@ class _LoginPageState extends State<LoginPage> with SingleTickerProviderStateMix
addAlias(identifier); addAlias(identifier);
} }
// 申请通知权限
Future<void> _requestNotificationPermission() async {
final PermissionStatus status = await Permission.notification.request();
if (status.isGranted) {
Logger.d('通知权限已授予');
} else if (status.isPermanentlyDenied) {
Logger.d('通知权限被永久拒绝');
}
}
// 初始化推送服务
Future<void> _initPushService() async {
try {
final _aliyunPush = AliyunPushFlutter();
// 初始化推送
final String appKey = Platform.isIOS ? AppTheme.ios_key : AppTheme.android_key;
final String appSecret = Platform.isIOS
? AppTheme.ios_appsecret
: AppTheme.android_appsecret;
final result = await _aliyunPush.initPush(appKey: appKey, appSecret: appSecret);
if (result['code'] != kAliyunPushSuccessCode) {
Logger.d('推送初始化失败: ${result['errorMsg']}');
return;
}
// 配置平台特定设置
if (Platform.isIOS) {
await _aliyunPush.showIOSNoticeWhenForeground(true);
} else if (Platform.isAndroid) {
await _aliyunPush.setNotificationInGroup(true);
await _aliyunPush.createAndroidChannel(
"xll_push_android",
'新消息通知',
4,
'用于接收加氢站实时状态提醒',
);
}
// 添加推送回调
_aliyunPush.addMessageReceiver(
onNotificationOpened: _onNotificationOpened,
);
isPushInitialized = true;
Logger.d('推送服务初始化成功');
} catch (e) {
Logger.d('推送服务初始化异常: $e');
}
}
Future<void> _onNotificationOpened(Map<dynamic, dynamic> message) async {
await Get.to(() => const MessagePage());
}
final _aliyunPush = AliyunPushFlutter(); final _aliyunPush = AliyunPushFlutter();
void addAlias(String alias) async { void addAlias(String alias) async {

View File

@@ -25,11 +25,14 @@ class StorageService extends GetxService {
static const String _stationAccountKey = 'station_account'; static const String _stationAccountKey = 'station_account';
static const String _stationPasswordKey = 'station_password'; static const String _stationPasswordKey = 'station_password';
// 新增:用于标记绑定车辆”弹窗是否已在本会话中显示过 // 新增:用于标记绑定车辆”弹窗是否已在本会话中显示过
static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown'; static const String _bindDialogShownKey = 'bind_vehicle_dialog_shown';
static const String _hostUrlKey = 'host_url'; static const String _hostUrlKey = 'host_url';
// 隐私政策相关
static const String _privacyAgreedKey = 'privacy_agreed';
static StorageService get to => Get.find(); static StorageService get to => Get.find();
Future<StorageService> init() async { Future<StorageService> init() async {
@@ -63,9 +66,12 @@ class StorageService extends GetxService {
String? get stationPassword => _box.read<String?>(_stationPasswordKey); String? get stationPassword => _box.read<String?>(_stationPasswordKey);
// 新增:获取绑定车辆”弹窗是否已显示的标志 // 新增:获取绑定车辆”弹窗是否已显示的标志
bool get hasShownBindVehicleDialog => _box.read<bool>(_bindDialogShownKey) ?? false; bool get hasShownBindVehicleDialog => _box.read<bool>(_bindDialogShownKey) ?? false;
// 获取隐私政策是否已同意
bool get isPrivacyAgreed => _box.read<bool>(_privacyAgreedKey) ?? false;
VehicleInfo? get vehicleInfo { VehicleInfo? get vehicleInfo {
final vehicleJson = _box.read<String?>(_vehicleInfoKey); final vehicleJson = _box.read<String?>(_vehicleInfoKey);
if (vehicleJson != null) { if (vehicleJson != null) {
@@ -110,6 +116,11 @@ class StorageService extends GetxService {
await _box.write(_stationPasswordKey, password); await _box.write(_stationPasswordKey, password);
} }
// 保存隐私政策同意状态
Future<void> savePrivacyAgreed(bool agreed) async {
await _box.write(_privacyAgreedKey, agreed);
}
// 新增:标记“绑定车辆”弹窗已显示 // 新增:标记“绑定车辆”弹窗已显示
Future<void> markBindVehicleDialogAsShown() async { Future<void> markBindVehicleDialogAsShown() async {
await _box.write(_bindDialogShownKey, true); await _box.write(_bindDialogShownKey, true);

View File

@@ -162,13 +162,13 @@ packages:
source: hosted source: hosted
version: "3.2.4" version: "3.2.4"
device_info_plus: device_info_plus:
dependency: transitive dependency: "direct overridden"
description: description:
name: device_info_plus name: device_info_plus
sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 sha256: "4df8babf73058181227e18b08e6ea3520cf5fc5d796888d33b7cb0f33f984b7c"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "10.1.2" version: "12.3.0"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -798,7 +798,7 @@ packages:
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
path_provider: path_provider:
dependency: transitive dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
@@ -957,6 +957,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.2.3" version: "2.2.3"
saver_gallery:
dependency: "direct main"
description:
name: saver_gallery
sha256: "1d942bd7f4fedc162d9a751e156ebac592e4b81fc2e757af82de9077f3437003"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.0"
shared_preferences: shared_preferences:
dependency: transitive dependency: transitive
description: description:
@@ -1222,10 +1230,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32_registry name: win32_registry
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.5" version: "2.1.0"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:

View File

@@ -16,12 +16,12 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.2.3+6 version: 1.2.4+7
environment: environment:
sdk: ^3.9.0 sdk: ^3.9.0
# Dependencies specify other packages that your package needs in order to work. # Dependencies specify other packages tha。。。t your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions # To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively, # consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to # dependencies can be manually updated by changing the version numbers below to
@@ -53,7 +53,8 @@ dependencies:
aliyun_push_flutter: ^1.3.6 aliyun_push_flutter: ^1.3.6
pull_to_refresh: ^2.0.0 pull_to_refresh: ^2.0.0
flutter_app_update: ^3.2.2 flutter_app_update: ^3.2.2
saver_gallery: ^4.0.0
path_provider: ^2.1.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -64,6 +65,7 @@ dev_dependencies:
dependency_overrides: dependency_overrides:
intl: 0.19.0 intl: 0.19.0
device_info_plus: ^12.3.0
flutter: flutter: