From: liangzhenying <867174124@qq.com> Date: Fri, 17 Oct 2025 09:58:04 +0000 (+0800) Subject: 完成意见反馈功能开发 X-Git-Tag: 1.0.2~89 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=2957521b83c3c20fe5f198192641d96ccc654980;p=mirrors%2FShenYin.git 完成意见反馈功能开发 --- diff --git a/ShenYin/ShenYin.xcodeproj/project.pbxproj b/ShenYin/ShenYin.xcodeproj/project.pbxproj index aeed467..298fe4c 100644 --- a/ShenYin/ShenYin.xcodeproj/project.pbxproj +++ b/ShenYin/ShenYin.xcodeproj/project.pbxproj @@ -251,7 +251,7 @@ ); GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = ShenYin/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "深音"; + INFOPLIST_KEY_CFBundleDisplayName = DeepChords; INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "扫描附近蓝牙设备需要获得权限"; INFOPLIST_KEY_NSCameraUsageDescription = "修改用户头像、提交意见反馈需要访问相册使用摄像头"; INFOPLIST_KEY_NSMicrophoneUsageDescription = "录音需要使用麦克风"; @@ -294,7 +294,7 @@ ); GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = ShenYin/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "深音"; + INFOPLIST_KEY_CFBundleDisplayName = DeepChords; INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "扫描附近蓝牙设备需要获得权限"; INFOPLIST_KEY_NSCameraUsageDescription = "修改用户头像、提交意见反馈需要访问相册使用摄像头"; INFOPLIST_KEY_NSMicrophoneUsageDescription = "录音需要使用麦克风"; diff --git a/ShenYin/ShenYin/Api/HttpClient2.swift b/ShenYin/ShenYin/Api/HttpClient2.swift index b1d45e5..4bf340c 100644 --- a/ShenYin/ShenYin/Api/HttpClient2.swift +++ b/ShenYin/ShenYin/Api/HttpClient2.swift @@ -55,6 +55,18 @@ enum CommomApi case musicUrl(filedId:String) /// 上传图片 case uploadImage(param:[String:Any]) + /// 获取产品列表 + case getProductList + /// 获取产品说明书 + case productBook(productId:String) + /// 获取qa分类 + case qaCategory + /// 获取qa列表 + case qaList(categoryId:String,page:Int) + /// 提交意见反馈 + case commitFeedback(param:[String:Any]) + /// 获取提交的意见反馈 + case feedbackHistory } // 实现TargetType协议 @@ -121,12 +133,27 @@ extension CommomApi{ return "/res/music-file/path/\(id)" case .uploadImage(_): return "/res/image" + case .getProductList: + return "/dev/product/list" + case .productBook(let productId): + return "/res/prod-book-file?productId=\(productId)" + case .qaCategory: + return "/uc/qa-category/list" + case .qaList(let categoryId,let page): + return "/uc/qa/list/\(page)?categoryId=\(categoryId)" + + case .commitFeedback(_): + return "/uc/feedback" + case .feedbackHistory: + return "/uc/feedback" + + } } var method:RequestMethod{ switch self { - case .register(_),.phoneCodeLogin(_),.emailCodeLogin(_),.login(_): + case .register(_),.phoneCodeLogin(_),.emailCodeLogin(_),.login(_),.commitFeedback(_): return .post case .updatePwd(_),.updateUserInfo(_),.updatePhone(_),.updateEmail(_): return .put @@ -175,6 +202,9 @@ extension CommomApi{ case let .uploadImage(para): params += para break + case let .commitFeedback(para): + params += para + break default: break } @@ -246,33 +276,71 @@ class HttpClient{ Logger.debug("下载进度:\(progress)") // 进度值在 0 到 1 之间 } task.downloadHandler = { response, tempUrl in - if let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("\(fileId).mp3") { - if FileManager.default.fileExists(atPath: destinationUrl.path) { - Logger.debug("文件已经存在,先移除 => ",url) + DispatchQueue.main.sync { + if let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("\(fileId).mp3") { + if FileManager.default.fileExists(atPath: destinationUrl.path) { + Logger.debug("文件已经存在,先移除 => ",url) + do { + try FileManager.default.removeItem(atPath: destinationUrl.path) + }catch{ + Logger.debug("移除文件失败:\(error)") + completionHandler(nil) + } + } do { - try FileManager.default.removeItem(atPath: destinationUrl.path) - }catch{ - Logger.debug("移除文件失败:\(error)") + try FileManager.default.moveItem(at: tempUrl, to: destinationUrl) + Logger.debug("文件下载成功,保存路径:\(destinationUrl.path)") + completionHandler(destinationUrl.path) + } catch { + Logger.debug("移动文件失败:\(error)") completionHandler(nil) } } - do { - try FileManager.default.moveItem(at: tempUrl, to: destinationUrl) - Logger.debug("文件下载成功,保存路径:\(destinationUrl.path)") - completionHandler(destinationUrl.path) - } catch { - Logger.debug("移动文件失败:\(error)") + else{ completionHandler(nil) } } - else{ - completionHandler(nil) + } + task.run() + } + } + static func download(url:String,completionHandler:@escaping ((String?) -> Void)){ + Logger.debug("dowload => ",url) + if let request = URLRequest(urlString:url) { + let task = HTTP(request, isDownload: true) + task.progress = { progress in + Logger.debug("下载进度:\(progress)") // 进度值在 0 到 1 之间 + } + task.downloadHandler = { response, tempUrl in + DispatchQueue.main.sync { + if let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("\(Date().timeIntervalSince1970).pdf") { + Logger.debug("保存路径 => ",destinationUrl) + if FileManager.default.fileExists(atPath: destinationUrl.path) { + Logger.debug("文件已经存在,先移除 => ",url) + do { + try FileManager.default.removeItem(atPath: destinationUrl.path) + }catch{ + Logger.debug("移除文件失败:\(error)") + completionHandler(nil) + } + } + do { + try FileManager.default.moveItem(at: tempUrl, to: destinationUrl) + Logger.debug("文件下载成功,保存路径:\(destinationUrl.path)") + completionHandler(destinationUrl.path) + } catch { + Logger.debug("移动文件失败:\(error)") + completionHandler(nil) + } + } + else{ + completionHandler(nil) + } } } task.run() } } - } extension HttpClient{ diff --git a/ShenYin/ShenYin/Api/LanConfig.swift b/ShenYin/ShenYin/Api/LanConfig.swift deleted file mode 100644 index 904b077..0000000 --- a/ShenYin/ShenYin/Api/LanConfig.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// LangConfig.swift -// ShenYin -// -// Created by liangshi on 2025/10/15. -// - -enum AppSupportLanguage{ - case chinse - case english - case japanese - case korean - case french - case spanish - case portuguese - case indonesian - case russian - case malay - - static var all:[AppSupportLanguage]{ - return [.chinse,.english,.japanese,.korean,.french,.spanish,.portuguese,.indonesian,.russian,.malay] - } - var title:String{ - switch self { - case .chinse: - return "中文" - case .english: - return "英文" - case .japanese: - return "日文" - case .korean: - return "韩文" - case .french: - return "法语" - case .spanish: - return "西班牙文" - case .portuguese: - return "葡萄牙文" - case .indonesian: - return "印度尼西亚文" - case .russian: - return "俄文" - case .malay: - return "马来文" - } - } - var map:[String:String]{ - switch self { - case .chinse: - return englishMap - case .english: - return englishMap - case .japanese: - return japaneseMap - case .korean: - return koreanMap - case .french: - return frenchMap - case .spanish: - return spanishMap - case .portuguese: - return portugueseMap - case .indonesian: - return indonesianMap - case .russian: - return russianMap - case .malay: - return malayMap - } - } -} - -let chineseMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let englishMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let japaneseMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let koreanMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let frenchMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let spanishMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let portugueseMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let indonesianMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let russianMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] -let malayMap:[String:String] = [ - "登录" : "login", - "注册" : "register", -] - -extension String{ - var l10n:String{ - if let value = Config.appLanguage.map[self] { - return value - } - else{ - return self - } - } -} - - diff --git a/ShenYin/ShenYin/Api/ResponseBaseModel.swift b/ShenYin/ShenYin/Api/ResponseBaseModel.swift index 8f98274..74c8ebd 100644 --- a/ShenYin/ShenYin/Api/ResponseBaseModel.swift +++ b/ShenYin/ShenYin/Api/ResponseBaseModel.swift @@ -16,3 +16,8 @@ public class ResponseBaseModel: HandyJSON { public var isSuccess: Bool { return success} } + + +class CommonDataModel:ResponseBaseModel { + var data = "" +} diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Contents.json new file mode 100644 index 0000000..c8ff4ea --- /dev/null +++ b/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame_2291@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame_2291@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Frame_2291@2x.png b/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Frame_2291@2x.png new file mode 100644 index 0000000..b4befe4 Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Frame_2291@2x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Frame_2291@3x.png b/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Frame_2291@3x.png new file mode 100644 index 0000000..de783a7 Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/add_picture.imageset/Frame_2291@3x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/Contents.json new file mode 100644 index 0000000..ce54822 --- /dev/null +++ b/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "删除@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "删除@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/\345\210\240\351\231\244@2x.png" "b/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/\345\210\240\351\231\244@2x.png" new file mode 100644 index 0000000..5957d97 Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/\345\210\240\351\231\244@2x.png" differ diff --git "a/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/\345\210\240\351\231\244@3x.png" "b/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/\345\210\240\351\231\244@3x.png" new file mode 100644 index 0000000..f691e28 Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/mine/delete_icon.imageset/\345\210\240\351\231\244@3x.png" differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Contents.json new file mode 100644 index 0000000..39978db --- /dev/null +++ b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame_2252@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame_2252@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Frame_2252@2x.png b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Frame_2252@2x.png new file mode 100644 index 0000000..263e0bf Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Frame_2252@2x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Frame_2252@3x.png b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Frame_2252@3x.png new file mode 100644 index 0000000..26d63da Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_chat.imageset/Frame_2252@3x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Frame@2x.png b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Frame@2x.png new file mode 100644 index 0000000..377c4d7 Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Frame@2x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Frame@3x.png b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Frame@3x.png new file mode 100644 index 0000000..8bc7f28 Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_edit.imageset/Frame@3x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/Contents.json new file mode 100644 index 0000000..8e19255 --- /dev/null +++ b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "反馈历史_1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "反馈历史_1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/\345\217\215\351\246\210\345\216\206\345\217\262_1@2x.png" "b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/\345\217\215\351\246\210\345\216\206\345\217\262_1@2x.png" new file mode 100644 index 0000000..9c915a7 Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/\345\217\215\351\246\210\345\216\206\345\217\262_1@2x.png" differ diff --git "a/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/\345\217\215\351\246\210\345\216\206\345\217\262_1@3x.png" "b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/\345\217\215\351\246\210\345\216\206\345\217\262_1@3x.png" new file mode 100644 index 0000000..b818b40 Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/mine/feedback_history.imageset/\345\217\215\351\246\210\345\216\206\345\217\262_1@3x.png" differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Frame@2x.png b/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Frame@2x.png new file mode 100644 index 0000000..a3bf533 Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Frame@2x.png differ diff --git a/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Frame@3x.png b/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Frame@3x.png new file mode 100644 index 0000000..ed2e1c3 Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/mine/mine_cell_lan.imageset/Frame@3x.png differ diff --git a/ShenYin/ShenYin/Tools/LogManager.swift b/ShenYin/ShenYin/Tools/LogManager.swift index 5ae693a..173baf7 100644 --- a/ShenYin/ShenYin/Tools/LogManager.swift +++ b/ShenYin/ShenYin/Tools/LogManager.swift @@ -25,7 +25,7 @@ class Logger { private func getPath()->String{ - let foldPath = NSHomeDirectory() + "/Documents" + let foldPath = NSHomeDirectory() + "/Documents/" let fileManager = FileManager.default if !fileManager.fileExists(atPath: foldPath) { do { diff --git a/ShenYin/ShenYin/UI/Launch/AppManager.swift b/ShenYin/ShenYin/UI/Launch/AppManager.swift index afd8487..dfaa579 100644 --- a/ShenYin/ShenYin/UI/Launch/AppManager.swift +++ b/ShenYin/ShenYin/UI/Launch/AppManager.swift @@ -48,6 +48,13 @@ class App{ topVC().navigationController?.popToViewController(vcs[index], animated: true) } } + func popToRootPage(){ + topVC().navigationController?.popToRootViewController(animated: true) + } + var tabController:UITabBarController?{ + let tb = window?.rootViewController as? UITabBarController + return tb + } } extension App{ private func getTopViewController(from vc: UIViewController) -> UIViewController { @@ -65,8 +72,8 @@ extension App{ extension App{ var deviceValid:Bool{ - return BleManager.shared.isConnetd -// return !BleManager.shared.isConnetd +// return BleManager.shared.isConnetd + return !BleManager.shared.isConnetd } } diff --git a/ShenYin/ShenYin/UI/Launch/SceneDelegate.swift b/ShenYin/ShenYin/UI/Launch/SceneDelegate.swift index f6032c7..4dbefb7 100644 --- a/ShenYin/ShenYin/UI/Launch/SceneDelegate.swift +++ b/ShenYin/ShenYin/UI/Launch/SceneDelegate.swift @@ -18,7 +18,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { App.shared.window = window window?.rootViewController = BaseTC() -// window?.rootViewController = UINavigationController(rootViewController: AudioPlayerVC()) +// window?.rootViewController = UINavigationController(rootViewController: FeedbackCommitVC()) AppLaunch.start() } diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackCommitVC.swift b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackCommitVC.swift new file mode 100644 index 0000000..bc73177 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackCommitVC.swift @@ -0,0 +1,170 @@ +// +// FeedbackCommitVC.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +import UIKit + +class FeedbackCommitVC:BaseVC{ + let bgView = UIScrollView() + let typeView = FeedbackTypeView() + let contentView = FeedbackInputView() + let imgView = FeedbackImageView() + let contactView = FeedbackContactView() + let loginBtn = CustomButton() + override func viewDidLoad() { + super.viewDidLoad() + + + } + override func navRightViewTapped() { + App.shared.goToPage(FeedbackHistoryVC()) + } + override func setupViews() { + self.navBar.title = "意见反馈" + navBar.rightView.setImage(UIImage(named: "feedback_history"), for: .normal) + + view.addSubview(bgView) + bgView.addSubviews([typeView,contentView,imgView,contactView,loginBtn]) + + bgView.do { v in + v.backgroundColor = .white + v.yc.setCornerRadius(12) + } + loginBtn.set(title: "确定",style: .theme1, target: self, action: #selector(loginAction)) + } + override func setupLayout() { + bgView.snp.makeConstraints { make in + make.top.equalTo(kNavBtm + 10) + make.width.equalTo(kScreenWid - 36) + make.height.equalTo(kScreenHei - kNavBtm - 20) + make.left.equalToSuperview().inset(18) + } + typeView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.left.equalToSuperview() + make.width.equalToSuperview() + make.height.equalTo(80) + } + contentView.snp.makeConstraints { make in + make.top.equalTo(typeView.snp.bottom).offset(15) + make.left.equalToSuperview() + make.width.equalToSuperview() + make.height.equalTo(150) + } + imgView.snp.makeConstraints { make in + make.top.equalTo(contentView.snp.bottom).offset(15) + make.left.equalToSuperview() + make.width.equalToSuperview() + make.height.equalTo(120) + } + contactView.snp.makeConstraints { make in + make.top.equalTo(imgView.snp.bottom).offset(15) + make.left.equalToSuperview() + make.width.equalToSuperview() + make.height.equalTo(90) + } + loginBtn.snp.makeConstraints { make in + make.top.equalTo(contactView.snp.bottom).offset(40) + make.centerX.equalToSuperview() + make.width.equalTo(kScreenWid - 102) + make.height.equalTo(55) + make.bottom.equalToSuperview().inset(50) + } + } + @objc func loginAction(){ + let content = contentView.textView.textView.text ?? "" + if content.isEmpty && imgView.dataArray.count == 1 { + YLprogressHUD.showAutoHiden("内容不能为空") + return + } + + + if imgView.dataArray.count > 1 { + YLprogressHUD.showLoading() + uploadImages { [weak self] urls in + guard let self = self else{return} + if let list = urls { + YLprogressHUD.hidden() + startCommit(list) + } + else{ + YLprogressHUD.showAutoHiden("请求失败") + } + } + } + else{ + startCommit([]) + } + } + func uploadImages(_ finished:@escaping (([String]?) -> Void)){ + var urls = [String]() + let dispatchGroup = DispatchGroup() + for item in imgView.dataArray { + if !item.isAdd { + dispatchGroup.enter() + startUploadImage(item.img) { url in + if let url = url { + urls.append(url) + } + dispatchGroup.leave() + } + } + } + dispatchGroup.notify(queue:.main) { + if urls.count == self.imgView.dataArray.count - 1{ + finished(urls) + } + else{ + finished(nil) + } + } + } + + func startUploadImage(_ img:UIImage,finished:@escaping ((String?) -> Void)){ + guard let path = CacheManager.saveImg(img) else{ + finished(nil) + return + } + let url = URL(fileURLWithPath: path) + + var params:[String:Any] = [:] + params["type"] = "report" + params["fileUrl"] = url + let api = CommomApi.uploadImage(param: params) + HttpClient.uploadImage(api){[weak self] (model:CommonDataModel, res) in + if model.isSuccess{ + finished(model.data) + } + else{ + finished(nil) + } + } + } + func startCommit(_ imgs:[String]){ + let phone = contactView.textField.text ?? "" + let content = contentView.textView.textView.text ?? "" + + + YLprogressHUD.showLoading() + var params:[String:Any] = [:] + params["type"] = typeView.type ?? "" + params["images"] = imgs + params["description"] = content + params["phone"] = phone + + let api = CommomApi.commitFeedback(param: params) + HttpClient.request(api) {[weak self] (model:ResponseBaseModel,res) in + guard let self = self else {return} + if model.isSuccess{ + YLprogressHUD.hidden() + } + else{ + YLprogressHUD.showAutoHiden(model.msg) + } + } + + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackContactView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackContactView.swift new file mode 100644 index 0000000..f4854a2 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackContactView.swift @@ -0,0 +1,53 @@ +// +// FeedbackContectView.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +class FeedbackContactView: BaseView,UITextFieldDelegate { + let titleLabel = UILabel() + let bgView = UIView() + let textField = UITextField() + + override func setupViews() { + addSubviews([titleLabel,bgView]) + bgView.addSubview(textField) + + titleLabel.do { v in + v.textAlignment = .center + v.font = .bold(14) + v.textColor = .hexString("#666666") + v.text = "联系方式" + } + bgView.do { v in + v.backgroundColor = .hexString("#F7F8F9") + v.yc.setCornerRadius(12) + } + textField.do { v in + v.placeholder = "请输入手机号或邮箱" + v.font = .regular(14) + v.returnKeyType = .done + v.delegate = self + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview() + make.left.equalToSuperview().inset(16) + } + bgView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(16) + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.height.equalTo(50) + } + textField.snp.makeConstraints { make in + make.edges.equalToSuperview().inset(15) + } + } + func textFieldShouldReturn(_ textField: UITextField) -> Bool{ + textField.resignFirstResponder() + return false + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackImageView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackImageView.swift new file mode 100644 index 0000000..30eb2fb --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackImageView.swift @@ -0,0 +1,167 @@ +// +// FeedbackImageView.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +import Foundation +import UIKit + +class FeedbackImageCellModel{ + + var img = UIImage() + var isAdd = false + init(img: UIImage = UIImage(), isAdd: Bool = false) { + self.img = img + self.isAdd = isAdd + } +} + + +final class FeedbackImageView: BaseView { + let imgPicker = ImagePickerManager() + var dataArray = [FeedbackImageCellModel(img: UIImage(named: "add_picture")!, isAdd: true)] + private var collectionView:UICollectionView! + + override func setupViews() { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + //layout.minimumInteritemSpacing = 10.fitR + layout.minimumLineSpacing = 18 + layout.itemSize = CGSize(width: 90, height: 90) + collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout) + addSubview(collectionView) + + collectionView.do { (v) in + v.dataSource = self + v.delegate = self + v.backgroundColor = .clear + v.bounces = true + v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18) + v.register(FeedbackImageCell.self, forCellWithReuseIdentifier: FeedbackImageCell.reuseID) + } + } + override func setupLayout() { + collectionView.snp.makeConstraints { (m) in + m.top.equalToSuperview() + m.left.right.bottom.equalToSuperview() + } + } + func scrollToBottom() { + let itemCount = collectionView.numberOfItems(inSection: 0) + if itemCount > 0 { + let lastIndexPath = IndexPath(item: itemCount - 1, section: 0) + collectionView.scrollToItem(at: lastIndexPath, at:.bottom, animated: true) + } + } + @objc func addAction() -> Void { + imgPicker.showImagePicker2(from: App.shared.topVC()) {[weak self] image in + guard let self = self else { return } + guard let image = image,let img = UIImage.resizeImage(image: image, toWidth: 300) else { return} + let model = FeedbackImageCellModel(img:image, isAdd: false) + dataArray.insert(model, at: dataArray.count - 1) + collectionView.reloadData() + scrollToBottom() + } + } + func deleteAction(_ model:FeedbackImageCellModel){ + dataArray.removeAll { item in + return item === model + } + collectionView.reloadData() + } + +} + +extension FeedbackImageView: UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout { + func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return dataArray.count + } + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = FeedbackImageCell.cell(withCollectionView: collectionView, indexPath: indexPath) + cell.model = dataArray[indexPath.row] + cell.deleteAction = {[weak self] cell in + guard let self = self else {return} + deleteAction(cell.model) + } + return cell + } + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = dataArray[indexPath.row] + if model.isAdd { + addAction() + } + } +} + + + +class FeedbackImageCell: BaseCollectionViewCell { + let bgView = UIView() + let imgV = UIImageView() + let playImgV = UIImageView() + var deleteAction:((_ cell:FeedbackImageCell)->Void)? + + + override init(frame: CGRect) { + super.init(frame: frame) + contentView.addSubview(bgView) + bgView.addSubview(imgV) + bgView.addSubview(playImgV) + + +// bgView.backgroundColor = .green + + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + imgV.snp.makeConstraints { (make) in + make.left.equalToSuperview() + make.top.equalToSuperview().inset(8) + make.size.equalTo(80) + } + + playImgV.snp.makeConstraints { (make) in + make.size.equalTo(32) + make.right.equalToSuperview() + make.centerY.equalTo(16) + } + + + imgV.do { v in + v.contentMode = .scaleAspectFill + v.clipsToBounds = true + v.yc.setCornerRadius(12) + v.clipsToBounds = true + } + playImgV.do { v in +// v.backgroundColor = .red + v.image = UIImage(named: "delete_icon") + v.contentMode = .top + v.yc.addTap(target: self, action: #selector(tapAction)) + } + } + + @objc func tapAction(){ + deleteAction?(self) + } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var model:FeedbackImageCellModel!{ + didSet{ + imgV.image = model.img + if model.isAdd { + playImgV.isHidden = true + } + else{ + playImgV.isHidden = false + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackInputView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackInputView.swift new file mode 100644 index 0000000..8c0f1f0 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackInputView.swift @@ -0,0 +1,49 @@ +// +// Untitled.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +class FeedbackInputView: BaseView { + let titleLabel = UILabel() + let bgView = UIView() + let textView = PlaceHolderTextView2() + + override func setupViews() { + // backgroundColor = .red + addSubviews([titleLabel,bgView]) + bgView.addSubview(textView) + + titleLabel.do { v in + v.textAlignment = .center + v.font = .bold(14) + v.textColor = .hexString("#666666") + v.text = "问题描述或建议" + } + bgView.do { v in + v.backgroundColor = .hexString("#F7F8F9") + v.yc.setCornerRadius(12) + } + textView.do {v in + v.placeHolde = "请至少用10个字描述问题,并添加截图,这有助于问题快速解决。" + v.backgroundColor = .clear + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview() + make.left.equalToSuperview().inset(16) + } + bgView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(16) + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.bottom.equalToSuperview() + } + textView.snp.makeConstraints({ make in + make.edges.equalToSuperview().inset(10) + }) + } + +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackTypeView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackTypeView.swift new file mode 100644 index 0000000..191180f --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/Commit/FeedbackTypeView.swift @@ -0,0 +1,106 @@ +// +// Untitled.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +class FeedbackTypeView: BaseView { + let titleLabel = UILabel() + let errorItem = SelectedTypeItem() + let adviceItem = SelectedTypeItem() + + var isOk:Bool{ + return errorItem.isSelected || adviceItem.isSelected + } + var type:String?{ + if adviceItem.isSelected { + return adviceItem.titleLabel.text + } + if errorItem.isSelected { + return adviceItem.titleLabel.text + } + return nil + } + + override func setupViews() { +// backgroundColor = .red + addSubviews([titleLabel,errorItem,adviceItem]) + + titleLabel.do { v in + v.textAlignment = .center + v.font = .bold(14) + v.textColor = .hexString("#666666") + v.text = "问题类型" + } + errorItem.do { v in + v.titleLabel.text = "功能异常" + v.yc.setCornerRadius(17) + v.yc.addTap(target: self, action: #selector(errorAction)) + } + adviceItem.do { v in + v.titleLabel.text = "意见与反馈" + v.yc.setCornerRadius(17) + v.yc.addTap(target: self, action: #selector(adviceAction)) + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.left.top.equalToSuperview().inset(16) + } + errorItem.snp.makeConstraints { make in + make.left.equalToSuperview().inset(16) + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.width.equalTo(95) + make.height.equalTo(34) + } + adviceItem.snp.makeConstraints { make in + make.left.equalTo(errorItem.snp.right).offset(16) + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.width.equalTo(95) + make.height.equalTo(34) + } + } + + @objc func errorAction(){ + errorItem.isSelected = true + adviceItem.isSelected = false + } + @objc func adviceAction(){ + errorItem.isSelected = false + adviceItem.isSelected = true + } + class SelectedTypeItem: BaseView { + let titleLabel = UILabel() + + var isSelected:Bool = false{ + didSet{ + if isSelected { + titleLabel.textColor = .white + backgroundColor = .color(.theme) + } + else{ + titleLabel.textColor = .hexString("#121212") + backgroundColor = .hexString("#F7F8F9") + } + } + } + + override func setupViews() { + backgroundColor = .hexString("#F7F8F9") + addSubviews([titleLabel]) + titleLabel.do { v in + v.textAlignment = .center + v.font = .regular(14) + v.yc.setCornerRadius(40) + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackBottomView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackBottomView.swift new file mode 100644 index 0000000..ba1ceff --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackBottomView.swift @@ -0,0 +1,88 @@ +// +// FeedbackBottomView.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + + + +class FeedbackBottomView: BaseView { + let feedbackItem = RecordLanguageItem() + let chatItem = RecordLanguageItem() + let line = UIView() + + override func setupViews() { + backgroundColor = .white + addSubviews([feedbackItem,chatItem,line]) + feedbackItem.do { v in + v.icon.image = UIImage(named: "feedback_edit") + v.titleLabel.text = "意见反馈" +// v.backgroundColor = .green + } + line.do { v in + v.backgroundColor = .hexString("#999999") + + } + chatItem.do { v in + v.icon.image = UIImage(named: "feedback_chat") + v.titleLabel.text = "在线咨询" +// v.backgroundColor = .red + } + } + override func setupLayout() { + feedbackItem.snp.makeConstraints { make in +// make.width.equalToSuperview().multipliedBy(0.5) + make.height.equalToSuperview() + make.top.equalToSuperview() + make.centerX.equalTo(kScreenWid/4) + } + chatItem.snp.makeConstraints { make in +// make.width.equalToSuperview().multipliedBy(0.5) + make.height.equalToSuperview() + make.top.equalToSuperview() + make.centerX.equalTo(kScreenWid/4*3) + + } + line.snp.makeConstraints { make in + make.width.equalTo(1) + make.height.equalTo(22) + make.centerX.equalToSuperview() + make.top.equalToSuperview().inset(12) + } + } + + class RecordLanguageItem: BaseView { + let icon = UIImageView() + let titleLabel = UILabel() + + var language:AiSupportLanguage = AiSupportLanguage.chinse{ + didSet{ + titleLabel.text = language.title + } + } + + override func setupViews() { + addSubviews([titleLabel,icon]) + icon.do { v in + } + titleLabel.do { v in + v.textColor = .rgb(0x121212) + v.font = .bold(16) + } + } + + override func setupLayout() { + icon.snp.makeConstraints { make in + make.size.equalTo(20) + make.top.equalToSuperview().inset(13) + make.left.equalToSuperview().inset(30) + } + titleLabel.snp.makeConstraints { make in + make.left.equalTo(icon.snp.right).offset(1) + make.centerY.equalTo(icon) + make.right.equalToSuperview().inset(30) + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackContentView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackContentView.swift new file mode 100644 index 0000000..0f99200 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackContentView.swift @@ -0,0 +1,133 @@ +// +// FeedbackContentView.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +class FeedbackContentModel{ + var content = "" + var isSend = false + init(content: String = "", isSend: Bool = false) { + self.content = content + self.isSend = isSend + } +} + +class FeedbackContentView: BaseView { + let tableView = UITableView(frame: .zero, style: .plain) + var list = [FeedbackContentModel]() + + override func setupViews() { + backgroundColor = .clear + tableView.do { v in + v.backgroundColor = .clear + v.delegate = self + v.dataSource = self + v.separatorStyle = .none + v.estimatedRowHeight = 50 + v.register(FeedbackContentViewCell.self, forCellReuseIdentifier: FeedbackContentViewCell.reuseID) + } + + addSubview(tableView) + } + override func setupLayout() { + tableView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(0) + make.top.bottom.equalToSuperview().inset(0) + } + } + + func addData(model:FeedbackContentModel){ + list.append(model) + tableView.reloadData() + if list.count > 0 { + tableView.scrollToRow(at: IndexPath(row: list.count - 1, section: 0), at: .none, animated: true) + } + } +} +extension FeedbackContentView:UITableViewDelegate,UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list.count + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = FeedbackContentViewCell.cell(withTableView: tableView, indexPath: indexPath) + cell.data = list[indexPath.row] + return cell + } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let data = list[indexPath.row] + + } +} + +class FeedbackContentViewCell:BaseTableViewCell{ + let bgView = UIView() + let originalLabel = UILabel() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func setupViews() { + contentView.backgroundColor = .rgb(0xF6F6F6) + + bgView.do { v in + v.yc.setCornerRadius(12) + } + originalLabel.do { v in + v.font = .bold(14) + v.textColor = .hexString("#606D80") + v.numberOfLines = 0 + v.textAlignment = .left + } + + contentView.addSubview(bgView) + bgView.addSubviews([originalLabel]) + } + + override func setupLayout() { + bgView.snp.makeConstraints { make in + make.top.bottom.equalToSuperview().inset(10) + make.width.lessThanOrEqualTo(kScreenWid - 36) + make.left.equalToSuperview().inset(18) + } + + originalLabel.snp.makeConstraints { make in + make.top.bottom.equalToSuperview().inset(14) + make.left.right.equalToSuperview().inset(12) + make.width.lessThanOrEqualTo(kScreenWid - 60) + make.width.greaterThanOrEqualTo(60) + make.height.greaterThanOrEqualTo(19) + } + } + + var data:FeedbackContentModel!{ + didSet{ + originalLabel.text = data.content + if data.isSend { + bgView.backgroundColor = .color(.theme) + originalLabel.textColor = .white + + bgView.snp.remakeConstraints { make in + make.top.bottom.equalToSuperview().inset(10) + make.right.equalToSuperview().inset(20) + } + } + else{ + bgView.backgroundColor = .white + originalLabel.textColor = .hexString("#121212") + + bgView.snp.remakeConstraints { make in + make.top.bottom.equalToSuperview().inset(10) + make.left.equalToSuperview().inset(20) + } + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackHistoryVC.swift b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackHistoryVC.swift new file mode 100644 index 0000000..c6e3a5a --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackHistoryVC.swift @@ -0,0 +1,152 @@ +// +// FeedbackHistoryVC.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +import UIKit +class FeedbackHistoryVC: BaseVC{ + let tableView = UITableView(frame: .zero, style: .plain) + var list = [FeedbackHistoryModel]() + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + override func setupViews() { + self.navBar.title = "反馈历史" + + tableView.do { v in + v.backgroundColor = .color(.bgColor) + v.delegate = self + v.dataSource = self + v.rowHeight = 76 + v.sectionHeaderHeight = 52 + v.separatorStyle = .none + v.register(FeedbackHistoryCell.self, forCellReuseIdentifier: FeedbackHistoryCell.reuseID) + + } + + view.addSubview(tableView) + } + override func setupLayout() { + tableView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalTo(kNavBtm) + } + } + override func setupData() { + let api = CommomApi.feedbackHistory + HttpClient.request(api) {[weak self] (model:FeedbackHistoryRoot,res) in + guard let self = self else {return} + if model.isSuccess{ + self.list = model.data + self.tableView.reloadData() + } + } + } +} + +extension FeedbackHistoryVC:UITableViewDelegate,UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list.count + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = FeedbackHistoryCell.cell(withTableView: tableView, indexPath: indexPath) + cell.model = list[indexPath.row] + return cell + } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + } +} + + +fileprivate class FeedbackHistoryCell: BaseTableViewCell { + let bgView = UIView() + let icon = UIImageView() + let nameLabel = UILabel() + let contentLabel = UILabel() + let timeLabel = UILabel() + + var model:FeedbackHistoryModel!{ + didSet{ + icon.kf.setImage(with: CacheManager.shared.user.info.avatar.yc.asUrl) + nameLabel.text = CacheManager.shared.user.info.userName + contentLabel.text = model.description + timeLabel.text = model.createTime + } + } + + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func setupViews() { + contentView.addSubview(bgView) + bgView.addSubviews([icon,nameLabel,contentLabel,timeLabel]) + + backgroundColor = .rgb(0xF7F7F7) + contentView.backgroundColor = .clear + selectionStyle = .none + bgView.do { v in + v.backgroundColor = UIColor.white + v.yc.setCornerRadius(8) + } + nameLabel.do { (v) in + v.textColor = .hexString("#121212") + v.font = .medium(16) + v.textAlignment = .left + v.lineBreakMode = .byTruncatingTail + } + contentLabel.do { v in + v.textColor = .rgb(0x666666) + v.font = .regular(14) + v.textAlignment = .left + v.lineBreakMode = .byTruncatingTail + } + timeLabel.do { v in + v.textColor = .rgb(0x999999) + v.font = .regular(14) + v.textAlignment = .right + } + icon.do { v in + v.yc.setCornerRadius(18) + } + } + + override func setupLayout() { + bgView.snp.makeConstraints { (m) in + m.left.right.equalToSuperview().inset(18) + m.top.equalToSuperview().inset(10) + m.bottom.equalToSuperview() + } + + icon.snp.makeConstraints { (m) in + m.size.equalTo(36) + m.left.equalToSuperview().inset(15) + m.top.equalToSuperview().inset(15) + } + nameLabel.snp.makeConstraints { (m) in + m.top.equalToSuperview().inset(10) + m.left.equalToSuperview().offset(60) + m.right.lessThanOrEqualToSuperview().inset(150) + } + contentLabel.snp.makeConstraints { (m) in + m.bottom.equalToSuperview().inset(10) + m.left.equalToSuperview().offset(60) + m.right.lessThanOrEqualToSuperview().inset(16) + } + timeLabel.snp.makeConstraints { (m) in + m.top.equalToSuperview().inset(11) + m.right.equalToSuperview().inset(16) + + } + } + + +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackQaListView.swift b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackQaListView.swift new file mode 100644 index 0000000..44c05de --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackQaListView.swift @@ -0,0 +1,88 @@ +// +// FeedbackQaListView.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +class FeedbackQaListView: BaseView { + let tableView = UITableView(frame: .zero, style: .plain) + let vm = FeedbackVM() + var didSelected:((_ model:QaModelListModel)->Void)? + + override func setupViews() { + backgroundColor = .white + yc.setCornerRadius(12) + tableView.do { v in + v.delegate = self + v.dataSource = self + v.separatorStyle = .none + v.estimatedRowHeight = 50 + v.register(FeedbackQaListViewCell.self, forCellReuseIdentifier: FeedbackQaListViewCell.reuseID) + } + + addSubview(tableView) + } + override func setupLayout() { + tableView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(0) + make.top.bottom.equalToSuperview().inset(15) + } + } + + func loadData(categoryId:String){ + vm.categoryId = categoryId + vm.refresh {[weak self] model in + guard let self = self else{return} + if model.isSuccess{ + tableView.reloadData() + } + } + } +} +extension FeedbackQaListView:UITableViewDelegate,UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return vm.list.count + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = FeedbackQaListViewCell.cell(withTableView: tableView, indexPath: indexPath) + cell.titleLabel.text = "\(indexPath.row + 1)." + vm.list[indexPath.row].title + return cell + } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let data = vm.list[indexPath.row] + didSelected?(data) + } +} +class FeedbackQaListViewCell: BaseTableViewCell { + let titleLabel = UILabel() + + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func setupViews() { + contentView.addSubviews([titleLabel]) + + titleLabel.do { (v) in + v.textColor = .rgb(0x666666) + v.font = .regular(14) + v.textAlignment = .left + v.numberOfLines = 0 + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { (m) in + m.top.bottom.equalToSuperview().inset(5) + m.left.equalToSuperview().inset(15) + m.right.lessThanOrEqualToSuperview().inset(10) + } + } + + +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackVM.swift b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackVM.swift new file mode 100644 index 0000000..4490005 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/FeedbackVM.swift @@ -0,0 +1,62 @@ +// +// FeedbackQaVM.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +class FeedbackVM:BaseVM{ + var categoryId = "" + var list = [QaModelListModel]() + var page = 0 + + public func refresh(completion:@escaping (_ result:QaModelListModelroot) ->Void) { + self.page = 1 + let api = CommomApi.qaList(categoryId: categoryId, page: self.page) + HttpClient.request(api) {[weak self] (model:QaModelListModelroot,res) in + guard let self = self else {return} + if model.isSuccess{ + page = model.data.currentPage + if model.data.currentPage == 1 { + list = model.data.list + } + else{ + list += model.data.list + } + } + completion(model) + } + } + public func loadMore(completion:@escaping (_ result:QaModelListModelroot) ->Void) { + self.page += 1 + let api = CommomApi.qaList(categoryId: categoryId, page: self.page) + HttpClient.request(api) {[weak self] (model:QaModelListModelroot,res) in + guard let self = self else {return} + if model.isSuccess{ + page = model.data.currentPage + if model.data.currentPage == 1 { + list = model.data.list + } + else{ + list += model.data.list + } + } + completion(model) + } + } +} + +extension FeedbackVM{ +// static public func getCagory( completion:@escaping (_ result:MusicCategoryRoot) ->Void) { +// let api = CommomApi.musicCategory +// HttpClient.request(api) { (model:MusicCategoryRoot,res) in +// completion(model) +// } +// } +// static public func getMusicUrl(filedId id:String, completion:@escaping (_ result:MusicDownloadModel) ->Void) { +// let api = CommomApi.musicUrl(filedId: id) +// HttpClient.request(api) { (model:MusicDownloadModel,res) in +// completion(model) +// } +// } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/FeekbackVC.swift b/ShenYin/ShenYin/UI/Mine/Feedback/FeekbackVC.swift new file mode 100644 index 0000000..c58b9ef --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/FeekbackVC.swift @@ -0,0 +1,75 @@ +// +// FeekbackVC.swift +// ShenYin +// +// Created by liangshi on 2025/8/6. +// + +import UIKit + +class FeekbackVC:BaseVC{ + let bottomView = FeedbackBottomView() + let qaView = FeedbackQaListView() + let contentView = FeedbackContentView() + + override func viewDidLoad() { + super.viewDidLoad() + + + } + override func setupViews() { + self.navBar.title = "意见反馈" + view.backgroundColor = .color(.bgColor) + view.addSubviews([bottomView,qaView,contentView]) + + qaView.do { v in + v.didSelected = {[weak self] model in + guard let self = self else{return} + addModel(model) + } + } + bottomView.do { v in + v.feedbackItem.yc.addTap(target: self, action: #selector(feedbackAction)) + v.chatItem.yc.addTap(target: self, action: #selector(chatAction)) + } + } + override func setupLayout() { + bottomView.snp.makeConstraints { make in + make.left.width.bottom.equalToSuperview() + make.height.equalTo(73) + } + qaView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(18) + make.height.equalTo(162) + make.top.equalToSuperview().inset(150) + } + contentView.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(18) + make.bottom.equalTo(bottomView.snp.top).offset(0) + make.top.equalTo(qaView.snp.bottom).offset(20) + } + } + override func setupData() { + let api = CommomApi.qaCategory + HttpClient.request(api) {[weak self] (model:QaCategoryModelRoot,res) in + guard let self = self else {return} + if model.isSuccess,let item = model.data.first{ + self.qaView.loadData(categoryId: item.id) + } + } + } + + func addModel(_ model:QaModelListModel){ + contentView.addData(model: FeedbackContentModel(content: model.title,isSend: true)) + contentView.addData(model: FeedbackContentModel(content: model.content,isSend: false)) + } + + @objc func feedbackAction(){ + App.shared.goToPage(FeedbackCommitVC()) + } + @objc func chatAction(){ + App.shared.popToRootPage() + App.shared.tabController?.selectedIndex = 3 + + } +} diff --git a/ShenYin/ShenYin/UI/Mine/Feedback/QaModel.swift b/ShenYin/ShenYin/UI/Mine/Feedback/QaModel.swift new file mode 100644 index 0000000..c9b4af2 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Feedback/QaModel.swift @@ -0,0 +1,56 @@ +// +// QaModel.swift +// ShenYin +// +// Created by liangshi on 2025/10/16. +// + +import HandyJSON + +class QaCategoryModelRoot:ResponseBaseModel { + var data = [QaCategoryModel]() +} +class QaCategoryModel:HandyJSON { + var id = "" + var name = "" + required public init() { } +} + + +class QaModelListModelroot:ResponseBaseModel { + var data = QaModelListData() +} +class QaModelListData:ResponseBaseModel { + var list = [QaModelListModel]() + var total = 0 + var pageSize = 0 + var currentPage = 0 + var totalPage = 0 + var hasNext = false + var hasPre = false + + required public init() { } +} +class QaModelListModel:HandyJSON { + var id = "" + var title = "" + var content = "" + var categoryId = "" + + required public init() { } +} + + + +class FeedbackHistoryRoot:ResponseBaseModel { + var data = [FeedbackHistoryModel]() +} +class FeedbackHistoryModel:HandyJSON { + var id = "" + var type = "" + var description = "" + var images = "" + var phone = "" + var createTime = "" + required public init() { } +} diff --git a/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsDetailVC.swift b/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsDetailVC.swift new file mode 100644 index 0000000..eab06cc --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsDetailVC.swift @@ -0,0 +1,208 @@ +// +// Untitled.swift +// ShenYin +// +// Created by liangshi on 2025/10/15. +// + +import UIKit +import WebKit + + +final class InstructionsDetailVC: BaseVC { + let webView = BaseWebView() + private let progressView = UIProgressView(progressViewStyle: .default) + + private var productId: String + init(productId: String) { + self.productId = productId + super.init() + } + + override func setupViews() { + + navBar.title = "电子说明书" + + view.addSubview(webView) + webView.addSubview(progressView) + + view.backgroundColor = .color(.bgColor) + webView.navigationDelegate = self + webView.uiDelegate = self + webView.backgroundColor = .color(.bgColor) + + webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil) + webView.addObserver(self, forKeyPath: "canGoBack", options: .new, context: nil) + webView.addObserver(self, forKeyPath: "title", options: .new, context: nil) + webView.evaluateJavaScript("document.getElementsByTagName('body')[0].style.background='#FAFAFA'", completionHandler: nil) + + /// 进度条 + progressView.trackTintColor = .clear + progressView.progressTintColor = .color(.theme) + progressView.isHidden = false + progressView.setProgress(0.05, animated: true) + } + override func setupLayout() { + webView.snp.makeConstraints { (m) in + m.top.equalToSuperview().inset(kNavBtm) + m.bottom.equalToSuperview() + m.leading.trailing.equalToSuperview() + } + progressView.snp.makeConstraints { (m) in + m.top.leading.trailing.equalToSuperview() + m.height.equalTo(2) + } + } + + override func setupData() { + let api = CommomApi.productBook(productId: productId) + HttpClient.request(api) {[weak self] (model:InstructionsBookRoot,res) in + guard let self = self else {return} + if model.isSuccess{ + self.dowmload(url: model.data) + } + } + } + func dowmload(url:String){ + HttpClient.download(url: url){[weak self] filePath in + guard let self = self else {return} + if let path = filePath{ + let url = URL(fileURLWithPath: path) + let request = URLRequest(url: url) + webView.load(request) + } + } + } + + func loadWebData(){ +// /// 加载URL +// if let requestUrl = initData.urlStr.yc.asUrl { +// let request = URLRequest(url: requestUrl) +// webView.load(request) +// } +// else if let request = initData.request { +// webView.load(request) +// } +// else { return } + } + + override func navleftViewTapped() { + if webView.canGoBack { + webView.goBack() + } + else{ + if let _ = self.presentingViewController { + self.dismiss(animated: true, completion: nil) + } else if let nav = self.navigationController { + nav.popViewController(animated: true) + } + } + + } + override func navRightViewTapped() { + if let _ = self.presentingViewController { + self.dismiss(animated: true, completion: nil) + } else if let nav = self.navigationController { + nav.popViewController(animated: true) + } + } + + deinit { + webView.removeObserver(self, forKeyPath: "canGoBack") + webView.removeObserver(self, forKeyPath: "estimatedProgress") + webView.removeObserver(self, forKeyPath: "title") + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + if keyPath == "canGoBack" { + if webView.canGoBack { + self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true + } else { + self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false + } + } else if keyPath == "estimatedProgress" { + progressView.alpha = CGFloat(1.0 - webView.estimatedProgress) + 0.2 + let progerss = max(Float(webView.estimatedProgress), 0.1) + progressView.setProgress(progerss, animated: true) + if webView.estimatedProgress >= 1.0 { + kDelay(0.3) { + self.progressView.alpha = 0.0 + self.progressView.setProgress(0.0, animated: false) + } + } + }else if keyPath == "title" { + navBar.title = webView.title ?? " " + + } else { + super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) + } + } +} + +// MARK: - ********* webview delegate +extension InstructionsDetailVC: WKNavigationDelegate { + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + webView.evaluateJavaScript( + "document.getElementsByTagName('body')[0].style.background='#FAFAFA'", + completionHandler: nil) + } + func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + k_log("==== error: \(error)") + } + func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + k_log("==== error: \(error)") + } + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if (navigationAction.targetFrame == nil) { + webView.load(navigationAction.request) + } + guard let policy = WKNavigationActionPolicy(rawValue: WKNavigationActionPolicy.allow.rawValue + 2) + else { decisionHandler(.allow); return } + decisionHandler(policy) + } +} + +// MARK: - WKUIDelegate 不实现该代理方法 网页内调用弹窗时会抛出异常,导致程序崩溃 +extension InstructionsDetailVC: WKUIDelegate { + // 获取js 里面的提示 + func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { + if self.navigationController?.visibleViewController != self { + completionHandler() + return + } + let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in + completionHandler() + })) + alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in + completionHandler() + })) + self.present(alert, animated: true, completion: nil) + } + + // js 信息的交流 + func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { + let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in + completionHandler(true) + })) + alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in + completionHandler(false) + })) + self.present(alert, animated: true, completion: nil) + } + + // 交互。可输入的文本。 + func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) { + let alert = UIAlertController(title: prompt, message: defaultText, preferredStyle: .alert) + alert.addTextField { (textField: UITextField) -> Void in + textField.textColor = UIColor.red + } + alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in + completionHandler(alert.textFields![0].text!) + })) + self.present(alert, animated: true, completion: nil) + } +} + diff --git a/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsModel.swift b/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsModel.swift new file mode 100644 index 0000000..1d0ab11 --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsModel.swift @@ -0,0 +1,27 @@ +// +// Untitled.swift +// ShenYin +// +// Created by liangshi on 2025/10/15. +// + +import HandyJSON + +class InstructionsModelRoot:ResponseBaseModel { + var data = [InstructionsModel]() +} +class InstructionsModel:HandyJSON { + var id = "" + var managerId = "" + var name = "" + var image = "" + var description = "" + var deleted = "" + var createTime = "" + var updateTime = "" + + required public init() { } +} +class InstructionsBookRoot:ResponseBaseModel { + var data = "" +} diff --git a/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsVC.swift b/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsVC.swift new file mode 100644 index 0000000..b11bdbd --- /dev/null +++ b/ShenYin/ShenYin/UI/Mine/Instructions/InstructionsVC.swift @@ -0,0 +1,73 @@ +// +// InstructionsVC.swift +// ShenYin +// +// Created by liangshi on 2025/8/26. +// + +import UIKit +class InstructionsVC: BaseVC{ + let tableView = UITableView(frame: .zero, style: .plain) + var list = [InstructionsModel]() + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + override func setupViews() { + self.navBar.title = "电子说明书" + tableView.do { v in + v.backgroundColor = .color(.bgColor) + v.delegate = self + v.dataSource = self + v.rowHeight = 52 + v.sectionHeaderHeight = 52 + v.separatorStyle = .none + v.register(CustomCell1.self, forCellReuseIdentifier: CustomCell1.reuseID) + v.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: kScreenHei, height: 20)) + } + + view.addSubview(tableView) + } + override func setupLayout() { + tableView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalTo(kNavBtm) + } + } + override func setupData() { + let api = CommomApi.getProductList + HttpClient.request(api) {[weak self] (model:InstructionsModelRoot,res) in + guard let self = self else {return} + if model.isSuccess{ + self.list = model.data + self.tableView.reloadData() + } + } + } +} + +extension InstructionsVC:UITableViewDelegate,UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return list.count + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = CustomCell1.cell(withTableView: tableView, indexPath: indexPath) + cell.titleLabel.text = list[indexPath.row].name + let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 52) + if indexPath.row == 0 { + cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 12, height: 12)) + } + else if indexPath.row == list.count - 1{ + cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 12, height: 12)) + } + else{ + cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0)) + } + return cell + } + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let data = list[indexPath.row] + App.shared.goToPage(InstructionsDetailVC(productId: data.id)) + } +} diff --git a/ShenYin/ShenYin/UI/Mine/MoreSetVC.swift b/ShenYin/ShenYin/UI/Mine/MoreSetVC.swift index f456ff3..f2d66de 100644 --- a/ShenYin/ShenYin/UI/Mine/MoreSetVC.swift +++ b/ShenYin/ShenYin/UI/Mine/MoreSetVC.swift @@ -8,7 +8,7 @@ import UIKit class MoreSetVC: BaseVC{ let tableView = UITableView(frame: .zero, style: .plain) - let list:[CustomCellType] = [.notice,.language] + let list:[CustomCellType] = [.notice,.system] let switchBtn = CustomButton() let logoutBtn = CustomButton() @@ -52,12 +52,12 @@ class MoreSetVC: BaseVC{ make.height.equalTo(55) } logoutBtn.snp.makeConstraints { make in - make.bottom.equalTo(deactivateBtn.snp.top).offset(-20) + make.bottom.equalTo(deactivateBtn.snp.top).offset(-10) make.left.right.equalToSuperview().inset(18) make.height.equalTo(55) } switchBtn.snp.makeConstraints { make in - make.bottom.equalTo(logoutBtn.snp.top).offset(-20) + make.bottom.equalTo(logoutBtn.snp.top).offset(-10) make.left.right.equalToSuperview().inset(18) make.height.equalTo(55) } @@ -84,6 +84,18 @@ class MoreSetVC: BaseVC{ } } } + + //MARK: 跳转到APP系统设置权限界面 + func jumpToSystemPrivacySetting() { + guard let appSetting = URL(string: UIApplication.openSettingsURLString) else { + return + } + if #available(iOS 10, *) { + UIApplication.shared.open(appSetting, options: [:], completionHandler: nil) + } else { + UIApplication.shared.openURL(appSetting) + } + } } extension MoreSetVC:UITableViewDelegate,UITableViewDataSource { @@ -108,8 +120,8 @@ extension MoreSetVC:UITableViewDelegate,UITableViewDataSource { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let data = list[indexPath.row] switch data { - case .language: - App.shared.goToPage(LanguageVC()) + case .system: + jumpToSystemPrivacySetting() case .notice: // App.shared.goToPage(SetPhoneVC()) break diff --git a/ShenYin/ShenYin/UI/Mine/Root/MineCell.swift b/ShenYin/ShenYin/UI/Mine/Root/MineCell.swift index e4f3286..ee2c094 100644 --- a/ShenYin/ShenYin/UI/Mine/Root/MineCell.swift +++ b/ShenYin/ShenYin/UI/Mine/Root/MineCell.swift @@ -10,6 +10,7 @@ import UIKit public enum MineCellType: Int { case instructions case update + case language case more case feeback case about @@ -20,6 +21,8 @@ public enum MineCellType: Int { return "电子说明书" case .update: return "固件升级" + case .language: + return "语言设置" case .more: return "更多设置" case .feeback: @@ -34,6 +37,8 @@ public enum MineCellType: Int { return "mine_cell_instru" case .update: return "mine_cell_update" + case .language: + return "mine_cell_lan" case .more: return "mine_cell_more" case .feeback: diff --git a/ShenYin/ShenYin/UI/Mine/Root/MineVC.swift b/ShenYin/ShenYin/UI/Mine/Root/MineVC.swift index 1025bb4..0357c07 100644 --- a/ShenYin/ShenYin/UI/Mine/Root/MineVC.swift +++ b/ShenYin/ShenYin/UI/Mine/Root/MineVC.swift @@ -7,7 +7,7 @@ import UIKit class MineVC: BaseVC{ let tableView = UITableView(frame: .zero, style: .plain) - let list:[MineCellType] = [.instructions,.update,.more,.feeback,.about] + let list:[MineCellType] = [.instructions,.update,.language,.more,.feeback,.about] let headerView = MineHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 266)) override func viewDidLoad() { @@ -74,6 +74,8 @@ extension MineVC:UITableViewDelegate,UITableViewDataSource { App.shared.goToPage(InstructionsVC()) case .update: App.shared.goToPage(UpdateVC()) + case .language: + App.shared.goToPage(LanguageVC()) case .more: App.shared.goToPage(MoreSetVC()) case .feeback: diff --git a/ShenYin/ShenYin/UI/Mine/UserInfo/CustomCell1.swift b/ShenYin/ShenYin/UI/Mine/UserInfo/CustomCell1.swift index 7367ea4..a5f0957 100644 --- a/ShenYin/ShenYin/UI/Mine/UserInfo/CustomCell1.swift +++ b/ShenYin/ShenYin/UI/Mine/UserInfo/CustomCell1.swift @@ -22,7 +22,7 @@ public enum CustomCellType: Int { case privacyPolicy case notice - case language + case system case deregister @@ -55,8 +55,8 @@ public enum CustomCellType: Int { case .notice: return "系统消息通知" - case .language: - return "语言设置" + case .system: + return "系统权限管理" case .deregister: return "注销账号" diff --git a/ShenYin/ShenYin/UI/Mode/ModeControView.swift b/ShenYin/ShenYin/UI/Mode/ModeControView.swift index 22a4586..7874e36 100644 --- a/ShenYin/ShenYin/UI/Mode/ModeControView.swift +++ b/ShenYin/ShenYin/UI/Mode/ModeControView.swift @@ -130,7 +130,6 @@ class ModeControView: BaseView { titleLabel.do { (v) in v.textColor = .rgb(0x666666) v.font = .regular(12) - v.text = "降噪" } } diff --git a/ShenYin/ShenYin/UI/Sleep/MusicModel.swift b/ShenYin/ShenYin/UI/Sleep/MusicModel.swift index 8bc1034..8b72ba5 100644 --- a/ShenYin/ShenYin/UI/Sleep/MusicModel.swift +++ b/ShenYin/ShenYin/UI/Sleep/MusicModel.swift @@ -29,6 +29,6 @@ class MusicModel:HandyJSON { var categoryId = "" required public init() { } } - class MusicDownloadModel:ResponseBaseModel { - var data = "" - } +class MusicDownloadModel:ResponseBaseModel { + var data = "" +} diff --git a/ShenYin/ShenYin/UI/common/ImagePickerManager.swift b/ShenYin/ShenYin/UI/common/ImagePickerManager.swift index 47e82e0..b5a14b7 100644 --- a/ShenYin/ShenYin/UI/common/ImagePickerManager.swift +++ b/ShenYin/ShenYin/UI/common/ImagePickerManager.swift @@ -40,7 +40,20 @@ class ImagePickerManager: NSObject, TZImagePickerControllerDelegate { picker?.modalPresentationStyle = .overFullScreen viewController.present(picker!, animated: true, completion: nil) } - + func showImagePicker2(from viewController: UIViewController, callback: @escaping ImagePickerCallback) { + self.imageCallback = callback + + let picker = TZImagePickerController(maxImagesCount: 1, delegate: self) +// picker?.needCircleCrop = true +// picker?.circleCropRadius = Int(UIScreen.main.bounds.size.width/2) +// picker?.allowCrop = true + picker?.showSelectBtn = false + picker?.allowPickingOriginalPhoto = false + picker?.allowPickingVideo = false + picker?.allowPickingImage = true + picker?.modalPresentationStyle = .overFullScreen + viewController.present(picker!, animated: true, completion: nil) + } // MARK: - 视频选择 func showVideoPicker(from viewController: UIViewController, callback: @escaping VideoPickerCallback) { self.videoCallback = callback diff --git a/ShenYin/ShenYin/UI/common/PlaceHolderTextView.swift b/ShenYin/ShenYin/UI/common/PlaceHolderTextView.swift index 8e08442..7b4c6d0 100644 --- a/ShenYin/ShenYin/UI/common/PlaceHolderTextView.swift +++ b/ShenYin/ShenYin/UI/common/PlaceHolderTextView.swift @@ -72,3 +72,82 @@ class PlaceHolderTextView: BaseView { textView.scrollRangeToVisible(range) } } +class PlaceHolderTextView2: BaseView,UITextViewDelegate { + let bgView = UIView() + let textView = UITextView() + let label = UILabel() + + var placeHolde:String?{ + didSet{ + label.text = placeHolde + } + } +// var text:String?{ +// didSet{ +// textView.text = text +// if let text = text,text.isNotEmpty { +// label.isHidden = true +// return +// } +// label.isHidden = false +// } +// } + + override func setupViews() { + backgroundColor = .yellow + label.do { v in + v.backgroundColor = .clear + v.textAlignment = .left + v.textColor = .hexString("#999999") + v.font = .regular(14) + v.numberOfLines = 0 +// v.backgroundColor = .red + } + textView.do { v in + v.isEditable = true + v.font = .regular(14) + v.textColor = .hexString("#121212") + v.backgroundColor = .clear + v.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) +// v.backgroundColor = .green + v.delegate = self + v.returnKeyType = .done + } + addSubviews([bgView]) + addSubviews([textView,label]) + } + + + deinit { + NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: nil) + } + override func setupLayout() { + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + label.snp.makeConstraints { make in + make.left.top.equalToSuperview().inset(6) + make.right.lessThanOrEqualToSuperview() + } + textView.snp.makeConstraints { make in + // make.left.right.equalToSuperview().inset(18) + // make.top.bottom.equalToSuperview().inset(18) + make.edges.equalToSuperview() + } + } + + func scrollToBottom(){ + let range = NSMakeRange(textView.text.count - 1, 1) + textView.scrollRangeToVisible(range) + } + func textViewDidChange(_ textView: UITextView) { + label.isHidden = textView.text.isNotEmpty + } + func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { + if text == "\n" { + textView.resignFirstResponder() + return false + } + return true + } +}