diff --git a/Visual_Novel_iOS.xcodeproj/project.pbxproj b/Visual_Novel_iOS.xcodeproj/project.pbxproj
index 252dc5c..352997a 100644
--- a/Visual_Novel_iOS.xcodeproj/project.pbxproj
+++ b/Visual_Novel_iOS.xcodeproj/project.pbxproj
@@ -437,6 +437,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = 6GS5RC7C89;
@@ -460,8 +461,9 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.personal.ChinaTravel;
+ PRODUCT_BUNDLE_IDENTIFIER = com.person.ChinaTravel;
PRODUCT_NAME = Visual_Novel_iOSLevel;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = CLPRODUCT;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/Visual_Novel_iOS/CL-Bridging-Header.h";
@@ -550,6 +552,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = 6GS5RC7C89;
@@ -573,8 +576,9 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.personal.ChinaTravel;
+ PRODUCT_BUNDLE_IDENTIFIER = com.person.ChinaTravel;
PRODUCT_NAME = Visual_Novel_iOSLevel;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = CLAPPSTORE;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/Visual_Novel_iOS/CL-Bridging-Header.h";
@@ -607,6 +611,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = 6GS5RC7C89;
@@ -630,8 +635,9 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.personal.ChinaTravel;
+ PRODUCT_BUNDLE_IDENTIFIER = com.person.ChinaTravel;
PRODUCT_NAME = Visual_Novel_iOSLevel;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/Visual_Novel_iOS/CL-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -645,6 +651,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 121;
DEVELOPMENT_TEAM = 6GS5RC7C89;
@@ -668,8 +675,9 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.personal.ChinaTravel;
+ PRODUCT_BUNDLE_IDENTIFIER = com.person.ChinaTravel;
PRODUCT_NAME = Visual_Novel_iOSLevel;
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/Visual_Novel_iOS/CL-Bridging-Header.h";
SWIFT_VERSION = 5.0;
diff --git a/Visual_Novel_iOS/Info.plist b/Visual_Novel_iOS/Info.plist
index 7ee5ec2..9b14c1d 100644
--- a/Visual_Novel_iOS/Info.plist
+++ b/Visual_Novel_iOS/Info.plist
@@ -22,7 +22,15 @@
NSAllowsArbitraryLoadsInWebContent
NSExceptionDomains
-
+
+ 54.223.196.180
+
+ NSExceptionAllowsInsecureHTTPLoads
+
+ NSIncludesSubdomains
+
+
+
UIAppFonts
diff --git a/Visual_Novel_iOS/Src/API/Network/APIConfig.swift b/Visual_Novel_iOS/Src/API/Network/APIConfig.swift
index 752ca08..7d46302 100644
--- a/Visual_Novel_iOS/Src/API/Network/APIConfig.swift
+++ b/Visual_Novel_iOS/Src/API/Network/APIConfig.swift
@@ -43,18 +43,18 @@ struct APIConfig {
static func apiHeaders() -> [String: String]? {
var updatHeaders = headers
+//
+// let platform = "IOS" // _\(Bundle.appVersion)
+// updatHeaders?.updateValue(platform, forKey: "platform")
- let platform = "IOS" // _\(Bundle.appVersion)
- updatHeaders?.updateValue(platform, forKey: "platform")
+// let tokenNow = UserCore.shared.token
+// if tokenNow.count > 0 {
+// updatHeaders?.updateValue(tokenNow, forKey: "AUTH_TK")
+// }
- let tokenNow = UserCore.shared.token
- if tokenNow.count > 0 {
- updatHeaders?.updateValue(tokenNow, forKey: "AUTH_TK")
- }
+// updatHeaders?.updateValue("\(versionNum)", forKey: "versionNum")
- updatHeaders?.updateValue("\(versionNum)", forKey: "versionNum")
-
- updatHeaders?.updateValue(UIDevice.UUID, forKey: "AUTH_DID")
+// updatHeaders?.updateValue(UIDevice.UUID, forKey: "AUTH_DID")
/*
if let lan = Languages.preferedLans.first {
updatHeaders?.updateValue(lan.rawValue, forKey: "accept-language")
@@ -106,4 +106,9 @@ struct APIConfig {
static var pigeon: String{
return "https://test-pigeon.crushlevel.ai"
}
+
+ static var role: String {
+ // 确保 URL 格式正确,包含协议、域名和端口
+ return "http://54.223.196.180:8091"
+ }
}
diff --git a/Visual_Novel_iOS/Src/API/Network/APIProvider.swift b/Visual_Novel_iOS/Src/API/Network/APIProvider.swift
index 69f1a94..e5fca56 100644
--- a/Visual_Novel_iOS/Src/API/Network/APIProvider.swift
+++ b/Visual_Novel_iOS/Src/API/Network/APIProvider.swift
@@ -128,11 +128,14 @@ public enum ServiceErrorEnum: String, Codable {
// 假设 ResponseData 是一个泛型结构体,用于包装 API 响应
struct ResponseData: Codable {
/// OK or ERROR
- let status: String?
- let errorCode: ServiceErrorEnum?
- let errorMsg: String?
- let content: T?
- let traceId : String?
+// let status: String?
+// let errorCode: ServiceErrorEnum?
+// let errorMsg: String?
+// let content: T?
+// let traceId : String?
+ let code: Int?
+ let message: String?
+ let data: T?
}
class ResponseContentPageData: Codable{
@@ -213,58 +216,58 @@ extension MoyaProvider {
dlog("👉⭐️\(target.path)⭐️ response:\n\(jsonString)")
}
- let status = data.status
- let code = data.errorCode
- let msg = data.errorMsg
+// let status = data.status
+// let code = data.errorCode
+// let msg = data.errorMsg
- if (status ?? "") == "OK" {
- let model = data.content
+ if (data.code ?? 0) == 200 {
+ let model = data.data
completion(.success(model))
} else {
- var toastMsg = autoShowErrMsg
-
- if code == .tokenExpired || code == .tokenIllegal || code == .accountIsFrozen || code == .sign_usernotexist || code == .sign_usernotLoggedIn || code == .sign_userLoginclientNotExist || code == .sign_userNotAuthorizedClient {
- // ⚠️ 弹出登陆
- UserCore.shared.logout()
-
- if let Vc = UIWindow.getTopViewController(), (Vc is CLLoginMainController || Vc is PersonalInformationFillController) {
- // do nothing.
- } else {
-// AppRouter.goBackRootController(jumpIndex: .home) {
-// NotificationCenter.post(name: .presentSignInVc, object: nil, userInfo: nil)
+// var toastMsg = autoShowErrMsg
+//
+// if code == .tokenExpired || code == .tokenIllegal || code == .accountIsFrozen || code == .sign_usernotexist || code == .sign_usernotLoggedIn || code == .sign_userLoginclientNotExist || code == .sign_userNotAuthorizedClient {
+// // ⚠️ 弹出登陆
+// UserCore.shared.logout()
+//
+// if let Vc = UIWindow.getTopViewController(), (Vc is CLLoginMainController || Vc is PersonalInformationFillController) {
+// // do nothing.
+// } else {
+//// AppRouter.goBackRootController(jumpIndex: .home) {
+//// NotificationCenter.post(name: .presentSignInVc, object: nil, userInfo: nil)
+//// }
+// NotificationCenter.post(name: .presentSignInVc, object: nil, userInfo: nil)
+// }
+// } else if code == .newAccount {
+// // ⚠️ 不进行Toast的Msg类型
+// toastMsg = false
+// } else if code == .insufficentCoin {
+// // ⚠️钱包余额不足
+// // refresh wallet
+// toastMsg = false
+//
+// var handled = false
+// if let cow = target as? AICowAPI{
+// switch cow{
+// case .voiceCallOperate, .voiceAsr2, .voiceTts:
+// IMAIViewModel.shared.showChatModelInsufficentCoinSheet()
+// handled = true
+// default:
+// break
// }
- NotificationCenter.post(name: .presentSignInVc, object: nil, userInfo: nil)
- }
- } else if code == .newAccount {
- // ⚠️ 不进行Toast的Msg类型
- toastMsg = false
- } else if code == .insufficentCoin {
- // ⚠️钱包余额不足
- // refresh wallet
- toastMsg = false
-
- var handled = false
- if let cow = target as? AICowAPI{
- switch cow{
- case .voiceCallOperate, .voiceAsr2, .voiceTts:
- IMAIViewModel.shared.showChatModelInsufficentCoinSheet()
- handled = true
- default:
- break
- }
- }
- if handled == false{
- // 弹出充值Sheet
- CLPurchase.shared.showIAPBuyCoinSheet()
- }
- }
-
- if toastMsg, let msgUnpack = msg, msgUnpack.count > 0 {
- UIWindow.getTopDisplayWindow()?.makeToast(msgUnpack)
- }
-
- dlog("⛔️error: code = \(code ?? .common), msg = \(data.errorMsg ?? "业务状态失败")")
- completion(.failure(.serviceError(code: code, msg: msg)))
+// }
+// if handled == false{
+// // 弹出充值Sheet
+// CLPurchase.shared.showIAPBuyCoinSheet()
+// }
+// }
+//
+// if toastMsg, let msgUnpack = msg, msgUnpack.count > 0 {
+// UIWindow.getTopDisplayWindow()?.makeToast(msgUnpack)
+// }
+//
+// dlog("⛔️error: code = \(code ?? .common), msg = \(data.errorMsg ?? "业务状态失败")")
+// completion(.failure(.serviceError(code: code, msg: msg)))
}
} catch {
diff --git a/Visual_Novel_iOS/Src/API/RoleApi.swift b/Visual_Novel_iOS/Src/API/RoleApi.swift
new file mode 100644
index 0000000..2ced0d6
--- /dev/null
+++ b/Visual_Novel_iOS/Src/API/RoleApi.swift
@@ -0,0 +1,69 @@
+//
+// RoleApi.swift
+// Visual_Novel_iOS
+//
+// Created by mh on 2025/11/6.
+//
+
+import Moya
+
+let RoleProvider = APIConfig.useMock && UserAPI.useMock
+? MoyaProvider(endpointClosure: myEndpointClosure, stubClosure: { target in
+ let data = target.sampleData
+ if(data.count > 0){
+ return .delayed(seconds: 0.5)
+ }else{
+ return .never
+ }
+})
+: MoyaProvider(requestClosure: myRequestClosure)
+
+enum RoleAPI {
+ static let useMock: Bool = false
+
+ // 查询角色列表
+ case characterList(params: [String: Any])
+
+}
+
+extension RoleAPI: TargetType {
+ var method: Moya.Method {
+ return .post
+ }
+
+ var task: Task {
+ var mParams = [String: Any]()
+ switch self {
+ case .characterList(let params):
+ // 将传入的参数赋值给 mParams
+ mParams = params
+ }
+ return .requestParameters(parameters: mParams, encoding: JSONEncoding.default)
+ }
+
+ var headers: [String : String]? {
+ return APIConfig.apiHeaders()
+ }
+
+ var baseURL: URL {
+ // 确保 URL 格式正确,避免强制解包导致的崩溃
+ guard let url = URL(string: APIConfig.role) else {
+ fatalError("Invalid baseURL: \(APIConfig.role)")
+ }
+ return url
+ }
+
+ var path: String {
+ switch self {
+ case .characterList:
+ return "/character/list"
+ }
+ }
+
+ var sampleData: Data {
+ switch self {
+ case .characterList:
+ return Data()
+ }
+ }
+}
diff --git a/Visual_Novel_iOS/Src/Modules/Chat/Setting/Model/ChatRoleViewModel.swift b/Visual_Novel_iOS/Src/Modules/Chat/Setting/Model/ChatRoleViewModel.swift
new file mode 100644
index 0000000..92fe652
--- /dev/null
+++ b/Visual_Novel_iOS/Src/Modules/Chat/Setting/Model/ChatRoleViewModel.swift
@@ -0,0 +1,64 @@
+//
+// ChatRoleViewModel.swift
+// Visual_Novel_iOS
+//
+// Created by mh on 2025/11/6.
+//
+
+import Foundation
+import CodableWrappers
+
+// request
+struct RoleListRequest: Codable {
+ var index = 1
+ var limit = 20
+ var name: String = ""
+ var sourceId = 0
+ var tagId: Int?
+}
+
+// model
+struct RoleListModel: Codable {
+ var total: Int = 0
+ var index: Int = -1
+ var rows: [RoleItem] = []
+}
+
+struct RoleItem: Codable {
+ var id: Int = 0
+ var name: String = ""
+ var coverImage: String = ""
+ var updateTime: String = ""
+ var sourceId: Int = 0
+}
+
+class ChatRoleViewModel {
+
+ func loadRoles(index: Int, limit: Int = 20, name: String = "", sourceId: Int = -1, tagId: Int? = nil, completion: ((_ datas: [RoleListModel]?) -> Void)?) {
+ var req = RoleListRequest()
+ req.index = index
+ req.limit = limit
+ req.name = name
+ req.sourceId = sourceId
+ req.tagId = tagId
+
+ let params = req.toNonNilDictionary()
+
+ // 根据 API 响应格式,返回的是单个 RoleListModel 对象,而不是数组
+ // 但为了保持接口一致性,我们将单个对象包装成数组
+ RoleProvider.request(.characterList(params: params), modelType: RoleListModel.self) { result in
+ switch result {
+ case .success(let model):
+ // 如果返回的是单个 RoleListModel,将其包装成数组
+ if let model = model {
+ completion?([model])
+ } else {
+ completion?(nil)
+ }
+ case .failure(let failure):
+ dlog("⛔️ 加载角色列表失败: \(failure)")
+ completion?(nil)
+ }
+ }
+ }
+}
diff --git a/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift b/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift
index 3ce98ea..711c83a 100644
--- a/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift
+++ b/Visual_Novel_iOS/Src/Modules/Chat/Setting/View/ChatSettingSwipeView.swift
@@ -189,11 +189,6 @@ extension ChatSettingSwipeView {
extension ChatSettingSwipeView: UITableViewDelegate, UITableViewDataSource {
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
- // 确保tableView内容可以滑动到最顶部
- // 不需要额外的contentInset调整
- }
-
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let imageRow = rows[indexPath.section][indexPath.row] as? ImageRow,
imageRow.showArrow else { return }
diff --git a/Visual_Novel_iOS/Src/Modules/Roles/RolesRootPageController.swift b/Visual_Novel_iOS/Src/Modules/Roles/RolesRootPageController.swift
index 951fa79..544b194 100644
--- a/Visual_Novel_iOS/Src/Modules/Roles/RolesRootPageController.swift
+++ b/Visual_Novel_iOS/Src/Modules/Roles/RolesRootPageController.swift
@@ -12,6 +12,8 @@ import Combine
class RolesRootPageController: CLTabRootController {
private var cancellables = Set()
+ var page: Int = 1
+ var viewModel: ChatRoleViewModel = ChatRoleViewModel()
override func viewDidLoad() {
super.viewDidLoad()
@@ -29,6 +31,11 @@ class RolesRootPageController: CLTabRootController {
setupEvent()
}
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ loadData()
+ }
+
private func setupViews() {
navigationView.bgView.alpha = 0
navigationView.setupBgViewToStatusBarHeight()
@@ -44,6 +51,18 @@ class RolesRootPageController: CLTabRootController {
.store(in: &cancellables)
}
+ func loadData() {
+// if page == 1{
+//// loadedAiIds.removeAll()
+// }
+
+ viewModel.loadRoles(index: page) { datas in
+ print(datas)
+ print("11111")
+
+ }
+ }
+
// 点击顶部 实现跳转
private func handleJump(_ target: JumpTarget) {
switch target {