申诉
This commit is contained in:
@@ -74,6 +74,7 @@
|
||||
79CECC222A8A2A2900B95D8B /* VehicleMonitoringController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CECC212A8A2A2900B95D8B /* VehicleMonitoringController.swift */; };
|
||||
79CECC242A8B16D400B95D8B /* VehicleMonitoringListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CECC232A8B16D400B95D8B /* VehicleMonitoringListController.swift */; };
|
||||
79CECC262A8C749B00B95D8B /* VehicleMonitorVideoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CECC252A8C749B00B95D8B /* VehicleMonitorVideoController.swift */; };
|
||||
79D964E02E77FE2100309946 /* AppealInputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D964DF2E77FE2100309946 /* AppealInputViewController.swift */; };
|
||||
79DD0DAA2A9481BC00768FE7 /* NotificationAuthTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DD0DA92A9481BC00768FE7 /* NotificationAuthTool.swift */; };
|
||||
79DD0DB12A94B3DB00768FE7 /* EmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DD0DB02A94B3DB00768FE7 /* EmptyView.swift */; };
|
||||
79DD0DB42A95F00B00768FE7 /* Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DD0DB32A95F00B00768FE7 /* Extension.swift */; };
|
||||
@@ -225,6 +226,7 @@
|
||||
79CECCB52A8E04EF00B95D8B /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; };
|
||||
79CECCB62A8E04FA00B95D8B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
79CECCB72A8E050200B95D8B /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
79D964DF2E77FE2100309946 /* AppealInputViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppealInputViewController.swift; sourceTree = "<group>"; };
|
||||
79DD0DA12A94501500768FE7 /* OrderScheduling-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OrderScheduling-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
79DD0DA52A945D9E00768FE7 /* OrderSchedulingRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OrderSchedulingRelease.entitlements; sourceTree = "<group>"; };
|
||||
79DD0DA62A946B2500768FE7 /* OrderSchedulingDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OrderSchedulingDebug.entitlements; sourceTree = "<group>"; };
|
||||
@@ -735,6 +737,7 @@
|
||||
children = (
|
||||
79CECC182A89EE6A00B95D8B /* ReviewFailedController.swift */,
|
||||
79CECC1A2A89F83800B95D8B /* AdditionalPhotoController.swift */,
|
||||
79D964DF2E77FE2100309946 /* AppealInputViewController.swift */,
|
||||
);
|
||||
path = ViewController;
|
||||
sourceTree = "<group>";
|
||||
@@ -1195,6 +1198,7 @@
|
||||
791887AE2A80F943007EA0C1 /* UserData.swift in Sources */,
|
||||
79FB75EE2A9898EB00DB00A4 /* AcceptOrderView.swift in Sources */,
|
||||
791887BA2A82495D007EA0C1 /* EnvironmentStrings.swift in Sources */,
|
||||
79D964E02E77FE2100309946 /* AppealInputViewController.swift in Sources */,
|
||||
791887A62A80D50C007EA0C1 /* ParametersList.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -77,4 +77,8 @@ open class ApiList {
|
||||
public let alarmList = "/supplierAppV2/dispatchApp/alarm/alarmList"
|
||||
|
||||
public let getAlarmByCode = "/supplierAppV2/dispatchApp/alarm/getAlarmByCode"
|
||||
|
||||
public let getAppeal = "/supplierAppV2/dispatchApp/order/getAppeal"
|
||||
|
||||
public let saveAppeal = "/driverApp/task/saveAppeal"
|
||||
}
|
||||
|
||||
@@ -257,3 +257,13 @@ public struct AlarmListParameters : Encodable {
|
||||
public struct GetAlarmByCodeParameters : Encodable {
|
||||
var code : String?
|
||||
}
|
||||
|
||||
public struct GetAppealParameters : Encodable {
|
||||
var orderCode : String?
|
||||
}
|
||||
|
||||
public struct SaveAppealParameters : Encodable {
|
||||
var orderCode : String?
|
||||
var vehicleId : Int?
|
||||
var msg : String?
|
||||
}
|
||||
|
||||
@@ -160,4 +160,12 @@ open class RequestList {
|
||||
func getAlarmByCode<P:Encodable>(parameters:P) -> Single<ResponseModel<GetAlarmByCodeDataModel>?> {
|
||||
return DDAF.post(urlString: HOST+API.getAlarmByCode,parameters: parameters,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<GetAlarmByCodeDataModel>.self)
|
||||
}
|
||||
|
||||
func getAppeal<P:Encodable>(parameters:P) -> Single<ResponseModel<GetAppealDataModel>?> {
|
||||
return DDAF.get(urlString: HOST+API.getAppeal,parameters: parameters,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<GetAppealDataModel>.self)
|
||||
}
|
||||
|
||||
func saveAppeal<P:Encodable>(parameters:P) -> Single<ResponseModel<SaveAppealModel>?> {
|
||||
return DDAF.get(urlString: HOST+API.saveAppeal,parameters: parameters,encoding: URLEncodedFormParameterEncoder.default,headers: [tokenHeader()],responseType: ResponseModel<SaveAppealModel>.self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ class OrderListDataModel: Decodable {
|
||||
var supplierSettleRatio : SupplierSettleRatioModel?
|
||||
/// 案件类型 0 传统案件 1 聚合派工
|
||||
var schedulingFinalRule : Int?
|
||||
var showAppealBtn : Bool?
|
||||
var taskVehicleId : Int?
|
||||
class SupplierSettleModel : Decodable {
|
||||
var code : Int
|
||||
var label : String
|
||||
@@ -397,3 +399,11 @@ public class GetVideoUrlDataModel : Decodable {
|
||||
var channelList : [String]?
|
||||
var realtimeList : [String]?
|
||||
}
|
||||
|
||||
public class GetAppealDataModel : Decodable {
|
||||
var appealReason : String?
|
||||
}
|
||||
|
||||
public class SaveAppealModel : Decodable {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// AppealInputViewController.swift
|
||||
// OrderScheduling
|
||||
//
|
||||
// Created by 中道 on 2025/9/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class AppealInputViewController: UIViewController {
|
||||
|
||||
let titleLabel = UILabel()
|
||||
let textField = UITextField()
|
||||
|
||||
init(prefill: String? = nil) {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
textField.text = prefill
|
||||
}
|
||||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .white
|
||||
view.layer.cornerRadius = 12
|
||||
view.clipsToBounds = true
|
||||
|
||||
// 标题
|
||||
titleLabel.text = "申诉理由"
|
||||
titleLabel.textAlignment = .center
|
||||
titleLabel.font = .systemFont(ofSize: 16, weight: .semibold)
|
||||
titleLabel.textColor = .black
|
||||
|
||||
// 输入框
|
||||
textField.placeholder = "请输入申诉原因…"
|
||||
textField.borderStyle = .none
|
||||
textField.backgroundColor = UIColor(white: 0.98, alpha: 1)
|
||||
textField.layer.cornerRadius = 10
|
||||
textField.layer.borderWidth = 1
|
||||
textField.layer.borderColor = UIColor.systemBlue.withAlphaComponent(0.35).cgColor
|
||||
textField.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
|
||||
textField.leftViewMode = .always
|
||||
textField.clearButtonMode = .whileEditing
|
||||
textField.returnKeyType = .done
|
||||
textField.delegate = self
|
||||
|
||||
let container = UIStackView(arrangedSubviews: [titleLabel, textField])
|
||||
container.axis = .vertical
|
||||
container.spacing = 14
|
||||
container.alignment = .fill
|
||||
container.distribution = .fill
|
||||
view.addSubview(container)
|
||||
container.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
container.topAnchor.constraint(equalTo: view.topAnchor, constant: 16),
|
||||
container.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
|
||||
container.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
|
||||
container.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -16),
|
||||
textField.heightAnchor.constraint(equalToConstant: 40)
|
||||
])
|
||||
}
|
||||
|
||||
// 控制弹窗内容的尺寸(宽度由库控制,这里给出理想高度)
|
||||
override var preferredContentSize: CGSize {
|
||||
get { CGSize(width: 280, height: 140) }
|
||||
set { super.preferredContentSize = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
extension AppealInputViewController: UITextFieldDelegate {
|
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
textField.resignFirstResponder()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import RxRelay
|
||||
import RxCocoa
|
||||
import MJRefresh
|
||||
import ESTabBarController_swift
|
||||
import PopupDialog
|
||||
|
||||
extension ReviewFailedController {
|
||||
func addActions() {
|
||||
@@ -196,11 +197,53 @@ extension ReviewFailedController : UITableViewDelegate,UITableViewDataSource {
|
||||
})
|
||||
.disposed(by: cell!.disposeBag)
|
||||
|
||||
cell!.appealButton.rx.tap
|
||||
.flatMapLatest({ _ in
|
||||
return RQ.getAppeal(parameters: GetAppealParameters(orderCode: model.orderCode))
|
||||
})
|
||||
.flatMapLatest({ [weak self] response -> Observable<String> in
|
||||
// 若已有申诉,提示并结束流
|
||||
guard response?.data == nil else {
|
||||
DispatchQueue.main.async {
|
||||
self?.view.dd_makeToast("该订单正在申诉中")
|
||||
}
|
||||
return .empty()
|
||||
}
|
||||
// 否则弹出输入框,异步拿到申诉理由
|
||||
return Observable<String>.create { ob in
|
||||
guard let self = self else { return Disposables.create() }
|
||||
DispatchQueue.main.async {
|
||||
self.presentAppealPopup(from: self) { reason in
|
||||
ob.onNext(reason)
|
||||
ob.onCompleted()
|
||||
}
|
||||
}
|
||||
return Disposables.create()
|
||||
}
|
||||
})
|
||||
.flatMapLatest({ reason in
|
||||
return RQ.saveAppeal(parameters: SaveAppealParameters(orderCode: model.orderCode, vehicleId: model.taskVehicleId, msg: reason))
|
||||
})
|
||||
.observe(on: ConcurrentMainScheduler.instance)
|
||||
.subscribe(onNext: {[weak self] response in
|
||||
if response?.success == true {
|
||||
}else{
|
||||
self?.view.dd_makeToast(response?.msg)
|
||||
}
|
||||
})
|
||||
.disposed(by: cell!.disposeBag)
|
||||
|
||||
if USERP.canSupplierAuditUploadPhotoBtn == true {
|
||||
cell?.additionalButton.isHidden = false
|
||||
}else{
|
||||
cell?.additionalButton.isHidden = true
|
||||
}
|
||||
|
||||
if model.showAppealBtn == true {
|
||||
cell?.appealButton.isHidden = false
|
||||
}else{
|
||||
cell?.appealButton.isHidden = true
|
||||
}
|
||||
return cell!
|
||||
}
|
||||
|
||||
@@ -314,6 +357,66 @@ open class ReviewFailedController : ZDViewController {
|
||||
super.reloadData()
|
||||
preRefreshRelay.accept(nil)
|
||||
}
|
||||
|
||||
/// 弹出“申诉理由”输入弹窗
|
||||
/// - Parameters:
|
||||
/// - from: 当前控制器
|
||||
/// - prefill: 预填内容
|
||||
/// - onConfirm: 点击【确定】回调(返回填写的文本)
|
||||
func presentAppealPopup(from: UIViewController,
|
||||
prefill: String? = nil,
|
||||
onConfirm: @escaping (String) -> Void) {
|
||||
|
||||
// 内容 VC
|
||||
let inputVC = AppealInputViewController(prefill: prefill)
|
||||
|
||||
// 弹窗
|
||||
let popup = PopupDialog(
|
||||
viewController: inputVC,
|
||||
buttonAlignment: .horizontal, // 底部按钮水平排列
|
||||
transitionStyle: .bounceDown, // 动画风格
|
||||
tapGestureDismissal: false, // 点击外部不关闭
|
||||
panGestureDismissal: false // 禁止下拉关闭(避免误触)
|
||||
)
|
||||
|
||||
// 取消
|
||||
let cancel = CancelButton(title: "取消") {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// 确定
|
||||
let ok = DefaultButton(title: "确定", dismissOnTap: false) {
|
||||
let text = inputVC.textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
guard text.isEmpty == false else {
|
||||
// 简单的必填校验(也可改成 toast / 抖动)
|
||||
inputVC.textField.layer.borderColor = UIColor.systemRed.withAlphaComponent(0.6).cgColor
|
||||
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
||||
return
|
||||
}
|
||||
popup.dismiss() {
|
||||
onConfirm(text)
|
||||
}
|
||||
}
|
||||
|
||||
popup.addButtons([cancel, ok])
|
||||
|
||||
// (可选)统一外观:分割线/按钮颜色/标题样式
|
||||
let pv = PopupDialogDefaultView.appearance()
|
||||
pv.titleFont = .systemFont(ofSize: 16, weight: .semibold)
|
||||
pv.titleTextAlignment = .center
|
||||
pv.titleColor = .black
|
||||
pv.messageTextAlignment = .center
|
||||
|
||||
let cb = CancelButton.appearance()
|
||||
cb.titleColor = UIColor.darkText
|
||||
cb.separatorColor = UIColor.systemGray5
|
||||
|
||||
let db = DefaultButton.appearance()
|
||||
db.titleColor = UIColor.systemBlue
|
||||
db.separatorColor = UIColor.systemGray5
|
||||
|
||||
from.present(popup, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
open class ReviewFailedView : DDView {
|
||||
@@ -343,6 +446,18 @@ open class ReviewFailedCell : DDTableViewCell {
|
||||
public let orderStatusLabel : DDLabel
|
||||
public let descLabel : DDLabel
|
||||
public let dateLabel : DDLabel
|
||||
public let stackView : UIStackView
|
||||
public let appealButton : DDButton
|
||||
public var appealLayer : CAGradientLayer = {
|
||||
var layer = CAGradientLayer.init()
|
||||
layer.startPoint = CGPoint(x: 0, y: 0)
|
||||
layer.endPoint = CGPoint(x: 1, y: 1)
|
||||
layer.locations = [0.0,1.0]
|
||||
layer.colors = [UIColor.hex("FF5A2C").cgColor,UIColor.hex("FE9D4D").cgColor]
|
||||
layer.cornerRadius = auto(4)
|
||||
layer.masksToBounds = true
|
||||
return layer
|
||||
}()
|
||||
public let additionalButton : DDButton
|
||||
public var additionalLayer : CAGradientLayer = {
|
||||
var layer = CAGradientLayer.init()
|
||||
@@ -364,7 +479,9 @@ open class ReviewFailedCell : DDTableViewCell {
|
||||
orderStatusLabel = DDLabel.dd_init(withText: "", font: .mediumFont(auto(12)), textColor: .hex("E69B0B"))
|
||||
descLabel = DDLabel.dd_init(withText: "", font: .mediumFont(auto(13)), textColor: .hex("FF8F37"))
|
||||
dateLabel = DDLabel.dd_init(withText: "", font: .regularFont(auto(12)), textColor: .hex("000000").alpha(0.55))
|
||||
stackView = UIStackView()
|
||||
additionalButton = DDButton.dd_initCustom()
|
||||
appealButton = DDButton.dd_initCustom()
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
|
||||
backgroundColor = .hex("F4F5F7")
|
||||
@@ -385,12 +502,26 @@ open class ReviewFailedCell : DDTableViewCell {
|
||||
descLabel.numberOfLines = 0
|
||||
radiusView.addSubview(descLabel)
|
||||
radiusView.addSubview(dateLabel)
|
||||
stackView.axis = .horizontal
|
||||
stackView.distribution = .equalSpacing
|
||||
stackView.alignment = .center
|
||||
stackView.spacing = 10
|
||||
radiusView.addSubview(stackView)
|
||||
appealButton.setTitle("申诉", for: .normal)
|
||||
appealButton.setTitleColor(.white, for: .normal)
|
||||
appealButton.titleLabel?.font = .mediumFont(auto(13))
|
||||
appealButton.layer.cornerRadius = auto(4)
|
||||
appealButton.layer.masksToBounds = true
|
||||
appealButton.contentEdgeInsets = UIEdgeInsets(top: auto(6), left: auto(12), bottom: auto(6), right: auto(12))
|
||||
stackView.addArrangedSubview(appealButton)
|
||||
appealButton.layer.insertSublayer(appealLayer, at: 0)
|
||||
additionalButton.setTitle("补充", for: .normal)
|
||||
additionalButton.setTitleColor(.white, for: .normal)
|
||||
additionalButton.titleLabel?.font = .mediumFont(auto(13))
|
||||
additionalButton.layer.cornerRadius = auto(4)
|
||||
additionalButton.layer.masksToBounds = true
|
||||
radiusView.addSubview(additionalButton)
|
||||
additionalButton.contentEdgeInsets = UIEdgeInsets(top: auto(6), left: auto(12), bottom: auto(6), right: auto(12))
|
||||
stackView.addArrangedSubview(additionalButton)
|
||||
additionalButton.layer.insertSublayer(additionalLayer, at: 0)
|
||||
|
||||
radiusView.snp.makeConstraints { make in
|
||||
@@ -432,11 +563,11 @@ open class ReviewFailedCell : DDTableViewCell {
|
||||
make.bottom.equalTo(-auto(15))
|
||||
}
|
||||
|
||||
additionalButton.snp.makeConstraints { make in
|
||||
make.right.equalTo(-auto(10))
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.right.equalToSuperview().offset(-auto(10))
|
||||
make.centerY.equalTo(dateLabel)
|
||||
make.width.equalTo(auto(50))
|
||||
make.height.equalTo(auto(20))
|
||||
make.height.equalTo(auto(50))
|
||||
make.left.greaterThanOrEqualTo(dateLabel.snp.right).offset(auto(10))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,10 +578,14 @@ open class ReviewFailedCell : DDTableViewCell {
|
||||
open override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
disposeBag = DisposeBag()
|
||||
appealButton.isHidden = true
|
||||
additionalButton.isHidden = true
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
additionalLayer.frame = CGRectMake(0, 0, auto(50), auto(20))
|
||||
// Match gradient layers to button bounds
|
||||
appealLayer.frame = appealButton.bounds
|
||||
additionalLayer.frame = additionalButton.bounds
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user