ar_tourism_flutter_unity/lib/pages/publish/choiceWorks.dart
2025-05-14 17:04:13 +08:00

415 lines
17 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 '../../../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 {
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'],
},
);
print("-------------publishData: $publishData");
try {
final result =
await userApi.getPublish(publishData);
// print("@@@@@@@@@@@result: $result");
if (result['code'] == 200) {
final orderId = result['msg'].toString();
print("@@@@@@@@@@@orderId: $orderId");
// 查看类型 orderId
print(
"@@@@@@@@@@@orderId类型: ${orderId.runtimeType}");
Fluttertoast.showToast(msg: '请支付订单');
Navigator.pushReplacementNamed(context, '/pay',
arguments: {
'orderId': orderId,
'totalPrice': sourceInfo[0]['totalPrice'],
},);
// Navigator.pushNamedAndRemoveUntil(
// context,
// '/tabs',
// (route) => false,
// arguments: {'initialIndex': 1}, // 传递参数设置初始选中的tab
// );
} 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,
),
),
),
),
],
),
],
),
);
}
}