227 lines
7.0 KiB
Dart
227 lines
7.0 KiB
Dart
import 'dart:io';
|
||
import 'package:autosos_flutter/provider/providers.dart';
|
||
import 'package:autosos_flutter/util/toast.dart';
|
||
import 'package:autosos_flutter/widget/photo_grid_picker.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
|
||
/// 拍照取证页(对应 Android CheckPhotoActivity)
|
||
/// 自定义相机 + 照片队列 + 备注 + 上传
|
||
class PhotographPage extends ConsumerStatefulWidget {
|
||
final int orderId;
|
||
const PhotographPage({super.key, required this.orderId});
|
||
|
||
@override
|
||
ConsumerState<PhotographPage> createState() => _PhotographPageState();
|
||
}
|
||
|
||
class _PhotographPageState extends ConsumerState<PhotographPage> {
|
||
final List<String> _localPaths = [];
|
||
final TextEditingController _remarkCtrl = TextEditingController();
|
||
bool _showCamera = false;
|
||
bool _uploading = false;
|
||
|
||
@override
|
||
void dispose() {
|
||
_remarkCtrl.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
void _onCaptured(String path) {
|
||
setState(() {
|
||
_localPaths.add(path);
|
||
// 拍到一张后自动收起相机,让用户确认后再拍
|
||
_showCamera = false;
|
||
});
|
||
}
|
||
|
||
Future<void> _pickFromAlbum() async {
|
||
final files = await AlbumPicker.pick();
|
||
if (files.isEmpty) return;
|
||
setState(() => _localPaths.addAll(files));
|
||
}
|
||
|
||
Future<void> _submit() async {
|
||
if (_localPaths.isEmpty) {
|
||
Toast.error('请先拍照');
|
||
return;
|
||
}
|
||
setState(() => _uploading = true);
|
||
EasyLoading.show(status: '上传中…');
|
||
try {
|
||
// 1) 走七牛
|
||
final urls = await ref
|
||
.read(uploadServiceProvider)
|
||
.uploadBatch(_localPaths);
|
||
// 2) 通知后端
|
||
final resp = await ref
|
||
.read(orderApiProvider)
|
||
.uploadPhotos(widget.orderId, urls);
|
||
EasyLoading.dismiss();
|
||
if (!resp.isSuccess) {
|
||
Toast.error(resp.message ?? '保存失败');
|
||
return;
|
||
}
|
||
Toast.success('已上传 ${urls.length} 张照片');
|
||
if (mounted) context.pop(true);
|
||
} catch (e) {
|
||
EasyLoading.dismiss();
|
||
Toast.error('上传失败:$e');
|
||
} finally {
|
||
if (mounted) setState(() => _uploading = false);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: Colors.black,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.black,
|
||
title: const Text('拍照取证'),
|
||
iconTheme: const IconThemeData(color: Colors.white),
|
||
),
|
||
body: SafeArea(
|
||
child: Column(
|
||
children: [
|
||
// 备注
|
||
Container(
|
||
color: Colors.white,
|
||
padding: const EdgeInsets.all(12),
|
||
child: TextField(
|
||
controller: _remarkCtrl,
|
||
maxLines: 2,
|
||
decoration: const InputDecoration(
|
||
hintText: '可填写现场情况描述(选填)',
|
||
border: OutlineInputBorder(),
|
||
),
|
||
),
|
||
),
|
||
Expanded(
|
||
child: _showCamera
|
||
? CameraView(onCaptured: _onCaptured)
|
||
: _photoList(),
|
||
),
|
||
// 底部按钮区
|
||
Container(
|
||
color: Colors.white,
|
||
padding: const EdgeInsets.all(8),
|
||
child: Column(
|
||
children: [
|
||
PhotoThumbStrip(
|
||
paths: _localPaths,
|
||
onAdd: () => setState(() => _showCamera = true),
|
||
onRemove: (i) =>
|
||
setState(() => _localPaths.removeAt(i)),
|
||
),
|
||
Row(
|
||
children: [
|
||
Expanded(
|
||
child: OutlinedButton.icon(
|
||
onPressed: _showCamera
|
||
? null
|
||
: () =>
|
||
setState(() => _showCamera = true),
|
||
icon: const Icon(Icons.camera_alt),
|
||
label: const Text('拍照'),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
child: OutlinedButton.icon(
|
||
onPressed: _showCamera
|
||
? null
|
||
: _pickFromAlbum,
|
||
icon: const Icon(Icons.photo_library),
|
||
label: const Text('相册'),
|
||
),
|
||
),
|
||
const SizedBox(width: 8),
|
||
Expanded(
|
||
flex: 2,
|
||
child: ElevatedButton.icon(
|
||
onPressed: _uploading ? null : _submit,
|
||
icon: const Icon(Icons.cloud_upload),
|
||
label: Text(
|
||
_uploading
|
||
? '上传中…'
|
||
: '完成(${_localPaths.length})',
|
||
),
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor:
|
||
Theme.of(context).primaryColor,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _photoList() {
|
||
if (_localPaths.isEmpty) {
|
||
return Center(
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: const [
|
||
Icon(Icons.photo_camera,
|
||
size: 80, color: Colors.white24),
|
||
SizedBox(height: 8),
|
||
Text('点击下方"拍照"开始取证',
|
||
style: TextStyle(color: Colors.white54)),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
return GridView.builder(
|
||
padding: const EdgeInsets.all(8),
|
||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||
crossAxisCount: 3,
|
||
crossAxisSpacing: 8,
|
||
mainAxisSpacing: 8,
|
||
),
|
||
itemCount: _localPaths.length,
|
||
itemBuilder: (ctx, i) => Stack(
|
||
children: [
|
||
Positioned.fill(
|
||
child: ClipRRect(
|
||
borderRadius: BorderRadius.circular(6),
|
||
child: Image.file(
|
||
File(_localPaths[i]),
|
||
fit: BoxFit.cover,
|
||
),
|
||
),
|
||
),
|
||
Positioned(
|
||
top: 2,
|
||
right: 2,
|
||
child: GestureDetector(
|
||
onTap: () => setState(() => _localPaths.removeAt(i)),
|
||
child: Container(
|
||
decoration: const BoxDecoration(
|
||
color: Colors.black54,
|
||
shape: BoxShape.circle,
|
||
),
|
||
padding: const EdgeInsets.all(2),
|
||
child: const Icon(
|
||
Icons.close,
|
||
size: 14,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|