feat:增加闪灵上传图片功能

This commit is contained in:
2025-11-11 18:27:41 +08:00
parent 4ac7b2a698
commit 703a5a6aeb
7 changed files with 212 additions and 14 deletions

View File

@@ -25,7 +25,7 @@ class FlispPageState extends State<FlispPage> {
late List<Flisp> _flisps;
FlispTab _currentTab = FlispTab.all;
// 获取过滤后的待办事项
// 获取过滤后的闪灵事项
List<Flisp> get _activeFlisps => getActiveFlisps(_currentTab, _flisps);
void showAddDialog() {

View File

@@ -0,0 +1,57 @@
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:file_picker/file_picker.dart';
import 'package:minio/io.dart';
import 'package:minio/minio.dart';
class MinIOHelper {
static final MinIOHelper _instance = MinIOHelper._internal();
factory MinIOHelper() => _instance;
final String rustfsIp = '14.103.235.151';
final String rustfsFileUrl = 'http://14.103.235.151:9100';
final String bucketName = 'flisp';
MinIOHelper._internal() {
_minio = Minio(
endPoint: rustfsIp,
port: 9100,
accessKey: "tHSFfcDW8qpCzKa2Xg6Y",
secretKey: "oq79EeYJ4jdczRp2IHUMCnbKtSw58NgDlG3sOkvX",
useSSL: false,
);
}
late Minio _minio;
Future<String> uploadFile({
required PlatformFile file,
Function(double)? onProgress,
}) async {
try {
String hashName = await _generateMD5HashName(file.path!);
String fileName = '$hashName${_getFileExtension(file.name)}';
await _minio.fPutObject(bucketName, fileName, file.path!);
return fileName;
} catch (e) {
throw Exception('文件上传失败: $e');
}
}
String _getFileExtension(String fileName) {
if (fileName.contains('.')) {
return '.${fileName.split('.').last.toLowerCase()}';
}
return '';
}
Future<String> _generateMD5HashName(String filePath) async {
final file = File(filePath);
final bytes = await file.readAsBytes();
final hash = md5.convert(bytes);
return hash.toString();
}
}

View File

@@ -1,5 +1,7 @@
import 'package:file_picker/file_picker.dart';
import 'package:flisp_app/models/flisp.dart';
import 'package:flisp_app/provider/flisp_provider.dart';
import 'package:flisp_app/utils/minio_utils.dart';
import 'package:flisp_app/widgets/flisp_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
@@ -45,6 +47,21 @@ class _FlispFormState extends State<FlispForm> {
});
}
void _selectImage(String fileName) {
final provider = Provider.of<FlispProvider>(context, listen: false);
setState(() {
provider.formItem.imageUrl =
'${MinIOHelper().rustfsFileUrl}/${MinIOHelper().bucketName}/$fileName';
});
}
void _deleteImage() {
final provider = Provider.of<FlispProvider>(context, listen: false);
setState(() {
provider.formItem.imageUrl = '';
});
}
@override
Widget build(BuildContext context) {
final int maxContentCount = 100;
@@ -105,15 +122,35 @@ class _FlispFormState extends State<FlispForm> {
SizedBox(height: 8),
buildFlispTag(provider.formItem),
SizedBox(height: 12),
if (provider.formItem.imageUrl.isNotEmpty)
buildFlispImage(
flisp: provider.formItem,
showDelete: true,
onDelete: _deleteImage,
),
],
),
),
);
}
void selectImage() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'jpeg', 'png'],
allowMultiple: false,
);
if (result != null) {
PlatformFile file = result.files.first;
final fileName = await MinIOHelper().uploadFile(file: file);
_selectImage(fileName);
}
}
Widget buildSelectImageButton() {
return GestureDetector(
onTap: () {},
onTap: () => selectImage(),
child: Container(
width: 36,
height: 36,

View File

@@ -98,26 +98,64 @@ Widget _buildFlispContent(Flisp flisp) {
);
}
Widget _buildFlispImage(Flisp flisp) {
Widget _buildDeleteImage(VoidCallback? onDelete) {
return Positioned(
top: -8,
right: 0,
child: GestureDetector(
onTap: onDelete,
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(10),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Icon(Icons.close, color: Colors.white, size: 16),
),
),
);
}
Widget buildFlispImage({
required Flisp flisp,
bool showDelete = false,
VoidCallback? onDelete,
}) {
return Container(
height: 150,
height: 200,
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
image: NetworkImage(flisp.imageUrl),
fit: BoxFit.cover,
fit: BoxFit.contain,
),
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.black.withOpacity(0.3),
color: Colors.black.withAlpha(10),
),
alignment: Alignment.topRight,
child: const Padding(
padding: EdgeInsets.all(6.0),
child: Icon(Icons.image, color: Colors.white, size: 20),
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.topRight,
child: const Padding(
padding: EdgeInsets.all(6.0),
child: Icon(Icons.image, color: Colors.white, size: 20),
),
),
if (showDelete) _buildDeleteImage(onDelete),
],
),
),
);
@@ -253,7 +291,7 @@ Widget _buildFlispItem({
children: [
_buildFlispContent(flisp),
const SizedBox(height: 8),
if (hasImage) _buildFlispImage(flisp),
if (hasImage) buildFlispImage(flisp: flisp, showDelete: false),
const SizedBox(height: 4),
if (hasVideo) _buildFlispVideo(flisp),
const SizedBox(height: 4),