This commit is contained in:
abu 2025-09-18 16:13:37 +08:00
parent a000a4aeea
commit 27001b12d6
9 changed files with 467 additions and 224 deletions

View File

@ -14,7 +14,12 @@ import 'package:loopin/utils/scan_code_type.dart';
import 'package:pretty_qr_code/pretty_qr_code.dart'; import 'package:pretty_qr_code/pretty_qr_code.dart';
class MyQrcode extends StatelessWidget { class MyQrcode extends StatelessWidget {
MyQrcode({super.key}); MyQrcode({
super.key,
this.prefix,
});
final String? prefix;
final controller = Get.find<ImUserInfoController>(); final controller = Get.find<ImUserInfoController>();
@ -22,12 +27,14 @@ class MyQrcode extends StatelessWidget {
final GlobalKey _qrKey = GlobalKey(); final GlobalKey _qrKey = GlobalKey();
/// Widget Uint8List /// Widget Uint8List
Future<Uint8List?> capturePng() async { Future<Uint8List?> capturePng(BuildContext context) async {
try { try {
final boundary = _qrKey.currentContext?.findRenderObject() as RenderRepaintBoundary?; final boundary = _qrKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) return null; if (boundary == null) return null;
final image = await boundary.toImage(pixelRatio: ui.window.devicePixelRatio); // final image = await boundary.toImage(pixelRatio: ui.window.devicePixelRatio);
final pixelRatio = View.of(context).devicePixelRatio;
final image = await boundary.toImage(pixelRatio: pixelRatio);
final byteData = await image.toByteData(format: ui.ImageByteFormat.png); final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData?.buffer.asUint8List(); return byteData?.buffer.asUint8List();
} catch (e) { } catch (e) {
@ -39,7 +46,7 @@ class MyQrcode extends StatelessWidget {
/// ///
Future<void> saveQrToGallery() async { Future<void> saveQrToGallery() async {
logger.w('长安了'); logger.w('长安了');
final pngBytes = await capturePng(); final pngBytes = await capturePng(Get.context!);
if (pngBytes == null) return; if (pngBytes == null) return;
final result = await ImageGallerySaverPlus.saveImage( final result = await ImageGallerySaverPlus.saveImage(
@ -67,6 +74,8 @@ class MyQrcode extends StatelessWidget {
face = CachedNetworkImageProvider(faceUrl); face = CachedNetworkImageProvider(faceUrl);
} }
final data = '${prefix ?? QrTypeCode.hym}$userID';
return GestureDetector( return GestureDetector(
onLongPress: () { onLongPress: () {
showModalBottomSheet( showModalBottomSheet(
@ -104,7 +113,7 @@ class MyQrcode extends StatelessWidget {
key: _qrKey, key: _qrKey,
child: PrettyQrView.data( child: PrettyQrView.data(
errorCorrectLevel: QrErrorCorrectLevel.H, // errorCorrectLevel: QrErrorCorrectLevel.H, //
data: '${QrTypeCode.hym}$userID', data: data, //
decoration: PrettyQrDecoration( decoration: PrettyQrDecoration(
background: Colors.transparent, background: Colors.transparent,
shape: const PrettyQrShape.custom( shape: const PrettyQrShape.custom(

View File

@ -1713,26 +1713,54 @@ class _ChatNoFriendState extends State<ChatNoFriend> with SingleTickerProviderSt
), ),
onPressed: () async { onPressed: () async {
// //
final res = await ImService.instance.followUser(userIDList: [arguments.value.userID!]); final ctl = Get.find<ChatController>();
if (res.success) {
final chatRes = await ImService.instance.followUser(userIDList: [arguments.value.userID!]);
if (chatRes.success) {
controller.isFriend.value = true; controller.isFriend.value = true;
controller.followType.value = 3; controller.followType.value = 3;
if (arguments.value.conversationGroupList?.isNotEmpty == true) { final res = await ImService.instance.getConversation(conversationID: 'c2c_${arguments.value.userID}');
// if (res.success) {
final ctl = Get.find<ChatController>(); V2TimConversation conversation = res.data;
ctl.removeNoFriend(conversationID: arguments.value.conversationID); if (conversation.conversationGroupList?.isNotEmpty ?? false) {
ctl.updateNoFriendMenu(); await ImService.instance.deleteConversationsFromGroup(
groupName: conversation.conversationGroupList!.first!,
conversationIDList: [conversation.conversationID],
);
await ctl.updateNoFriendMenu();
// chat地址
Get.offAllNamed(
'/chat',
arguments: arguments.value,
predicate: (route) {
// `/`
return route.settings.name == '/';
},
);
}
} }
// chat地址
Get.offAllNamed(
'/chat',
arguments: arguments.value,
predicate: (route) {
// `/`
return route.settings.name == '/';
},
);
} }
//
// final res = await ImService.instance.followUser(userIDList: [arguments.value.userID!]);
// if (res.success) {
// controller.isFriend.value = true;
// controller.followType.value = 3;
// if (arguments.value.conversationGroupList?.isNotEmpty == true) {
// //
// final ctl = Get.find<ChatController>();
// await ctl.removeNoFriend(conversationID: arguments.value.conversationID);
// ctl.updateNoFriendMenu();
// // chat地址
// Get.offAllNamed(
// '/chat',
// arguments: arguments.value,
// predicate: (route) {
// // `/`
// return route.settings.name == '/';
// },
// );
// }
// }
}, },
child: const Text('回关', style: TextStyle(color: Colors.white)), child: const Text('回关', style: TextStyle(color: Colors.white)),
), ),

View File

@ -107,11 +107,15 @@ class _AddFriendState extends State<AddFriend> {
suffixIcon: TextButton( suffixIcon: TextButton(
child: Text('搜索'), child: Text('搜索'),
onPressed: () { onPressed: () {
// //
final value = txtcontroller.text.trim(); final value = txtcontroller.text.trim();
if (value.isNotEmpty) { if (value.isNotEmpty) {
// //
focusNode.unfocus(); focusNode.unfocus();
Get.toNamed(
'/search-result',
arguments: {'searchWords': value, 'tab': 2},
);
} }
}, },
), ),
@ -124,8 +128,12 @@ class _AddFriendState extends State<AddFriend> {
), ),
onSubmitted: (value) { onSubmitted: (value) {
if (value.trim().isNotEmpty) { if (value.trim().isNotEmpty) {
focusNode.unfocus();
// //
focusNode.unfocus();
Get.toNamed(
'/search-result',
arguments: {'searchWords': value, 'tab': 2},
);
} }
}, },
), ),
@ -155,6 +163,7 @@ class _AddFriendState extends State<AddFriend> {
SizedBox(height: 20), SizedBox(height: 20),
//
MyQrcode(), MyQrcode(),
], ],
), ),

View File

@ -42,7 +42,6 @@ class _GoodsState extends State<Goods> {
double scrollOffset = 0; double scrollOffset = 0;
// //
List shareList = [ List shareList = [
{'icon': 'assets/images/share-wx.png', 'label': '好友'},
{'icon': 'assets/images/share-wx.png', 'label': '微信'}, {'icon': 'assets/images/share-wx.png', 'label': '微信'},
{'icon': 'assets/images/share-pyq.png', 'label': '朋友圈'}, {'icon': 'assets/images/share-pyq.png', 'label': '朋友圈'},
]; ];
@ -105,11 +104,12 @@ class _GoodsState extends State<Goods> {
} }
void handleShareClick(int index) { void handleShareClick(int index) {
final description = shopObj['describe']; // logger.w(shopObj);
if (index == 1) { final description = shopObj['describe'] ?? '未上传商品描述'; //
if (index == 0) {
// //
Wxsdk.shareToFriend(title: '快看看我分享的商品', description: description, webpageUrl: '${ShareType.shop.name}?id=${shopObj['id']}'); Wxsdk.shareToFriend(title: '快看看我分享的商品', description: description, webpageUrl: '${ShareType.shop.name}?id=${shopObj['id']}');
} else if (index == 2) { } else if (index == 1) {
// //
Wxsdk.shareToTimeline(title: '快看看我分享的商品', webpageUrl: '${ShareType.shop.name}?id=${shopObj['id']}'); Wxsdk.shareToTimeline(title: '快看看我分享的商品', webpageUrl: '${ShareType.shop.name}?id=${shopObj['id']}');
} }
@ -178,7 +178,9 @@ class _GoodsState extends State<Goods> {
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20.0), padding: EdgeInsets.symmetric(horizontal: 0, vertical: 20.0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return GestureDetector( return GestureDetector(
onTap: () => handleShareClick(index), onTap: () {
handleShareClick(index);
},
child: Container( child: Container(
width: 64, width: 64,
margin: EdgeInsets.symmetric(horizontal: 8.0), margin: EdgeInsets.symmetric(horizontal: 8.0),

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/components/my_qrcode.dart';
import 'package:loopin/pages/my/merchant/balance/balance.dart';
import 'package:loopin/pages/my/merchant/balance/controller.dart';
import 'package:loopin/utils/scan_code_type.dart';
class AllFunctionsPage extends StatefulWidget { class AllFunctionsPage extends StatefulWidget {
const AllFunctionsPage({super.key}); const AllFunctionsPage({super.key});
@ -29,6 +33,7 @@ class _AllFunctionsPageState extends State<AllFunctionsPage> {
] ]
}, },
]; ];
final ImUserInfoController controller = Get.find<ImUserInfoController>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -106,7 +111,12 @@ class _AllFunctionsPageState extends State<AllFunctionsPage> {
itemCount: (section['items'] as List).length, itemCount: (section['items'] as List).length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = (section['items'] as List)[index]; final item = (section['items'] as List)[index];
return _buildFunctionItem(item); final role = controller.role.value;
if (item['id'] == 'home_promo' && role != 4) {
return SizedBox();
} else {
return _buildFunctionItem(item);
}
}, },
), ),
@ -137,7 +147,7 @@ class _AllFunctionsPageState extends State<AllFunctionsPage> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( SizedBox(
width: 36, width: 36,
height: 36, height: 36,
child: Center( child: Center(
@ -176,18 +186,25 @@ class _AllFunctionsPageState extends State<AllFunctionsPage> {
Get.toNamed('/myOrder'); Get.toNamed('/myOrder');
break; break;
case 'home_balance': case 'home_balance':
showLogoutDialog(context); //
Get.put(BalanceController());
Get.to(() => Balance());
// showLogoutDialog(context);
break; break;
case 'home_withdraw': case 'home_withdraw':
Get.toNamed('/vloger'); Get.toNamed('/vloger');
break; break;
case 'home_promo': case 'home_promo':
// 广
Get.to(() => MyQrcode(
prefix: QrTypeCode.tgm,
));
break; break;
case 'more_seller_order': case 'more_seller_order':
Get.toNamed('/sellerOrder'); Get.toNamed('/sellerOrder');
break; break;
case 'more_seller_income': case 'more_seller_income':
Get.toNamed('/merchant/income'); Get.toNamed('/merchant/income');
break; break;
} }
} }
@ -211,10 +228,10 @@ class _AllFunctionsPageState extends State<AllFunctionsPage> {
}, },
child: const Text('取消', style: TextStyle(color: Colors.black54)), child: const Text('取消', style: TextStyle(color: Colors.black54)),
), ),
TextButton(onPressed: ()=>{}, child: const Text('退出登录', style: TextStyle(color: Colors.red))), TextButton(onPressed: () => {}, child: const Text('退出登录', style: TextStyle(color: Colors.red))),
], ],
); );
}, },
); );
} }
} }

View File

@ -5,15 +5,18 @@ import 'package:get/get.dart';
import 'package:get/get_rx/src/rx_typedefs/rx_typedefs.dart'; import 'package:get/get_rx/src/rx_typedefs/rx_typedefs.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart'; import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/im_service.dart'; import 'package:loopin/IM/im_service.dart';
import 'package:loopin/api/video_api.dart';
import 'package:loopin/api/common_api.dart'; import 'package:loopin/api/common_api.dart';
import 'package:loopin/utils/index.dart'; import 'package:loopin/api/video_api.dart';
import 'package:loopin/components/custom_sticky_header.dart'; import 'package:loopin/components/custom_sticky_header.dart';
import 'package:loopin/components/my_confirm.dart'; import 'package:loopin/components/my_confirm.dart';
import 'package:loopin/components/my_qrcode.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/components/only_down_scroll_physics.dart'; import 'package:loopin/components/only_down_scroll_physics.dart';
import 'package:loopin/controller/video_module_controller.dart'; import 'package:loopin/controller/video_module_controller.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart';
import 'package:loopin/utils/scan_code_type.dart';
import 'package:nested_scroll_view_plus/nested_scroll_view_plus.dart'; import 'package:nested_scroll_view_plus/nested_scroll_view_plus.dart';
import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:shirne_dialog/shirne_dialog.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_info.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_info.dart';
@ -131,17 +134,14 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
super.dispose(); super.dispose();
} }
// //
void getUserLikesCount() async { void getUserLikesCount() async {
try { try {
final resData = await Http.get(CommonApi.accountInfo); final resData = await Http.get(CommonApi.accountInfo);
if(resData != null && resData['code'] == 200){ if (resData != null && resData['code'] == 200) {
vlogLikeCount = resData['data']['vlogLikeCount']??0; vlogLikeCount = resData['data']['vlogLikeCount'] ?? 0;
}
} catch (e) {
} }
} catch (e) {}
} }
// //
@ -263,121 +263,20 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
} }
} }
//
// //
void deletePersonalVideo(videoId) async { void deletePersonalVideo(videoId) async {
logger.i('删除视频${videoId}'); logger.i('删除视频$videoId');
try { try {
final res = await Http.post('${VideoApi.deleteVideo}?id=${videoId}', data: {}); final res = await Http.post('${VideoApi.deleteVideo}?id=$videoId', data: {});
logger.i('删除成功响应${res}'); logger.i('删除成功响应$res');
if(res != null && res['code'] == 200){ if (res != null && res['code'] == 200) {
MyDialog.toast('删除成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200))); MyDialog.toast('删除成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200)));
loadData(0); loadData(0);
} }
} catch (e) { } catch (e) {}
logger.e('删除视频失败: $e');
}
} }
//
void showDeleteConfirmDialog(String videoId) {
Get.dialog(
Dialog(
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
//
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.red.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
Icons.delete_outline,
color: Colors.red,
size: 30,
),
),
SizedBox(height: 16),
//
Text(
'删除视频',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
SizedBox(height: 8),
//
Text(
'确认要删除这个视频吗?\n删除后将无法恢复',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
height: 1.4,
),
),
SizedBox(height: 24),
//
Row(
children: [
//
Expanded(
child: OutlinedButton(
onPressed: () => Get.back(),
style: OutlinedButton.styleFrom(
backgroundColor: Colors.transparent,
foregroundColor: Colors.grey[700],
side: BorderSide(color: Colors.grey[300]!),
padding: EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: Text('取消'),
),
),
SizedBox(width: 12),
//
Expanded(
child: ElevatedButton(
onPressed: () {
Get.back();
deletePersonalVideo(videoId);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: Text('确认删除'),
),
),
],
),
],
),
),
),
barrierDismissible: true,
);
}
// //
void qrcodeAlertDialog(BuildContext context) { void qrcodeAlertDialog(BuildContext context) {
showDialog( showDialog(
@ -397,13 +296,14 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Image.asset('assets/images/pic1.jpg', width: 250.0, fit: BoxFit.contain), MyQrcode(prefix: QrTypeCode.tgm)
const SizedBox(height: 15.0), // Image.asset('assets/images/pic1.jpg', width: 250.0, fit: BoxFit.contain),
const Text('扫一扫,加好友', // const SizedBox(height: 15.0),
style: TextStyle( // const Text('扫一扫,加好友',
color: Colors.white38, // style: TextStyle(
fontSize: 14.0, // color: Colors.white38,
)), // fontSize: 14.0,
// )),
], ],
), ),
), ),
@ -657,7 +557,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: _buildVdCard(listToShow[index],tabIndex), child: _buildVdCard(listToShow[index], tabIndex),
); );
}, },
childCount: listToShow.length, childCount: listToShow.length,
@ -683,48 +583,55 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
}); });
} }
Widget _buildVdCard(item,tabIndex) { Widget _buildVdCard(item, tabIndex) {
return InkWell( return InkWell(
onTap: () { onTap: () {
// //
Get.toNamed('/videoDetail', arguments: {'videoId': item['id']}); Get.toNamed('/videoDetail', arguments: {'videoId': item['id']});
}, },
onLongPress: () { onLongPress: () {
if(tabIndex == 0){ // if (tabIndex == 0) {
//
showModalBottomSheet( showModalBottomSheet(
context: Get.context!, context: Get.context!,
backgroundColor: Colors.white, backgroundColor: Colors.white,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)), borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
), ),
builder: (context) { builder: (context) {
return SafeArea( return SafeArea(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// ListTile( // ListTile(
// leading: const Icon(Icons.lock, color: Colors.black), // leading: const Icon(Icons.lock, color: Colors.black),
// title: const Text('设为私密', style: TextStyle(color: Colors.black)), // title: const Text('设为私密', style: TextStyle(color: Colors.black)),
// onTap: () { // onTap: () {
// Navigator.pop(context); // Navigator.pop(context);
// // TODO: // // TODO:
// }, // },
// ), // ),
ListTile( ListTile(
leading: const Icon(Icons.delete, color: Colors.redAccent), leading: const Icon(Icons.delete, color: Colors.redAccent),
title: const Text('删除视频', style: TextStyle(color: Colors.redAccent)), title: const Text('删除视频', style: TextStyle(color: Colors.redAccent)),
onTap: () async { onTap: () async {
Get.back(); Get.back();
showDeleteConfirmDialog(item['id']); final confirmed = await ConfirmDialog.show(
}, title: "提示",
), content: "确认要删除吗?",
], );
), if (confirmed == true) {
); Get.back();
}, deletePersonalVideo(item['id']);
); }
},
),
],
),
);
},
);
} }
}, },
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -830,35 +737,72 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
Row( Row(
children: [ children: [
// Obx // Obx
Obx(() { Obx(
final nickname = imUserInfoController?.nickname.value ?? ''; () {
return Container( final nickname = imUserInfoController?.nickname.value ?? '';
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), return Container(
decoration: BoxDecoration( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
color: Colors.black.withAlpha(76), decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: Colors.black.withAlpha(76),
), borderRadius: BorderRadius.circular(20),
child: Text(
nickname.isNotEmpty ? nickname : '昵称',
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
), ),
), child: Text(
); nickname.isNotEmpty ? nickname : '昵称',
}), style: const TextStyle(
const SizedBox(width: 8), fontSize: 20,
InkWell( fontWeight: FontWeight.bold,
onTap: () => qrcodeAlertDialog(context), color: Colors.white,
child: Container( ),
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5), ),
decoration: BoxDecoration( );
color: Colors.black.withAlpha(76), },
borderRadius: BorderRadius.circular(20), ),
),
child: const Icon(Icons.qr_code_outlined, size: 18, color: Colors.white), //
), Obx(
() {
// MERCHANT(2, "商家"),
// AGENT(3, "代理"),
// PLATFORM(4, "平台"),
// REFERENCE(5, "团长")
final role = imUserInfoController?.role.value;
if (role == 4) {
return Row(children: [
SizedBox(width: 8),
//
InkWell(
onTap: () => qrcodeAlertDialog(context),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
decoration: BoxDecoration(
color: Colors.black.withAlpha(176),
borderRadius: BorderRadius.circular(20),
),
child: Row(
children: [
Icon(
Icons.qr_code_outlined,
size: 18,
color: FStyle.secondaryColor,
),
SizedBox(width: 4),
Text(
'团长邀请码',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: FStyle.secondaryColor, //
),
)
],
),
),
),
]);
} else {
return const SizedBox();
}
},
), ),
], ],
), ),
@ -912,7 +856,11 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
// '已售${Utils.graceNumber(int.tryParse(vlogLikeCount?.toString() ?? '0') ?? 0)}', // '已售${Utils.graceNumber(int.tryParse(vlogLikeCount?.toString() ?? '0') ?? 0)}',
Column(children: [Text('${Utils.graceNumber(vlogLikeCount)}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), SizedBox(height: 3.0), Text('获赞')]), Column(children: [
Text(Utils.graceNumber(vlogLikeCount), style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)),
SizedBox(height: 3.0),
Text('获赞')
]),
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
// //

View File

@ -0,0 +1,125 @@
//
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/pages/my/merchant/balance/controller.dart';
class Balance extends StatefulWidget {
const Balance({super.key});
@override
State<Balance> createState() => _BalanceState();
}
class _BalanceState extends State<Balance> {
final controller = Get.put(BalanceController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("我的钱包")),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: Column(
children: [
// +
Container(
padding: const EdgeInsets.all(16),
color: Colors.blueAccent,
width: double.infinity,
child: Obx(() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"钱包余额",
style: TextStyle(color: Colors.white, fontSize: 16),
),
const SizedBox(height: 8),
Text(
"¥ ${controller.balance.value.toStringAsFixed(2)}",
style: const TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
ElevatedButton(
onPressed: () => controller.recharge(100.0),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
),
child: const Text("充值 100 元"),
),
],
);
}),
),
//
Expanded(
child: Obx(() {
return EasyRefresh.builder(
callLoadOverOffset: 20, //
callRefreshOverOffset: 20, //
header: ClassicHeader(
dragText: '下拉刷新',
armedText: '释放刷新',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
footer: ClassicFooter(
dragText: '加载更多',
armedText: '释放加载',
readyText: '加载中...',
processingText: '加载中...',
processedText: controller.hasMore.value ? '加载完成' : '没有更多了~',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
succeededIcon: controller.hasMore.value ? Icon(Icons.check_circle, color: Colors.green) : Icon(Icons.warning, color: Colors.orange),
),
onRefresh: () async {
await controller.getData(reset: true);
},
onLoad: () async {
if (controller.hasMore.value) {
await controller.getData();
}
},
childBuilder: (context, physics) {
return ListView.builder(
physics: physics,
itemCount: controller.data.length,
itemBuilder: (context, index) {
final tx = controller.data[index];
logger.w(tx.source);
return ListTile(
title: Text(tx.source),
subtitle: Text(tx.createTime),
trailing: Text(
"变动金额:${tx.changeType == 1 ? '+' : '-'}${tx.changeAmount}", //
style: TextStyle(
fontWeight: FontWeight.bold,
color: tx.changeType == 1 ? Colors.green : Colors.red,
),
),
);
},
);
},
);
}),
),
],
),
),
);
}
}

View File

@ -0,0 +1,56 @@
import 'package:get/get.dart';
import 'package:loopin/pages/my/merchant/balance/model.dart';
class BalanceController extends GetxController {
///
final balance = 0.0.obs;
final data = <AccountBill>[].obs;
int currentPage = 1;
final isLoading = false.obs;
///
var hasMore = true.obs;
@override
void onInit() {
super.onInit();
getData(reset: true);
}
///
void recharge(double amount) {
balance.value += amount;
//
}
///
Future<void> getData({bool reset = false}) async {
if (isLoading.value) return;
isLoading.value = true;
if (reset) {
currentPage = 1;
data.clear();
hasMore.value = true;
}
await Future.delayed(const Duration(seconds: 3)); //
List<AccountBill> newData = List.generate(
10,
(index) => AccountBill(id: index),
);
data.addAll(newData);
currentPage++;
if (currentPage > 3) {
hasMore.value = false;
}
isLoading.value = false;
}
}

View File

@ -0,0 +1,49 @@
class AccountBill {
final int id;
final int? memberId;
final int? accountId;
final double moneyBalance; //
final double beforeBalance; //
final double afterBalance; //
final double changeAmount; //
final int changeType; // 1 2
final String changeDesc; //
final String source; //
final String createTime; //
final int createBy;
final String updateTime;
AccountBill({
required this.id,
this.memberId,
this.accountId,
this.moneyBalance = 0.0,
this.beforeBalance = 0.0,
this.afterBalance = 0.0,
this.changeAmount = 0.0,
this.changeType = 1,
this.changeDesc = '',
this.source = '未知来源',
this.createTime = '',
this.createBy = 0,
this.updateTime = '',
});
factory AccountBill.fromJson(Map<String, dynamic> json) {
return AccountBill(
id: json['id'] ?? 0,
memberId: json['member_id'],
accountId: json['account_id'],
moneyBalance: (json['money_balance'] as num?)?.toDouble() ?? 0.0,
beforeBalance: (json['before_balance'] as num?)?.toDouble() ?? 0.0,
afterBalance: (json['after_balance'] as num?)?.toDouble() ?? 0.0,
changeAmount: (json['change_amount'] as num?)?.toDouble() ?? 0.0,
changeType: json['change_type'] ?? 1,
changeDesc: json['change_desc'] ?? '',
source: json['source'] ?? '未知来源',
createTime: json['create_time'] ?? '',
createBy: json['create_by'] ?? 0,
updateTime: json['update_time'] ?? '',
);
}
}