ar_tourism_flutter_unity/lib/pages/publish/choiceWorks.dart

436 lines
18 KiB
Dart

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:intl/intl.dart';
import '../../components/appbar.dart';
import '../../components/gradientButton.dart';
import '../../components/cached_image.dart';
import '../../components/CustomAlertDialog.dart';
import '../../../apis/app.dart';
import '../mine/mine.dart';
import '../mine/work/worksDetail.dart';
class ChoiceWorksPage extends StatefulWidget {
const ChoiceWorksPage({
super.key,
required this.data,
});
final List<Map<String, dynamic>> data;
@override
State<ChoiceWorksPage> createState() => _ChoiceWorksPageState();
}
class _ChoiceWorksPageState extends State<ChoiceWorksPage> {
List<WorkItem> works = [];
bool isLoading = false;
String? error;
late List<int?> selectedImages;
late final List<Map<String, dynamic>> sourceInfo;
@override
void initState() {
super.initState();
sourceInfo = widget.data;
selectedImages = List.filled(sourceInfo.length, null);
getMyCollection();
}
Future<void> getMyCollection() async {
try {
setState(() {
isLoading = true;
error = null;
});
final result = await userApi.getMyCollection();
if (result['code'] == 200) {
final List<dynamic> data = result['rows'] ?? [];
setState(() {
works = data.map((item) => WorkItem.fromJson(item)).toList();
});
} else {
setState(() {
error = result['msg'];
});
}
} catch (e) {
setState(() {
error = e.toString();
});
} finally {
setState(() {
isLoading = false;
});
}
}
void _selectImage(int index) {
setState(() {
int? emptyPosition = selectedImages.indexOf(null);
if (emptyPosition != -1) {
selectedImages[emptyPosition] = index;
} else {
Fluttertoast.showToast(msg: '已选择足够数量的作品');
}
});
}
void _removeImage(int position) {
setState(() {
selectedImages[position] = null;
for (int i = position; i < selectedImages.length - 1; i++) {
selectedImages[i] = selectedImages[i + 1];
}
selectedImages[selectedImages.length - 1] = null;
});
}
bool get isAllImagesSelected => !selectedImages.contains(null);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(title: '选择作品'),
body: Container(
decoration: const BoxDecoration(
color: Color(0xff0C0C16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'请按照顺序依次进行投放',
style: TextStyle(
color: Colors.red,
fontSize: 16,
),
),
),
Expanded(
child: isLoading
? const Center(child: CircularProgressIndicator())
: error != null
? Center(
child: Text(
error!,
style: const TextStyle(color: Colors.red),
),
)
: works.isEmpty
? _buildEmptyState()
: GridView.builder(
padding:
const EdgeInsets.symmetric(horizontal: 16),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 166 / 219,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: works.length,
itemBuilder: (context, index) {
final work = works[index];
return GestureDetector(
onTap: () => _selectImage(index),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
// border: selectedImages.contains(index)
// ? Border.all(
// color: const Color(0xFF96FBE9)
// .withOpacity(0.8),
// width: 2)
// : null,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Stack(
fit: StackFit.expand,
children: [
CachedImage(
imageUrl: work.imageUrl,
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
borderRadius: BorderRadius.circular(8),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.transparent,
Colors.black.withOpacity(0.7),
],
),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
work.title,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
),
overflow: TextOverflow.ellipsis,
),
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
WorksDetailPage(
id: work.workId,
type: 'collection',
),
),
);
},
child: Image.asset(
'images/full.png',
width: 24,
height: 24,
color: Colors.white,
),
),
],
),
),
),
// if (selectedImages.contains(index))
// Positioned(
// top: 8,
// right: 8,
// child: Container(
// padding:
// const EdgeInsets.all(4),
// decoration: BoxDecoration(
// color: const Color(0xFF96FBE9)
// .withOpacity(0.8),
// shape: BoxShape.circle,
// ),
// child: Text(
// '${selectedImages.indexOf(index) + 1}',
// style: const TextStyle(
// color: Colors.white,
// fontSize: 12,
// ),
// ),
// ),
// ),
],
),
),
),
);
},
),
),
Container(
width: MediaQuery.of(context).size.width,
padding: const EdgeInsets.all(16),
color: const Color(0xff1F212E),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(
sourceInfo.length,
(index) => _buildSelectedImageSlot(index),
),
),
),
const SizedBox(height: 16),
// 发布按钮部分
SizedBox(
width: double.infinity,
child: GradientButton(
text: '发布',
onPressed: isAllImagesSelected
? () async {
// 显示确认对话框
bool? confirm = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return CustomAlertDialog(
title: '确认发布',
content: '确认发布后作品将进入审核阶段',
onConfirm: () {
Navigator.of(context).pop(true);
},
onCancel: () {
Navigator.of(context).pop(false);
},
);
},
);
if (confirm == true) {
final selectedWorks = selectedImages
.map((index) =>
index != null ? works[index] : null)
.toList();
final publishData = List.generate(
selectedWorks.length,
(index) => {
"workId": selectedWorks[index]?.workId,
"sourceId": sourceInfo[index]['sourceId'],
"day": sourceInfo[index]['day'],
},
);
try {
// 发布接口
final result = await userApi.getPublish(publishData);
if (result['code'] == 200) {
final orderId = result['msg'].toString();
print("@@@@@@@@@@@orderId: ${orderId}");
// 直接调用支付回调接口
final payResult = await userApi.getPayCallback(orderId);
if (payResult['code'] == 200) {
Fluttertoast.showToast(msg: '发布成功');
// 返回到首页或指定页面
Navigator.pushNamedAndRemoveUntil(
context,
'/tabs',
(route) => false,
arguments: {'initialIndex': 0},
);
} else {
Fluttertoast.showToast(
msg: payResult['msg'] ?? '支付失败');
}
} else {
Fluttertoast.showToast(
msg: result['msg'] ?? '发布失败');
}
} catch (e) {
Fluttertoast.showToast(msg: '发布失败:$e');
}
}
}
: () => Fluttertoast.showToast(msg: '请将作品选择完整'),
),
),
],
),
),
],
),
),
);
}
Widget _buildEmptyState() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'images/empty_works.png',
width: 120,
height: 120,
),
const SizedBox(height: 16),
const Text(
'暂无作品',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
],
),
);
}
Widget _buildSelectedImageSlot(int index) {
final imageIndex = selectedImages[index];
final hasImage = imageIndex != null;
final work = hasImage ? works[imageIndex] : null;
return Padding(
padding: const EdgeInsets.only(right: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
sourceInfo[index]['position'] ?? '未选择',
style: const TextStyle(color: Colors.white),
),
const SizedBox(height: 8),
Stack(
clipBehavior: Clip.none,
children: [
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: const Color(0xff1F212E),
),
child: hasImage
? ClipRRect(
borderRadius: BorderRadius.circular(8),
child: CachedImage(
imageUrl: work?.imageUrl ?? '',
width: 60,
height: 60,
fit: BoxFit.cover,
),
)
: const Center(
child: Icon(
Icons.add_photo_alternate_outlined,
color: Colors.white,
),
),
),
if (hasImage)
Positioned(
top: -8,
right: -8,
child: GestureDetector(
onTap: () => _removeImage(index),
child: Container(
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
shape: BoxShape.circle,
),
child: const Icon(
Icons.close,
color: Colors.white,
size: 14,
),
),
),
),
],
),
],
),
);
}
}