import 'dart:io'; import 'package:client_proxy_framework/client_proxy_framework.dart'; import 'package:http/http.dart' as http; /// PUT 到 [FeedbackApi.getUploadPresignedUrl] 返回的地址,返回服务端 [FeedbackUploadPresignedUrlResponse.filePath] 供 [FeedbackApi.submit] 的 `fileUrls`。 Future uploadFeedbackAttachment(File file) async { final name = file.path.split('/').last; final presignedRes = await FeedbackApi.getUploadPresignedUrl(fileName: name); if (!presignedRes.isSuccess || presignedRes.data == null) { throw StateError( presignedRes.msg.isNotEmpty ? presignedRes.msg : 'Could not get upload URL', ); } final p = presignedRes.data!; final uploadUrl = p.uploadUrl; final filePath = p.filePath; if (uploadUrl == null || uploadUrl.isEmpty || filePath == null || filePath.isEmpty) { throw StateError('Invalid upload URL response'); } final bytes = await file.readAsBytes(); final contentType = _mimeForPath(file.path); final headers = {'Content-Type': contentType}; final extra = p.putHeaders; if (extra != null) { for (final e in extra.entries) { final k = e.key.trim(); if (k.isEmpty) continue; headers[k] = e.value.toString(); } } if (!headers.containsKey('Content-Type')) { headers['Content-Type'] = contentType; } final r = await http.put( Uri.parse(uploadUrl), headers: headers, body: bytes, ); if (r.statusCode < 200 || r.statusCode >= 300) { throw StateError('Upload failed (${r.statusCode})'); } return filePath; } String _mimeForPath(String path) { final lower = path.toLowerCase(); if (lower.endsWith('.png')) return 'image/png'; if (lower.endsWith('.gif')) return 'image/gif'; if (lower.endsWith('.webp')) return 'image/webp'; return 'image/jpeg'; }