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 createState() => _PhotographPageState(); } class _PhotographPageState extends ConsumerState { final List _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 _pickFromAlbum() async { final files = await AlbumPicker.pick(); if (files.isEmpty) return; setState(() => _localPaths.addAll(files)); } Future _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, ), ), ), ), ], ), ); } }