16 changed files with 997 additions and 1 deletions
@ -0,0 +1,9 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/goodsai_controller.dart'; |
||||
|
|
||||
|
class GoodsaiBinding extends Bindings { |
||||
|
@override |
||||
|
void dependencies() { |
||||
|
Get.lazyPut<GoodsaiController>(() => GoodsaiController()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/goodsmeet_controller.dart'; |
||||
|
|
||||
|
class GoodsmeetBinding extends Bindings { |
||||
|
@override |
||||
|
void dependencies() { |
||||
|
Get.lazyPut<GoodsmeetController>(() => GoodsmeetController()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/goodstrade_controller.dart'; |
||||
|
|
||||
|
class GoodstradeBinding extends Bindings { |
||||
|
@override |
||||
|
void dependencies() { |
||||
|
Get.lazyPut<GoodstradeController>(() => GoodstradeController()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../controllers/goodsvip_controller.dart'; |
||||
|
|
||||
|
class GoodsvipBinding extends Bindings { |
||||
|
@override |
||||
|
void dependencies() { |
||||
|
Get.lazyPut<GoodsvipController>(() => GoodsvipController()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../../../routes/app_routes.dart'; |
||||
|
|
||||
|
class AIItem { |
||||
|
final String id; |
||||
|
final String title; |
||||
|
final String description; |
||||
|
final double price; |
||||
|
final String productId; |
||||
|
|
||||
|
AIItem({ |
||||
|
required this.id, |
||||
|
required this.title, |
||||
|
required this.description, |
||||
|
required this.price, |
||||
|
required this.productId, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
class GoodsaiController extends GetxController { |
||||
|
final RxList<AIItem> items = <AIItem>[].obs; |
||||
|
final RxBool loading = false.obs; |
||||
|
final RxString error = ''.obs; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
_loadProducts(); |
||||
|
} |
||||
|
|
||||
|
Future<void> _loadProducts() async { |
||||
|
loading.value = true; |
||||
|
error.value = ''; |
||||
|
try { |
||||
|
items.assignAll([ |
||||
|
AIItem( |
||||
|
id: 'ai_chat', |
||||
|
title: '通用AI聊天包', |
||||
|
description: '更长对话额度与工具调用', |
||||
|
price: 19.9, |
||||
|
productId: 'ai_chat_101', |
||||
|
), |
||||
|
AIItem( |
||||
|
id: 'ai_tools', |
||||
|
title: 'AI工具扩展', |
||||
|
description: '额外工具能力与上下文长度', |
||||
|
price: 39.9, |
||||
|
productId: 'ai_tools_201', |
||||
|
), |
||||
|
]); |
||||
|
} catch (e) { |
||||
|
error.value = e.toString(); |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void purchase(AIItem item) { |
||||
|
Get.toNamed(Routes.payment, arguments: { |
||||
|
'productId': item.productId, |
||||
|
'amount': item.price, |
||||
|
'description': item.title, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../../../routes/app_routes.dart'; |
||||
|
|
||||
|
class MeetItem { |
||||
|
final String id; |
||||
|
final String title; |
||||
|
final String description; |
||||
|
final double price; |
||||
|
final String productId; |
||||
|
|
||||
|
MeetItem({ |
||||
|
required this.id, |
||||
|
required this.title, |
||||
|
required this.description, |
||||
|
required this.price, |
||||
|
required this.productId, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
class GoodsmeetController extends GetxController { |
||||
|
final RxList<MeetItem> items = <MeetItem>[].obs; |
||||
|
final RxBool loading = false.obs; |
||||
|
final RxString error = ''.obs; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
_loadProducts(); |
||||
|
} |
||||
|
|
||||
|
Future<void> _loadProducts() async { |
||||
|
loading.value = true; |
||||
|
error.value = ''; |
||||
|
try { |
||||
|
items.assignAll([ |
||||
|
MeetItem( |
||||
|
id: 'meet_basic', |
||||
|
title: '会议助手基础版', |
||||
|
description: '会议纪要与基础翻译', |
||||
|
price: 29.9, |
||||
|
productId: 'meet_101', |
||||
|
), |
||||
|
MeetItem( |
||||
|
id: 'meet_pro', |
||||
|
title: '会议助手高级版', |
||||
|
description: '纪要、翻译与AI总结增强', |
||||
|
price: 59.9, |
||||
|
productId: 'meet_201', |
||||
|
), |
||||
|
]); |
||||
|
} catch (e) { |
||||
|
error.value = e.toString(); |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void purchase(MeetItem item) { |
||||
|
Get.toNamed(Routes.payment, arguments: { |
||||
|
'productId': item.productId, |
||||
|
'amount': item.price, |
||||
|
'description': item.title, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../../../routes/app_routes.dart'; |
||||
|
|
||||
|
class TradeItem { |
||||
|
final String id; |
||||
|
final String title; |
||||
|
final String description; |
||||
|
final double price; |
||||
|
final String productId; |
||||
|
|
||||
|
TradeItem({ |
||||
|
required this.id, |
||||
|
required this.title, |
||||
|
required this.description, |
||||
|
required this.price, |
||||
|
required this.productId, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
class GoodstradeController extends GetxController { |
||||
|
final RxList<TradeItem> items = <TradeItem>[].obs; |
||||
|
final RxBool loading = false.obs; |
||||
|
final RxString error = ''.obs; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
_loadProducts(); |
||||
|
} |
||||
|
|
||||
|
Future<void> _loadProducts() async { |
||||
|
loading.value = true; |
||||
|
error.value = ''; |
||||
|
try { |
||||
|
items.assignAll([ |
||||
|
TradeItem( |
||||
|
id: 'trans_100', |
||||
|
title: '翻译包 100 分钟', |
||||
|
description: '实时翻译服务时长包', |
||||
|
price: 19.9, |
||||
|
productId: 'trans_100', |
||||
|
), |
||||
|
TradeItem( |
||||
|
id: 'trans_500', |
||||
|
title: '翻译包 500 分钟', |
||||
|
description: '更划算的翻译时长包', |
||||
|
price: 79.9, |
||||
|
productId: 'trans_500', |
||||
|
), |
||||
|
]); |
||||
|
} catch (e) { |
||||
|
error.value = e.toString(); |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void purchase(TradeItem item) { |
||||
|
Get.toNamed(Routes.payment, arguments: { |
||||
|
'productId': item.productId, |
||||
|
'amount': item.price, |
||||
|
'description': item.title, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
import 'package:get/get.dart'; |
||||
|
import '../../../routes/app_routes.dart'; |
||||
|
|
||||
|
class GoodsItem { |
||||
|
final String id; |
||||
|
final String title; |
||||
|
final String description; |
||||
|
final double price; |
||||
|
final String productId; |
||||
|
|
||||
|
GoodsItem({ |
||||
|
required this.id, |
||||
|
required this.title, |
||||
|
required this.description, |
||||
|
required this.price, |
||||
|
required this.productId, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
class GoodsvipController extends GetxController { |
||||
|
final RxList<GoodsItem> items = <GoodsItem>[].obs; |
||||
|
final RxBool loading = false.obs; |
||||
|
final RxString error = ''.obs; |
||||
|
|
||||
|
@override |
||||
|
void onInit() { |
||||
|
super.onInit(); |
||||
|
_loadProducts(); |
||||
|
} |
||||
|
|
||||
|
Future<void> _loadProducts() async { |
||||
|
loading.value = true; |
||||
|
error.value = ''; |
||||
|
try { |
||||
|
// 示例数据,可接后端商品接口替换 |
||||
|
items.assignAll([ |
||||
|
GoodsItem( |
||||
|
id: 'vip_month', |
||||
|
title: '月度会员', |
||||
|
description: '解锁高级功能,按月订阅', |
||||
|
price: 9.9, |
||||
|
productId: 'vip_101', |
||||
|
), |
||||
|
GoodsItem( |
||||
|
id: 'vip_year', |
||||
|
title: '年度会员', |
||||
|
description: '解锁高级功能,按年订阅', |
||||
|
price: 99.0, |
||||
|
productId: 'vip_201', |
||||
|
), |
||||
|
]); |
||||
|
} catch (e) { |
||||
|
error.value = e.toString(); |
||||
|
} finally { |
||||
|
loading.value = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void purchase(GoodsItem item) { |
||||
|
Get.toNamed(Routes.payment, arguments: { |
||||
|
'productId': item.productId, |
||||
|
'amount': item.price, |
||||
|
'description': item.title, |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,131 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../controllers/goodsai_controller.dart'; |
||||
|
|
||||
|
class GoodsaiView extends GetView<GoodsaiController> { |
||||
|
const GoodsaiView({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
||||
|
appBar: AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0.5, |
||||
|
title: Text( |
||||
|
'aiFunction'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
), |
||||
|
body: Obx(() { |
||||
|
if (controller.loading.value) { |
||||
|
return const Center(child: CircularProgressIndicator()); |
||||
|
} |
||||
|
if (controller.error.isNotEmpty) { |
||||
|
return Center(child: Text(controller.error.value)); |
||||
|
} |
||||
|
return ListView.separated( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
itemCount: controller.items.length, |
||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h), |
||||
|
itemBuilder: (_, index) { |
||||
|
final item = controller.items[index]; |
||||
|
return _buildCard(item, isDarkMode); |
||||
|
}, |
||||
|
); |
||||
|
}), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildCard(AIItem item, bool isDarkMode) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: isDarkMode |
||||
|
? Colors.black.withOpacity(0.2) |
||||
|
: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 42.w, |
||||
|
height: 42.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.teal[900]!.withOpacity(0.3) |
||||
|
: Colors.teal[100]!, |
||||
|
borderRadius: BorderRadius.circular(21.r), |
||||
|
), |
||||
|
child: Icon(Icons.auto_awesome, |
||||
|
color: |
||||
|
isDarkMode ? Colors.teal[300]! : Colors.teal[600]!), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
Expanded( |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text(item.title, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 4.h), |
||||
|
Text(item.description, |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: |
||||
|
isDarkMode ? Colors.white70 : Colors.grey[600], |
||||
|
)), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||
|
children: [ |
||||
|
Text('¥${item.price.toStringAsFixed(2)}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 8.h), |
||||
|
GestureDetector( |
||||
|
onTap: () => controller.purchase(item), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
horizontal: 12.w, vertical: 6.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: Colors.blue[600], |
||||
|
borderRadius: BorderRadius.circular(20.r), |
||||
|
), |
||||
|
child: Text( |
||||
|
'购买', |
||||
|
style: TextStyle(fontSize: 12.sp, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,132 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../controllers/goodsmeet_controller.dart'; |
||||
|
|
||||
|
class GoodsmeetView extends GetView<GoodsmeetController> { |
||||
|
const GoodsmeetView({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
||||
|
appBar: AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0.5, |
||||
|
title: Text( |
||||
|
'conferenceAssistant'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
), |
||||
|
body: Obx(() { |
||||
|
if (controller.loading.value) { |
||||
|
return const Center(child: CircularProgressIndicator()); |
||||
|
} |
||||
|
if (controller.error.isNotEmpty) { |
||||
|
return Center(child: Text(controller.error.value)); |
||||
|
} |
||||
|
return ListView.separated( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
itemCount: controller.items.length, |
||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h), |
||||
|
itemBuilder: (_, index) { |
||||
|
final item = controller.items[index]; |
||||
|
return _buildCard(item, isDarkMode); |
||||
|
}, |
||||
|
); |
||||
|
}), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildCard(MeetItem item, bool isDarkMode) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: isDarkMode |
||||
|
? Colors.black.withOpacity(0.2) |
||||
|
: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 42.w, |
||||
|
height: 42.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.pink[900]!.withOpacity(0.3) |
||||
|
: Colors.pink[100]!, |
||||
|
borderRadius: BorderRadius.circular(21.r), |
||||
|
), |
||||
|
child: Icon(Icons.people_alt, |
||||
|
color: isDarkMode |
||||
|
? Colors.pink[300]! |
||||
|
: Colors.pink[600]!), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
Expanded( |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text(item.title, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 4.h), |
||||
|
Text(item.description, |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: |
||||
|
isDarkMode ? Colors.white70 : Colors.grey[600], |
||||
|
)), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||
|
children: [ |
||||
|
Text('¥${item.price.toStringAsFixed(2)}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 8.h), |
||||
|
GestureDetector( |
||||
|
onTap: () => controller.purchase(item), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
horizontal: 12.w, vertical: 6.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: Colors.blue[600], |
||||
|
borderRadius: BorderRadius.circular(20.r), |
||||
|
), |
||||
|
child: Text( |
||||
|
'购买', |
||||
|
style: TextStyle(fontSize: 12.sp, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,132 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../controllers/goodstrade_controller.dart'; |
||||
|
|
||||
|
class GoodstradeView extends GetView<GoodstradeController> { |
||||
|
const GoodstradeView({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
||||
|
appBar: AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0.5, |
||||
|
title: Text( |
||||
|
'simultaneousTranslation'.tr, |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
), |
||||
|
body: Obx(() { |
||||
|
if (controller.loading.value) { |
||||
|
return const Center(child: CircularProgressIndicator()); |
||||
|
} |
||||
|
if (controller.error.isNotEmpty) { |
||||
|
return Center(child: Text(controller.error.value)); |
||||
|
} |
||||
|
return ListView.separated( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
itemCount: controller.items.length, |
||||
|
separatorBuilder: (_, __) => SizedBox(height: 12.h), |
||||
|
itemBuilder: (_, index) { |
||||
|
final item = controller.items[index]; |
||||
|
return _buildCard(item, isDarkMode); |
||||
|
}, |
||||
|
); |
||||
|
}), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildCard(TradeItem item, bool isDarkMode) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: isDarkMode |
||||
|
? Colors.black.withOpacity(0.2) |
||||
|
: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 42.w, |
||||
|
height: 42.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.indigo[900]!.withOpacity(0.3) |
||||
|
: Colors.indigo[100]!, |
||||
|
borderRadius: BorderRadius.circular(21.r), |
||||
|
), |
||||
|
child: Icon(Icons.translate, |
||||
|
color: isDarkMode |
||||
|
? Colors.indigo[300]! |
||||
|
: Colors.indigo[600]!), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
Expanded( |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text(item.title, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 4.h), |
||||
|
Text(item.description, |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: |
||||
|
isDarkMode ? Colors.white70 : Colors.grey[600], |
||||
|
)), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||
|
children: [ |
||||
|
Text('¥${item.price.toStringAsFixed(2)}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 8.h), |
||||
|
GestureDetector( |
||||
|
onTap: () => controller.purchase(item), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
horizontal: 12.w, vertical: 6.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: Colors.blue[600], |
||||
|
borderRadius: BorderRadius.circular(20.r), |
||||
|
), |
||||
|
child: Text( |
||||
|
'购买', |
||||
|
style: TextStyle(fontSize: 12.sp, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,137 @@ |
|||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:get/get.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import '../controllers/goodsvip_controller.dart'; |
||||
|
|
||||
|
class GoodsvipView extends GetView<GoodsvipController> { |
||||
|
const GoodsvipView({super.key}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isDarkMode = Theme.of(context).brightness == Brightness.dark; |
||||
|
|
||||
|
return Scaffold( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], |
||||
|
appBar: AppBar( |
||||
|
backgroundColor: isDarkMode ? Colors.black : Colors.white, |
||||
|
elevation: 0.5, |
||||
|
title: Text( |
||||
|
'premiumMember'.tr, // 高级会员 |
||||
|
style: TextStyle( |
||||
|
fontSize: 18.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
), |
||||
|
), |
||||
|
centerTitle: true, |
||||
|
), |
||||
|
body: Obx(() { |
||||
|
if (controller.loading.value) { |
||||
|
return const Center(child: CircularProgressIndicator()); |
||||
|
} |
||||
|
if (controller.error.isNotEmpty) { |
||||
|
return Center(child: Text(controller.error.value)); |
||||
|
} |
||||
|
return ListView.separated( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
itemCount: controller.items.length, |
||||
|
separatorBuilder: (_, __) => |
||||
|
SizedBox(height: 12.h), |
||||
|
itemBuilder: (_, index) { |
||||
|
final item = controller.items[index]; |
||||
|
return _buildGoodsCard(item, isDarkMode); |
||||
|
}, |
||||
|
); |
||||
|
}), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildGoodsCard(GoodsItem item, bool isDarkMode) { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.all(16.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode ? Colors.grey[900] : Colors.white, |
||||
|
borderRadius: BorderRadius.circular(12.r), |
||||
|
boxShadow: [ |
||||
|
BoxShadow( |
||||
|
color: isDarkMode |
||||
|
? Colors.black.withOpacity(0.2) |
||||
|
: Colors.black.withOpacity(0.05), |
||||
|
blurRadius: 10, |
||||
|
offset: const Offset(0, 2), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Container( |
||||
|
width: 42.w, |
||||
|
height: 42.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: isDarkMode |
||||
|
? Colors.amber[900]!.withOpacity(0.3) |
||||
|
: Colors.amber[100]!, |
||||
|
borderRadius: BorderRadius.circular(21.r), |
||||
|
), |
||||
|
child: Icon(Icons.workspace_premium, |
||||
|
color: isDarkMode |
||||
|
? Colors.amber[300]! |
||||
|
: Colors.amber[600]!), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
Expanded( |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
children: [ |
||||
|
Text(item.title, |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 4.h), |
||||
|
Text(item.description, |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: |
||||
|
isDarkMode ? Colors.white70 : Colors.grey[600], |
||||
|
)), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 12.w), |
||||
|
Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.end, |
||||
|
children: [ |
||||
|
Text('¥${item.price.toStringAsFixed(2)}', |
||||
|
style: TextStyle( |
||||
|
fontSize: 16.sp, |
||||
|
fontWeight: FontWeight.w600, |
||||
|
color: isDarkMode ? Colors.white : Colors.black, |
||||
|
)), |
||||
|
SizedBox(height: 8.h), |
||||
|
GestureDetector( |
||||
|
onTap: () => controller.purchase(item), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric( |
||||
|
horizontal: 12.w, vertical: 6.h), |
||||
|
decoration: BoxDecoration( |
||||
|
color: Colors.blue[600], |
||||
|
borderRadius: BorderRadius.circular(20.r), |
||||
|
), |
||||
|
child: Text( |
||||
|
'购买', |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue