merge
This commit is contained in:
parent
39d621e5ad
commit
51ad2614f0
151
lib/IM/im_group_listeners.dart
Normal file
151
lib/IM/im_group_listeners.dart
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import 'package:logger/logger.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/enum/V2TimGroupListener.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_change_info.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_change_info.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member_info.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_topic_info.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/native_im/adapter/tim_manager.dart';
|
||||||
|
|
||||||
|
final logger = Logger();
|
||||||
|
|
||||||
|
class ImGroupListeners {
|
||||||
|
ImGroupListeners();
|
||||||
|
|
||||||
|
late final V2TimGroupListener _listener;
|
||||||
|
|
||||||
|
void register() {
|
||||||
|
_listener = V2TimGroupListener(
|
||||||
|
onGroupCreated: (String groupID) {
|
||||||
|
logger.i('群被创建: $groupID');
|
||||||
|
onGroupCreated(groupID);
|
||||||
|
},
|
||||||
|
onGroupDismissed: (String groupID, V2TimGroupMemberInfo opUser) {
|
||||||
|
logger.i('群组被解散: $groupID, 操作人: ${opUser.nickName}');
|
||||||
|
onGroupDismissed(groupID, opUser);
|
||||||
|
},
|
||||||
|
onGroupRecycled: (String groupID, V2TimGroupMemberInfo opUser) {
|
||||||
|
logger.i('群组被回收: $groupID, 操作人: ${opUser.nickName}');
|
||||||
|
},
|
||||||
|
onGroupInfoChanged: (String groupID, List<V2TimGroupChangeInfo?> changeInfos) {
|
||||||
|
logger.i('群信息变更: $groupID, $changeInfos');
|
||||||
|
onGroupInfoChanged(groupID, changeInfos);
|
||||||
|
},
|
||||||
|
onMemberEnter: (String groupID, List<V2TimGroupMemberInfo> memberList) {
|
||||||
|
logger.i('成员加入群 $groupID: ${memberList.map((e) => e.userID).join(', ')}');
|
||||||
|
onMemberEnter(groupID, memberList);
|
||||||
|
},
|
||||||
|
onMemberLeave: (String groupID, V2TimGroupMemberInfo member) {
|
||||||
|
logger.i('成员离开群 $groupID: ${member.userID}');
|
||||||
|
onMemberLeave(groupID, member);
|
||||||
|
},
|
||||||
|
onMemberInvited: (String groupID, V2TimGroupMemberInfo opUser, List<V2TimGroupMemberInfo> memberList) {
|
||||||
|
logger.i('成员被邀请 $groupID, inviter: ${opUser.userID}, members: ${memberList.map((e) => e.userID).join(', ')}');
|
||||||
|
onMemberInvited(groupID, memberList);
|
||||||
|
},
|
||||||
|
onMemberKicked: (String groupID, V2TimGroupMemberInfo opUser, List<V2TimGroupMemberInfo> memberList) {
|
||||||
|
logger.i('成员被踢 $groupID, opUser: ${opUser.userID}, members: ${memberList.map((e) => e.userID).join(', ')}');
|
||||||
|
onMemberKicked(groupID, memberList);
|
||||||
|
},
|
||||||
|
onMemberInfoChanged: (String groupID, List<V2TimGroupMemberChangeInfo> v2TIMGroupMemberChangeInfoList) {
|
||||||
|
logger.i('成员信息变更: $groupID, $v2TIMGroupMemberChangeInfoList');
|
||||||
|
onMemberInfoChanged(groupID, v2TIMGroupMemberChangeInfoList);
|
||||||
|
},
|
||||||
|
onQuitFromGroup: (String groupID) {
|
||||||
|
logger.i('主动退出群 $groupID');
|
||||||
|
onQuitFromGroup(groupID);
|
||||||
|
},
|
||||||
|
onReceiveJoinApplication: (String groupID, V2TimGroupMemberInfo member, String opReason) {
|
||||||
|
logger.i('收到入群申请 $groupID, member: ${member.userID}, reason: $opReason');
|
||||||
|
onReceiveJoinApplication(groupID, member, opReason);
|
||||||
|
},
|
||||||
|
onApplicationProcessed: (String groupID, V2TimGroupMemberInfo opUser, bool isAgreeJoin, String opReason) {
|
||||||
|
logger.i('入群申请已处理 $groupID, opUser: ${opUser.userID}, isAgree: $isAgreeJoin, reason: $opReason');
|
||||||
|
onApplicationProcessed(groupID, opUser, isAgreeJoin, opUser);
|
||||||
|
},
|
||||||
|
onGrantAdministrator: (String groupID, V2TimGroupMemberInfo opUser, List<V2TimGroupMemberInfo> memberList) {
|
||||||
|
logger.i('被授予管理员 $groupID, opUser: ${opUser.userID}, members: ${memberList.map((e) => e.userID).join(', ')}');
|
||||||
|
onGrantAdministrator(groupID, opUser, memberList);
|
||||||
|
},
|
||||||
|
onRevokeAdministrator: (String groupID, V2TimGroupMemberInfo opUser, List<V2TimGroupMemberInfo> memberList) {
|
||||||
|
logger.i('管理员权限被撤销 $groupID, opUser: ${opUser.userID}, members: ${memberList.map((e) => e.userID).join(', ')}');
|
||||||
|
onRevokeAdministrator(groupID, opUser, memberList);
|
||||||
|
},
|
||||||
|
onReceiveRESTCustomData: (String groupID, String customData) {
|
||||||
|
logger.i('收到自定义数据 $groupID: $customData');
|
||||||
|
onReceiveRESTCustomData(groupID, customData);
|
||||||
|
},
|
||||||
|
onGroupAttributeChanged: (String groupID, Map<String, String> groupAttributeMap) {
|
||||||
|
logger.i('群属性变更 $groupID: $groupAttributeMap');
|
||||||
|
},
|
||||||
|
onAllGroupMembersMuted: (String groupID, bool isMute) {
|
||||||
|
logger.i('全体禁言状态变更 $groupID: $isMute');
|
||||||
|
},
|
||||||
|
onMemberMarkChanged: (String groupID, List<String> memberIDList, int markType, bool enableMark) {
|
||||||
|
logger.i('成员标记变更 $groupID, members: ${memberIDList.join(', ')}, type: $markType, enable: $enableMark');
|
||||||
|
},
|
||||||
|
onGroupCounterChanged: (String groupID, String key, int newValue) {
|
||||||
|
logger.i('群计数器变更 $groupID, key: $key, value: $newValue');
|
||||||
|
},
|
||||||
|
onTopicCreated: (String groupID, String topicID) {
|
||||||
|
logger.i('话题创建 $groupID, topic: $topicID');
|
||||||
|
},
|
||||||
|
onTopicDeleted: (String groupID, List<String> topicIDList) {
|
||||||
|
logger.i('话题删除 $groupID, topics: ${topicIDList.join(', ')}');
|
||||||
|
},
|
||||||
|
onTopicInfoChanged: (String groupID, V2TimTopicInfo topicInfo) {
|
||||||
|
logger.i('话题信息变更 $groupID, topic: ${topicInfo.topicID}');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
TIMManager.instance.addGroupListener(listener: _listener);
|
||||||
|
|
||||||
|
logger.i("群组监听器已注册");
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister() {
|
||||||
|
TIMManager.instance.removeGroupListener(listener: _listener);
|
||||||
|
logger.i("群组监听器已移除");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新群被创建
|
||||||
|
void onGroupCreated(String groupID) {}
|
||||||
|
|
||||||
|
//解散群
|
||||||
|
void onGroupDismissed(String groupID, V2TimGroupMemberInfo opUser) {}
|
||||||
|
|
||||||
|
// 群信息变更
|
||||||
|
void onGroupInfoChanged(String groupID, List<V2TimGroupChangeInfo?> changeInfos) {}
|
||||||
|
|
||||||
|
// 成员加入群
|
||||||
|
void onMemberEnter(String groupID, List<V2TimGroupMemberInfo> memberList) {}
|
||||||
|
|
||||||
|
// 成员离开群
|
||||||
|
void onMemberLeave(String groupID, V2TimGroupMemberInfo member) {}
|
||||||
|
|
||||||
|
// 成员被邀请入群
|
||||||
|
void onMemberInvited(String groupID, List<V2TimGroupMemberInfo> memberList) {}
|
||||||
|
|
||||||
|
// 成员被踢出群
|
||||||
|
void onMemberKicked(String groupID, List<V2TimGroupMemberInfo> memberList) {}
|
||||||
|
|
||||||
|
// 成员信息变更
|
||||||
|
void onMemberInfoChanged(String groupID, List<V2TimGroupMemberChangeInfo> v2timGroupMemberChangeInfoList) {}
|
||||||
|
|
||||||
|
// 主动退出群
|
||||||
|
void onQuitFromGroup(String groupID) {}
|
||||||
|
|
||||||
|
// 入群申请
|
||||||
|
void onReceiveJoinApplication(String groupID, V2TimGroupMemberInfo member, String opReason) {}
|
||||||
|
|
||||||
|
// 处理入群申请处理结果
|
||||||
|
void onApplicationProcessed(String groupID, V2TimGroupMemberInfo opUser, bool isAgreeJoin, V2TimGroupMemberInfo opUser2) {}
|
||||||
|
|
||||||
|
// 册封管理员
|
||||||
|
void onGrantAdministrator(String groupID, V2TimGroupMemberInfo opUser, List<V2TimGroupMemberInfo> memberList) {}
|
||||||
|
|
||||||
|
// 移除管理员权限
|
||||||
|
void onRevokeAdministrator(String groupID, V2TimGroupMemberInfo opUser, List<V2TimGroupMemberInfo> memberList) {}
|
||||||
|
|
||||||
|
// 收到自定义消息
|
||||||
|
void onReceiveRESTCustomData(String groupID, String customData) {}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import 'package:loopin/IM/controller/tab_bar_controller.dart';
|
|||||||
import 'package:loopin/IM/global_badge.dart';
|
import 'package:loopin/IM/global_badge.dart';
|
||||||
import 'package:loopin/IM/im_core.dart';
|
import 'package:loopin/IM/im_core.dart';
|
||||||
import 'package:loopin/IM/im_friend_listeners.dart';
|
import 'package:loopin/IM/im_friend_listeners.dart';
|
||||||
|
import 'package:loopin/IM/im_group_listeners.dart';
|
||||||
import 'package:loopin/IM/im_message_listeners.dart';
|
import 'package:loopin/IM/im_message_listeners.dart';
|
||||||
import 'package:loopin/IM/im_result.dart';
|
import 'package:loopin/IM/im_result.dart';
|
||||||
import 'package:loopin/IM/push_service.dart';
|
import 'package:loopin/IM/push_service.dart';
|
||||||
@ -15,7 +16,9 @@ import 'package:loopin/utils/wxsdk.dart';
|
|||||||
import 'package:tencent_cloud_chat_sdk/enum/friend_application_type_enum.dart';
|
import 'package:tencent_cloud_chat_sdk/enum/friend_application_type_enum.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/enum/friend_response_type_enum.dart';
|
import 'package:tencent_cloud_chat_sdk/enum/friend_response_type_enum.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/enum/friend_type_enum.dart';
|
import 'package:tencent_cloud_chat_sdk/enum/friend_type_enum.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/enum/group_add_opt_enum.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/enum/history_msg_get_type_enum.dart';
|
import 'package:tencent_cloud_chat_sdk/enum/history_msg_get_type_enum.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/manager/v2_tim_group_manager.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_callback.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_callback.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation_filter.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation_filter.dart';
|
||||||
@ -27,6 +30,7 @@ import 'package:tencent_cloud_chat_sdk/models/v2_tim_follow_type_check_result.da
|
|||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info_result.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info_result.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_operation_result.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_operation_result.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_change_info.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_change_info.dart';
|
||||||
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_search_param.dart';
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message_search_param.dart';
|
||||||
@ -82,9 +86,13 @@ class ImService {
|
|||||||
// 登录成功后注册高级消息监听器
|
// 登录成功后注册高级消息监听器
|
||||||
final messageService = ImMessageListenerService();
|
final messageService = ImMessageListenerService();
|
||||||
Get.put<ImMessageListenerService>(messageService, permanent: true);
|
Get.put<ImMessageListenerService>(messageService, permanent: true);
|
||||||
|
|
||||||
await messageService.init();
|
await messageService.init();
|
||||||
|
|
||||||
|
// 注册群监听器
|
||||||
|
final groupListener = ImGroupListeners();
|
||||||
|
Get.put<ImGroupListeners>(groupListener, permanent: true);
|
||||||
|
groupListener.register();
|
||||||
|
|
||||||
// 注册关系链监听器
|
// 注册关系链监听器
|
||||||
final friendListener = ImFriendListeners();
|
final friendListener = ImFriendListeners();
|
||||||
Get.put<ImFriendListeners>(friendListener, permanent: true);
|
Get.put<ImFriendListeners>(friendListener, permanent: true);
|
||||||
@ -122,6 +130,10 @@ class ImService {
|
|||||||
Get.find<ImFriendListeners>().unregister();
|
Get.find<ImFriendListeners>().unregister();
|
||||||
await Get.delete<ImFriendListeners>(force: true);
|
await Get.delete<ImFriendListeners>(force: true);
|
||||||
|
|
||||||
|
// 移除群监听器
|
||||||
|
Get.find<ImGroupListeners>().unregister();
|
||||||
|
await Get.delete<ImGroupListeners>(force: true);
|
||||||
|
|
||||||
/// 清理tabbar
|
/// 清理tabbar
|
||||||
Get.find<TabBarController>().badgeMap.clear();
|
Get.find<TabBarController>().badgeMap.clear();
|
||||||
|
|
||||||
@ -721,4 +733,39 @@ class ImService {
|
|||||||
);
|
);
|
||||||
return ImResult.wrap(res);
|
return ImResult.wrap(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 创建群
|
||||||
|
Future<ImResult<String>> createGroup({
|
||||||
|
String? groupID,
|
||||||
|
required String groupType,
|
||||||
|
required String groupName,
|
||||||
|
String? notification,
|
||||||
|
String? introduction,
|
||||||
|
String? faceUrl,
|
||||||
|
bool? isAllMuted,
|
||||||
|
bool isSupportTopic = false,
|
||||||
|
GroupAddOptTypeEnum? addOpt,
|
||||||
|
List<V2TimGroupMember>? memberList,
|
||||||
|
GroupAddOptTypeEnum? approveOpt,
|
||||||
|
bool? isEnablePermissionGroup,
|
||||||
|
int? defaultPermissions,
|
||||||
|
}) async {
|
||||||
|
final res = await V2TIMGroupManager().createGroup(
|
||||||
|
groupID: groupID,
|
||||||
|
groupType: groupType,
|
||||||
|
groupName: groupName,
|
||||||
|
notification: notification, // 群公告
|
||||||
|
introduction: introduction, // 群简介
|
||||||
|
faceUrl: faceUrl, // 群头像
|
||||||
|
isAllMuted: isAllMuted, // true=全员禁言
|
||||||
|
isSupportTopic: isSupportTopic, // 是否支持话题
|
||||||
|
addOpt: addOpt, // 加群方式(非直播群有效)
|
||||||
|
memberList: memberList, // 初始群成员(不支持直播群)
|
||||||
|
approveOpt: approveOpt, //入群申请的处理方式(一般和 addOpt 配合使用)对 Work / Public 群有用
|
||||||
|
isEnablePermissionGroup: isEnablePermissionGroup, // 是否开启权限组
|
||||||
|
defaultPermissions: defaultPermissions, // 默认权限配置,搭配 isEnablePermissionGroup 使用
|
||||||
|
);
|
||||||
|
|
||||||
|
return ImResult.wrap(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,15 @@ class _LayoutState extends State<Layout> {
|
|||||||
VideoModuleController videoModuleController = Get.put(VideoModuleController());
|
VideoModuleController videoModuleController = Get.put(VideoModuleController());
|
||||||
|
|
||||||
// page页面
|
// page页面
|
||||||
List pageList = [VideoPage(), IndexPage(), UploadVideoPage(), ChatPage(), MyPage()];
|
List pageList = [
|
||||||
|
VideoPage(),
|
||||||
|
IndexPage(),
|
||||||
|
UploadVideoPage(
|
||||||
|
visible: false,
|
||||||
|
),
|
||||||
|
ChatPage(),
|
||||||
|
MyPage()
|
||||||
|
];
|
||||||
// tabs选项
|
// tabs选项
|
||||||
List navItems = [
|
List navItems = [
|
||||||
BottomNavigationBarItem(icon: Icon(Icons.play_circle_outline), label: '视频'),
|
BottomNavigationBarItem(icon: Icon(Icons.play_circle_outline), label: '视频'),
|
||||||
@ -131,7 +139,9 @@ class _LayoutState extends State<Layout> {
|
|||||||
),
|
),
|
||||||
Offstage(
|
Offstage(
|
||||||
offstage: videoModuleController.layoutPageCurrent.value != 2,
|
offstage: videoModuleController.layoutPageCurrent.value != 2,
|
||||||
child: UploadVideoPage(), // 不需要保活
|
child: UploadVideoPage(
|
||||||
|
visible: videoModuleController.layoutPageCurrent.value == 2,
|
||||||
|
), // 不需要保活
|
||||||
),
|
),
|
||||||
Offstage(
|
Offstage(
|
||||||
offstage: videoModuleController.layoutPageCurrent.value != 3,
|
offstage: videoModuleController.layoutPageCurrent.value != 3,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,16 @@
|
|||||||
|
// 创建群聊
|
||||||
import 'package:easy_refresh/easy_refresh.dart';
|
import 'package:easy_refresh/easy_refresh.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:loopin/IM/controller/im_user_info_controller.dart';
|
||||||
|
import 'package:loopin/IM/im_service.dart';
|
||||||
|
import 'package:loopin/components/network_or_asset_image.dart';
|
||||||
|
import 'package:loopin/styles/index.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/enum/group_member_role_enum.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/enum/group_type.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_member.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart';
|
||||||
|
import 'package:tencent_cloud_chat_sdk/web/compatible_models/v2_tim_conversation.dart';
|
||||||
|
|
||||||
class StartGroupChatPage extends StatefulWidget {
|
class StartGroupChatPage extends StatefulWidget {
|
||||||
const StartGroupChatPage({super.key});
|
const StartGroupChatPage({super.key});
|
||||||
@ -11,11 +22,12 @@ class StartGroupChatPage extends StatefulWidget {
|
|||||||
class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
|
||||||
List<Map<String, dynamic>> dataList = [];
|
List<V2TimUserFullInfo> dataList = [];
|
||||||
List<Map<String, dynamic>> filteredList = [];
|
List<V2TimUserFullInfo> filteredList = [];
|
||||||
Set<String> selectedIds = {}; // 已选中的用户 id
|
Set<String> selectedIds = {}; // 已选中的用户 id
|
||||||
int page = 1;
|
String page = '';
|
||||||
bool hasMore = true;
|
bool hasMore = true;
|
||||||
|
bool isLoading = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -29,29 +41,38 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分页获取陌关注列表数据
|
||||||
Future<void> _loadData({bool reset = false}) async {
|
Future<void> _loadData({bool reset = false}) async {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
page = 1;
|
page = '';
|
||||||
hasMore = true;
|
hasMore = true;
|
||||||
dataList.clear();
|
dataList.clear();
|
||||||
}
|
}
|
||||||
|
final res = await ImService.instance.getMutualFollowersList(
|
||||||
// 模拟网络请求
|
nextCursor: page,
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> newItems = List.generate(
|
|
||||||
10,
|
|
||||||
(index) => {"nickName": "用户 ${(page - 1) * 10 + index + 1}", "id": "${page}_$index"},
|
|
||||||
);
|
);
|
||||||
|
if (res.success && res.data != null) {
|
||||||
|
final userInfoList = res.data!.userFullInfoList ?? [];
|
||||||
|
final isFinished = res.data!.nextCursor == null || res.data!.nextCursor!.isEmpty;
|
||||||
|
logger.w('获取成功:${res.data!.nextCursor},是否还有更多:$isFinished');
|
||||||
|
|
||||||
if (newItems.isEmpty) {
|
if (isFinished) {
|
||||||
|
setState(() {
|
||||||
hasMore = false;
|
hasMore = false;
|
||||||
|
});
|
||||||
|
// 加载没数据了
|
||||||
|
page = '';
|
||||||
} else {
|
} else {
|
||||||
dataList.addAll(newItems);
|
page = res.data!.nextCursor ?? '';
|
||||||
page++;
|
|
||||||
}
|
}
|
||||||
|
logger.i('获取数据成功:$userInfoList');
|
||||||
|
setState(() {
|
||||||
|
dataList.addAll(userInfoList);
|
||||||
_applySearch(_searchController.text);
|
_applySearch(_searchController.text);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
logger.e('获取数据失败:${res.desc}');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _applySearch(String query) {
|
void _applySearch(String query) {
|
||||||
@ -59,7 +80,7 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
filteredList = List.from(dataList);
|
filteredList = List.from(dataList);
|
||||||
} else {
|
} else {
|
||||||
filteredList = dataList.where((item) => item["nickName"].toString().contains(query.trim())).toList();
|
filteredList = dataList.where((item) => (item.nickName ?? '').contains(query.trim())).toList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -74,6 +95,77 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 创建群聊
|
||||||
|
void createGroup(Set<String> selectedIds) async {
|
||||||
|
// dataList是原始数据List<V2TimUserFullInfo> dataList = [];
|
||||||
|
// 通过dataList和selectedIds来构建memberList
|
||||||
|
final ctl = Get.find<ImUserInfoController>();
|
||||||
|
final memberList = dataList
|
||||||
|
.where((user) => selectedIds.contains(user.userID))
|
||||||
|
.map((user) => V2TimGroupMember(
|
||||||
|
userID: user.userID!,
|
||||||
|
role: GroupMemberRoleTypeEnum.V2TIM_GROUP_MEMBER_ROLE_MEMBER, // 加群的成员角色(默认普通成员)
|
||||||
|
))
|
||||||
|
.toList();
|
||||||
|
final self = V2TimGroupMember(
|
||||||
|
userID: ctl.userID.value,
|
||||||
|
role: GroupMemberRoleTypeEnum.V2TIM_GROUP_MEMBER_ROLE_OWNER, // 建群的人为群主
|
||||||
|
);
|
||||||
|
memberList.insert(0, self);
|
||||||
|
final groupName = buildGroupName(selectedIds);
|
||||||
|
final res = await ImService.instance.createGroup(groupType: GroupType.Work, groupName: groupName, memberList: memberList);
|
||||||
|
if (res.success) {
|
||||||
|
final groupID = res.data;
|
||||||
|
logger.w(groupID);
|
||||||
|
final V2TimConversation conv = V2TimConversation(conversationID: 'group_$groupID');
|
||||||
|
conv.showName = groupName;
|
||||||
|
Get.toNamed('/chatGroup', arguments: conv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建默认群名称
|
||||||
|
String buildGroupName(Set<String> selectedIds) {
|
||||||
|
int maxLength = 20;
|
||||||
|
// 根据 selectedIds 找到对应的昵称
|
||||||
|
final memberNicknames = selectedIds.map((id) {
|
||||||
|
final user = dataList.firstWhere(
|
||||||
|
(u) => u.userID == id,
|
||||||
|
orElse: () => V2TimUserFullInfo(userID: id, nickName: id),
|
||||||
|
);
|
||||||
|
return user.nickName?.isNotEmpty == true ? user.nickName! : user.userID;
|
||||||
|
}).toList();
|
||||||
|
final ctl = Get.find<ImUserInfoController>();
|
||||||
|
// 插入群主的信息
|
||||||
|
memberNicknames.insert(0, ctl.nickname.value);
|
||||||
|
|
||||||
|
// 拼接成群名
|
||||||
|
String name = memberNicknames.join("、");
|
||||||
|
|
||||||
|
// 如果超过长度限制,截断
|
||||||
|
if (name.length > maxLength) {
|
||||||
|
name = "${name.substring(0, maxLength - 3)}...";
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空状态提示
|
||||||
|
Widget _emptyTip(String text) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Image.asset('assets/images/empty.png', width: 100),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: const TextStyle(color: Colors.grey, fontSize: 13),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildCard({
|
Widget _buildCard({
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
required String title,
|
required String title,
|
||||||
@ -96,7 +188,6 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
// backgroundColor: Colors.white,
|
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
forceMaterialTransparency: true,
|
forceMaterialTransparency: true,
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
@ -122,23 +213,23 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
icon: Icons.public,
|
icon: Icons.public,
|
||||||
title: "创建公开群",
|
title: "创建公开群",
|
||||||
onTap: () {
|
onTap: () {
|
||||||
print("跳转到 创建公开群");
|
logger.w("跳转到 创建公开群");
|
||||||
},
|
|
||||||
),
|
|
||||||
_buildCard(
|
|
||||||
icon: Icons.group,
|
|
||||||
title: "创建好友群",
|
|
||||||
onTap: () {
|
|
||||||
print("跳转到 创建好友群");
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
// _buildCard(
|
||||||
|
// icon: Icons.group,
|
||||||
|
// title: "创建好友群",
|
||||||
|
// onTap: () {
|
||||||
|
// logger.w("跳转到 创建好友群");
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
|
||||||
// 下半部分 - 搜索框 + 列表
|
// 下半部分
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -161,24 +252,50 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
// 列表
|
// 列表
|
||||||
Expanded(
|
Expanded(
|
||||||
child: EasyRefresh(
|
child: EasyRefresh(
|
||||||
|
header: ClassicHeader(
|
||||||
|
dragText: '下拉刷新',
|
||||||
|
armedText: '释放刷新',
|
||||||
|
readyText: '加载中...',
|
||||||
|
processingText: '加载中...',
|
||||||
|
processedText: '加载完成',
|
||||||
|
failedText: '加载失败,请重试',
|
||||||
|
messageText: '最后更新于 %T',
|
||||||
|
),
|
||||||
|
footer: ClassicFooter(
|
||||||
|
dragText: '加载更多',
|
||||||
|
armedText: '释放加载',
|
||||||
|
readyText: '加载中...',
|
||||||
|
processingText: '加载中...',
|
||||||
|
processedText: hasMore ? '加载完成' : '没有更多了~',
|
||||||
|
failedText: '加载失败,请重试',
|
||||||
|
messageText: '最后更新于 %T',
|
||||||
|
),
|
||||||
onRefresh: () async => _loadData(reset: true),
|
onRefresh: () async => _loadData(reset: true),
|
||||||
onLoad: () async {
|
onLoad: () async {
|
||||||
if (hasMore) await _loadData();
|
if (hasMore) await _loadData();
|
||||||
},
|
},
|
||||||
child: ListView.builder(
|
child: filteredList.isEmpty
|
||||||
|
? _emptyTip('暂无数据')
|
||||||
|
: ListView.builder(
|
||||||
itemCount: filteredList.length,
|
itemCount: filteredList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = filteredList[index];
|
final item = filteredList[index];
|
||||||
final id = item["id"] as String;
|
final id = item.userID as String;
|
||||||
final isSelected = selectedIds.contains(id);
|
final isSelected = selectedIds.contains(id);
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: CircleAvatar(
|
leading: ClipOval(
|
||||||
child: Text(item["nickName"].substring(0, 1)),
|
// child: Text((item.nickName ?? '未知').substring(0, 1)),
|
||||||
|
child: NetworkOrAssetImage(
|
||||||
|
imageUrl: item.faceUrl,
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
),
|
),
|
||||||
title: Text(item["nickName"]),
|
),
|
||||||
|
title: Text(item.nickName ?? '未知'),
|
||||||
trailing: Checkbox(
|
trailing: Checkbox(
|
||||||
value: isSelected,
|
value: isSelected,
|
||||||
|
shape: const CircleBorder(),
|
||||||
onChanged: (_) => _toggleSelection(id),
|
onChanged: (_) => _toggleSelection(id),
|
||||||
),
|
),
|
||||||
onTap: () => _toggleSelection(id),
|
onTap: () => _toggleSelection(id),
|
||||||
@ -197,23 +314,37 @@ class _StartGroupChatPageState extends State<StartGroupChatPage> {
|
|||||||
bottomNavigationBar: SafeArea(
|
bottomNavigationBar: SafeArea(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12.0),
|
padding: const EdgeInsets.all(12.0),
|
||||||
child: ElevatedButton(
|
child: TweenAnimationBuilder<Color?>(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
tween: ColorTween(
|
||||||
|
begin: Colors.grey,
|
||||||
|
end: selectedIds.isEmpty ? Colors.grey : FStyle.primaryColor,
|
||||||
|
),
|
||||||
|
builder: (context, bgColor, _) {
|
||||||
|
return ElevatedButton(
|
||||||
onPressed: selectedIds.isEmpty
|
onPressed: selectedIds.isEmpty
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
print("选择了用户:$selectedIds");
|
logger.w("选择了用户:$selectedIds");
|
||||||
|
createGroup(selectedIds);
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size.fromHeight(50),
|
minimumSize: const Size.fromHeight(50),
|
||||||
backgroundColor: selectedIds.isEmpty ? Colors.grey : Colors.blue,
|
backgroundColor: bgColor,
|
||||||
),
|
shape: const StadiumBorder(), // 胶囊形状
|
||||||
child: const Text(
|
|
||||||
"发起聊天",
|
|
||||||
style: TextStyle(fontSize: 16),
|
|
||||||
),
|
),
|
||||||
|
child: AnimatedDefaultTextStyle(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: selectedIds.isEmpty ? Colors.black : Colors.white,
|
||||||
),
|
),
|
||||||
|
child: const Text("发起聊天"),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -853,7 +853,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
_buildOrderIcon('assets/images/ico_order.png', '订单', () {
|
_buildOrderIcon('assets/images/ico_order.png', '订单', () {
|
||||||
Get.toNamed('/order');
|
Get.toNamed('/sellerOrder');
|
||||||
}),
|
}),
|
||||||
_buildOrderIcon('assets/images/ico_dhx.png', '余额logout', () {
|
_buildOrderIcon('assets/images/ico_dhx.png', '余额logout', () {
|
||||||
showLogoutDialog(context);
|
showLogoutDialog(context);
|
||||||
|
@ -18,8 +18,8 @@ class _OrderState extends State<Order> with SingleTickerProviderStateMixin {
|
|||||||
|
|
||||||
List tabList = [
|
List tabList = [
|
||||||
{'name': "全部"},
|
{'name': "全部"},
|
||||||
{'name': "待付款", 'badge': 1},
|
{'name': "待退款", 'badge': 1},
|
||||||
{'name': "待核销"},
|
{'name': "待核销", 'badge': 1},
|
||||||
{'name': "已完成"},
|
{'name': "已完成"},
|
||||||
{'name': "取消"}
|
{'name': "取消"}
|
||||||
];
|
];
|
||||||
@ -65,28 +65,33 @@ class _OrderState extends State<Order> with SingleTickerProviderStateMixin {
|
|||||||
forceMaterialTransparency: true,
|
forceMaterialTransparency: true,
|
||||||
titleSpacing: 1.0,
|
titleSpacing: 1.0,
|
||||||
title: Container(
|
title: Container(
|
||||||
height: 35.0,
|
// height: 35.0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[50],
|
// color: Colors.grey[50],
|
||||||
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(30.0),
|
borderRadius: BorderRadius.circular(30.0),
|
||||||
),
|
),
|
||||||
child: TextField(
|
child: Text(
|
||||||
decoration: InputDecoration(
|
'订单',
|
||||||
isDense: true,
|
style: TextStyle(fontSize: 18),
|
||||||
hintText: "搜索订单",
|
|
||||||
hintStyle: TextStyle(color: Colors.black38, fontSize: 14.0),
|
|
||||||
prefixIcon: Icon(
|
|
||||||
Icons.search,
|
|
||||||
color: Colors.black38,
|
|
||||||
size: 21.0,
|
|
||||||
),
|
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10.0),
|
|
||||||
border: OutlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(30.0))),
|
|
||||||
cursorColor: Colors.black,
|
|
||||||
onChanged: (val) {
|
|
||||||
debugPrint(val);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
// child: TextField(
|
||||||
|
// decoration: InputDecoration(
|
||||||
|
// isDense: true,
|
||||||
|
// hintText: "搜索订单",
|
||||||
|
// hintStyle: TextStyle(color: Colors.black38, fontSize: 14.0),
|
||||||
|
// prefixIcon: Icon(
|
||||||
|
// Icons.search,
|
||||||
|
// color: Colors.black38,
|
||||||
|
// size: 21.0,
|
||||||
|
// ),
|
||||||
|
// contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10.0),
|
||||||
|
// border: OutlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(30.0))),
|
||||||
|
// cursorColor: Colors.black,
|
||||||
|
// onChanged: (val) {
|
||||||
|
// debugPrint(val);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
),
|
),
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
preferredSize: Size.fromHeight(45.0),
|
preferredSize: Size.fromHeight(45.0),
|
||||||
@ -102,7 +107,13 @@ class _OrderState extends State<Order> with SingleTickerProviderStateMixin {
|
|||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
count: item['badge'] ?? 0,
|
count: item['badge'] ?? 0,
|
||||||
isLabelVisible: item['badge'] != null ? true : false,
|
isLabelVisible: item['badge'] != null ? true : false,
|
||||||
child: Text(item['name'])),
|
child: Text(
|
||||||
|
item['name'],
|
||||||
|
style: TextStyle(fontSize: 16),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
softWrap: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
isScrollable: false,
|
isScrollable: false,
|
||||||
@ -129,7 +140,9 @@ class _OrderState extends State<Order> with SingleTickerProviderStateMixin {
|
|||||||
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
|
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.grey[50],
|
color: Colors.grey[50],
|
||||||
child: TabBarView(controller: tabController, children: [
|
child: TabBarView(
|
||||||
|
controller: tabController,
|
||||||
|
children: [
|
||||||
ListView(
|
ListView(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
physics: BouncingScrollPhysics(),
|
physics: BouncingScrollPhysics(),
|
||||||
@ -304,13 +317,186 @@ class _OrderState extends State<Order> with SingleTickerProviderStateMixin {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
emptyTip(),
|
emptyTip(),
|
||||||
|
hexiao(),
|
||||||
emptyTip(),
|
emptyTip(),
|
||||||
emptyTip(),
|
emptyTip(),
|
||||||
emptyTip(),
|
emptyTip(),
|
||||||
emptyTip(),
|
],
|
||||||
]),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget hexiao() {
|
||||||
|
return ListView(
|
||||||
|
physics: BouncingScrollPhysics(),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 10.0),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withAlpha(10),
|
||||||
|
offset: Offset(0.0, 1.0),
|
||||||
|
blurRadius: 1.0,
|
||||||
|
spreadRadius: 0.0,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Column(
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/avatar/img11.jpg',
|
||||||
|
width: 25.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('老白干自营旗舰店'),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
color: Colors.grey,
|
||||||
|
size: 12.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'待付款',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Image.network(
|
||||||
|
'https://img13.360buyimg.com/n1/jfs/t1/263909/5/4187/123220/676eb220F3e481086/0cee829b1894fc4c.jpg',
|
||||||
|
width: 80.0,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'茅台(MOUTAI)飞天 53度 酱香型白酒 500ml*2 海外版送礼袋年货送礼',
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'¥3800',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'x10',
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// 提示信息
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[50],
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(children: [
|
||||||
|
TextSpan(text: '实付款: '),
|
||||||
|
TextSpan(
|
||||||
|
text: '¥38000',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 按钮组
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('取消订单'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('去支付'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Color(0xFF10B9FC)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('评价'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('申请退款'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Color(0xFFFCBE13)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('联系客服'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('删除'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed('/order/detail');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
588
lib/pages/order/seller.dart
Normal file
588
lib/pages/order/seller.dart
Normal file
@ -0,0 +1,588 @@
|
|||||||
|
/// 商家的订单
|
||||||
|
library;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import '../../behavior/custom_scroll_behavior.dart';
|
||||||
|
|
||||||
|
class Seller extends StatefulWidget {
|
||||||
|
const Seller({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Seller> createState() => _SellerState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SellerState extends State<Seller> with SingleTickerProviderStateMixin {
|
||||||
|
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
|
||||||
|
|
||||||
|
List tabList = [
|
||||||
|
{'name': "全部"},
|
||||||
|
{'name': "已退款", 'badge': 1},
|
||||||
|
{'name': "待核销", 'badge': 1},
|
||||||
|
{'name': "已完成"},
|
||||||
|
{'name': "取消"}
|
||||||
|
];
|
||||||
|
|
||||||
|
late ScrollController scrollController = ScrollController();
|
||||||
|
late TabController tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this);
|
||||||
|
|
||||||
|
Widget emptyTip() {
|
||||||
|
return Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/images/empty.png',
|
||||||
|
width: 100.0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'还没有相关订单~',
|
||||||
|
style: TextStyle(color: Colors.grey, fontSize: 12.0),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
scrollController.dispose();
|
||||||
|
tabController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: AppBar(
|
||||||
|
titleSpacing: 1.0,
|
||||||
|
title: Text(
|
||||||
|
'商家订单',
|
||||||
|
style: TextStyle(fontSize: 18),
|
||||||
|
),
|
||||||
|
bottom: PreferredSize(
|
||||||
|
preferredSize: Size.fromHeight(45.0),
|
||||||
|
child: Row(children: [
|
||||||
|
Expanded(
|
||||||
|
child: TabBar(
|
||||||
|
controller: tabController,
|
||||||
|
tabs: tabList
|
||||||
|
.map((item) => Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
height: 45.0,
|
||||||
|
child: Badge.count(
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
offset: Offset(14, -4),
|
||||||
|
count: item['badge'] ?? 0,
|
||||||
|
isLabelVisible: item['badge'] != null ? true : false,
|
||||||
|
child: Text(
|
||||||
|
item['name'],
|
||||||
|
style: TextStyle(fontSize: 16),
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
softWrap: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
isScrollable: false,
|
||||||
|
overlayColor: WidgetStateProperty.all(Colors.transparent),
|
||||||
|
unselectedLabelColor: Colors.black87,
|
||||||
|
labelColor: Color(0xFFFF5000),
|
||||||
|
indicator: UnderlineTabIndicator(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
borderSide: BorderSide(color: Color(0xFFFF5000), width: 2.0),
|
||||||
|
),
|
||||||
|
indicatorSize: TabBarIndicatorSize.tab,
|
||||||
|
unselectedLabelStyle: TextStyle(fontSize: 16.0, fontFamily: 'Microsoft YaHei'),
|
||||||
|
labelStyle: TextStyle(fontSize: 18.0, fontFamily: 'Microsoft YaHei', fontWeight: FontWeight.w700),
|
||||||
|
dividerHeight: 0,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
|
labelPadding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||||
|
indicatorPadding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 5.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: ScrollConfiguration(
|
||||||
|
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.grey[50],
|
||||||
|
child: TabBarView(
|
||||||
|
controller: tabController,
|
||||||
|
children: [
|
||||||
|
ListView(
|
||||||
|
controller: scrollController,
|
||||||
|
physics: BouncingScrollPhysics(),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 10.0),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withAlpha(10),
|
||||||
|
offset: Offset(0.0, 1.0),
|
||||||
|
blurRadius: 1.0,
|
||||||
|
spreadRadius: 0.0,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Column(
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/avatar/img11.jpg',
|
||||||
|
width: 25.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('人人乐超市'),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
color: Colors.grey,
|
||||||
|
size: 12.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'待付款',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Image.network(
|
||||||
|
'https://img13.360buyimg.com/n1/jfs/t1/263909/5/4187/123220/676eb220F3e481086/0cee829b1894fc4c.jpg',
|
||||||
|
width: 80.0,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'茅台(MOUTAI)飞天 53度 酱香型白酒 500ml*2 海外版送礼袋年货送礼',
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'¥3800',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'x10',
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// 提示信息
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[50],
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(children: [
|
||||||
|
TextSpan(text: '实付款: '),
|
||||||
|
TextSpan(
|
||||||
|
text: '¥38000',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 按钮组
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('取消订单'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('去支付'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStateProperty.all(Color(0xFF10B9FC)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('评价'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('申请退款'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: WidgetStateProperty.all(Color(0xFFFCBE13)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('联系客服'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('删除'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed('/order/detail');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
emptyTip(),
|
||||||
|
hexiao(),
|
||||||
|
finish(),
|
||||||
|
emptyTip(),
|
||||||
|
emptyTip(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget finish() {
|
||||||
|
return ListView(
|
||||||
|
physics: BouncingScrollPhysics(),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 10.0),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withAlpha(10),
|
||||||
|
offset: Offset(0.0, 1.0),
|
||||||
|
blurRadius: 1.0,
|
||||||
|
spreadRadius: 0.0,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Column(
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/avatar/img12.jpg',
|
||||||
|
width: 25.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('人人乐超市'),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
color: Colors.grey,
|
||||||
|
size: 12.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'已完成',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Image.network(
|
||||||
|
'https://img13.360buyimg.com/n1/jfs/t1/263909/5/4187/123220/676eb220F3e481086/0cee829b1894fc4c.jpg',
|
||||||
|
width: 80.0,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'茅台(MOUTAI)飞天 53度 酱香型白酒 500ml 海外版送礼袋年货送礼',
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'¥1900',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// 提示信息
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(children: [
|
||||||
|
TextSpan(text: '实付款: '),
|
||||||
|
TextSpan(
|
||||||
|
text: '¥1880',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed('/order/detail');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget hexiao() {
|
||||||
|
return ListView(
|
||||||
|
physics: BouncingScrollPhysics(),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(bottom: 10.0),
|
||||||
|
padding: EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withAlpha(10),
|
||||||
|
offset: Offset(0.0, 1.0),
|
||||||
|
blurRadius: 1.0,
|
||||||
|
spreadRadius: 0.0,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
child: Column(
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
ClipOval(
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/avatar/img11.jpg',
|
||||||
|
width: 25.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('老白干自营旗舰店'),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios_rounded,
|
||||||
|
color: Colors.grey,
|
||||||
|
size: 12.0,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'待付款',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 10.0,
|
||||||
|
children: [
|
||||||
|
Image.network(
|
||||||
|
'https://img13.360buyimg.com/n1/jfs/t1/263909/5/4187/123220/676eb220F3e481086/0cee829b1894fc4c.jpg',
|
||||||
|
width: 80.0,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
spacing: 5.0,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'茅台(MOUTAI)飞天 53度 酱香型白酒 500ml*2 海外版送礼袋年货送礼',
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'¥3800',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
|
Text(
|
||||||
|
'x10',
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// 提示信息
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[50],
|
||||||
|
borderRadius: BorderRadius.circular(5.0),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Spacer(),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(children: [
|
||||||
|
TextSpan(text: '实付款: '),
|
||||||
|
TextSpan(
|
||||||
|
text: '¥38000',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 按钮组
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('取消订单'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('去支付'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Color(0xFF10B9FC)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('评价'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('申请退款'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Color(0xFFFCBE13)), foregroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('联系客服'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Row(
|
||||||
|
spacing: 10.0,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
|
||||||
|
child: Text('删除'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed('/order/detail');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.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/common_api.dart';
|
import 'package:loopin/api/common_api.dart';
|
||||||
import 'package:loopin/api/video_api.dart';
|
import 'package:loopin/api/video_api.dart';
|
||||||
@ -13,7 +14,8 @@ import 'package:loopin/utils/snapshot.dart';
|
|||||||
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
||||||
|
|
||||||
class UploadVideoPage extends StatefulWidget {
|
class UploadVideoPage extends StatefulWidget {
|
||||||
const UploadVideoPage({super.key});
|
final bool visible;
|
||||||
|
const UploadVideoPage({super.key, required this.visible});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<UploadVideoPage> createState() => _UploadVideoPageState();
|
State<UploadVideoPage> createState() => _UploadVideoPageState();
|
||||||
@ -36,13 +38,22 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
final videoPath = ''.obs; // 本地视频地址
|
final videoPath = ''.obs; // 本地视频地址
|
||||||
final imgPath = ''.obs; //本地图片地址
|
final imgPath = ''.obs; //本地图片地址
|
||||||
final snapshot = ''.obs;
|
final snapshot = ''.obs;
|
||||||
|
// 文件id
|
||||||
|
final fileId = ''.obs;
|
||||||
|
|
||||||
final FocusNode descFocusNode = FocusNode();
|
late final FocusNode descFocusNode;
|
||||||
|
|
||||||
final TextEditingController descriptionController = TextEditingController();
|
late TextEditingController descriptionController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
descFocusNode = FocusNode();
|
||||||
|
descriptionController = TextEditingController();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> pickVideo() async {
|
Future<void> pickVideo() async {
|
||||||
FocusScope.of(context).unfocus();
|
descFocusNode.unfocus();
|
||||||
|
|
||||||
final result = await PhotoManager.requestPermissionExtend();
|
final result = await PhotoManager.requestPermissionExtend();
|
||||||
|
|
||||||
@ -82,7 +93,7 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
|
|
||||||
// 选择封面图
|
// 选择封面图
|
||||||
Future<void> pickCoverImage() async {
|
Future<void> pickCoverImage() async {
|
||||||
FocusScope.of(context).unfocus();
|
descFocusNode.unfocus();
|
||||||
|
|
||||||
final result = await PhotoManager.requestPermissionExtend();
|
final result = await PhotoManager.requestPermissionExtend();
|
||||||
|
|
||||||
@ -169,6 +180,7 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
status.value = '上传中...';
|
status.value = '上传中...';
|
||||||
videoPath.value = file.path;
|
videoPath.value = file.path;
|
||||||
logger.w(videoPath.value);
|
logger.w(videoPath.value);
|
||||||
|
// vwidth.value = file.width;
|
||||||
|
|
||||||
snapshot.value = (await generateVideoThumbnail(file.path))!;
|
snapshot.value = (await generateVideoThumbnail(file.path))!;
|
||||||
logger.w(snapshot.value);
|
logger.w(snapshot.value);
|
||||||
@ -180,19 +192,25 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
fileKey: 'file',
|
fileKey: 'file',
|
||||||
onSendProgress: (sent, total) {
|
onSendProgress: (sent, total) {
|
||||||
if (total > 0) {
|
if (total > 0) {
|
||||||
uploadProgress.value = sent / total;
|
final pro = sent / total;
|
||||||
|
uploadProgress.value = pro.clamp(0, 0.999);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
logger.w('上传结果$res');
|
||||||
uploadedVideoUrl.value = res['data']['url'];
|
uploadedVideoUrl.value = res['data']['url'];
|
||||||
|
fileId.value = res['data']['ossId'];
|
||||||
status.value = '上传成功';
|
status.value = '上传成功';
|
||||||
} catch (e) {
|
|
||||||
descFocusNode.unfocus();
|
descFocusNode.unfocus();
|
||||||
|
uploading.value = false;
|
||||||
|
} catch (e) {
|
||||||
if (e is SocketException) {
|
if (e is SocketException) {
|
||||||
status.value = '网络错误,请检查连接';
|
status.value = '网络错误,请检查连接';
|
||||||
} else {
|
} else {
|
||||||
status.value = '上传失败: ${e.toString()}';
|
status.value = '上传失败: ${e.toString()}';
|
||||||
}
|
}
|
||||||
|
logger.e(e);
|
||||||
|
descFocusNode.unfocus();
|
||||||
} finally {
|
} finally {
|
||||||
descFocusNode.unfocus();
|
descFocusNode.unfocus();
|
||||||
uploading.value = false;
|
uploading.value = false;
|
||||||
@ -203,8 +221,8 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
Future<void> submitForm() async {
|
Future<void> submitForm() async {
|
||||||
logger.w(descriptionController.text);
|
logger.w(descriptionController.text);
|
||||||
|
|
||||||
FocusScope.of(context).unfocus();
|
descFocusNode.unfocus();
|
||||||
if (uploadedVideoUrl.value.isEmpty) {
|
if (fileId.value.isEmpty) {
|
||||||
Get.snackbar('请先上传视频', '未检测到上传的视频');
|
Get.snackbar('请先上传视频', '未检测到上传的视频');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -217,6 +235,10 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
final data = {
|
final data = {
|
||||||
'url': uploadedVideoUrl.value,
|
'url': uploadedVideoUrl.value,
|
||||||
'title': descriptionController.text.trim(),
|
'title': descriptionController.text.trim(),
|
||||||
|
'fileId': fileId.value,
|
||||||
|
'vlogerId': Get.find<ImUserInfoController>().userID.value,
|
||||||
|
'width': selectedVideo.value!.width,
|
||||||
|
'height': selectedVideo.value!.height,
|
||||||
};
|
};
|
||||||
if (uploadedImgUrl.value.isNotEmpty) {
|
if (uploadedImgUrl.value.isNotEmpty) {
|
||||||
data['cover'] = uploadedImgUrl.value;
|
data['cover'] = uploadedImgUrl.value;
|
||||||
@ -242,11 +264,14 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
uploadProgress.value = 0.0;
|
uploadProgress.value = 0.0;
|
||||||
uploadProgress2.value = 0.0;
|
uploadProgress2.value = 0.0;
|
||||||
videoPath.value = '';
|
videoPath.value = '';
|
||||||
|
// 本地回显
|
||||||
|
snapshot.value = '';
|
||||||
|
imgPath.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 预览视频
|
// 预览视频
|
||||||
void openVd() {
|
void openVd() {
|
||||||
FocusScope.of(context).unfocus();
|
descFocusNode.unfocus();
|
||||||
showGeneralDialog(
|
showGeneralDialog(
|
||||||
context: context,
|
context: context,
|
||||||
// barrierDismissible: true,
|
// barrierDismissible: true,
|
||||||
@ -282,10 +307,11 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return FocusScope(
|
||||||
onTap: () {
|
canRequestFocus: widget.visible,
|
||||||
FocusScope.of(context).unfocus();
|
// 只有 UploadVideoPage 可见时才允许 TextField 聚焦
|
||||||
},
|
child: GestureDetector(
|
||||||
|
onTap: () => descFocusNode.unfocus(),
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(title: const Text('上传视频')),
|
appBar: AppBar(title: const Text('上传视频')),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
@ -303,12 +329,11 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// 视频
|
// 视频上传区
|
||||||
Obx(() {
|
Obx(() {
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// 左侧封面预览
|
|
||||||
snapshot.value.isNotEmpty
|
snapshot.value.isNotEmpty
|
||||||
? GestureDetector(
|
? GestureDetector(
|
||||||
onTap: () => openVd(),
|
onTap: () => openVd(),
|
||||||
@ -329,10 +354,7 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
style: TextStyle(fontSize: 16),
|
style: TextStyle(fontSize: 16),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(width: 24),
|
const SizedBox(width: 24),
|
||||||
|
|
||||||
// 右侧按钮/进度条
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: uploading.value
|
child: uploading.value
|
||||||
? Column(
|
? Column(
|
||||||
@ -358,12 +380,11 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
// 图片上传
|
// 图片上传区
|
||||||
Obx(() {
|
Obx(() {
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// 左侧图片预览
|
|
||||||
imgPath.value.isNotEmpty
|
imgPath.value.isNotEmpty
|
||||||
? GestureDetector(
|
? GestureDetector(
|
||||||
onTap: () => openImg(),
|
onTap: () => openImg(),
|
||||||
@ -384,10 +405,7 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
style: TextStyle(fontSize: 16),
|
style: TextStyle(fontSize: 16),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(width: 24),
|
const SizedBox(width: 24),
|
||||||
|
|
||||||
// 右侧按钮/进度条
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: uploading2.value
|
child: uploading2.value
|
||||||
? Column(
|
? Column(
|
||||||
@ -425,6 +443,8 @@ class _UploadVideoPageState extends State<UploadVideoPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import 'package:loopin/pages/my/nick_name.dart';
|
|||||||
import 'package:loopin/pages/my/setting.dart';
|
import 'package:loopin/pages/my/setting.dart';
|
||||||
import 'package:loopin/pages/my/user_info.dart';
|
import 'package:loopin/pages/my/user_info.dart';
|
||||||
import 'package:loopin/pages/my/vloger.dart';
|
import 'package:loopin/pages/my/vloger.dart';
|
||||||
|
import 'package:loopin/pages/order/seller.dart';
|
||||||
import 'package:loopin/pages/search/index.dart';
|
import 'package:loopin/pages/search/index.dart';
|
||||||
import 'package:loopin/pages/search/search-result.dart';
|
import 'package:loopin/pages/search/search-result.dart';
|
||||||
import 'package:loopin/pages/video/commonVideo.dart';
|
import 'package:loopin/pages/video/commonVideo.dart';
|
||||||
@ -42,6 +43,7 @@ final Map<String, Widget> routes = {
|
|||||||
// '/chatNoFriend': const ChatNoFriend(),
|
// '/chatNoFriend': const ChatNoFriend(),
|
||||||
// '/chatGroup': const ChatGroup(),
|
// '/chatGroup': const ChatGroup(),
|
||||||
'/order': const Order(),
|
'/order': const Order(),
|
||||||
|
'/sellerOrder': const Seller(),
|
||||||
'/order/detail': const OrderDetail(),
|
'/order/detail': const OrderDetail(),
|
||||||
'/vloger': const Vloger(),
|
'/vloger': const Vloger(),
|
||||||
'/report': const ReportPage(),
|
'/report': const ReportPage(),
|
||||||
|
@ -14,6 +14,9 @@ class HttpConfig {
|
|||||||
|
|
||||||
// connectTimeout: Duration(seconds: 30),
|
// connectTimeout: Duration(seconds: 30),
|
||||||
// receiveTimeout: Duration(seconds: 30),
|
// receiveTimeout: Duration(seconds: 30),
|
||||||
|
connectTimeout: const Duration(seconds: 30), // 建立连接超时
|
||||||
|
receiveTimeout: const Duration(seconds: 300), // 接收响应超时(下载)
|
||||||
|
sendTimeout: const Duration(minutes: 10), // 发送请求超时(上传)
|
||||||
));
|
));
|
||||||
|
|
||||||
static final box = GetStorage();
|
static final box = GetStorage();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user