diff --git a/lib/components/page_appbar.dart b/lib/components/page_appbar.dart index 68dd6a7..ef87634 100644 --- a/lib/components/page_appbar.dart +++ b/lib/components/page_appbar.dart @@ -21,7 +21,7 @@ class PageAppbar extends StatelessWidget implements PreferredSizeWidget { title: Text( title, style: TextStyle( - fontSize: 16, + fontSize: 18, fontWeight: FontWeight.bold, color: const Color.fromRGBO(51, 51, 51, 1) ), diff --git a/lib/controller/mine/league_controller.dart b/lib/controller/mine/league_controller.dart index ecadc9c..0e2d782 100644 --- a/lib/controller/mine/league_controller.dart +++ b/lib/controller/mine/league_controller.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:get/get.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../../network/user_api.dart'; +import '../../pages/setting/match_spread_page.dart'; import '../global.dart'; class LeagueController extends GetxController { @@ -74,12 +75,13 @@ class LeagueController extends GetxController { }); } - Future changePhone() async { + Future submitInfo() async { if(isSendingCode.value){ return; } if (phoneNumber.value.isEmpty) { SmartDialog.showToast('请输入手机号'); + Get.off(() => MatchSpreadPage()); return; } if (verificationCode.value.isEmpty) { @@ -94,9 +96,8 @@ class LeagueController extends GetxController { final response = await _userApi.updatePhone(param); // 处理响应 if (response.data.isSuccess) { - GlobalData().userData!.phone = phoneNumber.value; - SmartDialog.showToast('更换成功'); - Get.back(result: 1); + SmartDialog.showToast('提交成功'); + Get.off(() => MatchSpreadPage()); } else { SmartDialog.showToast(response.data.message); } diff --git a/lib/controller/setting/spread_controller.dart b/lib/controller/setting/spread_controller.dart new file mode 100644 index 0000000..d85aeea --- /dev/null +++ b/lib/controller/setting/spread_controller.dart @@ -0,0 +1,84 @@ +import 'package:dating_touchme_app/model/mine/rose_data.dart'; +import 'package:dating_touchme_app/network/user_api.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:fluwx/fluwx.dart'; +import 'package:get/get.dart'; + +class SpreadController extends GetxController { + + // UserApi实例 + late UserApi _userApi; + final roseList = [].obs; + + final roseNum = 0.obs; + + final payChecked = true.obs; + + final activePay = 0.obs; + + final Fluwx fluwx = Fluwx(); + + changePayActive(int index){ + activePay.value = index; + } + + List list2 = [ + {'title': '邀请注册', 'unit': '10%', 'desc': '分佣', 'enable': 1, 'value': 111, 'icon': 'icon-right1'}, + {'title': '发布悬赏', 'unit': '10%', 'desc': '分佣', 'enable': 1, 'value': 112, 'icon': 'icon-right2'}, + {'title': '匹配悬赏', 'unit': '10%', 'desc': '分佣', 'enable': 0, 'value': 113, 'icon': 'icon-right41'}, + {'title': '推荐红娘', 'unit': '10%', 'desc': '分佣', 'enable': 1, 'value': 114, 'icon': 'icon-right3'}, + {'title': '免费升级', 'desc': '门店合伙人', 'enable': 0, 'value': 0, 'icon': 'icon-right51'}, + {'title': '资源共享', 'desc': '所有资料', 'enable': 1, 'value': 0, 'icon': 'icon-right6'}, + {'title': '业绩奖励', 'unit': '5%', 'desc': '奖励', 'enable': 1, 'value': 0, 'icon': 'icon-right71'}, + {'title': '次年续签', 'unit': '90%', 'desc': '减免', 'enable': 1, 'value': 0, 'icon': 'icon-right8'} + ].obs; + + @override + void onInit() { + super.onInit(); + _userApi = Get.find(); + getRoseList(); + } + + getRoseList() async { + try{ + final response = await _userApi.getMatchmakerFee(); + if (response.data.isSuccess && response.data.data != null) { + final data = response.data.data!.records; + roseList.addAll(data.toList()); + } + print('rose>>>${roseList.length}'); + } catch (e) { + print('玫瑰列表获取失败: $e'); + rethrow; + } + } + + submitOrder() async { + try { + final response = await _userApi.submitOrder({ + "productSpecId": roseList[activePay.value].productSpecId + }); + if (response.data.isSuccess && response.data.data != null) { + final data = response.data.data; + fluwx.open(target: MiniProgram( + username: 'gh_9ea8d46add6f', + path:"pages/index/index?amount=${roseList[activePay.value].unitSellingPrice}&paymentOrderId=${data!.paymentOrderId}&url=match-fee" + )); + + SmartDialog.showToast('开始支付'); + } else { + + // 响应失败,抛出异常 + throw Exception(response.data.message ?? '获取数据失败'); + } + } catch (e) { + print('玫瑰列表获取失败: $e'); + SmartDialog.showToast('下单失败'); + rethrow; + } + + + } + +} \ No newline at end of file diff --git a/lib/model/mine/rose_data.dart b/lib/model/mine/rose_data.dart index 3bae08c..0410a90 100644 --- a/lib/model/mine/rose_data.dart +++ b/lib/model/mine/rose_data.dart @@ -9,6 +9,7 @@ class RoseData { num? unitOriginalPrice; num? unitSellingPrice; String? purchaseTimeValue; + String? validityPeriodDays; RoseData( {this.productId, @@ -20,7 +21,9 @@ class RoseData { this.detailDesc, this.unitOriginalPrice, this.unitSellingPrice, - this.purchaseTimeValue}); + this.purchaseTimeValue, + this.validityPeriodDays + }); RoseData.fromJson(Map json) { productId = json['productId']; @@ -33,6 +36,7 @@ class RoseData { unitOriginalPrice = json['unitOriginalPrice']; unitSellingPrice = json['unitSellingPrice']; purchaseTimeValue = json['purchaseTimeValue']; + validityPeriodDays = json['validityPeriodDays']; } Map toJson() { @@ -47,6 +51,7 @@ class RoseData { data['unitOriginalPrice'] = this.unitOriginalPrice; data['unitSellingPrice'] = this.unitSellingPrice; data['purchaseTimeValue'] = this.purchaseTimeValue; + data['validityPeriodDays'] = this.validityPeriodDays; return data; } } diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index 5aefe9b..003242f 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -86,4 +86,6 @@ class ApiUrls { 'dating-agency-service/user/page/dongwo/marriage-information'; // 后续可以在此添加更多API端点 + static const String listMatchmakerProduct = + 'dating-agency-mall/user/page/product/by/matchmaker'; } diff --git a/lib/network/user_api.dart b/lib/network/user_api.dart index 2e29f99..2b986d5 100644 --- a/lib/network/user_api.dart +++ b/lib/network/user_api.dart @@ -185,4 +185,7 @@ abstract class UserApi { @Query('miId') required String miId, } ); + + @GET(ApiUrls.listMatchmakerProduct) + Future>>> getMatchmakerFee(); } diff --git a/lib/network/user_api.g.dart b/lib/network/user_api.g.dart index eefaa2e..d2bab25 100644 --- a/lib/network/user_api.g.dart +++ b/lib/network/user_api.g.dart @@ -1129,6 +1129,44 @@ class _UserApi implements UserApi { return httpResponse; } + @override + Future>>> + getMatchmakerFee() async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + const Map? _data = null; + final _options = + _setStreamType>>>( + Options(method: 'GET', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-mall/user/page/product/by/matchmaker', + queryParameters: queryParameters, + data: _data, + ) + .copyWith( + baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl), + ), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse> _value; + try { + _value = BaseResponse>.fromJson( + _result.data!, + (json) => PaginatedResponse.fromJson( + json as Map, + (json) => RoseData.fromJson(json as Map), + ), + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + RequestOptions _setStreamType(RequestOptions requestOptions) { if (T != dynamic && !(requestOptions.responseType == ResponseType.bytes || diff --git a/lib/pages/discover/live_room_page.dart b/lib/pages/discover/live_room_page.dart index 001faff..29c566c 100644 --- a/lib/pages/discover/live_room_page.dart +++ b/lib/pages/discover/live_room_page.dart @@ -30,14 +30,6 @@ class _LiveRoomPageState extends State { final activeGift = ValueNotifier(null); - List giftList = [ - {"icon": Assets.imagesGift1, "title": "爱心礼物", "price": 30}, - {"icon": Assets.imagesGift2, "title": "小小小星星", "price": 30}, - {"icon": Assets.imagesGift3, "title": "助威", "price": 30}, - {"icon": Assets.imagesGift4, "title": "点赞", "price": 30}, - {"icon": Assets.imagesGift5, "title": "崇拜衣柜", "price": 30}, - ]; - final giftNum = ValueNotifier(1); final activePay = ValueNotifier(null); @@ -99,12 +91,18 @@ class _LiveRoomPageState extends State { SmartDialog.show( alignment: Alignment.bottomCenter, maskColor: TDTheme.of(context).fontGyColor2, - builder: (_) => LiveGiftPopup( - activeGift: activeGift, - giftNum: giftNum, - giftList: giftList, - changeActive: changeActive, - ), + builder: (_) => Obx(() { + // 优先使用 API 返回的 giftProducts,如果为空则使用后备列表 + final giftProducts = _roomController.giftProducts; + final giftList = giftProducts.toList(); + + return LiveGiftPopup( + activeGift: activeGift, + giftNum: giftNum, + giftList: giftList, + changeActive: changeActive, + ); + }), ); } diff --git a/lib/pages/setting/match_league_page.dart b/lib/pages/setting/match_league_page.dart index b9f7c77..bbc4a5d 100644 --- a/lib/pages/setting/match_league_page.dart +++ b/lib/pages/setting/match_league_page.dart @@ -107,7 +107,7 @@ class MatchLeaguePage extends StatelessWidget { backgroundColor: Color(0xC37562F9), ), onTap: (){ - // controller.startAuthing(); + controller.submitInfo(); }, ), ], diff --git a/lib/pages/setting/match_spread_page.dart b/lib/pages/setting/match_spread_page.dart new file mode 100644 index 0000000..ab39f08 --- /dev/null +++ b/lib/pages/setting/match_spread_page.dart @@ -0,0 +1,197 @@ +import 'package:dating_touchme_app/components/page_appbar.dart'; +import 'package:dating_touchme_app/extension/ex_widget.dart'; +import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/model/mine/rose_data.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:tdesign_flutter/tdesign_flutter.dart'; + +import '../../controller/setting/spread_controller.dart'; + +class MatchSpreadPage extends StatelessWidget { + const MatchSpreadPage({super.key}); + + @override + Widget build(BuildContext context) { + return GetX( + init: SpreadController(), + builder: (controller){ + return Scaffold( + appBar: PageAppbar(title: "入驻加盟"), + body: SingleChildScrollView( + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.w, horizontal: 12.w), + child: Column( + children: [ + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + ...controller.roseList.asMap().entries.map((entry){ + return PayItem(item: entry.value, active: controller.activePay.value, index: entry.key, changeActive: controller.changePayActive); + }), + ], + ), + ), + SizedBox(height: 32.w), + Row( + children: [ + Text('红娘权益', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), + ], + ), + SizedBox(height: 24.w,), + Wrap( + spacing: 10.w, + runSpacing: 18.w, + children: [ + ...controller.list2.map((e){ + return SizedBox( + width: 80.w, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(TDIcons.help_circle, color: Colors.orange, size: 36), + SizedBox(height: 8.w,), + Text(e['title'], style: TextStyle(fontSize: 14, color: Color(0xFF999999))), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if(e['unit'] != null)Text(e['unit'], style: TextStyle(fontSize: 14)), + Text(e['desc'], style: TextStyle(fontSize: 14, color: Color(0xFF999999))), + ], + ) + ], + ), + ); + }), + ], + ), + ], + ), + ), + ), + bottomNavigationBar: SafeArea( + child: Container( + height: 60, + padding: EdgeInsets.symmetric(vertical: 5.w, horizontal: 16.w), + child: TDButton( + text: '立即加入', + width: MediaQuery.of(context).size.width - 40, + size: TDButtonSize.large, + type: TDButtonType.fill, + shape: TDButtonShape.round, + style: TDButtonStyle( + textColor: Colors.white, + backgroundColor: Color(0xFFEE811B), + ), + activeStyle: TDButtonStyle( + textColor: Colors.white, + backgroundColor: Color(0xC3EE811B), + ), + onTap: (){ + controller.submitOrder(); + }, + ), + ) + ), + ); + }, + ); + } +} + + +class PayItem extends StatefulWidget { + final RoseData item; + final int active; + final int index; + final void Function(int) changeActive; + const PayItem({super.key, required this.item, required this.active, required this.index, required this.changeActive, }); + + @override + State createState() => _PayItemState(); +} + +class _PayItemState extends State { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Container( + width: 124.w, + height: 160.h, + margin: const EdgeInsets.only(right: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: widget.active == widget.index ? const Color.fromRGBO(239, 19, 46, .05) : Colors.white, + border: widget.active == widget.index ? Border.all(width: 1, color: const Color(0xFFEE811B)) : Border.all(width: 1, color: const Color(0xFFEEEEEE)) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Container( + padding: EdgeInsets.only(bottom: 5), + child: Text( + "¥", + style: TextStyle( + fontSize: 16.w, + color: Color(0xFFEE811B), + fontWeight: FontWeight.bold + ), + ), + ), + const SizedBox(width: 2), + Text( + "${widget.item.unitSellingPrice}", + style: TextStyle( + fontSize: 26.w, + color: Color(0xFFEE811B), + fontWeight: FontWeight.bold + ), + ), + ], + ), + TDText("¥${widget.item.unitOriginalPrice}", isTextThrough: true, style: TextStyle(color: Color(0xFFCCCCCC)),), + const SizedBox(height: 18), + Text( + "有效期:${widget.item.validityPeriodDays}天", + style: TextStyle( + fontSize: 14.w, + color: Color(0xFF333333), + fontWeight: FontWeight.bold + ), + ), + ], + ), + ), + Positioned( + left: 0, + top: 0, + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.w, horizontal: 6.w), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(6.w), + bottomRight: Radius.circular(6.w), + ), + color: widget.active == widget.index ? const Color(0xFFEE811B) : Color(0xFFCCCCCC) + ), + child: Center( + child: Text(widget.item.productTitle!.replaceAll('加盟费', ''), style: TextStyle(fontSize: 12, color: Colors.white)), + ), + ), + ) + ], + ).onTap((){ + widget.changeActive(widget.index); + }); + } +} \ No newline at end of file diff --git a/lib/widget/live/live_gift_popup.dart b/lib/widget/live/live_gift_popup.dart index c0376dc..0da1d71 100644 --- a/lib/widget/live/live_gift_popup.dart +++ b/lib/widget/live/live_gift_popup.dart @@ -1,11 +1,16 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dating_touchme_app/controller/discover/room_controller.dart'; +import 'package:dating_touchme_app/controller/global.dart'; import 'package:dating_touchme_app/generated/assets.dart'; +import 'package:dating_touchme_app/model/rtc/rtc_channel_detail.dart'; import 'package:dating_touchme_app/widget/live/live_room_gift_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart'; +import 'package:get/get.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; -class LiveGiftPopup extends StatelessWidget { +class LiveGiftPopup extends StatefulWidget { const LiveGiftPopup({ super.key, required this.activeGift, @@ -16,9 +21,44 @@ class LiveGiftPopup extends StatelessWidget { final ValueNotifier activeGift; final ValueNotifier giftNum; - final List giftList; + final List giftList; // 支持 List 或 List final void Function(int) changeActive; + @override + State createState() => _LiveGiftPopupState(); +} + +class _LiveGiftPopupState extends State { + // 选中的用户ID集合 + final Set _selectedUserIds = {}; + + // 切换用户选中状态 + void _toggleUserSelection(String userId) { + setState(() { + if (_selectedUserIds.contains(userId)) { + _selectedUserIds.remove(userId); + } else { + _selectedUserIds.add(userId); + } + }); + } + + // 全选/取消全选 + void _toggleSelectAll(List users) { + setState(() { + if (_selectedUserIds.length == users.length) { + // 如果已全选,则取消全选 + _selectedUserIds.clear(); + } else { + // 否则全选 + _selectedUserIds.clear(); + for (var user in users) { + _selectedUserIds.add(user.userId); + } + } + }); + } + @override Widget build(BuildContext context) { return Material( @@ -32,7 +72,9 @@ class LiveGiftPopup extends StatelessWidget { Expanded( child: Container( decoration: BoxDecoration( - borderRadius: BorderRadius.vertical(top: Radius.circular(9.w)), + borderRadius: BorderRadius.vertical( + top: Radius.circular(9.w), + ), color: const Color.fromRGBO(22, 19, 28, 1), ), child: Column( @@ -51,88 +93,166 @@ class LiveGiftPopup extends StatelessWidget { } Widget _buildHeader() { - return Container( - height: 53.w, - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: Row( - children: [ - Row( - children: [ - Text( - "送给: ", - style: TextStyle(fontSize: 13.w, color: Colors.white), - ), - SizedBox(width: 6.w), - ...List.generate(3, (index) { - return Padding( - padding: EdgeInsets.only(right: 10.w), - child: Stack( - children: [ - ClipRRect( - borderRadius: BorderRadius.all( - Radius.circular(index == 0 ? 68.w : 34.w), - ), - child: Container( - width: 34.w, - height: 34.w, - decoration: BoxDecoration( + return Obx(() { + // 获取 RoomController + final roomController = Get.isRegistered() + ? Get.find() + : null; + + // 获取 rtcChannelDetail + final rtcChannelDetail = roomController?.rtcChannelDetail.value; + + // 获取当前用户ID + final currentUserId = GlobalData().userId ?? GlobalData().userData?.id; + + // 构建用户列表(anchorInfo, maleInfo, femaleInfo) + final List userList = []; + if (rtcChannelDetail?.anchorInfo != null) { + userList.add(rtcChannelDetail!.anchorInfo!); + } + if (rtcChannelDetail?.maleInfo != null) { + userList.add(rtcChannelDetail!.maleInfo!); + } + if (rtcChannelDetail?.femaleInfo != null) { + userList.add(rtcChannelDetail!.femaleInfo!); + } + + // 移除本人 + final filteredUserList = userList.where((user) { + // 通过 userId 或 miId 判断是否是本人 + return user.userId != currentUserId && user.miId != currentUserId; + }).toList(); + + // 最多显示3个用户 + final displayUsers = filteredUserList.take(3).toList(); + + return Container( + height: 53.w, + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + children: [ + Row( + children: [ + Text( + "送给: ", + style: TextStyle(fontSize: 13.w, color: Colors.white), + ), + SizedBox(width: 6.w), + ...displayUsers.asMap().entries.map((entry) { + final index = entry.key; + final user = entry.value; + final isSelected = _selectedUserIds.contains(user.userId); + return GestureDetector( + onTap: () => _toggleUserSelection(user.userId), + child: Padding( + padding: EdgeInsets.only(right: 10.w), + child: Stack( + children: [ + ClipRRect( borderRadius: BorderRadius.all( Radius.circular(index == 0 ? 68.w : 34.w), ), - border: Border.all( - width: index == 0 ? 2 : 1, - color: const Color.fromRGBO(117, 98, 249, 1), + child: Container( + width: 34.w, + height: 34.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(index == 0 ? 68.w : 34.w), + ), + border: Border.all( + width: index == 0 ? 2 : 1, + color: const Color.fromRGBO(117, 98, 249, 1), + ), + ), + child: user.profilePhoto.isNotEmpty + ? CachedNetworkImage( + imageUrl: user.profilePhoto, + width: 34.w, + height: 34.w, + fit: BoxFit.cover, + placeholder: (context, url) => Container( + width: 34.w, + height: 34.w, + color: Colors.grey[300], + child: Center( + child: SizedBox( + width: 16.w, + height: 16.w, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.grey[600], + ), + ), + ), + ), + errorWidget: (context, url, error) => + Image.asset( + Assets.imagesUserAvatar, + width: 32.w, + height: 32.w, + ), + ) + : Image.asset( + Assets.imagesUserAvatar, + width: 32.w, + height: 32.w, + ), ), ), - child: Image.asset( - Assets.imagesUserAvatar, - width: 32.w, - height: 32.w, - ), - ), - ), - Positioned( - bottom: 0, - right: 2.w, - child: Container( - width: 12.w, - height: 12.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(12.w)), - color: const Color.fromRGBO(117, 98, 249, 1), - ), - child: Center( - child: Image.asset( - Assets.imagesCheck, - width: 6.w, - height: 4.w, + if (isSelected) + Positioned( + bottom: 0, + right: 2.w, + child: Container( + width: 12.w, + height: 12.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(12.w), + ), + color: const Color.fromRGBO(117, 98, 249, 1), + ), + child: Center( + child: Image.asset( + Assets.imagesCheck, + width: 6.w, + height: 4.w, + ), + ), + ), ), - ), - ), + ], ), - ], - ), - ); - }), - ], - ), - Container( - width: 63.w, - height: 30.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(30.w)), - color: const Color.fromRGBO(117, 98, 249, 1), + ), + ); + }), + ], ), - child: Center( - child: Text( - "全选", - style: TextStyle(fontSize: 13.w, color: Colors.white), + // 如果列表为空,不显示全选按钮 + if (displayUsers.isNotEmpty) + GestureDetector( + onTap: () => _toggleSelectAll(displayUsers), + child: Container( + width: 63.w, + height: 30.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(30.w)), + color: const Color.fromRGBO(117, 98, 249, 1), + ), + child: Center( + child: Text( + _selectedUserIds.length == displayUsers.length + ? "取消全选" + : "全选", + style: TextStyle(fontSize: 13.w, color: Colors.white), + ), + ), + ), ), - ), - ), - ], - ), - ); + ], + ), + ); + }); } Widget _buildTab() { @@ -163,34 +283,61 @@ class LiveGiftPopup extends StatelessWidget { } Widget _buildGiftSwiper() { + if (widget.giftList.isEmpty) { + return Expanded( + child: Center( + child: Text( + '暂无礼物', + style: TextStyle(fontSize: 14.w, color: Colors.white70), + ), + ), + ); + } + + // 计算需要多少页,每页显示8个礼物(2行4列) + final itemsPerPage = 8; + final totalPages = (widget.giftList.length / itemsPerPage).ceil(); + return Expanded( child: ValueListenableBuilder( - valueListenable: activeGift, + valueListenable: widget.activeGift, builder: (context, active, _) { return Swiper( autoplay: false, - itemCount: 6, - loop: true, - pagination: const SwiperPagination( - alignment: Alignment.bottomCenter, - builder: TDSwiperDotsPagination( - color: Color.fromRGBO(144, 144, 144, 1), - activeColor: Color.fromRGBO(77, 77, 77, 1), - ), - ), - itemBuilder: (context, index) { + itemCount: totalPages, + loop: false, + pagination: totalPages > 1 + ? const SwiperPagination( + alignment: Alignment.bottomCenter, + builder: TDSwiperDotsPagination( + color: Color.fromRGBO(144, 144, 144, 1), + activeColor: Color.fromRGBO(77, 77, 77, 1), + ), + ) + : null, + itemBuilder: (context, pageIndex) { + final startIndex = pageIndex * itemsPerPage; + final endIndex = (startIndex + itemsPerPage).clamp( + 0, + widget.giftList.length, + ); + final pageItems = widget.giftList.sublist(startIndex, endIndex); + return Align( alignment: Alignment.topCenter, child: Wrap( + spacing: 7.w, + runSpacing: 7.w, children: [ - ...giftList.asMap().entries.map( - (entry) => LiveRoomGiftItem( + ...pageItems.asMap().entries.map((entry) { + final globalIndex = startIndex + entry.key; + return LiveRoomGiftItem( item: entry.value, active: active ?? 0, - index: entry.key, - changeActive: changeActive, - ), - ), + index: globalIndex, + changeActive: widget.changeActive, + ); + }), ], ), ); @@ -209,26 +356,18 @@ class LiveGiftPopup extends StatelessWidget { children: [ Row( children: [ - Image.asset( - Assets.imagesRoseGift, - width: 21.w, - height: 21.w, - ), + Image.asset(Assets.imagesRoseGift, width: 21.w, height: 21.w), SizedBox(width: 8.w), Text( "9", style: TextStyle(fontSize: 13.w, color: Colors.white), ), SizedBox(width: 12.w), - Image.asset( - Assets.imagesRoseGift, - width: 68.w, - height: 33.w, - ), + Image.asset(Assets.imagesRoseGift, width: 68.w, height: 33.w), ], ), ValueListenableBuilder( - valueListenable: giftNum, + valueListenable: widget.giftNum, builder: (context, num, _) { return Row( children: [ @@ -236,8 +375,8 @@ class LiveGiftPopup extends StatelessWidget { label: "-", enabled: num > 1, onTap: () { - if (giftNum.value <= 1) return; - giftNum.value -= 1; + if (widget.giftNum.value <= 1) return; + widget.giftNum.value -= 1; }, ), SizedBox( @@ -253,7 +392,7 @@ class LiveGiftPopup extends StatelessWidget { label: "+", enabled: true, onTap: () { - giftNum.value += 1; + widget.giftNum.value += 1; }, ), SizedBox(width: 9.w), @@ -323,4 +462,3 @@ class LiveGiftPopup extends StatelessWidget { ); } } - diff --git a/lib/widget/live/live_room_gift_item.dart b/lib/widget/live/live_room_gift_item.dart index a74be2e..d1987c7 100644 --- a/lib/widget/live/live_room_gift_item.dart +++ b/lib/widget/live/live_room_gift_item.dart @@ -1,8 +1,10 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:dating_touchme_app/model/live/gift_product_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class LiveRoomGiftItem extends StatefulWidget { - final Map item; + final dynamic item; // 支持 Map 或 GiftProductModel final int active; final int index; final void Function(int) changeActive; @@ -19,6 +21,83 @@ class LiveRoomGiftItem extends StatefulWidget { } class _LiveRoomGiftItemState extends State { + // 判断是否为 GiftProductModel + bool get _isGiftProductModel => widget.item is GiftProductModel; + + // 获取图片 + Widget _buildImage() { + if (_isGiftProductModel) { + final gift = widget.item as GiftProductModel; + if (gift.mainPic.isNotEmpty) { + return CachedNetworkImage( + imageUrl: gift.mainPic, + width: 41.w, + height: 41.w, + fit: BoxFit.cover, + placeholder: (context, url) => Container( + width: 41.w, + height: 41.w, + color: Colors.grey[300], + child: Center( + child: SizedBox( + width: 20.w, + height: 20.w, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.grey[600], + ), + ), + ), + ), + errorWidget: (context, url, error) => Container( + width: 41.w, + height: 41.w, + color: Colors.grey[300], + child: Icon(Icons.error_outline, size: 20.w, color: Colors.grey), + ), + ); + } else { + return Container( + width: 41.w, + height: 41.w, + color: Colors.grey[300], + ); + } + } else { + final map = widget.item as Map; + final icon = map["icon"] as String?; + if (icon != null && icon.isNotEmpty) { + return Image.asset(icon, width: 41.w, height: 41.w); + } else { + return Container( + width: 41.w, + height: 41.w, + color: Colors.grey[300], + ); + } + } + } + + // 获取标题 + String _getTitle() { + if (_isGiftProductModel) { + return (widget.item as GiftProductModel).productTitle; + } else { + return (widget.item as Map)["title"]?.toString() ?? ''; + } + } + + // 获取价格 + String _getPrice() { + if (_isGiftProductModel) { + final price = (widget.item as GiftProductModel).unitSellingPrice; + return "${price.toInt()}支"; + } else { + final price = (widget.item as Map)["price"]; + return "${price ?? 0}支"; + } + } + @override Widget build(BuildContext context) { return InkWell( @@ -49,15 +128,17 @@ class _LiveRoomGiftItemState extends State { ), child: Column( children: [ - Image.asset(widget.item["icon"], width: 41.w, height: 41.w), + _buildImage(), SizedBox(height: 7.w), Text( - widget.item["title"], + _getTitle(), style: TextStyle(fontSize: 11.w, color: Colors.white), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), SizedBox(height: 1.w), Text( - "${widget.item["price"]}支", + _getPrice(), style: TextStyle( fontSize: 7.w, color: const Color.fromRGBO(144, 144, 144, 1),