This commit is contained in:
abu 2025-09-29 02:34:41 +08:00
parent 6291dbc55d
commit 564cd38516
69 changed files with 5101 additions and 2706 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,4 +1,8 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
# source 'https://mirrors.tuna.tsinghua.edu.cn/cocoapods/simple/'
platform :ios, '12.0' platform :ios, '12.0'
# 允许拉取http资源 # 允许拉取http资源
# ENV['COCOAPODS_ALLOW_INSECURE_SOURCES'] = 'true' # ENV['COCOAPODS_ALLOW_INSECURE_SOURCES'] = 'true'
@ -33,6 +37,9 @@ target 'Runner' do
use_frameworks! use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
# 集成微信官方 SDK
# pod 'WechatOpenSDK-XCFramework', '~> 2.0.5'
target 'RunnerTests' do target 'RunnerTests' do
inherit! :search_paths inherit! :search_paths
end end

View File

@ -1,4 +1,6 @@
PODS: PODS:
- app_links (6.4.1):
- Flutter
- audioplayers_darwin (0.0.1): - audioplayers_darwin (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -19,7 +21,7 @@ PODS:
- fluwx/pay (= 0.0.1) - fluwx/pay (= 0.0.1)
- fluwx/pay (0.0.1): - fluwx/pay (0.0.1):
- Flutter - Flutter
- WechatOpenSDK-XCFramework (~> 2.0.4) - WechatOpenSDK-XCFramework (~> 2.0.5)
- geolocator_apple (1.2.0): - geolocator_apple (1.2.0):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
@ -33,17 +35,17 @@ PODS:
- Flutter - Flutter
- install_plugin (2.0.0): - install_plugin (2.0.0):
- Flutter - Flutter
- libwebp (1.3.2): - libwebp (1.5.0):
- libwebp/demux (= 1.3.2) - libwebp/demux (= 1.5.0)
- libwebp/mux (= 1.3.2) - libwebp/mux (= 1.5.0)
- libwebp/sharpyuv (= 1.3.2) - libwebp/sharpyuv (= 1.5.0)
- libwebp/webp (= 1.3.2) - libwebp/webp (= 1.5.0)
- libwebp/demux (1.3.2): - libwebp/demux (1.5.0):
- libwebp/webp - libwebp/webp
- libwebp/mux (1.3.2): - libwebp/mux (1.5.0):
- libwebp/demux - libwebp/demux
- libwebp/sharpyuv (1.3.2) - libwebp/sharpyuv (1.5.0)
- libwebp/webp (1.3.2): - libwebp/webp (1.5.0):
- libwebp/sharpyuv - libwebp/sharpyuv
- Mantle (2.2.0): - Mantle (2.2.0):
- Mantle/extobjc (= 2.2.0) - Mantle/extobjc (= 2.2.0)
@ -67,9 +69,9 @@ PODS:
- FlutterMacOS - FlutterMacOS
- record_ios (1.0.0): - record_ios (1.0.0):
- Flutter - Flutter
- SDWebImage (5.20.0): - SDWebImage (5.21.2):
- SDWebImage/Core (= 5.20.0) - SDWebImage/Core (= 5.21.2)
- SDWebImage/Core (5.20.0) - SDWebImage/Core (5.21.2)
- SDWebImageWebPCoder (0.14.6): - SDWebImageWebPCoder (0.14.6):
- libwebp (~> 1.0) - libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17) - SDWebImage/Core (~> 5.17)
@ -87,7 +89,7 @@ PODS:
- TIMPush (8.6.7019): - TIMPush (8.6.7019):
- TXIMSDK_Plus_iOS_XCFramework (>= 8.6.7019) - TXIMSDK_Plus_iOS_XCFramework (>= 8.6.7019)
- TOCropViewController (2.7.4) - TOCropViewController (2.7.4)
- TXIMSDK_Plus_iOS_XCFramework (8.6.7019) - TXIMSDK_Plus_iOS_XCFramework (8.6.7040)
- url_launcher_ios (0.0.1): - url_launcher_ios (0.0.1):
- Flutter - Flutter
- video_player_avfoundation (0.0.1): - video_player_avfoundation (0.0.1):
@ -100,9 +102,13 @@ PODS:
- Flutter - Flutter
- wakelock_plus (0.0.1): - wakelock_plus (0.0.1):
- Flutter - Flutter
- WechatOpenSDK-XCFramework (2.0.4) - webview_flutter_wkwebview (0.0.1):
- Flutter
- FlutterMacOS
- WechatOpenSDK-XCFramework (2.0.5)
DEPENDENCIES: DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`) - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
@ -131,6 +137,7 @@ DEPENDENCIES:
- video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`) - video_thumbnail (from `.symlinks/plugins/video_thumbnail/ios`)
- volume_controller (from `.symlinks/plugins/volume_controller/ios`) - volume_controller (from `.symlinks/plugins/volume_controller/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
@ -145,6 +152,8 @@ SPEC REPOS:
- WechatOpenSDK-XCFramework - WechatOpenSDK-XCFramework
EXTERNAL SOURCES: EXTERNAL SOURCES:
app_links:
:path: ".symlinks/plugins/app_links/ios"
audioplayers_darwin: audioplayers_darwin:
:path: ".symlinks/plugins/audioplayers_darwin/darwin" :path: ".symlinks/plugins/audioplayers_darwin/darwin"
device_info_plus: device_info_plus:
@ -201,22 +210,25 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/volume_controller/ios" :path: ".symlinks/plugins/volume_controller/ios"
wakelock_plus: wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios" :path: ".symlinks/plugins/wakelock_plus/ios"
webview_flutter_wkwebview:
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
SPEC CHECKSUMS: SPEC CHECKSUMS:
app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
audioplayers_darwin: 4f9ca89d92d3d21cec7ec580e78ca888e5fb68bd audioplayers_darwin: 4f9ca89d92d3d21cec7ec580e78ca888e5fb68bd
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1 flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_upgrader: 16a975eb987fc210cdf6bebffe0069a480f80523 flutter_upgrader: 16a975eb987fc210cdf6bebffe0069a480f80523
fluwx: 6bf9c5a3a99ad31b0de137dd92370a0d10a60f4b fluwx: 2ef787502fccb3f3596b380509001a8ea71cbbff
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
HydraAsync: 8d589bd725b0224f899afafc9a396327405f8063 HydraAsync: 8d589bd725b0224f899afafc9a396327405f8063
image_cropper: c4326ea50132b1e1564499e5d32a84f01fb03537 image_cropper: c4326ea50132b1e1564499e5d32a84f01fb03537
image_gallery_saver_plus: e597bf65a7846979417a3eae0763b71b6dfec6c3 image_gallery_saver_plus: e597bf65a7846979417a3eae0763b71b6dfec6c3
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
install_plugin: e17e38d6f504857748a3ec1299d8a2bbeeeea854 install_plugin: e17e38d6f504857748a3ec1299d8a2bbeeeea854
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854
media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474
@ -226,21 +238,22 @@ SPEC CHECKSUMS:
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62 photo_manager: 1d80ae07a89a67dfbcae95953a1e5a24af7c3e62
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
tencent_cloud_chat_push: f87ae58098c2062b06e81f39fc53afc528395916 tencent_cloud_chat_push: f87ae58098c2062b06e81f39fc53afc528395916
tencent_cloud_chat_sdk: 0a406f1854a65aad2f853494c02a2e084a027ab2 tencent_cloud_chat_sdk: 0a406f1854a65aad2f853494c02a2e084a027ab2
TIMPush: d0dfe96355ee413a7cacb2576f8aaa66f6073ab2 TIMPush: d0dfe96355ee413a7cacb2576f8aaa66f6073ab2
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654 TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
TXIMSDK_Plus_iOS_XCFramework: cb54f7de6e30e1368c6831c6eff31c25393bbb98 TXIMSDK_Plus_iOS_XCFramework: 36ea2cdb544315d79e520cd54d0bbb1fbb1110bc
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b
video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140 video_thumbnail: b637e0ad5f588ca9945f6e2c927f73a69a661140
volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
WechatOpenSDK-XCFramework: 36fb2bea0754266c17184adf4963d7e6ff98b69f webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2
WechatOpenSDK-XCFramework: b072030c9eeee91dfff1856a7846f70f7b9a88ed
PODFILE CHECKSUM: 866435f3a12ad92d8fb66fa46b52776da7e16ce5 PODFILE CHECKSUM: f650ed3bb2b12d7ea6a8477a748641b3d65c4991
COCOAPODS: 1.16.2 COCOAPODS: 1.16.2

View File

@ -15,8 +15,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
C8092B212E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8092B202E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework */; }; C8F379732E85F00600E7B665 /* WechatOpenSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = C8F379722E85F00600E7B665 /* WechatOpenSDK.xcframework */; };
C8092B222E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C8092B202E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
ECDFBB33253E89949730F7D8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 898AE91CA73F2F6E910D884D /* Pods_Runner.framework */; }; ECDFBB33253E89949730F7D8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 898AE91CA73F2F6E910D884D /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -37,7 +36,6 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
C8092B222E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework in Embed Frameworks */,
); );
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -66,8 +64,8 @@
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A9774DDA95C7FD895F6925A4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; A9774DDA95C7FD895F6925A4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
BB84C2FA9C50ACAF0C376254 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; }; BB84C2FA9C50ACAF0C376254 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
C8092B202E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = "WechatOpenSDK-XCFramework.xcframework"; path = "Pods/WechatOpenSDK-XCFramework/WechatOpenSDK-XCFramework.xcframework"; sourceTree = "<group>"; };
C891EF1D2E43F9730021EB39 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; }; C891EF1D2E43F9730021EB39 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
C8F379722E85F00600E7B665 /* WechatOpenSDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = WechatOpenSDK.xcframework; path = "Pods/WechatOpenSDK-XCFramework/WechatOpenSDK.xcframework"; sourceTree = "<group>"; };
DCA23AF172275D04ECB63EFB /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; }; DCA23AF172275D04ECB63EFB /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
E3EC116A6CCDD06C6D4615E2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; E3EC116A6CCDD06C6D4615E2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -77,7 +75,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
C8092B212E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework in Frameworks */, C8F379732E85F00600E7B665 /* WechatOpenSDK.xcframework in Frameworks */,
ECDFBB33253E89949730F7D8 /* Pods_Runner.framework in Frameworks */, ECDFBB33253E89949730F7D8 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -165,7 +163,7 @@
9CE4C2341F34F9A85A1D3EED /* Frameworks */ = { 9CE4C2341F34F9A85A1D3EED /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
C8092B202E34A78000D25A0B /* WechatOpenSDK-XCFramework.xcframework */, C8F379722E85F00600E7B665 /* WechatOpenSDK.xcframework */,
898AE91CA73F2F6E910D884D /* Pods_Runner.framework */, 898AE91CA73F2F6E910D884D /* Pods_Runner.framework */,
1AE799326ED7557212A901E0 /* Pods_RunnerTests.framework */, 1AE799326ED7557212A901E0 /* Pods_RunnerTests.framework */,
); );
@ -510,8 +508,13 @@
PRODUCT_BUNDLE_IDENTIFIER = cn.net.wzj.mall; PRODUCT_BUNDLE_IDENTIFIER = cn.net.wzj.mall;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Profile; name = Profile;
@ -689,6 +692,54 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 9C9VWBX77X; DEVELOPMENT_TEAM = 9C9VWBX77X;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_CONFIGURATION_BUILD_DIR}/HydraAsync\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/Mantle\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/SDWebImageWebPCoder\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/app_links\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/audioplayers_darwin\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/device_info_plus\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/flutter_image_compress_common\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/flutter_native_splash\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/flutter_upgrader\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/fluwx\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/geolocator_apple\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/image_cropper\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/image_gallery_saver_plus\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/install_plugin\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/libwebp\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/media_kit_libs_ios_video\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/media_kit_video\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/mobile_scanner\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/package_info_plus\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/path_provider_foundation\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/permission_handler_apple\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/photo_manager\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/record_ios\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/sqflite_darwin\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/tencent_cloud_chat_push\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/tencent_cloud_chat_sdk\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/url_launcher_ios\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/video_player_avfoundation\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/video_thumbnail\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/volume_controller\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/wakelock_plus\"",
"\"${PODS_CONFIGURATION_BUILD_DIR}/webview_flutter_wkwebview\"",
"\"${PODS_ROOT}/../.symlinks/plugins/media_kit_libs_ios_video/ios/Frameworks\"",
"\"${PODS_ROOT}/../.symlinks/plugins/tencent_cloud_chat_sdk/ios/Frameworks\"",
"\"${PODS_ROOT}/TIMPush\"",
"\"${PODS_ROOT}/TXIMSDK_Plus_iOS_XCFramework\"",
"\"${PODS_ROOT}/WechatOpenSDK-XCFramework\"",
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/TIMPush\"",
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/TXIMSDK_Plus_iOS_XCFramework\"",
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/WechatOpenSDK-XCFramework\"/**",
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/media_kit_libs_ios_video\"",
"\"${PODS_XCFRAMEWORKS_BUILD_DIR}/tencent_cloud_chat_sdk\"",
);
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -698,9 +749,14 @@
PRODUCT_BUNDLE_IDENTIFIER = cn.net.wzj.mall; PRODUCT_BUNDLE_IDENTIFIER = cn.net.wzj.mall;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Debug; name = Debug;
@ -726,8 +782,13 @@
PRODUCT_BUNDLE_IDENTIFIER = cn.net.wzj.mall; PRODUCT_BUNDLE_IDENTIFIER = cn.net.wzj.mall;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
}; };
name = Release; name = Release;

View File

@ -5,17 +5,50 @@ import Flutter
import TIMPush import TIMPush
import tencent_cloud_chat_push import tencent_cloud_chat_push
// SDK
import WechatOpenSDK
// Add `, TIMPushDelegate` to the following line // Add `, TIMPushDelegate` to the following line
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, TIMPushDelegate { @objc class AppDelegate: FlutterAppDelegate, TIMPushDelegate {
private let CHANNEL = "wechat_business_view"
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
//
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name: CHANNEL, binaryMessenger: controller.binaryMessenger)
methodChannel.setMethodCallHandler { [weak self] (call, result) in
if call.method == "openBusinessView" {
if let args = call.arguments as? [String: Any],
let packageInfo = args["package"] as? String {
self?.openBusinessView(packageInfo: packageInfo)
result(true)
} else {
result(FlutterError(code: "BAD_ARGS", message: "Missing package info", details: nil))
}
} else {
result(FlutterMethodNotImplemented)
}
}
//end
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
private func openBusinessView(packageInfo: String) {
let req = WXOpenBusinessViewReq()
req.businessType = "requestMerchantTransfer"
req.query = packageInfo
WXApi.send(req) { success in
print("WXOpenBusinessViewReq send result: \(success)")
}
}
// To be deprecatedplease use the new field businessID below. // To be deprecatedplease use the new field businessID below.
@objc func offlinePushCertificateID() -> Int32 { @objc func offlinePushCertificateID() -> Int32 {
return TencentCloudChatPushFlutterModal.shared.offlinePushCertificateID(); return TencentCloudChatPushFlutterModal.shared.offlinePushCertificateID();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 69 B

View File

@ -38,7 +38,7 @@
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
<image name="LaunchImage" width="1024" height="1536"/> <image name="LaunchImage" width="168" height="185"/>
<image name="LaunchBackground" width="1" height="1"/> <image name="LaunchBackground" width="1" height="1"/>
</resources> </resources>
</document> </document>

View File

@ -34,6 +34,16 @@
<string>wxebcdaea31881caab</string> <string>wxebcdaea31881caab</string>
</array> </array>
</dict> </dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>startApp</string>
<key>CFBundleURLSchemes</key>
<array>
<string>wuzhongjie</string>
</array>
</dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
@ -62,8 +72,12 @@
<string>App需要访问您的相册用于选择图片或视频</string> <string>App需要访问您的相册用于选择图片或视频</string>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen.storyboard</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
<string>Main</string> <string>Main</string>
<key>UIStatusBarHidden</key> <key>UIStatusBarHidden</key>
@ -83,15 +97,16 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>com.apple.developer.associated-domains</key> <key>com.apple.developer.associated-domains</key>
<array> <array>
<string>applinks:wuzhongjie.com.cn</string> <string>applinks:wuzhongjie.com.cn</string>
</array> </array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
<string>weixinULAPI</string>
<string>weixinURLParamsAPI</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -147,9 +147,9 @@ class ChatController extends GetxController {
} }
final List<ConversationViewModel> convList = res.data; final List<ConversationViewModel> convList = res.data;
for (var conv in convList) { // for (var conv in convList) {
logger.w('基本会话: ${conv.conversation.toJson()}'); // logger.w('基本会话: ${conv.conversation.toJson()}');
} // }
// //
// ID集合 // ID集合
final existingIds = chatList.map((e) => e.conversation.conversationID).where((id) => id.isNotEmpty).toSet(); final existingIds = chatList.map((e) => e.conversation.conversationID).where((id) => id.isNotEmpty).toSet();

View File

@ -9,6 +9,13 @@ class ImUserInfoController extends GetxController {
void onInit() { void onInit() {
super.onInit(); super.onInit();
logger.i('开始IM用户信息初始化'); logger.i('开始IM用户信息初始化');
init(V2TimUserFullInfo(customInfo: {
"coverBg": "",
"area": "",
"areaCode": "",
"openId": "",
"tag": "",
}));
} }
V2TimUserFullInfo? rawUserInfo; V2TimUserFullInfo? rawUserInfo;
@ -47,6 +54,19 @@ class ImUserInfoController extends GetxController {
"openId": "", "openId": "",
"tag": "", "tag": "",
}); });
// final safeMap = <String, String>{};
// userInfo.customInfo?.forEach((key, value) {
// safeMap[key] = value;
// });
// customInfo.assignAll({
// "coverBg": "",
// "area": "",
// "areaCode": "",
// "openId": "",
// "tag": "",
// ...safeMap, //
// });
role.value = userInfo.role ?? 0; role.value = userInfo.role ?? 0;
level.value = userInfo.level ?? 0; level.value = userInfo.level ?? 0;

View File

@ -23,7 +23,12 @@ class ImCore {
// //
final videoController = Get.find<VideoModuleController>(); final videoController = Get.find<VideoModuleController>();
videoController.init(); videoController.init();
Get.toNamed('/login'); Get.offAllNamed(
'/login',
predicate: (route) {
return route.settings.name == '/';
},
);
} }
} }

View File

@ -1,10 +1,17 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:logger/logger.dart'; import 'package:logger/logger.dart';
import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/im_message.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/models/conversation_view_model.dart';
import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart'; import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart';
import 'package:tencent_cloud_chat_sdk/enum/V2TimGroupListener.dart'; import 'package:tencent_cloud_chat_sdk/enum/V2TimGroupListener.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_group_change_info.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_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_group_member_info.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_topic_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'; import 'package:tencent_cloud_chat_sdk/native_im/adapter/tim_manager.dart';
@ -130,19 +137,67 @@ class ImGroupListeners {
} }
// //
void onMemberInvited(String groupID, List<V2TimGroupMemberInfo> memberList) { void onMemberInvited(String groupID, List<V2TimGroupMemberInfo> memberList) async {
if (Get.isRegistered<GroupDetailController>()) { if (Get.isRegistered<GroupDetailController>()) {
final ctl = Get.find<GroupDetailController>(); final ctl = Get.find<GroupDetailController>();
ctl.init(); ctl.init();
} }
//
await ImService.instance.setConversationCustomData(customData: 'int', conversationIDList: ['group_$groupID']);
} }
// //
void onMemberKicked(String groupID, List<V2TimGroupMemberInfo> memberList) { void onMemberKicked(String groupID, List<V2TimGroupMemberInfo> memberList) async {
if (Get.isRegistered<GroupDetailController>()) { if (Get.isRegistered<GroupDetailController>()) {
final ctl = Get.find<GroupDetailController>(); final ctl = Get.find<GroupDetailController>();
ctl.init(); ctl.init();
} }
//
final infoCtl = Get.find<ImUserInfoController>();
final hasSelf = memberList.any((m) => m.userID == infoCtl.userID.value);
logger.e(hasSelf);
if (hasSelf) {
//
await ImService.instance.setConversationCustomData(customData: 'out', conversationIDList: ['group_$groupID']);
//
final chatCtl = Get.find<ChatController>();
ConversationViewModel? conv;
try {
conv = chatCtl.chatList.firstWhere((m) => m.conversation.groupID == groupID);
} catch (e) {
conv = null;
}
if (conv != null) {
logger.e('本地找到');
// 9=tips
final result = await IMMessage().createTextMessage(text: '你已被移出群聊');
if (result.success && result.data != null) {
V2TimMessage msg = result.data!.messageInfo!;
msg.cloudCustomData = 'tips';
final index = chatCtl.chatList.indexOf(conv);
if (index != -1) {
chatCtl.chatList[index].conversation.lastMessage = msg;
chatCtl.chatList.refresh();
logger.e('刷新');
}
}
} else {
//
final cloudRes = await ImService.instance.getConversation(conversationID: 'group_$groupID');
if (cloudRes.success && cloudRes.data != null) {
V2TimConversation cloudConv = cloudRes.data;
final result = await IMMessage().createTextMessage(text: '你已被移出群聊');
if (result.success && result.data != null) {
V2TimMessage msg = result.data!.messageInfo!;
msg.cloudCustomData = 'tips';
cloudConv.lastMessage = msg;
final resModel = await ConversationViewModel.createConversationViewModel(convList: [cloudConv]);
chatCtl.chatList.insertAll(0, resModel);
}
}
}
}
} }
// //

View File

@ -84,13 +84,6 @@ class ImService {
if (result.success) { if (result.success) {
logger.i("IM 登录成功:$userID"); logger.i("IM 登录成功:$userID");
//
final ctl = Get.find<ChatController>();
await ctl.getConversationList();
/// SDK
await Wxsdk.init();
// (+) // (+)
if (!Get.isRegistered<ImUserInfoController>()) { if (!Get.isRegistered<ImUserInfoController>()) {
final imInfo = Get.put(ImUserInfoController(), permanent: true); final imInfo = Get.put(ImUserInfoController(), permanent: true);
@ -99,6 +92,13 @@ class ImService {
await Get.find<ImUserInfoController>().refreshUserInfo(); await Get.find<ImUserInfoController>().refreshUserInfo();
} }
//
final ctl = Get.find<ChatController>();
await ctl.getConversationList();
/// SDK
await Wxsdk.init();
// //
final messageService = ImMessageListenerService(); final messageService = ImMessageListenerService();
Get.put<ImMessageListenerService>(messageService, permanent: true); Get.put<ImMessageListenerService>(messageService, permanent: true);
@ -275,7 +275,7 @@ class ImService {
// userID groupID // userID groupID
for (var conv in convList) { for (var conv in convList) {
logger.e('未过滤前到会话数据:${conv.toLogString()}'); // logger.e('未过滤前到会话数据:${conv.toLogString()}');
if (conv.userID != null) { if (conv.userID != null) {
userIDList.add(conv.userID!); userIDList.add(conv.userID!);
} else if (conv.groupID != null) { } else if (conv.groupID != null) {
@ -297,7 +297,7 @@ class ImService {
// //
final customInfo = user.customInfo; final customInfo = user.customInfo;
logger.w('自定义信息:${user.toJson()}'); // logger.w('自定义信息:${user.toJson()}');
if (customInfo != null) { if (customInfo != null) {
isCustomAdmin[userId] = customInfo['admin'] ?? '0'; isCustomAdmin[userId] = customInfo['admin'] ?? '0';
} }
@ -504,6 +504,14 @@ class ImService {
); );
} }
///
Future<ImResult> markC2CMessageAsReadResult({
required String userID,
}) async {
final res = await TIMMessageManager.instance.markC2CMessageAsRead(userID: userID);
return ImResult.wrapNoData(res);
}
/// ///
/// ///
/// ///
@ -646,6 +654,12 @@ class ImService {
return ImResult.wrap(res); return ImResult.wrap(res);
} }
///
Future<ImResult<List<V2TimFriendInfo>>> blackList() async {
final res = await TIMFriendshipManager.instance.getBlackList();
return ImResult.wrap(res);
}
/// ///
Future<ImResult<List<V2TimFriendInfo>>> getFriendList() async { Future<ImResult<List<V2TimFriendInfo>>> getFriendList() async {
final res = await TIMFriendshipManager.instance.getFriendList(); final res = await TIMFriendshipManager.instance.getFriendList();

View File

@ -48,20 +48,25 @@ class PushService {
} }
// //
// if (Platform.isAndroid) { if (Platform.isAndroid) {
// await compute(_registerPushInIsolate, { // await compute(_registerPushInIsolate, {
// 'sdkAppId': sdkAppId, // 'sdkAppId': sdkAppId,
// 'appKey': appKey, // 'appKey': appKey,
// 'apnsCertificateID': apnsCertificateID, // 'apnsCertificateID': apnsCertificateID,
// }); // });
// } else { await _registerPushInIsolate({
'sdkAppId': sdkAppId,
'appKey': appKey,
'apnsCertificateID': apnsCertificateID,
});
} else {
await TencentCloudChatPush().registerPush( await TencentCloudChatPush().registerPush(
onNotificationClicked: _onNotificationClicked, onNotificationClicked: _onNotificationClicked,
sdkAppId: sdkAppId, sdkAppId: sdkAppId,
appKey: appKey, appKey: appKey,
apnsCertificateID: apnsCertificateID, apnsCertificateID: apnsCertificateID,
); );
// } }
// App // App
await TencentCloudChatPush().disablePostNotificationInForeground(disable: true); await TencentCloudChatPush().disablePostNotificationInForeground(disable: true);
@ -70,8 +75,11 @@ class PushService {
if (Platform.isAndroid) { if (Platform.isAndroid) {
await TencentImSDKPlugin.v2TIMManager.login(userID: Storage.read('userId'), userSig: Storage.read('userSig')); await TencentImSDKPlugin.v2TIMManager.login(userID: Storage.read('userId'), userSig: Storage.read('userSig'));
} }
final token = await TencentCloudChatPush().getAndroidPushToken();
logger.i('推送服务已注册,手机:$devices,证书ID:$apnsCertificateID'); logger.i(
'推送服务已注册,手机:$devices,证书ID:$apnsCertificateID,token=${token.code},tk=${token.data}',
);
// 线 // 线
_addPushListener(); _addPushListener();
@ -123,19 +131,21 @@ class PushService {
/// ///
static void _handleNotificationClick(String ext, {String? userID, String? groupID}) async { static void _handleNotificationClick(String ext, {String? userID, String? groupID}) async {
try { try {
// ext={id:ID,type:'newFocus',userID:idgroupIDID} // ext={id:ID,type:'newFocus',userID:idgroupIDID} // type=
// final ext = jsonEncode({ // final ext = jsonEncode({
// "userID": "123456", // "userID": "123456",
// "groupID": "654321", // "groupID": "654321",
// }); // });
final isGroup = groupID != null && groupID.isNotEmpty;
final data = jsonDecode(ext); final data = jsonDecode(ext);
logger.i(data); logger.i(data);
final type = data['type']; // final type = data['type'];
final router = conversationTypeFromString(type); final router = conversationTypeFromString(userID); //userID
logger.w(router); logger.w(router);
if (router == null || router != '') { if (router == null) {
// //
if (data['userID'] != null) { if (!isGroup) {
logger.w('有userID'); logger.w('有userID');
// //
final covRes = await ImService.instance.getConversation(conversationID: 'c2c_${data['userID']}'); final covRes = await ImService.instance.getConversation(conversationID: 'c2c_${data['userID']}');
@ -160,7 +170,9 @@ class PushService {
} }
} else { } else {
// (ID只在特定业务场景才有退id对应的就是订单id) // (ID只在特定业务场景才有退id对应的就是订单id)
Get.toNamed('/$router', arguments: data['id'] ?? ''); final notifyRes = await ImService.instance.getConversation(conversationID: 'c2c_$router');
final V2TimConversation notifyConversation = notifyRes.data;
Get.toNamed('/$router', arguments: notifyConversation);
} }
} catch (e) { } catch (e) {
logger.i("[推送点击] ext 解析失败: $e"); logger.i("[推送点击] ext 解析失败: $e");

View File

@ -4,7 +4,10 @@ class CommonApi {
// /app/member/sms/code // /app/member/sms/code
static const String getDelCode = '/app/member/sms/code'; // {'templateId'} static const String getDelCode = '/app/member/sms/code'; // {'templateId'}
static const String accountInfo = '/app/member/info'; // static const String accountInfo = '/app/member/info'; //
/// /app/member/account
static const String userAccount = '/app/member/account';
///---------post ///---------post
static const String login = '/auth/login'; // {'phonenumber': '', 'smsCode': '', 'clientId': '428a8310cd442757ae699df5d894f051', 'grantType': 'sms'}; static const String login = '/auth/login'; // {'phonenumber': '', 'smsCode': '', 'clientId': '428a8310cd442757ae699df5d894f051', 'grantType': 'sms'};
@ -22,13 +25,13 @@ class CommonApi {
/// [money] /// [money]
// { // {
// "orderType": "RECHARGE", // "orderType": "RECHARGE","ORDER"
// "clientType": "APP", // "clientType": "APP",
// "paymentMethod": "WECHAT", // "paymentMethod": "WECHAT",
// "paymentClient": "APP", // "paymentClient": "APP",
// "money": 100 // "money": 100
// } // }
static const String addBalance = '/app/payment/pay'; static const String wechatPay = '/app/payment/pay';
/// ///
// { // {
@ -40,5 +43,21 @@ class CommonApi {
/// /app/member/revoked /// /app/member/revoked
static const String revoked = '/app/member/revoked'; static const String revoked = '/app/member/revoked';
///resource/oss/upload /// [source]=3
static const String bills = '/app/member/bills';
/// /api/red-packet/send
// "chatType": 1, 1= 2=
// "senderId": 1950059660646047745,
// "receiverId": 1949004087674580994,
// "groupId": "",
// "totalAmount": 1,
// "totalCount": 1,
// "remark": "恭喜发财"
static const String redpacket = '/app/customer/packet/send';
/// /api/red-packet/grab
// "packetId": "1954790726899544065",
// "memberId": "1949004087674580994"
static const String getpacket = '/app/customer/packet/grab';
} }

View File

@ -5,6 +5,8 @@ class VideoApi {
static const String friendList = '/app/vlog/friendList'; // static const String friendList = '/app/vlog/friendList'; //
static const String followList = '/app/vlog/followList'; // static const String followList = '/app/vlog/followList'; //
static const String detail = '/app/vlog/detail'; // static const String detail = '/app/vlog/detail'; //
static const String deleteVideo = '/app/vlog/delete'; //
// post // post
static const String myPublicList = '/app/vlog/myPublicList'; // static const String myPublicList = '/app/vlog/myPublicList'; //
static const String myLikedList = '/app/vlog/myLikedList'; // static const String myLikedList = '/app/vlog/myLikedList'; //
@ -13,9 +15,6 @@ class VideoApi {
static const String reportVideoApi = '/app/feedback/add'; // static const String reportVideoApi = '/app/feedback/add'; //
static const String videoDetailApi = '/app/vlog/detail/'; // Id获取视频系详情 static const String videoDetailApi = '/app/vlog/detail/'; // Id获取视频系详情
static const String unlike = '/app/vlog/unlike'; // static const String unlike = '/app/vlog/unlike'; //
static const String totalLikedCounts = '/app/vlog/totalLikedCounts'; // static const String totalLikedCounts = '/app/vlog/totalLikedCounts'; //
static const String publish = '/app/vlog/publish'; // static const String publish = '/app/vlog/publish'; //
@ -24,6 +23,5 @@ class VideoApi {
static const String changeToPublic = '/app/vlog/changeToPublic'; // static const String changeToPublic = '/app/vlog/changeToPublic'; //
static const String changeToPrivate = '/app/vlog/changeToPrivate'; // static const String changeToPrivate = '/app/vlog/changeToPrivate'; //
static const String deleteVideo = '/app/vlog/delete'; //
static const String getVideoListByMemberId = '/app/vlog/page'; // static const String getVideoListByMemberId = '/app/vlog/page'; //
} }

View File

@ -27,12 +27,14 @@ class NetworkOrAssetImage extends StatelessWidget {
width: width, width: width,
height: height, height: height,
fit: fit, fit: fit,
placeholder: (context, url) => Image.asset( placeholder: placeholderAsset.isNotEmpty
? (context, url) => Image.asset(
placeholderAsset.isEmpty ? 'assets/images/avatar/default.png' : placeholderAsset, placeholderAsset.isEmpty ? 'assets/images/avatar/default.png' : placeholderAsset,
width: width, width: width,
height: height, height: height,
fit: fit, fit: fit,
), )
: null,
errorWidget: (context, url, error) => Image.asset( errorWidget: (context, url, error) => Image.asset(
placeholderAsset, placeholderAsset,
width: width, width: width,

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebPage extends StatefulWidget {
final String url;
final String title;
const WebPage({super.key, required this.url, required this.title});
@override
State<WebPage> createState() => _WebPageState();
}
class _WebPageState extends State<WebPage> {
late final WebViewController _controller;
double _progress = 0.0;
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onProgress: (progress) {
setState(() {
_progress = progress / 100.0;
});
},
),
)
..loadRequest(Uri.parse(widget.url));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () async {
if (await _controller.canGoBack()) {
_controller.goBack();
} else {
Navigator.of(context).pop();
}
},
),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(2.0),
child: _progress < 1.0 ? LinearProgressIndicator(value: _progress) : const SizedBox.shrink(),
),
),
body: WebViewWidget(controller: _controller),
);
}
}

View File

@ -32,15 +32,15 @@ class _LayoutState extends State<Layout> {
VideoModuleController videoModuleController = Get.put(VideoModuleController()); VideoModuleController videoModuleController = Get.put(VideoModuleController());
// page页面 // page页面
List pageList = [ // List pageList = [
VideoPage(), // VideoPage(),
IndexPage(), // IndexPage(),
UploadVideoPage( // UploadVideoPage(
visible: false, // visible: false,
), // ),
ChatPage(), // ChatPage(),
MyPage() // MyPage(key: myPageKey)
]; // ];
// tabs选项 // tabs选项
List navItems = [ List navItems = [
BottomNavigationBarItem(icon: Icon(Icons.play_circle_outline), label: '视频'), BottomNavigationBarItem(icon: Icon(Icons.play_circle_outline), label: '视频'),
@ -126,34 +126,62 @@ class _LayoutState extends State<Layout> {
return Scaffold( return Scaffold(
backgroundColor: Colors.grey[50], backgroundColor: Colors.grey[50],
// body: pageList[pageCurrent], // body: pageList[pageCurrent],
body: Obx(() { // body: Stack(
return Stack( // children: [
// Obx(
// () => Offstage(
// offstage: videoModuleController.layoutPageCurrent.value != 0,
// child: const KeepAliveWrapper(child: VideoPage()),
// ),
// ),
// Obx(
// () => Offstage(
// offstage: videoModuleController.layoutPageCurrent.value != 1,
// child: IndexPage(), //
// ),
// ),
// Obx(
// () => Offstage(
// offstage: videoModuleController.layoutPageCurrent.value != 2,
// child: UploadVideoPage(
// visible: videoModuleController.layoutPageCurrent.value == 2,
// ), //
// ),
// ),
// Obx(
// () => Offstage(
// offstage: videoModuleController.layoutPageCurrent.value != 3,
// child: ChatPage(), //
// ),
// ),
// Obx(
// () => Offstage(
// offstage: videoModuleController.layoutPageCurrent.value != 4,
// child: MyPage(key: myPageKey), //
// ),
// ),
// ],
// ),
body: Obx(
() {
return IndexedStack(
index: videoModuleController.layoutPageCurrent.value,
children: [ children: [
Offstage( const KeepAliveWrapper(child: VideoPage()),
offstage: videoModuleController.layoutPageCurrent.value != 0, const KeepAliveWrapper(child: IndexPage()),
child: const KeepAliveWrapper(child: VideoPage()), UploadVideoPage(
),
Offstage(
offstage: videoModuleController.layoutPageCurrent.value != 1,
child: IndexPage(), //
),
Offstage(
offstage: videoModuleController.layoutPageCurrent.value != 2,
child: UploadVideoPage(
visible: videoModuleController.layoutPageCurrent.value == 2, visible: videoModuleController.layoutPageCurrent.value == 2,
), //
),
Offstage(
offstage: videoModuleController.layoutPageCurrent.value != 3,
child: ChatPage(), //
),
Offstage(
offstage: videoModuleController.layoutPageCurrent.value != 4,
child: MyPage(key: myPageKey), //
), ),
const KeepAliveWrapper(child: ChatPage()),
KeepAliveWrapper(
child: MyPage(
key: myPageKey,
)),
], ],
); );
}), },
),
// //
bottomNavigationBar: Theme( bottomNavigationBar: Theme(
// Flutter去掉BottomNavigationBar底部导航栏的水波纹 // Flutter去掉BottomNavigationBar底部导航栏的水波纹
@ -241,6 +269,6 @@ class _LayoutState extends State<Layout> {
myPageKey.currentState?.refreshData(); myPageKey.currentState?.refreshData();
} }
videoModuleController.updateLayoutPage(index); videoModuleController.updateLayoutPage(index);
setState(() {}); // setState(() {});
} }
} }

View File

@ -7,12 +7,13 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:loopin/IM/controller/chat_controller.dart'; import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/controller/tab_bar_controller.dart'; import 'package:loopin/IM/controller/tab_bar_controller.dart';
import 'package:loopin/IM/im_core.dart' as im_core; import 'package:loopin/IM/im_core.dart' as im_core;
import 'package:loopin/IM/im_service.dart'; import 'package:loopin/IM/im_service.dart';
import 'package:loopin/controller/shop_index_controller.dart';
import 'package:loopin/service/http_config.dart'; import 'package:loopin/service/http_config.dart';
import 'package:loopin/utils/common.dart'; import 'package:loopin/utils/common.dart';
import 'package:loopin/utils/deep_link_listener.dart';
import 'package:loopin/utils/lifecycle_handler.dart'; import 'package:loopin/utils/lifecycle_handler.dart';
import 'package:loopin/utils/storage.dart'; import 'package:loopin/utils/storage.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
@ -24,18 +25,20 @@ import 'layouts/index.dart';
import 'router/index.dart'; import 'router/index.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized();
// tabbar // tabbar
Get.put(TabBarController(), permanent: true); Get.put(TabBarController(), permanent: true);
// //
Get.put(ChatController(), permanent: true); Get.put(ChatController(), permanent: true);
// //
Get.put(ShopIndexController(), permanent: true); // Get.put(ShopIndexController(), permanent: true);
//
Get.put(ImUserInfoController(), permanent: true);
// app前后台状态 // app前后台状态
WidgetsFlutterBinding.ensureInitialized();
WidgetsBinding.instance.addObserver(LifecycleHandler()); WidgetsBinding.instance.addObserver(LifecycleHandler());
// //
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([ await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp, DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown, DeviceOrientation.portraitDown,
@ -86,7 +89,8 @@ class App extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GetMaterialApp( return DeepLinkListener(
child: GetMaterialApp(
title: '无终街', title: '无终街',
locale: const Locale('zh'), locale: const Locale('zh'),
supportedLocales: const [ supportedLocales: const [
@ -115,6 +119,7 @@ class App extends StatelessWidget {
Get.put<RouteObserver<PageRoute>>(routeObserver); Get.put<RouteObserver<PageRoute>>(routeObserver);
return child!; return child!;
}, },
),
); );
} }
} }

View File

@ -12,6 +12,7 @@ enum NotifyMessageType {
orderRecharge, //-> online orderRecharge, //-> online
orderPay, //-> online orderPay, //-> online
orderRefund, //->退 orderRefund, //->退
orderWithDraw, //->
groupNotifyCheck, //-> online groupNotifyCheck, //-> online
groupNotifyAccpet, // -> online groupNotifyAccpet, // -> online
groupNotifyFail, // -> online groupNotifyFail, // -> online
@ -32,6 +33,7 @@ class NotifyMessageTypeConstants {
static const String orderRecharge = 'orderRecharge'; static const String orderRecharge = 'orderRecharge';
static const String orderPay = 'orderPay'; static const String orderPay = 'orderPay';
static const String orderRefund = 'orderRefund'; static const String orderRefund = 'orderRefund';
static const String orderWithDraw = 'orderWithDraw';
static const String groupNotifyCheck = 'groupNotifyCheck'; static const String groupNotifyCheck = 'groupNotifyCheck';
static const String groupNotifyAccpet = 'groupNotifyAccpet'; static const String groupNotifyAccpet = 'groupNotifyAccpet';
static const String groupNotifyFail = 'groupNotifyFail'; static const String groupNotifyFail = 'groupNotifyFail';
@ -63,6 +65,8 @@ extension NotifyMessageTypeExtension on NotifyMessageType {
return 'orderRecharge'; return 'orderRecharge';
case NotifyMessageType.orderPay: case NotifyMessageType.orderPay:
return 'orderPay'; return 'orderPay';
case NotifyMessageType.orderWithDraw:
return 'orderWithDraw';
case NotifyMessageType.orderRefund: case NotifyMessageType.orderRefund:
return 'orderRefund'; return 'orderRefund';
case NotifyMessageType.groupNotifyCheck: case NotifyMessageType.groupNotifyCheck:
@ -101,6 +105,8 @@ notifyMessageTypeFromString(String? type) {
return NotifyMessageType.orderRecharge.name; return NotifyMessageType.orderRecharge.name;
case 'orderPay': case 'orderPay':
return NotifyMessageType.orderPay.name; return NotifyMessageType.orderPay.name;
case 'orderWithDraw':
return NotifyMessageType.orderWithDraw.name;
case 'orderRefund': case 'orderRefund':
return NotifyMessageType.orderRefund.name; return NotifyMessageType.orderRefund.name;
case 'groupNotifyCheck': case 'groupNotifyCheck':

View File

@ -30,7 +30,7 @@ class _LoginState extends State<Login> {
Timer? timer; Timer? timer;
String vcodeText = '获取验证码'; String vcodeText = '获取验证码';
bool disabled = false; bool disabled = false;
int time = 6; int time = 60;
@override @override
void initState() { void initState() {

View File

@ -8,20 +8,27 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/controller/chat_detail_controller.dart'; import 'package:loopin/IM/controller/chat_detail_controller.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/im_message.dart'; import 'package:loopin/IM/im_message.dart';
import 'package:loopin/IM/im_result.dart'; import 'package:loopin/IM/im_result.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/components/animation.dart'; import 'package:loopin/components/animation.dart';
import 'package:loopin/components/image_viewer.dart'; import 'package:loopin/components/image_viewer.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/components/preview_video.dart'; import 'package:loopin/components/preview_video.dart';
import 'package:loopin/models/summary_type.dart'; import 'package:loopin/models/summary_type.dart';
import 'package:loopin/pages/chat/components/reportChat.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/utils/audio_player_service.dart'; import 'package:loopin/utils/audio_player_service.dart';
import 'package:loopin/utils/snapshot.dart'; import 'package:loopin/utils/snapshot.dart';
import 'package:loopin/utils/voice_service.dart'; import 'package:loopin/utils/voice_service.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:shirne_dialog/shirne_dialog.dart';
import 'package:tencent_cloud_chat_sdk/enum/message_status.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_message.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
import 'package:video_player/video_player.dart'; import 'package:video_player/video_player.dart';
@ -81,7 +88,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
List chooseOptions = [ List chooseOptions = [
{'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'}, {'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'},
{'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'}, {'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'},
{'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'}, // {'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'},
{'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'}, {'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'},
]; ];
@ -285,6 +292,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
List<Widget> renderChatList() { List<Widget> renderChatList() {
List<Widget> msgtpl = []; List<Widget> msgtpl = [];
for (var item in controller.chatList) { for (var item in controller.chatList) {
// logger.e(item.status);
// //
if (item.localCustomData == 'time_label') { if (item.localCustomData == 'time_label') {
msgtpl.add(Container( msgtpl.add(Container(
@ -322,7 +330,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
msgtpl.add( msgtpl.add(
RenderChatItem( RenderChatItem(
data: item, data: item,
child: Ink( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink(
decoration: BoxDecoration( decoration: BoxDecoration(
color: !(item.isSelf ?? false) ? Color(0xFFFFFFFF) : Color(0xFF89E45B), color: !(item.isSelf ?? false) ? Color(0xFFFFFFFF) : Color(0xFF89E45B),
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
@ -332,13 +351,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
child: Container( child: Container(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: RichTextUtil.getRichText(item.textElem?.text ?? '', color: !(item.isSelf ?? false) ? Colors.black : Colors.white), // emoj// child: RichTextUtil.getRichText(
item.textElem?.text ?? '',
color: !(item.isSelf ?? false) ? Colors.black : Colors.white,
), // emoj//
), ),
onLongPress: () { onLongPress: () {
contextMenuDialog(); contextMenuDialog();
}, },
), ),
), ),
],
),
), ),
); );
} }
@ -346,7 +370,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
else if (item.elemType == 8) { else if (item.elemType == 8) {
msgtpl.add(RenderChatItem( msgtpl.add(RenderChatItem(
data: item, data: item,
child: Ink( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink(
child: InkWell( child: InkWell(
overlayColor: WidgetStateProperty.all(Colors.transparent), overlayColor: WidgetStateProperty.all(Colors.transparent),
child: Container( child: Container(
@ -362,6 +397,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
}, },
), ),
), ),
],
),
)); ));
} }
// =3 // =3
@ -371,7 +408,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
List<String> imagePaths = originImage != null ? [originImage.url!] : []; List<String> imagePaths = originImage != null ? [originImage.url!] : [];
msgtpl.add(RenderChatItem( msgtpl.add(RenderChatItem(
data: item, data: item,
child: Ink( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
// //
@ -402,7 +450,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
color: Colors.grey[300], color: Colors.grey[300],
alignment: Alignment.center, alignment: Alignment.center,
child: CircularProgressIndicator( child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, value:
loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null,
), ),
); );
}, },
@ -420,6 +469,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
}, },
), ),
), ),
],
),
)); ));
} }
// =5 // =5
@ -427,7 +478,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// print(item.videoElem!.toLogString()); // print(item.videoElem!.toLogString());
msgtpl.add(RenderChatItem( msgtpl.add(RenderChatItem(
data: item, data: item,
child: Ink( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink(
child: InkWell( child: InkWell(
overlayColor: WidgetStateProperty.all(Colors.transparent), overlayColor: WidgetStateProperty.all(Colors.transparent),
child: SizedBox( child: SizedBox(
@ -478,6 +540,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
}, },
), ),
), ),
],
),
)); ));
} }
// =4 // =4
@ -487,6 +551,17 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
final maxWidth = (durationSeconds / 60 * 230).clamp(80.0, 230.0); final maxWidth = (durationSeconds / 60 * 230).clamp(80.0, 230.0);
List<Widget> audiobody = [ List<Widget> audiobody = [
Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink( Ink(
decoration: BoxDecoration( decoration: BoxDecoration(
color: !(item.isSelf ?? false) ? const Color(0xFFFFFFFF) : const Color(0xFF89E45B), color: !(item.isSelf ?? false) ? const Color(0xFFFFFFFF) : const Color(0xFF89E45B),
@ -551,6 +626,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
}, },
), ),
), ),
],
),
const SizedBox( const SizedBox(
width: 5.0, width: 5.0,
), ),
@ -597,7 +674,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// ID // ID
Get.toNamed('/goods', arguments: {'goodsId': goodsId, 'userID': userID}); Get.toNamed('/goods', arguments: {'goodsId': goodsId, 'userID': userID});
}, },
child: Container( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Container(
width: 160, width: 160,
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [ decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
@ -658,6 +746,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
], ],
), ),
), ),
],
),
), ),
)); ));
} }
@ -672,9 +762,21 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
final width = obj['width'] as num; final width = obj['width'] as num;
final height = obj['height'] as num; final height = obj['height'] as num;
final isHorizontal = width > height; final isHorizontal = width > height;
msgtpl.add(RenderChatItem( msgtpl.add(
RenderChatItem(
data: item, data: item,
child: Ink( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink(
child: InkWell( child: InkWell(
overlayColor: WidgetStateProperty.all(Colors.transparent), overlayColor: WidgetStateProperty.all(Colors.transparent),
child: SizedBox( child: SizedBox(
@ -735,7 +837,10 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// }, // },
), ),
), ),
)); ],
),
),
);
} }
// ==2 // ==2
else if (item.elemType == 2 && item.cloudCustomData == SummaryType.hongbao) { else if (item.elemType == 2 && item.cloudCustomData == SummaryType.hongbao) {
@ -745,7 +850,18 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// final maxNum = obj['maxNum']; // final maxNum = obj['maxNum'];
msgtpl.add(RenderChatItem( msgtpl.add(RenderChatItem(
data: item, data: item,
child: Ink( child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (item.status == MessageStatus.V2TIM_MSG_STATUS_SEND_FAIL) ...[
Icon(
Icons.error,
color: Colors.red,
size: 18,
),
SizedBox(width: 4),
],
Ink(
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFFF7F43), color: const Color(0xFFFF7F43),
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
@ -805,6 +921,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
}, },
), ),
), ),
],
),
)); ));
} }
// =7 // =7
@ -1088,7 +1206,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
} }
// //
Future<void> sendMessage(message) async { Future<void> sendMessage(message, {bool? isHb}) async {
// //
List<V2TimMessage> messagesToInsert = []; List<V2TimMessage> messagesToInsert = [];
V2TimMessage? lastRealMsg; V2TimMessage? lastRealMsg;
@ -1134,9 +1252,15 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// controller.chatList.addAll(messagesToInsert); // controller.chatList.addAll(messagesToInsert);
controller.scrollToBottom(); controller.scrollToBottom();
print('发送成功'); logger.w('发送成功');
if (isHb == true) {
createHb(res.data);
}
} else { } else {
print('消息发送失败: ${res.code} - ${res.desc}'); logger.e('消息发送失败: ${res.code} - ${res.desc}');
if (res.code == 20007) {
MyToast().tip(title: '您已被对方拉黑,无法发送消息', position: 'top');
}
} }
} }
@ -1210,26 +1334,69 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// //
void sendHongbao(date) async { void sendHongbao(date) async {
final amount = date['amount']; // final totalAmount = date['amount']; //
final remark = date['remark']; // final remark = date['remark']; //
final maxNum = date['maxNum']; // final totalCount = date['maxNum']; //
//
final resB = await Http.get(CommonApi.userAccount);
final resData = resB['data']['wallet']; //
if (resData == null) {
// balance.value = double.parse(resData);
MyToast().tip(title: '余额不足');
return;
}
if (double.parse(totalAmount) > double.parse(resData)) {
MyToast().tip(title: '余额不足');
return;
}
//
final makeJson = jsonEncode({ final makeJson = jsonEncode({
"amount": amount, // "packetId": packRes['data']['packetId'],
"packetId": '',
"totalAmount": totalAmount,
"remark": remark, "remark": remark,
"maxNum": maxNum, "totalCount": totalCount, //
"open": false, "open": false,
}); });
final res = await IMMessage().createCustomMessage(data: makeJson); final res = await IMMessage().createCustomMessage(data: makeJson);
if (res.success && (res.data != null)) { if (res.success && (res.data != null)) {
final custMsg = res.data!.messageInfo; final custMsg = res.data!.messageInfo;
custMsg!.cloudCustomData = SummaryType.hongbao; custMsg!.cloudCustomData = SummaryType.hongbao;
sendMessage(res.data!.messageInfo); sendMessage(res.data!.messageInfo, isHb: true);
Get.back(); Navigator.pop(context);
} }
} }
//
void createHb(V2TimMessage msg) async {
// final makeJson = jsonEncode({
// "packetId": packRes['data']['packetId'],
// "packetId": '',
// "totalAmount": totalAmount,
// "remark": remark,
// "totalCount": totalCount, //
// "open": false,
// });
final data = jsonDecode(msg.customElem!.data!);
//
final makeData = {
"chatType": "1",
"totalAmount": data['totalAmount'],
"totalCount": data['totalCount'],
"receiverId": arguments.value.userID,
"remark": data['remark'],
};
logger.w(makeData);
final packRes = await Http.post(CommonApi.redpacket, data: makeData);
data['packetId'] = packRes['data']['packetId'];
msg.customElem!.data = jsonEncode(data);
//
await ImService.instance.modifyMessage(message: msg);
logger.e(packRes);
}
// =3 // =3
void sendImage(imgPath) async { void sendImage(imgPath) async {
final resImg = await IMMessage().createImageMessage(imagePath: imgPath); final resImg = await IMMessage().createImageMessage(imagePath: imgPath);
@ -1479,7 +1646,8 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
context: context, context: context,
builder: (context) { builder: (context) {
final obj = jsonDecode(data.customElem!.data!); final obj = jsonDecode(data.customElem!.data!);
final amount = obj['amount']; final totalAmount = obj['totalAmount'];
final packetId = obj['packetId'];
final remark = obj['remark']; final remark = obj['remark'];
final open = obj['open'] ?? false; final open = obj['open'] ?? false;
@ -1513,7 +1681,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
), ),
SizedBox(height: 10), SizedBox(height: 10),
Text( Text(
amount, totalAmount,
style: const TextStyle(color: Color(0xFFFFF9C7), fontWeight: FontWeight.w500, fontSize: 20.0), style: const TextStyle(color: Color(0xFFFFF9C7), fontWeight: FontWeight.w500, fontSize: 20.0),
), ),
SizedBox(height: 20.0), SizedBox(height: 20.0),
@ -1524,7 +1692,7 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
SizedBox( SizedBox(
height: 100.0, height: 100.0,
), ),
if (open == false && data.isSelf == false) if (open == false)
AnimatedBuilder( AnimatedBuilder(
animation: animTurns, animation: animTurns,
builder: (context, child) { builder: (context, child) {
@ -1550,6 +1718,9 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// //
//-------- //--------
// //
final ctl = Get.find<ImUserInfoController>();
try {
await Http.post(CommonApi.getpacket, data: {"packetId": packetId, "memberId": ctl.userID.value});
obj['open'] = true; //true obj['open'] = true; //true
data.customElem!.data = jsonEncode(obj); data.customElem!.data = jsonEncode(obj);
ImService.instance.modifyMessage(message: data); ImService.instance.modifyMessage(message: data);
@ -1559,6 +1730,9 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
animController.reset(); animController.reset();
Get.back(); Get.back();
}); });
} catch (e) {
logger.e(e);
}
}, },
), ),
); );
@ -1624,6 +1798,25 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// ); // );
} }
//
void _handleBlack() async {
logger.w('开始执行拉黑${arguments.value.userID}');
final res = await ImService.instance.addToBlackList(userIDList: [arguments.value.userID ?? '']);
logger.w(res.success);
//
if (res.success) {
//退
await ImService.instance.deleteConversation(conversationID: arguments.value.conversationID);
final ctl = Get.find<ChatController>();
ctl.chatList.removeWhere(
(conv) => conv.conversation.conversationID == arguments.value.conversationID,
);
ctl.chatList.refresh();
Get.back();
Get.back();
}
}
// //
void sendRedPacketDialog() { void sendRedPacketDialog() {
showModalBottomSheet( showModalBottomSheet(
@ -1639,7 +1832,15 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
builder: (context) { builder: (context) {
return RedPacket( return RedPacket(
flag: false, flag: false,
onSend: (date) { onSend: (date) async {
//
// final res = await ImService.instance.blackList();
// if (res.success && res.data != null) {
// //
// final blackList = res.data;
// blackList
// }
// ImService.instance.isMyFriend(arguments.value.userID!, FriendTypeEnum.V2TIM_FRIEND_TYPE_SINGLE);
sendHongbao(date); sendHongbao(date);
}); });
}, },
@ -1788,10 +1989,33 @@ class _ChatState extends State<Chat> with SingleTickerProviderStateMixin {
// break; // break;
case 'report': case 'report':
print('点击了举报'); // print('点击了举报');
Get.to(() => ReportChat(convsationID: arguments.value.conversationID));
break; break;
case 'block': case 'block':
print('点击了拉黑'); // print('点击了拉黑');
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: const Text('确认要拉黑对方吗?拉黑后将不保留任何聊天记录', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0),
actions: [
TextButton(
onPressed: () {
Get.back();
},
child: const Text('取消', style: TextStyle(color: Colors.black54)),
),
TextButton(onPressed: _handleBlack, child: const Text('确认拉黑', style: TextStyle(color: Colors.red))),
],
);
},
);
break; break;
// case 'foucs': // case 'foucs':
// print('点击了取关'); // print('点击了取关');

View File

@ -8,22 +8,28 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:loopin/IM/controller/chat_detail_controller.dart'; import 'package:loopin/IM/controller/chat_detail_controller.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/im_message.dart'; import 'package:loopin/IM/im_message.dart';
import 'package:loopin/IM/im_result.dart'; import 'package:loopin/IM/im_result.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/components/image_viewer.dart'; import 'package:loopin/components/image_viewer.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/components/preview_video.dart'; import 'package:loopin/components/preview_video.dart';
import 'package:loopin/models/summary_type.dart'; import 'package:loopin/models/summary_type.dart';
import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart'; import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart';
import 'package:loopin/pages/groupChat/groupDetail.dart'; import 'package:loopin/pages/groupChat/groupDetail.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/utils/audio_player_service.dart'; import 'package:loopin/utils/audio_player_service.dart';
import 'package:loopin/utils/parse_message_summary.dart'; import 'package:loopin/utils/parse_message_summary.dart';
import 'package:loopin/utils/snapshot.dart'; import 'package:loopin/utils/snapshot.dart';
import 'package:loopin/utils/voice_service.dart'; import 'package:loopin/utils/voice_service.dart';
import 'package:mime/mime.dart'; import 'package:mime/mime.dart';
import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:shirne_dialog/shirne_dialog.dart';
import 'package:tencent_cloud_chat_sdk/enum/group_type.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_group_info.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:video_player/video_player.dart'; import 'package:video_player/video_player.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart'; import 'package:wechat_assets_picker/wechat_assets_picker.dart';
@ -79,7 +85,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
List chooseOptions = [ List chooseOptions = [
{'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'}, {'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'},
{'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'}, {'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'},
{'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'}, // {'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'},
{'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'}, {'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'},
]; ];
@ -662,10 +668,16 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
} }
// ==2 // ==2
else if (item.elemType == 2 && item.cloudCustomData == SummaryType.hongbao) { else if (item.elemType == 2 && item.cloudCustomData == SummaryType.hongbao) {
//
final selfId = Get.find<ImUserInfoController>().userID.value;
final obj = jsonDecode(item.customElem!.data!); final obj = jsonDecode(item.customElem!.data!);
final open = obj['open'] ?? false; final open = obj['open'] ?? false; // true
final remark = obj['remark']; final remark = obj['remark'];
// final maxNum = obj['maxNum']; final totalCount = obj['totalCount']; //
String idsString = obj['ids'] ?? '';
final ids = idsString.isEmpty ? <String>[] : idsString.split(',');
//
final hasGet = ids.contains(selfId);
msgtpl.add(RenderChatItem( msgtpl.add(RenderChatItem(
data: item, data: item,
child: Ink( child: Ink(
@ -688,7 +700,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
open open || hasGet
? Icon(Icons.check_circle, size: 32.0, color: Colors.white70) ? Icon(Icons.check_circle, size: 32.0, color: Colors.white70)
: Image.asset( : Image.asset(
'assets/images/hbico.png', 'assets/images/hbico.png',
@ -1151,17 +1163,50 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
// //
void sendHongbao(date) async { void sendHongbao(date) async {
final amount = date['amount']; // final totalAmount = date['amount']; //
final remark = date['remark']; // final remark = date['remark']; //
final maxNum = date['maxNum']; // final totalCount = date['maxNum']; //
// //
final makeJson = jsonEncode({
"amount": amount, final makeData = {
"chatType": "2",
"totalAmount": totalAmount,
"totalCount": totalCount,
"groupId": arguments.groupID,
"remark": remark, "remark": remark,
"maxNum": maxNum, };
"open": false,
//
final resB = await Http.get(CommonApi.userAccount);
final resData = resB['data']['wallet']; //
if (resData == null) {
// balance.value = double.parse(resData);
MyToast().tip(title: '余额不足');
return;
}
if (double.parse(totalAmount) > double.parse(resData)) {
MyToast().tip(title: '余额不足');
return;
}
final packRes = await Http.post(CommonApi.redpacket, data: makeData);
logger.e('');
logger.w('红包发送成功响应:$packRes');
final makeJson = jsonEncode({
"packetId": packRes['data']['packetId'], // id
// "totalAmount": totalAmount,
"totalAmount": packRes['data']['totalAmount'], //
"remark": remark,
"totalCount": packRes['data']['totalCount'], //
// "totalCount": totalCount, //
"open": false, //
"ids": '', //,,
}); });
logger.e('红包数据:$makeJson');
logger.e('请求数据:$makeData');
final res = await IMMessage().createCustomMessage(data: makeJson); final res = await IMMessage().createCustomMessage(data: makeJson);
if (res.success && (res.data != null)) { if (res.success && (res.data != null)) {
final custMsg = res.data!.messageInfo; final custMsg = res.data!.messageInfo;
@ -1419,9 +1464,18 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
context: context, context: context,
builder: (context) { builder: (context) {
final obj = jsonDecode(data.customElem!.data!); final obj = jsonDecode(data.customElem!.data!);
final amount = obj['amount']; final totalAmount = obj['totalAmount'];
final remark = obj['remark']; final remark = obj['remark']; // true
final open = obj['open'] ?? false; final open = obj['open'] ?? false;
logger.e('开了吗$open');
final packetId = obj['packetId'];
final selfId = Get.find<ImUserInfoController>().userID.value;
final totalCount = obj['totalCount'] ?? '0'; //
String idsString = obj['ids'] ?? '';
final ids = idsString.isEmpty ? <String>[] : idsString.split(',');
//
final hasGet = ids.contains(selfId);
return Material( return Material(
type: MaterialType.transparency, type: MaterialType.transparency,
@ -1453,7 +1507,7 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
), ),
SizedBox(height: 10), SizedBox(height: 10),
Text( Text(
amount, totalAmount,
style: const TextStyle(color: Color(0xFFFFF9C7), fontWeight: FontWeight.w500, fontSize: 20.0), style: const TextStyle(color: Color(0xFFFFF9C7), fontWeight: FontWeight.w500, fontSize: 20.0),
), ),
SizedBox(height: 20.0), SizedBox(height: 20.0),
@ -1464,7 +1518,10 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
SizedBox( SizedBox(
height: 100.0, height: 100.0,
), ),
if (open == false && data.isSelf == false) if (open == false) ...[
//
if (hasGet == false)
//
AnimatedBuilder( AnimatedBuilder(
animation: animTurns, animation: animTurns,
builder: (context, child) { builder: (context, child) {
@ -1490,20 +1547,63 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
// //
//-------- //--------
// //
obj['open'] = true; //true final ctl = Get.find<ImUserInfoController>();
logger.w(packetId);
try {
final res = await Http.post(CommonApi.getpacket, data: {"packetId": packetId, "memberId": ctl.userID.value});
logger.e('开群红包$res');
if (res != null) {
//
final canGetNum = totalCount - ids.length;
if (canGetNum > 0) {
//
obj['totalCount'] = totalCount - 1;
} else {
//
obj['totalCount'] = 0;
obj['open'] = true; //true
}
// id
ids.add(selfId);
obj['ids'] = ids.join(',');
data.customElem!.data = jsonEncode(obj); data.customElem!.data = jsonEncode(obj);
//
ImService.instance.modifyMessage(message: data); ImService.instance.modifyMessage(message: data);
// 1 // 1
Future.delayed(Duration(seconds: 1), () { Future.delayed(Duration(seconds: 1), () {
animController.stop(); animController.stop();
animController.reset(); animController.reset();
Get.back(); Get.back();
MyToast().tip(
title: '恭喜!抢到了${res['data']['receiveAmount']}',
type: 'success',
position: 'center',
);
}); });
} else {
// 500
obj['totalCount'] = 0;
obj['open'] = true; //true
data.customElem!.data = jsonEncode(obj);
ImService.instance.modifyMessage(message: data);
Future.delayed(Duration(seconds: 1), () {
animController.stop();
animController.reset();
Navigator.pop(context);
});
}
} catch (e) {
logger.e(e);
logger.e('开红包失败');
Get.back();
}
}, },
), ),
); );
}, },
), ),
]
], ],
), ),
), ),
@ -1565,7 +1665,14 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
} }
// //
void sendRedPacketDialog() { void sendRedPacketDialog() async {
final max = await getGroupMaxNumber();
if (max == -1) {
MyToast().tip(title: '获取群资料失败');
return;
}
showModalBottomSheet( showModalBottomSheet(
backgroundColor: Colors.grey[50], backgroundColor: Colors.grey[50],
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(15.0))), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(15.0))),
@ -1579,11 +1686,27 @@ class _ChatGroupState extends State<ChatGroup> with SingleTickerProviderStateMix
builder: (context) { builder: (context) {
return RedPacket( return RedPacket(
flag: true, flag: true,
maxNum: max,
onSend: (date) { onSend: (date) {
sendHongbao(date); sendHongbao(date);
});
}, },
); );
},
);
}
//
Future<int> getGroupMaxNumber() async {
final res = await ImService.instance.getGroupsInfo(groupIDList: [arguments.groupID!]);
if (res.success && res.data != null) {
V2TimGroupInfo info = res.data!.first.groupInfo ?? V2TimGroupInfo(groupID: '', groupType: GroupType.Work);
if (info.groupID.isEmpty) {
return -1;
}
return info.memberCount ?? -1;
} else {
return -1;
}
} }
Future<void> isInGroup() async { Future<void> isInGroup() async {

View File

@ -77,7 +77,7 @@ class _ChatNoFriendState extends State<ChatNoFriend> with SingleTickerProviderSt
List chooseOptions = [ List chooseOptions = [
{'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'}, {'key': 'photo', 'name': '相册', 'icon': 'assets/images/icon_photo.webp'},
{'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'}, {'key': 'camera', 'name': '拍摄', 'icon': 'assets/images/icon_camera.webp'},
{'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'}, // {'key': 'location', 'name': '位置', 'icon': 'assets/images/icon_location.webp'},
{'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'}, {'key': 'redpacket', 'name': '红包', 'icon': 'assets/images/icon_hb.webp'},
]; ];

View File

@ -3,12 +3,13 @@ library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:shirne_dialog/shirne_dialog.dart';
class RedPacket extends StatefulWidget { class RedPacket extends StatefulWidget {
final bool flag; // true=false= final bool flag; // true=false=
final void Function(Map<String, dynamic>)? onSend; final void Function(Map<String, dynamic>)? onSend;
final int? maxNum; // final int? maxNum; //
const RedPacket({super.key, required this.flag, this.onSend, this.maxNum}); const RedPacket({super.key, required this.flag, this.onSend, this.maxNum});
@override @override
@ -22,6 +23,7 @@ class _RedPacketState extends State<RedPacket> {
String amount = '0.00'; String amount = '0.00';
String remark = '恭喜发财,大吉大利'; String remark = '恭喜发财,大吉大利';
String outMax = ''; //
// //
final List<TextInputFormatter> _decimalInputFormatters = [ final List<TextInputFormatter> _decimalInputFormatters = [
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}')), FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}')),
@ -58,7 +60,7 @@ class _RedPacketState extends State<RedPacket> {
const Text('红包个数'), const Text('红包个数'),
Expanded( Expanded(
child: TextField( child: TextField(
maxLength: widget.maxNum, maxLength: widget.maxNum ?? 1, //1
controller: _maxNumController, controller: _maxNumController,
textAlign: TextAlign.right, textAlign: TextAlign.right,
buildCounter: (_, {required currentLength, maxLength, required isFocused}) => null, // buildCounter: (_, {required currentLength, maxLength, required isFocused}) => null, //
@ -66,8 +68,19 @@ class _RedPacketState extends State<RedPacket> {
hintText: "填写个数", isDense: true, hintStyle: TextStyle(fontSize: 14.0), border: OutlineInputBorder(borderSide: BorderSide.none)), hintText: "填写个数", isDense: true, hintStyle: TextStyle(fontSize: 14.0), border: OutlineInputBorder(borderSide: BorderSide.none)),
onChanged: (value) { onChanged: (value) {
// //
if (value.isEmpty) return;
final intValue = int.tryParse(value) ?? 0;
if (intValue > (widget.maxNum ?? 1)) {
// 退
_maxNumController.text = widget.maxNum.toString();
MyToast().tip(title: '当前群内人数为${widget.maxNum}', position: 'top');
//
_maxNumController.selection = TextSelection.fromPosition(
TextPosition(offset: _maxNumController.text.length),
);
}
setState(() { setState(() {
remark = value; outMax = value;
}); });
}, },
), ),
@ -169,12 +182,13 @@ class _RedPacketState extends State<RedPacket> {
shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0))), shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0))),
), ),
onPressed: () { onPressed: () {
FocusScope.of(context).unfocus();
double amountDouble = double.tryParse(amount) ?? 0.0; double amountDouble = double.tryParse(amount) ?? 0.0;
if (amountDouble > 0) { if (amountDouble > 0) {
// //
widget.onSend!( widget.onSend!(
{ {
'maxNum': widget.maxNum ?? 1, 'maxNum': outMax.isEmpty ? '1' : outMax,
'amount': amount, 'amount': amount,
'remark': remark, 'remark': remark,
}, },

View File

@ -0,0 +1,249 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/api/video_api.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/utils/getCommonDictionary.dart';
class ReportChat extends StatefulWidget {
final String convsationID;
const ReportChat({super.key, required this.convsationID});
@override
State<ReportChat> createState() => _ReportChatState();
}
class _ReportChatState extends State<ReportChat> with SingleTickerProviderStateMixin {
int? _selectedIndex;
late dynamic args;
final TextEditingController _reportController = TextEditingController();
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
List<dynamic> reasonTypeData = [];
@override
void initState() {
super.initState();
args = Get.arguments ?? {};
getReportReasons('ums_chat_report'); //
}
@override
void dispose() {
_reportController.dispose();
super.dispose();
}
//
Future<void> getReportReasons(String key) async {
try {
final data = await Commondictionary.getCommonDictionary(key);
setState(() {
reasonTypeData = data;
});
} catch (e) {
print('加载失败: $e');
}
}
//
Future<void> doReport(String dictValue, String reasonText) async {
try {
final res = await Http.post(VideoApi.reportVideoApi, data: {
'type': '1', // 1 2 3
'content': reasonText,
'aimId': widget.convsationID,
'aimType': '5', // 1 2 3 4 5
'reasonType': dictValue
});
if (res['code'] == 200) {
//
MyToast().tip(
title: '投诉成功',
position: 'center',
type: 'success',
);
Get.back(result: {'returnTo': '/'});
} else {
MyToast().tip(
title: '投诉失败',
position: 'center',
type: 'error',
);
}
} catch (e) {
print('投诉失败: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
title: const Text(
'举报',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'您的举报我们将尽快受理,核实后我们将第一时间告知受理结果,请尽量提交完整的举报描述',
style: TextStyle(fontSize: 13, color: Colors.grey, height: 1.4),
),
const SizedBox(height: 20),
//
reasonTypeData.isEmpty
? const Center(child: CircularProgressIndicator())
: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 2,
childAspectRatio: 4,
),
itemCount: reasonTypeData.length,
itemBuilder: (context, index) {
return _buildRadioItem(index);
},
),
const SizedBox(height: 24),
const Text(
'举报描述(选填)',
style: TextStyle(fontSize: 14, color: Colors.black54, fontWeight: FontWeight.w500),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(4),
),
child: TextField(
controller: _reportController,
maxLines: 5,
maxLength: 32,
cursorColor: Colors.black54,
style: const TextStyle(
color: Colors.black54,
fontSize: 14,
),
decoration: const InputDecoration(
contentPadding: EdgeInsets.all(12),
border: InputBorder.none,
hintText: '请输入内容',
hintStyle: TextStyle(color: Colors.grey, fontSize: 13),
),
),
),
Align(
alignment: Alignment.centerRight,
child: Text(
'${_reportController.text.length}/32',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
),
const SizedBox(height: 30),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _selectedIndex != null ? _submitReport : null,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
child: const Text('提交', style: TextStyle(fontSize: 15)),
),
),
],
),
),
),
);
}
Widget _buildRadioItem(int index) {
final item = reasonTypeData[index];
final isSelected = _selectedIndex == index;
return GestureDetector(
onTap: () {
setState(() {
_selectedIndex = index;
});
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected ? Colors.green : Colors.grey,
width: 1.5,
),
),
child: isSelected
? Center(
child: Container(
width: 12,
height: 12,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.green,
),
),
)
: null,
),
const SizedBox(width: 8),
Expanded(
child: Text(
item['dictLabel'] ?? '未知原因',
style: TextStyle(
fontSize: 13,
color: isSelected ? Colors.green : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
),
);
}
void _submitReport() {
if (_selectedIndex == null) {
MyToast().tip(
title: '请选择举报原因!',
position: 'center',
type: 'error',
);
return;
}
//
final selectedReason = reasonTypeData[_selectedIndex!];
final reasonText = _reportController.text;
doReport(selectedReason['dictValue'], reasonText);
}
}

View File

@ -6,10 +6,12 @@ import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/IM/controller/chat_controller.dart'; import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/global_badge.dart'; import 'package:loopin/IM/global_badge.dart';
import 'package:loopin/IM/im_service.dart'; import 'package:loopin/IM/im_service.dart';
import 'package:loopin/api/shop_api.dart'; import 'package:loopin/api/shop_api.dart';
import 'package:loopin/components/empty_tip.dart'; import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/components/scan_util.dart'; import 'package:loopin/components/scan_util.dart';
import 'package:loopin/models/conversation_type.dart' as myConversationType; import 'package:loopin/models/conversation_type.dart' as myConversationType;
@ -69,9 +71,11 @@ class ChatPageState extends State<ChatPage> {
// 使 // 使
final scanType = ScanCodeType.fromCode(code); final scanType = ScanCodeType.fromCode(code);
if (scanType != null) { if (scanType != null) {
final value = code.substring(scanType.prefix.length + 1); // // final value = code.substring(scanType.prefix.length + 1); //
_processScanCode(scanType, value); // _processScanCode(scanType, value);
_processScanCode(scanType, code);
} else { } else {
// //
Get.snackbar('未知的二维码类型', '无法识别此二维码: $code'); Get.snackbar('未知的二维码类型', '无法识别此二维码: $code');
@ -96,8 +100,16 @@ class ChatPageState extends State<ChatPage> {
// //
void _handleVerificationCode(String value) async { void _handleVerificationCode(String value) async {
print('处理核销码: $value'); print('处理核销码: $value');
final controller = Get.find<ImUserInfoController>();
final role = controller.role.value;
final isSeller = Utils.hasRole(role, 2);
if (isSeller) {
// //
Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId': value}); Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId': value});
} else {
//
MyToast().tip(title: '未入驻的商家不可操作');
}
} }
// //
@ -315,19 +327,19 @@ class ChatPageState extends State<ChatPage> {
], ],
), ),
), ),
PopupMenuItem<String>( // PopupMenuItem<String>(
value: 'cs', // value: 'cs',
child: Row( // child: Row(
children: [ // children: [
Icon(Icons.qr_code_scanner, color: Colors.white, size: 18), // Icon(Icons.qr_code_scanner, color: Colors.white, size: 18),
SizedBox(width: 8), // SizedBox(width: 8),
Text( // Text(
'测试', // '测试',
style: TextStyle(color: Colors.white), // style: TextStyle(color: Colors.white),
), // ),
], // ],
), // ),
), // ),
], ],
); );
@ -345,10 +357,11 @@ class ChatPageState extends State<ChatPage> {
logger.w('点击了扫一扫'); logger.w('点击了扫一扫');
ScanUtil.openScanner(onResult: handleScanResult); ScanUtil.openScanner(onResult: handleScanResult);
break; break;
case 'cs': // case 'cs':
logger.w('去互动'); // logger.w('去互动');
Get.toNamed('/newFoucs'); // // order newFoucs interaction
break; // Get.toNamed('/interaction');
// break;
} }
} }
}, },
@ -563,9 +576,10 @@ class ChatPageState extends State<ChatPage> {
const SizedBox(height: 2.0), const SizedBox(height: 2.0),
// //
Text( Text(
chatList[index].conversation.lastMessage != null _handleLast(index),
? parseMessageSummary(chatList[index].conversation.lastMessage!) // chatList[index].conversation.lastMessage != null
: '', // ? parseMessageSummary(chatList[index].conversation.lastMessage!)
// : '',
style: const TextStyle(color: Colors.grey, fontSize: 13.0), style: const TextStyle(color: Colors.grey, fontSize: 13.0),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
@ -660,4 +674,24 @@ class ChatPageState extends State<ChatPage> {
), ),
); );
} }
String _handleLast(index) {
// logger.e('开始处理显示');
//
// final outConv = controller.chatList.firstWhere(
// (conv) => conv.conversation.customData == 'out',
// orElse: () => ConversationViewModel(conversation: V2TimConversation(conversationID: '')),
// );
// logger.e('conv=${controller.chatList[index].conversation.toLogString()}');
if (controller.chatList[index].conversation.customData == 'out') {
// logger.e('找到了');
// ,
return '你已被移出群聊';
} else {
final str = controller.chatList[index].conversation.lastMessage != null ? parseMessageSummary(controller.chatList[index].conversation.lastMessage!) : '';
return str;
}
}
} }

View File

@ -5,6 +5,7 @@ import 'package:loopin/IM/im_friend_listeners.dart';
import 'package:loopin/components/my_qrcode.dart'; import 'package:loopin/components/my_qrcode.dart';
import 'package:loopin/components/my_toast.dart'; import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/scan_util.dart'; import 'package:loopin/components/scan_util.dart';
import 'package:loopin/utils/index.dart';
import 'package:loopin/utils/scan_code_type.dart'; import 'package:loopin/utils/scan_code_type.dart';
class AddFriend extends StatefulWidget { class AddFriend extends StatefulWidget {
@ -55,8 +56,18 @@ class _AddFriendState extends State<AddFriend> {
// //
void _handleVerificationCode(String value) async { void _handleVerificationCode(String value) async {
logger.w('处理核销码: $value'); logger.w('处理核销码: $value');
//
final controller = Get.find<ImUserInfoController>();
final role = controller.role.value;
final isSeller = Utils.hasRole(role, 2);
if (isSeller) {
// //
Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId': value}); Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId': value});
} else {
//
MyToast().tip(title: '无法识别');
}
// Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId': value});
} }
// //

View File

@ -7,11 +7,13 @@ import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.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/behavior/custom_scroll_behavior.dart'; import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/empty_tip.dart'; import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart'; import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/models/notify_message.type.dart'; import 'package:loopin/models/notify_message.type.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart'; import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart'; import 'package:loopin/utils/index.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
@ -44,7 +46,7 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
{'value': 'all', 'label': '全部', 'icon': Icons.all_inclusive}, {'value': 'all', 'label': '全部', 'icon': Icons.all_inclusive},
{'value': NotifyMessageTypeConstants.interactionLike, 'label': '点赞', 'icon': Icons.favorite_border}, {'value': NotifyMessageTypeConstants.interactionLike, 'label': '点赞', 'icon': Icons.favorite_border},
{'value': NotifyMessageTypeConstants.interactionComment, 'label': '评论', 'icon': Icons.comment}, {'value': NotifyMessageTypeConstants.interactionComment, 'label': '评论', 'icon': Icons.comment},
{'value': NotifyMessageTypeConstants.interactionAt, 'label': '@我', 'icon': Icons.alternate_email}, // {'value': NotifyMessageTypeConstants.interactionAt, 'label': '@我', 'icon': Icons.alternate_email},
{'value': NotifyMessageTypeConstants.interactionReply, 'label': '回复', 'icon': Icons.reply}, {'value': NotifyMessageTypeConstants.interactionReply, 'label': '回复', 'icon': Icons.reply},
]; ];
RxList demoList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].obs; RxList demoList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].obs;
@ -58,6 +60,7 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
final lastmsg = conv?.lastMessage; final lastmsg = conv?.lastMessage;
if (lastmsg != null) { if (lastmsg != null) {
msgList.add(lastmsg); msgList.add(lastmsg);
getMsgData();
} }
} }
// chatController.addListener(() { // chatController.addListener(() {
@ -74,6 +77,18 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
// }); // });
} }
@override
void dispose() {
cleanUnRead();
super.dispose();
}
void cleanUnRead() async {
if ((conv?.unreadCount ?? 0) > 0) {
await ImService.instance.clearConversationUnreadCount(conversationID: conv?.conversationID ?? '');
}
}
// //
Future<void> getMsgData() async { Future<void> getMsgData() async {
// //
@ -260,14 +275,14 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
childBuilder: (context, physics) { childBuilder: (context, physics) {
return Obx( return Obx(
() { () {
// if (msgList.isEmpty) return EmptyTip(); if (msgList.isEmpty) return EmptyTip();
if (demoList.isEmpty) return EmptyTip(); // if (demoList.isEmpty) return EmptyTip();
return ListView.builder( return ListView.builder(
// controller: chatController, // controller: chatController,
shrinkWrap: true, shrinkWrap: true,
physics: physics, physics: physics,
// itemCount: msgList.length, itemCount: msgList.length,
itemCount: demoList.length, // itemCount: demoList.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
//cloudCustomData //cloudCustomData
// interactionComment, //-> // interactionComment, //->
@ -276,17 +291,18 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
// interactionReply, //-> // interactionReply, //->
//---- //----
final element = msgList[index];
// final element = msgList[index].customElem!; // final element = msgList[index].customElem!;
// final cloudCustomData = msgList[index].cloudCustomData; final cloudCustomData = msgList[index].cloudCustomData;
// final desc = msgList[index].customElem!.desc!; final desc = msgList[index].customElem!.desc!;
// final jsonData = msgList[index].customElem!.data; final jsonData = msgList[index].customElem!.data ?? '{"faceUrl":"","nickName":"data为null","userID":"213213"}';
// ----
final jsonData = '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}';
final item = jsonDecode(jsonData); // final item = jsonDecode(jsonData); //
final desc = '测试desc'; // ----
final cloudCustomData = 'interactionLike'; // final jsonData = '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}';
V2TimMessage element = V2TimMessage(elemType: 2, isRead: index > 2 ? true : false); // final item = jsonDecode(jsonData); //
// final desc = '测试desc';
// final cloudCustomData = 'interactionLike';
// V2TimMessage element = V2TimMessage(elemType: 2, isRead: index > 2 ? true : false);
return Container( return Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0), padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0),
@ -300,10 +316,9 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
// //
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id // cloudCustomData是interactionCommentinteractionAtinteractionReply,id
// //
// final res = await Http.get('${VideoApi.detail}/${item['vlogID']}'); final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
// //
// Get.toNamed('/vloger', arguments: res['data']); Get.toNamed('/vloger', arguments: res['data']);
Get.toNamed('/vloger');
}, },
child: ClipOval( child: ClipOval(
child: NetworkOrAssetImage( child: NetworkOrAssetImage(
@ -317,14 +332,14 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
// //
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () async {
// //
// //
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id // cloudCustomData是interactionCommentinteractionAtinteractionReply,id
// //
// final res = await Http.get('${VideoApi.detail}/${item['vlogID']}'); final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
// Get.toNamed('/vloger', arguments: res['data']); Get.toNamed('/vloger', arguments: res['data']);
Get.toNamed('/vloger'); // Get.toNamed('/vloger');
}, },
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -343,8 +358,7 @@ class InteractionState extends State<Interaction> with SingleTickerProviderState
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.grey, fontSize: 12.0), style: const TextStyle(color: Colors.grey, fontSize: 12.0),
// desc, desc,
'很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容',
), ),
Text( Text(
Utils.formatTime(element.timestamp ?? DateTime.now().millisecondsSinceEpoch ~/ 1000), Utils.formatTime(element.timestamp ?? DateTime.now().millisecondsSinceEpoch ~/ 1000),

View File

@ -10,6 +10,7 @@ import 'package:loopin/IM/im_service.dart';
import 'package:loopin/api/video_api.dart'; import 'package:loopin/api/video_api.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart'; import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/empty_tip.dart'; import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart'; import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
@ -48,10 +49,23 @@ class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin
final lastmsg = conv?.lastMessage; final lastmsg = conv?.lastMessage;
if (lastmsg != null) { if (lastmsg != null) {
msgList.add(lastmsg); msgList.add(lastmsg);
getMsgData();
} }
} }
} }
@override
void dispose() {
cleanUnRead();
super.dispose();
}
void cleanUnRead() async {
if ((conv?.unreadCount ?? 0) > 0) {
await ImService.instance.clearConversationUnreadCount(conversationID: conv?.conversationID ?? '');
}
}
// //
Future<void> getMsgData() async { Future<void> getMsgData() async {
// //
@ -172,7 +186,7 @@ class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin
String? jsonData = msgList[index].customElem!.data; String? jsonData = msgList[index].customElem!.data;
jsonData = (jsonData == null || jsonData.isEmpty) ? '{"faceUrl":"","nickName":"data为空","userID":"213213"}' : jsonData; jsonData = (jsonData == null || jsonData.isEmpty) ? '{"faceUrl":"","nickName":"data为空","userID":"213213"}' : jsonData;
final item = jsonDecode(jsonData ?? '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}'); final item = jsonDecode(jsonData);
logger.w(element.toJson()); logger.w(element.toJson());
@ -197,8 +211,12 @@ class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id // cloudCustomData是interactionCommentinteractionAtinteractionReply,id
// //
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}'); final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
if (res['data'] == null) {
MyToast().tip(title: '视频数据不存在', position: 'top');
} else {
//
Get.toNamed('/vloger', arguments: res['data']); Get.toNamed('/vloger', arguments: res['data']);
// Get.toNamed('/vloger'); }
}, },
child: ClipOval( child: ClipOval(
child: NetworkOrAssetImage( child: NetworkOrAssetImage(

View File

@ -1,290 +0,0 @@
///
library;
import 'dart:convert';
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/api/video_api.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_custom_elem.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
// newFocus,
class Newfoucs extends StatefulWidget {
const Newfoucs({super.key});
@override
State<Newfoucs> createState() => NewfoucsState();
}
class NewfoucsState extends State<Newfoucs> with SingleTickerProviderStateMixin {
bool isLoading = false; //
RxBool hasMore = true.obs; //
String page = '';
///-------------------
V2TimConversation? conv;
RxList<V2TimMessage> msgList = <V2TimMessage>[].obs;
@override
void initState() {
super.initState();
if (Get.arguments != null && Get.arguments is V2TimConversation) {
//
conv = Get.arguments as V2TimConversation;
logger.e('lastmsg:$conv');
final lastmsg = conv?.lastMessage;
if (lastmsg != null) {
msgList.add(lastmsg);
}
}
}
//
Future<void> getMsgData() async {
//
V2TimMessage? lastRealMsg;
lastRealMsg = msgList.last;
final res = await ImService.instance.getHistoryMessageList(
userID: ConversationType.newFocus.name, // userID为固定的newFocus
lastMsg: lastRealMsg,
);
if (res.success && res.data != null) {
msgList.addAll(res.data!);
logger.e(msgList);
if (res.data!.isEmpty) {
hasMore.value = false;
}
logger.i('聊天数据加载成功');
} else {
logger.e('聊天数据加载失败:${res.desc}');
}
}
//
Future<void> handleRefresh() async {
await Future.delayed(Duration(seconds: 5));
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
centerTitle: true,
forceMaterialTransparency: true,
bottom: PreferredSize(
preferredSize: Size.fromHeight(1.0),
child: Container(
color: Colors.grey[300],
height: 1.0,
),
),
title: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(width: 4),
Text(
'新的关注',
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
),
actions: [],
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: Column(
children: [
Expanded(
child: EasyRefresh.builder(
callLoadOverOffset: 20, //
callRefreshOverOffset: 20, //
header: ClassicHeader(
dragText: '下拉刷新',
armedText: '释放刷新',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
footer: ClassicFooter(
dragText: '加载更多',
armedText: '释放加载',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
noMoreText: '没有更多了~',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
onRefresh: () async {
await handleRefresh();
},
onLoad: () async {
if (hasMore.value) {
await getMsgData();
return hasMore.value ? IndicatorResult.success : IndicatorResult.noMore;
}
},
childBuilder: (context, physics) {
return Obx(
() {
if (msgList.isEmpty) return EmptyTip();
return ListView.builder(
shrinkWrap: true,
physics: physics,
itemCount: msgList.length,
itemBuilder: (context, index) {
//cloudCustomData
///[userID],
///[nickName],
///[faceUrl],
//----
V2TimMessage msg = msgList[index];
V2TimCustomElem element = msgList[index].customElem!;
final cloudCustomData = msgList[index].cloudCustomData;
logger.w(cloudCustomData);
final desc = msgList[index].customElem!.desc!;
String? jsonData = msgList[index].customElem!.data;
jsonData = (jsonData == null || jsonData.isEmpty) ? '{"faceUrl":"","nickName":"data为空","userID":"213213"}' : jsonData;
final item = jsonDecode(jsonData ?? '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}');
logger.w(element.toJson());
// ----
// final jsonData = '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}';
// final item = jsonDecode(jsonData); //
// final desc = '测试desc';
// final cloudCustomData = 'newFocus';
// V2TimCustomElem msg = V2TimMessage(elemType: 2, isRead: index > 2 ? true : false);
// -----------
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0),
child: Row(
spacing: 10.0,
children: <Widget>[
//
InkWell(
onTap: () async {
//
//
// cloudCustomData是interactionCommentinteractionAtinteractionReply,id
//
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
Get.toNamed('/vloger', arguments: res['data']);
// Get.toNamed('/vloger');
},
child: ClipOval(
child: NetworkOrAssetImage(
imageUrl: item['faceUrl'],
width: 50,
height: 50,
),
),
),
//
Expanded(
child: InkWell(
onTap: () async {
// ,
final res = await Http.get('${VideoApi.detail}/${item['vlogID']}');
Get.toNamed('/vloger', arguments: res['data']);
// Get.toNamed('/vloger');
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//
Text(
item['nickName'] ?? '未知',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
),
),
const SizedBox(height: 2.0),
//
Text(
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.grey, fontSize: 12.0),
desc,
// '很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容很长文本内容',
),
Text(
Utils.formatTime(msg.timestamp ?? DateTime.now().millisecondsSinceEpoch ~/ 1000),
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
],
),
),
),
//
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Visibility(
visible: false, //
//
child: NetworkOrAssetImage(
imageUrl: item['firstFrameImg'],
placeholderAsset: 'assets/images/bk.jpg',
width: 40,
height: 60,
),
),
const SizedBox(width: 5.0),
//
Visibility(
visible: !(msg.isRead ?? true),
child: FStyle.badge(0, isdot: true),
),
],
),
],
),
);
},
);
},
);
},
),
),
],
),
),
);
}
}

View File

@ -0,0 +1,391 @@
///
library;
import 'dart:convert';
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/components/empty_tip.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/models/notify_message.type.dart';
import 'package:loopin/pages/my/merchant/balance/balance.dart';
import 'package:loopin/pages/my/merchant/balance/controller.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_message.dart';
// order,
class OrderNotify extends StatefulWidget {
const OrderNotify({super.key});
@override
State<OrderNotify> createState() => OrderNotifyState();
}
class OrderNotifyState extends State<OrderNotify> with SingleTickerProviderStateMixin {
bool isLoading = false; //
RxBool hasMore = true.obs; //
String page = '';
///-------------------
V2TimConversation? conv;
RxList<V2TimMessage> msgList = <V2TimMessage>[].obs;
@override
void initState() {
super.initState();
if (Get.arguments != null && Get.arguments is V2TimConversation) {
//
conv = Get.arguments as V2TimConversation;
logger.e('lastmsg:$conv');
final lastmsg = conv?.lastMessage;
if (lastmsg != null) {
msgList.add(lastmsg);
getMsgData();
}
}
}
@override
void dispose() {
cleanUnRead();
super.dispose();
}
void cleanUnRead() async {
if ((conv?.unreadCount ?? 0) > 0) {
await ImService.instance.clearConversationUnreadCount(conversationID: conv?.conversationID ?? '');
}
}
//
Future<void> getMsgData() async {
//
V2TimMessage? lastRealMsg;
lastRealMsg = msgList.last;
final res = await ImService.instance.getHistoryMessageList(
userID: ConversationType.order.name, // userID为固定的order
lastMsg: lastRealMsg,
);
if (res.success && res.data != null) {
msgList.addAll(res.data!);
logger.e(msgList);
if (res.data!.isEmpty) {
hasMore.value = false;
}
logger.i('聊天数据加载成功');
} else {
logger.e('聊天数据加载失败:${res.desc}');
}
}
//
Future<void> handleRefresh() async {
await Future.delayed(Duration(seconds: 5));
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
centerTitle: true,
forceMaterialTransparency: true,
bottom: PreferredSize(
preferredSize: Size.fromHeight(1.0),
child: Container(
color: Colors.grey[300],
height: 1.0,
),
),
title: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(width: 4),
Text(
'订单通知',
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
),
actions: [],
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: Column(
children: [
Expanded(
child: EasyRefresh.builder(
callLoadOverOffset: 20, //
callRefreshOverOffset: 20, //
header: ClassicHeader(
dragText: '下拉刷新',
armedText: '释放刷新',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
footer: ClassicFooter(
dragText: '加载更多',
armedText: '释放加载',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
noMoreText: '没有更多了~',
failedText: '加载失败,请重试',
messageText: '最后更新于 %T',
),
onRefresh: () async {
await handleRefresh();
},
onLoad: () async {
if (hasMore.value) {
await getMsgData();
return hasMore.value ? IndicatorResult.success : IndicatorResult.noMore;
}
},
childBuilder: (context, physics) {
return Obx(
() {
if (msgList.isEmpty) return EmptyTip();
return ListView.builder(
shrinkWrap: true,
physics: physics,
itemCount: msgList.length,
itemBuilder: (context, index) {
//cloudCustomData
/// [orderID]
/// [amount]
/// [name]
/// [describe]
/// [price]
/// [pic]
//----
V2TimMessage msg = msgList[index];
// V2TimCustomElem element = msgList[index].customElem;
final cloudCustomData = msgList[index].cloudCustomData ?? '';
logger.w(cloudCustomData);
final desc = msgList[index].customElem?.desc;
String? jsonData = msgList[index].customElem?.data;
logger.e(msgList[index].toJson());
jsonData = (jsonData == null || jsonData.isEmpty) ? '{"faceUrl":"","nickName":"data为空","userID":"213213"}' : jsonData;
var item = jsonDecode(jsonData);
if (item is Map<String, dynamic>) {
item = jsonDecode(jsonData);
} else {
// Map
item = {
"faceUrl": "",
"nickName": "数据异常",
"userID": "",
};
}
final showName = conv?.showName ?? '未知';
// logger.w(element.toJson());
// ----
// final jsonData = '{"faceUrl":"","nickName":"测试昵称","userID":"213213"}';
// final item = jsonDecode(jsonData); //
// final desc = '您购买的巧克力已经下单成功您购买的巧克力已经下单成功您购买的巧克力已经下单成功';
// final cloudCustomData = 'orderRefund';
// V2TimMessage msg = V2TimMessage(elemType: 2, isRead: index > 2 ? true : false);
// -----------
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0),
child: Row(
children: <Widget>[
Expanded(
child: InkWell(
onTap: () async {
if (cloudCustomData == NotifyMessageTypeConstants.orderWithDraw ||
cloudCustomData == NotifyMessageTypeConstants.orderRecharge) {
//
Get.put(BalanceController());
Get.to(() => Balance());
} else {
//
Get.toNamed('/order/detail', arguments: {'orderId': item['orderID']});
}
},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
// +
Row(
children: [
ClipOval(
child: NetworkOrAssetImage(
imageUrl: msg.faceUrl,
width: 25,
height: 25,
),
),
const SizedBox(width: 8),
Expanded(
child: Text(
showName,
// item['name'] ?? '未知商品名称',
// cloudCustomData == NotifyMessageTypeConstants.orderWithDraw
// ? (conv?.showName ?? '未知')
// : ((item['name'] as String?) ?? '未知商品名称'),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Colors.black54,
),
),
),
],
),
const SizedBox(height: 8),
const Divider(height: 1, thickness: 1, color: Color(0xFFE0E0E0)),
const SizedBox(height: 4),
Text(
_transLabel(cloudCustom: cloudCustomData, status: item['status']),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 2),
//
Text(
Utils.formatTime(msg.timestamp ?? DateTime.now().millisecondsSinceEpoch ~/ 1000),
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
const SizedBox(height: 8),
// + +
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
//
Visibility(
visible: item['pic'] != null && item['pic'].toString().isNotEmpty,
child: NetworkOrAssetImage(
imageUrl: item['pic'],
placeholderAsset: 'assets/images/bk.jpg',
width: 50,
height: 50,
),
),
SizedBox(
width: 8,
),
//
Expanded(
child: Text(
desc ?? '未知描述',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black87, fontSize: 12.0),
),
),
const SizedBox(width: 20),
//
Visibility(
visible: !(msg.isRead ?? true),
child: FStyle.badge(0, isdot: true),
),
],
),
SizedBox(
height: 8,
),
const Divider(height: 1, thickness: 1, color: Color(0xFFE0E0E0)),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0),
child: Row(
children: [
const Text('查看详情'),
const Spacer(),
const Icon(Icons.arrow_forward_ios, size: 16, color: Colors.grey),
],
),
),
],
),
),
),
),
),
],
),
);
},
);
},
);
},
),
),
],
),
),
);
}
///
String _transLabel({required String cloudCustom, String? status}) {
//
var str = status == null
? '未知状态'
: status == '1'
? '成功'
: '失败';
if (NotifyMessageTypeConstants.orderPay == cloudCustom) {
return '下单成功';
} else if (NotifyMessageTypeConstants.orderRecharge == cloudCustom) {
return '充值成功';
} else if (NotifyMessageTypeConstants.orderRefund == cloudCustom) {
return '退款$str';
} else if (NotifyMessageTypeConstants.orderWithDraw == cloudCustom) {
return '提现$str';
} else {
return '未知action';
}
}
}

View File

@ -1,517 +1 @@
///
library;
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/IM/controller/chat_controller.dart';
import 'package:loopin/IM/global_badge.dart';
import 'package:loopin/IM/im_service.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/api/shop_api.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/components/scan_util.dart';
import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/models/conversation_view_model.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/parse_message_summary.dart';
import 'package:loopin/utils/scan_code_type.dart'; //
import 'package:shirne_dialog/shirne_dialog.dart';
// systemNotify, // ->
// systemReport, // ->
// systemCheck, // ->
// systemPush, //->广
class System extends StatefulWidget {
const System({super.key});
@override
State<System> createState() => SystemState();
}
class SystemState extends State<System> {
late final ChatController controller;
dynamic writeOffInfo;
@override
void initState() {
super.initState();
controller = Get.find<ChatController>();
}
void deletConv(context, ConversationViewModel item) async {
final res = await ImService.instance.deleteConversation(conversationID: item.conversation.conversationID);
if (res.success) {
Navigator.of(context).pop();
controller.chatList.remove(item);
}
}
//
double posDX = 0.0;
double posDY = 0.0;
//
Future<void> handleRefresh() async {
await Future.delayed(Duration(seconds: 1));
setState(() {});
}
//
void showContextMenu(BuildContext context, ConversationViewModel item) {
bool isLeft = posDX > MediaQuery.of(context).size.width / 2 ? false : true;
bool isTop = posDY > MediaQuery.of(context).size.height / 2 ? false : true;
showDialog(
context: context,
barrierColor: Colors.black12, //
builder: (context) {
return Stack(
children: [
Positioned(
top: isTop ? posDY : posDY - 135,
left: isLeft ? posDX : posDX - 135,
width: 135,
child: Material(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
color: Colors.white,
elevation: 2.0,
clipBehavior: Clip.hardEdge,
child: Column(
children: [
ListTile(
title: const Text(
'设为免打扰',
style: TextStyle(color: Colors.black87, fontSize: 14.0),
),
dense: true,
onTap: () {},
),
ListTile(
title: const Text(
'置顶消息',
style: TextStyle(color: Colors.black87, fontSize: 14.0),
),
dense: true,
onTap: () {},
),
ListTile(
title: const Text(
'不显示该消息',
style: TextStyle(color: Colors.black87, fontSize: 14.0),
),
dense: true,
onTap: () {},
),
ListTile(
title: const Text(
'删除',
style: TextStyle(color: Colors.black87, fontSize: 14.0),
),
dense: true,
onTap: () {
deletConv(context, item);
},
)
],
),
),
)
],
);
},
);
}
//
void handleScanResult(String code) {
print('扫码结果:$code');
// 使
final scanType = ScanCodeType.fromCode(code);
if (scanType != null) {
final value = code.substring(scanType.prefix.length + 1); //
_processScanCode(scanType, value);
} else {
//
Get.snackbar('未知的二维码类型', '无法识别此二维码: $code');
}
}
//
void _processScanCode(ScanCodeType type, String value) {
switch (type) {
case ScanCodeType.verification:
_handleVerificationCode(value);
break;
case ScanCodeType.friend:
_handleFriendCode(value);
break;
case ScanCodeType.promotion:
_handlePromotionCode(value);
break;
}
}
//
void _handleVerificationCode (String value) async {
print('处理核销码: $value');
//
Get.toNamed('/sellerOrder/detail', arguments: {'writeOffCodeId':value});
}
//
void _handleFriendCode(String value) {
print('处理好友码: $value');
// 仿
Get.toNamed('/vloger', arguments: {'memberId':value});
}
// 广
void _handlePromotionCode(String value)async {
try {
print('处理推广码111: $value');
final res = await Http.post('${ShopApi.bindSpreadCodeId}', data: {
"socialCode": value
});
if(res != null && res['code'] == 200){
MyDialog.toast('推广码绑定成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200)));
Get.toNamed('/vloger', arguments: {'memberId':value});
}
} catch (e) {
MyDialog.toast('推广码绑定失败');
}
}
// 广
bindSpreadCode(code) async {
try {
final res = await Http.post('${ShopApi.bindSpreadCodeId}', data: {
"socialCode": "01901839908031348736"
});
print('绑定结果-------------->${res['res']}');
} catch (e) {
MyDialog.toast('推广码绑定失败');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(
forceMaterialTransparency: true,
title: Row(
spacing: 8.0,
children: [
Text('消息'),
Container(
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 4.0),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20.0), boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(20),
offset: Offset(0.0, 1.0),
blurRadius: 2.0,
spreadRadius: 0.0,
),
]),
child: InkWell(
onTap: () async {
if (Get.find<GlobalBadge>().totalUnread > 0) {
final res = await ImService.instance.clearConversationUnreadCount(conversationID: '');
if (res.success) {
MyDialog.toast('操作成功', icon: const Icon(Icons.check_circle), style: ToastStyle(backgroundColor: Colors.green.withAlpha(200)));
} else {
MyDialog.toast(res.desc, icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
}
}
},
child: Row(
spacing: 3.0,
children: [
Icon(
Icons.cleaning_services_sharp,
size: 14.0,
),
Text(
'清除未读',
style: TextStyle(fontSize: 12.0),
)
],
),
)),
],
),
actions: [
///
// IconButton(
// icon: const Icon(Icons.search),
// onPressed: () {},
// ),
IconButton(
icon: const Icon(Icons.add_circle_outline),
onPressed: () async {
final paddingTop = MediaQuery.of(Get.context!).padding.top;
final selected = await showMenu(
context: Get.context!,
position: RelativeRect.fromLTRB(
double.infinity,
kToolbarHeight + paddingTop - 12,
8,
double.infinity,
),
color: FStyle.primaryColor,
elevation: 8,
items: [
PopupMenuItem<String>(
value: 'group',
child: Row(
children: [
Icon(Icons.group, color: Colors.white, size: 18),
SizedBox(width: 8),
Text(
'发起群聊',
style: TextStyle(color: Colors.white),
),
],
),
),
PopupMenuItem<String>(
value: 'friend',
child: Row(
children: [
Icon(Icons.person_add, color: Colors.white, size: 18),
SizedBox(width: 8),
Text(
'添加朋友',
style: TextStyle(color: Colors.white),
),
],
),
),
PopupMenuItem<String>(
value: 'scan',
child: Row(
children: [
Icon(Icons.qr_code_scanner, color: Colors.white, size: 18),
SizedBox(width: 8),
Text(
'扫一扫',
style: TextStyle(color: Colors.white),
),
],
),
),
],
);
if (selected != null) {
switch (selected) {
case 'group':
print('点击了发起群聊');
break;
case 'friend':
print('点击了添加朋友');
break;
case 'scan':
print('点击了扫一扫');
ScanUtil.openScanner(onResult: handleScanResult);
break;
}
}
},
),
],
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: Column(
children: [
Container(
margin: EdgeInsets.symmetric(horizontal: 15.0, vertical: 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: 2.0,
spreadRadius: 0.0,
),
]),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
SvgPicture.asset(
'assets/images/svg/order.svg',
height: 36.0,
width: 36.0,
),
Text('群聊'),
],
),
Column(
children: [
SvgPicture.asset(
'assets/images/svg/kefu.svg',
height: 36.0,
width: 36.0,
),
Text('互关'),
],
),
Column(
children: [
SvgPicture.asset(
'assets/images/svg/comment.svg',
height: 36.0,
width: 36.0,
),
Text('粉丝'),
],
),
Column(
children: [
SvgPicture.asset(
'assets/images/svg/comment.svg',
height: 36.0,
width: 36.0,
),
Text('关注'),
],
),
],
),
),
Expanded(
child: RefreshIndicator(
backgroundColor: Colors.white,
color: Color(0xFFFF5000),
displacement: 10.0,
onRefresh: handleRefresh,
child: Obx(() {
final chatList = controller.chatList;
return ListView.builder(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: chatList.length,
itemBuilder: (context, index) {
return Ink(
// color: chatList[index]['topMost'] == null ? Colors.white : Colors.grey[100], //
child: InkWell(
splashColor: Colors.grey[200],
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 10.0),
child: Row(
spacing: 10.0,
children: <Widget>[
//
ClipOval(
child: NetworkOrAssetImage(
imageUrl: chatList[index].faceUrl,
width: 50,
height: 50,
),
),
//
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
chatList[index].conversation.showName ?? '未知',
style: TextStyle(
fontSize: (chatList[index].conversation.conversationGroupList!.contains(ConversationType.noFriend.name)) ||
chatList[index].isCustomAdmin != '0'
? 20
: 16,
fontWeight: (chatList[index].conversation.conversationGroupList!.contains(ConversationType.noFriend.name)) ||
chatList[index].isCustomAdmin != '0'
? FontWeight.bold
: FontWeight.normal),
),
const SizedBox(height: 2.0),
Text(
chatList[index].conversation.lastMessage != null
? parseMessageSummary(chatList[index].conversation.lastMessage!)
: '',
style: const TextStyle(color: Colors.grey, fontSize: 13.0),
overflow: TextOverflow.ellipsis,
),
],
),
),
//
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Visibility(
visible: !(chatList[index].isCustomAdmin != '0' ||
chatList[index].conversation.conversationGroupList!.contains(ConversationType.noFriend.name)),
child: Text(
//
DateTime.fromMillisecondsSinceEpoch(
(chatList[index].conversation.lastMessage!.timestamp ?? 0) * 1000,
).toLocal().toString().substring(0, 16), //
style: const TextStyle(color: Colors.grey, fontSize: 12.0),
),
),
const SizedBox(height: 5.0),
//
Visibility(
visible: (chatList[index].conversation.unreadCount ?? 0) > 0,
child: FStyle.badge(chatList[index].conversation.unreadCount ?? 0),
),
],
),
Visibility(
visible: chatList[index].isCustomAdmin != '0' ||
chatList[index].conversation.conversationGroupList!.contains(ConversationType.noFriend.name),
child: const Icon(
Icons.arrow_forward_ios,
color: Colors.blueGrey,
size: 14.0,
),
),
],
),
),
onTap: () {
if (conversationTypeFromString(chatList[index].isCustomAdmin)) {
//
logger.e(chatList[index].isCustomAdmin);
} else if (chatList[index].conversation.conversationGroupList!.contains(ConversationType.noFriend.name)) {
//
logger.e(chatList[index].conversation.conversationGroupList);
} else {
// id查询会话详情
Get.toNamed('/chat', arguments: chatList[index].conversation);
}
},
onTapDown: (TapDownDetails details) {
posDX = details.globalPosition.dx;
posDY = details.globalPosition.dy;
},
onLongPress: () {
showContextMenu(context, chatList[index]);
},
),
);
},
);
})),
),
],
),
),
);
}
}

View File

@ -108,6 +108,7 @@ class _GoodsState extends State<Goods> {
Get.back(); Get.back();
} }
} }
// SKU // SKU
void locateSelectedSku() { void locateSelectedSku() {
if (shopObj != null && shopObj['skuList'] != null) { if (shopObj != null && shopObj['skuList'] != null) {
@ -145,20 +146,25 @@ void handleAttributeSelect(String attrName, String optionName) {
locateSelectedSku(); // SKU locateSelectedSku(); // SKU
}); });
} }
/// ///
createOrder(String goodsId) async { createOrder(String goodsId) async {
var params = { var params = {
"type": 1, // 1->2->;3-> "type": 1, // 1->2->;3->
"distribution": 1, // 1->2->;3->; "distribution": 1, // 1->2->;3->;
"skuItemBOList": [ "skuItemBOList": [
{"skuId": goodsId, "quantity": _quantity} {
"skuId": goodsId,
"quantity": _quantity,
"shareMemberId": Get.arguments['userID'] ?? '',
}
] ]
}; };
print('下单请求参数---->$params'); print('下单请求参数---->$params');
try { try {
final res = await Http.post(ShopApi.createGoodsOrder, data: params); final res = await Http.post(ShopApi.createGoodsOrder, data: params);
var resData = res['data']; var resData = res['data'];
print('1111111111111111111111111---->$res'); logger.w(res);
if (resData['id'].isNotEmpty) { if (resData['id'].isNotEmpty) {
return resData['id']; return resData['id'];
} else { } else {
@ -338,6 +344,7 @@ void handleAttributeSelect(String attrName, String optionName) {
}, },
); );
} }
// //
bool isAttributeSelected(String attrName, String optionName) { bool isAttributeSelected(String attrName, String optionName) {
return selectedAttributes[attrName] == optionName; return selectedAttributes[attrName] == optionName;
@ -545,7 +552,7 @@ void handleAttributeSelect(String attrName, String optionName) {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
image: DecorationImage( image: DecorationImage(
image: NetworkImage(selectedSku['pic'] != null ? selectedSku['pic'] : shopObj['pic']), image: NetworkImage(selectedSku['pic'] ?? shopObj['pic']),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
@ -687,7 +694,7 @@ void handleAttributeSelect(String attrName, String optionName) {
SizedBox(height: 12), SizedBox(height: 12),
], ],
); );
}).toList(), }),
], ],
), ),
), ),
@ -736,7 +743,8 @@ void handleAttributeSelect(String attrName, String optionName) {
color: Color(0xFFFFEBEB), color: Color(0xFFFFEBEB),
borderRadius: BorderRadius.circular(30.0), borderRadius: BorderRadius.circular(30.0),
), ),
child: shopObj['canOrder'] == true?Row( child: shopObj['canOrder'] == true
? Row(
children: [ children: [
Container( Container(
alignment: Alignment.center, alignment: Alignment.center,
@ -746,6 +754,7 @@ void handleAttributeSelect(String attrName, String optionName) {
onTap: () async { onTap: () async {
// orderId // orderId
String skuId = selectedSku != null ? selectedSku['id'] : shopObj['skuList'][0]['id']; String skuId = selectedSku != null ? selectedSku['id'] : shopObj['skuList'][0]['id'];
logger.e(skuId);
String orderId = await createOrder(skuId); String orderId = await createOrder(skuId);
if (orderId.isNotEmpty) { if (orderId.isNotEmpty) {
Get.toNamed('/order/detail', arguments: {'orderId': orderId}); Get.toNamed('/order/detail', arguments: {'orderId': orderId});
@ -760,7 +769,8 @@ void handleAttributeSelect(String attrName, String optionName) {
), ),
), ),
], ],
):null, )
: null,
), ),
], ],
), ),

View File

@ -10,6 +10,7 @@ import 'package:loopin/pages/groupChat/components/invite_action_sheet.dart';
import 'package:loopin/pages/groupChat/components/member_action_sheet.dart'; import 'package:loopin/pages/groupChat/components/member_action_sheet.dart';
import 'package:loopin/pages/groupChat/components/set_group_info.dart'; import 'package:loopin/pages/groupChat/components/set_group_info.dart';
import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart'; import 'package:loopin/pages/groupChat/controller/group_detail_controller.dart';
import 'package:loopin/pages/groupChat/reportGp.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
import 'package:loopin/utils/index.dart'; import 'package:loopin/utils/index.dart';
import 'package:loopin/utils/permissions.dart'; import 'package:loopin/utils/permissions.dart';
@ -500,13 +501,14 @@ class GroupdetailState extends State<Groupdetail> {
const Divider(height: 1), const Divider(height: 1),
// //
// ListTile( ListTile(
// title: const Text("举报"), title: const Text("举报"),
// trailing: const Icon(Icons.chevron_right), trailing: const Icon(Icons.chevron_right),
// onTap: () { onTap: () {
// // //
// }, Get.to(() => ReportGp(groupID: controller.info.value!.groupID));
// ), },
),
// 退 // 退
const SizedBox(height: 20), const SizedBox(height: 20),

View File

@ -0,0 +1,250 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:loopin/api/video_api.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/service/http.dart';
import 'package:loopin/utils/getCommonDictionary.dart';
import '../../behavior/custom_scroll_behavior.dart';
class ReportGp extends StatefulWidget {
final String groupID;
const ReportGp({super.key, required this.groupID});
@override
State<ReportGp> createState() => _ReportGpState();
}
class _ReportGpState extends State<ReportGp> with SingleTickerProviderStateMixin {
int? _selectedIndex;
late dynamic args;
final TextEditingController _reportController = TextEditingController();
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
List<dynamic> reasonTypeData = [];
@override
void initState() {
super.initState();
args = Get.arguments ?? {};
getReportReasons('ums_chat_report'); //
}
@override
void dispose() {
_reportController.dispose();
super.dispose();
}
//
Future<void> getReportReasons(String key) async {
try {
final data = await Commondictionary.getCommonDictionary(key);
setState(() {
reasonTypeData = data;
});
} catch (e) {
print('加载失败: $e');
}
}
//
Future<void> doReport(String dictValue, String reasonText) async {
try {
final res = await Http.post(VideoApi.reportVideoApi, data: {
'type': '1', // 1 2 3
'content': reasonText,
'aimId': widget.groupID,
'aimType': '2', // 1 2 3 4 5
'reasonType': dictValue
});
if (res['code'] == 200) {
//
MyToast().tip(
title: '投诉成功',
position: 'center',
type: 'success',
);
Get.back(result: {'returnTo': '/'});
} else {
MyToast().tip(
title: '投诉失败',
position: 'center',
type: 'error',
);
}
} catch (e) {
print('投诉失败: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.white,
foregroundColor: Colors.black,
elevation: 0,
title: const Text(
'举报',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'您的举报我们将尽快受理,核实后我们将第一时间告知受理结果,请尽量提交完整的举报描述',
style: TextStyle(fontSize: 13, color: Colors.grey, height: 1.4),
),
const SizedBox(height: 20),
//
reasonTypeData.isEmpty
? const Center(child: CircularProgressIndicator())
: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 2,
childAspectRatio: 4,
),
itemCount: reasonTypeData.length,
itemBuilder: (context, index) {
return _buildRadioItem(index);
},
),
const SizedBox(height: 24),
const Text(
'举报描述(选填)',
style: TextStyle(fontSize: 14, color: Colors.black54, fontWeight: FontWeight.w500),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(4),
),
child: TextField(
controller: _reportController,
maxLines: 5,
maxLength: 32,
cursorColor: Colors.black54,
style: const TextStyle(
color: Colors.black54,
fontSize: 14,
),
decoration: const InputDecoration(
contentPadding: EdgeInsets.all(12),
border: InputBorder.none,
hintText: '请输入内容',
hintStyle: TextStyle(color: Colors.grey, fontSize: 13),
),
),
),
Align(
alignment: Alignment.centerRight,
child: Text(
'${_reportController.text.length}/32',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
),
const SizedBox(height: 30),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _selectedIndex != null ? _submitReport : null,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
child: const Text('提交', style: TextStyle(fontSize: 15)),
),
),
],
),
),
),
);
}
Widget _buildRadioItem(int index) {
final item = reasonTypeData[index];
final isSelected = _selectedIndex == index;
return GestureDetector(
onTap: () {
setState(() {
_selectedIndex = index;
});
},
child: Container(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected ? Colors.green : Colors.grey,
width: 1.5,
),
),
child: isSelected
? Center(
child: Container(
width: 12,
height: 12,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.green,
),
),
)
: null,
),
const SizedBox(width: 8),
Expanded(
child: Text(
item['dictLabel'] ?? '未知原因',
style: TextStyle(
fontSize: 13,
color: isSelected ? Colors.green : Colors.black54,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
),
);
}
void _submitReport() {
if (_selectedIndex == null) {
MyToast().tip(
title: '请选择举报原因!',
position: 'center',
type: 'error',
);
return;
}
//
final selectedReason = reasonTypeData[_selectedIndex!];
final reasonText = _reportController.text;
doReport(selectedReason['dictValue'], reasonText);
}
}

View File

@ -1,20 +1,26 @@
/// ///
library; library;
import 'dart:ui';
import 'package:card_swiper/card_swiper.dart'; import 'package:card_swiper/card_swiper.dart';
import 'package:dynamic_tabbar/dynamic_tabbar.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/IM/im_friend_listeners.dart'; import 'package:loopin/IM/im_friend_listeners.dart';
import 'package:loopin/components/backtop.dart'; import 'package:loopin/api/shop_api.dart';
import 'package:loopin/components/custom_pageview_indicator.dart';
import 'package:loopin/components/custom_sticky_header.dart';
import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/loading.dart'; import 'package:loopin/components/loading.dart';
import 'package:loopin/components/network_or_asset_image.dart'; import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/controller/shop_index_controller.dart'; import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart'; import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart'; import 'package:loopin/utils/index.dart';
import '../../behavior/custom_scroll_behavior.dart';
import '../../components/backtop.dart';
class IndexPage extends StatefulWidget { class IndexPage extends StatefulWidget {
const IndexPage({super.key}); const IndexPage({super.key});
@ -22,30 +28,223 @@ class IndexPage extends StatefulWidget {
State<IndexPage> createState() => _IndexPageState(); State<IndexPage> createState() => _IndexPageState();
} }
class _IndexPageState extends State<IndexPage> with SingleTickerProviderStateMixin { class _IndexPageState extends State<IndexPage> with TickerProviderStateMixin {
///-----------
//
List waterfallData = [
{
'price': 199.00,
'title': '韩料界的萨莉亚!',
'shop': '萨莉亚专卖店',
'image': 'https://qcloud.dpfile.com/pc/1c3egbzM_ICz90dhi6MAiTsazjxWYQcHCd-sbpD1Wqtph2eIJA04NCRvoGqL4_opG45IiB1YIyNuDTtqzVRwesm_qA1Pf8rFcayTY-n-rG8.jpg',
'saleNum': '2.1万'
},
{
'price': 1499.90,
'title': '茅台MOUTAI飞天 53%vol 500ml 贵州茅台酒(带杯)',
'shop': '茅台京东自营旗舰店',
'image': 'https://img13.360buyimg.com/n1/jfs/t1/97097/12/15694/245806/5e7373e6Ec4d1b0ac/9d8c13728cc2544d.jpg',
'saleNum': '1254'
},
{
'price': 18.90,
'title': '上海街头苹果糖!一口一个不吱声',
'shop': '芝洛洛自营旗舰店',
'image': 'https://p0.meituan.net/coverpic/f0eefdfa02619fb09ca53eacd4d97231123115.jpg',
'saleNum': '1.2万'
},
{
'price': 59.00,
'title': '谁懂,就是这个菜,尝了第一口,立马决定加单了,真正的咸甜永动机啊🍬 去过云南的朋友都知道,当地的乳扇真的很好吃。',
'shop': '薄荷牛舌卷旗舰店',
'image': 'https://qcloud.dpfile.com/pc/UcW-v6AN1TxVTt9--5Kaw2-t4W55jUhEG_pM5S-w_AQ4IP3z9WxHzwJ9fOthIjEYY0q73sB2DyQcgmKUxZFQtw.jpg',
'saleNum': '1639'
},
{
'price': 2499.00,
'title': '小米 REDMI K80 国家补贴 第三代骁龙 8 6550mAh大电池 澎湃OS 玄夜黑 12GB+256GB 红米5G至尊手机',
'shop': '小米京东自营旗舰店',
'image': 'https://img10.360buyimg.com/n1/s450x450_jfs/t1/264409/38/13856/102861/678dcfdaFb723c58f/5b97cf154bbba96c.jpg',
'saleNum': '9726'
},
{
'price': 1.00,
'title': '圣菲尔伯爵法国红酒Saintfilcount干红葡萄酒珍藏13.5度单瓶送礼红酒 一元试饮',
'shop': '小森葡萄酒专营店',
'image': 'https://img10.360buyimg.com/n7/jfs/t1/226168/23/3411/118733/65537e5fF2db2d109/7d1d11a8013d6e8f.jpg',
'saleNum': '9.9万'
},
{
'price': 42.00,
'title': '美的MideaLED便携充电小台灯书桌学习阅读灯学生宿舍卧室床头灯学习台灯',
'shop': '美的Midea旗舰店',
'image': 'https://img14.360buyimg.com/mobilecms/s360x360_jfs/t1/226233/4/10194/156936/658e8f88Fcfc9cb40/cea4a48783f11a7a.jpg',
'saleNum': '5106'
},
{
'price': 22.90,
'title': '蒙都 羊杂500g 加热即食 京东超市肉干肉脯及礼包11.11真便宜',
'shop': '蒙都旗舰店',
'image': 'https://img10.360buyimg.com/n7/jfs/t1/155306/32/25324/231912/62d22fb8E4ffab855/c6001ee702fb240a.jpg',
'saleNum': '1.6万'
},
{
'price': 19.90,
'title': '『 江西炒米粉 』本次最佳😋香就一个字话。锅气的香🔥干辣椒的焦香🌶️油的润香🐷蔬菜混合的清香🥬',
'shop': '去月球野餐嗎',
'image': 'https://qcloud.dpfile.com/pc/pOAOL-DQRBWfkVZIWYVoy0mMQf6_UutNlOpEpGkT_nz3b1n7ZbpikPgtXMhMsjXNY0q73sB2DyQcgmKUxZFQtw.jpg',
'saleNum': '3.2万'
},
{
'price': 109.00,
'title': '附近新开业的,作为江西人当然要去试试。点了几个家常菜。',
'shop': '辣评新开江西菜',
'image': 'https://qcloud.dpfile.com/pc/HePD48CFNnS0kMZyf3Q391wxaW_zVgHimctthH__J6UI54HLPUkNt5e3qtP4Nl2G_aW_B6sGElzX-tSmYRvRnQxxxek7cKy7_R0W-KdxWUk.jpg',
'saleNum': '8764'
},
];
//
RxList dataList = [].obs;
//
RxBool isLoading = false.obs;
RxBool isInitLoading = true.obs;
RxBool hasMore = true.obs;
//
RxInt currentIndex = 0.obs;
TextEditingController textEditingController = TextEditingController();
FocusNode focusNode = FocusNode();
TabController? tabController;
// //
// List cateList = [ RxList<dynamic> tabList = <dynamic>[].obs;
// {
// 'id': 1, ///
// 'list': [ RxList<dynamic> swiperData = <dynamic>[].obs;
// { late ScrollController scrollController = ScrollController();
// 'icon': 'order.svg', final PageController pageController = PageController();
// 'label': '我的订单', //
// }, double scrollOffset = 0;
// { int page = 1;
// 'icon': 'chongzhi.svg',
// 'label': '充值中心', /// Tab
// }, Future<void> initTabs() async {
// {'icon': 'qianbao.svg', 'label': '余额'}, page = 1;
// {'icon': 'comment.svg', 'label': '评价中心'} currentIndex.value = 0;
// ] isLoading.value = false;
// } hasMore.value = true;
// ]; dataList.value = [];
final ScrollController pageScrollController = ScrollController(); isInitLoading.value = true;
late ShopIndexController controller;
// tab
final res = await Http.post(ShopApi.shopCategory, data: {
'level': 1,
});
final data = res['data'] as List<dynamic>;
tabList.value = data;
// controller
tabController?.dispose();
tabController = TabController(
initialIndex: 0,
length: tabList.length,
vsync: this,
);
if (tabList.isNotEmpty) {
loadSwiperData();
loadData(currentIndex.value);
}
}
/// swiper数据
Future<void> loadSwiperData() async {
final res = await Http.post(ShopApi.shopSwiperList, data: {
'type': 1,
});
final data = res['data'];
logger.w(res);
swiperData.assignAll(data);
}
///
Future<void> changeData(int index) async {
if (isLoading.value) return;
isLoading.value = true;
final res = await Http.post(ShopApi.shopList, data: {
'size': 10,
'current': page,
'categoryId': tabList[index]['id'],
});
final data = res['data']['records'];
final total = res['data']['total'];
logger.w(res);
dataList.value = data;
if (dataList.length >= total) {
hasMore.value = false;
}
// logger.w(res);
page += 1;
isLoading.value = false;
isInitLoading.value = false;
}
/// pageview数据
Future<void> loadData(int index) async {
if (isLoading.value) return;
isLoading.value = true;
final res = await Http.post(ShopApi.shopList, data: {
'size': 10,
'current': page,
'categoryId': tabList[index]['id'],
});
final data = res['data']['records'];
final total = res['data']['total'];
logger.w(res);
dataList.addAll(data);
if (dataList.length >= total) {
hasMore.value = false;
}
// logger.w(res);
page += 1;
isLoading.value = false;
isInitLoading.value = false;
}
@override
void initState() {
super.initState();
scrollController.addListener(() {
setState(() {
scrollOffset = scrollController.offset;
});
if (scrollController.position.pixels == scrollController.position.maxScrollExtent) {
debugPrint('[index]滚动到底部');
if (!isLoading.value) {
loadData(currentIndex.value);
}
}
});
//
initTabs();
}
@override
void dispose() {
scrollController.dispose();
pageController.dispose();
super.dispose();
}
// //
Widget cardList(item) { Widget cardList(item) {
if (item == null) {
return Loading(
title: '加载中',
);
}
return GestureDetector( return GestureDetector(
child: Container( child: Container(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
@ -59,11 +258,10 @@ class _IndexPageState extends State<IndexPage> with SingleTickerProviderStateMix
]), ]),
child: Column( child: Column(
children: [ children: [
// Image.network(),
NetworkOrAssetImage( NetworkOrAssetImage(
imageUrl: '${item['pic']}', imageUrl: '${item['pic']}',
width: double.infinity, width: double.infinity,
placeholderAsset: 'assets/images/bk.jpg', placeholderAsset: 'assets/images/wait_loading.png',
), ),
Container( Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
@ -113,218 +311,265 @@ class _IndexPageState extends State<IndexPage> with SingleTickerProviderStateMix
); );
} }
@override
void initState() {
super.initState();
controller = Get.find<ShopIndexController>();
// controller.initTabs(vsync: this);
controller.initTabs();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return GestureDetector(
backgroundColor: Colors.grey[50], onTap: () {
body: Column( focusNode.unfocus();
},
child: Scaffold(
body: ScrollConfiguration(
behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: RefreshIndicator(
color: FStyle.primaryColor,
onRefresh: () async {
await initTabs();
},
child: CustomScrollView(
scrollBehavior: CustomScrollBehavior().copyWith(scrollbars: false),
controller: scrollController,
slivers: [
SliverAppBar(
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
pinned: true,
expandedHeight: 200.0,
titleSpacing: 10.0,
// ()
title: ClipRRect(
borderRadius: BorderRadius.circular(30.0),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
height: 45.0,
decoration: BoxDecoration(
color: Colors.white.withAlpha(150),
),
child: TextField(
focusNode: focusNode,
controller: textEditingController,
decoration: InputDecoration(
isDense: true,
hintText: "热销商品",
hintStyle: TextStyle(fontSize: 15.0),
prefixIcon: Icon(
Icons.search,
color: Colors.black38,
size: 21.0,
),
suffixIcon: Container(
padding: EdgeInsets.only(right: 15.0),
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 10.0,
children: [ children: [
_buildTopSection(), TextButton(
// onPressed: () {
Expanded( focusNode.unfocus();
child: controller.tabList.isEmpty if (textEditingController.text.isNotEmpty) {
? Center(child: CircularProgressIndicator()) // tab索引
: Obx( Get.toNamed(
() { '/search-result',
final tabs = controller.tabList.asMap().entries.map((entry) { arguments: {'searchWords': textEditingController.text, 'tab': 1},
final idx = entry.key;
final item = entry.value;
return TabData(
index: idx,
title: Tab(
child: Center(
child: Text(
item['name'] ?? '',
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
softWrap: false,
),
),
),
content: _buildTabContent(idx),
); );
}).toList();
return DynamicTabBarWidget(
onTabControllerUpdated: (tabController) {
// controller.tabController = tabController;
// controller.initTabs(changeController: tabController, vsync: this);
controller.addTabListener(tabController);
//
if (tabController.index != 0) {
tabController.animateTo(0);
} }
}, },
onTabChanged: (index) { child: Text('搜索'),
logger.w("当前选中ssssstab: $index");
},
dynamicTabs: tabs,
tabAlignment: TabAlignment.start,
isScrollable: true,
showNextIcon: false, //
showBackIcon: false, // 退
labelColor: FStyle.primaryColor,
indicatorColor: FStyle.primaryColor,
overlayColor: WidgetStateProperty.all(Colors.transparent),
unselectedLabelColor: Colors.black87,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(color: Color.fromARGB(255, 236, 108, 49), width: 2.0),
),
unselectedLabelStyle: const TextStyle(
fontSize: 14.0,
fontFamily: 'Microsoft YaHei',
),
labelStyle: const TextStyle(
fontSize: 14.0,
fontFamily: 'Microsoft YaHei',
fontWeight: FontWeight.bold,
),
dividerHeight: 0,
);
},
),
), ),
], ],
), ),
floatingActionButton: Obx(() { ),
final tabIndex = controller.currentTabIndex.value; contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10.0),
final currentTab = controller.tabs[tabIndex]; border: OutlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(30.0))),
if (currentTab == null) return const SizedBox.shrink(); cursorColor: Colors.black,
onSubmitted: (value) {
return Backtop( focusNode.unfocus();
controller: currentTab.scrollController, if (value.isNotEmpty) {
offset: currentTab.scrollOffset.value, // tab索引
); Get.toNamed(
}), '/search-result',
arguments: {'searchWords': value, 'tab': 1},
); );
} }
},
),
),
),
),
// ()
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFFFF5000), Color(0xFFfcaec4)],
),
),
child: FlexibleSpaceBar(
background: Obx(() {
//
if (swiperData.isEmpty) return SizedBox.shrink();
//
Widget _buildTopSection() {
if (controller.swiperData.isEmpty) {
return SizedBox();
}
return Column(
children: [
//
Obx(() {
if (controller.swiperData.isEmpty) return const SizedBox.shrink();
if (controller.swiperData.length == 1) {
final imageUrl = controller.swiperData.first['images'] ?? '';
return Image.network(imageUrl, fit: BoxFit.fill, width: double.infinity, height: 240);
}
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
height: 240, child: Swiper.children(
child: Swiper( pagination: SwiperPagination(
itemCount: controller.swiperData.length,
autoplay: true,
loop: true,
pagination: const SwiperPagination(
builder: DotSwiperPaginationBuilder( builder: DotSwiperPaginationBuilder(
color: Colors.white70, color: Colors.white70,
activeColor: Colors.white, activeColor: Colors.white,
size: 6.0,
activeSize: 8.0,
space: 4.0,
), ),
), ),
itemBuilder: (context, index) { indicatorLayout: PageIndicatorLayout.SCALE,
final imageUrl = controller.swiperData[index]['images'] ?? ''; children: swiperData.map<Widget>((itm) {
return imageUrl.isNotEmpty ? Image.network(imageUrl, fit: BoxFit.fill) : const SizedBox.shrink(); return NetworkOrAssetImage(
}, imageUrl: itm['images'],
placeholderAsset: 'assets/images/bk.jpg',
);
}).toList(),
), ),
); );
}), }),
], ),
); ),
),
//
SliverPersistentHeader(
pinned: false,
delegate: CustomStickyHeader(
child: PreferredSize(
preferredSize: Size.fromHeight(110.0),
child: Obx(
() {
return Container(
margin: EdgeInsets.all(10.0),
padding: EdgeInsets.symmetric(vertical: 10.0),
height: 110.0,
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: [
Expanded(
child: PageView.builder(
controller: pageController,
itemCount: (tabList.length / 4).ceil(),
itemBuilder: (context, pageIndex) {
final start = pageIndex * 4;
final end = (start + 4) > tabList.length ? tabList.length : (start + 4);
final pageItems = tabList.sublist(start, end);
return GridView.builder(
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4, //
mainAxisSpacing: 0, //
),
itemCount: pageItems.length,
itemBuilder: (BuildContext context, int index) {
final citem = pageItems[index];
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
//index
final globalIndex = start + index;
logger.e(globalIndex);
if (globalIndex != currentIndex.value) {
currentIndex.value = globalIndex;
page = 1;
isLoading.value = false;
changeData(globalIndex);
} }
},
child: Column(
spacing: 3.0,
children: [
ClipOval(
child: NetworkOrAssetImage(
imageUrl: citem['icon'],
width: 30.0,
height: 30.0,
placeholderAsset: 'assets/images/wait_loading.png',
),
),
Text(citem['name']),
],
),
);
},
);
},
),
),
//
CustomPageViewIndicator(
controller: pageController,
count: (tabList.length / 4).ceil(),
color: Color(0xFFCECECE),
activeColor: Color(0xFFFF5000),
),
],
),
);
},
),
),
),
),
// //
Widget _buildTabContent(int index) { SliverToBoxAdapter(
final tabState = controller.tabs[index]!; child: Obx(
() {
return Obx(() { if (isInitLoading.value) {
if (tabState.dataList.isEmpty && tabState.isLoading.value) { return Column(
return Center( children: [
child: RefreshProgressIndicator( RefreshProgressIndicator(
backgroundColor: Colors.white, backgroundColor: Colors.white,
color: Color(0xFFFF5000), color: Color(0xFFFF5000),
), ),
],
); );
} }
if (dataList.isEmpty) {
// return EmptyTip();
return EasyRefresh( }
onRefresh: () async { return Container(
await controller.refreshData(index); padding: EdgeInsets.all(10.0),
}, child: Column(
header: ClassicHeader( children: [
dragText: '下拉刷新', MasonryGridView.count(
armedText: '释放刷新', shrinkWrap: true,
readyText: '加载中...', padding: EdgeInsets.zero,
processingText: '加载中...', physics: NeverScrollableScrollPhysics(),
processedText: '加载完成',
messageText: '最后更新于 %T',
),
child: CustomScrollView(
controller: tabState.scrollController,
key: PageStorageKey('tab_$index'),
physics: const AlwaysScrollableScrollPhysics(), //
slivers: [
SliverPadding(
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
sliver: tabState.dataList.isEmpty
? SliverToBoxAdapter(
child: SizedBox(
height: MediaQuery.of(context).size.height - 500, //
child: Center(child: _emptyTip('暂无数据')),
),
)
: SliverMasonryGrid.count(
crossAxisCount: 2, crossAxisCount: 2,
mainAxisSpacing: 10.0, mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0, crossAxisSpacing: 10.0,
childCount: tabState.dataList.length, itemCount: dataList.length,
itemBuilder: (context, idx) => cardList(tabState.dataList[idx]), itemBuilder: (BuildContext context, int index) {
return cardList(dataList[index]);
},
), ),
Opacity(opacity: dataList.isNotEmpty && isLoading.value ? 1 : 0, child: Loading(title: 'loading...')),
],
), ),
SliverToBoxAdapter( );
child: Padding( },
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Center(
child: tabState.isLoading.value
? const Loading(title: 'loading...')
: (tabState.dataList.isNotEmpty ? const Text('没有更多数据了') : const SizedBox.shrink()),
),
), ),
), ),
], ],
), ),
);
});
}
//
Widget _emptyTip(String text) {
return Center(
child: Padding(
padding: const EdgeInsets.only(top: 50),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset('assets/images/empty.png', width: 50, height: 50),
const SizedBox(height: 8),
Text(
text,
style: const TextStyle(color: Colors.grey, fontSize: 13),
), ),
],
), ),
//
floatingActionButton: Backtop(controller: scrollController, offset: scrollOffset),
), ),
); );
} }

331
lib/pages/index/index2.dart Normal file
View File

@ -0,0 +1,331 @@
///
library;
import 'package:card_swiper/card_swiper.dart';
import 'package:dynamic_tabbar/dynamic_tabbar.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:get/get.dart';
import 'package:loopin/IM/im_friend_listeners.dart';
import 'package:loopin/components/backtop.dart';
import 'package:loopin/components/loading.dart';
import 'package:loopin/components/network_or_asset_image.dart';
import 'package:loopin/controller/shop_index_controller.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/index.dart';
class IndexPage extends StatefulWidget {
const IndexPage({super.key});
@override
State<IndexPage> createState() => _IndexPageState();
}
class _IndexPageState extends State<IndexPage> with SingleTickerProviderStateMixin {
//
// List cateList = [
// {
// 'id': 1,
// 'list': [
// {
// 'icon': 'order.svg',
// 'label': '我的订单',
// },
// {
// 'icon': 'chongzhi.svg',
// 'label': '充值中心',
// },
// {'icon': 'qianbao.svg', 'label': '余额'},
// {'icon': 'comment.svg', 'label': '评价中心'}
// ]
// }
// ];
final ScrollController pageScrollController = ScrollController();
late ShopIndexController controller;
//
Widget cardList(item) {
return GestureDetector(
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.0), boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(5),
offset: Offset(0.0, 1.0),
blurRadius: 1.0,
spreadRadius: 0.0,
),
]),
child: Column(
children: [
// Image.network(),
NetworkOrAssetImage(
imageUrl: '${item['pic']}',
width: double.infinity,
placeholderAsset: 'assets/images/bk.jpg',
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 5.0,
children: [
Text(
'${item['name']}',
style: TextStyle(fontSize: 14.0, height: 1.2),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
Row(
spacing: 5.0,
children: [
Text.rich(
TextSpan(style: TextStyle(color: Colors.red, fontSize: 12.0, fontWeight: FontWeight.w700, fontFamily: 'Arial'), children: [
TextSpan(text: '¥'),
TextSpan(
text: '${item['price']}',
style: TextStyle(
fontSize: 16.0,
)),
]),
),
Text(
'已售${Utils.graceNumber(int.parse(item['sales'] ?? '0'))}',
style: TextStyle(color: Colors.grey, fontSize: 10.0),
),
],
),
Text(
'${item['storeName']}',
style: TextStyle(color: Colors.grey, fontSize: 12.0),
),
],
),
)
],
),
),
onTap: () {
// Get.toNamed('/goods', arguments: item['id']);
Get.toNamed('/goods', arguments: {'goodsId': item['id']});
},
);
}
@override
void initState() {
super.initState();
controller = Get.find<ShopIndexController>();
// controller.initTabs(vsync: this);
controller.initTabs();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
body: Column(
children: [
_buildTopSection(),
//
Expanded(
child: controller.tabList.isEmpty
? Center(child: CircularProgressIndicator())
: Obx(
() {
final tabs = controller.tabList.asMap().entries.map((entry) {
final idx = entry.key;
final item = entry.value;
return TabData(
index: idx,
title: Tab(
child: Center(
child: Text(
item['name'] ?? '',
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
softWrap: false,
),
),
),
content: _buildTabContent(idx),
);
}).toList();
return DynamicTabBarWidget(
onTabControllerUpdated: (tabController) {
// controller.tabController = tabController;
// controller.initTabs(changeController: tabController, vsync: this);
controller.addTabListener(tabController);
//
if (tabController.index != 0) {
tabController.animateTo(0);
}
},
onTabChanged: (index) {
logger.w("当前选中ssssstab: $index");
},
dynamicTabs: tabs,
tabAlignment: TabAlignment.start,
isScrollable: true,
showNextIcon: false, //
showBackIcon: false, // 退
labelColor: FStyle.primaryColor,
indicatorColor: FStyle.primaryColor,
overlayColor: WidgetStateProperty.all(Colors.transparent),
unselectedLabelColor: Colors.black87,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(color: Color.fromARGB(255, 236, 108, 49), width: 2.0),
),
unselectedLabelStyle: const TextStyle(
fontSize: 14.0,
fontFamily: 'Microsoft YaHei',
),
labelStyle: const TextStyle(
fontSize: 14.0,
fontFamily: 'Microsoft YaHei',
fontWeight: FontWeight.bold,
),
dividerHeight: 0,
);
},
),
),
],
),
floatingActionButton: Obx(() {
final tabIndex = controller.currentTabIndex.value;
final currentTab = controller.tabs[tabIndex];
if (currentTab == null) return const SizedBox.shrink();
return Backtop(
controller: currentTab.scrollController,
offset: currentTab.scrollOffset.value,
);
}),
);
}
//
Widget _buildTopSection() {
if (controller.swiperData.isEmpty) {
return SizedBox();
}
return Column(
children: [
//
Obx(() {
if (controller.swiperData.isEmpty) return const SizedBox.shrink();
if (controller.swiperData.length == 1) {
final imageUrl = controller.swiperData.first['images'] ?? '';
return Image.network(imageUrl, fit: BoxFit.fill, width: double.infinity, height: 240);
}
return SizedBox(
width: double.infinity,
height: 240,
child: Swiper(
itemCount: controller.swiperData.length,
autoplay: true,
loop: true,
pagination: const SwiperPagination(
builder: DotSwiperPaginationBuilder(
color: Colors.white70,
activeColor: Colors.white,
),
),
itemBuilder: (context, index) {
final imageUrl = controller.swiperData[index]['images'] ?? '';
return imageUrl.isNotEmpty ? Image.network(imageUrl, fit: BoxFit.fill) : const SizedBox.shrink();
},
),
);
}),
],
);
}
//
Widget _buildTabContent(int index) {
final tabState = controller.tabs[index]!;
return Obx(() {
if (tabState.dataList.isEmpty && tabState.isLoading.value) {
return Center(
child: RefreshProgressIndicator(
backgroundColor: Colors.white,
color: Color(0xFFFF5000),
),
);
}
//
return EasyRefresh(
onRefresh: () async {
await controller.refreshData(index);
},
header: ClassicHeader(
dragText: '下拉刷新',
armedText: '释放刷新',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
messageText: '最后更新于 %T',
),
child: CustomScrollView(
controller: tabState.scrollController,
key: PageStorageKey('tab_$index'),
physics: const AlwaysScrollableScrollPhysics(), //
slivers: [
SliverPadding(
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
sliver: tabState.dataList.isEmpty
? SliverToBoxAdapter(
child: SizedBox(
height: MediaQuery.of(context).size.height - 500, //
child: Center(child: _emptyTip('暂无数据')),
),
)
: SliverMasonryGrid.count(
crossAxisCount: 2,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childCount: tabState.dataList.length,
itemBuilder: (context, idx) => cardList(tabState.dataList[idx]),
),
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Center(
child: tabState.isLoading.value
? const Loading(title: 'loading...')
: (tabState.dataList.isNotEmpty ? const Text('没有更多数据了') : const SizedBox.shrink()),
),
),
),
],
),
);
});
}
//
Widget _emptyTip(String text) {
return Center(
child: Padding(
padding: const EdgeInsets.only(top: 50),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset('assets/images/empty.png', width: 50, height: 50),
const SizedBox(height: 8),
Text(
text,
style: const TextStyle(color: Colors.grey, fontSize: 13),
),
],
),
),
);
}
}

View File

@ -240,8 +240,8 @@ class _AllFunctionsPageState extends State<AllFunctionsPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
MyQrcode( MyQrcode(
prefix: QrTypeCode.tgm, prefix: isLeader ? QrTypeCode.tgm : QrTypeCode.hym,
text: isLeader ? '推广' : '', text: isLeader ? '团长' : '',
) )
], ],
), ),

View File

@ -64,7 +64,10 @@ class _DeleteState extends State<Delete> {
MyDialog.toast('验证码不能为空', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200))); MyDialog.toast('验证码不能为空', icon: Icon(Icons.warning), style: ToastStyle(backgroundColor: Colors.red.withAlpha(200)));
} else { } else {
final dialogController = MyDialog.loading('注销中...'); final dialogController = MyDialog.loading('注销中...');
// 退 //
final del = await Http.post('${CommonApi.revoked}?smsCode=${authObj['smsCode']}');
logger.w(del);
// 退
final loginRes = await ImService.instance.logout(); final loginRes = await ImService.instance.logout();
if (loginRes.success) { if (loginRes.success) {
// //
@ -72,11 +75,12 @@ class _DeleteState extends State<Delete> {
// //
final videoController = Get.find<VideoModuleController>(); final videoController = Get.find<VideoModuleController>();
videoController.init(); videoController.init();
// Get.offAllNamed(
final del = await Http.post('${CommonApi.revoked}?smsCode=${authObj['smsCode']}'); '/login',
logger.w(del); predicate: (route) {
// return route.settings.name == '/';
Get.offAllNamed('/'); },
);
} }
} }
} }

View File

@ -66,7 +66,8 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
// //
// late Rx<V2TimUserFullInfo?> userInfo = Rx<V2TimUserFullInfo?>(null); // late Rx<V2TimUserFullInfo?> userInfo = Rx<V2TimUserFullInfo?>(null);
ImUserInfoController? imUserInfoController; // ImUserInfoController? imUserInfoController;
late ImUserInfoController imUserInfoController;
// //
late Rx<V2TimFollowInfo?> followInfo = Rx<V2TimFollowInfo?>(null); late Rx<V2TimFollowInfo?> followInfo = Rx<V2TimFollowInfo?>(null);
@ -87,13 +88,14 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
late Callback tabListener; late Callback tabListener;
late Callback scrollListener; late Callback scrollListener;
late int vlogLikeCount = 0; // late RxInt vlogLikeCount = 0.obs; //
RxBool isPinned = false.obs; // RxBool isPinned = false.obs; //
@override @override
void initState() { void initState() {
super.initState(); super.initState();
imUserInfoController = Get.find<ImUserInfoController>();
initControllers(); initControllers();
scrollListener = () { scrollListener = () {
@ -140,7 +142,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
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.value = resData['data']['vlogLikeCount'] ?? 0;
} }
} catch (e) {} } catch (e) {}
} }
@ -168,7 +170,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
// itemsParams.isInitLoading = true; // itemsParams.isInitLoading = true;
final res = await Http.post(VideoApi.myPublicList, data: { final res = await Http.post(VideoApi.myPublicList, data: {
"userId": imUserInfoController?.userID.value, "userId": imUserInfoController.userID.value,
"yesOrNo": 0, "yesOrNo": 0,
"current": itemsParams.page, "current": itemsParams.page,
"size": itemsParams.pageSize, "size": itemsParams.pageSize,
@ -197,7 +199,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
// favoriteParams.isInitLoading = true; // favoriteParams.isInitLoading = true;
final res = await Http.post(VideoApi.myLikedList, data: { final res = await Http.post(VideoApi.myLikedList, data: {
"userId": imUserInfoController?.userID.value, "userId": imUserInfoController.userID.value,
"yesOrNo": 0, "yesOrNo": 0,
"current": favoriteParams.page, "current": favoriteParams.page,
"size": favoriteParams.pageSize, "size": favoriteParams.pageSize,
@ -255,7 +257,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
logger.e('用户信息controller未注册'); logger.e('用户信息controller未注册');
return; return;
} }
final res = await ImService.instance.getUserFollowInfo(userIDList: [imUserInfoController?.userID.value ?? '']); final res = await ImService.instance.getUserFollowInfo(userIDList: [imUserInfoController.userID.value ?? '']);
if (res.success) { if (res.success) {
// //
// followersCount粉丝,mutualFollowersCount互关,followingCount我关注了多少人 // followersCount粉丝,mutualFollowersCount互关,followingCount我关注了多少人
@ -269,18 +271,18 @@ 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.get('${VideoApi.deleteVideo}?id=$videoId');
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); refreshData();
} }
} catch (e) {} } catch (e) {}
} }
// //
void qrcodeAlertDialog(BuildContext context) { void qrcodeAlertDialog(BuildContext context) {
final role = imUserInfoController?.role.value ?? 0; final role = imUserInfoController.role.value ?? 0;
final isLeader = Utils.hasRole(role, 5); final isLeader = Utils.hasRole(role, 5);
showDialog( showDialog(
context: context, context: context,
@ -402,9 +404,9 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
child: Column( child: Column(
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
Obx(() => _buildStatsCard()), _buildStatsCard(),
const SizedBox(height: 10), const SizedBox(height: 10),
Obx(() => _buildInfoDesc(context)), _buildInfoDesc(context),
const SizedBox(height: 10.0), const SizedBox(height: 10.0),
_buildOrderCard(context), _buildOrderCard(context),
const SizedBox(height: 10.0), const SizedBox(height: 10.0),
@ -499,8 +501,8 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
} }
Widget _buildInfoDesc(BuildContext context) { Widget _buildInfoDesc(BuildContext context) {
final tx = imUserInfoController?.signature; final tx = imUserInfoController.signature;
if (tx == null || tx.isEmpty) { if (tx.isEmpty) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return Container( return Container(
@ -520,11 +522,13 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Text( child: Obx(
'${imUserInfoController!.signature}', () => Text(
'${imUserInfoController.signature}',
style: const TextStyle(fontSize: 16), style: const TextStyle(fontSize: 16),
), ),
), ),
),
], ],
)); ));
} }
@ -538,8 +542,6 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
if (listToShow.isEmpty) { if (listToShow.isEmpty) {
return emptyTip('暂无相关数据'); return emptyTip('暂无相关数据');
} }
return Obx(() {
return CustomScrollView( return CustomScrollView(
// physics: !isPinned.value ? NeverScrollableScrollPhysics() : AlwaysScrollableScrollPhysics(), // physics: !isPinned.value ? NeverScrollableScrollPhysics() : AlwaysScrollableScrollPhysics(),
// physics: AlwaysScrollableScrollPhysics(), // physics: AlwaysScrollableScrollPhysics(),
@ -573,13 +575,14 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0), padding: const EdgeInsets.symmetric(vertical: 20.0),
child: Center( child: Center(
child: params.hasMore.value ? CircularProgressIndicator() : Text('没有更多数据了'), child: Obx(
() => params.hasMore.value ? CircularProgressIndicator() : Text('没有更多数据了'),
),
), ),
), ),
), ),
], ],
); );
});
} }
Widget _buildVdCard(item, tabIndex) { Widget _buildVdCard(item, tabIndex) {
@ -688,6 +691,8 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
} }
Widget _buildFlexibleSpace() { Widget _buildFlexibleSpace() {
logger.e('定位');
logger.w(imUserInfoController);
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
final double maxHeight = 180; final double maxHeight = 180;
@ -699,14 +704,17 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
// Obx // Obx
Obx(() { Obx(
final bgUrl = imUserInfoController?.customInfo['coverBg'] ?? ''; () {
final map = imUserInfoController.customInfo ?? {};
final bgUrl = map['coverBg'] ?? '';
return NetworkOrAssetImage( return NetworkOrAssetImage(
imageUrl: bgUrl, imageUrl: bgUrl,
placeholderAsset: 'assets/images/bk.jpg', placeholderAsset: 'assets/images/bk.jpg',
fit: BoxFit.cover, fit: BoxFit.cover,
); );
}), },
),
Positioned( Positioned(
left: 15, left: 15,
@ -719,10 +727,10 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
children: [ children: [
// Obx // Obx
Obx(() { Obx(() {
final faceUrl = imUserInfoController?.faceUrl.value ?? ''; final faceUrl = imUserInfoController.faceUrl.value;
return ClipOval( return ClipOval(
child: NetworkOrAssetImage( child: NetworkOrAssetImage(
imageUrl: faceUrl, imageUrl: faceUrl ?? '',
width: 80, width: 80,
height: 80, height: 80,
), ),
@ -735,27 +743,24 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
children: [ children: [
Row( Row(
children: [ children: [
// Obx //
Obx( Container(
() {
final nickname = imUserInfoController?.nickname.value ?? '';
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withAlpha(76), color: Colors.black.withAlpha(76),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: Text( child: Obx(() {
final nickname = imUserInfoController.nickname.value ?? '';
return Text(
nickname.isNotEmpty ? nickname : '昵称', nickname.isNotEmpty ? nickname : '昵称',
// '啊啊啊啊啊啊啊啊',
style: const TextStyle( style: const TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: Colors.white,
), ),
),
); );
}, }),
), ),
// //
@ -809,15 +814,15 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
// ID Obx // ID Obx
Obx(() { Container(
final userId = imUserInfoController?.userID.value ?? '';
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withAlpha(76), color: Colors.black.withAlpha(76),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
), ),
child: InkWell( child: Obx(() {
final userId = imUserInfoController.userID.value ?? '';
return InkWell(
onTap: () { onTap: () {
Clipboard.setData(ClipboardData(text: userId)); Clipboard.setData(ClipboardData(text: userId));
MyDialog.toast( MyDialog.toast(
@ -827,9 +832,9 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
); );
}, },
child: Text('ID:$userId', style: const TextStyle(fontSize: 12, color: Colors.white)), child: Text('ID:$userId', style: const TextStyle(fontSize: 12, color: Colors.white)),
),
); );
}), }),
),
], ],
), ),
), ),
@ -856,9 +861,10 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
// '已售${Utils.graceNumber(int.tryParse(vlogLikeCount?.toString() ?? '0') ?? 0)}',
Column(children: [ Column(children: [
Text(Utils.graceNumber(vlogLikeCount), style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), Obx(() {
return Text(Utils.graceNumber(vlogLikeCount.value), style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold));
}),
SizedBox(height: 3.0), SizedBox(height: 3.0),
Text('获赞') Text('获赞')
]), ]),
@ -869,7 +875,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
refreshData(); refreshData();
}, },
child: Column(children: [ child: Column(children: [
Text('${followInfo.value?.mutualFollowersCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), Obx(() => Text('${followInfo.value?.mutualFollowersCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold))),
SizedBox(height: 3.0), SizedBox(height: 3.0),
Text('互关') Text('互关')
]), ]),
@ -881,7 +887,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
refreshData(); refreshData();
}, },
child: Column(children: [ child: Column(children: [
Text('${followInfo.value?.followingCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold)), Obx(() => Text('${followInfo.value?.followingCount ?? 0}', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold))),
SizedBox(height: 3.0), SizedBox(height: 3.0),
Text('关注') Text('关注')
]), ]),
@ -893,10 +899,12 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
}, },
child: Column( child: Column(
children: [ children: [
Text( Obx(
() => Text(
'${followInfo.value?.followersCount ?? 0}', '${followInfo.value?.followersCount ?? 0}',
style: const TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 16.0, fontWeight: FontWeight.bold),
), ),
),
const SizedBox(height: 3.0), const SizedBox(height: 3.0),
const Text('粉丝'), const Text('粉丝'),
], ],
@ -908,7 +916,7 @@ class MyPageState extends State<MyPage> with SingleTickerProviderStateMixin {
} }
Widget _buildOrderCard(BuildContext context) { Widget _buildOrderCard(BuildContext context) {
final role = imUserInfoController?.role.value ?? 0; final role = imUserInfoController.role.value ?? 0;
final isLeader = Utils.hasRole(role, 5); final isLeader = Utils.hasRole(role, 5);
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -5,6 +5,7 @@ import 'package:get/get.dart';
import 'package:loopin/IM/controller/im_user_info_controller.dart'; import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/behavior/custom_scroll_behavior.dart'; import 'package:loopin/behavior/custom_scroll_behavior.dart';
import 'package:loopin/components/empty_tip.dart'; import 'package:loopin/components/empty_tip.dart';
import 'package:loopin/components/my_toast.dart';
import 'package:loopin/pages/my/merchant/balance/controller.dart'; import 'package:loopin/pages/my/merchant/balance/controller.dart';
import 'package:loopin/utils/index.dart'; import 'package:loopin/utils/index.dart';
@ -61,10 +62,52 @@ class _BalanceState extends State<Balance> {
Row( Row(
children: [ children: [
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () async {
// //
controller.recharge(money: '0.1'); // controller.recharge(money: '0.1');
// http final money = await showDialog<String>(
context: context,
builder: (context) {
String input = "";
return AlertDialog(
title: Text("请输入充值金额"),
content: TextField(
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
hintText: "请输入50~200之间的金额",
),
onChanged: (value) => input = value,
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(), //
child: Text("取消"),
),
TextButton(
onPressed: () {
final num? value = num.tryParse(input);
if (value == null) {
Navigator.of(context).pop();
MyToast().tip(title: '请输入正确的金额');
return;
}
if (value < 0 || value > 200) {
Navigator.of(context).pop();
MyToast().tip(title: '金额必须在 50 ~ 200 之间');
return;
}
Navigator.of(context).pop(input); //
},
child: Text("确定"),
),
],
);
},
);
if (money != null && money.isNotEmpty) {
controller.recharge(money: money);
}
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange, backgroundColor: Colors.orange,
@ -74,11 +117,63 @@ class _BalanceState extends State<Balance> {
SizedBox(width: 20), SizedBox(width: 20),
// //
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () async {
// onWithdrawPressed();
// //
// controller.recharge(money: '0.1'); if (controller.balance.value < 10) {
controller.withDraw(money: '1000'); MyToast().tip(title: '钱包余额不足');
// http return;
}
final money = await showDialog<String>(
context: context,
builder: (context) {
String input = "";
return AlertDialog(
title: Text("请输入提现金额"),
content: TextField(
maxLength: 5,
maxLines: 1,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
hintText: "当前可提现金额为:${controller.balance.value}",
),
onChanged: (value) => input = value,
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(), //
child: Text("取消"),
),
TextButton(
onPressed: () {
final num? value = num.tryParse(input);
if (value == null || value < 0.1) {
Navigator.of(context).pop();
MyToast().tip(title: '请输入正确的金额');
return;
}
if (value > controller.balance.value) {
Navigator.of(context).pop();
MyToast().tip(title: '您当前可提现余额为:${controller.balance.value}');
return;
}
if (value > 200) {
Navigator.of(context).pop();
MyToast().tip(title: '提现金额上限为200');
return;
}
Navigator.of(context).pop(input); //
},
child: Text("确定"),
),
],
);
},
);
if (money != null && money.isNotEmpty) {
controller.withDraw(money: money);
}
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange, backgroundColor: Colors.orange,
@ -92,6 +187,25 @@ class _BalanceState extends State<Balance> {
}), }),
), ),
//
Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: double.infinity, //
child: Text(
'提示:\n'
'1. 余额不可用于购买商品\n'
'2. 余额只支持提现到授权的微信账户内\n'
'3. 提现申请通过后将于一个工作日内到账\n',
style: TextStyle(
fontSize: 14,
color: Colors.red[700],
),
textAlign: TextAlign.left,
),
),
),
// //
Expanded( Expanded(
child: EasyRefresh.builder( child: EasyRefresh.builder(
@ -146,10 +260,10 @@ class _BalanceState extends State<Balance> {
final tx = controller.data[index]; final tx = controller.data[index];
return ListTile( return ListTile(
title: Text(tx.source), title: Text(tx.sourceName), //
subtitle: Text(tx.createTime), subtitle: Text(tx.createTime), //
trailing: Text( trailing: Text(
"变动金额:${tx.changeType == 1 ? '+' : '-'}${tx.changeAmount}${tx.id}", // "变动金额:${tx.changeType == 1 ? '+' : '-'}${tx.changeAmount}", //
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: tx.changeType == 1 ? Colors.green : Colors.red, color: tx.changeType == 1 ? Colors.green : Colors.red,
@ -169,3 +283,21 @@ class _BalanceState extends State<Balance> {
); );
} }
} }
String _handleSource(String source) {
String res;
if (source == '3') {
res = '充值';
} else if (source == '2') {
res = '待确认';
} else if (source == '1') {
res = '提现';
} else if (source == '5') {
res = '提现退款';
} else if (source == '4') {
res = '充值退款';
} else {
res = '未知';
}
return res;
}

View File

@ -5,6 +5,8 @@ import 'package:loopin/IM/im_friend_listeners.dart';
import 'package:loopin/api/common_api.dart'; import 'package:loopin/api/common_api.dart';
import 'package:loopin/pages/my/merchant/balance/model.dart'; import 'package:loopin/pages/my/merchant/balance/model.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
import 'package:loopin/styles/index.dart';
import 'package:loopin/utils/wechat_business_view.dart';
import 'package:loopin/utils/wxsdk.dart'; import 'package:loopin/utils/wxsdk.dart';
class BalanceController extends GetxController { class BalanceController extends GetxController {
@ -20,17 +22,39 @@ class BalanceController extends GetxController {
/// ///
var hasMore = true.obs; var hasMore = true.obs;
//
final RxBool buttonLoading = false.obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
getAccount();
getData(reset: true); getData(reset: true);
} }
///
Future<void> getAccount() async {
final res = await Http.get(CommonApi.userAccount);
logger.w(res);
final resData = res['data']['wallet'];
if (resData != null) {
balance.value = double.parse(resData);
} else {
balance.value = 0.0;
}
}
/// ///
Future<void> recharge({required String money}) async { Future<void> recharge({required String money}) async {
// //
final data = {"orderType": "RECHARGE", "clientType": "APP", "paymentMethod": "WECHAT", "paymentClient": "APP", "money": money}; final data = {
final res = await Http.post(CommonApi.addBalance, data: data); "orderType": "RECHARGE",
"clientType": "APP",
"paymentMethod": "WECHAT",
"paymentClient": "APP",
"money": money,
};
final res = await Http.post(CommonApi.wechatPay, data: data);
logger.w(res); logger.w(res);
final payParams = res['data']; final payParams = res['data'];
logger.w(payParams); logger.w(payParams);
@ -79,30 +103,91 @@ class BalanceController extends GetxController {
); );
return; return;
} }
//
// final res = await Http.post(CommonApi.withdraw, data: {
// "money": money,
// "method": "1",
// });
// MyDialog.('提现成功,系统将在一个工作日内将余额提现至您绑定的微信内');
showDialog( showDialog(
context: Get.context!, context: Get.context!,
builder: (context) { builder: (context) {
return AlertDialog( return AlertDialog(
title: Text('现成功'), title: Text('提示!'),
content: const Text('系统将在一个工作日内将余额提现至您绑定的微信内', style: TextStyle(fontSize: 16.0)), content: const Text('发起提现申请后请及时进行确认收款未进行确认收款金额将于24小后退回', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white, backgroundColor: Colors.white,
surfaceTintColor: Colors.white, surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0, elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0), actionsPadding: const EdgeInsets.all(15.0),
actions: [ actions: [
TextButton(onPressed: () => {Get.back()}, child: Text('确认')), Obx(() {
return TextButton(
onPressed: buttonLoading.value
? null
: () async {
buttonLoading.value = true;
try {
final res = await Http.post(CommonApi.withdraw, data: {
"money": money,
"method": "1",
});
logger.w(res);
final pkg = res['data']['packageInfo'];
await getData(reset: true);
await getAccount();
await onWithdrawPressed(packageInfo: pkg);
Get.back();
} catch (e) {
logger.e("提现失败$e");
} finally {
buttonLoading.value = false;
}
},
child: buttonLoading.value
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(FStyle.primaryColor),
),
)
: const Text('确认'),
);
}),
// TextButton(
// onPressed: () async {
// //
// final res = await Http.post(CommonApi.withdraw, data: {
// "money": money,
// "method": "1",
// });
// logger.w(res);
// final pkg = res['data']['packageInfo'];
// await getData(reset: true);
// await getAccount();
// await onWithdrawPressed(packageInfo: pkg);
// Get.back();
// },
// child: Text('确认'),
// ),
], ],
); );
}, },
); );
getData(reset: true); }
Future<void> onWithdrawPressed({required String packageInfo}) async {
String encodedPackage = Uri.encodeComponent(packageInfo);
String query = 'mchId=1658665710&appId=wxebcdaea31881caab&package=$encodedPackage';
logger.e(query);
bool success = await WechatBusinessView.openBusinessView(
packageInfo: query,
);
if (success) {
logger.w("已唤起微信确认收款码");
} else {
logger.e("唤起失败");
}
} }
/// ///
@ -111,12 +196,16 @@ class BalanceController extends GetxController {
logger.w('正在加载中,跳过'); logger.w('正在加载中,跳过');
return; return;
} }
isLoading.value = true; isLoading.value = true;
logger.w('开始加载数据reset: $reset, currentPage: $currentPage'); final res = await Http.post(CommonApi.bills, data: {
"size": 10,
await Future.delayed(const Duration(seconds: 2)); "current": currentPage,
});
logger.e(res);
final List resData = res['data']?['records'] ?? [];
final bills = resData.map((item) => AccountBill.fromJson(item)).toList();
final total = res['data']['total'] ?? 0;
if (reset) { if (reset) {
logger.w('重置数据'); logger.w('重置数据');
currentPage = 1; currentPage = 1;
@ -124,32 +213,16 @@ class BalanceController extends GetxController {
hasMore.value = true; hasMore.value = true;
} }
List<AccountBill> newData = List.generate( data.addAll(bills);
10,
(index) {
int id = currentPage * 10 + index + 1;
// logger.w('生成数据: id=$id');
return AccountBill(
id: id,
source: '来源 $currentPage-${index + 1}',
changeAmount: (index + 1) * 10.0,
changeType: index % 2 + 1,
createTime: DateTime.now().toString(),
);
},
);
data.addAll(newData); if (data.length >= total) {
logger.w('添加了 ${newData.length} 条数据,总数据量: ${data.length}');
currentPage++;
logger.w('页码增加到: $currentPage');
if (currentPage > 5) {
hasMore.value = false; hasMore.value = false;
logger.w('没有更多数据了'); logger.w('没有更多数据了');
} }
currentPage++;
logger.w('页码增加到: $currentPage');
isLoading.value = false; isLoading.value = false;
logger.w('加载完成'); logger.w('加载完成');
} }

View File

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

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/components/web_page.dart';
import 'package:loopin/styles/index.dart'; import 'package:loopin/styles/index.dart';
class Setting extends StatelessWidget { class Setting extends StatelessWidget {
@ -23,14 +24,19 @@ class Setting extends StatelessWidget {
}, },
{ {
'icon': Icons.lock, 'icon': Icons.lock,
'title': '隐私', 'title': '隐私协议',
'onTap': () => Get.toNamed('/privacy'), 'onTap': () => Get.to(() => SafeArea(child: WebPage(url: 'https://www.wuzhongjie.com.cn/download/yinsizhengce.html', title: '隐私协议'))),
}, },
{ {
'icon': Icons.info, 'icon': Icons.lock,
'title': '关于我们', 'title': '用户协议',
'onTap': () => Get.toNamed('/about'), 'onTap': () => Get.to(() => SafeArea(child: WebPage(url: 'https://www.wuzhongjie.com.cn/download/yonhuxieyi.html', title: '用户协议'))),
}, },
// {
// 'icon': Icons.info,
// 'title': '关于我们',
// 'onTap': () => Get.toNamed('/about'),
// },
]; ];
return Scaffold( return Scaffold(

View File

@ -16,6 +16,7 @@ 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_conversation.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.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';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_friend_info.dart';
import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_user_full_info.dart';
class PageParams { class PageParams {
@ -55,6 +56,7 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
}, },
role: 0, role: 0,
)); ));
String blackTxt = '拉黑';
late RxInt followed = 0.obs; // late RxInt followed = 0.obs; //
// followersCount粉丝,mutualFollowersCount互关,followingCount我关注了多少人 // followersCount粉丝,mutualFollowersCount互关,followingCount我关注了多少人
@ -113,6 +115,7 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
loadData(0); loadData(0);
getUserLikesCount(); getUserLikesCount();
getBlackList();
} }
@override @override
@ -175,7 +178,7 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
final resIm = await ImService.instance.otherInfo(args['memberId']); final resIm = await ImService.instance.otherInfo(args['memberId']);
if (resIm.success && resIm.data != null) { if (resIm.success && resIm.data != null) {
userInfo.value = resIm.data!; userInfo.value = resIm.data!;
logger.i(userInfo.value.toLogString()); // logger.i(userInfo.value.toLogString());
} else { } else {
logger.e(resIm.desc); logger.e(resIm.desc);
} }
@ -210,6 +213,64 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
} }
} }
//
void getBlackList() async {
final res = await ImService.instance.blackList();
if (res.success && res.data != null) {
//
final data = res.data;
for (V2TimFriendInfo element in data ?? []) {
logger.w(element.toJson());
if (element.userID == args['memberId']) {
//
blackTxt = '取消拉黑';
}
}
}
}
//
void _cancelBlack() async {
logger.w('开始执行取消拉黑${args['memberId']}');
final res = await ImService.instance.deleteFromBlackList(userIDList: [args['memberId'] ?? '']);
logger.w(res.success);
//
if (res.success) {
blackTxt = '拉黑';
//退
Get.back();
}
}
//
void _addBlack() async {
logger.w('开始执行拉黑${args['memberId']}');
final res = await ImService.instance.addToBlackList(userIDList: [args['memberId'] ?? '']);
logger.w(res.success);
//
if (res.success) {
blackTxt = '取消拉黑';
//退
await ImService.instance.deleteConversation(conversationID: 'c2c_${args['memberId']}');
final ctl = Get.find<ChatController>();
ctl.chatList.removeWhere(
(conv) => conv.conversation.conversationID == 'c2c_${args['memberId']}',
);
ctl.chatList.refresh();
Get.back();
}
}
///
void _handleBlack() {
if (blackTxt == '拉黑') {
//_addBlack
_addBlack();
} else {
_cancelBlack();
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopScope( return PopScope(
@ -235,6 +296,77 @@ class MyPageState extends State<Vloger> with SingleTickerProviderStateMixin {
collapsedHeight: 120.0, collapsedHeight: 120.0,
pinned: true, pinned: true,
stretch: true, stretch: true,
actions: [
IconButton(
icon: const Icon(
Icons.more_horiz,
color: Colors.black,
),
onPressed: () async {
final paddingTop = MediaQuery.of(Get.context!).padding.top;
final selected = await showMenu(
context: Get.context!,
position: RelativeRect.fromLTRB(
double.infinity,
kToolbarHeight + paddingTop - 12,
8,
double.infinity,
),
color: FStyle.primaryColor,
elevation: 8,
items: [
PopupMenuItem<String>(
value: 'block',
child: Row(
children: [
Icon(Icons.block, color: Colors.white, size: 18),
SizedBox(width: 8),
Text(
blackTxt,
style: TextStyle(color: Colors.white),
),
],
),
),
],
);
if (selected != null) {
switch (selected) {
case 'block':
// print('点击了拉黑');
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text('确认要$blackTxt对方吗', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0),
actions: [
TextButton(
onPressed: () {
Get.back();
},
child: const Text('取消', style: TextStyle(color: Colors.black54)),
),
TextButton(onPressed: _handleBlack, child: const Text('确认', style: TextStyle(color: Colors.red))),
],
);
},
);
break;
// case 'foucs':
// print('点击了取关');
// break;
}
}
},
),
],
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
onPressed: () { onPressed: () {

View File

@ -1,14 +1,19 @@
library; library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/im_friend_listeners.dart';
import 'package:loopin/api/common_api.dart';
import 'package:loopin/api/shop_api.dart'; import 'package:loopin/api/shop_api.dart';
import 'package:loopin/components/my_toast.dart'; import 'package:loopin/components/my_toast.dart';
import 'package:shirne_dialog/shirne_dialog.dart'; import 'package:loopin/service/http.dart';
import 'package:timer_count_down/timer_count_down.dart';
import 'package:loopin/utils/wxsdk.dart'; import 'package:loopin/utils/wxsdk.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import 'package:shirne_dialog/shirne_dialog.dart';
import 'package:timer_count_down/timer_count_down.dart';
import '../../behavior/custom_scroll_behavior.dart'; import '../../behavior/custom_scroll_behavior.dart';
import '../../utils/lifecycle_handler.dart'; import '../../utils/lifecycle_handler.dart';
@ -20,9 +25,11 @@ class OrderDetail extends StatefulWidget {
} }
class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStateMixin { class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStateMixin {
late List orderStatusDict;
final String _orderId = Get.arguments['orderId'] ?? ''; final String _orderId = Get.arguments['orderId'] ?? '';
dynamic orderGoodsInfo; dynamic orderGoodsInfo;
int _initialSeconds = 30 * 60; // final int _initialSeconds = 30 * 60; //
bool _countdownFinished = false; // bool _countdownFinished = false; //
bool _isLoading = true; // bool _isLoading = true; //
bool _showQrCodeDialog = false; bool _showQrCodeDialog = false;
@ -31,7 +38,8 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getOrderDetail(orderId: _orderId); getOrderStatusDict();
// getOrderDetail(orderId: _orderId);
LifecycleHandler.onAppResumed = _onAppResumed; LifecycleHandler.onAppResumed = _onAppResumed;
} }
@ -42,7 +50,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
} }
void _onAppResumed() { void _onAppResumed() {
print('App回到前台刷新订单状态,订单Id${_orderId}'); print('App回到前台刷新订单状态,订单Id$_orderId');
getOrderDetail(orderId: _orderId); // getOrderDetail(orderId: _orderId); //
_showPaymentResultDialog(); // _showPaymentResultDialog(); //
} }
@ -53,7 +61,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
final res = await Http.get('${ShopApi.goodsOrderStatus}/$orderId'); final res = await Http.get('${ShopApi.goodsOrderStatus}/$orderId');
Get.toNamed('/myOrder'); Get.toNamed('/myOrder');
} catch (e) { } catch (e) {
print('报错-------------->${e}'); print('报错-------------->$e');
} }
} }
@ -64,7 +72,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
_isLoading = true; _isLoading = true;
}); });
final res = await Http.get('${ShopApi.goodsOrderDetail}/$orderId'); final res = await Http.get('${ShopApi.goodsOrderDetail}/$orderId');
debugPrint(res['data'].toString(), wrapWidth: 600); logger.w(res);
setState(() { setState(() {
orderGoodsInfo = res['data']; orderGoodsInfo = res['data'];
_isLoading = false; _isLoading = false;
@ -77,6 +85,12 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
} }
} }
Future<void> getOrderStatusDict() async {
final res = await Http.get('${CommonApi.dictionaryApi}oms_order_status');
orderStatusDict = res['data'] as List;
getOrderDetail(orderId: _orderId);
}
// //
void _cancelOrder() async { void _cancelOrder() async {
try { try {
@ -89,9 +103,11 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
// //
void _writeOffQrCode(verificationCodes) async { void _writeOffQrCode(verificationCodes) async {
if (verificationCodes != null && verificationCodes.isNotEmpty) { logger.e(orderGoodsInfo);
final orderInfo = orderGoodsInfo['items'];
if (orderInfo != null) {
// status为0 // status为0
List<dynamic> newVerifyList = verificationCodes.where((item) => item['status'] == 0).toList(); List<dynamic> newVerifyList = orderInfo.where((item) => item['status'] == 0).toList();
if (newVerifyList.isNotEmpty) { if (newVerifyList.isNotEmpty) {
setState(() { setState(() {
@ -108,7 +124,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
} else { } else {
MyToast().tip( MyToast().tip(
title: '暂无可用的核销码', title: '暂无可用的核销码',
position: 'center', position: 'top',
type: 'error', type: 'error',
); );
} }
@ -229,8 +245,19 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
); );
} }
//
String getOrderStatusText(dynamic status) {
int statusCode = status is String ? int.tryParse(status) ?? -1 : (status is int ? status : -1);
final match = orderStatusDict.firstWhere(
(item) => item['dictValue'].toString() == statusCode.toString(),
orElse: () => {'dictLabel': '未知状态'},
);
return match['dictLabel'] ?? '未知状态';
}
// //
String getOrderStatusText(int status) { String getOrderStatusText_old(int status) {
print('111111111111$status'); print('111111111111$status');
switch (status) { switch (status) {
case 0: case 0:
@ -276,10 +303,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
// //
dynamic _getFirstProductInfo() { dynamic _getFirstProductInfo() {
if (orderGoodsInfo == null || if (orderGoodsInfo == null || orderGoodsInfo['items'] == null || orderGoodsInfo['items'] is! List || orderGoodsInfo['items'].isEmpty) {
orderGoodsInfo['items'] == null ||
orderGoodsInfo['items'] is! List ||
orderGoodsInfo['items'].isEmpty) {
return {}; return {};
} }
return orderGoodsInfo['items'][0]; return orderGoodsInfo['items'][0];
@ -288,6 +312,8 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
// //
Widget _buildProductImage() { Widget _buildProductImage() {
final productInfo = _getFirstProductInfo(); final productInfo = _getFirstProductInfo();
logger.e(orderGoodsInfo);
final picUrl = productInfo?['pic']; final picUrl = productInfo?['pic'];
if (picUrl == null || picUrl.isEmpty) { if (picUrl == null || picUrl.isEmpty) {
@ -337,9 +363,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
), ),
child: Center( child: Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null,
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
), ),
), ),
); );
@ -372,9 +396,63 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
), ),
const SizedBox(width: 10.0), const SizedBox(width: 10.0),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () async {
// pages/index/index // pages/index/index
Wxsdk.openMiniApp(orderId: _orderId); // Wxsdk.openMiniApp(orderId: _orderId);
//-----------
final infoCtl = Get.find<ImUserInfoController>();
final openId = infoCtl.customInfo['openId'];
if (openId == null || openId.isEmpty) {
showDialog(
context: Get.context!,
builder: (context) {
return AlertDialog(
title: Text('微信授权'),
content: const Text('当前支付需要您进行微信授权', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0),
actions: [
TextButton(onPressed: () => {Get.back()}, child: Text('取消', style: TextStyle(color: Colors.red))),
TextButton(
onPressed: () async {
//
await Wxsdk.login();
Get.back();
},
child: Text('去授权')),
],
);
},
);
return;
}
//
final data = {
"orderType": "ORDER",
"clientType": "APP",
"paymentMethod": "WECHAT",
"paymentClient": "APP",
"sn": _orderId,
};
final res = await Http.post(CommonApi.wechatPay, data: data);
logger.w(res);
final payParams = res['data'];
logger.w(payParams);
//
await Wxsdk.payWithWx(
appId: payParams['appid'],
partnerId: payParams['partnerid'],
prepayId: payParams['prepayid'],
packageValue: payParams['package'],
nonceStr: payParams['noncestr'],
timestamp: int.parse(payParams['timestamp']),
sign: payParams['sign'],
);
}, },
style: ButtonStyle( style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), backgroundColor: WidgetStateProperty.all(Color(0xff07c160)),
@ -385,7 +463,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
], ],
); );
case 1: // case 2: //
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -401,21 +479,21 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
], ],
); );
case 2: // // case 2: //
return Row( // return Row(
mainAxisAlignment: MainAxisAlignment.end, // mainAxisAlignment: MainAxisAlignment.end,
children: [ // children: [
const SizedBox(width: 10.0), // const SizedBox(width: 10.0),
ElevatedButton( // ElevatedButton(
onPressed: () {}, // onPressed: () {},
style: ButtonStyle( // style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.green), // backgroundColor: WidgetStateProperty.all(Colors.green),
foregroundColor: WidgetStateProperty.all(Colors.white), // foregroundColor: WidgetStateProperty.all(Colors.white),
), // ),
child: const Text('已完成'), // child: const Text('已完成'),
), // ),
], // ],
); // );
case 3: // case 3: //
return Row( return Row(
@ -701,6 +779,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
build: (_, double time) { build: (_, double time) {
int m = ((time % 3600) ~/ 60).toInt(); int m = ((time % 3600) ~/ 60).toInt();
int s = (time % 60).toInt(); int s = (time % 60).toInt();
String formatted = "${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}"; String formatted = "${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}";
return Text( return Text(
@ -721,9 +800,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
), ),
SizedBox(height: 4), SizedBox(height: 4),
Text( Text(
_countdownFinished _countdownFinished ? '订单已自动取消' : '超过30分钟未支付订单将自动取消',
? '订单已自动取消'
: '超过30分钟未支付订单将自动取消',
style: TextStyle(color: Colors.grey, fontSize: 12.0), style: TextStyle(color: Colors.grey, fontSize: 12.0),
), ),
], ],
@ -750,7 +827,15 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
Row( Row(
children: [ children: [
Spacer(), Spacer(),
Text( orderGoodsInfo['items'][0]['status'] == 1
? Text(
'已核销',
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
)
: Text(
getOrderStatusText(orderGoodsInfo?['status']), getOrderStatusText(orderGoodsInfo?['status']),
style: TextStyle( style: TextStyle(
color: getOrderStatusColor(orderGoodsInfo?['status']), color: getOrderStatusColor(orderGoodsInfo?['status']),
@ -842,7 +927,7 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
_buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime'] ?? ''), _buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime'] ?? ''),
_buildOrderInfoRow('购买数量', (productInfo['quantity'] ?? 0).toString()), _buildOrderInfoRow('购买数量', (productInfo['quantity'] ?? 0).toString()),
_buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount'] ?? '0.00'}'), _buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount'] ?? '0.00'}'),
_buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount'] ?? '0.00'}'), // _buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount'] ?? '0.00'}'),
], ],
) )
], ],
@ -856,9 +941,21 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
if (_showQrCodeDialog) _buildQrCodeDialog(), if (_showQrCodeDialog) _buildQrCodeDialog(),
], ],
), ),
bottomNavigationBar: orderGoodsInfo == null // bottomNavigationBar: orderGoodsInfo == null
? null // ? null
: SafeArea( // : SafeArea(
// bottom: true,
// minimum: const EdgeInsets.all(10),
// child: Container(
// height: 60.0,
// color: Colors.white,
// padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
// child: buildBottomButtons(),
// ),
// ),
bottomNavigationBar: (orderGoodsInfo != null && !_showQrCodeDialog)
? SafeArea(
bottom: true,
minimum: const EdgeInsets.all(10), minimum: const EdgeInsets.all(10),
child: Container( child: Container(
height: 60.0, height: 60.0,
@ -866,7 +963,8 @@ class _OrderDetailState extends State<OrderDetail> with SingleTickerProviderStat
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
child: buildBottomButtons(), child: buildBottomButtons(),
), ),
), )
: null,
); );
} }
} }

View File

@ -3,10 +3,13 @@ library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/utils/wxsdk.dart'; import 'package:loopin/IM/controller/im_user_info_controller.dart';
import 'package:loopin/IM/push_service.dart';
import 'package:loopin/api/common_api.dart';
import 'package:loopin/api/shop_api.dart'; import 'package:loopin/api/shop_api.dart';
import 'package:loopin/components/my_toast.dart'; import 'package:loopin/components/my_toast.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
import 'package:loopin/utils/wxsdk.dart';
import '../../behavior/custom_scroll_behavior.dart'; import '../../behavior/custom_scroll_behavior.dart';
@ -28,36 +31,39 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
List<Map<String, dynamic>> _allOrders = []; List<Map<String, dynamic>> _allOrders = [];
List<Map<String, dynamic>> _pendingPaymentOrders = []; List<Map<String, dynamic>> _pendingPaymentOrders = [];
List<Map<String, dynamic>> _pendingVerificationOrders = []; List<Map<String, dynamic>> _pendingVerificationOrders = [];
List<Map<String, dynamic>> _completedOrders = []; // List<Map<String, dynamic>> _completedOrders = [];
List<Map<String, dynamic>> _closedOrders = []; List<Map<String, dynamic>> _closedOrders = [];
List<Map<String, dynamic>> _refundingOrders = []; List<Map<String, dynamic>> _refundingOrders = [];
List<Map<String, dynamic>> _refundedOrders = []; List<Map<String, dynamic>> _refundedOrders = [];
List<Map<String, dynamic>> _cancelledOrders = []; List<Map<String, dynamic>> _cancelledOrders = [];
// Tab的分页状态 // Tab的分页状态
Map<int, int> _pageNums = {}; final Map<int, int> _pageNums = {};
Map<int, int> _totalCounts = {}; final Map<int, int> _totalCounts = {};
Map<int, bool> _hasMoreData = {}; final Map<int, bool> _hasMoreData = {};
Map<int, bool> _isLoading = {}; final Map<int, bool> _isLoading = {};
// 0->1->2->3->4->退5->退 6-> // 0->1->2->3->4->退5->退 6->
List tabList = [ List tabList = [
{'id': '', 'name': "全部", 'index': 0}, {'id': '', 'name': "全部", 'index': 0},
{'id': 0, 'name': "待付款", 'index': 1}, {'id': 0, 'name': "待付款", 'index': 1},
{'id': 1, 'name': "待核销", 'index': 2}, {'id': 2, 'name': "已支付", 'index': 2},
{'id': 2, 'name': "已完成", 'index': 3}, // {'id': 2, 'name': "已完成", 'index': 3},
{'id': 3, 'name': "已关闭", 'index': 4}, {'id': 3, 'name': "已关闭", 'index': 4},
{'id': 4, 'name': "退款中", 'index': 5}, {'id': 4, 'name': "退款中", 'index': 5},
{'id': 5, 'name': "已退款", 'index': 6}, {'id': 5, 'name': "已退款", 'index': 6},
{'id': 6, 'name': "已取消", 'index': 7} {'id': 6, 'name': "已取消", 'index': 7}
]; ];
late List orderStatusDict;
late ScrollController scrollController = ScrollController(); late ScrollController scrollController = ScrollController();
late TabController tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this); late TabController tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this);
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getOrderStatusDict();
// //
for (var tab in tabList) { for (var tab in tabList) {
_pageNums[tab['index']] = 1; _pageNums[tab['index']] = 1;
@ -83,19 +89,36 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
super.dispose(); super.dispose();
} }
Future<void> getOrderStatusDict() async {
final res = await Http.get('${CommonApi.dictionaryApi}oms_order_status');
orderStatusDict = res['data'] as List;
//
getOrderList(false);
// dictValue
}
// Tab的订单列表 // Tab的订单列表
List<Map<String, dynamic>> _getCurrentOrderList() { List<Map<String, dynamic>> _getCurrentOrderList() {
final currentIndex = tabController.index; final currentIndex = tabController.index;
switch (currentIndex) { switch (currentIndex) {
case 0: return _allOrders; case 0:
case 1: return _pendingPaymentOrders; return _allOrders;
case 2: return _pendingVerificationOrders; case 1:
case 3: return _completedOrders; return _pendingPaymentOrders;
case 4: return _closedOrders; case 2:
case 5: return _refundingOrders; return _pendingVerificationOrders;
case 6: return _refundedOrders; // case 3:
case 7: return _cancelledOrders; // return _completedOrders;
default: return _allOrders; case 3:
return _closedOrders;
case 4:
return _refundingOrders;
case 5:
return _refundedOrders;
case 6:
return _cancelledOrders;
default:
return _allOrders;
} }
} }
@ -125,35 +148,35 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
_pendingVerificationOrders = orders; _pendingVerificationOrders = orders;
} }
break; break;
// case 3:
// if (loadMore) {
// _completedOrders.addAll(orders);
// } else {
// _completedOrders = orders;
// }
// break;
case 3: case 3:
if (loadMore) {
_completedOrders.addAll(orders);
} else {
_completedOrders = orders;
}
break;
case 4:
if (loadMore) { if (loadMore) {
_closedOrders.addAll(orders); _closedOrders.addAll(orders);
} else { } else {
_closedOrders = orders; _closedOrders = orders;
} }
break; break;
case 5: case 4:
if (loadMore) { if (loadMore) {
_refundingOrders.addAll(orders); _refundingOrders.addAll(orders);
} else { } else {
_refundingOrders = orders; _refundingOrders = orders;
} }
break; break;
case 6: case 5:
if (loadMore) { if (loadMore) {
_refundedOrders.addAll(orders); _refundedOrders.addAll(orders);
} else { } else {
_refundedOrders = orders; _refundedOrders = orders;
} }
break; break;
case 7: case 6:
if (loadMore) { if (loadMore) {
_cancelledOrders.addAll(orders); _cancelledOrders.addAll(orders);
} else { } else {
@ -167,9 +190,7 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
// //
void _scrollListener() { void _scrollListener() {
final currentIndex = tabController.index; final currentIndex = tabController.index;
if (scrollController.position.pixels == scrollController.position.maxScrollExtent && if (scrollController.position.pixels == scrollController.position.maxScrollExtent && !_isLoading[currentIndex]! && _hasMoreData[currentIndex]!) {
!_isLoading[currentIndex]! &&
_hasMoreData[currentIndex]!) {
getOrderList(true); getOrderList(true);
} }
} }
@ -212,6 +233,7 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
if (res['code'] == 200 && res['data'] != null) { if (res['code'] == 200 && res['data'] != null) {
final data = res['data']; final data = res['data'];
logger.e(data);
final List<Map<String, dynamic>> newOrders = List<Map<String, dynamic>>.from(data['records'] ?? []); final List<Map<String, dynamic>> newOrders = List<Map<String, dynamic>>.from(data['records'] ?? []);
final int total = data['total'] ?? 0; final int total = data['total'] ?? 0;
@ -267,10 +289,10 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
switch (statusCode) { switch (statusCode) {
case 0: // case 0: //
return '待付款: '; return '待付款: ';
case 1: // case 2: //
return '已付款: '; return '已付款: ';
case 2: // // case 2: //
return '实付款: '; // return '实付款: ';
case 3: // case 3: //
return '订单金额: '; return '订单金额: ';
case 4: // 退 case 4: // 退
@ -310,13 +332,12 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
spacing: 5.0, spacing: 5.0,
children: [ children: [
ClipOval( // ClipOval(
child: Image.asset( // child: NetworkOrAssetImage(
'assets/images/avatar/img11.jpg', // imageUrl: order['items'][0]['faceUrl'] ?? '',
width: 25.0, // width: 25,
), // )),
), Text(order['items'][0]['tenantName'] ?? '未知商家名称'),
Text(order['items'][0]['tenantName'] ?? '商家名称'),
Icon( Icon(
Icons.arrow_forward_ios_rounded, Icons.arrow_forward_ios_rounded,
color: Colors.grey, color: Colors.grey,
@ -325,7 +346,12 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
], ],
), ),
Spacer(), Spacer(),
Text( order['items'][0]['status'] == 1
? Text(
'已核销',
style: TextStyle(color: Colors.red),
)
: Text(
_getStatusText(order['status']), _getStatusText(order['status']),
style: TextStyle(color: _getStatusColor(order['status'])), style: TextStyle(color: _getStatusColor(order['status'])),
) )
@ -334,7 +360,8 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
SizedBox(height: 10), SizedBox(height: 10),
// //
if (order['items'] != null && order['items'].isNotEmpty) if (order['items'] != null && order['items'].isNotEmpty)
...order['items'].map<Widget>((item) => Row( ...order['items']
.map<Widget>((item) => Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
@ -386,7 +413,8 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
), ),
) )
], ],
)).toList(), ))
.toList(),
SizedBox(height: 10), SizedBox(height: 10),
// //
Container( Container(
@ -422,8 +450,18 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
); );
} }
//
String _getStatusText(dynamic status) { String _getStatusText(dynamic status) {
int statusCode = status is String ? int.tryParse(status) ?? -1 : (status is int ? status : -1);
final match = orderStatusDict.firstWhere(
(item) => item['dictValue'].toString() == statusCode.toString(),
orElse: () => {'dictLabel': '未知状态'},
);
return match['dictLabel'] ?? '未知状态';
}
//
String _getStatusTextold(dynamic status) {
// //
int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0);
@ -515,7 +553,7 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
void _cancelOrder(String orderId) async { void _cancelOrder(String orderId) async {
try { try {
final res = await Http.post('${ShopApi.cancelGoodsOrder}/$orderId'); final res = await Http.post('${ShopApi.cancelGoodsOrder}/$orderId');
print('取消订单成功-------------->${res}'); print('取消订单成功-------------->$res');
if (res['code'] == 200) { if (res['code'] == 200) {
MyToast().tip( MyToast().tip(
@ -527,7 +565,7 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
_refreshAllRelatedTabs(); _refreshAllRelatedTabs();
} }
} catch (e) { } catch (e) {
print('取消订单失败-------------->${e}'); print('取消订单失败-------------->$e');
} }
} }
@ -546,9 +584,61 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
} }
} }
void _payOrder(_orderId) { void _payOrder(orderId) async {
// pages/index/index // pages/index/index
Wxsdk.openMiniApp(orderId: _orderId); // Wxsdk.openMiniApp(orderId: orderId);
//------------
final infoCtl = Get.find<ImUserInfoController>();
final openId = infoCtl.customInfo['openId'];
if (openId == null || openId.isEmpty) {
showDialog(
context: Get.context!,
builder: (context) {
return AlertDialog(
title: Text('微信授权'),
content: const Text('当前支付需要您进行微信授权', style: TextStyle(fontSize: 16.0)),
backgroundColor: Colors.white,
surfaceTintColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
elevation: 2.0,
actionsPadding: const EdgeInsets.all(15.0),
actions: [
TextButton(onPressed: () => {Get.back()}, child: Text('取消', style: TextStyle(color: Colors.red))),
TextButton(
onPressed: () async {
//
await Wxsdk.login();
Get.back();
},
child: Text('去授权')),
],
);
},
);
return;
}
//------
final data = {
"orderType": "ORDER",
"clientType": "APP",
"paymentMethod": "WECHAT",
"paymentClient": "APP",
"sn": orderId,
};
final res = await Http.post(CommonApi.wechatPay, data: data);
final payParams = res['data'];
//
await Wxsdk.payWithWx(
appId: payParams['appid'],
partnerId: payParams['partnerid'],
prepayId: payParams['prepayid'],
packageValue: payParams['package'],
nonceStr: payParams['noncestr'],
timestamp: int.parse(payParams['timestamp']),
sign: payParams['sign'],
);
} }
// tab的数据 // tab的数据
@ -560,14 +650,30 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
_hasMoreData[index] = true; _hasMoreData[index] = true;
switch (index) { switch (index) {
case 0: _allOrders = []; break; case 0:
case 1: _pendingPaymentOrders = []; break; _allOrders = [];
case 2: _pendingVerificationOrders = []; break; break;
case 3: _completedOrders = []; break; case 1:
case 4: _closedOrders = []; break; _pendingPaymentOrders = [];
case 5: _refundingOrders = []; break; break;
case 6: _refundedOrders = []; break; case 2:
case 7: _cancelledOrders = []; break; _pendingVerificationOrders = [];
break;
// case 3:
// _completedOrders = [];
// break;
case 3:
_closedOrders = [];
break;
case 4:
_refundingOrders = [];
break;
case 5:
_refundedOrders = [];
break;
case 6:
_cancelledOrders = [];
break;
} }
}); });
} }
@ -638,8 +744,7 @@ class _MyOrderState extends State<MyOrder> 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: Builder( child: Builder(builder: (context) {
builder: (context) {
final currentOrders = _getOrderListByIndex(index); final currentOrders = _getOrderListByIndex(index);
final isLoading = _isLoading[index] ?? false; final isLoading = _isLoading[index] ?? false;
final hasMoreData = _hasMoreData[index] ?? false; final hasMoreData = _hasMoreData[index] ?? false;
@ -658,29 +763,36 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
return _buildOrderItem(currentOrders[itemIndex]); return _buildOrderItem(currentOrders[itemIndex]);
}, },
); );
} }),
),
), ),
), ),
); );
}), }),
), ),
); );
} }
// //
List<Map<String, dynamic>> _getOrderListByIndex(int index) { List<Map<String, dynamic>> _getOrderListByIndex(int index) {
switch (index) { switch (index) {
case 0: return _allOrders; case 0:
case 1: return _pendingPaymentOrders; return _allOrders;
case 2: return _pendingVerificationOrders; case 1:
case 3: return _completedOrders; return _pendingPaymentOrders;
case 4: return _closedOrders; case 2:
case 5: return _refundingOrders; return _pendingVerificationOrders;
case 6: return _refundedOrders; // case 3:
case 7: return _cancelledOrders; // return _completedOrders;
default: return _allOrders; case 3:
return _closedOrders;
case 4:
return _refundingOrders;
case 5:
return _refundedOrders;
case 6:
return _cancelledOrders;
default:
return _allOrders;
} }
} }
@ -708,7 +820,7 @@ class _MyOrderState extends State<MyOrder> with SingleTickerProviderStateMixin {
} }
Widget emptyTip() { Widget emptyTip() {
return Container( return SizedBox(
width: double.infinity, width: double.infinity,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View File

@ -1,11 +1,15 @@
library; library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/IM/push_service.dart';
import 'package:loopin/api/common_api.dart';
import 'package:loopin/api/shop_api.dart'; import 'package:loopin/api/shop_api.dart';
import 'package:shirne_dialog/shirne_dialog.dart';
import 'package:loopin/components/my_toast.dart'; import 'package:loopin/components/my_toast.dart';
import 'package:loopin/service/http.dart';
import 'package:shirne_dialog/shirne_dialog.dart';
import '../../behavior/custom_scroll_behavior.dart'; import '../../behavior/custom_scroll_behavior.dart';
class SellerOrderDetail extends StatefulWidget { class SellerOrderDetail extends StatefulWidget {
@ -16,28 +20,27 @@ class SellerOrderDetail extends StatefulWidget {
} }
class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTickerProviderStateMixin { class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTickerProviderStateMixin {
late String ? _orderId; late List orderStatusDict;
late String ?_writeOffCodeId;
late String _orderId;
late String _writeOffCodeId;
dynamic orderGoodsInfo; dynamic orderGoodsInfo;
bool _isLoading = true; // bool _isLoading = true; //
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_orderId = Get.arguments['orderId'] ?? ''; // id
_writeOffCodeId = Get.arguments['writeOffCodeId'] ?? ''; // getOrderStatusDict();
if(_orderId != null){ // _orderId = Get.arguments['orderId'] ?? ''; // id
getOrderDetailByOrderId(_orderId); // _writeOffCodeId = Get.arguments['writeOffCodeId'] ?? ''; //
}else if(_writeOffCodeId != null){ // if (_orderId.isNotEmpty) {
getOrderDetailByWriteOffId(_writeOffCodeId); // getOrderDetailByOrderId(_orderId);
// } else if (_writeOffCodeId.isNotEmpty) {
// getOrderDetailByWriteOffId(_writeOffCodeId);
// }
} }
}
@override
void dispose() {
super.dispose();
}
// id // id
void getOrderDetailByOrderId(orderId) async { void getOrderDetailByOrderId(orderId) async {
try { try {
@ -57,14 +60,30 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
MyDialog.toast('获取订单详情失败'); MyDialog.toast('获取订单详情失败');
} }
} }
Future<void> getOrderStatusDict() async {
final res = await Http.get('${CommonApi.dictionaryApi}oms_order_status');
// logger.e(res);
orderStatusDict = res['data'] as List;
//
_orderId = Get.arguments['orderId'] ?? ''; // id
_writeOffCodeId = Get.arguments['writeOffCodeId'] ?? ''; //
if (_orderId.isNotEmpty) {
getOrderDetailByOrderId(_orderId);
} else if (_writeOffCodeId.isNotEmpty) {
getOrderDetailByWriteOffId(_writeOffCodeId);
}
}
// //
void getOrderDetailByWriteOffId(code) async { void getOrderDetailByWriteOffId(code) async {
try { try {
setState(() { setState(() {
_isLoading = true; _isLoading = true;
}); });
logger.e('code=$code');
final res = await Http.get('${ShopApi.getWriteOffDetail}?code=$code'); final res = await Http.get('${ShopApi.getWriteOffDetail}?code=$code');
print('订单详情-------------->${res['data']}'); logger.w('订单详情-------------->${res['data']}');
setState(() { setState(() {
orderGoodsInfo = res['data']; orderGoodsInfo = res['data'];
_isLoading = false; _isLoading = false;
@ -79,44 +98,58 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
// //
void _confirmVerifyCode() async { void _confirmVerifyCode() async {
late String writeOffCode; logger.e(orderGoodsInfo);
if(_orderId != null){ // final status = orderGoodsInfo['verificationCodeStatus'];
var verificationCodesList = orderGoodsInfo['verificationCodes']; final code = orderGoodsInfo['code'];
if (verificationCodesList != null && verificationCodesList.isNotEmpty) { if (status == 0) {
// status为0
List<dynamic> newVerifyList = verificationCodesList.where((item) => item['status'] == 0).toList();
if (newVerifyList.isNotEmpty) {
writeOffCode = newVerifyList[0]['code'] ?? '';
} else {
return MyToast().tip(
title: '暂无可用的核销码',
position: 'center',
type: 'error',
);
}
} else {
return MyToast().tip(
title: '暂无可用的核销码',
position: 'center',
type: 'error',
);
}
}else if(_writeOffCodeId != null){
writeOffCode = _writeOffCodeId?? '';
}
try { try {
final res = await Http.get('${ShopApi.confirmWriteOff}?code=$writeOffCode'); final res = await Http.get('${ShopApi.confirmWriteOff}?code=$code');
debugPrint(res['data'].toString(), wrapWidth: 600); logger.e(res);
MyToast().tip( MyToast().tip(
title: '核销成功', title: '核销成功',
position: 'center', position: 'center',
type: 'error', type: 'success',
); );
} catch (e) { } catch (e) {
logger.e('失败:$e');
} }
} }
// //
// var verificationCodesList = orderGoodsInfo['verificationCodes'];
// logger.e(verificationCodesList);
// if (verificationCodesList != null && verificationCodesList.isNotEmpty) {
// // status为0
// List<dynamic> newVerifyList = verificationCodesList.where((item) => item['status'] == 0).toList();
// if (newVerifyList.isNotEmpty) {
// writeOffCode = newVerifyList[0]['code'] ?? '';
// } else {
// return MyToast().tip(
// title: '暂无可用的核销码',
// position: 'center',
// type: 'error',
// );
// }
// } else {
// return MyToast().tip(
// title: '暂无可用的核销码',
// position: 'center',
// type: 'error',
// );
// }
}
String getOrderStatusText(dynamic status) {
int statusCode = status is String ? int.tryParse(status) ?? -1 : (status is int ? status : -1);
final match = orderStatusDict.firstWhere(
(item) => item['dictValue'].toString() == statusCode.toString(),
orElse: () => {'dictLabel': '未知状态'},
);
return match['dictLabel'] ?? '未知状态';
}
// //
String getOrderStatusText(int status) { String _getOrderStatusText_old(int status) {
switch (status) { switch (status) {
case 0: case 0:
return '待付款'; return '待付款';
@ -161,14 +194,18 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
// //
List<dynamic> getProductInfoList() { List<dynamic> getProductInfoList() {
// 使 items // 使 items --------
if (orderGoodsInfo?['items'] != null && orderGoodsInfo!['items'] is List) { if (orderGoodsInfo?['items'] != null && orderGoodsInfo!['items'] is List) {
return orderGoodsInfo!['items']; return orderGoodsInfo!['items'];
} }
// items 使 productInfo // items 使 productInfo ---------
if (orderGoodsInfo?['productInfo'] != null && orderGoodsInfo!['productInfo'] is List) { if (orderGoodsInfo?['productInfo'] != null && orderGoodsInfo!['productInfo'] is List) {
return orderGoodsInfo!['productInfo']; return orderGoodsInfo!['productInfo'];
} }
//
if (orderGoodsInfo != null) {
return [orderGoodsInfo];
}
// //
return []; return [];
} }
@ -230,9 +267,7 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
), ),
child: Center( child: Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null,
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
: null,
), ),
), ),
); );
@ -310,7 +345,7 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
children: [], children: [],
); );
case 1: // case 2: //
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
@ -328,11 +363,11 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
], ],
); );
case 2: // // case 2: //
return Row( // return Row(
mainAxisAlignment: MainAxisAlignment.end, // mainAxisAlignment: MainAxisAlignment.end,
children: [], // children: [],
); // );
case 3: // case 3: //
return Row( return Row(
@ -432,8 +467,6 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
style: TextStyle(color: Colors.orange), style: TextStyle(color: Colors.orange),
), ),
SizedBox(width: 4), SizedBox(width: 4),
], ],
), ),
SizedBox(height: 4), SizedBox(height: 4),
@ -461,7 +494,15 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
Row( Row(
children: [ children: [
Spacer(), Spacer(),
Text( orderGoodsInfo['items'][0]['status'] == 1
? Text(
'已核销',
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
)
: Text(
getOrderStatusText(orderGoodsInfo?['status'] ?? 0), getOrderStatusText(orderGoodsInfo?['status'] ?? 0),
style: TextStyle( style: TextStyle(
color: getOrderStatusColor(orderGoodsInfo?['status'] ?? 0), color: getOrderStatusColor(orderGoodsInfo?['status'] ?? 0),
@ -519,8 +560,11 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
_buildOrderInfoRow('订单号', orderGoodsInfo?['orderId']?.toString() ?? ''), _buildOrderInfoRow('订单号', orderGoodsInfo?['orderId']?.toString() ?? ''),
_buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime']?.toString() ?? ''), _buildOrderInfoRow('下单时间', orderGoodsInfo?['createTime']?.toString() ?? ''),
_buildOrderInfoRow('购买数量', _calculateTotalQuantity().toString()), _buildOrderInfoRow('购买数量', _calculateTotalQuantity().toString()),
_buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount']?.toString() ?? '0.00'}'), _orderId.isNotEmpty
_buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount']?.toString() ?? '0.00'}'), ? _buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['totalAmount']?.toString() ?? '0.00'}')
: _buildOrderInfoRow('订单金额', '¥${orderGoodsInfo?['salePrice']?.toString() ?? '0.00'}'),
// _buildOrderInfoRow('实付金额', '¥${orderGoodsInfo?['payAmount']?.toString() ?? '0.00'}'),
], ],
) )
], ],
@ -538,7 +582,7 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
height: 60.0, height: 60.0,
color: Colors.white, color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0),
// child: buildBottomButtons(), child: _orderId.isEmpty ? buildBottomButtons() : null,
), ),
), ),
); );
@ -546,10 +590,18 @@ class _SellerOrderDetailState extends State<SellerOrderDetail> with SingleTicker
// //
int _calculateTotalQuantity() { int _calculateTotalQuantity() {
// final productList = getProductInfoList();
// int total = 0;
// for (var product in productList) {
// total += (product?['buyNum'] as int? ?? 0);
// }
// return total;
final productList = getProductInfoList(); final productList = getProductInfoList();
int total = 0; // logger.e(productList);
var total = 0;
for (var product in productList) { for (var product in productList) {
total += (product?['buyNum'] as int? ?? 0); total = product['quantity'];
} }
return total; return total;
} }

View File

@ -3,7 +3,8 @@ library;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/utils/wxsdk.dart'; import 'package:loopin/IM/push_service.dart';
import 'package:loopin/api/common_api.dart';
import 'package:loopin/api/shop_api.dart'; import 'package:loopin/api/shop_api.dart';
import 'package:loopin/components/my_toast.dart'; import 'package:loopin/components/my_toast.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
@ -28,33 +29,45 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
List<Map<String, dynamic>> _allOrders = []; List<Map<String, dynamic>> _allOrders = [];
List<Map<String, dynamic>> _pendingPaymentOrders = []; List<Map<String, dynamic>> _pendingPaymentOrders = [];
List<Map<String, dynamic>> _pendingVerificationOrders = []; List<Map<String, dynamic>> _pendingVerificationOrders = [];
List<Map<String, dynamic>> _completedOrders = []; // List<Map<String, dynamic>> _completedOrders = [];
List<Map<String, dynamic>> _closedOrders = []; List<Map<String, dynamic>> _closedOrders = [];
List<Map<String, dynamic>> _refundingOrders = []; List<Map<String, dynamic>> _refundingOrders = [];
List<Map<String, dynamic>> _refundedOrders = []; List<Map<String, dynamic>> _refundedOrders = [];
List<Map<String, dynamic>> _cancelledOrders = []; List<Map<String, dynamic>> _cancelledOrders = [];
// Tab的分页状态 // Tab的分页状态
Map<int, int> _pageNums = {}; final Map<int, int> _pageNums = {};
Map<int, int> _totalCounts = {}; final Map<int, int> _totalCounts = {};
Map<int, bool> _hasMoreData = {}; final Map<int, bool> _hasMoreData = {};
Map<int, bool> _isLoading = {}; final Map<int, bool> _isLoading = {};
// 0->1->2->3->4->退5->退 6-> // 0->1->2->3->4->退5->退 6->
// List tabList = [
// {'id': '', 'name': "全部", 'index': 0},
// {'id': 0, 'name': "待付款", 'index': 1},
// {'id': 1, 'name': "待核销", 'index': 2},
// {'id': 2, 'name': "已完成", 'index': 3},
// {'id': 3, 'name': "已关闭", 'index': 4},
// {'id': 4, 'name': "退款中", 'index': 5},
// {'id': 5, 'name': "已退款", 'index': 6},
// {'id': 6, 'name': "已取消", 'index': 7}
// ];
List tabList = [ List tabList = [
{'id': '', 'name': "全部", 'index': 0}, {'id': '', 'name': "全部", 'index': 0},
{'id': 0, 'name': "待付款", 'index': 1}, {'id': 0, 'name': "待付款", 'index': 1},
{'id': 1, 'name': "待核销", 'index': 2}, {'id': 2, 'name': "已支付", 'index': 2},
{'id': 2, 'name': "已完成", 'index': 3}, // {'id': 2, 'name': "已完成", 'index': 3},
{'id': 3, 'name': "已关闭", 'index': 4}, {'id': 3, 'name': "已关闭", 'index': 3},
{'id': 4, 'name': "退款中", 'index': 5}, {'id': 4, 'name': "退款中", 'index': 4},
{'id': 5, 'name': "已退款", 'index': 6}, {'id': 5, 'name': "已退款", 'index': 5},
{'id': 6, 'name': "已取消", 'index': 7} {'id': 6, 'name': "已取消", 'index': 6}
]; ];
late ScrollController scrollController = ScrollController(); late ScrollController scrollController = ScrollController();
late TabController tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this); late TabController tabController = TabController(initialIndex: 0, length: tabList.length, vsync: this);
late List orderStatusDict;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -70,8 +83,9 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
scrollController.addListener(_scrollListener); scrollController.addListener(_scrollListener);
// tab切换事件 // tab切换事件
tabController.addListener(_tabChanged); tabController.addListener(_tabChanged);
getOrderStatusDict();
// //
getOrderList(false); // getOrderList(false);
} }
@override @override
@ -83,19 +97,37 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
super.dispose(); super.dispose();
} }
Future<void> getOrderStatusDict() async {
final res = await Http.get('${CommonApi.dictionaryApi}oms_order_status');
logger.e(res);
orderStatusDict = res['data'] as List;
//
getOrderList(false);
// dictValue
}
// Tab的订单列表 // Tab的订单列表
List<Map<String, dynamic>> _getCurrentOrderList() { List<Map<String, dynamic>> _getCurrentOrderList() {
final currentIndex = tabController.index; final currentIndex = tabController.index;
switch (currentIndex) { switch (currentIndex) {
case 0: return _allOrders; case 0:
case 1: return _pendingPaymentOrders; return _allOrders;
case 2: return _pendingVerificationOrders; case 1:
case 3: return _completedOrders; return _pendingPaymentOrders;
case 4: return _closedOrders; case 2:
case 5: return _refundingOrders; return _pendingVerificationOrders;
case 6: return _refundedOrders; // case 3:
case 7: return _cancelledOrders; // return _completedOrders;
default: return _allOrders; case 3:
return _closedOrders;
case 4:
return _refundingOrders;
case 5:
return _refundedOrders;
case 6:
return _cancelledOrders;
default:
return _allOrders;
} }
} }
@ -125,35 +157,35 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
_pendingVerificationOrders = orders; _pendingVerificationOrders = orders;
} }
break; break;
// case 3:
// if (loadMore) {
// _completedOrders.addAll(orders);
// } else {
// _completedOrders = orders;
// }
// break;
case 3: case 3:
if (loadMore) {
_completedOrders.addAll(orders);
} else {
_completedOrders = orders;
}
break;
case 4:
if (loadMore) { if (loadMore) {
_closedOrders.addAll(orders); _closedOrders.addAll(orders);
} else { } else {
_closedOrders = orders; _closedOrders = orders;
} }
break; break;
case 5: case 4:
if (loadMore) { if (loadMore) {
_refundingOrders.addAll(orders); _refundingOrders.addAll(orders);
} else { } else {
_refundingOrders = orders; _refundingOrders = orders;
} }
break; break;
case 6: case 5:
if (loadMore) { if (loadMore) {
_refundedOrders.addAll(orders); _refundedOrders.addAll(orders);
} else { } else {
_refundedOrders = orders; _refundedOrders = orders;
} }
break; break;
case 7: case 6:
if (loadMore) { if (loadMore) {
_cancelledOrders.addAll(orders); _cancelledOrders.addAll(orders);
} else { } else {
@ -167,9 +199,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
// //
void _scrollListener() { void _scrollListener() {
final currentIndex = tabController.index; final currentIndex = tabController.index;
if (scrollController.position.pixels == scrollController.position.maxScrollExtent && if (scrollController.position.pixels == scrollController.position.maxScrollExtent && !_isLoading[currentIndex]! && _hasMoreData[currentIndex]!) {
!_isLoading[currentIndex]! &&
_hasMoreData[currentIndex]!) {
getOrderList(true); getOrderList(true);
} }
} }
@ -179,6 +209,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
if (tabController.index != tabController.previousIndex) { if (tabController.index != tabController.previousIndex) {
// Tab没有数据 // Tab没有数据
final currentOrders = _getCurrentOrderList(); final currentOrders = _getCurrentOrderList();
if (currentOrders.isEmpty) { if (currentOrders.isEmpty) {
getOrderList(false); getOrderList(false);
} }
@ -207,16 +238,17 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
final res = await Http.post(ShopApi.sellerOrderList, data: { final res = await Http.post(ShopApi.sellerOrderList, data: {
'current': _pageNums[currentIndex], // 'current': _pageNums[currentIndex], //
'size': pageSize, 'size': pageSize,
'status': status == '' ? '' : status.toString(), 'orderStatus': status == '' ? '' : status.toString(),
}); });
logger.w(status);
logger.w(res);
if (res['code'] == 200 && res['data'] != null) { if (res['code'] == 200 && res['data'] != null) {
final data = res['data']; final data = res['data'];
final List<Map<String, dynamic>> newOrders = List<Map<String, dynamic>>.from(data['records'] ?? []); final List<Map<String, dynamic>> newOrders = List<Map<String, dynamic>>.from(data['records'] ?? []);
final int total = data['total'] ?? 0; final int total = data['total'] ?? 0;
debugPrint(data.toString(), wrapWidth: 1024);
// Tab的数据 // Tab的数据
_setCurrentOrderList(newOrders, loadMore); _setCurrentOrderList(newOrders, loadMore);
@ -236,7 +268,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
}); });
} }
} catch (e) { } catch (e) {
print('获取订单列表失败: $e'); logger.w('获取订单列表失败: $e');
setState(() { setState(() {
_hasMoreData[currentIndex] = false; _hasMoreData[currentIndex] = false;
}); });
@ -266,11 +298,11 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
switch (statusCode) { switch (statusCode) {
case 0: // case 0: //
return '待付款: '; return '用户待付款: ';
case 1: // case 2: //
return '已付款: '; return '已付款: ';
case 2: // // case 2: //
return '实付款: '; // return '实付款: ';
case 3: // case 3: //
return '订单金额: '; return '订单金额: ';
case 4: // 退 case 4: // 退
@ -310,13 +342,13 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
crossAxisAlignment: WrapCrossAlignment.center, crossAxisAlignment: WrapCrossAlignment.center,
spacing: 5.0, spacing: 5.0,
children: [ children: [
ClipOval( // ClipOval(
child: Image.asset( // child: Image.asset(
'assets/images/avatar/img11.jpg', // 'assets/images/avatar/img11.jpg',
width: 25.0, // width: 25.0,
), // ),
), // ),
Text(order['items'][0]['tenantName'] ?? '商家名称'), Text(order['tenantName'] ?? '商家名称'),
Icon( Icon(
Icons.arrow_forward_ios_rounded, Icons.arrow_forward_ios_rounded,
color: Colors.grey, color: Colors.grey,
@ -325,7 +357,12 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
], ],
), ),
Spacer(), Spacer(),
Text( order['verificationCodeStatus'] == 1
? Text(
'已核销',
style: TextStyle(color: Colors.red),
)
: Text(
_getStatusText(order['status']), _getStatusText(order['status']),
style: TextStyle(color: _getStatusColor(order['status'])), style: TextStyle(color: _getStatusColor(order['status'])),
) )
@ -333,23 +370,25 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
), ),
SizedBox(height: 10), SizedBox(height: 10),
// //
if (order['items'] != null && order['items'].isNotEmpty) Row(
...order['items'].map<Widget>((item) => Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Container(
width: 80.0, width: 80.0,
height: 80.0, height: 80.0,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[200], color: Colors.white,
borderRadius: BorderRadius.circular(4.0), borderRadius: BorderRadius.circular(4.0),
), ),
child: order['items'][0]['pic'] != null && order['items'][0]['pic'].isNotEmpty child: order['pic'] != null && order['pic'].isNotEmpty
? Image.network( ? ClipRRect(
order['items'][0]['pic'], borderRadius: BorderRadius.circular(8.0),
child: Image.network(
order['pic'],
width: 80.0, width: 80.0,
height: 80.0, height: 80.0,
fit: BoxFit.cover, fit: BoxFit.cover,
),
) )
: Icon( : Icon(
Icons.shopping_bag_outlined, Icons.shopping_bag_outlined,
@ -363,7 +402,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
item['productName'] ?? '商品名称', order['productName'] ?? '商品名称',
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14), style: TextStyle(fontSize: 14),
@ -372,12 +411,12 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
Row( Row(
children: [ children: [
Text( Text(
'¥${item['salePrice'] ?? '0'}', '¥${order['salePrice'] ?? '0'}',
style: TextStyle(color: Colors.red, fontSize: 16), style: TextStyle(color: Colors.red, fontSize: 16),
), ),
Spacer(), Spacer(),
Text( Text(
'x${item['quantity'] ?? '1'}', 'x${order['quantity'] ?? '1'}',
style: TextStyle(color: Colors.grey), style: TextStyle(color: Colors.grey),
), ),
], ],
@ -386,13 +425,13 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
), ),
) )
], ],
)).toList(), ),
SizedBox(height: 10), SizedBox(height: 10),
// //
Container( Container(
padding: EdgeInsets.all(5.0), padding: EdgeInsets.all(5.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey[50], color: Colors.white,
borderRadius: BorderRadius.circular(5.0), borderRadius: BorderRadius.circular(5.0),
), ),
child: Row( child: Row(
@ -402,7 +441,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
TextSpan(children: [ TextSpan(children: [
TextSpan(text: _getPaymentText(order['status'])), // TextSpan(text: _getPaymentText(order['status'])), //
TextSpan( TextSpan(
text: '¥${order['totalAmount'] ?? '0'}', text: '¥${order['salePrice'] ?? '0'}',
style: TextStyle(color: Colors.red, fontSize: 16), style: TextStyle(color: Colors.red, fontSize: 16),
), ),
]), ]),
@ -417,16 +456,27 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
), ),
), ),
onTap: () { onTap: () {
Get.toNamed('/sellerOrder/detail', arguments: {'orderId': order['id']}); // logger.e(order);
Get.toNamed('/sellerOrder/detail', arguments: {'orderId': order['orderId']});
}, },
); );
} }
// //
String _getStatusText(dynamic status) { String _getStatusText(dynamic status) {
int statusCode = status is String ? int.tryParse(status) ?? -1 : (status is int ? status : -1);
final match = orderStatusDict.firstWhere(
(item) => item['dictValue'].toString() == statusCode.toString(),
orElse: () => {'dictLabel': '未知状态'},
);
return match['dictLabel'] ?? '未知状态';
}
//
String _getStatusText_old(dynamic status) {
// //
int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0);
switch (statusCode) { switch (statusCode) {
case 0: case 0:
return '待付款'; return '待付款';
@ -479,33 +529,34 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0); int statusCode = status is String ? int.tryParse(status) ?? 0 : (status is int ? status : 0);
switch (statusCode) { switch (statusCode) {
case 0: // case 0: //
return Row( return SizedBox();
mainAxisAlignment: MainAxisAlignment.end, // return Row(
children: [ // mainAxisAlignment: MainAxisAlignment.end,
ElevatedButton( // children: [
onPressed: () => _cancelOrder(orderId), // ElevatedButton(
style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)), // onPressed: () => _cancelOrder(orderId),
child: Text('取消订单'), // style: ButtonStyle(backgroundColor: WidgetStateProperty.all(Colors.white)),
), // child: Text('取消订单'),
SizedBox(width: 10), // ),
ElevatedButton( // SizedBox(width: 10),
onPressed: () => _payOrder(orderId), // ElevatedButton(
style: ButtonStyle( // onPressed: () => _payOrder(orderId),
backgroundColor: WidgetStateProperty.all(Color(0xff07c160)), // style: ButtonStyle(
foregroundColor: WidgetStateProperty.all(Colors.white), // backgroundColor: WidgetStateProperty.all(Color(0xff07c160)),
), // foregroundColor: WidgetStateProperty.all(Colors.white),
child: Text('去支付'), // ),
), // child: Text('用户待付款'),
], // ),
); // ],
case 1: // // );
return Row( case 2: //
mainAxisAlignment: MainAxisAlignment.end,
);
case 2: //
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
); );
// case 2: //
// return Row(
// mainAxisAlignment: MainAxisAlignment.end,
// );
default: default:
return SizedBox.shrink(); return SizedBox.shrink();
} }
@ -515,7 +566,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
void _cancelOrder(String orderId) async { void _cancelOrder(String orderId) async {
try { try {
final res = await Http.post('${ShopApi.cancelGoodsOrder}/$orderId'); final res = await Http.post('${ShopApi.cancelGoodsOrder}/$orderId');
print('取消订单成功-------------->${res}'); logger.w('取消订单成功-------------->$res');
if (res['code'] == 200) { if (res['code'] == 200) {
MyToast().tip( MyToast().tip(
@ -527,7 +578,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
_refreshAllRelatedTabs(); _refreshAllRelatedTabs();
} }
} catch (e) { } catch (e) {
print('取消订单失败-------------->${e}'); logger.w('取消订单失败-------------->$e');
} }
} }
@ -546,9 +597,9 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
} }
} }
void _payOrder(_orderId) { void _payOrder(orderId) {
// pages/index/index // pages/index/index
Wxsdk.openMiniApp(orderId: _orderId); // Wxsdk.openMiniApp(orderId: orderId);
} }
// tab的数据 // tab的数据
@ -560,14 +611,30 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
_hasMoreData[index] = true; _hasMoreData[index] = true;
switch (index) { switch (index) {
case 0: _allOrders = []; break; case 0:
case 1: _pendingPaymentOrders = []; break; _allOrders = [];
case 2: _pendingVerificationOrders = []; break; break;
case 3: _completedOrders = []; break; case 1:
case 4: _closedOrders = []; break; _pendingPaymentOrders = []; //
case 5: _refundingOrders = []; break; break;
case 6: _refundedOrders = []; break; case 2:
case 7: _cancelledOrders = []; break; _pendingVerificationOrders = []; //
break;
// case 3:
// _completedOrders = []; //
// break;
case 3:
_closedOrders = []; //
break;
case 4:
_refundingOrders = []; // 退
break;
case 5:
_refundedOrders = []; // 退
break;
case 6:
_cancelledOrders = []; //
break;
} }
}); });
} }
@ -627,7 +694,9 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
), ),
), ),
), ),
body: TabBarView( body: SafeArea(
bottom: true,
child: TabBarView(
controller: tabController, controller: tabController,
children: List.generate(tabList.length, (index) { children: List.generate(tabList.length, (index) {
return RefreshIndicator( return RefreshIndicator(
@ -638,8 +707,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
behavior: CustomScrollBehavior().copyWith(scrollbars: false), behavior: CustomScrollBehavior().copyWith(scrollbars: false),
child: Container( child: Container(
color: Colors.grey[50], color: Colors.grey[50],
child: Builder( child: Builder(builder: (context) {
builder: (context) {
final currentOrders = _getOrderListByIndex(index); final currentOrders = _getOrderListByIndex(index);
final isLoading = _isLoading[index] ?? false; final isLoading = _isLoading[index] ?? false;
final hasMoreData = _hasMoreData[index] ?? false; final hasMoreData = _hasMoreData[index] ?? false;
@ -658,28 +726,37 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
return _buildOrderItem(currentOrders[itemIndex]); return _buildOrderItem(currentOrders[itemIndex]);
}, },
); );
} }),
),
), ),
), ),
); );
}), }),
), ),
),
); );
} }
// //
List<Map<String, dynamic>> _getOrderListByIndex(int index) { List<Map<String, dynamic>> _getOrderListByIndex(int index) {
switch (index) { switch (index) {
case 0: return _allOrders; case 0:
case 1: return _pendingPaymentOrders; return _allOrders;
case 2: return _pendingVerificationOrders; case 1:
case 3: return _completedOrders; return _pendingPaymentOrders;
case 4: return _closedOrders; case 2:
case 5: return _refundingOrders; return _pendingVerificationOrders;
case 6: return _refundedOrders; // case 3:
case 7: return _cancelledOrders; // return _completedOrders;
default: return _allOrders; case 3:
return _closedOrders;
case 4:
return _refundingOrders;
case 5:
return _refundedOrders;
case 6:
return _cancelledOrders;
default:
return _allOrders;
} }
} }
@ -707,7 +784,7 @@ class _SellerState extends State<SellerOrder> with SingleTickerProviderStateMixi
} }
Widget emptyTip() { Widget emptyTip() {
return Container( return SizedBox(
width: double.infinity, width: double.infinity,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,

View File

@ -1,6 +1,8 @@
//
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/IM/im_service.dart' hide logger; import 'package:loopin/IM/controller/im_user_info_controller.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/components/my_toast.dart'; import 'package:loopin/components/my_toast.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
@ -41,6 +43,9 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
// //
static const double _itemCornerRadius = 8; static const double _itemCornerRadius = 8;
//
final ctl = Get.find<ImUserInfoController>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -269,6 +274,11 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
// //
onFocusBtnClick(user, index) async { onFocusBtnClick(user, index) async {
if (ctl.userID == user['id']) {
MyToast().tip(title: '不能关注自己');
return;
}
//
final vlogerId = user['id']; final vlogerId = user['id'];
final doIFollowVloger = user['doIFollowVloger']; final doIFollowVloger = user['doIFollowVloger'];
print('是否关注此用户------------->$doIFollowVloger'); print('是否关注此用户------------->$doIFollowVloger');
@ -507,6 +517,7 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
), ),
); );
} }
// //
Widget _buildVideoItem(Map<String, dynamic> video) { Widget _buildVideoItem(Map<String, dynamic> video) {
return GestureDetector( return GestureDetector(
@ -608,9 +619,7 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
) )
: null, : null,
), ),
child: video['avatar'] == null || video['avatar'].toString().isEmpty child: video['avatar'] == null || video['avatar'].toString().isEmpty ? const Icon(Icons.person, size: 10, color: Colors.grey) : null,
? const Icon(Icons.person, size: 10, color: Colors.grey)
: null,
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
// //
@ -683,6 +692,7 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
return Container(); return Container();
} }
// Tab // Tab
Widget _buildProductTab() { Widget _buildProductTab() {
if (_productResults.isEmpty && !_isLoading) { if (_productResults.isEmpty && !_isLoading) {
@ -920,7 +930,23 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
), ),
child: Row( child: Row(
children: [ children: [
Container( GestureDetector(
onTap: () async {
logger.w(user);
//
if (ctl.userID.value == user['id']) {
return;
}
//
final vloggerId = user['id'];
final result = await Get.toNamed('/vloger', arguments: {'memberId': vloggerId});
if (result != null) {
setState(() {
user['doIFollowVloger'] = result['followStatus'];
});
}
},
child: Container(
width: 45, width: 45,
height: 45, height: 45,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -935,9 +961,27 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
), ),
child: user['avatar'] == null ? const Icon(Icons.person, color: Colors.grey, size: 20) : null, child: user['avatar'] == null ? const Icon(Icons.person, color: Colors.grey, size: 20) : null,
), ),
),
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
//
if (ctl.userID.value == user['id']) {
return;
}
//
final vloggerId = user['id'];
final result = await Get.toNamed('/vloger', arguments: {'memberId': vloggerId});
if (result != null) {
setState(() {
user['doIFollowVloger'] = result['followStatus'];
});
}
},
child: Column( child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
@ -958,6 +1002,8 @@ class _SearchResultPageState extends State<SearchResultPage> with SingleTickerPr
], ],
), ),
), ),
),
//
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
await onFocusBtnClick(user, index); await onFocusBtnClick(user, index);

View File

@ -603,8 +603,15 @@ class _VideoDetailPageState extends State<VideoDetailPage> {
AnimatedOpacity( AnimatedOpacity(
opacity: position > Duration(milliseconds: 100) ? 0.0 : 1.0, opacity: position > Duration(milliseconds: 100) ? 0.0 : 1.0,
duration: Duration(milliseconds: 50), duration: Duration(milliseconds: 50),
child: Image.network( // child: Image.network(
videoData['firstFrameImg'] ?? 'https://wuzhongjie.com.cn/download/logo.png', // videoData['firstFrameImg'] ?? 'https://wuzhongjie.com.cn/download/logo.png',
// fit: isHorizontal ? BoxFit.contain : BoxFit.cover,
// width: double.infinity,
// height: double.infinity,
// ),
child: NetworkOrAssetImage(
imageUrl: videoData['firstFrameImg'] ?? '',
placeholderAsset: 'assets/images/bk.jpg',
fit: isHorizontal ? BoxFit.contain : BoxFit.cover, fit: isHorizontal ? BoxFit.contain : BoxFit.cover,
width: double.infinity, width: double.infinity,
height: double.infinity, height: double.infinity,

View File

@ -8,7 +8,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:loopin/utils/common.dart';
import 'package:loopin/IM/controller/chat_controller.dart'; import 'package:loopin/IM/controller/chat_controller.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_core.dart'; import 'package:loopin/IM/im_core.dart';
@ -21,6 +20,7 @@ import 'package:loopin/models/conversation_type.dart';
import 'package:loopin/models/share_type.dart'; import 'package:loopin/models/share_type.dart';
import 'package:loopin/models/summary_type.dart'; import 'package:loopin/models/summary_type.dart';
import 'package:loopin/service/http.dart'; import 'package:loopin/service/http.dart';
import 'package:loopin/utils/common.dart';
import 'package:loopin/utils/download_video.dart'; import 'package:loopin/utils/download_video.dart';
import 'package:loopin/utils/permissions.dart'; import 'package:loopin/utils/permissions.dart';
import 'package:loopin/utils/wxsdk.dart'; import 'package:loopin/utils/wxsdk.dart';
@ -298,8 +298,8 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
final comment = commentList[index]; final comment = commentList[index];
final hasReplies = comment['childCount'] > 0; final hasReplies = comment['childCount'] > 0;
final isExpanded = expandedReplies[comment['id']] == true; final isExpanded = expandedReplies[comment['commentId']] == true;
final replies = replyData[comment['id']] ?? []; final replies = replyData[comment['commentId']] ?? [];
return Column( return Column(
children: [ children: [
@ -328,9 +328,12 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
), ),
SizedBox(width: 20.0), SizedBox(width: 20.0),
GestureDetector( GestureDetector(
//
onTap: () { onTap: () {
setState(() { setState(() {
replyingCommentId = comment['id']; logger.e(comment);
// replyingCommentId = comment['id']; //null
replyingCommentId = comment['commentId'];
replyingCommentUser = comment['commentUserNickname'] ?? '未知用户'; replyingCommentUser = comment['commentUserNickname'] ?? '未知用户';
}); });
}, },
@ -357,11 +360,13 @@ class _CommentBottomSheetState extends State<CommentBottomSheet> {
if (hasReplies) if (hasReplies)
GestureDetector( GestureDetector(
onTap: () { onTap: () {
logger.e(comment);
setState(() { setState(() {
expandedReplies[comment['id']] = !isExpanded; logger.e(replyData);
if (expandedReplies[comment['id']] == true && expandedReplies[comment['commentId']] = !isExpanded;
(replyData[comment['id']] == null || replyData[comment['id']]!.isEmpty)) { if (expandedReplies[comment['commentId']] == true &&
fetchReplies(comment['id'], false); (replyData[comment['commentId']] == null || replyData[comment['commentId']]!.isEmpty)) {
fetchReplies(comment['commentId'], false);
} }
}); });
}, },
@ -570,7 +575,7 @@ class _RecommendModuleState extends State<RecommendModule> {
final List<StreamSubscription> subscriptions = []; final List<StreamSubscription> subscriptions = [];
// slider当前阈值 // slider当前阈值
double sliderValue = 0.0; double sliderValue = 0.1;
bool sliderDraging = false; bool sliderDraging = false;
late Duration position = Duration.zero; // late Duration position = Duration.zero; //
late Duration duration = Duration.zero; // late Duration duration = Duration.zero; //
@ -734,6 +739,7 @@ class _RecommendModuleState extends State<RecommendModule> {
final resCode = res['code']; final resCode = res['code'];
if (resCode == 200) { if (resCode == 200) {
item['doILikeThisVlog'] = !item['doILikeThisVlog']; item['doILikeThisVlog'] = !item['doILikeThisVlog'];
setState(() {});
} }
} catch (e) { } catch (e) {
logger.i('点击取消喜欢按钮报错: $e'); logger.i('点击取消喜欢按钮报错: $e');
@ -747,6 +753,7 @@ class _RecommendModuleState extends State<RecommendModule> {
final resCode = res['code']; final resCode = res['code'];
if (resCode == 200) { if (resCode == 200) {
item['doILikeThisVlog'] = !item['doILikeThisVlog']; item['doILikeThisVlog'] = !item['doILikeThisVlog'];
setState(() {});
} }
logger.i('点赞返回信息----------->: $res'); logger.i('点赞返回信息----------->: $res');
} catch (e) { } catch (e) {
@ -770,7 +777,8 @@ class _RecommendModuleState extends State<RecommendModule> {
), ),
context: context, context: context,
builder: (context) { builder: (context) {
return CommentBottomSheet( return SafeArea(
child: CommentBottomSheet(
videoId: videoId, videoId: videoId,
onCommentCountChanged: (newCount) { onCommentCountChanged: (newCount) {
// //
@ -779,7 +787,9 @@ class _RecommendModuleState extends State<RecommendModule> {
videoList[index]['commentsCounts'] = newCount; videoList[index]['commentsCounts'] = newCount;
} }
}); });
}); },
),
);
}, },
); );
} }
@ -1132,9 +1142,14 @@ class _RecommendModuleState extends State<RecommendModule> {
width: 48.0, width: 48.0,
child: GestureDetector( child: GestureDetector(
onTap: () async { onTap: () async {
//
final vloggerId = videoList[videoModuleController.videoPlayIndex.value]['memberId'];
final myID = Get.find<ImUserInfoController>().userID.value;
if (myID == vloggerId) {
return;
}
player.pause(); player.pause();
// Vloger // Vloger
final vloggerId = videoList[videoModuleController.videoPlayIndex.value]['memberId'];
final result = await Get.toNamed('/vloger', arguments: {'memberId': vloggerId}); final result = await Get.toNamed('/vloger', arguments: {'memberId': vloggerId});
if (result != null) { if (result != null) {
// //
@ -1184,6 +1199,12 @@ class _RecommendModuleState extends State<RecommendModule> {
return; return;
} }
final vlogerId = videoList[index]['memberId']; final vlogerId = videoList[index]['memberId'];
//
final myID = Get.find<ImUserInfoController>().userID.value;
if (myID == vlogerId) {
MyToast().tip(title: '不能关注自己');
return;
}
final doIFollowVloger = videoList[index]['doIFollowVloger']; final doIFollowVloger = videoList[index]['doIFollowVloger'];
// //
if (doIFollowVloger == false) { if (doIFollowVloger == false) {

View File

@ -10,7 +10,7 @@ import 'package:loopin/pages/chat/chat_no_friend.dart';
import 'package:loopin/pages/chat/notify/interaction.dart'; import 'package:loopin/pages/chat/notify/interaction.dart';
import 'package:loopin/pages/chat/notify/newFoucs.dart'; import 'package:loopin/pages/chat/notify/newFoucs.dart';
import 'package:loopin/pages/chat/notify/noFriend.dart'; import 'package:loopin/pages/chat/notify/noFriend.dart';
import 'package:loopin/pages/chat/notify/system.dart'; import 'package:loopin/pages/chat/notify/orderNotify.dart';
import 'package:loopin/pages/groupChat/groupList.dart'; import 'package:loopin/pages/groupChat/groupList.dart';
import 'package:loopin/pages/groupChat/index.dart'; import 'package:loopin/pages/groupChat/index.dart';
import 'package:loopin/pages/my/all_function.dart'; import 'package:loopin/pages/my/all_function.dart';
@ -27,7 +27,7 @@ import 'package:loopin/pages/my/vloger.dart';
import 'package:loopin/pages/order/my_order.dart'; import 'package:loopin/pages/order/my_order.dart';
import 'package:loopin/pages/order/seller_order.dart'; import 'package:loopin/pages/order/seller_order.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';
import 'package:loopin/pages/video/report.dart'; import 'package:loopin/pages/video/report.dart';
@ -37,8 +37,6 @@ import '../pages/auth/login.dart';
// //
import '../pages/goods/detail.dart'; import '../pages/goods/detail.dart';
import '../pages/order/detail.dart'; import '../pages/order/detail.dart';
//
import '../pages/order/index.dart';
import '../pages/order/seller_detail.dart'; import '../pages/order/seller_detail.dart';
// //
import '../utils/common.dart'; import '../utils/common.dart';
@ -49,7 +47,7 @@ final Map<String, Widget> routes = {
'/goods': const Goods(), '/goods': const Goods(),
// '/chatNoFriend': const ChatNoFriend(), // '/chatNoFriend': const ChatNoFriend(),
// '/chatGroup': const ChatGroup(), // '/chatGroup': const ChatGroup(),
'/order': const Order(), // '/order': const Order(),
'/sellerOrder': const SellerOrder(), '/sellerOrder': const SellerOrder(),
'/sellerOrder/detail': const SellerOrderDetail(), '/sellerOrder/detail': const SellerOrderDetail(),
'/myOrder': const MyOrder(), '/myOrder': const MyOrder(),
@ -73,9 +71,11 @@ final Map<String, Widget> routes = {
// //
'/noFriend': const Nofriend(), '/noFriend': const Nofriend(),
'/newFoucs': const Newfoucs(), '/newFocus': const Newfoucs(),
'/system': const System(), // '/system': const System(),
'/interaction': const Interaction(), '/interaction': const Interaction(),
'/order': const OrderNotify(),
// //
'/fans': const Fans(), '/fans': const Fans(),
'/flow': const Flowing(), '/flow': const Flowing(),

View File

@ -12,10 +12,10 @@ class HttpConfig {
// baseUrl: 'http://111.62.22.190:8080', // baseUrl: 'http://111.62.22.190:8080',
// baseUrl: 'http://cjh.wuzhongjie.com.cn', // baseUrl: 'http://cjh.wuzhongjie.com.cn',
// baseUrl: 'http://82.156.121.2:8880', // baseUrl: 'http://82.156.121.2:8880',
// baseUrl: 'https://www.wuzhongjie.com.cn/prod-api', baseUrl: 'https://www.wuzhongjie.com.cn/prod-api',
// baseUrl: 'http://192.168.1.65:8880', // baseUrl: 'http://192.168.1.65:8880',
baseUrl: 'http://192.168.1.22:8080', // baseUrl: 'http://192.168.1.22:8080',
// connectTimeout: Duration(seconds: 30), // connectTimeout: Duration(seconds: 30),
// receiveTimeout: Duration(seconds: 30), // receiveTimeout: Duration(seconds: 30),
@ -89,9 +89,11 @@ class HttpConfig {
// //
if (data['code'] != 200) { if (data['code'] != 200) {
Get.snackbar( Get.snackbar(
'错误码${data['code']}', // '错误码${data['code']}',
'${response.requestOptions.uri}\n${response.requestOptions.data}\n${data['msg']}' ?? '请求失败', '提示!',
duration: Duration(minutes: 1), // '${response.requestOptions.uri}\n${response.requestOptions.data}\n${data['msg']}' ?? '请求失败',
'${data['msg']}' ?? '请求失败',
duration: Duration(seconds: 5),
backgroundColor: Colors.red.withAlpha(230), backgroundColor: Colors.red.withAlpha(230),
colorText: Colors.white, colorText: Colors.white,
icon: const Icon(Icons.error_outline, color: Colors.white), icon: const Icon(Icons.error_outline, color: Colors.white),

View File

@ -0,0 +1,56 @@
import 'dart:async';
import 'package:app_links/app_links.dart';
import 'package:flutter/material.dart';
import 'package:loopin/IM/im_friend_listeners.dart';
/// schem启动参数 wuzhongjie://open?xxx=xxx
class DeepLinkListener extends StatefulWidget {
final Widget child;
const DeepLinkListener({required this.child, super.key});
@override
State<DeepLinkListener> createState() => _DeepLinkListenerState();
}
class _DeepLinkListenerState extends State<DeepLinkListener> {
final AppLinks _appLinks = AppLinks();
StreamSubscription? _sub;
@override
void initState() {
super.initState();
_handleLinks();
}
///
void _handleLinks() {
_sub = _appLinks.uriLinkStream.listen((Uri? uri) {
if (uri != null) {
_parseAppParameter(uri);
}
}, onError: (err) {
logger.e('启动参数监听报错: $err');
});
}
//
void _parseAppParameter(Uri uri) {
final appParameter = uri.queryParameters['appParameter'];
if (appParameter != null) {
logger.e('收到启动参数 appParameter: $appParameter');
}
}
@override
void dispose() {
_sub?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}

View File

@ -1,9 +1,11 @@
/// ///
library; library;
import 'dart:io';
import 'dart:async'; import 'dart:async';
import 'package:path_provider/path_provider.dart'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
// //
class DownloadManager { class DownloadManager {

View File

@ -186,8 +186,7 @@ String _parseCustomMessage(V2TimMessage? msg) {
// final sum = jsonDecode(msg.cloudCustomData!); // final sum = jsonDecode(msg.cloudCustomData!);
final elment = msg.customElem; // final elment = msg.customElem; //
// logger.w('解析自定义消息:$sum,自定义属性:${msg.cloudCustomData}'); // logger.w('解析自定义消息:$sum,自定义属性:${msg.cloudCustomData}');
logger.w(sum); logger.w('解析elementaciton=$sum,${elment?.desc ?? 'summary_error'}');
logger.w('解析element${elment?.desc ?? 'summary_error'}');
try { try {
switch (sum) { switch (sum) {
case SummaryType.hongbao: case SummaryType.hongbao:
@ -275,22 +274,28 @@ String _parseCustomMessage(V2TimMessage? msg) {
/// [comment] /// [comment]
return elment!.desc!; return elment!.desc!;
case NotifyMessageTypeConstants.orderRecharge: case NotifyMessageTypeConstants.orderRecharge:
// //
/// [orderID] /// [orderID]
/// [amount] /// [amount]
/// [totalAmount] /// [totalAmount]
return elment!.desc!; return elment!.desc!;
case NotifyMessageTypeConstants.orderPay: case NotifyMessageTypeConstants.orderPay:
// // --
/// [orderID] /// [orderID]
/// [amount] /// [amount]
/// [name] /// [name]
/// [describe] /// [describe]
/// [price] /// [price]
/// [pic] /// [pic]
return elment!.desc!;
case NotifyMessageTypeConstants.orderWithDraw:
// /-----/
/// [status] 0= 1=
return elment!.desc!; return elment!.desc!;
case NotifyMessageTypeConstants.orderRefund: case NotifyMessageTypeConstants.orderRefund:
// 退 // 退
/// 退[status] 0= 1=
/// [orderID] /// [orderID]
/// [amount] /// [amount]
/// [name] /// [name]

View File

@ -1,12 +1,12 @@
// //
class QrTypeCode { class QrTypeCode {
static const String hxm = 'hxm-'; static const String hxm = 'HXM-';
static const String hym = 'hym-'; static const String hym = 'hym-';
static const String tgm = 'tgm-'; static const String tgm = 'tgm-';
} }
enum ScanCodeType { enum ScanCodeType {
verification('hxm'), // verification('HXM'), //
friend('hym'), // friend('hym'), //
promotion('tgm'); // 广 promotion('tgm'); // 广

View File

@ -0,0 +1,19 @@
import 'package:flutter/services.dart';
import 'package:loopin/IM/im_friend_listeners.dart';
class WechatBusinessView {
static const MethodChannel _channel = MethodChannel('wechat_business_view'); // mainactivity.ktappdelegate.swift
///
static Future<bool> openBusinessView({required String packageInfo}) async {
try {
final result = await _channel.invokeMethod('openBusinessView', {
'package': packageInfo,
});
return result == true;
} on PlatformException catch (e) {
logger.w('调用失败: ${e.message}');
return false;
}
}
}

View File

@ -43,6 +43,7 @@ class Wxsdk {
"clientId": "428a8310cd442757ae699df5d894f051", "clientId": "428a8310cd442757ae699df5d894f051",
"grantType": "social" "grantType": "social"
}); });
logger.e(serverRes);
final info = Get.find<ImUserInfoController>(); final info = Get.find<ImUserInfoController>();
info.customInfo['openId'] = serverRes['data']['openId']; info.customInfo['openId'] = serverRes['data']['openId'];
info.updateOpenId(); info.updateOpenId();
@ -63,6 +64,8 @@ class Wxsdk {
final ctl = Get.find<BalanceController>(); final ctl = Get.find<BalanceController>();
// //
ctl.getData(reset: true); ctl.getData(reset: true);
//
ctl.getAccount();
} else { } else {
if (res.errCode == -2) { if (res.errCode == -2) {
logger.w("用户取消支付"); logger.w("用户取消支付");
@ -156,7 +159,7 @@ class Wxsdk {
var miniProgram = MiniProgram( var miniProgram = MiniProgram(
username: "gh_2ffaecc5508e", // ID username: "gh_2ffaecc5508e", // ID
path: "/pages/index/index?id=$orderId", // path: "/pages/index/index?id=$orderId", //
miniProgramType: WXMiniProgramType.preview, miniProgramType: WXMiniProgramType.preview, // release
); );
Fluwx().open(target: miniProgram); Fluwx().open(target: miniProgram);
} }

View File

@ -17,6 +17,38 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.3" version: "2.0.3"
app_links:
dependency: "direct main"
description:
name: app_links
sha256: "5f88447519add627fe1cbcab4fd1da3d4fed15b9baf29f28b22535c95ecee3e8"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.4.1"
app_links_linux:
dependency: transitive
description:
name: app_links_linux
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
app_links_platform_interface:
dependency: transitive
description:
name: app_links_platform_interface
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
app_links_web:
dependency: transitive
description:
name: app_links_web
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.4"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -529,10 +561,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: fluwx name: fluwx
sha256: "9db31d54043363c9c8283b5f0bc4df982edb45ba19d800df9d7de96a205371ae" sha256: "9bac596b34f37b08fd4cae0d0e1e205d0dc395dbec4200c588eed9b4b446f69f"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.7.0" version: "5.7.2"
form_builder_validators: form_builder_validators:
dependency: "direct main" dependency: "direct main"
description: description:
@ -605,6 +637,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
gtk:
dependency: transitive
description:
name: gtk
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
html: html:
dependency: transitive dependency: transitive
description: description:
@ -1682,6 +1722,38 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
webview_flutter:
dependency: "direct main"
description:
name: webview_flutter
sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.13.0"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: "9a25f6b4313978ba1c2cda03a242eea17848174912cfb4d2d8ee84a556f248e3"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.10.1"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.14.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: fb46db8216131a3e55bcf44040ca808423539bc6732e7ed34fb6d8044e3d512f
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.23.0"
wechat_assets_picker: wechat_assets_picker:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -85,7 +85,8 @@ dependencies:
city_pickers: ^1.3.0 city_pickers: ^1.3.0
bottom_picker: ^3.2.1 bottom_picker: ^3.2.1
fluwx: ^5.7.0 #微信sdk # fluwx: ^5.7.0 #微信sdk
fluwx: ^5.7.2 #微信sdk
flutter_image_compress: ^2.4.0 #处理图片 flutter_image_compress: ^2.4.0 #处理图片
video_thumbnail: ^0.5.6 #视频首帧截取 video_thumbnail: ^0.5.6 #视频首帧截取
record: ^6.0.0 #音频 record: ^6.0.0 #音频
@ -100,6 +101,8 @@ dependencies:
image_cropper: ^9.1.0 image_cropper: ^9.1.0
pretty_qr_code: ^3.5.0 pretty_qr_code: ^3.5.0
lottie: ^3.3.1 lottie: ^3.3.1
webview_flutter: ^4.13.0
app_links: ^6.4.1
dev_dependencies: dev_dependencies:
flutter_launcher_icons: ^0.13.1 # 使用最新版本 flutter_launcher_icons: ^0.13.1 # 使用最新版本
@ -188,21 +191,23 @@ flutter_launcher_icons:
#dart run flutter_native_splash:create #dart run flutter_native_splash:create
#flutter pub run flutter_native_splash:create #dart run flutter_native_splash:remove
flutter_native_splash: flutter_native_splash:
ios: true ios: true
android: true android: true
color: "#000000" color: "#ffffff"
image: assets/images/logo/start.png # image: assets/images/logo/start.png
fullscreen: true fullscreen: true
# background_image: assets/images/logo/start1.png background_image: assets/images/logo/start.png
# color_dark: "#000000" # color_dark: "#ffffff"
# image_dark: assets/images/logo/start1.png # image_dark: assets/images/logo/start.png
android_12: android_12:
image: assets/images/logo/logo.png image: assets/images/logo/androidlogo.png
icon_background_color: "#000000" icon_background_color: "#000000"
# image_dark: assets/images/logo/start.png # background_image: assets/images/logo/start.png
# icon_background_color_dark: "#000000"
image_dark: assets/images/logo/androidlogo.png
icon_background_color_dark: "#000000"
web: false web: false