Commit 982b39ac authored by Alex朱枝文's avatar Alex朱枝文

社区调整

parent 1020b4e0
...@@ -10,11 +10,30 @@ import UIKit ...@@ -10,11 +10,30 @@ import UIKit
import SnapKit import SnapKit
class YHCirclePublishViewController: YHBaseViewController { class YHCirclePublishViewController: YHBaseViewController {
struct UserInfo {
var userName: String = ""
var userTitle: String = ""
var avatar: String = ""
}
// MARK: - Properties
private var mediaItems: [YHSelectMediaItem] = []
private let maxMediaCount = 9
// private var resources: [YHResourceURLs] = []
private let marginX: CGFloat = 24 private let marginX: CGFloat = 24
private let itemSpace: CGFloat = 8 private let itemSpace: CGFloat = 8
var completion: (() -> Void)? var completion: (() -> Void)?
lazy var userInfoViewModel: YHInformationAuthorizeViewModel = YHInformationAuthorizeViewModel()
private var currentUser: UserInfo?
private var circleId: String?
lazy var viewModel: YHDynamicViewModel = YHDynamicViewModel()
// MARK: - Navigation Items // MARK: - Navigation Items
private lazy var leftBarItem: UIBarButtonItem = { private lazy var leftBarItem: UIBarButtonItem = {
let item = UIBarButtonItem(image: UIImage(named: "nav_black_24")?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(cancelButtonTapped)) let item = UIBarButtonItem(image: UIImage(named: "nav_black_24")?.withRenderingMode(.alwaysOriginal), style: .plain, target: self, action: #selector(cancelButtonTapped))
...@@ -29,9 +48,7 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -29,9 +48,7 @@ class YHCirclePublishViewController: YHBaseViewController {
button.setTitle("发布", for: .normal) button.setTitle("发布", for: .normal)
button.titleLabel?.font = UIFont.PFSC_M(ofSize: 12) button.titleLabel?.font = UIFont.PFSC_M(ofSize: 12)
button.setTitleColor(UIColor.brandGrayColor0, for: .normal) button.setTitleColor(UIColor.brandGrayColor0, for: .normal)
button.setTitleColor(UIColor.brandGrayColor0, for: .disabled) button.backgroundColor = UIColor.brandGrayColor8
button.isEnabled = false
button.backgroundColor = UIColor.brandGrayColor4
button.addTarget(self, action: #selector(publishButtonTapped), for: .touchUpInside) button.addTarget(self, action: #selector(publishButtonTapped), for: .touchUpInside)
return button return button
}() }()
...@@ -67,7 +84,6 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -67,7 +84,6 @@ class YHCirclePublishViewController: YHBaseViewController {
private lazy var usernameLabel: UILabel = { private lazy var usernameLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.text = "Monica杨晓丽"
label.font = UIFont.PFSC_R(ofSize: 14) label.font = UIFont.PFSC_R(ofSize: 14)
label.textColor = .brandGrayColor8 label.textColor = .brandGrayColor8
return label return label
...@@ -75,7 +91,6 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -75,7 +91,6 @@ class YHCirclePublishViewController: YHBaseViewController {
private lazy var subtitleLabel: UILabel = { private lazy var subtitleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.text = "董事长"
label.font = UIFont.PFSC_R(ofSize: 11) label.font = UIFont.PFSC_R(ofSize: 11)
label.textColor = UIColor.brandGrayColor6 label.textColor = UIColor.brandGrayColor6
return label return label
...@@ -145,9 +160,15 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -145,9 +160,15 @@ class YHCirclePublishViewController: YHBaseViewController {
return view return view
}() }()
// MARK: - Properties init(currentUser: UserInfo? = nil, id: String? = nil) {
private var mediaItems: [YHSelectMediaItem] = [] self.currentUser = currentUser
private let maxMediaCount = 9 self.circleId = id
super.init(nibName: nil, bundle: nil)
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
...@@ -155,6 +176,7 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -155,6 +176,7 @@ class YHCirclePublishViewController: YHBaseViewController {
setupUI() setupUI()
setupConstraints() setupConstraints()
setupNotifications() setupNotifications()
updateUserInfo()
} }
deinit { deinit {
...@@ -261,6 +283,32 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -261,6 +283,32 @@ class YHCirclePublishViewController: YHBaseViewController {
updateCollectionViewHeight() updateCollectionViewHeight()
} }
private func updateUserInfo() {
if let currentUser = currentUser {
usernameLabel.text = currentUser.userName
subtitleLabel.text = currentUser.userTitle
if !currentUser.avatar.isEmpty, let url = URL(string: currentUser.avatar) {
avatarImageView.kf.setImage(with: url, placeholder: UIImage(named: "people_head_default"))
} else {
avatarImageView.image = UIImage(named: "people_head_default")
}
} else {
userInfoViewModel.requestUserInfo { [weak self] _, _ in
guard let self = self else {
return
}
self.usernameLabel.text = self.userInfoViewModel.model.username
self.subtitleLabel.text = self.userInfoViewModel.model.position
let avatar = self.userInfoViewModel.model.avatar
if !avatar.isEmpty, let url = URL(string: avatar) {
avatarImageView.kf.setImage(with: url, placeholder: UIImage(named: "people_head_default"))
} else {
avatarImageView.image = UIImage(named: "people_head_default")
}
}
}
}
private func setupNotifications() { private func setupNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
...@@ -281,13 +329,57 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -281,13 +329,57 @@ class YHCirclePublishViewController: YHBaseViewController {
} }
@objc private func publishButtonTapped() { @objc private func publishButtonTapped() {
guard hasContent() else {
YHHUD.flash(message: "请至少添加一张图片")
return
}
// 检查是否所有媒体都上传成功
let uploadingItems = mediaItems.filter { $0.uploadState == .uploading }
let failedItems = mediaItems.filter { $0.uploadState == .failed }
if !uploadingItems.isEmpty {
YHHUD.flash(message: "图片上传中,请稍候...")
return
}
if !failedItems.isEmpty {
YHHUD.flash(message: "部分图片上传失败,请重试")
return
}
// 收集所有成功上传的资源
let resources = mediaItems.compactMap { $0.resourceURL }
guard resources.count == mediaItems.count else {
YHHUD.flash(message: "图片上传未完成")
return
}
// 发布逻辑 // 发布逻辑
showPublishingAlert() YHGrayCommonAlertView.show("", "确认发布本次动态?", "返回", "确认发布", fullGuestureEnable: false) {
} callBack: { [weak self] in
guard let self = self else {
return
}
// 模拟发布延迟
// 调用发布接口,传入 resources
self.publishDynamic(with: resources)
}
}
// 7. 实际发布方法
private func publishDynamic(with resources: [YHResourceURLs]) {
let title = textView.text ?? ""
let content = detailTextView.text ?? ""
// 模拟发布延迟 // 调用你的发布接口
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { viewModel.publishCircle(title, content, resources: resources) { [weak self] success, error in
self.completion?() guard let self = self else { return }
self.dismiss(animated: true) if success {
self.completion?()
self.dismiss(animated: true)
} else {
YHHUD.flash(message: error?.errorMsg ?? "发布失败")
}
} }
} }
...@@ -315,7 +407,8 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -315,7 +407,8 @@ class YHCirclePublishViewController: YHBaseViewController {
// MARK: - Helper Methods // MARK: - Helper Methods
private func hasContent() -> Bool { private func hasContent() -> Bool {
return !textView.text.isEmpty || !detailTextView.text.isEmpty || !mediaItems.isEmpty return !mediaItems.isEmpty // 目前卡图片
// return !textView.text.isEmpty || !detailTextView.text.isEmpty || !mediaItems.isEmpty
} }
private func updatePublishButton() { private func updatePublishButton() {
...@@ -335,22 +428,15 @@ class YHCirclePublishViewController: YHBaseViewController { ...@@ -335,22 +428,15 @@ class YHCirclePublishViewController: YHBaseViewController {
} }
private func showCancelAlert() { private func showCancelAlert() {
let alert = UIAlertController(title: "确定要离开吗?", message: "离开后内容将不会保存", preferredStyle: .alert) YHGrayCommonAlertView.show("确定要离开吗?", "离开后内容将不会保存", "取消", "确定", fullGuestureEnable: false) {
alert.addAction(UIAlertAction(title: "取消", style: .cancel)) } callBack: { [weak self] in
alert.addAction(UIAlertAction(title: "确定", style: .destructive) { _ in guard let self = self else {
return
}
self.dismiss(animated: true) self.dismiss(animated: true)
})
present(alert, animated: true)
}
private func showPublishingAlert() {
let alert = UIAlertController(title: "发布中...", message: nil, preferredStyle: .alert)
present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
alert.dismiss(animated: true)
} }
} }
} }
// MARK: - UITextViewDelegate // MARK: - UITextViewDelegate
...@@ -361,7 +447,7 @@ extension YHCirclePublishViewController: UITextViewDelegate { ...@@ -361,7 +447,7 @@ extension YHCirclePublishViewController: UITextViewDelegate {
} else if textView == detailTextView { } else if textView == detailTextView {
detailPlaceholderLabel.isHidden = !textView.text.isEmpty detailPlaceholderLabel.isHidden = !textView.text.isEmpty
} }
updatePublishButton() // updatePublishButton()
} }
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
...@@ -425,7 +511,7 @@ extension YHCirclePublishViewController: UICollectionViewDataSource, UICollectio ...@@ -425,7 +511,7 @@ extension YHCirclePublishViewController: UICollectionViewDataSource, UICollectio
// 刷新集合视图 // 刷新集合视图
self.mediaCollectionView.reloadData() self.mediaCollectionView.reloadData()
self.updateCollectionViewHeight() self.updateCollectionViewHeight()
self.updatePublishButton() // self.updatePublishButton()
printLog("已从发布页面删除媒体项,剩余: \(self.mediaItems.count)") printLog("已从发布页面删除媒体项,剩余: \(self.mediaItems.count)")
} }
...@@ -434,10 +520,17 @@ extension YHCirclePublishViewController: UICollectionViewDataSource, UICollectio ...@@ -434,10 +520,17 @@ extension YHCirclePublishViewController: UICollectionViewDataSource, UICollectio
} }
private func removeMedia(at index: Int) { private func removeMedia(at index: Int) {
let item = mediaItems[index]
// 如果已经上传成功,可以选择是否通知后端删除
if item.uploadState == .success {
// TODO: 可选 - 通知后端删除资源
// viewModel.deleteResource(item.resourceURL?.url)
}
mediaItems.remove(at: index) mediaItems.remove(at: index)
mediaCollectionView.reloadData() mediaCollectionView.reloadData()
updateCollectionViewHeight() updateCollectionViewHeight()
updatePublishButton() // updatePublishButton()
} }
private func showMediaUploadSheet() { private func showMediaUploadSheet() {
...@@ -457,9 +550,52 @@ extension YHCirclePublishViewController: UICollectionViewDataSource, UICollectio ...@@ -457,9 +550,52 @@ extension YHCirclePublishViewController: UICollectionViewDataSource, UICollectio
mediaCollectionView.reloadData() mediaCollectionView.reloadData()
updateCollectionViewHeight() updateCollectionViewHeight()
updatePublishButton() // updatePublishButton()
printLog("获得 \(itemsToAdd.count) 个媒体文件")
// 为每个新添加的 item 开始上传
itemsToAdd.forEach { item in
self.uploadMediaItem(item)
}
}
}
// 4. 独立的上传方法
private func uploadMediaItem(_ item: YHSelectMediaItem) {
guard let image = item.image else {
item.uploadState = .failed
return
}
item.uploadState = .uploading
viewModel.uploadImage(image, true) { [weak self, weak item] success, error in
guard let self = self, let item = item else { return }
if let error = error {
item.uploadState = .failed
item.uploadError = error
printLog("上传失败: \(item.name), error: \(error)")
return
}
let imageUrl = (success ?? "").getCdnUrl()
guard !imageUrl.isEmpty else {
item.uploadState = .failed
return
}
// 创建并保存到 item 自身
let source = YHResourceURLs()
source.url = imageUrl
source.width = "\(image.size.width)"
source.height = "\(image.size.height)"
source.type = 1
source.name = item.name
print("获得 \(itemsToAdd.count) 个媒体文件") item.resourceURL = source
item.uploadState = .success
printLog("上传成功: \(item.name)")
} }
} }
} }
...@@ -12,10 +12,8 @@ import JXSegmentedView ...@@ -12,10 +12,8 @@ import JXSegmentedView
class YHCircleViewController: YHBaseViewController { class YHCircleViewController: YHBaseViewController {
lazy var viewModel: YHCircleViewModel = { lazy var viewModel: YHDynamicViewModel = YHDynamicViewModel()
let viewModel = YHCircleViewModel() var arr: [YHDynamicItem] = []
return viewModel
}()
lazy var circleCollectView: UICollectionView = { lazy var circleCollectView: UICollectionView = {
let flowLayout = YHHomeCollectionLayout() let flowLayout = YHHomeCollectionLayout()
...@@ -25,8 +23,7 @@ class YHCircleViewController: YHBaseViewController { ...@@ -25,8 +23,7 @@ class YHCircleViewController: YHBaseViewController {
flowLayout.headerHeight = 112 flowLayout.headerHeight = 112
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
collectionView.backgroundColor = .white collectionView.backgroundColor = .white
// collectionView.register(YHCircleCollectionViewCell.self, forCellWithReuseIdentifier: YHCircleCollectionViewCell.cellReuseIdentifier) collectionView.register(YHCircleCollectionViewCell.self, forCellWithReuseIdentifier: YHCircleCollectionViewCell.cellReuseIdentifier)
collectionView.register(YHHomeCollectionViewCell.self, forCellWithReuseIdentifier: YHHomeCollectionViewCell.cellReuseIdentifier)
collectionView.register(YHCircleHeaderReusableView.self, forSupplementaryViewOfKind: CollectionViewWaterfallElementKindSectionHeader, withReuseIdentifier: YHCircleHeaderReusableView.reuseIdentifier) collectionView.register(YHCircleHeaderReusableView.self, forSupplementaryViewOfKind: CollectionViewWaterfallElementKindSectionHeader, withReuseIdentifier: YHCircleHeaderReusableView.reuseIdentifier)
collectionView.delegate = self collectionView.delegate = self
collectionView.dataSource = self collectionView.dataSource = self
...@@ -48,19 +45,17 @@ class YHCircleViewController: YHBaseViewController { ...@@ -48,19 +45,17 @@ class YHCircleViewController: YHBaseViewController {
btn.addTarget(self, action: #selector(publishButtonClicked), for: .touchUpInside) btn.addTarget(self, action: #selector(publishButtonClicked), for: .touchUpInside)
return btn return btn
}() }()
lazy var noDataView: YHEmptyDataView = {
let view = YHEmptyDataView.createView("暂无动态", kEmptyOrderBgName)
view.isHidden = true
return view
}()
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
setupUI() setupUI()
addDefaultData() requestList(true)
getData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if viewModel.arrCircleData?.isEmpty == true {
getData()
}
} }
deinit { deinit {
...@@ -86,87 +81,49 @@ private extension YHCircleViewController { ...@@ -86,87 +81,49 @@ private extension YHCircleViewController {
make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-30) make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-30)
} }
view.addSubview(self.noDataView)
noDataView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(48)
make.width.equalTo(KScreenWidth)
make.height.equalTo(149)
}
publishButton.iconInLeft(spacing: 6) publishButton.iconInLeft(spacing: 6)
circleCollectView.es.addYHPullToRefresh { circleCollectView.es.addYHPullToRefresh {
self.getData() self.requestList(true)
} }
circleCollectView.es.addInfiniteScrolling { circleCollectView.es.addInfiniteScrolling {
self.loadMoreData() self.requestList(false)
} }
circleCollectView.es.stopPullToRefresh() circleCollectView.es.stopPullToRefresh()
circleCollectView.es.stopLoadingMore() circleCollectView.es.stopLoadingMore()
} }
func addDefaultData() { func requestList(_ firstPage: Bool) {
getCacheDataForCircleData() let sourceType = 0
} self.viewModel.getList(firstPage, sourceType: sourceType) { [weak self] _, _ in
guard let self = self else {
func getCacheDataForCircleData() {
let arrString = UserDefaults.standard.value(forKey: "circleFirstPageData")
if let tmp = arrString as? String, let dic = tmp.toArray() {
guard let result = [YHCircleListModel].deserialize(from: dic) else {
return return
} }
DispatchQueue.global().async {
if let arrData = result as? [YHHomeListModel] { self.arr.removeAll()
for item in arrData { self.arr.append(contentsOf: (self.viewModel.dynamicArr))
for item in self.arr {
item.calHeightParam() item.calHeightParam()
} }
self.viewModel.arrCircleData = arrData
self.circleCollectView.reloadData()
}
}
}
func getData() {
loadFirstData()
}
func loadFirstData() {
DispatchQueue.global().async {
self.viewModel.getCircleList(firstFlag: true) { [weak self] _, _ in
guard let self = self else { return }
if let arrData = self.viewModel.arrCircleData, arrData.count > 0 {
let arrString = arrData.toJSONString()
UserDefaults.standard.set(arrString, forKey: "circleFirstPageData")
UserDefaults.standard.synchronize()
}
DispatchQueue.main.async { DispatchQueue.main.async {
self.circleCollectView.es.stopPullToRefresh() self.noDataView.isHidden = self.arr.count > 0
if self.viewModel.hasMoreForCircle == false {
self.circleCollectView.es.noticeNoMoreData()
self.circleCollectView.footer?.alpha = 1
}
self.circleCollectView.reloadData() self.circleCollectView.reloadData()
}
}
}
}
func loadMoreData() {
DispatchQueue.global().async {
self.viewModel.getCircleList(firstFlag: false) { [weak self] _, _ in
guard let self = self else { return }
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 0.35, execute: {
CATransaction.setDisableActions(true)
self.circleCollectView.reloadData()
CATransaction.commit()
self.circleCollectView.es.stopLoadingMore() self.circleCollectView.es.stopLoadingMore()
if self.viewModel.hasMoreForCircle == false { self.circleCollectView.es.stopPullToRefresh()
if !self.viewModel.hasMore, self.arr.count > 0 {
self.circleCollectView.es.noticeNoMoreData() self.circleCollectView.es.noticeNoMoreData()
self.circleCollectView.footer?.alpha = 1
} }
}) }
} }
} }
} }
...@@ -179,7 +136,7 @@ private extension YHCircleViewController { ...@@ -179,7 +136,7 @@ private extension YHCircleViewController {
let publishVC = YHCirclePublishViewController() let publishVC = YHCirclePublishViewController()
publishVC.completion = { [weak self] in publishVC.completion = { [weak self] in
self?.getData() self?.requestList(true)
} }
let nav = YHNavigationController(rootViewController: publishVC) let nav = YHNavigationController(rootViewController: publishVC)
nav.modalPresentationStyle = .fullScreen nav.modalPresentationStyle = .fullScreen
...@@ -219,34 +176,56 @@ private extension YHCircleViewController { ...@@ -219,34 +176,56 @@ private extension YHCircleViewController {
private func handleOrganizeEventAction() { private func handleOrganizeEventAction() {
NotificationCenter.default.post(name: YhConstant.YhNotification.goActivityVCNotifiction, object: nil) NotificationCenter.default.post(name: YhConstant.YhNotification.goActivityVCNotifiction, object: nil)
} }
private func gotoCircleDetailPage(id: String) {
var url = YHBaseUrlManager.shared.businessH5Url() + "/community/activity/\(id)"
if YHLoginManager.shared.isLogin() {
let token = YHLoginManager.shared.h5Token
let urlHasParam = String.hasQueryParameters(urlString: url)
if urlHasParam {
url = url + "&param=" + token
} else {
url = url + "?param=" + token
}
}
var tUrl = url
if !url.contains("navigationH=") {
tUrl = url + "?navigationH=\(k_Height_NavigationtBarAndStatuBar)"
if url.contains("?") {
tUrl = url + "&navigationH=\(k_Height_NavigationtBarAndStatuBar)"
}
}
let vc = YHH5WebViewVC()
vc.url = tUrl
navigationController?.pushViewController(vc)
}
} }
// MARK: - UICollectionViewDelegate, UICollectionViewDataSource // MARK: - UICollectionViewDelegate, UICollectionViewDataSource
extension YHCircleViewController: UICollectionViewDelegate, UICollectionViewDataSource { extension YHCircleViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.viewModel.arrCircleData?.count ?? 0 return arr.count
} }
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let datas = self.viewModel.arrCircleData, datas.count > indexPath.row else { guard arr.count > indexPath.row else {
return UICollectionViewCell() return UICollectionViewCell()
} }
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: YHHomeCollectionViewCell.cellReuseIdentifier, for: indexPath) as? YHHomeCollectionViewCell else { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: YHCircleCollectionViewCell.cellReuseIdentifier, for: indexPath) as? YHCircleCollectionViewCell else {
return UICollectionViewCell() return UICollectionViewCell()
} }
cell.listModel = datas[indexPath.row] cell.listModel = arr[indexPath.row]
cell.onImageHeightChanged = { [weak self] in
// cell.clickHeartEvent = { [weak self] item in guard let self = self else {
// self?.viewModel.toggleLike(postId: item.id) { success, _ in return
// if success { }
// DispatchQueue.main.async { UIView.performWithoutAnimation {
// self?.circleCollectView.reloadItems(at: [indexPath]) self.circleCollectView.reloadData()
// } }
// } }
// }
// }
return cell return cell
} }
...@@ -264,9 +243,12 @@ extension YHCircleViewController: UICollectionViewDelegate, UICollectionViewData ...@@ -264,9 +243,12 @@ extension YHCircleViewController: UICollectionViewDelegate, UICollectionViewData
} }
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let model = self.viewModel.arrCircleData?[indexPath.row] else { return } guard arr.count > indexPath.row else { return }
let model = arr[indexPath.row]
// printLog("\(model.img_width_use) \(model.img_height_use) \(model.img_width_cell) \(model.img_height_cell)")
// https://test-businessh5.galaxy-immi.com/community/activity/1
gotoCircleDetailPage(id: model.id)
} }
} }
...@@ -274,10 +256,9 @@ extension YHCircleViewController: UICollectionViewDelegate, UICollectionViewData ...@@ -274,10 +256,9 @@ extension YHCircleViewController: UICollectionViewDelegate, UICollectionViewData
extension YHCircleViewController: CollectionViewWaterfallLayoutDelegate { extension YHCircleViewController: CollectionViewWaterfallLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let count = self.viewModel.arrCircleData?.count ?? 0
if indexPath.row < count { if indexPath.row < arr.count {
guard let model = self.viewModel.arrCircleData?[indexPath.row] else { return CGSize.zero } let model = arr[indexPath.row]
return CGSize(width: model.img_width_cell, height: model.img_height_cell) return CGSize(width: model.img_width_cell, height: model.img_height_cell)
} }
...@@ -300,7 +281,7 @@ extension YHCircleViewController { ...@@ -300,7 +281,7 @@ extension YHCircleViewController {
let indexPathToCheck = IndexPath(item: itemIndex, section: section) let indexPathToCheck = IndexPath(item: itemIndex, section: section)
if circleCollectView.indexPathsForVisibleItems.contains(indexPathToCheck) { if circleCollectView.indexPathsForVisibleItems.contains(indexPathToCheck) {
loadMoreData() requestList(false)
} }
} }
} }
......
...@@ -7,175 +7,187 @@ ...@@ -7,175 +7,187 @@
// //
import UIKit import UIKit
import Kingfisher
// MARK: - Cell实现
class YHCircleCollectionViewCell: UICollectionViewCell { class YHCircleCollectionViewCell: UICollectionViewCell {
static let cellReuseIdentifier = "YHCircleCollectionViewCell" static let cellReuseIdentifier = "YHCircleCollectionViewCell"
var likeBlock: ((YHCircleListModel) -> Void)? var listModel: YHDynamicItem? {
var listModel: YHCircleListModel? {
didSet { didSet {
updateUI() updateUI()
} }
} }
private lazy var containerView: UIView = { var onImageHeightChanged: (() -> Void)?
let view = UIView()
view.backgroundColor = .white // MARK: - UI Components
view.layer.cornerRadius = 8
view.layer.shadowColor = UIColor.black.cgColor lazy var titleImageView: UIImageView = {
view.layer.shadowOffset = CGSize(width: 0, height: 2) let imageV = UIImageView(image: UIImage(named: "plan_product_default"))
view.layer.shadowRadius = 4 imageV.contentMode = .scaleAspectFill
view.layer.shadowOpacity = 0.1 imageV.isUserInteractionEnabled = true
return view imageV.clipsToBounds = true
return imageV
}() }()
private lazy var avatarImageView: UIImageView = { private lazy var avatarImageView: UIImageView = {
let iv = UIImageView() let iv = UIImageView()
iv.layer.cornerRadius = 15 iv.layer.cornerRadius = 8
iv.clipsToBounds = true iv.clipsToBounds = true
iv.contentMode = .scaleAspectFill iv.contentMode = .scaleAspectFill
iv.backgroundColor = UIColor(hex: 0xF5F5F5)
return iv return iv
}() }()
private lazy var nameLabel: UILabel = { private lazy var nameLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = UIFont.PFSC_M(ofSize: 13) label.font = UIFont.PFSC_R(ofSize: 12)
label.textColor = UIColor.mainTextColor label.textColor = UIColor.brandGrayColor6
return label
}()
private lazy var timeLabel: UILabel = {
let label = UILabel()
label.font = UIFont.PFSC_R(ofSize: 11)
label.textColor = UIColor.yhGreyColor
return label return label
}() }()
private lazy var contentLabel: UILabel = { lazy var contentLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = UIFont.PFSC_R(ofSize: 14) label.text = ""
label.textColor = UIColor.mainTextColor label.textColor = UIColor.mainTextColor
label.numberOfLines = 0 label.font = UIFont.PFSC_R(ofSize: 15)
label.numberOfLines = 2
label.lineBreakMode = .byTruncatingTail
return label return label
}() }()
private lazy var imageView: UIImageView = { lazy var subHoldView: UIView = {
let iv = UIImageView() let view = UIView()
iv.contentMode = .scaleAspectFill view.layer.backgroundColor = UIColor.white.cgColor
iv.clipsToBounds = true view.layer.borderWidth = 0.6
iv.layer.cornerRadius = 6 view.layer.borderColor = UIColor(red: 0.943, green: 0.952, blue: 0.969, alpha: 1).cgColor
iv.backgroundColor = UIColor(hex: 0xF5F5F5) return view
return iv
}() }()
private lazy var likeButton: UIButton = { // MARK: - Initialization
let btn = UIButton(type: .custom)
btn.setImage(UIImage(named: "home_like_normal"), for: .normal)
btn.setImage(UIImage(named: "home_like_selected"), for: .selected)
btn.addTarget(self, action: #selector(likeButtonClicked), for: .touchUpInside)
return btn
}()
private lazy var likeCountLabel: UILabel = { required init?(coder: NSCoder) {
let label = UILabel() super.init(coder: coder)
label.font = UIFont.PFSC_R(ofSize: 11) }
label.textColor = UIColor.yhGreyColor
return label
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setupUI() setupUI()
} }
required init?(coder: NSCoder) { // MARK: - Setup UI
fatalError("init(coder:) has not been implemented")
}
private func setupUI() { private func setupUI() {
contentView.addSubview(containerView) contentView.clipsToBounds = true
contentView.addSubview(titleImageView)
containerView.addSubview(avatarImageView) titleImageView.snp.makeConstraints { make in
containerView.addSubview(nameLabel) make.left.right.top.equalToSuperview()
containerView.addSubview(timeLabel) make.height.equalTo(210)
containerView.addSubview(contentLabel)
containerView.addSubview(imageView)
containerView.addSubview(likeButton)
containerView.addSubview(likeCountLabel)
containerView.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(4)
}
avatarImageView.snp.makeConstraints { make in
make.left.top.equalToSuperview().offset(10)
make.width.height.equalTo(30)
}
nameLabel.snp.makeConstraints { make in
make.left.equalTo(avatarImageView.snp.right).offset(8)
make.top.equalTo(avatarImageView)
make.right.equalToSuperview().offset(-10)
} }
timeLabel.snp.makeConstraints { make in contentView.addSubview(subHoldView)
make.left.equalTo(nameLabel) subHoldView.snp.makeConstraints { make in
make.bottom.equalTo(avatarImageView) make.top.equalTo(titleImageView.snp.bottom)
make.bottom.left.right.equalToSuperview()
} }
// 内容文本
subHoldView.addSubview(contentLabel)
contentLabel.snp.makeConstraints { make in contentLabel.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(10) make.top.equalToSuperview().offset(12)
make.top.equalTo(avatarImageView.snp.bottom).offset(8) make.left.equalToSuperview().offset(8)
} make.right.equalToSuperview().offset(-8)
imageView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(10)
make.top.equalTo(contentLabel.snp.bottom).offset(8)
make.height.equalTo(100)
} }
likeButton.snp.makeConstraints { make in // 头像
make.left.equalToSuperview().offset(10) subHoldView.addSubview(avatarImageView)
make.bottom.equalToSuperview().offset(-10) avatarImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(8)
make.top.equalTo(contentLabel.snp.bottom).offset(12)
make.width.height.equalTo(16) make.width.height.equalTo(16)
} }
likeCountLabel.snp.makeConstraints { make in // 昵称
make.left.equalTo(likeButton.snp.right).offset(4) subHoldView.addSubview(nameLabel)
make.centerY.equalTo(likeButton) nameLabel.snp.makeConstraints { make in
make.left.equalTo(avatarImageView.snp.right).offset(4)
make.centerY.equalTo(avatarImageView)
make.right.equalToSuperview().offset(-8)
} }
} }
// MARK: - Update UI
private func updateUI() { private func updateUI() {
guard let model = listModel else { return } guard let model = listModel else { return }
nameLabel.text = model.user_name // 顶部图片
timeLabel.text = model.create_time titleImageView.snp.remakeConstraints { make in
contentLabel.text = model.content make.left.right.top.equalToSuperview()
make.height.equalTo(model.img_height_use)
}
if let firstResource = model.firstImageResource, !firstResource.url.isEmpty, let url = URL(string: firstResource.url) {
titleImageView.kf.setImage(with: url, placeholder: UIImage(named: "plan_product_default")) { result in
switch result {
case let .success(value):
DispatchQueue.global().async {
var needRefreshHeight = false
let size = value.image.size
let scale = size.width > 0 ? Double(size.height / size.width) : 0.0
if scale > 0 {
let width = (KScreenWidth - 47) / 2
let height = scale * width
if height >= model.maxImageHeight, model.img_height_use >= model.maxImageHeight {
return
}
if height <= model.minImageHeight, model.img_height_use <= model.minImageHeight {
return
}
if abs(height - model.img_height_use) > 10 {
model.calHeightParam(height)
needRefreshHeight = true
}
}
DispatchQueue.main.async {
if needRefreshHeight {
self.titleImageView.snp.remakeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(model.img_height_use)
}
self.onImageHeightChanged?()
}
}
}
case .failure:
printLog("kf setImage failed")
}
}
} else {
titleImageView.image = UIImage(named: "plan_product_default")
}
// 设置头像 // 用户信息
// avatarImageView.yh_setImage(with: model.user_avatar) nameLabel.text = model.nickname.isEmpty ? "-" : model.nickname
// 设置图片 // 头像
if !model.images.isEmpty { if !model.avatar.isEmpty, let url = URL(string: model.avatar) {
imageView.isHidden = false avatarImageView.kf.setImage(with: url, placeholder: UIImage(named: "people_head_default"))
// imageView.yh_setImage(with: model.images.first)
} else { } else {
imageView.isHidden = true avatarImageView.image = UIImage(named: "people_head_default")
} }
// 设置点赞状态 // 内容文本
likeButton.isSelected = model.is_like contentLabel.text = model.content
likeCountLabel.text = model.like_count > 0 ? "\(model.like_count)" : "" contentLabel.snp.removeConstraints()
likeCountLabel.textColor = model.is_like ? UIColor.brandMainColor : UIColor.yhGreyColor contentLabel.snp.remakeConstraints { make in
} make.top.equalToSuperview().offset(12)
make.left.equalToSuperview().offset(8)
@objc private func likeButtonClicked() { make.right.equalToSuperview().offset(-8)
guard let model = listModel else { return } make.height.equalTo(model.textH)
likeBlock?(model) }
} }
} }
...@@ -482,13 +482,12 @@ private extension YHResourceViewController { ...@@ -482,13 +482,12 @@ private extension YHResourceViewController {
return return
} }
YHGrayCommonAlertView.show("需联系银河管家进行发布信息", "联系银河管家发布企业服务与企业需求,快来与我们联系吧~", "返回", "前往联系", fullGuestureEnable: false) { [weak self] in YHGrayCommonAlertView.show("需联系银河管家进行发布信息", "联系银河管家发布企业服务与企业需求,快来与我们联系吧~", "返回", "前往联系", fullGuestureEnable: false) {
} callBack: { [weak self] in
guard let self = self else { guard let self = self else {
return return
} }
self.messageHandler.gotoChatVC(senderID: "") self.messageHandler.gotoChatVC(senderID: "")
} callBack: {
//
} }
} }
......
...@@ -154,12 +154,13 @@ class YHResourceDetailDocumentsCell: UITableViewCell { ...@@ -154,12 +154,13 @@ class YHResourceDetailDocumentsCell: UITableViewCell {
return return
} }
let newImageHeight = image.size.height / image.size.width * imageWidth let newImageHeight = image.size.height / image.size.width * imageWidth
if abs(newImageHeight - imageHeight) > 10 {
// 关键:用 updateConstraints 而不是 remakeConstraints // 关键:用 updateConstraints 而不是 remakeConstraints
imageView.snp.updateConstraints { make in imageView.snp.updateConstraints { make in
make.height.equalTo(newImageHeight) make.height.equalTo(newImageHeight)
}
self.onImageHeightChanged?()
} }
self.onImageHeightChanged?()
} }
} else { } else {
// 设置图片视图的高度 // 设置图片视图的高度
......
...@@ -6,17 +6,16 @@ ...@@ -6,17 +6,16 @@
// Copyright © 2025 https://www.galaxy-immi.com. All rights reserved. // Copyright © 2025 https://www.galaxy-immi.com. All rights reserved.
// //
import UIKit
import SmartCodable import SmartCodable
import UIKit
class YHDynamicListModel: SmartCodable { class YHDynamicListModel: SmartCodable {
var total: Int = 0 var total: Int = 0
var page: Int = 0 var page: Int = 0
var pageSize: Int = 0 var pageSize: Int = 0
var list: [YHDynamicItem] = [] var list: [YHDynamicItem] = []
required init() { required init() {
} }
} }
...@@ -24,26 +23,26 @@ class YHResourceURLs: SmartCodable { ...@@ -24,26 +23,26 @@ class YHResourceURLs: SmartCodable {
var name: String = "" var name: String = ""
var url: String = "" var url: String = ""
var type: Int = 0 var type: Int = 0
var width: String = "0"
var height: String = "0"
required init() { required init() {
} }
} }
class YHDynamicItem: SmartCodable { class YHDynamicItem: SmartCodable {
var id: String = "" // 动态id var id: String = "" // 动态id
var user_id: String = "" var user_id: String = ""
var title: String = "" var title: String = ""
var content: String = "" var content: String = ""
var resource_urls: [YHResourceURLs] = [] var resource_urls: [YHResourceURLs] = []
var visibility: Int = 0 // 0-未知 1-公开,2-好友可见,3-仅自己可见 var visibility: Int = 0 // 0-未知 1-公开,2-好友可见,3-仅自己可见
var audit_status: Int = 0 // 0-未知 1-待审核,2-审核通过,3-不通过 var audit_status: Int = 0 // 0-未知 1-待审核,2-审核通过,3-不通过
var ai_audit_status: Int = 0 // 0-未知 1-待审核,2-审核通过,3-不通过 var ai_audit_status: Int = 0 // 0-未知 1-待审核,2-审核通过,3-不通过
var violation_reason: Int = 0 // 违规原因 0-未知 var violation_reason: Int = 0 // 违规原因 0-未知
var status: Int = 0 // 状态:0-未知 1-上架中 2-已下架 var status: Int = 0 // 状态:0-未知 1-上架中 2-已下架
var violation_remark: String = "" // 违规详情 var violation_remark: String = "" // 违规详情
var ai_audit_remark: String = "" // ai审核依据 var ai_audit_remark: String = "" // ai审核依据
var click_count: Int = 0 var click_count: Int = 0
var like_count: Int = 0 var like_count: Int = 0
var comment_count: Int = 0 var comment_count: Int = 0
...@@ -54,9 +53,91 @@ class YHDynamicItem: SmartCodable { ...@@ -54,9 +53,91 @@ class YHDynamicItem: SmartCodable {
var release_time: String = "" var release_time: String = ""
var format_release_time: String = "" var format_release_time: String = ""
var created_at: String = "" var created_at: String = ""
var is_self_posts: Int = 0 // 是否是自己的动态 var is_self_posts: Int = 0 // 是否是自己的动态
// MARK: - 高度计算相关属性
// 实际使用的图片宽高
var img_width_use: CGFloat = 0
var img_height_use: CGFloat = 0
// cell的宽高
var img_width_cell: CGFloat = 0
var img_height_cell: CGFloat = 0
// 描述的高度
var textH: CGFloat = 16.0
var isCalHeight = false
var maxImageHeight: CGFloat = 280
var minImageHeight: CGFloat = 140
var firstImageResource: YHResourceURLs? {
return resource_urls.first { resource in
resource.type == 1 && !resource.url.isEmpty
}
}
required init() { required init() {
}
func calHeightParam(_ defaultImageHeight: CGFloat = 0) {
if isCalHeight, defaultImageHeight <= 0 {
return
}
isCalHeight = true
let text = content
let width = (KScreenWidth - 47) / 2
let font = UIFont.PFSC_R(ofSize: 15) // 字体大小改为15
let maxWidth = width - 16 // 最大宽度限制(左右各8的内边距)
// 创建NSAttributedString对象并设置属性
let attributes = [NSAttributedString.Key.font: font] as [NSAttributedString.Key: Any]
// 根据指定的最大宽度和字体大小计算文本的高度
let size = (text as NSString).boundingRect(
with: CGSize(width: maxWidth, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: attributes,
context: nil
).size
var textHeight: CGFloat = size.height
// 固定2行的最大高度(行高约21,2行约42)
if textHeight > 42.0 {
textHeight = 42.0
} else if textHeight < 21 {
textHeight = 21
}
textH = textHeight
// 计算图片高度
var imageHeight: CGFloat = 0.0
if let firstResource = firstImageResource {
let imageSize = CGSize(width: Double(firstResource.width) ?? 0, height: Double(firstResource.height) ?? 0)
if imageSize.width == 0 || imageSize.height == 0, defaultImageHeight <= 0 {
imageHeight = width
} else {
imageHeight = defaultImageHeight > 0 ? defaultImageHeight : width * imageSize.height / imageSize.width
if imageHeight > maxImageHeight {
imageHeight = maxImageHeight
} else if imageHeight < minImageHeight {
imageHeight = minImageHeight
}
}
} else {
imageHeight = width
}
// 计算总高度
// 图片高度 + 顶部间距10 + 头像16 + 内容间距10 + 文本高度(约40) + 底部间距10
let totalHeight = imageHeight + 12 + 16 + 12 + textHeight + 12
img_width_use = width
img_height_use = imageHeight
img_width_cell = width
img_height_cell = totalHeight
} }
} }
...@@ -15,7 +15,7 @@ class YHNameCardDynamicCell: UITableViewCell { ...@@ -15,7 +15,7 @@ class YHNameCardDynamicCell: UITableViewCell {
static let imgH: CGFloat = (KScreenWidth-20*2-4*2)/3.0 static let imgH: CGFloat = (KScreenWidth-20*2-4*2)/3.0
var rePublishClick:(()->())? var rePublishClick: (() -> Void)?
private lazy var publishLabel: UILabel = { private lazy var publishLabel: UILabel = {
let label = UILabel() let label = UILabel()
......
...@@ -15,8 +15,9 @@ class YHDynamicViewModel: YHBaseViewModel { ...@@ -15,8 +15,9 @@ class YHDynamicViewModel: YHBaseViewModel {
var totalCount: Int = 0 var totalCount: Int = 0
var dynamicArr: [YHDynamicItem] = [] var dynamicArr: [YHDynamicItem] = []
var hasMore: Bool = true var hasMore: Bool = true
var preloadItemIndex: Int = 25
func getList(_ firstFlag: Bool, sourceType: Int, other_user_id: String, callBackBlock: @escaping (_ success: Bool, _ error: YHErrorModel?) -> Void) { func getList(_ firstFlag: Bool, sourceType: Int, other_user_id: String = "", callBackBlock: @escaping (_ success: Bool, _ error: YHErrorModel?) -> Void) {
var params: [String: Any] = ["page": curPageIndex] var params: [String: Any] = ["page": curPageIndex]
if firstFlag { if firstFlag {
curPageIndex = 1 curPageIndex = 1
...@@ -73,3 +74,63 @@ class YHDynamicViewModel: YHBaseViewModel { ...@@ -73,3 +74,63 @@ class YHDynamicViewModel: YHBaseViewModel {
} }
} }
} }
// MARK: - 点赞功能扩展
extension YHDynamicViewModel {
/// 点赞/取消点赞动态
/// - Parameters:
/// - id: 动态ID
/// - operation: 操作类型 1-点赞 2-取消点赞
/// - callBackBlock: 回调
func getLike(_ id: String, _ operation: Int, callBackBlock: @escaping (_ success: Bool, _ error: YHErrorModel?) -> Void) {
let params: [String: Any] = ["id": id, "operation": operation]
let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.Dynamic.like
_ = YHNetRequest.postRequest(url: strUrl, params: params) { json, _ in
if json.code == 200 {
callBackBlock(true, nil)
} else {
let error: YHErrorModel = YHErrorModel(errorCode: Int32(json.code), errorMsg: json.msg)
callBackBlock(false, error)
}
} failBlock: { err in
callBackBlock(false, err)
}
}
}
// MARK: - 发布动态
extension YHDynamicViewModel {
/// 发布动态
/// - Parameters:
/// - title: 标题
/// - content: 内容
/// - resources:图片/视频数组
/// - callBackBlock: 回调
func publishCircle(_ title: String, _ content: String, resources: [YHResourceURLs], callBackBlock: @escaping (_ success: Bool, _ error: YHErrorModel?) -> Void) {
var params: [String: Any] = ["title": title, "content": content]
params["resource_urls"] = resources.map { resource in
[
"name": resource.name,
"url": resource.url,
"type": resource.type,
"width": resource.width,
"height": resource.height
] as [String: Any]
}
let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.Dynamic.publishCircle
_ = YHNetRequest.postRequest(url: strUrl, params: params) { json, _ in
if json.code == 200 {
callBackBlock(true, nil)
} else {
let error: YHErrorModel = YHErrorModel(errorCode: Int32(json.code), errorMsg: json.msg)
callBackBlock(false, error)
}
} failBlock: { err in
callBackBlock(false, err)
}
}
}
...@@ -15,6 +15,18 @@ class YHSelectMediaItem { ...@@ -15,6 +15,18 @@ class YHSelectMediaItem {
var videoURL: URL? var videoURL: URL?
var duration: TimeInterval? var duration: TimeInterval?
// 新增:上传状态管理
var uploadState: UploadState = .pending
var resourceURL: YHResourceURLs? // 上传成功后的资源信息
var uploadError: YHErrorModel?
enum UploadState {
case pending // 待上传
case uploading // 上传中
case success // 上传成功
case failed // 上传失败
}
init(name: String = "", type: YHMediaType = .image, image: UIImage? = nil, videoURL: URL? = nil, duration: TimeInterval? = nil) { init(name: String = "", type: YHMediaType = .image, image: UIImage? = nil, videoURL: URL? = nil, duration: TimeInterval? = nil) {
self.name = name self.name = name
self.type = type self.type = type
......
...@@ -786,5 +786,7 @@ class YHAllApiName { ...@@ -786,5 +786,7 @@ class YHAllApiName {
struct Dynamic { struct Dynamic {
static let list = "super-app/content/posts/list" static let list = "super-app/content/posts/list"
static let like = "super-app/content/posts/message-like"
static let publishCircle = "super-app/content/posts/add"
} }
} }
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