司机-可上传证件

This commit is contained in:
2026-02-25 15:35:02 +08:00
parent a05d4ebb9b
commit 1724852a39
4 changed files with 271 additions and 7 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,5 +1,8 @@
import 'package:get/get.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/vehicle_info.dart';
import 'package:ln_jq_app/pages/c_page/car_info/attachment_viewer_page.dart';
@@ -89,6 +92,114 @@ 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;
// 根据标题映射业务类型
Logger.d("message-$title-$imageUrl");
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 {
if (StorageService.to.hasVehicleInfo) {
VehicleInfo? bean = StorageService.to.vehicleInfo;
@@ -102,7 +213,7 @@ class CarInfoController extends GetxController with BaseControllerMixin {
// 获取证件信息
final response = await HttpService.to.get(
'appointment/vehicle/getPicInfoByVin?vin=$vin',
'appointment/vehicle/getPicInfoByVin?vin=$vin&plateNumber=$plateNumber',
);
if (response != null && response.data != null) {
@@ -134,10 +245,10 @@ class CarInfoController extends GetxController with BaseControllerMixin {
...registerAttachments,
];
color = data['color'].toString();
hydrogenCapacity = data['hydrogenCapacity'].toString();
rentFromCompany = data['rentFromCompany'].toString();
address = data['address'].toString();
color = data['color'].toString();
hydrogenCapacity = data['hydrogenCapacity'].toString();
rentFromCompany = data['rentFromCompany'].toString();
address = data['address'].toString();
loadAllPdfs();
}

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:get/get.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/pages/c_page/message/view.dart';
import 'package:ln_jq_app/storage_service.dart';
@@ -368,7 +369,7 @@ class CarInfoPage extends GetView<CarInfoController> {
children: [
_buildCertificateContent('行驶证', controller.drivingAttachments),
_buildCertificateContent('营运证', controller.operationAttachments),
_buildCertificateContent('加氢资格', controller.hydrogenationAttachments),
_buildCertificateContent('加氢证', controller.hydrogenationAttachments),
_buildCertificateContent('登记证', controller.registerAttachments),
],
),
@@ -388,7 +389,7 @@ class CarInfoPage extends GetView<CarInfoController> {
child: Padding(
padding: EdgeInsets.all(16.0),
child: attachments.isEmpty
? const Center(child: Text('暂无相关证件信息'))
? _buildEmptyCertificateState(title)
: Column(
crossAxisAlignment: CrossAxisAlignment.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(
String label,
String value, {