Commit cbc2c9e7 authored by Steven杜宇's avatar Steven杜宇

Merge branch 'AI-1212' into yinhe-live-1212

# Conflicts:
#	galaxy/Podfile
#	galaxy/galaxy.xcodeproj/project.pbxproj
#	galaxy/galaxy/Classes/Modules/Login(登录)/Server/YHLoginManager.swift
#	galaxy/galaxy/Classes/Tools/Helper/YhConstant.swift
#	galaxy/galaxy/Classes/Tools/NetWork/YHAllApiName.swift
parents 22485f1c b67ba8f7
...@@ -115,7 +115,10 @@ target 'galaxy' do ...@@ -115,7 +115,10 @@ target 'galaxy' do
pod 'AliyunLogProducer', '4.3.3' pod 'AliyunLogProducer', '4.3.3'
#加密 #加密
pod 'xxtea', '1.0.2' pod 'xxtea', '1.0.2'
end #Realm
pod 'RealmSwift', '20.0.0'
pod 'Realm', '20.0.0'
end
post_install do |installer| post_install do |installer|
......
This diff is collapsed.
...@@ -25,8 +25,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, WXApiDelegate { ...@@ -25,8 +25,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, WXApiDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Thread.sleep(forTimeInterval: 0.5) // 应产品同学Nick要求 启动页时间展示长点 Thread.sleep(forTimeInterval: 0.5) // 应产品同学Nick要求 启动页时间展示长点
setupAudionConfig() setupAudionConfig()
//初始化 神策sdk //初始化 神策sdk
...@@ -217,27 +216,9 @@ extension AppDelegate { ...@@ -217,27 +216,9 @@ extension AppDelegate {
//1.设置HomePageView为主窗口 //1.设置HomePageView为主窗口
func setupRootVCWithTabBar() { func setupRootVCWithTabBar() {
let tabBarController = YHTabBarViewController()
let homeVC = YHHomeHoldViewPageViewController()
tabBarController.delegate = homeVC
let v0 = YHNavigationController(rootVC:homeVC)
let v1 = YHNavigationController(rootVC:YHServiceCenterViewController())
let v2 = YHNavigationController(rootVC:YHCommunityViewController())
let v3 = YHNavigationController(rootVC:YHMyViewController())
v0.tabBarItem = ESTabBarItem.init(YHHomeLottieAnimateContentView(),title: "首页", image: UIImage(named: "home"), selectedImage: UIImage(named: "home_1"))
v1.tabBarItem = ESTabBarItem.init(YHServiceLottieAnimateContentView(),title: "服务", image: UIImage(named: "service"), selectedImage: UIImage(named: "service_1"))
v2.tabBarItem = ESTabBarItem.init(YHCommunityLottieAnimateContentView(),title: "朋友", image: UIImage(named: "msg"), selectedImage: UIImage(named: "msg_1"))
v3.tabBarItem = ESTabBarItem.init(YHMyLottieAnimateContentView(),title: "我的", image: UIImage(named: "me"), selectedImage: UIImage(named: "me_1"))
tabBarController.viewControllers = [v0,v1,v2,v3]
tabBarController.tabBar.backgroundColor = .white
window = UIWindow(frame: UIScreen.main.bounds) window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = tabBarController window?.rootViewController = configTabBarController()
window?.makeKeyAndVisible() window?.makeKeyAndVisible()
if YHLoginManager.shared.needJumpToMsgTabFlag { if YHLoginManager.shared.needJumpToMsgTabFlag {
......
//
// YHAIViewController.swift
// galaxy
//
// Created by Dufet on 2024/11/23.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import Alamofire
class YHAIViewController: YHBaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func requestData() {
// AF.request("http://192.168.52.250:9898/stream")
// .responseStream { response in
// switch response.result {
// case .success(let stream):
// for line in stream {
// print("Received line: \(line)")
// }
// case .failure(let error):
// print("Error: \(error)")
// }
// }
}
}
...@@ -76,6 +76,7 @@ class YHTabBarViewController: ESTabBarController { ...@@ -76,6 +76,7 @@ class YHTabBarViewController: ESTabBarController {
NotificationCenter.default.addObserver(self, selector: #selector(clearFriendTabBadge), name: YhConstant.YhNotification.didMarkAllMessagesReadedNotifiction, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(clearFriendTabBadge), name: YhConstant.YhNotification.didMarkAllMessagesReadedNotifiction, object: nil)
} }
@objc func getTotalUnreadMsgCount() { @objc func getTotalUnreadMsgCount() {
...@@ -102,8 +103,8 @@ class YHTabBarViewController: ESTabBarController { ...@@ -102,8 +103,8 @@ class YHTabBarViewController: ESTabBarController {
} }
func showFriendTabRedBadgeNumber(_ num: Int) { func showFriendTabRedBadgeNumber(_ num: Int) {
if let vcs = self.viewControllers, vcs.count > 2 { if let vcs = self.viewControllers, vcs.count > 3 {
let friendVC = vcs[2] let friendVC = vcs[3]
if let tabBarItem = friendVC.tabBarItem as? ESTabBarItem { if let tabBarItem = friendVC.tabBarItem as? ESTabBarItem {
// badgeValue 空字符串会显示小红点 nil则隐藏 // badgeValue 空字符串会显示小红点 nil则隐藏
var badge: String? = nil var badge: String? = nil
......
//
// YHAITabBarItem.swift
// galaxy
//
// Created by Dufet on 2024/11/26.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import ESTabBarController_swift
class YHAITabBarItemContentView: ESTabBarItemContentView {
lazy var bottomTitleLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.mainTextColor
label.textAlignment = .center
label.font = UIFont.PFSC_R(ofSize:10)
label.text = "港小宝"
return label
}()
lazy var iconImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "tab_AI"))
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.removeSubviews()
self.addSubview(iconImgView)
self.addSubview(bottomTitleLabel)
bottomTitleLabel.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(14)
}
iconImgView.snp.makeConstraints { make in
make.width.height.equalTo(48.0)
make.bottom.equalTo(bottomTitleLabel.snp.top)
make.centerX.equalToSuperview()
}
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func updateLayout() {
super.updateLayout()
}
}
...@@ -10,13 +10,18 @@ import UIKit ...@@ -10,13 +10,18 @@ import UIKit
class YHAutoTextView: UITextView, UITextViewDelegate { class YHAutoTextView: UITextView, UITextViewDelegate {
var textChange:((String)->())?
override open var text: String! { override open var text: String! {
didSet { didSet {
textViewDidChange(self)
self.setNeedsLayout() self.setNeedsLayout()
self.layoutIfNeeded() self.layoutIfNeeded()
} }
} }
let maxHeight = 60.0
static let verticalGap = 5.0
var placeHolder: String = "" { var placeHolder: String = "" {
didSet { didSet {
placeholderLabel.text = placeHolder placeholderLabel.text = placeHolder
...@@ -26,21 +31,19 @@ class YHAutoTextView: UITextView, UITextViewDelegate { ...@@ -26,21 +31,19 @@ class YHAutoTextView: UITextView, UITextViewDelegate {
let placeholderLabel: UILabel = { let placeholderLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor.lightGray label.textColor = UIColor.init(hex: 0xB3C8E9)
label.font = UIFont.PFSC_R(ofSize: 15) label.font = UIFont.PFSC_R(ofSize: 14)
return label return label
}() }()
override init(frame: CGRect, textContainer: NSTextContainer?) { override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer) super.init(frame: frame, textContainer: textContainer)
self.font = .PFSC_R(ofSize: 14)
delegate = self delegate = self
isScrollEnabled = false // 禁止滚动 isScrollEnabled = false // 禁止滚动
translatesAutoresizingMaskIntoConstraints = false
clearsOnInsertion = true
self.addSubview(placeholderLabel) self.addSubview(placeholderLabel)
placeholderLabel.snp.makeConstraints { make in placeholderLabel.snp.makeConstraints { make in
make.top.equalTo(5) make.center.equalToSuperview()
make.left.equalTo(5) make.left.equalTo(5)
make.right.equalTo(-5) make.right.equalTo(-5)
} }
...@@ -55,11 +58,41 @@ class YHAutoTextView: UITextView, UITextViewDelegate { ...@@ -55,11 +58,41 @@ class YHAutoTextView: UITextView, UITextViewDelegate {
// 更新自身的高度 // 更新自身的高度
invalidateIntrinsicContentSize() invalidateIntrinsicContentSize()
placeholderLabel.isHidden = !textView.text.isEmpty placeholderLabel.isHidden = !textView.text.isEmpty
textChange?(textView.text)
} }
override var intrinsicContentSize: CGSize { override var intrinsicContentSize: CGSize {
// 计算内容的尺寸 // 计算内容的尺寸
// var height = self.getHeight(text: self.text, font: self.font!, width: frame.width)
// if height < 20.0 {
// height = 20.0
// }
// // 加上textView周边的缝隙
// height += 15.0
let size = sizeThatFits(CGSize(width: frame.width, height: .greatestFiniteMagnitude)) let size = sizeThatFits(CGSize(width: frame.width, height: .greatestFiniteMagnitude))
return CGSize(width: size.width, height: size.height) var height = size.height
isScrollEnabled = height > maxHeight
if height > maxHeight {
height = maxHeight
self.snp.updateConstraints { make in
make.top.equalTo(11)
make.bottom.equalTo(-11)
}
} else {
self.snp.updateConstraints { make in
make.top.equalTo(11-Self.verticalGap)
make.bottom.equalTo(-(11-Self.verticalGap))
}
}
return CGSize(width: size.width, height: height)
}
func getHeight(text:String, font:UIFont, width:CGFloat)->CGFloat {
let size = CGSize.init(width:width , height: CGFloat(MAXFLOAT))
let dic = [NSAttributedString.Key.font: font]
let strSize = text.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: dic, context:nil).size
return CGSizeMake(strSize.width, ceil(strSize.height)).height
} }
} }
//
// YHAIChatUIConfiguration.swift
// galaxy
//
// Created by Dufet on 2024/11/29.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIChatConfiguration {
static let defaultConfig = YHAIChatConfiguration()
var disableHandleMessage: Bool = false
func registerMessageGroupCells(_ tableView: UITableView) {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "UITableViewCell")
tableView.register(YHAITextMessageCell.self, forCellReuseIdentifier: YHAITextMessageCell.cellReuseIdentifier)
tableView.register(YHAIThinkingMessageCell.self, forCellReuseIdentifier: YHAIThinkingMessageCell.cellReuseIdentifier)
tableView.register(YHProductListMessageCell.self, forCellReuseIdentifier: YHProductListMessageCell.cellReuseIdentifier)
tableView.register(YHFixProductListMessageCell.self, forCellReuseIdentifier: YHFixProductListMessageCell.cellReuseIdentifier)
tableView.register(YHCardMessageCell.self, forCellReuseIdentifier: YHCardMessageCell.cellReuseIdentifier)
tableView.register(YHAIPictureMessageCell.self, forCellReuseIdentifier: YHAIPictureMessageCell.cellReuseIdentifier)
}
func handleReceiveMessage(_ res: YHAIChatMessage?, _ done: Bool, _ messages: inout [YHAIChatMessage]) {
if disableHandleMessage {
for msg in messages {
msg.isDone = true
}
return
}
// 去除loading消息
removeThinkingMessageFromChatList(&messages)
if let res = res {
var find = false
for msg in messages {
if msg.uuid == res.uuid {
if msg.isNeedSpiceMessage(), res.isNeedSpiceMessage() {
// 多个文字需要拼接
find = true
msg.body.contentText += res.body.contentText
msg.updateBodyToData()
}
}
}
if !find {
messages.append(res)
}
if done { // 思考完成
for msg in messages {
msg.isDone = true
}
}
}
}
func removeThinkingMessageFromChatList( _ messages: inout [YHAIChatMessage]) {
var findIndex = -1
for (index, msg) in messages.enumerated() {
if msg.getType() == .thinking {
findIndex = index
}
}
if findIndex != -1 {
messages.remove(at: findIndex)
}
}
}
//
// YHAIServiceListViewController.swift
// galaxy
//
// Created by Dufet on 2024/11/26.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import JXSegmentedView
import IQKeyboardManagerSwift
class YHAIServiceListViewController: YHBaseViewController {
var serviceArr: [YHEntranceconfigModel] = []
let viewModel = YHAIViewModel()
let manager = YHAIRequestManager()
lazy var collectionView: UICollectionView = {
let flowLayout = UICollectionViewFlowLayout()
flowLayout.minimumInteritemSpacing = 10.0
flowLayout.minimumLineSpacing = 28.0
flowLayout.scrollDirection = .vertical
let collectView = UICollectionView(frame:.zero, collectionViewLayout: flowLayout)
collectView.backgroundColor = .clear
collectView.delegate = self
collectView.dataSource = self
collectView.register(YHAIProductCell.self, forCellWithReuseIdentifier: YHAIProductCell.cellReuseIdentifier)
collectView.register(YHAIGreetCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: YHAIGreetCollectionReusableView.reuseIdentifier)
collectView.contentInset = .zero
return collectView
}()
lazy var bottomInputView: UIView = {
let v = UIView()
let whiteView = UIView()
whiteView.backgroundColor = .white
whiteView.layer.cornerRadius = 12.0
v.addSubview(whiteView)
let label = UILabel()
label.font = .PFSC_R(ofSize: 14)
label.text = "有什么问题尽管问我"
label.textColor = .init(hex: 0xB3C8E9)
whiteView.addSubview(label)
let sendImgV = UIImageView(image: UIImage(named: "ai_chat_send_gray"))
whiteView.addSubview(sendImgV)
let btn = UIButton()
btn.addTarget(self, action: #selector(didInputButtonClicked), for: .touchUpInside)
whiteView.addSubview(btn)
whiteView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
label.snp.makeConstraints { make in
make.left.equalTo(16)
make.height.equalTo(20)
make.centerY.equalToSuperview()
}
sendImgV.snp.makeConstraints { make in
make.right.equalTo(-16)
make.width.height.equalTo(24)
make.centerY.equalToSuperview()
}
btn.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return v
}()
@objc func didInputButtonClicked() {
NotificationCenter.default.post(name: YhConstant.YhNotification.didSwitchToAIChatNotification, object: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
gk_navBarAlpha = 0
gk_navigationBar.isHidden = true
IQKeyboardManager.shared.enable = false
view.backgroundColor = .clear
view.addSubview(collectionView)
view.addSubview(bottomInputView)
collectionView.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalToSuperview()
make.bottom.equalTo(bottomInputView.snp.top).offset(-8)
}
bottomInputView.snp.makeConstraints { make in
make.left.equalTo(20)
make.right.equalTo(-20)
make.height.equalTo(46)
make.bottom.equalTo(-10-k_Height_safeAreaInsetsBottom())
}
}
}
extension YHAIServiceListViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
// 返回单元格数量
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return serviceArr.count
}
// 返回每个单元格的大小
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = floor((KScreenWidth-16.0*2.0-10.0)/2.0)
let height = width * (200.0/166.0)
return CGSize(width: width, height: height)
}
// 返回自定义单元格
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: YHAIProductCell.cellReuseIdentifier, for: indexPath) as! YHAIProductCell
if 0 <= indexPath.item && indexPath.item < serviceArr.count {
let model = serviceArr[indexPath.item]
cell.model = model
// 根据索引设置旋转
cell.rotateToRight(indexPath.item % 2 == 0)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if 0 <= indexPath.item && indexPath.item < serviceArr.count {
let model = serviceArr[indexPath.item]
YHHUD.show(.progress(message: "加载中..."))
self.manager.getMainChatConversationId {
sesseionId in
YHHUD.hide()
let vc = YHAIRobotChatViewController()
vc.robotId = model.botId
vc.conversationId = sesseionId
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let headerView: YHAIGreetCollectionReusableView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: YHAIGreetCollectionReusableView.reuseIdentifier, for: indexPath) as! YHAIGreetCollectionReusableView
headerView.updateGreetingText()
return headerView
}
return UICollectionReusableView()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection:Int) -> CGSize {
return CGSize(width: KScreenWidth, height: 177)
}
}
extension YHAIServiceListViewController: JXSegmentedListContainerViewListDelegate {
func listView() -> UIView {
return view
}
}
//
// YHAITabViewController.swift
// galaxy
//
// Created by Dufet on 2024/11/26.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import JXSegmentedView
import IQKeyboardManagerSwift
class YHAITabViewController: YHBaseViewController {
var defaltIndex: Int = 0
let viewModel = YHAIViewModel()
let arrItemTitles = ["港小宝", "对话"]
var arrItemVCs : [YHBaseViewController] = []
lazy var headerImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "ai_product_list_head"))
return v
}()
lazy var bgImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "ai_chat_bg"))
v.isHidden = true
return v
}()
lazy var segmentedView : JXSegmentedView = {
let view = JXSegmentedView(frame: CGRect(x: 0, y: k_Height_safeAreaInsetsTop(), width: KScreenWidth, height: 48))
view.backgroundColor = .clear
return view
}()
lazy var segmentedDataSource: JXSegmentedTitleDataSource = {
let dataSource = JXSegmentedTitleDataSource()
dataSource.isTitleColorGradientEnabled = true
dataSource.titles = arrItemTitles
dataSource.titleNormalFont = UIFont.PFSC_M(ofSize: 16)
dataSource.titleNormalColor = UIColor.init(hex:0x778FB4)
dataSource.titleSelectedFont = UIFont(name: "AlimamaShuHeiTi-Bold", size: 18)
dataSource.titleSelectedColor = .mainTextColor
dataSource.isItemSpacingAverageEnabled = false
dataSource.itemWidth = JXSegmentedViewAutomaticDimension
dataSource.itemSpacing = 28.0
return dataSource
}()
//分类title 所对应的VC
lazy var listContainerView: JXSegmentedListContainerView! = {
let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView)
view.scrollView.isScrollEnabled = false
view.backgroundColor = .clear
return view
}()
lazy var backBtn: UIButton = {
let btn = UIButton()
btn.setImage(UIImage(named: "back_icon"), for: .normal)
btn.YH_clickEdgeInsets = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
btn.addTarget(self, action: #selector(didBackBtnClicked), for: .touchUpInside)
return btn
}()
lazy var listVC: YHAIServiceListViewController = {
let vc = YHAIServiceListViewController()
return vc
}()
lazy var mainChatVC: YHAIMainChatViewController = {
let vc = YHAIMainChatViewController()
return vc
}()
@objc func didBackBtnClicked() {
self.navigationController?.popViewController(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .init(hex:0xDEECFE)
gk_navBarAlpha = 0
gk_navigationBar.isHidden = true
createUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
requestList()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func createUI() {
IQKeyboardManager.shared.enable = false
NotificationCenter.default.addObserver(self, selector: #selector(didJumoToAIChat), name: YhConstant.YhNotification.didSwitchToAIChatNotification, object: nil)
view.addSubview(bgImgView)
view.addSubview(headerImgView)
arrItemVCs.removeAll()
for i in 0..<arrItemTitles.count {
if i == 0 { // 银河AI
arrItemVCs.append(listVC)
} else if i == 1 { // 对话
arrItemVCs.append(mainChatVC)
}
}
//segmentedViewDataSource一定要通过属性强持有!!!!!!!!!
segmentedView.dataSource = segmentedDataSource
view.addSubview(segmentedView)
segmentedView.listContainer = listContainerView
view.addSubview(listContainerView)
//分类Title
segmentedView.dataSource = segmentedDataSource
segmentedView.delegate = self
//配置指示器
let indicator = YHAITabIndicatorView()
indicator.indicatorWidth = 34
indicator.indicatorHeight = 14
indicator.indicatorCornerRadius = 0.0
indicator.verticalOffset = 5
segmentedView.indicators = [indicator]
segmentedView.defaultSelectedIndex = defaltIndex
view.addSubview(backBtn)
backBtn.snp.makeConstraints { make in
make.left.equalTo(16)
make.width.height.equalTo(21)
make.centerY.equalTo(segmentedView)
}
bgImgView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
headerImgView.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
make.height.equalTo(269)
}
let segmentHeight = 48.0
segmentedView.snp.makeConstraints { make in
make.left.equalTo(61-25)
make.right.equalToSuperview()
make.top.equalTo(k_Height_safeAreaInsetsTop())
make.height.equalTo(segmentHeight)
}
listContainerView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(k_Height_safeAreaInsetsTop() + segmentHeight)
make.bottom.equalTo(0)
}
}
func requestList() {
YHHUD.show(.progress(message: "加载中..."))
viewModel.getAIEntranceList {
[weak self] success, error in
YHHUD.hide()
guard let self = self else { return }
self.mainChatVC.robotId = self.viewModel.listModel.mainBotId
self.listVC.serviceArr.removeAll()
self.listVC.serviceArr.append(contentsOf: self.viewModel.listModel.entranceConfig)
self.listVC.collectionView.reloadData()
}
}
func jumpToItemIndex(itemIndex : Int) {
self.segmentedView.selectItemAt(index: itemIndex)
}
@objc func didJumoToAIChat() {
jumpToItemIndex(itemIndex: 1)
mainChatVC.bottomInputView.showKeyBoard()
}
}
extension YHAITabViewController: JXSegmentedViewDelegate {
func segmentedView(_ segmentedView: JXSegmentedView, didSelectedItemAt index: Int) {
if segmentedView.selectedIndex == 1 { // AI对话
bgImgView.isHidden = false
headerImgView.isHidden = true
} else { // 港小宝
bgImgView.isHidden = true
headerImgView.isHidden = false
}
}
}
extension YHAITabViewController: JXSegmentedListContainerViewDataSource {
func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
if let titleDataSource = segmentedView.dataSource as? JXSegmentedBaseDataSource {
return titleDataSource.dataSource.count
}
return 0
}
func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate {
return arrItemVCs[index] as! JXSegmentedListContainerViewListDelegate
}
}
//
// YHAIChatDataBaseManager.swift
// galaxy
//
// Created by Dufet on 2024/12/2.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import Realm
import RealmSwift
class YHAIChatDataBaseManager {
static let shared = YHAIChatDataBaseManager()
let dbName = "AI_CHAT_DB.realm"
// 如果要存储的数据模型属性发生变化,需要配置当前版本号比之前大
let dbVersion: UInt64 = 1
init() {
configDataBase()
}
private func configDataBase() {
let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as String
let dbPath = docPath.appending("/\(dbName)")
let config = Realm.Configuration(fileURL: URL.init(string: dbPath), inMemoryIdentifier: nil, encryptionKey: nil, readOnly: false, schemaVersion: dbVersion, migrationBlock: { (migration, oldSchemaVersion) in
}, deleteRealmIfMigrationNeeded: false, shouldCompactOnLaunch: nil, objectTypes: nil)
Realm.Configuration.defaultConfiguration = config
Realm.asyncOpen { result in
switch result {
case let .success(succeed):
print("Realm 服务器配置成功!")
break
case let .failure(error):
print("Realm 数据库配置失败:\(error.localizedDescription)")
break
}
}
}
private func getDB() -> Realm {
let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as String
let dbPath = docPath.appending("/\(dbName)")
/// 传入路径会自动创建数据库
let defaultRealm = try! Realm(fileURL: URL.init(string: dbPath)!)
return defaultRealm
}
func addDBMessages(_ messages: [YHAIChatDBMessage]) {
// 获取 Realm 实例
let defaultRealm = self.getDB()
// 开始写入事务
for message in messages {
let students = getDBMessageBy(uuid: message.uuid)
try! defaultRealm.write {
// 将新对象添加到 Realm 数据库
defaultRealm.add(message, update: students.count > 0 ? .modified : .all)
}
}
}
func addDBMessage(_ message: YHAIChatDBMessage) -> Void {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(message)
}
print(defaultRealm.configuration.fileURL ?? "")
}
/// 获取 所保存的消息
func getDBMessages() -> Results<YHAIChatDBMessage> {
let defaultRealm = self.getDB()
return defaultRealm.objects(YHAIChatDBMessage.self)
}
func getDBMessageBy(uuid: String) -> Results<YHAIChatDBMessage> {
return self.readDBMessages("uuid = '\(uuid)'")
}
func readDBMessages(_ predicate: String) -> Results<YHAIChatDBMessage> {
let defaultRealm = self.getDB()
print(defaultRealm.configuration.fileURL ?? "")
let predicate = NSPredicate(format: predicate)
let results = defaultRealm.objects(YHAIChatDBMessage.self)
return results.filter(predicate)
}
func readHistoryUIMessages() -> [YHAIChatMessage] {
let result = YHAIChatDataBaseManager.shared.getDBMessages()
var arr = [YHAIChatMessage]()
for msg in result {
let model = msg.getMessage()
arr.append(model)
}
return arr
}
}
//
// YHAIChatDataBaseModel.swift
// galaxy
//
// Created by Dufet on 2024/12/2.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import Realm
import RealmSwift
class YHAIChatDataBaseModel: NSObject {
}
class YHAIChatDBMessage: Object {
@objc var uuid: String = ""
@objc dynamic var id: String = ""
@objc dynamic var event: String = ""
@objc dynamic var data: String = ""
@objc dynamic var is_self: Bool = false
@objc dynamic var is_done: Bool = false
//重写 Object.primaryKey() 可以设置模型的主键。
//声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。
//一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。
override static func primaryKey() -> String? {
return "uuid"
}
//重写 Object.ignoredProperties() 可以防止 Realm 存储数据模型的某个属性
override static func ignoredProperties() -> [String] {
// return ["tempID"]
return []
}
//重写 Object.indexedProperties() 方法可以为数据模型中需要添加索引的属性建立索引,Realm 支持为字符串、整型、布尔值以及 Date 属性建立索引。
override static func indexedProperties() -> [String] {
// return ["name"]
return []
}
static func createMessage(_ message: YHAIChatMessage) -> YHAIChatDBMessage {
let msg = YHAIChatDBMessage()
msg.uuid = message.uuid
msg.id = message.id
msg.event = message.event
msg.data = message.data
msg.is_self = message.isSelf
msg.is_done = message.isDone
print("DB WRITE-- \(message)")
return msg
}
func getMessage() -> YHAIChatMessage {
let msg = YHAIChatMessage()
msg.uuid = self.uuid
msg.id = self.id
msg.event = self.event
msg.data = self.data
msg.isSelf = self.is_self
msg.isDone = self.is_done
print("DB READ-- \(msg)")
if let jsonData = self.data.data(using: .utf8) {
do {
let jsonDict = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any]
let dic = (jsonDict ?? [:])
msg.dataDict = dic
if let body = YHAIMessageBody.deserialize(from: dic) {
msg.body = body
}
} catch {
}
}
return msg
}
}
//
// YHAIHistoryMessage.swift
// galaxy
//
// Created by Dufet on 2024/12/3.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import SmartCodable
class YHAIHistoryMessage: SmartCodable {
var botId: String = ""
var chatId: String = ""
var contentText: String = ""
var contentType: Int = 0
var messageId: String = ""
var role: String = ""
var type: String = ""
var cardsInfo: YHAIListinfoModel?
required init() {
}
func convertToChatMessage() -> YHAIChatMessage {
let msg = YHAIChatMessage()
msg.uuid = self.messageId
msg.isSelf = self.role == "user"
msg.isDone = true
let body = YHAIMessageBody()
body.contentType = self.contentType
body.contentText = self.contentText
body.botId = self.botId
body.chatId = self.chatId
body.type = self.type
body.cardsInfo = self.cardsInfo
msg.body = body
msg.setFinished()
msg.updateBodyToData()
return msg
}
}
//
// YHAIListModel.swift
// galaxy
//
// Created by Dufet on 2024/11/27.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import SmartCodable
class YHAIListModel: SmartCodable {
var mainBotId: String = ""
var entranceConfig: [YHEntranceconfigModel] = []
required init() {
}
}
class YHEntranceconfigModel: SmartCodable {
var id: Int = 0
var title: String = ""
var icon: String = ""
var cover: String = ""
var description: String = ""
var btnText: String = ""
var redirectMode: Int = 0
var botId: String = ""
var redirectPath: String = ""
required init() {
}
}
//
// YHAIMessageModel.swift
// galaxy
//
// Created by Dufet on 2024/11/28.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import SmartCodable
class YHAIMessageModel: NSObject {
}
enum YHAIMessageType: Int {
case unknown = 0
case text = 1 // 文字消息
case cardList = 2 // 卡片列表消息
case productList = 3 // 商品列表消息
case picture = 4 // 图片消息
case fixProductList = 5 // 文章列表消息
// 自定义case
case thinking = 9527 // 思考消息
case recommendText = -9527 // 推荐文字消息
}
class YHAIChatMessage: CustomStringConvertible {
var id: String = ""
var event: String = ""
var data: String = ""
var dataDict: [String : Any] = [:]
var uuid: String = ""
var isSelf: Bool = false
var isDone: Bool = false
var body = YHAIMessageBody()
func isFinishd() -> Bool {
if event.isEmpty {
return true
}
if event == "conversation.message.completed" {
return true
}
return false
}
func setFinished() {
event = "conversation.message.completed"
}
func isTextMessage() -> Bool {
let type = self.getType()
return type == .text || type == .recommendText
}
func isNeedSpiceMessage() -> Bool {
let type = self.getType()
return type == .text
}
static func createQuestionMessage(_ text: String) -> YHAIChatMessage {
let question = YHAIChatMessage()
question.isSelf = true
let body = YHAIMessageBody()
body.contentType = 1
body.contentText = text
question.setFinished()
question.body = body
question.uuid = UUID().uuidString + NSDate().timeIntervalSince1970.description
question.updateBodyToData()
return question
}
static func createThinkingMesssage() -> YHAIChatMessage {
let message = YHAIChatMessage()
message.isSelf = false
let body = YHAIMessageBody()
body.contentType = YHAIMessageType.thinking.rawValue
message.setFinished()
message.body = body
message.uuid = UUID().uuidString + NSDate().timeIntervalSince1970.description
message.updateBodyToData()
return message
}
static func createTextMesssage(text: String) -> YHAIChatMessage {
let message = YHAIChatMessage()
message.uuid = UUID().uuidString + NSDate().timeIntervalSince1970.description
message.isSelf = false
let body = YHAIMessageBody()
body.contentType = YHAIMessageType.text.rawValue
body.contentText = text
message.setFinished()
message.body = body
message.updateBodyToData()
return message
}
static func createPictureMessage(url: String, imgType: Int) -> YHAIChatMessage {
let message = YHAIChatMessage()
message.uuid = UUID().uuidString + NSDate().timeIntervalSince1970.description
message.isSelf = false
let body = YHAIMessageBody()
message.setFinished()
body.contentType = YHAIMessageType.picture.rawValue
let imgInfo = YHAIImageInfo()
imgInfo.imageUrl = url
imgInfo.imageType = imgType
body.imageInfo = imgInfo
message.body = body
message.updateBodyToData()
return message
}
func updateBodyToData() {
dataDict = body.toDictionary() ?? [:]
data = self.dicToJSONString(dict: dataDict)
}
func updateDataToBody() {
}
func dicToJSONString(dict: [String: Any]) -> String {
if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) {
return String(data: jsonData, encoding: .utf8) ?? ""
}
return ""
}
// 获取消息类型
func getType() -> YHAIMessageType {
if let contentType = dataDict["contentType"] as? Int {
if contentType == YHAIMessageType.thinking.rawValue {
return .thinking
}
if contentType == YHAIMessageType.text.rawValue {
if let type = dataDict["type"] as? String {
if type == "follow_up" {
return .recommendText
}
}
return .text
}
if contentType == YHAIMessageType.cardList.rawValue {
return .cardList
}
if contentType == YHAIMessageType.fixProductList.rawValue {
return .fixProductList
}
if contentType == YHAIMessageType.picture.rawValue {
return .picture
}
if contentType == YHAIMessageType.productList.rawValue {
return .productList
}
}
return .unknown
}
// 获取文字消息的文字
func getText() -> String {
let msgType = getType()
if msgType == .text || msgType == .recommendText {
if let text = dataDict["contentText"] as? String, !text.isEmpty {
return text
}
}
return ""
}
var description: String {
return "uudi:\(uuid)\n id: \(id)\n event: \(event)\n data:\(data)\n \n"
}
}
class YHAIMessageBody: SmartCodable {
var contentType: Int = 0
var contentText: String = ""
var chatId: String = ""
var botId: String = ""
var status: String = ""
var type: String = ""
var cardsInfo: YHAIListinfoModel?
var imageInfo: YHAIImageInfo?
func isStart() -> Bool {
if status == "start" {
return true
}
return false
}
func isDone() -> Bool {
if status == "done" {
return true
}
return false
}
required init() {
}
// var description: String {
// return "contentType:\(contentType)\n contentText: \(contentText)\n type: \(type)\n status: \(status))\n"
// }
}
class YHAIListinfoModel: SmartCodable {
var title: String = ""
var icon: String = ""
var description: String = ""
var btnText: String = ""
var list: [YHAIListItemModel] = []
var redirectMode: Int = 0
var redirectPath: String = ""
var businessType: String = ""
// 是否是测评
func isEvaluation() -> Bool {
return businessType == "evaluation"
}
required init() {
}
}
class YHAIListItemModel: SmartCodable {
var title: String = ""
var cover: String = ""
var description: String = ""
var redirectMode: Int = 0
var redirectPath: String = ""
var tags: [YHProductTag] = []
var original_price: Int = 0
var discount_price: Int = 0
required init() {
}
}
class YHProductTag: SmartCodable {
var text: String = ""
var color: String = ""
required init() {
}
}
class YHAIImageInfo: SmartCodable {
var imageType: Int = 0
var imageUrl: String = ""
required init() {
}
}
//
// YHAIViewModel.swift
// galaxy
//
// Created by Dufet on 2024/11/27.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIViewModel: NSObject {
var listModel: YHAIListModel = YHAIListModel()
var sessionId: String = ""
var historyMessages: [YHAIHistoryMessage] = []
var lastHistroyMsgId: String = ""
func getAIEntranceList(callBackBlock:@escaping (_ success: Bool,_ error:YHErrorModel?)->()) {
let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.AIChat.aiProductList
let _ = YHNetRequest.getRequest(url: strUrl) { [weak self] json, code in
//1. json字符串 转 对象
guard let self = self else { return }
printLog("model 是 ==> \(json)")
if json.code == 200 {
guard let dic = json.data?.peel as? [String : Any], let resultModel = YHAIListModel.deserialize(from: dic) else {
let err = YHErrorModel(errorCode: YHErrorCode.dictParseError.rawValue, errorMsg: YHErrorCode.dictParseError.description())
callBackBlock(false,err)
return
}
self.listModel = resultModel
callBackBlock(true,nil)
} else {
let err = YHErrorModel(errorCode: Int32(json.code), errorMsg: json.msg.isEmpty ? "" : json.msg)
callBackBlock(false,err)
}
} failBlock: { err in
callBackBlock(false,err)
}
}
func requestConversationId(callBackBlock:@escaping (_ success: Bool,_ error:YHErrorModel?)->()) {
let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.AIChat.getAIChatSessionId
let _ = YHNetRequest.getRequest(url: strUrl) { [weak self] json, code in
//1. json字符串 转 对象
guard let self = self else { return }
printLog("model 是 ==> \(json)")
if json.code == 200 {
guard let dic = json.data?.peel as? [String : Any], let sessionId = dic["conversationId"] as? String else {
let err = YHErrorModel(errorCode: YHErrorCode.dictParseError.rawValue, errorMsg: YHErrorCode.dictParseError.description())
callBackBlock(false, err)
return
}
self.sessionId = sessionId
callBackBlock(true,nil)
} else {
let err = YHErrorModel(errorCode: Int32(json.code), errorMsg: json.msg.isEmpty ? "" : json.msg)
callBackBlock(false,err)
}
} failBlock: { err in
callBackBlock(false,err)
}
}
func getHistoryChatMessages(botId: String, conversationId: String, messageId: String, callBackBlock:@escaping (_ success: Bool,_ error:YHErrorModel?)->()) {
let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.AIChat.chatHistory
let params:[String : Any] = [
"botId" : botId,
"conversationId" : conversationId,
"messageId" : messageId
]
let _ = YHNetRequest.getRequest(url: strUrl, params:params) { [weak self] json, code in
//1. json字符串 转 对象
guard let self = self else { return }
printLog("model 是 ==> \(json)")
if json.code == 200 {
guard let dic = json.data?.peel as? [Any], let arr = [YHAIHistoryMessage].deserialize(from: dic) else {
let err = YHErrorModel(errorCode: YHErrorCode.dictParseError.rawValue, errorMsg: YHErrorCode.dictParseError.description())
callBackBlock(false, err)
return
}
self.historyMessages = arr.reversed()
if let lastMsg = arr.last {
self.lastHistroyMsgId = lastMsg.messageId
}
callBackBlock(true,nil)
} else {
let err = YHErrorModel(errorCode: Int32(json.code), errorMsg: json.msg.isEmpty ? "" : json.msg)
callBackBlock(false,err)
}
} failBlock: { err in
callBackBlock(false,err)
}
}
func createMessage(conversationId: String, role: String, msg: YHAIChatMessage, callBackBlock:@escaping (_ success: Bool,_ error:YHErrorModel?)->()) {
guard let msgDict = msg.body.toDictionary() else {
return
}
let content = self.dicToJSONString(dict: msgDict)
let params:[String : Any] = ["conversationId" : conversationId,
"contentType" : "\(msg.body.contentType)",
"role" : role,
"content" : content]
printLog("CREATE_MSG:\n \(params)")
let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.AIChat.createMessage
let _ = YHNetRequest.postRequest(url: strUrl, params: params) {
[weak self] json, code in
//1. json字符串 转 对象
guard let self = self else { return }
printLog("model 是 ==> \(json)")
if json.code == 200 {
callBackBlock(true,nil)
} else {
let err = YHErrorModel(errorCode: Int32(json.code), errorMsg: json.msg.isEmpty ? "" : json.msg)
callBackBlock(false,err)
}
} failBlock: { err in
callBackBlock(false,err)
}
}
func dicToJSONString(dict: [String: Any]) -> String {
if let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted) {
return String(data: jsonData, encoding: .utf8) ?? ""
}
return ""
}
}
//
// YHAICardItemView.swift
// galaxy
//
// Created by Dufet on 2024/12/3.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAICardItemView: UIView {
var cardModel = YHAIListItemModel() {
didSet {
cardImgView.sd_setImage(with: URL(string: cardModel.cover), placeholderImage: UIImage(named: "global_default_image"))
cardTitleLabel.text = cardModel.title
describeLabel.text = cardModel.description
}
}
lazy var lineView: UIView = {
let v = UIView()
v.backgroundColor = .init(hex: 0xE9ECF0)
return v
}()
lazy var cardImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "global_default_image"))
return v
}()
lazy var cardTitleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_B(ofSize:16)
lable.numberOfLines = 0
lable.text = "卡片标题"
return lable
}()
lazy var describeLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.init(hex: 0x8993A2)
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:12)
lable.numberOfLines = 0
lable.text = "卡片描述文字"
return lable
}()
override init(frame: CGRect) {
super.init(frame: frame)
createUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createUI() {
self.addSubview(lineView)
self.addSubview(cardImgView)
self.addSubview(cardTitleLabel)
self.addSubview(describeLabel)
lineView.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(0)
make.height.equalTo(0.5)
}
cardImgView.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(lineView.snp.bottom).offset(16)
make.height.equalTo(303)
}
cardTitleLabel.snp.makeConstraints { make in
make.top.equalTo(cardImgView.snp.bottom).offset(10)
make.left.equalTo(16)
make.right.equalTo(-16)
}
describeLabel.snp.makeConstraints { make in
make.top.equalTo(cardTitleLabel.snp.bottom).offset(4)
make.left.equalTo(16)
make.right.equalTo(-16)
make.bottom.equalTo(-16)
}
}
}
//
// YHAIChatBannerCollectionCell.swift
// galaxy
//
// Created by Dufet on 2024/11/30.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIChatBannerCollectionCell: UICollectionViewCell {
static let cellReuseIdentifier = "YHAIChatBannerCollectionCell"
lazy var titleLabel: UILabel = {
var label = UILabel()
label.font = .PFSC_R(ofSize: 12)
label.textAlignment = .left
label.textColor = UIColor.mainTextColor
return label
}()
lazy var shadowView: YHAIChatShadowView = {
let v = YHAIChatShadowView()
return v
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
private func setupUI() {
contentView.backgroundColor = .white
contentView.layer.cornerRadius = 6.0
contentView.addSubview(shadowView)
contentView.addSubview(titleLabel)
shadowView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.top.bottom.equalToSuperview()
make.left.equalToSuperview().offset(10.0)
make.right.equalToSuperview().offset(-10.0)
}
}
}
//
// YHAIChatBannerItemCell.swift
// galaxy
//
// Created by Dufet on 2024/11/30.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import FSPagerView
import VisualEffectView
class YHAIChatBannerItemCell: FSPagerViewCell {
static let cellReuseIdentifier = "YHAIChatBannerItemCell"
lazy var effectView:VisualEffectView = {
let visualEffectView = VisualEffectView()
visualEffectView.colorTint = UIColor(hex: 0xAFAFAF).withAlphaComponent(0.15)
visualEffectView.blurRadius = 16
visualEffectView.scale = 1
return visualEffectView
}()
lazy var bannerImagV: UIImageView = {
let imagV : UIImageView = UIImageView()
imagV.contentMode = .scaleAspectFill
imagV.clipsToBounds = true
imagV.image = UIImage(named: "global_default_image")
return imagV
}()
lazy var titleLabel: UILabel = {
let lable = UILabel()
lable.font = UIFont.PFSC_B(ofSize: 14)
lable.textColor = UIColor.brandMainColor
lable.text = "银河明星产品"
return lable
}()
lazy var subtitleLabel: UILabel = {
let lable = UILabel()
lable.font = UIFont.PFSC_R(ofSize: 13)
lable.textColor = UIColor.mainTextColor
lable.text = "这里是副标题"
return lable
}()
override init(frame: CGRect) {
super.init(frame: frame)
initView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func initView() {
contentView.layer.shadowColor = UIColor.clear.cgColor
contentView.layer.shadowRadius = 0
contentView.layer.shadowOpacity = 0
contentView.layer.shadowOffset = .zero
contentView.addSubview(bannerImagV)
bannerImagV.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
contentView.addSubview(effectView)
effectView.snp.makeConstraints { make in
make.bottom.left.right.equalToSuperview()
make.height.equalTo(95)
}
contentView.addSubview(subtitleLabel)
subtitleLabel.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.height.equalTo(20)
make.bottom.equalTo(-35)
}
contentView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.height.equalTo(24)
make.bottom.equalTo(subtitleLabel.snp.top)
}
}
}
//
// YHAIChatBannerView.swift
// galaxy
//
// Created by Dufet on 2024/11/30.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import FSPagerView
class YHAIChatBannerView: UIView {
static let bannerHeight = 242.0
let cellHeight: CGFloat = 33.0 // 单元格的固定高度
var items:[String] = [] {
didSet {
layout.dataSource = items
collectionView.reloadData()
}
}
var dataArr: [YHBannerModel] = [] {
didSet {
// 设置为0是先停掉自动滑动定时器
bannerView.automaticSlidingInterval = 0
self.indicatorView.indicatorItems = self.dataArr.count
bannerView.reloadData()
// 指定指示器为第一个
self.indicatorView.curIndicatorIndex = 0
// 指定显示图片为第一个
bannerView.selectItem(at: 0, animated: false)
// 开启定时器开始滚动
bannerView.automaticSlidingInterval = bannerSildingInterval
bannerView.removesInfiniteLoopForSingleItem = true
bannerView.alwaysBounceHorizontal = true
}
}
private lazy var bannerView: FSPagerView = {
let view = FSPagerView()
view.delegate = self
view.dataSource = self
view.bounces = false
view.isInfinite = true
view.automaticSlidingInterval = bannerSildingInterval
view.register(YHAIChatBannerItemCell.self, forCellWithReuseIdentifier: YHAIChatBannerItemCell.cellReuseIdentifier)
view.itemSize = CGSizeMake(KScreenWidth-40.0, YHAIChatBannerView.bannerHeight)//FSPagerView.automaticSize
return view
}()
lazy var indicatorView : YHHomeBannerIndicatorView = {
let view = YHHomeBannerIndicatorView()
return view
}()
lazy var layout: YHAIChatCustomFlowLayout = {
let layout = YHAIChatCustomFlowLayout()
layout.scrollDirection = .horizontal
layout.dataSource = []
return layout
}()
lazy var collectionView: UICollectionView = {
let collectView = UICollectionView(frame:.zero, collectionViewLayout: layout)
collectView.delegate = self
collectView.dataSource = self
collectView.backgroundColor = .clear
collectView.showsHorizontalScrollIndicator = false
collectView.showsVerticalScrollIndicator = false
// 注册自定义单元格
collectView.register(YHAIChatBannerCollectionCell.self, forCellWithReuseIdentifier: YHAIChatBannerCollectionCell.cellReuseIdentifier)
return collectView
}()
override init(frame: CGRect) {
super.init(frame: frame)
createUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createUI() {
addSubview(bannerView)
bannerView.snp.makeConstraints { make in
make.top.equalTo(10)
make.left.equalTo(20)
make.right.equalTo(-20)
make.height.equalTo(YHAIChatBannerView.bannerHeight)
}
bannerView.addSubview(indicatorView)
indicatorView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.height.equalTo(2)
make.bottom.equalTo(-14)
}
bannerView.reloadData()
addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.left.equalTo(20)
make.right.equalTo(-20)
make.height.equalTo(33.0*2+10.0 + 10.0*2.0)
make.top.equalTo(bannerView.snp.bottom).offset(6)
make.bottom.equalTo(-6)
}
}
// 计算文字宽度大小
func getwith(font: UIFont, height: CGFloat, string: String) -> CGSize {
let size = CGSize.init(width: CGFloat(MAXFLOAT), height: height)
let dic = [NSAttributedString.Key.font: font] // swift 4.2
let strSize = string.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: dic, context:nil).size
return CGSizeMake(ceil(strSize.width), strSize.height)
}
}
extension YHAIChatBannerView: FSPagerViewDataSource, FSPagerViewDelegate {
public func numberOfItems(in pagerView: FSPagerView) -> Int {
return self.dataArr.count
}
public func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
let cell = pagerView.dequeueReusableCell(withReuseIdentifier: YHAIChatBannerItemCell.cellReuseIdentifier, at: index) as! YHAIChatBannerItemCell
if index < dataArr.count {
}
return cell
}
// MARK: - FSPagerView Delegate
func pagerView(_ pagerView: FSPagerView, didSelectItemAt index: Int) {
pagerView.deselectItem(at: index, animated: true)
pagerView.scrollToItem(at: index, animated: true)
if index >= dataArr.count {
return
}
}
func pagerViewWillEndDragging(_ pagerView: FSPagerView, targetIndex: Int) {
self.indicatorView.curIndicatorIndex = targetIndex
}
func pagerViewDidEndScrollAnimation(_ pagerView: FSPagerView) {
self.indicatorView.curIndicatorIndex = pagerView.currentIndex
}
}
extension YHAIChatBannerView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
// 返回单元格数量
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items.count
}
// 返回每个单元格的大小
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return layout.getSize(index: indexPath.item)
}
// 返回自定义单元格
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: YHAIChatBannerCollectionCell.cellReuseIdentifier, for: indexPath) as! YHAIChatBannerCollectionCell
if 0 <= indexPath.item && indexPath.item < items.count {
cell.titleLabel.text = items[indexPath.item]
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if 0 <= indexPath.item && indexPath.item < items.count {
let text = items[indexPath.item]
}
}
}
//
// YHAIChatCustomFlowLayout.swift
// galaxy
//
// Created by Dufet on 2024/11/30.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIChatCustomFlowLayout: UICollectionViewFlowLayout {
let cellHeight = 33.0
let verticalGap = 10.0
let horizonalGap = 10.0
var firstLineX = 0.0
var secondLineX = 0.0
let firstLineY = 10.0
let secondLineY = 10.0 + 33.0 + 10.0
var attributes: [UICollectionViewLayoutAttributes] = []
// var dataSource:[String] = [] {
// didSet {
// attributes.removeAll()
// firstLineX = 0.0
// secondLineX = 0.0
// for (index, text) in dataSource.enumerated() {
// let attribute = UICollectionViewLayoutAttributes(forCellWith: IndexPath(row: index, section: 0))
// if index % 2 == 0 { // 第一行的数据
// let size = self.getSize(index: index)
// attribute.frame = CGRectMake(firstLineX, verticalGap, size.width, size.height)
// firstLineX = firstLineX + attribute.frame.width + horizonalGap
//
// } else { // 第二行的数据
// let size = self.getSize(index: index)
// attribute.frame = CGRectMake(secondLineX, verticalGap+cellHeight+verticalGap, size.width, size.height)
// secondLineX = secondLineX + attribute.frame.width + horizonalGap
// }
// attributes.append(attribute)
// }
// collectionView?.reloadData()
// }
// }
var dataSource:[String] = [] {
didSet {
attributes.removeAll()
firstLineX = 0.0
secondLineX = 0.0
for (index, text) in dataSource.enumerated() {
let attribute = UICollectionViewLayoutAttributes(forCellWith: IndexPath(row: index, section: 0))
let size = self.getSize(index: index)
if firstLineX <= secondLineX {
attribute.frame = CGRectMake(firstLineX, firstLineY, size.width, size.height)
firstLineX = firstLineX + attribute.frame.width + horizonalGap
} else {
attribute.frame = CGRectMake(secondLineX, secondLineY, size.width, size.height)
secondLineX = secondLineX + attribute.frame.width + horizonalGap
}
attributes.append(attribute)
}
collectionView?.reloadData()
}
}
override func prepare() {
super.prepare()
}
override func invalidateLayout() {
super.invalidateLayout()
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
if 0 <= indexPath.item, indexPath.item < attributes.count {
return attributes[indexPath.item]
}
return nil
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return attributes
}
override var collectionViewContentSize: CGSize {
guard let _ = collectionView else { return .zero }
let width = max(firstLineX, secondLineX)
let size = CGSize(width: width, height: cellHeight*2.0 + verticalGap)
return size
}
func getSize(index:Int) -> CGSize {
if 0 <= index, index < dataSource.count {
let size = self.getwith(font: UIFont.PFSC_R(ofSize: 12), height: cellHeight, string: dataSource[index])
let gap = 10.0
let width = size.width + gap*2.0
return CGSize(width: width, height: cellHeight)
}
return .zero
}
// 计算文字宽度大小
func getwith(font: UIFont, height: CGFloat, string: String) -> CGSize {
let size = CGSize.init(width: CGFloat(MAXFLOAT), height: height)
let dic = [NSAttributedString.Key.font: font] // swift 4.2
let strSize = string.boundingRect(with: size, options: [.usesLineFragmentOrigin], attributes: dic, context:nil).size
return CGSizeMake(ceil(strSize.width), strSize.height)
}
}
//
// YHAIChatInputShadowView.swift
// galaxy
//
// Created by Dufet on 2024/12/2.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import UIKit
class YHAIChatInputShadowView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupShadow()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupShadow()
}
private func setupShadow() {
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: 12)
layer.shadowPath = shadowPath.cgPath
layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.12).cgColor
layer.shadowOpacity = 1
layer.shadowRadius = 6
layer.shadowOffset = CGSize(width: 0, height: 0)
}
override func layoutSubviews() {
super.layoutSubviews()
// 确保在布局更新时更新阴影路径
setupShadow()
}
}
//
// YHAIChatShadowView.swift
// galaxy
//
// Created by Dufet on 2024/11/30.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIChatShadowView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupShadow()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupShadow()
}
private func setupShadow() {
// 创建阴影路径
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: 6)
// 设置阴影属性
layer.shadowPath = shadowPath.cgPath
layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.06).cgColor
layer.shadowOpacity = 1
layer.shadowRadius = 20
layer.shadowOffset = CGSize(width: 0, height: 4)
}
override func layoutSubviews() {
super.layoutSubviews()
// 确保在布局更新时更新阴影路径
setupShadow()
}
}
//
// YHAIEvaluationAlertWebView.swift
// galaxy
//
// Created by Dufet on 2024/12/3.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIEvaluationAlertWebView: UIView {
var url: String = ""
static func alertView(url: String) -> YHAIEvaluationAlertWebView {
let v = YHAIEvaluationAlertWebView()
return v
}
lazy var blackMaskView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(hex: 0x0F1214, alpha: 0.5)
let tap = UITapGestureRecognizer(target: self, action: #selector(dismiss))
view.addGestureRecognizer(tap)
return view
}()
lazy var bottomView: UIView = {
let view = UIView()
view.backgroundColor = .white
view.addSubview(leftBtn)
view.addSubview(rightBtn)
leftBtn.snp.makeConstraints { make in
make.top.equalTo(8)
make.left.equalTo(16)
make.width.equalTo(rightBtn)
make.right.equalTo(rightBtn.snp.left).offset(-10)
make.height.equalTo(46)
}
rightBtn.snp.makeConstraints { make in
make.top.equalTo(8)
make.right.equalTo(-16)
make.height.equalTo(46)
}
return view
}()
lazy var rightBtn: UIButton = {
let btn = UIButton()
btn.backgroundColor = .brandMainColor
btn.setTitle("重新选择提升目标", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = UIFont.PFSC_M(ofSize: 16)
btn.addTarget(self, action: #selector(didRightBtnClicked), for: .touchUpInside)
btn.layer.cornerRadius = kCornerRadius3
return btn
}()
lazy var leftBtn: UIButton = {
let btn = UIButton()
btn.backgroundColor = .init(hex: 0xF5F6F8)
btn.setTitle("返回", for: .normal)
btn.setTitleColor(.mainTextColor, for: .normal)
btn.titleLabel?.font = UIFont.PFSC_M(ofSize: 16)
btn.addTarget(self, action: #selector(didLeftBtnClicked), for: .touchUpInside)
btn.layer.cornerRadius = kCornerRadius3
return btn
}()
lazy var webVC: YHH5WebViewVC = {
let vc = YHH5WebViewVC()
vc.url = ""
vc.isNeedRefreshDataFlag = true
vc.isFullScreenFlag = false
return vc
}()
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
createUI()
}
static func alertView() -> YHAppVersionForceUpdateView {
let alertView = YHAppVersionForceUpdateView(frame:UIScreen.main.bounds)
return alertView
}
func createUI() {
self.addSubview(blackMaskView)
self.addSubview(bottomView)
webVC.url = self.url
webVC.view.frame = CGRectMake(0, 100, KScreenWidth, KScreenHeight-100-98)
self.addSubview(webVC.view)
blackMaskView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
bottomView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(98)
}
webVC.view.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(100)
}
}
@objc func show() {
UIApplication.shared.yhKeyWindow()?.addSubview(self)
}
@objc func dismiss() {
DispatchQueue.main.async {
self.removeFromSuperview()
}
}
@objc func didLeftBtnClicked() {
dismiss()
}
@objc func didRightBtnClicked() {
dismiss()
YHMyNewSchemeViewController.shared.goToSchemePage()
}
}
//
// YHAIGreetCollectionReusableView.swift
// galaxy
//
// Created by Dufet on 2024/11/27.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIGreetCollectionReusableView: UICollectionReusableView {
static let reuseIdentifier: String = "YHAIGreetCollectionReusableView"
let horizonalGap = 16.0
lazy var iconImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "ai_gangXiaoBao_logo"))
return v
}()
lazy var titleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont(name: "AlimamaShuHeiTi-Bold", size: 30)
lable.text = "Hi, 早上好!"
return lable
}()
lazy var subtitleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.init(hex:0x6D788A)
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:14)
lable.numberOfLines = 0
lable.text = "我是银河AI助手港小宝,可以为您提供申请进度查询和赴港攻略,有什么问题尽管问我哟~"
return lable
}()
override init(frame: CGRect) {
super.init(frame: frame)
createUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func updateGreetingText() {
titleLabel.text = greetingBasedOnTime()
}
func createUI() {
self.addSubview(iconImgView)
self.addSubview(titleLabel)
self.addSubview(subtitleLabel)
iconImgView.snp.makeConstraints { make in
make.right.equalTo(-20+horizonalGap)
make.top.equalTo(4)
make.width.equalTo(120)
make.height.equalTo(94)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(24-horizonalGap)
make.bottom.equalTo(iconImgView.snp.bottom).offset(-15)
make.height.equalTo(42)
}
subtitleLabel.snp.makeConstraints { make in
make.left.equalTo(24-horizonalGap)
make.right.equalTo(-24+horizonalGap)
make.top.equalTo(titleLabel.snp.bottom).offset(8)
}
}
func greetingBasedOnTime() -> String {
let currentDate = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: currentDate)
let minute = calendar.component(.minute, from: currentDate)
var result = "Hi,"
switch (hour, minute) {
case (5..<8, _):
result += "早上好"
case (8, 0..<30):
result += "早上好"
case (8, 30..<60):
result += "上午好"
case (8..<11, _):
result += "上午好"
case (11..<14, _):
result += "中午好"
case (14..<18, _):
result += "下午好"
case (18..<24, _):
result += "晚上好"
case (0..<5, _):
result += "晚上好"
default:
result += "晚上好" // 默认情况
}
result += "!"
return result
}
}
//
// YHAIPictureMessageCell.swift
// galaxy
//
// Created by Dufet on 2024/12/3.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIPictureMessageCell: UITableViewCell {
static let cellReuseIdentifier = "YHAIPictureMessageCell"
var imgInfo = YHAIImageInfo() {
didSet {
imgView.sd_setImage(with: URL(string: imgInfo.imageUrl), placeholderImage: UIImage(named: "global_default_image"), options: [], completed: { (image, error, cacheType, url) in
let size = self.getShowSize(image: image!)
self.imgView.snp.updateConstraints { make in
make.width.equalTo(size.width)
make.height.equalTo(size.height)
}
self.setNeedsLayout()
})
}
}
func getShowSize(image: UIImage) -> CGSize {
var imgW = 220.0
var imgH = 220.0
var ratio = 1.0
if image.size.width > 0, image.size.height > 0 {
ratio = image.size.width/image.size.height
}
imgH = imgW/ratio
// if imgH > 476 {
// imgH = 476
// imgW = imgH*ratio
//
// } else {
// imgW = 220
// imgH = imgW/ratio
// }
return CGSizeMake(imgW, imgH)
}
lazy var imgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "global_default_image"))
return v
}()
lazy var whiteContentView: UIView = {
let v = UIView()
v.layer.cornerRadius = 12.0
v.clipsToBounds = true
let tap = UITapGestureRecognizer(target: self, action: #selector(didMessageClicked))
v.addGestureRecognizer(tap)
return v
}()
lazy var shadowView: YHAIChatShadowView = {
let v = YHAIChatShadowView()
return v
}()
lazy var rightAngleView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.isHidden = true
return v
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
func setupUI() {
selectionStyle = .none
contentView.backgroundColor = .clear
backgroundColor = .clear
contentView.addSubview(shadowView)
contentView.addSubview(rightAngleView)
contentView.addSubview(whiteContentView)
whiteContentView.addSubview(imgView)
whiteContentView.snp.makeConstraints { make in
make.left.equalTo(20)
make.top.equalTo(20)
make.bottom.equalTo(0)
}
imgView.snp.makeConstraints { make in
make.width.equalTo(220)
make.height.equalTo(220)
make.edges.equalToSuperview()
}
shadowView.snp.makeConstraints { make in
make.edges.equalTo(whiteContentView)
}
rightAngleView.snp.makeConstraints { make in
make.top.left.equalTo(whiteContentView)
make.width.height.equalTo(15)
}
}
@objc func didMessageClicked() {
self.endEditing(true)
YHPictureReviewManager.shared.showNetWorkPicturs(curIndex: 0, arrPicturs: [imgInfo.imageUrl])
}
}
//
// YHAIProductCell.swift
// galaxy
//
// Created by Dufet on 2024/11/27.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAIProductCell: UICollectionViewCell {
static let cellReuseIdentifier = "YHAIProductCell"
var model = YHEntranceconfigModel() {
didSet {
titleLabel.text = model.title
if !model.btnText.isEmpty {
subtitleLabel.text = model.description
} else {
subtitleLabel.text = "详细了解银河产品"
}
if !model.btnText.isEmpty {
blackButton.setTitle(model.btnText, for: .normal)
} else {
blackButton.setTitle("去了解", for: .normal)
}
bgImgView.sd_setImage(with: URL(string: model.cover))
}
}
lazy var bgImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: ""))
return v
}()
lazy var titleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_B(ofSize:14)
lable.text = "产品智能体"
return lable
}()
lazy var subtitleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.init(hex:0x8993A2)
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:12)
lable.text = "银河在售商品介绍"
return lable
}()
lazy var blackButton: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("去了解", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.titleLabel?.font = .PFSC_M(ofSize: 11)
btn.backgroundColor = .black
btn.addTarget(self, action: #selector(didSendButtonClicked), for: .touchUpInside)
btn.YH_clickEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
btn.layer.cornerRadius = 13.0
btn.clipsToBounds = true
return btn
}()
@objc func didSendButtonClicked() {
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
func setupUI() {
contentView.backgroundColor = .clear
backgroundColor = .clear
contentView.addSubview(bgImgView)
bgImgView.addSubview(titleLabel)
bgImgView.addSubview(subtitleLabel)
bgImgView.addSubview(blackButton)
bgImgView.snp.makeConstraints { make in
make.left.equalTo(0)
make.right.equalTo(0)
make.bottom.equalTo(0)
make.top.equalTo(0)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(22)
make.right.equalTo(-22)
make.bottom.equalTo(subtitleLabel.snp.top).offset(-3)
make.height.equalTo(20)
}
subtitleLabel.snp.makeConstraints { make in
make.left.equalTo(22)
make.right.equalTo(-22)
make.bottom.equalTo(blackButton.snp.top).offset(-12)
}
blackButton.snp.makeConstraints { make in
make.left.equalTo(22)
make.bottom.equalTo(-24)
make.height.equalTo(26)
make.width.equalTo(54)
}
}
func rotateToRight(_ isRotateRight: Bool) {
let degree = isRotateRight ? 2.0 : -2.0
let transform = CGAffineTransform(rotationAngle: CGFloat(degree * CGFloat.pi / 180)) // 2 度转换为弧度
titleLabel.transform = transform
subtitleLabel.transform = transform
blackButton.transform = transform
if model.cover.isEmpty {
bgImgView.image = UIImage(named: isRotateRight ? "ai_product_left" : "ai_product_right")
}
}
}
//
// YHAITabIndicatorView.swift
// galaxy
//
// Created by Dufet on 2024/11/28.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import JXSegmentedView
class YHAITabIndicatorView: JXSegmentedIndicatorBaseView {
lazy var bgImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: "ai_tab_indicator"))
return v
}()
open var lineStyle: JXSegmentedIndicatorLineStyle = .normal
/// lineStyle为lengthenOffset时使用,滚动时x的偏移量
open var lineScrollOffsetX: CGFloat = 10
open override func commonInit() {
super.commonInit()
self.backgroundColor = .clear
self.addSubview(bgImgView)
bgImgView.snp.makeConstraints { make in
make.width.equalTo(34)
make.height.equalTo(14)
make.centerX.equalToSuperview()
make.top.equalTo(0)
}
}
open override func refreshIndicatorState(model: JXSegmentedIndicatorSelectedParams) {
super.refreshIndicatorState(model: model)
backgroundColor = .clear
layer.cornerRadius = getIndicatorCornerRadius(itemFrame: model.currentSelectedItemFrame)
let width = getIndicatorWidth(itemFrame: model.currentSelectedItemFrame, itemContentWidth: model.currentItemContentWidth)
let height = getIndicatorHeight(itemFrame: model.currentSelectedItemFrame)
let x = model.currentSelectedItemFrame.origin.x + (model.currentSelectedItemFrame.size.width - width)/2
var y: CGFloat = 0
switch indicatorPosition {
case .top:
y = verticalOffset
case .bottom:
y = model.currentSelectedItemFrame.size.height - height - verticalOffset
case .center:
y = (model.currentSelectedItemFrame.size.height - height)/2 + verticalOffset
}
frame = CGRect(x: x, y: y, width: width, height: height)
}
open override func contentScrollViewDidScroll(model: JXSegmentedIndicatorTransitionParams) {
super.contentScrollViewDidScroll(model: model)
guard canHandleTransition(model: model) else {
return
}
let rightItemFrame = model.rightItemFrame
let leftItemFrame = model.leftItemFrame
let percent = model.percent
var targetX: CGFloat = leftItemFrame.origin.x
var targetWidth = getIndicatorWidth(itemFrame: leftItemFrame, itemContentWidth: model.leftItemContentWidth)
let leftWidth = targetWidth
let rightWidth = getIndicatorWidth(itemFrame: rightItemFrame, itemContentWidth: model.rightItemContentWidth)
let leftX = leftItemFrame.origin.x + (leftItemFrame.size.width - leftWidth)/2
let rightX = rightItemFrame.origin.x + (rightItemFrame.size.width - rightWidth)/2
switch lineStyle {
case .normal:
targetX = JXSegmentedViewTool.interpolate(from: leftX, to: rightX, percent: CGFloat(percent))
if indicatorWidth == JXSegmentedViewAutomaticDimension {
targetWidth = JXSegmentedViewTool.interpolate(from: leftWidth, to: rightWidth, percent: CGFloat(percent))
}
case .lengthen:
//前50%,只增加width;后50%,移动x并减小width
let maxWidth = rightX - leftX + rightWidth
if percent <= 0.5 {
targetX = leftX
targetWidth = JXSegmentedViewTool.interpolate(from: leftWidth, to: maxWidth, percent: CGFloat(percent*2))
}else {
targetX = JXSegmentedViewTool.interpolate(from: leftX, to: rightX, percent: CGFloat((percent - 0.5)*2))
targetWidth = JXSegmentedViewTool.interpolate(from: maxWidth, to: rightWidth, percent: CGFloat((percent - 0.5)*2))
}
case .lengthenOffset:
//前50%,增加width,并少量移动x;后50%,少量移动x并减小width
let maxWidth = rightX - leftX + rightWidth - lineScrollOffsetX*2
if percent <= 0.5 {
targetX = JXSegmentedViewTool.interpolate(from: leftX, to: leftX + lineScrollOffsetX, percent: CGFloat(percent*2))
targetWidth = JXSegmentedViewTool.interpolate(from: leftWidth, to: maxWidth, percent: CGFloat(percent*2))
}else {
targetX = JXSegmentedViewTool.interpolate(from:leftX + lineScrollOffsetX, to: rightX, percent: CGFloat((percent - 0.5)*2))
targetWidth = JXSegmentedViewTool.interpolate(from: maxWidth, to: rightWidth, percent: CGFloat((percent - 0.5)*2))
}
}
self.frame.origin.x = targetX
self.frame.size.width = targetWidth
}
open override func selectItem(model: JXSegmentedIndicatorSelectedParams) {
super.selectItem(model: model)
let targetWidth = getIndicatorWidth(itemFrame: model.currentSelectedItemFrame, itemContentWidth: model.currentItemContentWidth)
var toFrame = self.frame
toFrame.origin.x = model.currentSelectedItemFrame.origin.x + (model.currentSelectedItemFrame.size.width - targetWidth)/2
toFrame.size.width = targetWidth
if canSelectedWithAnimation(model: model) {
UIView.animate(withDuration: scrollAnimationDuration, delay: 0, options: .curveEaseOut, animations: {
self.frame = toFrame
}) { (_) in
}
}else {
frame = toFrame
}
}
}
//
// YHAITextInputView.swift
// galaxy
//
// Created by Dufet on 2024/11/25.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import Lottie
import IQKeyboardManagerSwift
enum YHAITextInputStatus: Int {
case enableSend = 0
case disableSend = 1
case loading = 2
}
class YHAITextInputView: UIView {
var sendBlock: ((String)->())?
var stopSendBlock: (()->())?
var keyBoardChangeBlock: ((_ isShow: Bool)->())?
var status: YHAITextInputStatus = .enableSend {
didSet {
if status == .enableSend {
sendBtn.alpha = 1.0
sendBtn.isEnabled = true
sendBtn.isHidden = false
loadingImgView.isHidden = true
} else if status == .disableSend {
sendBtn.alpha = 0.3
sendBtn.isEnabled = false
sendBtn.isHidden = false
loadingImgView.isHidden = true
} else if status == .loading {
sendBtn.isHidden = true
loadingImgView.isHidden = false
}
}
}
lazy var contentView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 12.0
v.clipsToBounds = true
return v
}()
lazy var whiteView: UIView = {
let v = UIView()
return v
}()
lazy var sendBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "ai_chat_send"), for: .normal)
btn.addTarget(self, action: #selector(didSendButtonClicked), for: .touchUpInside)
btn.YH_clickEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
return btn
}()
lazy var loadingImgView: LottieAnimationView! = {
let lottieView = LottieAnimationView(name: "ai_chat_input_pause")
lottieView.loopMode = .loop
lottieView.contentMode = .scaleAspectFit
lottieView.play()
lottieView.isHidden = true
let btn = UIButton(type: .custom)
btn.YH_clickEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
btn.addTarget(self, action: #selector(didStopSendBtnClicked), for: .touchUpInside)
lottieView.addSubview(btn)
btn.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
return lottieView
}()
lazy var shadowView: YHAIChatInputShadowView = {
let v = YHAIChatInputShadowView()
return v
}()
@objc func didSendButtonClicked() {
sendBlock?(textView.text)
status = .loading
textView.text = ""
textView.isScrollEnabled = false
self.endEditing(true)
}
@objc func didStopSendBtnClicked() {
stopSendBlock?()
}
lazy var textView: YHAutoTextView = {
let v = YHAutoTextView()
v.backgroundColor = .clear
v.font = .PFSC_R(ofSize: 14)
v.placeHolder = "有什么问题尽管问我"
v.textChange = {
[weak self] text in
guard let self = self else { return }
if status != .loading {
status = text.count > 0 ? .enableSend : .disableSend
}
}
return v
}()
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
createUI()
}
deinit {
self.removeNotify()
}
func addKeyBoardNotify() {
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func removeNotify() {
NotificationCenter.default.removeObserver(self)
}
func showKeyBoard() {
self.textView.becomeFirstResponder()
}
func createUI() {
self.addSubview(whiteView)
whiteView.addSubview(shadowView)
whiteView.addSubview(contentView)
contentView.addSubview(sendBtn)
contentView.addSubview(loadingImgView)
contentView.addSubview(textView)
status = .disableSend
whiteView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
contentView.snp.makeConstraints { make in
make.left.equalTo(20)
make.top.equalTo(10)
make.bottom.equalTo(-10-k_Height_safeAreaInsetsBottom())
make.right.equalTo(-20)
}
shadowView.snp.makeConstraints { make in
make.edges.equalTo(contentView)
}
sendBtn.snp.makeConstraints { make in
make.width.equalTo(24)
make.height.equalTo(24)
make.right.equalTo(-16)
make.bottom.equalTo(-10)
}
loadingImgView.snp.makeConstraints { make in
make.edges.equalTo(sendBtn)
}
textView.snp.makeConstraints { make in
make.left.equalTo(5)
make.top.equalTo(11-YHAutoTextView.verticalGap)
make.bottom.equalTo(-(11-YHAutoTextView.verticalGap))
make.right.equalTo(sendBtn.snp.left).offset(-5)
}
addKeyBoardNotify()
}
@objc func handleKeyboardNotification(_ notification: Notification) {
if notification.userInfo != nil {
guard let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue else {return }
let isKeyboardShow = notification.name == UIResponder.keyboardWillShowNotification
let bottomMargin = (isKeyboardShow ? -keyboardFrame.height : 0)
contentView.snp.updateConstraints { make in
make.bottom.equalTo(-10-(isKeyboardShow ? 0.0 : k_Height_safeAreaInsetsBottom()))
}
self.snp.updateConstraints { make in
make.bottom.equalTo(bottomMargin)
}
self.setNeedsLayout()
self.layoutIfNeeded()
keyBoardChangeBlock?(isKeyboardShow)
}
}
}
//
// YHAIMessageCell.swift
// galaxy
//
// Created by Dufet on 2024/11/25.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHAITextMessageCell: UITableViewCell {
static let cellReuseIdentifier = "YHAITextMessageCell"
var messageClick:((String)->())?
var message: YHAIChatMessage = YHAIChatMessage() {
didSet {
messageLabel.text = message.body.contentText
rightAngleView.backgroundColor = message.isSelf ? .brandMainColor : .white
rightAngleView.isHidden = message.getType() != .text
if message.isSelf {
whiteContentView.backgroundColor = .brandMainColor
messageLabel.textColor = .white
whiteContentView.snp.remakeConstraints { make in
make.left.greaterThanOrEqualTo(20)
make.right.equalTo(-20)
make.top.equalTo(20)
make.bottom.equalTo(0)
}
rightAngleView.snp.remakeConstraints { make in
make.top.right.equalTo(whiteContentView)
make.width.height.equalTo(15)
}
isNeedShowCopyView = false
} else {
messageLabel.text = message.body.contentText
whiteContentView.backgroundColor = .white
messageLabel.textColor = .mainTextColor
whiteContentView.snp.remakeConstraints { make in
make.left.equalTo(20)
make.right.equalTo(-20)
make.top.equalTo(20)
make.bottom.equalTo(0)
}
rightAngleView.snp.remakeConstraints { make in
make.top.left.equalTo(whiteContentView)
make.width.height.equalTo(15)
}
if message.getType() == .recommendText {
isNeedShowCopyView = false
} else {
isNeedShowCopyView = message.isDone
}
}
self.setNeedsLayout()
self.layoutIfNeeded()
}
}
var isNeedShowCopyView: Bool = false {
didSet {
copyContentView.isHidden = !isNeedShowCopyView
copyContentView.snp.remakeConstraints { make in
make.left.equalTo(0)
make.right.equalTo(0)
make.top.equalTo(messageLabel.snp.bottom).offset(16)
make.height.equalTo(isNeedShowCopyView ? 37.0 : 0.0)
make.bottom.equalTo(0)
}
}
}
lazy var whiteContentView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 12.0
v.clipsToBounds = true
let tap = UITapGestureRecognizer(target: self, action: #selector(didMessageClicked))
v.addGestureRecognizer(tap)
return v
}()
var rightAngleView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.isHidden = true
return v
}()
lazy var messageLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:14)
lable.numberOfLines = 0
return lable
}()
lazy var copyContentView: UIView = {
let v = UIView()
v.clipsToBounds = true
v.isHidden = true
let bgImgV = UIImageView(image: UIImage(named: "ai_chat_copy_bg"))
v.addSubview(bgImgV)
bgImgV.snp.makeConstraints { make in
make.left.top.bottom.equalToSuperview()
make.width.equalTo(KScreenWidth-40)
}
let label = UILabel()
label.textColor = UIColor.init(hex: 0x8993A2)
label.textAlignment = .left
label.font = UIFont.PFSC_R(ofSize:12)
label.text = "以上内容由银河AI生成"
v.addSubview(label)
label.snp.makeConstraints { make in
make.left.equalTo(16)
make.centerY.equalToSuperview()
make.height.equalTo(17)
}
let copyBtn = UIButton()
copyBtn.setTitle("复制", for: .normal)
copyBtn.titleLabel?.font = .PFSC_R(ofSize: 12)
copyBtn.setTitleColor(.mainTextColor, for: .normal)
copyBtn.setImage(UIImage(named: "ai_chat_msg_copy"), for: .normal)
copyBtn.YH_clickEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
copyBtn.addTarget(self, action: #selector(didCopyTextButtonClicked), for: .touchUpInside)
v.addSubview(copyBtn)
copyBtn.snp.makeConstraints { make in
make.right.equalTo(0)
make.centerY.equalToSuperview()
make.height.equalTo(37)
make.width.equalTo(82)
}
copyBtn.iconInLeft(spacing: 0.0)
return v
}()
@objc func didCopyTextButtonClicked() {
let text = message.body.contentText
let pasteBoard = UIPasteboard.general
pasteBoard.string = text
YHHUD.flash(message: "复制成功")
}
lazy var shadowView: YHAIChatShadowView = {
let v = YHAIChatShadowView()
return v
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
func setupUI() {
selectionStyle = .none
contentView.backgroundColor = .clear
backgroundColor = .clear
contentView.addSubview(shadowView)
contentView.addSubview(rightAngleView)
contentView.addSubview(whiteContentView)
whiteContentView.addSubview(messageLabel)
whiteContentView.addSubview(copyContentView)
shadowView.snp.makeConstraints { make in
make.edges.equalTo(whiteContentView)
}
rightAngleView.snp.makeConstraints { make in
make.top.left.equalTo(whiteContentView)
make.width.height.equalTo(15)
}
whiteContentView.snp.makeConstraints { make in
make.left.equalTo(20)
make.right.equalTo(-20)
make.top.equalTo(20)
make.bottom.equalTo(0)
}
messageLabel.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(16)
}
copyContentView.snp.makeConstraints { make in
make.left.equalTo(0)
make.top.equalTo(messageLabel.snp.bottom).offset(16)
make.height.equalTo(0)
make.bottom.equalTo(0)
}
}
@objc func didMessageClicked() {
self.endEditing(true)
if message.getType() == .recommendText {
let text = message.getText()
messageClick?(text)
}
}
}
//
// YHAIThinkingMessageCell.swift
// galaxy
//
// Created by Dufet on 2024/11/28.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import Lottie
class YHAIThinkingMessageCell: UITableViewCell {
static let cellReuseIdentifier = "YHAIThinkingMessageCell"
var whiteContentView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 12.0
v.clipsToBounds = true
return v
}()
lazy var messageLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:14)
lable.text = "港小宝正在思考…"
return lable
}()
let loadingImgView: LottieAnimationView! = {
let lottieView = LottieAnimationView(name: "ai_chat_loading")
lottieView.loopMode = .loop
lottieView.contentMode = .scaleAspectFit
lottieView.play()
return lottieView
}()
lazy var shadowView: YHAIChatShadowView = {
let v = YHAIChatShadowView()
return v
}()
var rightAngleView: UIView = {
let v = UIView()
v.backgroundColor = .white
return v
}()
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
func setupUI() {
selectionStyle = .none
contentView.backgroundColor = .clear
backgroundColor = .clear
contentView.addSubview(shadowView)
contentView.addSubview(rightAngleView)
contentView.addSubview(whiteContentView)
whiteContentView.addSubview(messageLabel)
whiteContentView.addSubview(loadingImgView)
shadowView.snp.makeConstraints { make in
make.edges.equalTo(whiteContentView)
}
rightAngleView.snp.makeConstraints { make in
make.top.left.equalTo(whiteContentView)
make.width.height.equalTo(15)
}
whiteContentView.snp.makeConstraints { make in
make.left.equalTo(20)
make.right.lessThanOrEqualTo(-20)
make.top.equalTo(20)
make.bottom.equalTo(-20)
}
messageLabel.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(16)
}
loadingImgView.snp.makeConstraints { make in
make.left.equalTo(messageLabel)
make.width.equalTo(26)
make.height.equalTo(18)
make.top.equalTo(messageLabel.snp.bottom).offset(6)
make.bottom.equalTo(-16)
}
}
}
//
// YHCardMessageCell.swift
// galaxy
//
// Created by Dufet on 2024/11/29.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHCardMessageCell: UITableViewCell {
static let cellReuseIdentifier = "YHCardMessageCell"
var evaluationResultCallback: ((Dictionary<String, Any>)->()) = { dic in }
var cardListModel = YHAIListinfoModel() {
didSet {
iconImgView.sd_setImage(with: URL(string: cardListModel.icon))
titleLabel.text = cardListModel.title
subtitleLabel.text = cardListModel.description
bottomBtn.setTitle(cardListModel.title, for: .normal)
listView.removeSubviews()
var lastItemView:YHAICardItemView? = nil
for (index, item) in cardListModel.list.enumerated() {
let productView = YHAICardItemView()
productView.cardModel = item
listView.addSubview(productView)
productView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
if let lastItemView = lastItemView {
make.top.equalTo(lastItemView.snp.bottom)
} else {
make.top.equalTo(0)
}
if index == cardListModel.list.count-1 {
make.bottom.equalTo(0)
}
}
lastItemView = productView
}
self.setNeedsLayout()
self.layoutIfNeeded()
}
}
var whiteContentView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 12.0
v.clipsToBounds = true
return v
}()
lazy var iconImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: ""))
return v
}()
lazy var titleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_B(ofSize:16)
lable.text = "港小宝"
return lable
}()
lazy var subtitleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.init(hex: 0x8993A2)
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:12)
lable.text = "为您推荐以下优才产品"
return lable
}()
lazy var listView: UIView = {
let v = UIView()
return v
}()
lazy var bottomBtn: UIButton = {
let btn = UIButton()
btn.setTitle("", for: .normal)
btn.setTitleColor(UIColor.white, for: .normal)
btn.backgroundColor = .brandMainColor
btn.titleLabel?.font = .PFSC_M(ofSize: 14)
btn.layer.cornerRadius = 6.0
btn.addTarget(self, action: #selector(didBottomButtonClicked), for: .touchUpInside)
return btn
}()
lazy var shadowView: YHAIChatShadowView = {
let v = YHAIChatShadowView()
return v
}()
@objc func didBottomButtonClicked() {
if !cardListModel.redirectPath.isEmpty {
let vc = YHH5WebViewVC()
vc.isFullScreenFlag = true
vc.isHideNavigationBar = true
vc.url = cardListModel.redirectPath
vc.evaluationResultCallback = {
[weak self] dict in
guard let self = self else { return }
self.evaluationResultCallback(dict)
}
UIViewController.current?.present(vc, animated: true)
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
func setupUI() {
selectionStyle = .none
contentView.backgroundColor = .clear
backgroundColor = .clear
contentView.addSubview(shadowView)
contentView.addSubview(whiteContentView)
whiteContentView.addSubview(iconImgView)
whiteContentView.addSubview(titleLabel)
whiteContentView.addSubview(subtitleLabel)
whiteContentView.addSubview(listView)
whiteContentView.addSubview(bottomBtn)
shadowView.snp.makeConstraints { make in
make.edges.equalTo(whiteContentView)
}
whiteContentView.snp.makeConstraints { make in
make.left.equalTo(20)
make.right.equalTo(-20)
make.top.equalTo(16)
make.bottom.equalTo(0)
}
iconImgView.snp.makeConstraints { make in
make.width.height.equalTo(36)
make.top.equalTo(20)
make.left.equalTo(16)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(iconImgView)
make.left.equalTo(iconImgView.snp.right).offset(8)
make.height.equalTo(24)
make.right.equalTo(-16)
}
subtitleLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(0)
make.height.equalTo(20)
make.right.equalTo(-16)
}
listView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(subtitleLabel.snp.bottom).offset(10)
}
bottomBtn.snp.makeConstraints { make in
make.top.equalTo(listView.snp.bottom).offset(0)
make.left.equalTo(16)
make.right.equalTo(-16)
make.bottom.equalTo(-16)
make.height.equalTo(44)
}
}
}
//
// YHFixProductItemView.swift
// galaxy
//
// Created by Dufet on 2024/11/29.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
import AttributedString
class YHFixProductItemView: UIView {
var productModel = YHAIListItemModel() {
didSet {
iconImgView.sd_setImage(with: URL(string: productModel.cover), placeholderImage: UIImage(named: ""))
titleLabel.text = productModel.title
subtitleLabel.text = productModel.description
self.setNeedsLayout()
self.layoutIfNeeded()
}
}
lazy var bottomLineView: UIView = {
let v = UIView()
v.backgroundColor = .init(hex: 0xE9ECF0)
return v
}()
lazy var iconImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: ""))
return v
}()
lazy var titleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:14)
lable.text = "高才A香港企明星(7)"
return lable
}()
lazy var subtitleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:14)
lable.text = "高才A香港企明星(7)"
return lable
}()
override init(frame: CGRect) {
super.init(frame: frame)
createUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func didClickProductItem() {
if !productModel.redirectPath.isEmpty {
let vc = YHH5WebViewVC()
vc.isFullScreenFlag = false
vc.url = productModel.redirectPath
UIViewController.current?.navigationController?.pushViewController(vc)
}
}
func createUI() {
let tap = UITapGestureRecognizer(target: self, action: #selector(didClickProductItem))
self.addGestureRecognizer(tap)
self.addSubview(iconImgView)
self.addSubview(titleLabel)
self.addSubview(subtitleLabel)
self.addSubview(bottomLineView)
iconImgView.snp.makeConstraints { make in
make.width.height.equalTo(70)
make.left.equalTo(16)
make.top.equalTo(20)
make.bottom.equalTo(-16)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(iconImgView.snp.right).offset(12)
make.right.equalTo(-16)
make.top.equalTo(iconImgView)
make.height.equalTo(42)
}
subtitleLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.right.equalTo(-16)
make.bottom.equalTo(iconImgView)
make.height.equalTo(17)
}
bottomLineView.snp.makeConstraints { make in
make.left.equalTo(iconImgView)
make.right.equalTo(-16)
make.height.equalTo(0.5)
make.bottom.equalTo(0)
}
}
}
//
// YHFixProductMessageCell.swift
// galaxy
//
// Created by Dufet on 2024/11/29.
// Copyright © 2024 https://www.galaxy-immi.com. All rights reserved.
//
import UIKit
class YHFixProductListMessageCell: UITableViewCell {
static let cellReuseIdentifier = "YHFixProductMessageCell"
var listModel = YHAIListinfoModel() {
didSet {
iconImgView.sd_setImage(with: URL(string: listModel.icon))
titleLabel.text = listModel.title
subtitleLabel.text = listModel.description
listView.removeSubviews()
var lastItemView:YHFixProductItemView? = nil
for (_, item) in listModel.list.enumerated() {
let productView = YHFixProductItemView()
productView.productModel = item
listView.addSubview(productView)
productView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
if let lastItemView = lastItemView {
make.top.equalTo(lastItemView.snp.bottom)
} else {
make.top.equalTo(0)
}
}
lastItemView = productView
}
if listModel.list.count > 0 {
if let lastItemView = lastItemView {
listView.addSubview(moreBtn)
moreBtn.snp.remakeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(lastItemView.snp.bottom)
make.height.equalTo(40)
}
moreBtn.iconInRight(with: 0)
}
}
self.setNeedsLayout()
self.layoutIfNeeded()
}
}
var whiteContentView: UIView = {
let v = UIView()
v.backgroundColor = .white
v.layer.cornerRadius = 12.0
v.clipsToBounds = true
return v
}()
lazy var iconImgView: UIImageView = {
let v = UIImageView(image: UIImage(named: ""))
return v
}()
lazy var titleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.mainTextColor
lable.textAlignment = .left
lable.font = UIFont.PFSC_B(ofSize:16)
lable.text = "港小宝"
return lable
}()
lazy var subtitleLabel:UILabel = {
let lable = UILabel()
lable.textColor = UIColor.init(hex: 0x8993A2)
lable.textAlignment = .left
lable.font = UIFont.PFSC_R(ofSize:12)
lable.text = "为您推荐以下优才产品"
return lable
}()
lazy var lineView: UIView = {
let v = UIView()
v.backgroundColor = .init(hex: 0xE9ECF0)
return v
}()
lazy var listView: UIView = {
let v = UIView()
return v
}()
lazy var moreBtn: UIButton = {
let btn = UIButton()
btn.setTitle("查看更多", for: .normal)
btn.setTitleColor(UIColor.init(hex: 0xB9C1CC), for: .normal)
btn.setImage(UIImage(named: "my_doc_right_arrow"), for: .normal)
btn.titleLabel?.font = .PFSC_R(ofSize: 12)
btn.addTarget(self, action: #selector(didMoreButtonClicked), for: .touchUpInside)
return btn
}()
lazy var shadowView: YHAIChatShadowView = {
let v = YHAIChatShadowView()
return v
}()
@objc func didMoreButtonClicked() {
if !listModel.redirectPath.isEmpty {
let vc = YHH5WebViewVC()
vc.isFullScreenFlag = false
vc.url = listModel.redirectPath
UIViewController.current?.navigationController?.pushViewController(vc)
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
func setupUI() {
selectionStyle = .none
contentView.backgroundColor = .clear
backgroundColor = .clear
contentView.addSubview(shadowView)
contentView.addSubview(whiteContentView)
whiteContentView.addSubview(iconImgView)
whiteContentView.addSubview(titleLabel)
whiteContentView.addSubview(subtitleLabel)
whiteContentView.addSubview(lineView)
whiteContentView.addSubview(listView)
shadowView.snp.makeConstraints { make in
make.edges.equalTo(whiteContentView)
}
whiteContentView.snp.makeConstraints { make in
make.left.equalTo(20)
make.right.equalTo(-20)
make.top.equalTo(16)
make.bottom.equalTo(0)
}
iconImgView.snp.makeConstraints { make in
make.width.height.equalTo(36)
make.top.equalTo(20)
make.left.equalTo(16)
}
titleLabel.snp.makeConstraints { make in
make.top.equalTo(iconImgView)
make.left.equalTo(iconImgView.snp.right).offset(8)
make.height.equalTo(24)
make.right.equalTo(-16)
}
subtitleLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(0)
make.height.equalTo(20)
make.right.equalTo(-16)
}
lineView.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(subtitleLabel.snp.bottom).offset(10)
make.height.equalTo(0.5)
}
listView.snp.makeConstraints { make in
make.left.equalTo(16)
make.right.equalTo(-16)
make.top.equalTo(lineView.snp.bottom).offset(0)
make.bottom.equalTo(0)
}
}
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment