服务商系统、调度APP新增服务商人员确认的功能

This commit is contained in:
ddisfriend
2025-12-29 11:21:07 +08:00
parent 787326cee7
commit 599077de2d
20 changed files with 517 additions and 68 deletions

View File

@@ -69,6 +69,7 @@
79B966382AB0651C00308A8D /* VehicleLogoutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79B966372AB0651C00308A8D /* VehicleLogoutView.swift */; };
79BF24412E9CEFB300FA5F1E /* OnlineVehiclesEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79BF24402E9CEFB300FA5F1E /* OnlineVehiclesEntryView.swift */; };
79CB07CC2AA8465A00154B61 /* UserPermission.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CB07CB2AA8465A00154B61 /* UserPermission.swift */; };
79CE24AA2EF52EAF007FCF90 /* IdentityAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CE24A92EF52EAF007FCF90 /* IdentityAlertView.swift */; };
79CECC122A89BD1A00B95D8B /* MessageCenterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CECC112A89BD1A00B95D8B /* MessageCenterController.swift */; };
79CECC192A89EE6A00B95D8B /* ReviewFailedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CECC182A89EE6A00B95D8B /* ReviewFailedController.swift */; };
79CECC1B2A89F83800B95D8B /* AdditionalPhotoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CECC1A2A89F83800B95D8B /* AdditionalPhotoController.swift */; };
@@ -207,6 +208,7 @@
79B966372AB0651C00308A8D /* VehicleLogoutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleLogoutView.swift; sourceTree = "<group>"; };
79BF24402E9CEFB300FA5F1E /* OnlineVehiclesEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlineVehiclesEntryView.swift; sourceTree = "<group>"; };
79CB07CB2AA8465A00154B61 /* UserPermission.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPermission.swift; sourceTree = "<group>"; };
79CE24A92EF52EAF007FCF90 /* IdentityAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentityAlertView.swift; sourceTree = "<group>"; };
79CECC112A89BD1A00B95D8B /* MessageCenterController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageCenterController.swift; sourceTree = "<group>"; };
79CECC182A89EE6A00B95D8B /* ReviewFailedController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewFailedController.swift; sourceTree = "<group>"; };
79CECC1A2A89F83800B95D8B /* AdditionalPhotoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdditionalPhotoController.swift; sourceTree = "<group>"; };
@@ -327,6 +329,7 @@
792EE0942AA74E0A00A212AB /* PushNotiCommonView.swift */,
792EE0962AA74E5800A212AB /* PushNotiCommonTool.swift */,
79BF24402E9CEFB300FA5F1E /* OnlineVehiclesEntryView.swift */,
79CE24A92EF52EAF007FCF90 /* IdentityAlertView.swift */,
);
path = View;
sourceTree = "<group>";
@@ -1202,6 +1205,7 @@
791887AE2A80F943007EA0C1 /* UserData.swift in Sources */,
79FB75EE2A9898EB00DB00A4 /* AcceptOrderView.swift in Sources */,
791887BA2A82495D007EA0C1 /* EnvironmentStrings.swift in Sources */,
79CE24AA2EF52EAF007FCF90 /* IdentityAlertView.swift in Sources */,
79D964E02E77FE2100309946 /* AppealInputViewController.swift in Sources */,
791887A62A80D50C007EA0C1 /* ParametersList.swift in Sources */,
);

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "mine_info_manage.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "mine_info_manage@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "mine_info_manage@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "IdentityAlertNotice.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "IdentityAlertNotice@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "IdentityAlertNotice@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -61,7 +61,7 @@ open class AppUpdateTool : NSObject {
UIApplication.shared.dd_keyWindow.rootViewController?.view.dd_showHUD()
})
.flatMapLatest { (type,_) in
return Observable.zip(RQ.versionCheck(parameters: VersionCheckParameters(version: APPINFO.bundleVersionShort())).asObservable(), Observable.just(type))
return Observable.zip(RQ.updateVersion(parameters: UpdateVersionParameters(appVersion: APPINFO.bundleVersionShort(), supplierId: UserData.default.supplierId)).asObservable(), Observable.just(type))
}
.observe(on: MainScheduler.instance)
.do(onNext: { (_,_) in
@@ -70,18 +70,23 @@ open class AppUpdateTool : NSObject {
.observe(on: MainScheduler.instance)
.subscribe(onNext: {[weak self] (response,type) in
if response?.success == true {
if self?.canUpdate(localVersion: APPINFO.bundleVersionShort(), onlineVersion: response?.data?.appVersion ?? "0") == true {
if response?.data == nil {
return
}
if self?.canUpdate(localVersion: APPINFO.bundleVersionShort(), onlineVersion: response?.data?.newAppVersion ?? "0") == true {
if type == .auto {
if response?.data?.update.code == .YES || self?.shouldPresentEntry() == true {
if response?.data?.update == UpdateVersionDataModel.ForceUpdate.force.rawValue || self?.shouldPresentEntry() == true {
if let appUpdateView = self?.appUpdateView {
appUpdateView.isForce(isForce: response?.data?.update.code == .YES ? true : false)
appUpdateView.isForce(isForce: (response?.data?.update == UpdateVersionDataModel.ForceUpdate.force.rawValue) ? true : false)
appUpdateView.contentLabel.text = response?.data?.description
ENTRY.showAppUpdateEntry(view: appUpdateView,name: appUpdateEntry)
}
}
}else if type == .manual {
if let appUpdateView = self?.appUpdateView {
appUpdateView.isForce(isForce: response?.data?.update.code == .YES ? true : false)
appUpdateView.isForce(isForce: (response?.data?.update == UpdateVersionDataModel.ForceUpdate.force.rawValue) ? true : false)
appUpdateView.contentLabel.text = response?.data?.description
ENTRY.showAppUpdateEntry(view: appUpdateView,name: appUpdateEntry)
}

View File

@@ -21,6 +21,8 @@ open class WebViewTool : NSObject {
public var h5Models : DispatchAppH5UrlDataModel?
public var bannerInMineDataSources : [ConfigByCodeDataModel.ConfigByCodeBannerModel]?
public var supplierAppIsUserNewReportRelay = ReplayRelay<Any?>.create(bufferSize: 1)
public var supplierAppIsUserNewReport : Bool = false
enum WebViewNameEnum : String {
case todoList = "待办事项"
@@ -45,6 +47,8 @@ open class WebViewTool : NSObject {
case reportIndex = "报备"
case vehicleAlarmDetail = "报警详情"
case vehicleAlarmList = "车辆报警"
case kpiCaseNew = "服务商案件和车辆情况统计"
case managerPeople = "管理人员"
}
public override init() {
@@ -158,6 +162,12 @@ open class WebViewTool : NSObject {
case .vehicleAlarmDetail:
vc = WebViewController(showNavBar:true, title: WebViewNameEnum.vehicleAlarmDetail.rawValue, url: "\((h5Models?.vehicleAlarmDetail)!)?token=\((USER.token)!)"+(appending ?? ""))
break
case .kpiCaseNew:
vc = WebViewController(showNavBar:true, title: nil, url: "\((h5Models?.kpiCaseNew)!)?token=\((USER.token)!)"+(appending ?? ""))
break
case .managerPeople:
vc = WebViewController(showNavBar:false, title: nil, url: "\((h5Models?.managerPeople)!)?token=\((USER.token)!)"+(appending ?? ""))
break
}
if let vc {
@@ -167,6 +177,14 @@ open class WebViewTool : NSObject {
}
}
func openReportIndex(queryType: Int,userOrderId: Int,orderCode: String,type: Int,userOrderCode: String,supplierId: Int) {
if supplierAppIsUserNewReport == true {
open(name: .reportIndex,appending: "&userOrderId=\(userOrderId)&type=\(type)&userOrderCode=\(userOrderCode)&supplierId=\(supplierId)")
}else{
open(name: .reporting,appending: "&queryType=\(queryType)&userOrderId=\(userOrderId)&orderCode=\(orderCode)")
}
}
func open(name:WebViewNameEnum,appending:String?,completionHandler:(() -> Void)? = nil) {
requestModelRelay.accept(name)
appendingRelay.accept(appending)

View File

@@ -14,6 +14,60 @@ public let ENTRY = Entry.default
open class Entry {
public static let `default` = Entry()
func showIdentityAlert(view: UIView, name: String? = nil) {
var attributes = EKAttributes.centerFloat
attributes.name = name
attributes.precedence = .override(priority: .min, dropEnqueuedEntries: false)
attributes.displayMode = .inferred
attributes.displayDuration = .infinity
//
attributes.screenBackground = .color(
color: EKColor(UIColor.black.withAlphaComponent(0.45))
)
// entry
attributes.entryBackground = .color(color: .clear)
attributes.screenInteraction = .absorbTouches //
attributes.entryInteraction = .absorbTouches
attributes.scroll = .disabled
attributes.entranceAnimation = .init(
translate: .init(
duration: 0.25,
spring: .init(damping: 1, initialVelocity: 0)
)
)
attributes.exitAnimation = .init(
translate: .init(duration: 0.25)
)
attributes.popBehavior = .animated(
animation: .init(
translate: .init(duration: 0.25)
)
)
attributes.shadow = .active(
with: .init(
color: .black,
opacity: 0.3,
radius: 6
)
)
// entry
attributes.positionConstraints.size = .init(
width: .offset(value: 40), // 20
height: .intrinsic // view
)
attributes.positionConstraints.verticalOffset = 0
attributes.positionConstraints.safeArea = .overridden
attributes.positionConstraints.rotation.isEnabled = false
attributes.statusBar = .light
SwiftEntryKit.display(entry: view, using: attributes)
}
func showOnlineVehiclesEntry(view:UIView,name:String? = nil) {
var attributes = EKAttributes()
attributes = .centerFloat

View File

@@ -241,10 +241,9 @@ extension HistoryItemController : UITableViewDelegate, UITableViewDataSource {
cell?.reportButton.rx.tap
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
// if let supplierId = USER.supplierId {
// WEBTOOL.open(name: .reportIndex,appending: "&userOrderId=\(model.userOrderId)&type=1&userOrderCode=\(model.taskCode)&supplierId=\(supplierId)")
// }
WEBTOOL.open(name: .reporting, appending: "&queryType=\(OrderTypeEnum.UNCLOSED_ORDER.rawValue)&userOrderId=\(model.userOrderId)&orderCode=\(model.orderCode)")
if let supplierId = USER.supplierId {
WEBTOOL.openReportIndex(queryType: OrderTypeEnum.UNCLOSED_ORDER.rawValue, userOrderId: model.userOrderId, orderCode: model.orderCode, type: 1, userOrderCode: model.taskCode, supplierId: supplierId)
}
})
.disposed(by: cell!.disposeBag)

View File

@@ -48,9 +48,15 @@ open class ApiList {
public let generalInfo = "/supplierAppV2/dispatchApp/user/generalInfo"
public let getNeedConfirmPersonInfo = "/supplierAppV2/dispatchApp/wechat/getNeedConfirmPersonInfo"
public let giveUp = "/supplierAppV2/dispatchApp/wechat/giveUp"
public let judgeIfNeedConfirm = "/supplierAppV2/dispatchApp/wechat/judgeIfNeedConfirm"
public let dispatchAppH5Urls = "/supplierAppV2/open/dispatchAppH5Urls"
public let versionCheck = "/supplierAppV2/dispatchApp/user/versionCheck"
public let updateVersion = "/supplierAppV2/dispatchApp/user/updateVersion"
public let messageReminderList = "/supplierAppV2/dispatchApp/toDoMessage/messageReminderList"

View File

@@ -205,9 +205,10 @@ public struct SupplementOrderPhotoParameters : Encodable {
var file : Data
}
public struct VersionCheckParameters : Encodable {
var version : String
var platForm : Int = 2
public struct UpdateVersionParameters : Encodable {
var appVersion : String
var supplierId : Int?
var sysType : String = "ios"
}
public struct MessageReminderListParameters : Encodable {
@@ -278,3 +279,15 @@ public struct VehicleMonitorInfoParameters : Encodable {
var lat : String?
var code : String?
}
public struct NeedConfirmPersonInfoParameters : Encodable {
var supplierId : Int?
}
public struct JudgeIfNeedConfirmParameters : Encodable {
var supplierId : Int?
}
public struct GiveUpParameters : Encodable {
var supplierId : Int?
}

View File

@@ -99,12 +99,24 @@ open class RequestList {
return DDAF.post(urlString: HOST+API.generalInfo,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<GeneralInfoDataModel>.self)
}
func getNeedConfirmPersonInfo<P:Encodable>(prameters:P) -> Single<ResponseModel<[NeedConfirmPersonInfoDataModel]>?> {
return DDAF.get(urlString: HOST+API.getNeedConfirmPersonInfo,parameters: prameters,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<[NeedConfirmPersonInfoDataModel]>.self)
}
func judgeIfNeedConfirm<P:Encodable>(prameters:P) -> Single<ResponseModel<JudgeIfNeedConfirmDataModel>?> {
return DDAF.get(urlString: HOST+API.judgeIfNeedConfirm,parameters: prameters,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<JudgeIfNeedConfirmDataModel>.self)
}
func giveUp<P:Encodable>(prameters:P) -> Single<ResponseModel<String>?> {
return DDAF.get(urlString: HOST+API.giveUp,parameters: prameters,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<String>.self)
}
func dispatchAppH5Urls() -> Single<ResponseModel<DispatchAppH5UrlDataModel>?> {
return DDAF.post(urlString: HOST+API.dispatchAppH5Urls,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<DispatchAppH5UrlDataModel>.self)
}
func versionCheck<P:Encodable>(parameters:P) -> Single<ResponseModel<VersionCheckDataModel>?> {
return DDAF.post(urlString: HOST+API.versionCheck,parameters: parameters,encoding: JSONParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<VersionCheckDataModel>.self)
func updateVersion<P:Encodable>(parameters:P) -> Single<ResponseModel<UpdateVersionDataModel>?> {
return DDAF.post(urlString: HOST+API.updateVersion,parameters: parameters,encoding: JSONParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<UpdateVersionDataModel>.self)
}
func messageReminderList<P:Encodable>(parameters:P) -> Single<ResponseModel<[MessageReminderListDataModel]>?> {

View File

@@ -262,6 +262,15 @@ public class GeneralInfoDataModel : Decodable {
var addressLon : Double?
}
public class NeedConfirmPersonInfoDataModel : Decodable {
}
public class JudgeIfNeedConfirmDataModel : Decodable {
var needConfirm : Bool?
var count : Int?
var isLast : Bool?
}
public class DispatchAppH5UrlDataModel : Decodable {
var todoList : String?
var workOrderReconciliation : String
@@ -282,28 +291,17 @@ public class DispatchAppH5UrlDataModel : Decodable {
var reportIndex : String
var vehicleAlarmList : String
var vehicleAlarmDetail : String
var kpiCaseNew : String
var managerPeople : String
}
public class VersionCheckDataModel : Decodable {
var id : Int
var appVersion : String
var update : UpdateModel
var appType : TypeModel
class UpdateModel : Decodable {
var code : UpdateEnum
var label : String
}
class TypeModel : Decodable {
var code : Int
var label : String
}
enum UpdateEnum : Int,Decodable {
case NO = 0
case YES = 1
}
var updateTime : String?
var createTime : String?
public class UpdateVersionDataModel : Decodable {
var newAppVersion : String?
var update : Int?
var description : String?
public enum ForceUpdate : Int {
case force = 1
}
}
public class MessageReminderListDataModel : Decodable {
@@ -372,6 +370,7 @@ public class AppPushRecordListDataModel : Decodable {
public class ConfigByCodeDataModel : Decodable {
var bannerConfig : [ConfigByCodeBannerModel]?
var supplierAppIsUserNewReport : String?
public class ConfigByCodeBannerModel : Decodable {
var linkUrl : String?
var bannerIcon : String?

View File

@@ -49,14 +49,14 @@ extension MineController {
return RQ.thisWeekNumber()
})
.flatMapLatest { numberModel in
return Single.zip(RQ.generalInfo(),Single.just(numberModel))
return Single.zip(RQ.generalInfo(),RQ.getNeedConfirmPersonInfo(prameters: NeedConfirmPersonInfoParameters(supplierId: UserData.default.supplierId)),Single.just(numberModel))
}
.observe(on: MainScheduler.instance)
.subscribe(onNext: {[weak self] response,numberModel in
if response?.success == true {
.subscribe(onNext: {[weak self] response,needConfirmPersonInfoModel,numberModel in
self?.mineView.scrollView.mj_header?.endRefreshing()
if response?.success == true {
self?.mineView.carInfoView.descLabel.text = String(response?.data?.vehicleCount ?? 0)+""
self?.mineView.driverInfoView.descLabel.text = String(response?.data?.driverCount ?? 0)+""
self?.mineView.driverInfoView.descLabel.text = String(response?.data?.driverCount ?? 0)+""
if let icon = response?.data?.icon {
self?.mineView.avatar.sd_setImage(with: URL(string: icon),placeholderImage: UIImage(named: "placeholder_gender_man"))
}
@@ -68,6 +68,12 @@ extension MineController {
self?.view.dd_makeToast(response?.msg)
}
if needConfirmPersonInfoModel?.success == true {
self?.mineView.manageView.descLabel.text = String(needConfirmPersonInfoModel?.data?.count ?? 0)+""
}else{
self?.view.dd_makeToast(response?.msg)
}
if numberModel?.success == true {
if let number = numberModel?.data, number > 0 {
self?.mineView.ershouche.contentView.isHidden = false
@@ -81,6 +87,15 @@ extension MineController {
})
.disposed(by: disposeBag)
mineView.manageGes.rx.event
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
if let supplierId = UserData.default.supplierId {
WEBTOOL.open(name: .managerPeople, appending: "&supplierId=\(supplierId)")
}
})
.disposed(by: disposeBag)
mineView.carInfoGes.rx.event
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
@@ -97,6 +112,13 @@ extension MineController {
})
.disposed(by: disposeBag)
mineView.fuwushanganjianGes.rx.event
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
WEBTOOL.open(name: .kpiCaseNew, appending: nil)
})
.disposed(by: disposeBag)
mineView.shujutongjiGes.rx.event
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
@@ -222,12 +244,15 @@ open class MineController : ZDViewController {
make.bottom.equalTo(-view.safeAreaInsets.bottom - CGRectGetHeight(tabBarController?.tabBar.frame ?? .zero))
}
mineView.manageView.titleLabel.text = "管理人员"
mineView.manageView.imageView.image = UIImage(named: "mine_info_manage")
mineView.carInfoView.titleLabel.text = "车辆管理"
mineView.carInfoView.imageView.image = UIImage(named: "mine_info_car")
mineView.driverInfoView.titleLabel.text = "司机管理"
mineView.driverInfoView.imageView.image = UIImage(named: "mine_info_driver")
mineView.shujutongji.titleLabel.text = "KPI数据统计"
mineView.fuwushanganjian.titleLabel.text = "服务商案件和车辆情况统计"
mineView.shujutongji.titleLabel.text = "服务商KPI"
mineView.gongdanduizhang.titleLabel.text = "工单对账"
mineView.gongdanpici.titleLabel.text = "工单批次"
mineView.kaipiaoxinxi.titleLabel.text = "开票信息"
@@ -326,17 +351,22 @@ open class MineView : DDView {
private let topBackgroundImageView : DDImageView
public let avatar : DDImageView
public let companyLabel : DDLabel
public let manageGes : UITapGestureRecognizer
public let manageView : MineInfoView
public let carInfoGes : UITapGestureRecognizer
public let carInfoView : MineInfoView
public let driverInfoGes : UITapGestureRecognizer
public let driverInfoView : MineInfoView
public let infoRadiusView : DDView
private let infoStackView: UIStackView
public let infoRadiusSeparate : DDImageView
public let statisticsRadiusView : DDView
public let orderRadiusView : DDView
public let materialRadiusView : DDView
public let usedCarRadiusView : DDView
public let settingsRadiusView : DDView
public let fuwushanganjianGes : UITapGestureRecognizer
public let fuwushanganjian : MineCell
public let shujutongjiGes : UITapGestureRecognizer
public let shujutongji : MineCell
public let gongdanduizhangGes : UITapGestureRecognizer
@@ -369,17 +399,22 @@ open class MineView : DDView {
topBackgroundImageView = DDImageView()
avatar = DDImageView(image: UIImage(named: "placeholder_gender_man"))
companyLabel = DDLabel.dd_init(withText: "", font: .mediumFont(auto(12)), textColor: .hex("FFFFFF").alpha(0.5))
manageView = MineInfoView()
manageGes = UITapGestureRecognizer()
carInfoView = MineInfoView()
carInfoGes = UITapGestureRecognizer()
driverInfoView = MineInfoView()
driverInfoGes = UITapGestureRecognizer()
infoRadiusView = DDView()
infoStackView = UIStackView()
infoRadiusSeparate = DDImageView(image: UIImage(named: "mine_info_separate"))
statisticsRadiusView = DDView()
orderRadiusView = DDView()
materialRadiusView = DDView()
usedCarRadiusView = DDView()
settingsRadiusView = DDView()
fuwushanganjianGes = UITapGestureRecognizer()
fuwushanganjian = MineCell()
shujutongjiGes = UITapGestureRecognizer()
shujutongji = MineCell()
gongdanduizhangGes = UITapGestureRecognizer()
@@ -421,10 +456,20 @@ open class MineView : DDView {
infoRadiusView.backgroundColor = .hex("FFFFFF")
infoRadiusView.layer.cornerRadius = auto(12)
scrollContentView.addSubview(infoRadiusView)
infoStackView.axis = .horizontal
infoStackView.alignment = .fill
infoStackView.distribution = .fillEqually
infoRadiusView.addSubview(infoStackView)
manageView.addGestureRecognizer(manageGes)
carInfoView.addGestureRecognizer(carInfoGes)
infoRadiusView.addSubview(carInfoView)
driverInfoView.addGestureRecognizer(driverInfoGes)
infoRadiusView.addSubview(driverInfoView)
infoStackView.addArrangedSubview(manageView)
infoStackView.addArrangedSubview(carInfoView)
infoStackView.addArrangedSubview(driverInfoView)
scrollContentView.addSubview(infoRadiusSeparate)
statisticsRadiusView.backgroundColor = .hex("FFFFFF")
statisticsRadiusView.layer.cornerRadius = auto(6)
@@ -441,6 +486,8 @@ open class MineView : DDView {
settingsRadiusView.backgroundColor = .hex("FFFFFF")
settingsRadiusView.layer.cornerRadius = auto(6)
scrollContentView.addSubview(settingsRadiusView)
fuwushanganjian.addGestureRecognizer(fuwushanganjianGes)
statisticsRadiusView.addSubview(fuwushanganjian)
shujutongji.addGestureRecognizer(shujutongjiGes)
shujutongji.line.isHidden = true
statisticsRadiusView.addSubview(shujutongji)
@@ -518,14 +565,8 @@ open class MineView : DDView {
make.width.equalTo(auto(350))
}
carInfoView.snp.makeConstraints { make in
make.left.top.bottom.equalToSuperview()
make.width.equalToSuperview().multipliedBy(0.5)
}
driverInfoView.snp.makeConstraints { make in
make.right.top.bottom.equalToSuperview()
make.width.equalToSuperview().multipliedBy(0.5)
infoStackView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
infoRadiusSeparate.snp.makeConstraints { make in
@@ -537,7 +578,6 @@ open class MineView : DDView {
make.top.equalTo(infoRadiusView.snp.bottom).offset(auto(10))
make.width.equalTo(infoRadiusView)
make.centerX.equalToSuperview()
make.height.equalTo(auto(55))
}
orderRadiusView.snp.makeConstraints { make in
@@ -567,11 +607,18 @@ open class MineView : DDView {
make.height.equalTo(auto(110))
}
shujutongji.snp.makeConstraints { make in
fuwushanganjian.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(auto(55))
}
shujutongji.snp.makeConstraints { make in
make.top.equalTo(fuwushanganjian.snp.bottom)
make.left.right.equalToSuperview()
make.height.equalTo(auto(55))
make.bottom.equalToSuperview()
}
gongdanduizhang.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(auto(55))
@@ -729,23 +776,30 @@ public class MineInfoView : DDView {
addSubview(descLabel)
addSubview(arrow)
imageView.contentMode = .scaleAspectFit
imageView.snp.makeConstraints { make in
make.left.top.equalTo(auto(20))
make.right.equalTo(titleLabel.snp.left).offset(-auto(5))
make.width.height.equalTo(auto(24))
make.centerY.equalTo(titleLabel)
}
titleLabel.snp.makeConstraints { make in
make.left.equalTo(imageView.snp.right).offset(auto(10))
make.top.equalTo(imageView.snp.top).offset(auto(5))
make.top.equalToSuperview().offset(auto(10))
make.bottom.equalTo(snp.centerY).offset(-auto(2.5))
make.centerX.equalToSuperview().offset(auto(8))
}
descLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(auto(5))
make.top.equalTo(snp.centerY).offset(auto(2.5))
make.bottom.equalToSuperview().offset(-auto(10))
}
arrow.contentMode = .scaleAspectFit
arrow.snp.makeConstraints { make in
make.right.equalTo(-auto(20))
make.left.equalTo(titleLabel.snp.right).offset(auto(5))
make.centerY.equalTo(titleLabel)
make.width.height.equalTo(auto(8))
}
}

View File

@@ -0,0 +1,186 @@
//
// IdentityAlertView.swift
// OrderScheduling
//
// Created by on 2025/12/19.
//
import UIKit
import SnapKit
final class IdentityAlertView: UIView {
// MARK: - Public Callbacks
var onConfirm: (() -> Void)?
var onLater: (() -> Void)?
// MARK: - UI
private let containerView = UIView()
private let iconContainer = UIView()
private let iconImageView = UIImageView()
private let gradientLayer = CAGradientLayer()
private let titleLabel = UILabel()
private let messageLabel = UILabel()
private let confirmButton = UIButton(type: .system)
private let laterButton = UIButton(type: .system)
// MARK: - Init
/// times: totalTimes: 3
init(times: Int = 1, totalTimes: Int = 3, isLast: Bool) {
super.init(frame: .zero)
setupUI(times: times, totalTimes: totalTimes, isLast:isLast)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = containerView.bounds
}
}
// MARK: - UI
private extension IdentityAlertView {
func setupUI(times: Int, totalTimes: Int, isLast: Bool) {
backgroundColor = .clear
//
addSubview(containerView)
addSubview(iconContainer)
containerView.layer.cornerRadius = 18
containerView.layer.masksToBounds = true
// 稿
gradientLayer.colors = [
UIColor(red: 0xFF/255.0, green: 0xE4/255.0, blue: 0xD7/255.0, alpha: 1).cgColor,
UIColor.white.cgColor
]
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.25)
containerView.layer.insertSublayer(gradientLayer, at: 0)
// entry 52
iconContainer.layer.cornerRadius = 26
iconContainer.layer.masksToBounds = true
iconContainer.backgroundColor = .clear
iconContainer.snp.makeConstraints { make in
make.top.equalToSuperview() // entry
make.centerX.equalToSuperview()
make.width.height.equalTo(52)
}
//
containerView.snp.makeConstraints { make in
make.top.equalTo(iconContainer.snp.centerY)
make.left.right.bottom.equalToSuperview()
}
// 52x52
iconImageView.image = UIImage(named: "IdentityAlertNotice")
iconImageView.contentMode = .scaleAspectFit
iconContainer.addSubview(iconImageView)
iconImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
//
titleLabel.text = "重要提示"
titleLabel.font = .boldSystemFont(ofSize: 18)
titleLabel.textColor = UIColor(red: 51/255, green: 51/255, blue: 51/255, alpha: 1)
titleLabel.textAlignment = .center
containerView.addSubview(titleLabel)
titleLabel.snp.makeConstraints { make in
make.top.equalTo(iconContainer.snp.bottom).offset(16)
make.left.right.equalToSuperview().inset(20)
}
//
let reminderText = isLast ? "本次为最后一次提醒" : "此为第\(times)次提醒"
let message = """
中道救援将通过您确认的身份及联系方式,向您发送通知。请务必仔细核对您的身份及联系方式等关键信息,以免因无法接收通知而受到损失。\n
\(reminderText),请及时确认。若\(totalTimes)次提醒仍未确认,您将无法承接案件。
"""
let attr = NSMutableAttributedString(string: message)
let fullRange = NSRange(location: 0, length: attr.length)
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 4
paragraph.alignment = .center
attr.addAttributes([
.font: UIFont.systemFont(ofSize: 14),
.foregroundColor: UIColor(red: 0x66/255, green: 0x66/255, blue: 0x66/255, alpha: 1),
.paragraphStyle: paragraph
], range: fullRange)
//
if let highlightRange = (message as NSString).range(of: "请务必仔细核对您的身份及联系方式等关键信息").optionalNonEmpty {
attr.addAttribute(.foregroundColor,
value: UIColor(red: 0xF5/255, green: 0x52/255, blue: 0x3C/255, alpha: 1),
range: highlightRange)
}
messageLabel.attributedText = attr
messageLabel.numberOfLines = 0
containerView.addSubview(messageLabel)
messageLabel.snp.makeConstraints { make in
make.top.equalTo(titleLabel.snp.bottom).offset(12)
make.left.right.equalToSuperview().inset(24)
}
//
confirmButton.setTitle(isLast ? "放弃" : "立即确认", for: .normal)
confirmButton.setTitleColor(.white, for: .normal)
confirmButton.titleLabel?.font = .boldSystemFont(ofSize: 16)
confirmButton.backgroundColor = UIColor(red: 0xFF/255, green: 0x6B/255, blue: 0x50/255, alpha: 1)
confirmButton.layer.cornerRadius = 20
confirmButton.layer.masksToBounds = true
confirmButton.addTarget(self, action: #selector(handleConfirm), for: .touchUpInside)
containerView.addSubview(confirmButton)
confirmButton.snp.makeConstraints { make in
make.top.equalTo(messageLabel.snp.bottom).offset(20)
make.left.right.equalToSuperview().inset(40)
make.height.equalTo(40)
}
//
laterButton.setTitle("稍后提醒", for: .normal)
laterButton.setTitleColor(UIColor(red: 0x99/255, green: 0x99/255, blue: 0x99/255, alpha: 1), for: .normal)
laterButton.titleLabel?.font = .systemFont(ofSize: 14)
laterButton.addTarget(self, action: #selector(handleLater), for: .touchUpInside)
containerView.addSubview(laterButton)
laterButton.snp.makeConstraints { make in
make.top.equalTo(confirmButton.snp.bottom).offset(12)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-20)
}
}
}
// MARK: - Actions
private extension IdentityAlertView {
@objc func handleConfirm() {
onConfirm?()
}
@objc func handleLater() {
onLater?()
}
}
private extension NSRange {
var optionalNonEmpty: NSRange? {
return location != NSNotFound && length > 0 ? self : nil
}
}

View File

@@ -136,6 +136,20 @@ extension RescueController {
})
.disposed(by: disposeBag)
WEBTOOL.supplierAppIsUserNewReportRelay
.flatMapLatest { _ in
return RQ.getConfigByCode(parameters: ConfigByCodeParameters(code: "AppIsUseNewReport"))
}
.observe(on: MainScheduler.instance)
.subscribe(onNext: {[weak self] response in
if response?.success == true {
WEBTOOL.supplierAppIsUserNewReport = (response?.data?.supplierAppIsUserNewReport == "true")
}else{
self?.view.dd_makeToast(response?.msg)
}
})
.disposed(by: disposeBag)
onlineReminderRelay
.flatMapLatest { _ in
return RQ.onlineReminder(parameters: OnlineReminderParameters(supplierId: UserData.default.supplierId))
@@ -170,6 +184,43 @@ extension RescueController {
})
.disposed(by: disposeBag)
judgeIfNeedConfirmEntryRelay
.flatMapLatest { _ in
return RQ.judgeIfNeedConfirm(prameters: JudgeIfNeedConfirmParameters(supplierId: UserData.default.supplierId))
}
.observe(on: MainScheduler.instance)
.subscribe(onNext: {[weak self] response in
guard let self = self else { return }
if response?.success == true {
if response?.data?.needConfirm == true {
let isLast = (response?.data?.isLast == true)
let entryName = "IdentityAlert"
let entryView = IdentityAlertView(times: response?.data?.count ?? 0,totalTimes: 3, isLast: isLast)
entryView.onLater = {
Entry.default.dismiss(name: entryName)
}
entryView.onConfirm = {
Entry.default.dismiss(name: entryName,completion: {
if isLast {
RQ.giveUp(prameters: GiveUpParameters(supplierId: UserData.default.supplierId))
.subscribe(onSuccess: { _ in
})
.disposed(by: self.disposeBag)
}else{
if let supplierId = UserData.default.supplierId {
WEBTOOL.open(name: .managerPeople, appending: "&supplierId=\(supplierId)")
}
}
})
}
Entry.default.showIdentityAlert(view: entryView, name: entryName)
}
}else{
self.view.dd_makeToast(response?.msg)
}
})
.disposed(by: disposeBag)
// tabBar
preRefreshRelay
.observe(on: MainScheduler.instance)
@@ -183,9 +234,11 @@ extension RescueController {
func excuseRelay() {
NewTraining.default.newTrainingRelay.accept(nil)
WEBTOOL.supplierAppIsUserNewReportRelay.accept(nil)
appBannerRelay.accept(nil)
appPushRecordRelay.accept(nil)
onlineReminderRelay.accept(nil)
judgeIfNeedConfirmEntryRelay.accept(nil)
}
}
@@ -937,10 +990,9 @@ extension RescuePendingDispatchController : UITableViewDelegate,UITableViewDataS
cell?.reportButton.rx.tap
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
// if let supplierId = USER.supplierId {
// WEBTOOL.open(name: .reportIndex,appending: "&userOrderId=\(model.userOrderId)&type=1&userOrderCode=\(model.taskCode)&supplierId=\(supplierId)")
// }
WEBTOOL.open(name: .reporting,appending: "&queryType=\(OrderTypeEnum.TO_DISPATCH_VEHICLE.rawValue)&userOrderId=\(model.userOrderId)&orderCode=\(model.orderCode)")
if let supplierId = USER.supplierId {
WEBTOOL.openReportIndex(queryType: OrderTypeEnum.TO_DISPATCH_VEHICLE.rawValue, userOrderId: model.userOrderId, orderCode: model.orderCode, type: 1, userOrderCode: model.taskCode, supplierId: supplierId)
}
})
.disposed(by: cell!.disposeBag)
cell?.contactButton.rx.tap
@@ -1099,10 +1151,9 @@ extension RescueIsIngController : UITableViewDelegate,UITableViewDataSource {
cell?.reportButton.rx.tap
.observe(on: MainScheduler.instance)
.subscribe(onNext: { _ in
// if let supplierId = USER.supplierId {
// WEBTOOL.open(name: .reportIndex,appending: "&userOrderId=\(model.userOrderId)&type=1&userOrderCode=\(model.taskCode)&supplierId=\(supplierId)")
// }
WEBTOOL.open(name: .reporting,appending: "&queryType=\(OrderTypeEnum.TO_DISPATCH_VEHICLE.rawValue)&userOrderId=\(model.userOrderId)&orderCode=\(model.orderCode)")
if let supplierId = USER.supplierId {
WEBTOOL.openReportIndex(queryType: OrderTypeEnum.TO_DISPATCH_VEHICLE.rawValue, userOrderId: model.userOrderId, orderCode: model.orderCode, type: 1, userOrderCode: model.taskCode, supplierId: supplierId)
}
})
.disposed(by: cell!.disposeBag)
@@ -1222,6 +1273,8 @@ class RescueController : ZDViewController {
private var onlineReminderRelay = ReplayRelay<Any?>.create(bufferSize: 1)
private var judgeIfNeedConfirmEntryRelay = ReplayRelay<Any?>.create(bufferSize: 1)
override func viewDidLoad() {
super.viewDidLoad()
dd_navigationBarBackgroundColor = .hex("354683")