Commit 4fa16fab authored by Alex朱枝文's avatar Alex朱枝文

资源相关

parent 051ce9c5
...@@ -12,7 +12,8 @@ import SnapKit ...@@ -12,7 +12,8 @@ import SnapKit
class YHResourceDetailViewController: YHBaseViewController { class YHResourceDetailViewController: YHBaseViewController {
// MARK: - Properties // MARK: - Properties
var resourceModel: YHResourceListModel? var companyId: Int = 0 // 只需要传入公司ID
var detailModel: YHResourceDetailModel? // 详情数据
var isMyCompany: Bool = false { var isMyCompany: Bool = false {
didSet { didSet {
...@@ -20,6 +21,10 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -20,6 +21,10 @@ class YHResourceDetailViewController: YHBaseViewController {
} }
} }
private lazy var viewModel: YHResourceViewModel = {
return YHResourceViewModel()
}()
private lazy var messageHandler: YHIMMessageHandler = { private lazy var messageHandler: YHIMMessageHandler = {
return YHIMMessageHandler( return YHIMMessageHandler(
viewController: self, viewController: self,
...@@ -29,7 +34,7 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -29,7 +34,7 @@ class YHResourceDetailViewController: YHBaseViewController {
// MARK: - UI Components // MARK: - UI Components
// 背景图 - 改为在tableView后面 // 背景图
private lazy var bgIcon: UIImageView = { private lazy var bgIcon: UIImageView = {
let view = UIImageView() let view = UIImageView()
view.image = UIImage(named: "resource_detail_bg") view.image = UIImage(named: "resource_detail_bg")
...@@ -87,7 +92,6 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -87,7 +92,6 @@ class YHResourceDetailViewController: YHBaseViewController {
gk_backImage = UIImage(named: "nav_black_24") gk_backImage = UIImage(named: "nav_black_24")
view.addSubview(bgIcon) view.addSubview(bgIcon)
view.addSubview(tableView) view.addSubview(tableView)
// 添加底部操作栏
view.addSubview(bottomActionView) view.addSubview(bottomActionView)
bottomActionView.addSubview(contactButton) bottomActionView.addSubview(contactButton)
setupConstraints() setupConstraints()
...@@ -96,21 +100,15 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -96,21 +100,15 @@ class YHResourceDetailViewController: YHBaseViewController {
private func updateViewIsMine() { private func updateViewIsMine() {
gk_navTitle = isMyCompany ? "我的企业" : "企业详情" gk_navTitle = isMyCompany ? "我的企业" : "企业详情"
if isMyCompany { bottomActionView.isHidden = isMyCompany
bottomActionView.isHidden = true
} else {
bottomActionView.isHidden = false
}
updateRightBarButtonItem() updateRightBarButtonItem()
} }
private func setupConstraints() { private func setupConstraints() {
// 背景图约束 - 参照YHMemberCenterViewController
bgIcon.snp.makeConstraints { make in bgIcon.snp.makeConstraints { make in
make.top.left.right.bottom.equalToSuperview() make.top.left.right.bottom.equalToSuperview()
} }
// tableView约束
tableView.snp.makeConstraints { make in tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview() make.left.right.equalToSuperview()
make.top.equalTo(k_Height_NavigationtBarAndStatuBar) make.top.equalTo(k_Height_NavigationtBarAndStatuBar)
...@@ -130,7 +128,6 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -130,7 +128,6 @@ class YHResourceDetailViewController: YHBaseViewController {
make.height.equalTo(46) make.height.equalTo(46)
} }
// 不需要设置contentInset,让内容从导航栏下方开始
tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: KScreenWidth, height: 0.01)) tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: KScreenWidth, height: 0.01))
} }
...@@ -154,29 +151,42 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -154,29 +151,42 @@ class YHResourceDetailViewController: YHBaseViewController {
gk_navRightBarButtonItem = rightButtonItem gk_navRightBarButtonItem = rightButtonItem
gk_navItemRightSpace = 16 gk_navItemRightSpace = 16
} }
} }
// MARK: - Data // MARK: - Data
private func loadData() { private func loadData() {
guard let _ = resourceModel else { return } guard companyId > 0 else {
tableView.reloadData() YHHUD.flash(message: "公司ID无效")
incrementViewCount() return
} }
private func incrementViewCount() { // 直接调用详情接口
resourceModel?.incrementViewCount() YHHUD.show(.progress(message: "加载中..."))
viewModel.getCompanyDetail(companyId: companyId) { [weak self] detail, error in
guard let self = self else { return }
DispatchQueue.main.async {
YHHUD.hide()
if let detail = detail {
self.detailModel = detail
self.tableView.reloadData()
} else if let error = error {
YHHUD.flash(message: error)
}
}
}
} }
// MARK: - Actions // MARK: - Actions
@objc private func shareButtonClicked() { @objc private func shareButtonClicked() {
// // 分享功能
} }
@objc private func moreButtonClicked() { @objc private func moreButtonClicked() {
// // 更多操作
} }
@objc private func contactButtonClicked() { @objc private func contactButtonClicked() {
...@@ -184,9 +194,10 @@ class YHResourceDetailViewController: YHBaseViewController { ...@@ -184,9 +194,10 @@ class YHResourceDetailViewController: YHBaseViewController {
YHOneKeyLoginManager.shared.oneKeyLogin() YHOneKeyLoginManager.shared.oneKeyLogin()
return return
} }
messageHandler.gotoChatVC(senderID: "") if let detailModel = detailModel, !detailModel.yh_id.isEmpty {
messageHandler.gotoChatVC(senderID: detailModel.yh_id)
}
} }
} }
// MARK: - UITableViewDataSource & UITableViewDelegate // MARK: - UITableViewDataSource & UITableViewDelegate
...@@ -202,12 +213,10 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele ...@@ -202,12 +213,10 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele
} }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let model = resourceModel else { guard let model = detailModel else {
return UITableViewCell() return UITableViewCell()
} }
let hasDocuments = !model.images.isEmpty
switch indexPath.section { switch indexPath.section {
case 0: case 0:
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath) as? YHResourceDetailHeaderCell else { guard let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath) as? YHResourceDetailHeaderCell else {
...@@ -224,37 +233,23 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele ...@@ -224,37 +233,23 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele
return cell return cell
case 2: case 2:
if hasDocuments { guard let cell = tableView.dequeueReusableCell(withIdentifier: "DemandCell", for: indexPath) as? YHResourceDetailDemandCell else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "DemandCell", for: indexPath) as? YHResourceDetailDemandCell else { return UITableViewCell()
return UITableViewCell()
}
cell.configure(with: model)
return cell
} else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "DemandCell", for: indexPath) as? YHResourceDetailDemandCell else {
return UITableViewCell()
}
cell.configure(with: model)
return cell
} }
cell.configure(with: model)
return cell
case 3: case 3:
guard let cell = tableView.dequeueReusableCell(withIdentifier: "DocumentsCell", for: indexPath) as? YHResourceDetailDocumentsCell else { guard let cell = tableView.dequeueReusableCell(withIdentifier: "DocumentsCell", for: indexPath) as? YHResourceDetailDocumentsCell else {
return UITableViewCell() return UITableViewCell()
} }
cell.configure(with: model.images) let images = model.company_information.map { $0.url }
cell.configure(with: images)
cell.onImageTapped = { [weak self] index in cell.onImageTapped = { [weak self] index in
self?.showImageBrowser(at: index) self?.showImageBrowser(at: index)
} }
cell.onImageHeightChanged = { [weak self] in cell.onImageHeightChanged = { [weak self] in
guard let self = self else { return } guard let self = self else { return }
// NSObject.cancelPreviousPerformRequests(
// withTarget: self,
// selector: #selector(self.performBatchReload),
// object: nil
// )
// self.perform(#selector(self.performBatchReload), with: indexPath, afterDelay: 0.01)
// // 使用 performBatchUpdates 避免动画跳动
UIView.performWithoutAnimation { UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none) self.tableView.reloadRows(at: [indexPath], with: .none)
} }
...@@ -266,12 +261,6 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele ...@@ -266,12 +261,6 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele
} }
} }
@objc private func performBatchReload(indexPath: IndexPath) {
UIView.performWithoutAnimation {
self.tableView.reloadRows(at: [indexPath], with: .none)
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension return UITableView.automaticDimension
} }
...@@ -292,10 +281,8 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele ...@@ -292,10 +281,8 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele
return 0.01 return 0.01
} }
// 关键改动:参照YHMemberCenterViewController的scrollViewDidScroll实现
func scrollViewDidScroll(_ scrollView: UIScrollView) { func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 { if scrollView.contentOffset.y > 0 {
// 向上滚动
var alpha = scrollView.contentOffset.y / k_Height_NavigationtBarAndStatuBar var alpha = scrollView.contentOffset.y / k_Height_NavigationtBarAndStatuBar
if alpha > 1.0 { if alpha > 1.0 {
alpha = 1.0 alpha = 1.0
...@@ -311,7 +298,11 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele ...@@ -311,7 +298,11 @@ extension YHResourceDetailViewController: UITableViewDataSource, UITableViewDele
} }
private func showImageBrowser(at index: Int) { private func showImageBrowser(at index: Int) {
guard let images = resourceModel?.images else { return } guard let companyInformation = detailModel?.company_information else { return }
print("显示图片浏览器,索引:\(index),共\(images.count)张") let images = companyInformation.map { $0.url }
if images.count > index, images.count > 0 {
printLog("显示图片浏览器,索引:\(index),共\(images.count)张")
YHPictureReviewManager.shared.showNetWorkPicturs(curIndex: index, arrPicturs: images)
}
} }
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// galaxy // galaxy
// //
// Created by alexzzw on 2025/9/24. // Created by alexzzw on 2025/9/24.
// Copyright © 2025 https://www.galaxy-immi.com. All rights reserved. // Copyright © 2025 https://www.galaxy-immi.com. All rights reserved.
// //
import UIKit import UIKit
...@@ -33,6 +33,9 @@ class YHResourceViewController: YHBaseViewController { ...@@ -33,6 +33,9 @@ class YHResourceViewController: YHBaseViewController {
// 筛选条件 // 筛选条件
var selectedCategories: [YHResourceCategory] = [] var selectedCategories: [YHResourceCategory] = []
// 行业分类数据
var allCategories: [YHResourceCategory] = []
// MARK: - UI Components // MARK: - UI Components
// 自定义搜索视图 // 自定义搜索视图
...@@ -121,7 +124,6 @@ class YHResourceViewController: YHBaseViewController { ...@@ -121,7 +124,6 @@ class YHResourceViewController: YHBaseViewController {
}() }()
// 空状态视图 // 空状态视图
private lazy var noDataView: YHEmptyDataView = { private lazy var noDataView: YHEmptyDataView = {
let view = YHEmptyDataView.createView("暂无内容", kEmptyOrderBgName) let view = YHEmptyDataView.createView("暂无内容", kEmptyOrderBgName)
view.frame = CGRect(x: 0, y: 0, width: KScreenWidth, height: 164) view.frame = CGRect(x: 0, y: 0, width: KScreenWidth, height: 164)
...@@ -146,7 +148,8 @@ class YHResourceViewController: YHBaseViewController { ...@@ -146,7 +148,8 @@ class YHResourceViewController: YHBaseViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
setupUI() setupUI()
addDefaultData() loadCategories() // 先加载分类数据
// addDefaultData()
getData() getData()
} }
...@@ -162,7 +165,8 @@ class YHResourceViewController: YHBaseViewController { ...@@ -162,7 +165,8 @@ class YHResourceViewController: YHBaseViewController {
} }
func handleTypeChangeNotification(_ userInfo: [AnyHashable: Any]) { func handleTypeChangeNotification(_ userInfo: [AnyHashable: Any]) {
guard let selectTypeKey = userInfo[YHResourceViewController.selectTypeKey] as? String, let type = YHResourceFilterType(rawValue: selectTypeKey) else { guard let selectTypeKey = userInfo[YHResourceViewController.selectTypeKey] as? String,
let type = YHResourceFilterType(rawValue: selectTypeKey) else {
return return
} }
setResourceType(type) setResourceType(type)
...@@ -186,7 +190,7 @@ private extension YHResourceViewController { ...@@ -186,7 +190,7 @@ private extension YHResourceViewController {
view.addSubview(noDataView) view.addSubview(noDataView)
view.addSubview(publishButton) view.addSubview(publishButton)
// 分类视图要最后添加确保在最上层 // 分类视图要最后添加,确保在最上层
view.addSubview(maskView) view.addSubview(maskView)
view.addSubview(categoryView) view.addSubview(categoryView)
...@@ -206,6 +210,7 @@ private extension YHResourceViewController { ...@@ -206,6 +210,7 @@ private extension YHResourceViewController {
make.left.right.equalToSuperview() make.left.right.equalToSuperview()
make.height.equalTo(44) make.height.equalTo(44)
} }
serviceButton.setContentCompressionResistancePriority(.required, for: .horizontal) serviceButton.setContentCompressionResistancePriority(.required, for: .horizontal)
demandButton.setContentCompressionResistancePriority(.required, for: .horizontal) demandButton.setContentCompressionResistancePriority(.required, for: .horizontal)
industryButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) industryButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
...@@ -235,7 +240,6 @@ private extension YHResourceViewController { ...@@ -235,7 +240,6 @@ private extension YHResourceViewController {
categoryView.snp.makeConstraints { make in categoryView.snp.makeConstraints { make in
make.left.right.equalToSuperview() make.left.right.equalToSuperview()
make.top.equalTo(filterContainerView.snp.bottom) make.top.equalTo(filterContainerView.snp.bottom)
// 使用变量保存高度约束的引用
self.categoryViewHeightConstraint = make.height.equalTo(0).constraint self.categoryViewHeightConstraint = make.height.equalTo(0).constraint
} }
...@@ -303,6 +307,20 @@ private extension YHResourceViewController { ...@@ -303,6 +307,20 @@ private extension YHResourceViewController {
} }
} }
/// 加载行业分类数据
func loadCategories() {
viewModel.getResourceCategories { [weak self] categories, error in
guard let self = self else { return }
if let categories = categories {
self.allCategories = categories
self.categoryView.setCategories(categories)
} else if let error = error {
print("加载分类失败: \(error)")
}
}
}
func getData() { func getData() {
loadFirstData() loadFirstData()
} }
...@@ -313,49 +331,47 @@ private extension YHResourceViewController { ...@@ -313,49 +331,47 @@ private extension YHResourceViewController {
YHHUD.show(.progress(message: "加载中...")) YHHUD.show(.progress(message: "加载中..."))
} }
DispatchQueue.global().async { viewModel.getResourceList(firstFlag: true) { [weak self] success, message in
self.viewModel.getResourceList(firstFlag: true) { [weak self] success, message in guard let self = self else { return }
guard let self = self else { return }
DispatchQueue.main.async {
YHHUD.hide()
// if success, let arrData = self.viewModel.arrResourceData, arrData.count > 0 {
// let arrString = arrData.toJSONString()
// UserDefaults.standard.set(arrString, forKey: "resourceFirstPageData")
// UserDefaults.standard.synchronize()
// } else if !success, let errorMessage = message {
// YHHUD.flash(message: errorMessage)
// }
if !success, let errorMessage = message {
YHHUD.flash(message: errorMessage)
}
self.resourceTableView.es.stopPullToRefresh()
DispatchQueue.main.async { if self.viewModel.hasMoreForResource == false {
YHHUD.hide() self.resourceTableView.es.noticeNoMoreData()
self.resourceTableView.footer?.alpha = 1
if success, let arrData = self.viewModel.arrResourceData, arrData.count > 0 {
let arrString = arrData.toJSONString()
UserDefaults.standard.set(arrString, forKey: "resourceFirstPageData")
UserDefaults.standard.synchronize()
} else if !success, let errorMessage = message {
YHHUD.flash(message: errorMessage)
}
self.resourceTableView.es.stopPullToRefresh()
if self.viewModel.hasMoreForResource == false {
self.resourceTableView.es.noticeNoMoreData()
self.resourceTableView.footer?.alpha = 1
}
self.updateUI()
} }
self.updateUI()
} }
} }
} }
func loadMoreData() { func loadMoreData() {
DispatchQueue.global().async { viewModel.getResourceList(firstFlag: false) { [weak self] _, _ in
self.viewModel.getResourceList(firstFlag: false) { [weak self] _, _ in guard let self = self else { return }
guard let self = self else { return }
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 0.35, execute: {
self.resourceTableView.reloadData()
DispatchQueue.main.asyncAfter(wallDeadline: .now() + 0.35, execute: { self.resourceTableView.es.stopLoadingMore()
self.resourceTableView.reloadData() if self.viewModel.hasMoreForResource == false {
self.resourceTableView.es.noticeNoMoreData()
self.resourceTableView.es.stopLoadingMore() self.resourceTableView.footer?.alpha = 1
if self.viewModel.hasMoreForResource == false { }
self.resourceTableView.es.noticeNoMoreData() })
self.resourceTableView.footer?.alpha = 1
}
})
}
} }
} }
...@@ -454,7 +470,6 @@ private extension YHResourceViewController { ...@@ -454,7 +470,6 @@ private extension YHResourceViewController {
industryButton.setImage(UIImage(named: "resource_filter_up"), for: .normal) industryButton.setImage(UIImage(named: "resource_filter_up"), for: .normal)
} }
// 修改隐藏动画方法
@objc func hideCategoryView() { @objc func hideCategoryView() {
// 高度约束动画 // 高度约束动画
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: { UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn, animations: {
...@@ -510,9 +525,7 @@ extension YHResourceViewController: YHCustomSearchViewDelegate { ...@@ -510,9 +525,7 @@ extension YHResourceViewController: YHCustomSearchViewDelegate {
func searchView(_ searchView: YHCustomSearchView, didSearchWithText text: String?) { func searchView(_ searchView: YHCustomSearchView, didSearchWithText text: String?) {
viewModel.searchKeyword = text viewModel.searchKeyword = text
if text?.isEmpty == true { getData()
getData()
}
} }
func searchViewDidBeginEditing(_ searchView: YHCustomSearchView) { func searchViewDidBeginEditing(_ searchView: YHCustomSearchView) {
...@@ -521,7 +534,6 @@ extension YHResourceViewController: YHCustomSearchViewDelegate { ...@@ -521,7 +534,6 @@ extension YHResourceViewController: YHCustomSearchViewDelegate {
func searchViewDidEndEditing(_ searchView: YHCustomSearchView) { func searchViewDidEndEditing(_ searchView: YHCustomSearchView) {
// 搜索结束编辑时的处理 // 搜索结束编辑时的处理
getData()
} }
} }
...@@ -538,8 +550,9 @@ extension YHResourceViewController: UITableViewDelegate, UITableViewDataSource { ...@@ -538,8 +550,9 @@ extension YHResourceViewController: UITableViewDelegate, UITableViewDataSource {
let cell = tableView.dequeueReusableCell(withIdentifier: YHResourceTableViewCell.cellReuseIdentifier, for: indexPath) as? YHResourceTableViewCell else { let cell = tableView.dequeueReusableCell(withIdentifier: YHResourceTableViewCell.cellReuseIdentifier, for: indexPath) as? YHResourceTableViewCell else {
return UITableViewCell() return UITableViewCell()
} }
let model = datas[indexPath.row]
cell.resourceModel = datas[indexPath.row] model.isService = viewModel.currentType == .service
cell.resourceModel = model
return cell return cell
} }
...@@ -552,8 +565,10 @@ extension YHResourceViewController: UITableViewDelegate, UITableViewDataSource { ...@@ -552,8 +565,10 @@ extension YHResourceViewController: UITableViewDelegate, UITableViewDataSource {
tableView.deselectRow(at: indexPath, animated: true) tableView.deselectRow(at: indexPath, animated: true)
guard let model = viewModel.arrResourceData?[indexPath.row] else { return } guard let model = viewModel.arrResourceData?[indexPath.row] else { return }
// 跳转到详情页
let vc = YHResourceDetailViewController() let vc = YHResourceDetailViewController()
vc.resourceModel = model vc.companyId = model.id
navigationController?.pushViewController(vc, animated: true) navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -586,15 +601,14 @@ extension YHResourceViewController: YHResourceCategoryViewDelegate { ...@@ -586,15 +601,14 @@ extension YHResourceViewController: YHResourceCategoryViewDelegate {
selectedCategories = categories selectedCategories = categories
viewModel.selectedCategories = categories viewModel.selectedCategories = categories
updateIndustryButtonTitle() updateIndustryButtonTitle()
if isSet { if isSet {
// 隐藏分类视图 // 隐藏分类视图
hideCategoryView() hideCategoryView()
// 重新加载数据
getData()
} }
// 重新加载数据
getData()
} }
} }
// MARK: - 枚举定义 // MARK: - 枚举定义
......
...@@ -9,220 +9,190 @@ ...@@ -9,220 +9,190 @@
import UIKit import UIKit
import SmartCodable import SmartCodable
// MARK: - 资源列表模型 // MARK: - 公司列表响应模型
class YHResourceListModel: SmartCodable { class YHResourceListResponse: SmartCodable {
required init() {}
var total: Int = 0
var list: [YHResourceListModel] = []
}
// MARK: - 公司头像模型
class YHCompanyAvatar: SmartCodable {
required init() {} required init() {}
var needNewLine: Bool? var name: String = ""
var url: String = ""
}
// MARK: - 公司文档模型
class YHCompanyDocument: SmartCodable {
required init() {}
// MARK: - 基本信息 var name: String = ""
var id: String = "" var url: String = ""
var title: String = "" }
var content: String = ""
var company_name: String = "" // MARK: - 公司详情模型
var company_logo: String = "" class YHResourceDetailModel: SmartCodable {
var contact_name: String = "" required init() {}
var contact_phone: String = ""
var contact_wechat: String = ""
var category_id: String = ""
var category_name: String = ""
var type: String = "" // service 或 demand
var status: Int = 0 // 0-待审核 1-已发布 2-已下架
var is_favorite: Bool = false
var favorite_count: Int = 0
var view_count: Int = 0
var created_time: String = ""
var updated_time: String = ""
var expires_time: String = ""
var images: [String] = []
var tags: [String] = []
var location: String = ""
var price: String = ""
var price_unit: String = ""
// MARK: - 扩展属性
var user_id: String = ""
var user_name: String = ""
var user_avatar: String = ""
var certification_status: Int = 0 // 0-未认证 1-已认证
var priority: Int = 0 // 优先级,用于排序
var click_count: Int = 0 // 点击量
var comment_count: Int = 0 // 评论数
var share_count: Int = 0 // 分享数
var service_area: String = "" // 服务区域
var min_price: String = "" // 最低价格
var max_price: String = "" // 最高价格
var service_duration: String = "" // 服务周期
var qualification: String = "" // 资质证明
var business_hours: String = "" // 营业时间
var website: String = "" // 公司网站
var email: String = "" // 邮箱
var address: String = "" // 详细地址
// MARK: - UI相关属性
var cell_width: CGFloat = 0
var cell_height: CGFloat = 0
// MARK: - 计算属性 var contract_avatar: YHCompanyAvatar?
var id: Int = 0
var company_name: String = ""
var company_english_name: String = ""
var customer_id: Int = 0
var customer_name: String = ""
var last_processed_time: String = ""
var processor_id: Int = 0
var processor: String = ""
var settlement_status: Int = 0
var settlement_status_str: String = ""
var resource_provided: String = ""
var demand_published: String = ""
var settlement_time: String = ""
var industry_type: Int = 0
var industry_type_str: String = ""
var company_introduction: String = "" // 公司介绍
var company_business: String = "" // 主营业务
var company_information: [YHCompanyDocument] = [] // 公司资料图片
var created_at: String = ""
var updated_at: String = ""
var yh_id: String = ""
/// 显示时间(相对时间格式) // 计算属性
var displayTime: String { var companyLogoUrl: String {
return created_time.toDisplayTime() return contract_avatar?.url ?? ""
} }
/// 显示价格 var displayName: String {
var displayPrice: String { return company_name.isEmpty ? company_english_name : company_name
if price.isEmpty {
if !min_price.isEmpty && !max_price.isEmpty {
return "\(min_price)-\(max_price)" + (price_unit.isEmpty ? "" : "/" + price_unit)
} else if !min_price.isEmpty {
return "¥\(min_price)起" + (price_unit.isEmpty ? "" : "/" + price_unit)
}
return "面议"
}
return "¥" + price + (price_unit.isEmpty ? "" : "/" + price_unit)
} }
}
// MARK: - 资源列表模型(公司信息)
class YHResourceListModel: SmartCodable {
/// 类型显示名称 required init() {}
var typeDisplayName: String { var isService = true
return type == "service" ? "企业服务" : "企业需求"
}
/// 状态显示名称 // MARK: - 基本信息(匹配列表API)
var statusDisplayName: String { var id: Int = 0
switch status { var company_avatar: YHCompanyAvatar?
case 0: var company_name: String = ""
return "待审核" var company_english_name: String = ""
case 1: var resource_provided: String = "" // 提供的服务
return "已发布" var demand_published: String = "" // 发布的需求
case 2: var industry_type: Int = 0
return "已下架" var industry_type_str: String = ""
default:
return "未知" // MARK: - 详情字段(从详情接口获取后填充)
} var company_introduction: String = "" // 公司介绍
} var company_business: String = "" // 主营业务
var company_information: [YHCompanyDocument] = [] // 公司资料
var settlement_status: Int = 0
var settlement_status_str: String = ""
/// 认证状态显示 // MARK: - 计算属性
var certificationDisplayName: String {
return certification_status == 1 ? "已认证" : "未认证"
}
/// 是否已认证 /// 公司Logo URL
var isCertified: Bool { var companyLogoUrl: String {
return certification_status == 1 return company_avatar?.url ?? ""
} }
/// 是否为服务类型 /// 显示名称(优先显示中文名)
var isService: Bool { var displayName: String {
return type == "service" return company_name.isEmpty ? company_english_name : company_name
} }
/// 是否为需求类型 /// 是否有英文名
var isDemand: Bool { var hasEnglishName: Bool {
return type == "demand" return !company_english_name.isEmpty
} }
/// 是否已过期 /// 行业类型显示文本
var isExpired: Bool { var industryDisplayText: String {
guard !expires_time.isEmpty else { return false } return industry_type_str.isEmpty ? "其他" : industry_type_str
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
guard let expireDate = formatter.date(from: expires_time) else { return false }
return Date() > expireDate
} }
/// 剩余天数 /// 是否提供服务
var remainingDays: Int { var hasResourceProvided: Bool {
guard !expires_time.isEmpty else { return -1 } return !resource_provided.isEmpty
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
guard let expireDate = formatter.date(from: expires_time) else { return -1 }
let calendar = Calendar.current
let components = calendar.dateComponents([.day], from: Date(), to: expireDate)
return components.day ?? -1
} }
/// 热度值(综合点击、收藏、分享等) /// 是否有需求
var hotScore: Int { var hasDemandPublished: Bool {
return view_count + favorite_count * 2 + share_count * 3 + comment_count * 1 return !demand_published.isEmpty
} }
/// 第一张图片URL /// 服务和需求显示文本
var firstImageUrl: String { var serviceInfoText: String {
return images.first ?? "" var texts: [String] = []
if hasResourceProvided {
texts.append("服务: \(resource_provided)")
}
if hasDemandPublished {
texts.append("需求: \(demand_published)")
}
return texts.joined(separator: " | ")
} }
/// 是否有图片 /// ID字符串(用于兼容旧代码)
var hasImages: Bool { var idString: String {
return !images.isEmpty return "\(id)"
} }
/// 标签字符串(用逗号分隔) // MARK: - 兼容旧字段的计算属性
var tagsString: String {
return tags.joined(separator: ", ")
}
// MARK: - 计算Cell高度方法 /// 企业介绍(兼容旧字段 content)
func didFinishMapping() { var content: String {
if needNewLine == nil { return company_introduction.isEmpty ?
needNewLine = calculateNeedNewLine() (resource_provided.isEmpty ? demand_published : resource_provided) :
} company_introduction
} }
func calculateNeedNewLine() -> Bool { /// 分类名称(兼容旧字段 category_name)
let company = company_name.count > 0 ? company_name : "-" var category_name: String {
let categoryName = category_name.count > 0 ? category_name : "-" return industry_type_str
let companyWidth = YHResourceTableViewCell.getLabelWidth(company)
let categoryNameWidth = YHResourceTableViewCell.getLabelWidth(categoryName)
return companyWidth + categoryNameWidth >= KScreenWidth - YHResourceTableViewCell.logoWidth - YHResourceTableViewCell.logoToRight - YHResourceTableViewCell.arrowWidth - 2 * YHResourceTableViewCell.marginX - YHResourceTableViewCell.widthVLine - YHResourceTableViewCell.marginBetweenVLine * 2
} }
// MARK: - 便利方法 /// 服务周期(兼容旧字段 service_duration)
var service_duration: String {
/// 更新收藏状态 return company_business
func updateFavoriteStatus(_ isFavorite: Bool) {
is_favorite = isFavorite
if isFavorite {
favorite_count += 1
} else {
favorite_count = max(0, favorite_count - 1)
}
} }
/// 增加浏览量 /// 图片数组(兼容旧字段 images)
func incrementViewCount() { var images: [String] {
view_count += 1 return company_information.map { $0.url }
} }
/// 增加分享数 // MARK: - 便利方法
func incrementShareCount() {
share_count += 1
}
/// 验证数据完整性 /// 验证数据完整性
func isValid() -> Bool { func isValid() -> Bool {
return !id.isEmpty && return id > 0 && !displayName.isEmpty
!title.isEmpty &&
!content.isEmpty &&
!company_name.isEmpty &&
!contact_name.isEmpty &&
!contact_phone.isEmpty &&
!category_id.isEmpty
} }
/// 获取联系方式字符串 /// 更新详情数据(从详情接口获取后调用)
func getContactInfo() -> String { func updateWithDetail(_ detail: YHResourceDetailModel) {
var contactInfo = contact_name self.company_introduction = detail.company_introduction
if !contact_phone.isEmpty { self.company_business = detail.company_business
contactInfo += " \(contact_phone)" self.company_information = detail.company_information
self.settlement_status = detail.settlement_status
self.settlement_status_str = detail.settlement_status_str
// 如果需要,可以更新其他字段
if self.resource_provided.isEmpty {
self.resource_provided = detail.resource_provided
} }
if !contact_wechat.isEmpty { if self.demand_published.isEmpty {
contactInfo += " 微信:\(contact_wechat)" self.demand_published = detail.demand_published
} }
return contactInfo }
/// 增加浏览量(兼容方法)
func incrementViewCount() {
// 如果需要调用接口增加浏览量,在这里实现
print("增加浏览量")
} }
} }
...@@ -251,6 +221,29 @@ class YHResourceCategory: SmartCodable { ...@@ -251,6 +221,29 @@ class YHResourceCategory: SmartCodable {
} }
} }
// MARK: - 行业分类响应模型
class YHIndustryTypeResponse: SmartCodable {
required init() {}
var industry_type: [YHIndustryTypeModel] = []
}
// MARK: - 行业类型模型
class YHIndustryTypeModel: SmartCodable {
required init() {}
var id: String = ""
var name: String = ""
/// 转换为YHResourceCategory(用于兼容现有UI)
func toResourceCategory() -> YHResourceCategory {
let category = YHResourceCategory()
category.id = id
category.name = name
return category
}
}
// MARK: - String Extension // MARK: - String Extension
extension String { extension String {
func toDisplayTime() -> String { func toDisplayTime() -> String {
......
...@@ -40,6 +40,11 @@ class YHResourceCategoryView: UIView { ...@@ -40,6 +40,11 @@ class YHResourceCategoryView: UIView {
private lazy var bottomButtonContainer: UIView = { private lazy var bottomButtonContainer: UIView = {
let view = UIView() let view = UIView()
view.backgroundColor = .white view.backgroundColor = .white
// 添加顶部阴影
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 0, height: -2)
view.layer.shadowOpacity = 0.05
view.layer.shadowRadius = 4
return view return view
}() }()
...@@ -81,13 +86,11 @@ class YHResourceCategoryView: UIView { ...@@ -81,13 +86,11 @@ class YHResourceCategoryView: UIView {
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setupUI() setupUI()
loadCategories()
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
setupUI() setupUI()
loadCategories()
} }
// MARK: - Setup // MARK: - Setup
...@@ -130,87 +133,17 @@ class YHResourceCategoryView: UIView { ...@@ -130,87 +133,17 @@ class YHResourceCategoryView: UIView {
} }
} }
private func loadCategories() { // MARK: - Public Methods
// 模拟数据,实际使用时从接口获取
let allCategory = YHResourceCategory() /// 设置分类数据(从外部传入,通常来自API)
allCategory.id = "0" /// - Parameter categories: 分类数组
allCategory.name = "全部行业" func setCategories(_ categories: [YHResourceCategory]) {
self.categories = categories
let category1 = YHResourceCategory()
category1.id = "1"
category1.name = "金融会计"
let category2 = YHResourceCategory()
category2.id = "2"
category2.name = "资讯科技"
let category3 = YHResourceCategory()
category3.id = "3"
category3.name = "业务支持"
let category4 = YHResourceCategory()
category4.id = "4"
category4.name = "工业制造"
let category5 = YHResourceCategory()
category5.id = "5"
category5.name = "建筑工程"
let category6 = YHResourceCategory()
category6.id = "6"
category6.name = "地产开发"
let category7 = YHResourceCategory()
category7.id = "7"
category7.name = "法律服务"
let category8 = YHResourceCategory()
category8.id = "8"
category8.name = "商业贸易"
let category9 = YHResourceCategory()
category9.id = "9"
category9.name = "物流运输"
let category10 = YHResourceCategory()
category10.id = "10"
category10.name = "餐饮旅游"
let category11 = YHResourceCategory()
category11.id = "11"
category11.name = "广播娱乐"
let category12 = YHResourceCategory()
category12.id = "12"
category12.name = "艺术文化"
let category13 = YHResourceCategory()
category13.id = "13"
category13.name = "体育运动"
let category14 = YHResourceCategory()
category14.id = "14"
category14.name = "医疗健康"
let category15 = YHResourceCategory()
category15.id = "15"
category15.name = "学术教育"
let category16 = YHResourceCategory()
category16.id = "16"
category16.name = "其他"
categories = [
allCategory, category1, category2, category3, category4, category5,
category6, category7, category8, category9, category10, category11,
category12, category13, category14, category15, category16
]
collectionView.reloadData() collectionView.reloadData()
} }
// MARK: - Public Methods /// 设置已选中的分类
/// - Parameter categories: 已选中的分类数组
func setSelectedCategories(_ categories: [YHResourceCategory]) { func setSelectedCategories(_ categories: [YHResourceCategory]) {
selectedCategories = categories selectedCategories = categories
collectionView.reloadData() collectionView.reloadData()
...@@ -219,7 +152,7 @@ class YHResourceCategoryView: UIView { ...@@ -219,7 +152,7 @@ class YHResourceCategoryView: UIView {
// MARK: - Actions // MARK: - Actions
@objc private func resetButtonClicked() { @objc private func resetButtonClicked() {
// 重置为"全部行业" // 重置:清空所有选择
selectedCategories.removeAll() selectedCategories.removeAll()
collectionView.reloadData() collectionView.reloadData()
delegate?.categoryView(self, didSelectCategories: selectedCategories, isSet: false) delegate?.categoryView(self, didSelectCategories: selectedCategories, isSet: false)
...@@ -238,7 +171,8 @@ extension YHResourceCategoryView: UICollectionViewDataSource, UICollectionViewDe ...@@ -238,7 +171,8 @@ extension YHResourceCategoryView: UICollectionViewDataSource, UICollectionViewDe
} }
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard categories.count > indexPath.item, let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YHResourceCategoryCell", for: indexPath) as? YHResourceCategoryCell else { guard categories.count > indexPath.item,
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YHResourceCategoryCell", for: indexPath) as? YHResourceCategoryCell else {
return UICollectionViewCell() return UICollectionViewCell()
} }
...@@ -252,28 +186,20 @@ extension YHResourceCategoryView: UICollectionViewDataSource, UICollectionViewDe ...@@ -252,28 +186,20 @@ extension YHResourceCategoryView: UICollectionViewDataSource, UICollectionViewDe
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let category = categories[indexPath.item] let category = categories[indexPath.item]
// 如果是"全部行业",清空其他选择 // 切换选中状态(支持多选)
if category.id == "0" { if let index = selectedCategories.firstIndex(where: { $0.id == category.id }) {
selectedCategories.removeAll() // 如果已选中,则取消选中
selectedCategories.append(category) selectedCategories.remove(at: index)
} else { } else {
// 移除"全部行业"选项 // 如果未选中,则添加到选中列表
selectedCategories.removeAll { $0.id == "0" } selectedCategories.append(category)
// 切换选中状态
if let index = selectedCategories.firstIndex(where: { $0.id == category.id }) {
selectedCategories.remove(at: index)
} else {
selectedCategories.append(category)
}
// // 如果没有选中任何分类,自动选中"全部行业"
// if selectedCategories.isEmpty {
// selectedCategories.append(categories.first!)
// }
} }
// 刷新UI
collectionView.reloadData() collectionView.reloadData()
// 通知代理(不自动关闭,用户需要点击"筛选"按钮)
delegate?.categoryView(self, didSelectCategories: selectedCategories, isSet: false)
} }
} }
...@@ -295,9 +221,16 @@ extension YHResourceCategoryView: UICollectionViewDelegateFlowLayout { ...@@ -295,9 +221,16 @@ extension YHResourceCategoryView: UICollectionViewDelegateFlowLayout {
// MARK: - YHResourceCategoryCell // MARK: - YHResourceCategoryCell
class YHResourceCategoryCell: UICollectionViewCell { class YHResourceCategoryCell: UICollectionViewCell {
private lazy var iconLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 18)
label.textAlignment = .center
return label
}()
private lazy var titleLabel: UILabel = { private lazy var titleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = UIFont.PFSC_R(ofSize: 14) label.font = UIFont.PFSC_R(ofSize: 13)
label.textAlignment = .center label.textAlignment = .center
label.textColor = .brandGrayColor8 label.textColor = .brandGrayColor8
label.numberOfLines = 1 label.numberOfLines = 1
...@@ -306,6 +239,15 @@ class YHResourceCategoryCell: UICollectionViewCell { ...@@ -306,6 +239,15 @@ class YHResourceCategoryCell: UICollectionViewCell {
return label return label
}() }()
private lazy var containerStackView: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.spacing = 4
stack.alignment = .center
stack.distribution = .fill
return stack
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
setupUI() setupUI()
...@@ -318,26 +260,43 @@ class YHResourceCategoryCell: UICollectionViewCell { ...@@ -318,26 +260,43 @@ class YHResourceCategoryCell: UICollectionViewCell {
private func setupUI() { private func setupUI() {
backgroundColor = UIColor.brandGrayColor2 backgroundColor = UIColor.brandGrayColor2
layer.cornerRadius = 2// 调整圆角以适应新高度 layer.cornerRadius = 2
layer.borderWidth = 1 layer.borderWidth = 1
layer.borderColor = UIColor.clear.cgColor layer.borderColor = UIColor.clear.cgColor
contentView.addSubview(titleLabel) contentView.addSubview(containerStackView)
containerStackView.addArrangedSubview(iconLabel)
containerStackView.addArrangedSubview(titleLabel)
titleLabel.snp.makeConstraints { make in containerStackView.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 12, left: 4, bottom: 12, right: 4)) make.center.equalToSuperview()
make.left.greaterThanOrEqualToSuperview().offset(8)
make.right.lessThanOrEqualToSuperview().offset(-8)
} }
iconLabel.setContentHuggingPriority(.required, for: .horizontal)
titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
} }
func configure(with category: YHResourceCategory, isSelected: Bool) { func configure(with category: YHResourceCategory, isSelected: Bool) {
// 设置图标(如果有)
if !category.icon.isEmpty {
iconLabel.text = category.icon
iconLabel.isHidden = false
} else {
iconLabel.isHidden = true
}
titleLabel.text = category.name titleLabel.text = category.name
if isSelected { if isSelected {
layer.borderColor = UIColor.brandGrayColor8.cgColor layer.borderColor = UIColor.brandGrayColor8.cgColor
titleLabel.font = UIFont.PFSC_B(ofSize: 14) titleLabel.font = UIFont.PFSC_B(ofSize: 13)
titleLabel.textColor = UIColor.brandGrayColor8
} else { } else {
layer.borderColor = UIColor.clear.cgColor layer.borderColor = UIColor.clear.cgColor
titleLabel.font = UIFont.PFSC_R(ofSize: 14) titleLabel.font = UIFont.PFSC_R(ofSize: 13)
titleLabel.textColor = UIColor.brandGrayColor7
} }
} }
} }
...@@ -70,13 +70,19 @@ class YHResourceDetailBaseInfoCell: UITableViewCell { ...@@ -70,13 +70,19 @@ class YHResourceDetailBaseInfoCell: UITableViewCell {
} }
} }
func configure(with model: YHResourceListModel) { func configure(with model: YHResourceDetailModel) {
stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } stackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
addInfoRow(title: "企业介绍", content: model.content.isEmpty ? "未填写" : model.content) // 使用详情接口的字段
addInfoRow(title: "主营业务", content: model.category_name.isEmpty ? "未填写" : model.category_name) addInfoRow(title: "企业介绍", content: model.company_introduction.isEmpty ? "未填写" : model.company_introduction)
addInfoRow(title: "提供服务", content: model.service_duration.isEmpty ? "未填写" : model.service_duration) addInfoRow(title: "主营业务", content: model.company_business.isEmpty ? "未填写" : model.company_business)
addInfoRow(title: "行业类型", content: model.category_name.isEmpty ? "未填写" : model.category_name) addInfoRow(title: "提供服务", content: model.resource_provided.isEmpty ? "未填写" : model.resource_provided)
addInfoRow(title: "发布需求", content: model.demand_published.isEmpty ? "未填写" : model.demand_published)
addInfoRow(title: "行业类型", content: model.industry_type_str.isEmpty ? "未填写" : model.industry_type_str)
if !model.settlement_status_str.isEmpty {
addInfoRow(title: "入驻状态", content: model.settlement_status_str)
}
} }
private func addInfoRow(title: String, content: String) { private func addInfoRow(title: String, content: String) {
...@@ -98,7 +104,7 @@ class YHResourceDetailBaseInfoCell: UITableViewCell { ...@@ -98,7 +104,7 @@ class YHResourceDetailBaseInfoCell: UITableViewCell {
contentLabel.font = UIFont.PFSC_R(ofSize: 13) contentLabel.font = UIFont.PFSC_R(ofSize: 13)
contentLabel.textColor = UIColor.brandGrayColor8 contentLabel.textColor = UIColor.brandGrayColor8
contentLabel.text = content contentLabel.text = content
contentLabel.numberOfLines = 4 contentLabel.numberOfLines = 0
contentLabel.textAlignment = .left contentLabel.textAlignment = .left
container.addSubview(titleLabel) container.addSubview(titleLabel)
...@@ -110,7 +116,7 @@ class YHResourceDetailBaseInfoCell: UITableViewCell { ...@@ -110,7 +116,7 @@ class YHResourceDetailBaseInfoCell: UITableViewCell {
titleLabel.snp.makeConstraints { make in titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview() make.left.equalToSuperview()
make.top.equalToSuperview() make.top.equalToSuperview()
make.bottom.lessThanOrEqualToSuperview() make.width.equalTo(70)
} }
contentLabel.snp.makeConstraints { make in contentLabel.snp.makeConstraints { make in
......
...@@ -36,7 +36,7 @@ class YHResourceDetailDemandCell: UITableViewCell { ...@@ -36,7 +36,7 @@ class YHResourceDetailDemandCell: UITableViewCell {
let label = UILabel() let label = UILabel()
label.font = UIFont.PFSC_R(ofSize: 13) label.font = UIFont.PFSC_R(ofSize: 13)
label.textColor = UIColor.brandGrayColor8 label.textColor = UIColor.brandGrayColor8
label.numberOfLines = 4 label.numberOfLines = 0
return label return label
}() }()
...@@ -66,15 +66,15 @@ class YHResourceDetailDemandCell: UITableViewCell { ...@@ -66,15 +66,15 @@ class YHResourceDetailDemandCell: UITableViewCell {
} }
demandTitleLabel.snp.makeConstraints { make in demandTitleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16) make.left.equalToSuperview().offset(20)
make.top.equalTo(titleLabel.snp.bottom).offset(16) make.top.equalTo(titleLabel.snp.bottom).offset(16)
make.width.equalTo(70)
} }
demandContentLabel.snp.makeConstraints { make in demandContentLabel.snp.makeConstraints { make in
make.left.equalTo(demandTitleLabel.snp.right).offset(12) make.left.equalTo(demandTitleLabel.snp.right).offset(12)
make.right.equalToSuperview().offset(-20) make.right.equalToSuperview().offset(-20)
make.top.equalTo(demandTitleLabel) make.top.equalTo(demandTitleLabel)
} }
dividerView.snp.makeConstraints { make in dividerView.snp.makeConstraints { make in
...@@ -85,7 +85,8 @@ class YHResourceDetailDemandCell: UITableViewCell { ...@@ -85,7 +85,8 @@ class YHResourceDetailDemandCell: UITableViewCell {
} }
} }
func configure(with model: YHResourceListModel) { func configure(with model: YHResourceDetailModel) {
demandContentLabel.text = model.title.isEmpty ? "未填写" : model.title // 使用详情接口的 demand_published 字段
demandContentLabel.text = model.demand_published.isEmpty ? "未填写" : model.demand_published
} }
} }
...@@ -133,7 +133,7 @@ class YHResourceDetailDocumentsCell: UITableViewCell { ...@@ -133,7 +133,7 @@ class YHResourceDetailDocumentsCell: UITableViewCell {
} }
let imageWidth = KScreenWidth - 20 * 2 // 左右各16的padding let imageWidth = KScreenWidth - 20 * 2 // 左右各16的padding
let imageHeight = imageWidth * 1.4 // A4纸张比例 let imageHeight = imageWidth * 1.0 // A4纸张比例
for (index, imageUrl) in images.enumerated() { for (index, imageUrl) in images.enumerated() {
let imageView = UIImageView() let imageView = UIImageView()
......
...@@ -7,15 +7,18 @@ ...@@ -7,15 +7,18 @@
// //
import UIKit import UIKit
import Kingfisher
class YHResourceDetailHeaderCell: UITableViewCell { class YHResourceDetailHeaderCell: UITableViewCell {
private lazy var logoImageView: UIImageView = { private lazy var logoImageView: UIImageView = {
let imageView = UIImageView() let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true imageView.clipsToBounds = true
imageView.layer.cornerRadius = 4 imageView.layer.cornerRadius = 4
imageView.backgroundColor = .white imageView.backgroundColor = .white
imageView.layer.borderWidth = 1
imageView.layer.borderColor = UIColor.brandGrayColor3.cgColor
return imageView return imageView
}() }()
...@@ -72,11 +75,26 @@ class YHResourceDetailHeaderCell: UITableViewCell { ...@@ -72,11 +75,26 @@ class YHResourceDetailHeaderCell: UITableViewCell {
} }
} }
func configure(with model: YHResourceListModel) { func configure(with model: YHResourceDetailModel) {
if let url = URL(string: model.company_logo) { // 设置Logo
logoImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "people_head_default")) if !model.companyLogoUrl.isEmpty {
logoImageView.kf.setImage(
with: URL(string: model.companyLogoUrl),
placeholder: UIImage(named: "global_default_image")
)
} else {
logoImageView.image = UIImage(named: "global_default_image")
}
// 设置公司名称
companyNameLabel.text = model.displayName
// 设置英文名称
if !model.company_english_name.isEmpty {
companyEnglishNameLabel.text = model.company_english_name
companyEnglishNameLabel.isHidden = false
} else {
companyEnglishNameLabel.isHidden = true
} }
companyNameLabel.text = model.company_name
companyEnglishNameLabel.text = "JUXIN CERTIFIED PUBLIC ACCOUNTANTS FIRM"
} }
} }
...@@ -191,83 +191,35 @@ extension YHResourceTableViewCell { ...@@ -191,83 +191,35 @@ extension YHResourceTableViewCell {
private func updateUI() { private func updateUI() {
guard let model = resourceModel else { return } guard let model = resourceModel else { return }
// 设置基本信息 // 设置基本信息 - 使用新的API字段
let title = model.title.count > 0 ? model.title : "-" titleLabel.text = getServiceOrDemandText(model: model) // 显示服务或需求信息
let company = model.company_name.count > 0 ? model.company_name : "-" companyLabel.text = model.displayName // 使用 company_name
let categoryName = model.category_name.count > 0 ? model.category_name : "-" industryLabel.text = model.industryDisplayText // 使用 industry_type_str
titleLabel.text = title
companyLabel.text = company
industryLabel.text = categoryName
var needNext = false
if let needNewLine = model.needNewLine {
needNext = needNewLine
} else {
let needNewLine = model.calculateNeedNewLine()
model.needNewLine = needNewLine
needNext = needNewLine
}
if !needNext {
companyLabel.snp.remakeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(4)
}
vSeparatorLine.snp.remakeConstraints { make in
make.left.equalTo(companyLabel.snp.right).offset(YHResourceTableViewCell.marginBetweenVLine)
make.centerY.equalTo(companyLabel)
make.width.equalTo(1)
make.height.equalTo(8)
}
// 行业标签约束
industryLabel.snp.remakeConstraints { make in
make.left.equalTo(vSeparatorLine.snp.right).offset(YHResourceTableViewCell.marginBetweenVLine)
make.right.lessThanOrEqualTo(rightArrow.snp.left)
make.top.equalTo(companyLabel)
make.bottom.equalToSuperview().offset(-32)
}
} else {
companyLabel.snp.remakeConstraints { make in
make.left.equalTo(titleLabel)
make.right.lessThanOrEqualTo(rightArrow.snp.left)
make.top.equalTo(titleLabel.snp.bottom).offset(4)
}
vSeparatorLine.snp.remakeConstraints { make in
make.left.equalTo(companyLabel.snp.left)
make.centerY.equalTo(industryLabel)
make.width.equalTo(1)
make.height.equalTo(8)
}
// 行业标签约束
industryLabel.snp.remakeConstraints { make in
make.left.equalTo(vSeparatorLine.snp.right).offset(YHResourceTableViewCell.marginBetweenVLine)
make.right.lessThanOrEqualTo(rightArrow.snp.left)
make.top.equalTo(companyLabel.snp.bottom).offset(4)
make.bottom.equalToSuperview().offset(-32)
}
}
// 设置Logo // 设置Logo - 使用新的API字段
if !model.company_logo.isEmpty { if !model.companyLogoUrl.isEmpty {
logoImageView.kf.setImage( logoImageView.kf.setImage(
with: URL(string: model.company_logo), with: URL(string: model.companyLogoUrl),
placeholder: UIImage(named: "global_default_image") placeholder: UIImage(named: "global_default_image")
) )
} else { } else {
logoImageView.image = UIImage(named: "global_default_image") logoImageView.image = UIImage(named: "global_default_image")
} }
// 设置类型标签 // 设置类型标签 - 根据是服务还是需求
if model.type == "service" { if model.isService {
typeTagIcon.image = UIImage(named: "resource_flag_service") typeTagIcon.image = UIImage(named: "resource_flag_service")
} else if model.type == "demand" {
typeTagIcon.image = UIImage(named: "resource_flag_demand")
} else { } else {
typeTagIcon.image = nil typeTagIcon.image = UIImage(named: "resource_flag_demand")
} }
} }
/// 获取服务或需求文本
private func getServiceOrDemandText(model: YHResourceListModel) -> String {
if model.isService {
return model.resource_provided.isEmpty ? "-" : model.resource_provided
} else {
return model.demand_published.isEmpty ? "-" : model.demand_published
}
}
} }
...@@ -16,6 +16,7 @@ class YHResourceViewModel: NSObject { ...@@ -16,6 +16,7 @@ class YHResourceViewModel: NSObject {
var currentPage: Int = 1 var currentPage: Int = 1
var pageSize: Int = 20 var pageSize: Int = 20
var preloadItemIndex: Int = 10 var preloadItemIndex: Int = 10
var totalCount: Int = 0
// 筛选条件 // 筛选条件
var currentType: YHResourceFilterType = .service var currentType: YHResourceFilterType = .service
...@@ -28,7 +29,7 @@ class YHResourceViewModel: NSObject { ...@@ -28,7 +29,7 @@ class YHResourceViewModel: NSObject {
// MARK: - 网络请求 // MARK: - 网络请求
/// 获取资源列表 /// 获取资源列表(公司列表)
/// - Parameters: /// - Parameters:
/// - firstFlag: 是否首次加载 /// - firstFlag: 是否首次加载
/// - completion: 完成回调 /// - completion: 完成回调
...@@ -45,16 +46,17 @@ class YHResourceViewModel: NSObject { ...@@ -45,16 +46,17 @@ class YHResourceViewModel: NSObject {
} }
} }
// 构建请求参数
var params: [String: Any] = [ var params: [String: Any] = [
"page": currentPage, "page": currentPage,
"page_size": pageSize, "page_size": pageSize,
"type": currentType == .service ? "service" : "demand" "type": currentType == .service ? 1 : 2 // 1-服务 2-需求
] ]
// 添加分类筛选(多选) // 添加分类筛选(多选)- 转为Int数组
if !selectedCategories.isEmpty { if !selectedCategories.isEmpty {
let categoryIds = selectedCategories.map { $0.id } let categoryIds = selectedCategories.compactMap { Int($0.id) }
params["category_ids"] = categoryIds params["industry_type"] = categoryIds
} }
// 添加搜索关键词 // 添加搜索关键词
...@@ -62,229 +64,110 @@ class YHResourceViewModel: NSObject { ...@@ -62,229 +64,110 @@ class YHResourceViewModel: NSObject {
params["keyword"] = keyword params["keyword"] = keyword
} }
// 模拟网络延迟 // 调用真实API
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.Resource.companyList
let mockData = self.generateMockResourceData(page: self.currentPage)
_ = YHNetRequest.postRequest(url: strUrl, params: params) { [weak self] json, _ in
if firstFlag { guard let self = self else { return }
self.arrResourceData = mockData
} else { if json.code == 200 {
self.arrResourceData?.append(contentsOf: mockData) guard let dic = json.data?.peel as? [String: Any],
} let result = YHResourceListResponse.deserialize(from: dic) else {
completion(false, "数据解析失败")
self.currentPage += 1 return
self.hasMoreForResource = self.currentPage <= 5 // 模拟5页数据 }
completion(true, nil) if firstFlag {
} self.totalCount = result.total
} self.arrResourceData = result.list
} else {
/// 切换收藏状态 self.arrResourceData?.append(contentsOf: result.list)
/// - Parameters: }
/// - resourceId: 资源ID
/// - completion: 完成回调 self.currentPage += 1
func toggleFavorite(resourceId: String, completion: @escaping (Bool, String?) -> Void) {
// 模拟网络延迟 // 判断是否还有更多数据
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { if (self.arrResourceData?.count ?? 0) >= self.totalCount {
if let index = self.arrResourceData?.firstIndex(where: { $0.id == resourceId }) { self.hasMoreForResource = false
let item = self.arrResourceData![index] } else {
item.updateFavoriteStatus(!item.is_favorite) self.hasMoreForResource = true
}
completion(true, nil) completion(true, nil)
} else { } else {
completion(false, "资源不存在") let errorMsg = json.msg.isEmpty ? "获取数据失败" : json.msg
completion(false, errorMsg)
} }
} failBlock: { err in
let errorMsg = err.errorMsg
completion(false, errorMsg)
} }
} }
/// 获取资源分类 /// 获取资源分类(行业类型)
/// - Parameter completion: 完成回调 /// - Parameter completion: 完成回调
func getResourceCategories(completion: @escaping ([YHResourceCategory]?, String?) -> Void) { func getResourceCategories(completion: @escaping ([YHResourceCategory]?, String?) -> Void) {
// 模拟网络延迟 let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.Resource.categoryList
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
let categories = self.generateMockCategories() _ = YHNetRequest.getRequest(url: strUrl, params: [:]) { json, _ in
completion(categories, nil) if json.code == 200 {
guard let dic = json.data?.peel as? [String: Any],
let result = YHIndustryTypeResponse.deserialize(from: dic) else {
completion(nil, "数据解析失败")
return
}
// 转换为YHResourceCategory数组
let categories = result.industry_type.map { $0.toResourceCategory() }
completion(categories, nil)
} else {
let errorMsg = json.msg.isEmpty ? "获取分类失败" : json.msg
completion(nil, errorMsg)
}
} failBlock: { err in
let errorMsg = err.errorMsg
completion(nil, errorMsg)
} }
} }
// MARK: - Mock数据生成 /// 获取公司详情
/// - Parameters:
private func generateMockResourceData(page: Int) -> [YHResourceListModel] { /// - companyId: 公司ID
let serviceTitles = [ /// - completion: 完成回调
"专业财务咨询服务", func getCompanyDetail(companyId: Int, completion: @escaping (YHResourceDetailModel?, String?) -> Void) {
"企业IT系统开发", let params: [String: Any] = ["id": companyId]
"品牌营销策划方案", let strUrl = YHBaseUrlManager.shared.curURL() + YHAllApiName.Resource.companyDetail
"法律顾问服务",
"人力资源管理咨询",
"企业培训服务",
"网站建设与维护",
"财务审计服务"
]
let demandTitles = [
"寻找优质供应商",
"招聘高级技术人员",
"需要市场推广合作",
"寻求投资合作伙伴",
"需要办公场地租赁",
"寻找物流配送服务",
"需要设备采购咨询",
"寻求技术合作"
]
let companies = [
("北京科技有限公司哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈", "https://picsum.photos/60/60?random=1"),
("上海贸易集团", "https://picsum.photos/60/60?random=2"),
("深圳创新科技", "https://picsum.photos/60/60?random=3"),
("杭州电商公司", "https://picsum.photos/60/60?random=4"),
("成都软件开发", "https://picsum.photos/60/60?random=5"),
("广州制造企业", "https://picsum.photos/60/60?random=6"),
("武汉咨询公司", "https://picsum.photos/60/60?random=7"),
("西安技术公司", "https://picsum.photos/60/60?random=8")
]
let categories = [
("finance", "金融会计哈哈哈哈哈哈"),
("tech", "资讯科技"),
("business", "业务支援"),
("manufacturing", "工业制造"),
("legal", "法律服务"),
("trade", "商业贸易"),
("logistics", "物流运输"),
("other", "其他")
]
let contacts = [
("张经理", "138****1234", "zhang123"),
("李总监", "139****5678", "li_manager"),
("王助理", "136****9876", "wang_assistant"),
("赵主管", "137****4321", "zhao_supervisor"),
("孙经理", "135****8765", "sun_manager"),
("周总", "134****2468", "zhou_boss"),
("吴主任", "133****1357", "wu_director"),
("郑经理", "132****9753", "zheng_manager")
]
let locations = ["北京·朝阳区", "上海·浦东新区", "深圳·南山区", "杭州·西湖区", "成都·锦江区", "广州·天河区", "武汉·江汉区", "西安·雁塔区"]
let contents = [
"我们提供专业的财务咨询服务,帮助企业优化财务结构,降低运营成本,提高资金使用效率。团队拥有10年以上行业经验。",
"专业的IT系统开发团队,提供定制化解决方案,包括Web应用、移动应用、企业管理系统等。技术栈涵盖主流开发框架。",
"专注品牌营销策划,提供全方位的品牌推广方案。从品牌定位到执行落地,一站式服务,已服务500+企业客户。",
"资深律师团队提供专业法律顾问服务,涵盖合同审查、法律风险评估、争议解决等。保障企业合规经营。",
"人力资源管理专家,提供招聘、培训、绩效管理等全方位HR服务。帮助企业建立完善的人才管理体系。",
"企业培训专业机构,提供管理培训、技能培训、团队建设等服务。定制化课程设计,提升员工综合素质。",
"专业网站建设团队,提供网站设计、开发、运维一体化服务。响应式设计,SEO优化,提升企业网络形象。",
"注册会计师团队提供财务审计服务,确保财务报表真实可靠。严格按照审计准则执行,保障审计质量。"
]
// 根据筛选条件过滤数据
var filteredData: [YHResourceListModel] = []
for i in 0..<8 { _ = YHNetRequest.getRequest(url: strUrl, params: params) { json, _ in
let model = YHResourceListModel() if json.code == 200 {
let baseId = (page - 1) * 8 + i guard let dic = json.data?.peel as? [String: Any],
let result = YHResourceDetailModel.deserialize(from: dic) else {
model.id = "resource_\(baseId)" completion(nil, "数据解析失败")
return
// 根据当前类型选择标题 }
let titles = currentType == .service ? serviceTitles : demandTitles
model.title = titles[i % titles.count] completion(result, nil)
model.content = contents[i % contents.count] } else {
model.type = currentType == .service ? "service" : "demand" let errorMsg = json.msg.isEmpty ? "获取详情失败" : json.msg
completion(nil, errorMsg)
// 公司信息
let company = companies[i % companies.count]
model.company_name = company.0
model.company_logo = company.1
// 分类信息
let category = categories[i % categories.count]
model.category_id = category.0
model.category_name = category.1
// 联系信息
let contact = contacts[i % contacts.count]
model.contact_name = contact.0
model.contact_phone = contact.1
model.contact_wechat = contact.2
// 其他信息
model.location = locations[i % locations.count]
model.price = i % 3 == 0 ? "" : "\(Int.random(in: 1000...9999))"
model.price_unit = i % 3 == 0 ? "" : ["小时", "天", "月", "项目"][i % 4]
model.view_count = Int.random(in: 10...999)
model.favorite_count = Int.random(in: 0...50)
model.is_favorite = Bool.random()
model.status = 1 // 已发布
model.certification_status = i % 2 // 随机认证状态
// 时间
let daysAgo = Int.random(in: 0...30)
let date = Calendar.current.date(byAdding: .day, value: -daysAgo, to: Date()) ?? Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
model.created_time = formatter.string(from: date)
// 图片(随机添加1-3张图片)
let imageCount = Int.random(in: 0...3)
model.images = (0..<imageCount).map { "https://picsum.photos/300/200?random=\(baseId)_\($0)" }
// 标签
let allTags = ["优质服务", "专业团队", "价格优惠", "经验丰富", "快速响应", "全程跟踪", "售后保障", "行业领先"]
let tagCount = Int.random(in: 0...3)
model.tags = Array(allTags.shuffled().prefix(tagCount))
// 应用筛选条件
var shouldInclude = true
// 分类筛选
if !selectedCategories.isEmpty {
let categoryIds = selectedCategories.map { $0.id }
shouldInclude = shouldInclude && categoryIds.contains(model.category_id)
}
// 搜索关键词筛选
if let keyword = searchKeyword, !keyword.isEmpty {
let searchText = "\(model.title) \(model.content) \(model.company_name)".lowercased()
shouldInclude = shouldInclude && searchText.contains(keyword.lowercased())
} }
if shouldInclude { } failBlock: { err in
filteredData.append(model) let errorMsg = err.errorMsg
} completion(nil, errorMsg)
} }
return filteredData
} }
private func generateMockCategories() -> [YHResourceCategory] { /// 切换收藏状态(如果有收藏功能的话)
let categoryData = [ /// - Parameters:
("finance", "金融会计", "💰"), /// - resourceId: 资源ID
("tech", "资讯科技", "💻"), /// - completion: 完成回调
("business", "业务支援", "📊"), func toggleFavorite(resourceId: String, completion: @escaping (Bool, String?) -> Void) {
("manufacturing", "工业制造", "🏭"), // TODO: 如果后端提供收藏接口,在这里实现
("construction", "建筑工程", "🏗️"), // 目前暂时不支持收藏功能
("real_estate", "地产开发", "🏢"), completion(false, "暂不支持收藏功能")
("legal", "法律服务", "⚖️"),
("trade", "商业贸易", "🛒"),
("logistics", "物流运输", "🚚"),
("food", "餐饮旅游", "🍽️"),
("media", "广播娱乐", "📺"),
("culture", "艺术文化", "🎨"),
("sports", "体育运动", "⚽"),
("health", "医疗健康", "🏥"),
("education", "学术教育", "📚"),
("other", "其他", "📋")
]
return categoryData.map { (id, name, icon) in
let category = YHResourceCategory()
category.id = id
category.name = name
category.icon = icon
category.resource_count = Int.random(in: 10...999)
category.is_hot = Int.random(in: 0...1) == 1
return category
}
} }
} }
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