修复任务提交与弹窗交互问题

This commit is contained in:
2026-07-10 14:51:34 +08:00
parent df547a16dc
commit f88a85a807
48 changed files with 1065 additions and 254 deletions

View File

@ -220,7 +220,18 @@ private extension String {
}
/// 退 Android `OrderRefundDialog` / `DepositOrderRefundDialog`
final class OrderRefundDialogView: UIView, UITextViewDelegate {
final class OrderRefundDialogView: KeyboardAvoidingDialogView, UITextViewDelegate {
/// 退
private enum Layout {
static let sectionGap: CGFloat = AppSpacing.lg
static let formGap: CGFloat = AppSpacing.md
static let controlHeight: CGFloat = AppSpacing.minTouchTarget
static let amountGroupHeight: CGFloat = 67
static let remarkHeight: CGFloat = 88
static let actionTop: CGFloat = 14
static let bottomInset: CGFloat = AppSpacing.md
}
/// 退/
struct Configuration {
@ -266,8 +277,6 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
private let configuration: Configuration
private var selectedMode: OrderRefundMode
private var keyboardObservers: [NSObjectProtocol] = []
private var cardCenterYConstraint: Constraint?
private let dimView = UIView()
private let cardView = UIView()
@ -304,16 +313,11 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
fatalError("init(coder:) has not been implemented")
}
deinit {
unregisterKeyboardObservers()
}
func show(in parent: UIView) {
frame = parent.bounds
autoresizingMask = [.flexibleWidth, .flexibleHeight]
alpha = 0
parent.addSubview(self)
registerKeyboardObservers()
UIView.animate(withDuration: 0.2) {
self.alpha = 1
}
@ -321,7 +325,6 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
func dismiss() {
endEditing(true)
unregisterKeyboardObservers()
UIView.animate(withDuration: 0.2, animations: {
self.alpha = 0
}, completion: { _ in
@ -330,6 +333,9 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
}
private func setupUI() {
keyboardAvoidingContentView = cardView
keyboardAvoidingMinimumSpacing = AppSpacing.sm
dimView.backgroundColor = UIColor.black.withAlphaComponent(0.2)
dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(cancelTapped)))
@ -422,7 +428,7 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
}
cardView.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
cardCenterYConstraint = make.centerY.equalToSuperview().constraint
keyboardAvoidingCenterYConstraint = make.centerY.equalToSuperview().constraint
}
titleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(AppSpacing.sm)
@ -442,18 +448,18 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
refundModeTitleLabel.snp.makeConstraints { make in
make.top.equalTo(orderNumberLabel.snp.bottom).offset(AppSpacing.xl)
make.top.equalTo(orderNumberLabel.snp.bottom).offset(Layout.sectionGap)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
modeButtonStack.snp.makeConstraints { make in
make.top.equalTo(refundModeTitleLabel.snp.bottom).offset(AppSpacing.xs)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
make.height.equalTo(46)
make.height.equalTo(Layout.controlHeight)
}
amountGroupView.snp.makeConstraints { make in
make.top.equalTo(modeButtonStack.snp.bottom).offset(AppSpacing.xl)
make.top.equalTo(modeButtonStack.snp.bottom).offset(Layout.formGap)
make.leading.trailing.equalToSuperview()
make.height.equalTo(73)
make.height.equalTo(Layout.amountGroupHeight)
}
amountTitleLabel.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(UIEdgeInsets(top: 0, left: AppSpacing.md, bottom: 0, right: AppSpacing.md))
@ -461,20 +467,20 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
amountContainerView.snp.makeConstraints { make in
make.top.equalTo(amountTitleLabel.snp.bottom).offset(AppSpacing.xs)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
make.height.equalTo(46)
make.height.equalTo(Layout.controlHeight)
}
amountField.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview().inset(AppSpacing.sm)
make.centerY.equalToSuperview()
}
remarkTitleLabel.snp.makeConstraints { make in
make.top.equalTo(amountGroupView.snp.bottom).offset(AppSpacing.xl)
make.top.equalTo(amountGroupView.snp.bottom).offset(Layout.formGap)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
remarkContainerView.snp.makeConstraints { make in
make.top.equalTo(remarkTitleLabel.snp.bottom).offset(AppSpacing.xs)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
make.height.equalTo(104)
make.height.equalTo(Layout.remarkHeight)
}
remarkTextView.snp.makeConstraints { make in
make.edges.equalToSuperview()
@ -484,9 +490,9 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
make.leading.trailing.equalToSuperview().inset(AppSpacing.sm)
}
actionRow.snp.makeConstraints { make in
make.top.equalTo(remarkContainerView.snp.bottom).offset(20)
make.top.equalTo(remarkContainerView.snp.bottom).offset(Layout.actionTop)
make.trailing.equalToSuperview().inset(AppSpacing.md)
make.bottom.equalToSuperview().inset(AppSpacing.lg)
make.bottom.equalToSuperview().inset(Layout.bottomInset)
}
[cancelButton, confirmButton].forEach { button in
button.snp.makeConstraints { make in
@ -521,10 +527,10 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
let amountHidden = selectedMode == .full
amountGroupView.isHidden = amountHidden
amountGroupView.snp.updateConstraints { make in
make.height.equalTo(amountHidden ? 0 : 73)
make.height.equalTo(amountHidden ? 0 : Layout.amountGroupHeight)
}
remarkTitleLabel.snp.remakeConstraints { make in
make.top.equalTo((amountHidden ? modeButtonStack : amountGroupView).snp.bottom).offset(AppSpacing.xl)
make.top.equalTo((amountHidden ? modeButtonStack : amountGroupView).snp.bottom).offset(Layout.formGap)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
@ -544,60 +550,6 @@ final class OrderRefundDialogView: UIView, UITextViewDelegate {
button.setTitleColor(selected ? .white : UIColor(hex: 0x4B5563), for: .normal)
}
private func registerKeyboardObservers() {
unregisterKeyboardObservers()
let center = NotificationCenter.default
keyboardObservers = [
center.addObserver(
forName: UIResponder.keyboardWillChangeFrameNotification,
object: nil,
queue: .main
) { [weak self] notification in
self?.handleKeyboardNotification(notification)
},
center.addObserver(
forName: UIResponder.keyboardWillHideNotification,
object: nil,
queue: .main
) { [weak self] notification in
self?.handleKeyboardNotification(notification)
}
]
}
private func unregisterKeyboardObservers() {
keyboardObservers.forEach(NotificationCenter.default.removeObserver)
keyboardObservers.removeAll()
}
private func handleKeyboardNotification(_ notification: Notification) {
layoutIfNeeded()
guard let userInfo = notification.userInfo else { return }
let duration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.25
let curveRaw = (userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue
?? UInt(UIView.AnimationCurve.easeInOut.rawValue)
let options = UIView.AnimationOptions(rawValue: curveRaw << 16)
let offset = keyboardAvoidanceOffset(from: userInfo)
cardCenterYConstraint?.update(offset: offset)
UIView.animate(withDuration: duration, delay: 0, options: options) {
self.layoutIfNeeded()
}
}
private func keyboardAvoidanceOffset(from userInfo: [AnyHashable: Any]) -> CGFloat {
guard
let keyboardFrameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
else {
return 0
}
let keyboardFrame = convert(keyboardFrameValue.cgRectValue, from: nil)
guard keyboardFrame.minY < bounds.height else { return 0 }
let desiredBottom = keyboardFrame.minY - AppSpacing.sm
let overlap = cardView.frame.maxY - desiredBottom
return overlap > 0 ? -overlap : 0
}
func textViewDidChange(_ textView: UITextView) {
if textView.text.count > 255 {
textView.text = String(textView.text.prefix(255))

View File

@ -17,6 +17,7 @@ final class OrderSourceEntryView: UIControl {
private let personRow = UIStackView()
private let personNameLabel = UILabel()
private let personPhoneLabel = UILabel()
private let personSpacerView = UIView()
private let divider = UIView()
private let leadContentView = OrderSourceLeadContentView()
private var currentImages: [String] = []
@ -83,10 +84,19 @@ final class OrderSourceEntryView: UIControl {
personRow.spacing = 10
personNameLabel.font = .systemFont(ofSize: 13, weight: .medium)
personNameLabel.textColor = AppColor.text333
personNameLabel.lineBreakMode = .byTruncatingTail
personNameLabel.setContentHuggingPriority(.required, for: .horizontal)
personNameLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
personPhoneLabel.font = .systemFont(ofSize: 13)
personPhoneLabel.textColor = AppColor.text666
personPhoneLabel.lineBreakMode = .byTruncatingTail
personPhoneLabel.setContentHuggingPriority(.required, for: .horizontal)
personPhoneLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
personSpacerView.setContentHuggingPriority(.defaultLow, for: .horizontal)
personSpacerView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
personRow.addArrangedSubview(personNameLabel)
personRow.addArrangedSubview(personPhoneLabel)
personRow.addArrangedSubview(personSpacerView)
divider.backgroundColor = OrderTokens.sourceDivider

View File

@ -15,6 +15,7 @@ final class OrderSourceLeadContentView: UIView {
private let phoneRow = UIStackView()
private let phoneTitleLabel = UILabel()
private let phoneValueLabel = UILabel()
private let phoneSpacerView = UIView()
private let remarkLabel = UILabel()
private let imageRow = UIStackView()
private let emptyImageLabel = UILabel()
@ -91,12 +92,20 @@ final class OrderSourceLeadContentView: UIView {
phoneTitleLabel.text = "客户手机号"
phoneTitleLabel.font = .systemFont(ofSize: 12)
phoneTitleLabel.textColor = AppColor.text666
phoneTitleLabel.setContentHuggingPriority(.required, for: .horizontal)
phoneTitleLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
phoneValueLabel.font = .systemFont(ofSize: 13, weight: .medium)
phoneValueLabel.lineBreakMode = .byTruncatingTail
phoneValueLabel.setContentHuggingPriority(.required, for: .horizontal)
phoneValueLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
phoneValueLabel.addGestureRecognizer(
UITapGestureRecognizer(target: self, action: #selector(phoneTapped))
)
phoneSpacerView.setContentHuggingPriority(.defaultLow, for: .horizontal)
phoneSpacerView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
phoneRow.addArrangedSubview(phoneTitleLabel)
phoneRow.addArrangedSubview(phoneValueLabel)
phoneRow.addArrangedSubview(phoneSpacerView)
remarkLabel.textColor = AppColor.text333
remarkLabel.lineBreakMode = .byTruncatingTail