修改举报和UI
This commit is contained in:
@@ -103,7 +103,7 @@
|
|||||||
if (!_actionButton) {
|
if (!_actionButton) {
|
||||||
_actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
_actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
_actionButton.titleLabel.font = [UIFont systemFontOfSize:13];
|
_actionButton.titleLabel.font = [UIFont systemFontOfSize:13];
|
||||||
[_actionButton setTitleColor:[UIColor secondaryLabelColor]
|
[_actionButton setTitleColor:[UIColor whiteColor]
|
||||||
forState:UIControlStateNormal];
|
forState:UIControlStateNormal];
|
||||||
_actionButton.tintColor = [UIColor secondaryLabelColor];
|
_actionButton.tintColor = [UIColor secondaryLabelColor];
|
||||||
|
|
||||||
|
|||||||
@@ -213,7 +213,7 @@
|
|||||||
_replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
_replyButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
_replyButton.titleLabel.font = [UIFont systemFontOfSize:11];
|
_replyButton.titleLabel.font = [UIFont systemFontOfSize:11];
|
||||||
[_replyButton setTitle:@"回复" forState:UIControlStateNormal];
|
[_replyButton setTitle:@"回复" forState:UIControlStateNormal];
|
||||||
[_replyButton setTitleColor:[UIColor secondaryLabelColor] forState:UIControlStateNormal];
|
[_replyButton setTitleColor:[UIColor colorWithHex:0x9F9F9F] forState:UIControlStateNormal];
|
||||||
[_replyButton addTarget:self
|
[_replyButton addTarget:self
|
||||||
action:@selector(replyButtonTapped)
|
action:@selector(replyButtonTapped)
|
||||||
forControlEvents:UIControlEventTouchUpInside];
|
forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "AIReportVC.h"
|
#import "AIReportVC.h"
|
||||||
|
#import "AiVM.h"
|
||||||
|
|
||||||
#pragma mark - AIReportOptionCell
|
#pragma mark - AIReportOptionCell
|
||||||
|
|
||||||
@@ -116,6 +117,8 @@
|
|||||||
/// 提交按钮
|
/// 提交按钮
|
||||||
@property (nonatomic, strong) UIButton *submitButton;
|
@property (nonatomic, strong) UIButton *submitButton;
|
||||||
|
|
||||||
|
@property (nonatomic, strong) AiVM *viewModel;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AIReportVC
|
@implementation AIReportVC
|
||||||
@@ -134,6 +137,8 @@
|
|||||||
[self setupUI];
|
[self setupUI];
|
||||||
/// 3:绑定事件
|
/// 3:绑定事件
|
||||||
[self bindActions];
|
[self bindActions];
|
||||||
|
/// 4:其他(通知/键盘等)
|
||||||
|
[self bindKeyboardNotifications];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - 1:初始化数据
|
#pragma mark - 1:初始化数据
|
||||||
@@ -286,6 +291,59 @@
|
|||||||
[self.view endEditing:YES];
|
[self.view endEditing:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - 4:键盘处理
|
||||||
|
|
||||||
|
- (void)bindKeyboardNotifications {
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(handleKeyboardWillChange:)
|
||||||
|
name:UIKeyboardWillChangeFrameNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(handleKeyboardWillHide:)
|
||||||
|
name:UIKeyboardWillHideNotification
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleKeyboardWillChange:(NSNotification *)notification {
|
||||||
|
NSDictionary *userInfo = notification.userInfo ?: @{};
|
||||||
|
CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||||
|
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||||
|
NSInteger curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||||
|
|
||||||
|
CGRect endFrameInView = [self.view convertRect:endFrame fromView:nil];
|
||||||
|
CGFloat keyboardHeight = MAX(0, CGRectGetMaxY(self.view.bounds) - CGRectGetMinY(endFrameInView));
|
||||||
|
|
||||||
|
UIEdgeInsets inset = self.scrollView.contentInset;
|
||||||
|
inset.bottom = keyboardHeight;
|
||||||
|
|
||||||
|
UIViewAnimationOptions options = (UIViewAnimationOptions)(curve << 16);
|
||||||
|
[UIView animateWithDuration:duration delay:0 options:options animations:^{
|
||||||
|
self.scrollView.contentInset = inset;
|
||||||
|
self.scrollView.scrollIndicatorInsets = inset;
|
||||||
|
if ([self.descriptionTextView isFirstResponder]) {
|
||||||
|
CGRect rect = [self.descriptionTextView convertRect:self.descriptionTextView.bounds toView:self.scrollView];
|
||||||
|
rect = CGRectInset(rect, 0, -12);
|
||||||
|
[self.scrollView scrollRectToVisible:rect animated:NO];
|
||||||
|
}
|
||||||
|
} completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)handleKeyboardWillHide:(NSNotification *)notification {
|
||||||
|
NSDictionary *userInfo = notification.userInfo ?: @{};
|
||||||
|
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||||
|
NSInteger curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
||||||
|
UIViewAnimationOptions options = (UIViewAnimationOptions)(curve << 16);
|
||||||
|
|
||||||
|
[UIView animateWithDuration:duration delay:0 options:options animations:^{
|
||||||
|
self.scrollView.contentInset = UIEdgeInsetsZero;
|
||||||
|
self.scrollView.scrollIndicatorInsets = UIEdgeInsetsZero;
|
||||||
|
} completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - UITableViewDataSource
|
#pragma mark - UITableViewDataSource
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
@@ -351,6 +409,11 @@
|
|||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
|
|
||||||
- (void)submitButtonTapped {
|
- (void)submitButtonTapped {
|
||||||
|
if (self.personaId <= 0) {
|
||||||
|
[KBHUD showError:KBLocalized(@"Invalid parameter")];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (self.selectedReasonIndexes.count == 0) {
|
if (self.selectedReasonIndexes.count == 0) {
|
||||||
[KBHUD showError:KBLocalized(@"Please select at least one report reason")];
|
[KBHUD showError:KBLocalized(@"Please select at least one report reason")];
|
||||||
return;
|
return;
|
||||||
@@ -373,19 +436,53 @@
|
|||||||
[selectedContents addObject:self.contentOptions[index.integerValue]];
|
[selectedContents addObject:self.contentOptions[index.integerValue]];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *description = self.descriptionTextView.text ?: @"";
|
NSString *reportDesc = [self.descriptionTextView.text ?: @"" stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
|
||||||
NSLog(@"[AIReportVC] 举报人设 ID: %ld", (long)self.personaId);
|
NSLog(@"[AIReportVC] 举报人设 ID: %ld", (long)self.personaId);
|
||||||
NSLog(@"[AIReportVC] 举报原因: %@", selectedReasons);
|
NSLog(@"[AIReportVC] 举报原因: %@", selectedReasons);
|
||||||
NSLog(@"[AIReportVC] 内容类型: %@", selectedContents);
|
NSLog(@"[AIReportVC] 内容类型: %@", selectedContents);
|
||||||
NSLog(@"[AIReportVC] 描述: %@", description);
|
NSLog(@"[AIReportVC] 描述: %@", reportDesc);
|
||||||
|
|
||||||
// TODO: 调用举报接口
|
// 组装举报类型(从上到下 1-12:举报原因 1-9,内容类型 10-12)
|
||||||
[KBHUD showSuccess:KBLocalized(@"Report submitted")];
|
NSMutableArray<NSNumber *> *reportTypes = [NSMutableArray array];
|
||||||
|
NSArray<NSNumber *> *sortedReasonIndexes = [[self.selectedReasonIndexes allObjects]
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES]]];
|
||||||
[self.navigationController popViewControllerAnimated:YES];
|
for (NSNumber *index in sortedReasonIndexes) {
|
||||||
});
|
NSInteger type = index.integerValue + 1;
|
||||||
|
if (type > 0) {
|
||||||
|
[reportTypes addObject:@(type)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSArray<NSNumber *> *sortedContentIndexes = [[self.selectedContentIndexes allObjects]
|
||||||
|
sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES]]];
|
||||||
|
for (NSNumber *index in sortedContentIndexes) {
|
||||||
|
NSInteger type = self.reportReasons.count + index.integerValue + 1;
|
||||||
|
if (type > 0) {
|
||||||
|
[reportTypes addObject:@(type)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[KBHUD show];
|
||||||
|
__weak typeof(self) weakSelf = self;
|
||||||
|
[self.viewModel reportCompanionWithCompanionId:self.personaId
|
||||||
|
reportTypes:reportTypes
|
||||||
|
reportDesc:reportDesc
|
||||||
|
chatContext:nil
|
||||||
|
evidenceImageUrl:nil
|
||||||
|
completion:^(BOOL success, NSError * _Nullable error) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[KBHUD dismiss];
|
||||||
|
if (!success) {
|
||||||
|
NSString *msg = error.localizedDescription ?: KBLocalized(@"Network error");
|
||||||
|
[KBHUD showError:msg];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[KBHUD showSuccess:KBLocalized(@"Report submitted")];
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
|
[weakSelf.navigationController popViewControllerAnimated:YES];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Lazy Load
|
#pragma mark - Lazy Load
|
||||||
@@ -395,6 +492,7 @@
|
|||||||
_scrollView = [[UIScrollView alloc] init];
|
_scrollView = [[UIScrollView alloc] init];
|
||||||
_scrollView.showsVerticalScrollIndicator = NO;
|
_scrollView.showsVerticalScrollIndicator = NO;
|
||||||
_scrollView.alwaysBounceVertical = YES;
|
_scrollView.alwaysBounceVertical = YES;
|
||||||
|
_scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
|
||||||
}
|
}
|
||||||
return _scrollView;
|
return _scrollView;
|
||||||
}
|
}
|
||||||
@@ -536,4 +634,11 @@
|
|||||||
return _submitButton;
|
return _submitButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (AiVM *)viewModel {
|
||||||
|
if (!_viewModel) {
|
||||||
|
_viewModel = [[AiVM alloc] init];
|
||||||
|
}
|
||||||
|
return _viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -173,6 +173,22 @@ typedef void (^AiVMSpeechTranscribeCompletion)(KBAiSpeechTranscribeResponse *_Nu
|
|||||||
- (void)fetchCompanionDetailWithCompanionId:(NSInteger)companionId
|
- (void)fetchCompanionDetailWithCompanionId:(NSInteger)companionId
|
||||||
completion:(void(^)(KBAICompanionDetailModel * _Nullable detail, NSError * _Nullable error))completion;
|
completion:(void(^)(KBAICompanionDetailModel * _Nullable detail, NSError * _Nullable error))completion;
|
||||||
|
|
||||||
|
#pragma mark - 举报接口
|
||||||
|
|
||||||
|
/// 举报 AI 角色
|
||||||
|
/// @param companionId AI 角色 ID
|
||||||
|
/// @param reportTypes 举报类型数组(按界面从上到下 1-12)
|
||||||
|
/// @param reportDesc 详细描述
|
||||||
|
/// @param chatContext 聊天上下文快照 JSON 字符串
|
||||||
|
/// @param evidenceImageUrl 图片证据 URL
|
||||||
|
/// @param completion 完成回调
|
||||||
|
- (void)reportCompanionWithCompanionId:(NSInteger)companionId
|
||||||
|
reportTypes:(NSArray<NSNumber *> *)reportTypes
|
||||||
|
reportDesc:(nullable NSString *)reportDesc
|
||||||
|
chatContext:(nullable NSString *)chatContext
|
||||||
|
evidenceImageUrl:(nullable NSString *)evidenceImageUrl
|
||||||
|
completion:(void(^)(BOOL success, NSError * _Nullable error))completion;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|||||||
@@ -808,4 +808,100 @@ autoShowBusinessError:NO
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - 举报接口
|
||||||
|
|
||||||
|
- (void)reportCompanionWithCompanionId:(NSInteger)companionId
|
||||||
|
reportTypes:(NSArray<NSNumber *> *)reportTypes
|
||||||
|
reportDesc:(nullable NSString *)reportDesc
|
||||||
|
chatContext:(nullable NSString *)chatContext
|
||||||
|
evidenceImageUrl:(nullable NSString *)evidenceImageUrl
|
||||||
|
completion:(void (^)(BOOL, NSError * _Nullable))completion {
|
||||||
|
if (companionId <= 0) {
|
||||||
|
NSError *error = [NSError errorWithDomain:@"AiVM"
|
||||||
|
code:-1
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"invalid companionId"}];
|
||||||
|
if (completion) {
|
||||||
|
completion(NO, error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableArray<NSNumber *> *typeList = [NSMutableArray array];
|
||||||
|
for (id item in reportTypes) {
|
||||||
|
if ([item isKindOfClass:[NSNumber class]]) {
|
||||||
|
[typeList addObject:(NSNumber *)item];
|
||||||
|
} else if ([item isKindOfClass:[NSString class]]) {
|
||||||
|
NSInteger value = [(NSString *)item integerValue];
|
||||||
|
[typeList addObject:@(value)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeList.count == 0) {
|
||||||
|
NSError *error = [NSError errorWithDomain:@"AiVM"
|
||||||
|
code:-1
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"reportTypes is empty"}];
|
||||||
|
if (completion) {
|
||||||
|
completion(NO, error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||||
|
params[@"companionId"] = @(companionId);
|
||||||
|
params[@"reportTypes"] = [typeList copy];
|
||||||
|
if (reportDesc.length > 0) {
|
||||||
|
params[@"reportDesc"] = reportDesc;
|
||||||
|
}
|
||||||
|
if (chatContext.length > 0) {
|
||||||
|
params[@"chatContext"] = chatContext;
|
||||||
|
}
|
||||||
|
if (evidenceImageUrl.length > 0) {
|
||||||
|
params[@"evidenceImageUrl"] = evidenceImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"[AiVM] /ai-companion/report request: %@", params);
|
||||||
|
[[KBNetworkManager shared]
|
||||||
|
POST:@"/ai-companion/report"
|
||||||
|
jsonBody:[params copy]
|
||||||
|
headers:nil
|
||||||
|
autoShowBusinessError:NO
|
||||||
|
completion:^(NSDictionary *_Nullable json,
|
||||||
|
NSURLResponse *_Nullable response,
|
||||||
|
NSError *_Nullable error) {
|
||||||
|
if (error) {
|
||||||
|
NSLog(@"[AiVM] /ai-companion/report failed: %@", error.localizedDescription ?: @"");
|
||||||
|
if (completion) {
|
||||||
|
completion(NO, error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"[AiVM] /ai-companion/report response: %@", json);
|
||||||
|
if (![json isKindOfClass:[NSDictionary class]]) {
|
||||||
|
NSError *parseError = [NSError errorWithDomain:@"AiVM"
|
||||||
|
code:-1
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"数据格式错误"}];
|
||||||
|
if (completion) {
|
||||||
|
completion(NO, parseError);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSInteger code = [json[@"code"] integerValue];
|
||||||
|
if (code != 0) {
|
||||||
|
NSString *message = json[@"message"] ?: @"请求失败";
|
||||||
|
NSError *bizError = [NSError errorWithDomain:@"AiVM"
|
||||||
|
code:code
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : message}];
|
||||||
|
if (completion) {
|
||||||
|
completion(NO, bizError);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completion) {
|
||||||
|
completion(YES, nil);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Reference in New Issue
Block a user