修复合作获客扫码绑定崩溃与 Toast 层级,并接入分成比例修改。

将扫码页提升到列表层弹出并补齐 AppDelegate.window,避免扫码时 UIKit 取主窗口崩溃;Toast 改用独立 UIWindow 显示在 sheet 之上;合作获客员支持短信验证修改分成比例,同时优化冷启动根视图创建时机并补充相关测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-03 20:37:24 +08:00
parent 00c3cd0a93
commit 49e997ddba
20 changed files with 905 additions and 70 deletions

View File

@ -160,6 +160,10 @@ struct ReferralLeadCard: View {
.font(.system(size: 11))
.foregroundStyle(CooperationOrderColors.text999)
}
CooperationListInfoRow(
label: "获客员",
value: lead.displaySalerName.isEmpty ? "" : lead.displaySalerName
)
Text("备注")
.font(.system(size: 13))
@ -302,6 +306,7 @@ struct CooperativeSalerCard: View {
let acquirer: CooperativeSaler
let onDial: (String) -> Void
let onEditRemark: () -> Void
let onEditCommission: () -> Void
var body: some View {
ZStack(alignment: .topTrailing) {
@ -323,6 +328,10 @@ struct CooperativeSalerCard: View {
label: "绑定时间",
value: acquirer.displayBindTime.isEmpty ? "" : acquirer.displayBindTime
)
AcquirerCommissionInfoRow(
commissionRate: acquirer.displayCommissionRate.isEmpty ? "" : acquirer.displayCommissionRate,
onEdit: onEditCommission
)
}
.padding(.leading, 12)
.frame(maxWidth: .infinity, alignment: .leading)
@ -344,6 +353,179 @@ struct CooperativeSalerCard: View {
}
}
struct AcquirerCommissionInfoRow: View {
let commissionRate: String
let onEdit: () -> Void
var body: some View {
HStack(alignment: .center, spacing: 0) {
Text("分成比例")
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.text999)
Text(commissionRate)
.font(.system(size: 13, weight: .medium))
.foregroundStyle(CooperationOrderColors.text666)
.padding(.leading, 12)
Spacer(minLength: 8)
Button("修改比例") {
onEdit()
}
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.primary)
.buttonStyle(.plain)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.contentShape(Rectangle())
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct BindCommissionRateInputRow: View {
@Binding var value: String
var enabled: Bool = true
var body: some View {
VStack(alignment: .leading, spacing: 7) {
Text("分账比例")
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.text666)
HStack(spacing: 8) {
TextField("请输入0到100", text: $value)
.keyboardType(.numberPad)
.font(.system(size: 14))
.foregroundStyle(CooperationOrderColors.text333)
.disabled(!enabled)
Text("%")
.font(.system(size: 14))
.foregroundStyle(CooperationOrderColors.text666)
}
.padding(.horizontal, 12)
.padding(.vertical, 13)
.background(Color(hex: 0xF7F8FA), in: RoundedRectangle(cornerRadius: 8))
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
struct CommissionRateEditSheet: View {
let acquirer: CooperativeSaler
@Binding var commissionRate: String
@Binding var smsCode: String
let smsCountdown: Int
let sending: Bool
let submitting: Bool
let onSendSmsCode: () -> Void
let onConfirm: () -> Void
let onCancel: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 16) {
Capsule()
.fill(Color.black.opacity(0.16))
.frame(width: 36, height: 4)
.frame(maxWidth: .infinity)
.padding(.top, 8)
Text("修改分成比例")
.font(.system(size: 18, weight: .bold))
.foregroundStyle(CooperationOrderColors.text333)
Text("修改分成比例需验证手机号")
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.primary)
.padding(.horizontal, 12)
.padding(.vertical, 10)
.frame(maxWidth: .infinity, alignment: .leading)
.background(CooperationOrderColors.primary.opacity(0.08), in: RoundedRectangle(cornerRadius: 8))
VStack(alignment: .leading, spacing: 8) {
Text("分成比例")
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.text666)
HStack(spacing: 8) {
TextField("请输入0到100", text: $commissionRate)
.keyboardType(.numberPad)
.font(.system(size: 15))
Text("%")
.font(.system(size: 15, weight: .medium))
.foregroundStyle(CooperationOrderColors.text666)
}
.padding(.horizontal, 12)
.frame(height: 46)
.background(CooperationOrderColors.searchBg, in: RoundedRectangle(cornerRadius: 8))
}
VStack(alignment: .leading, spacing: 8) {
Text("验证码发送手机号")
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.text666)
Text(maskAcquirerPhone(acquirer.displayMaskedPhone))
.font(.system(size: 15))
.foregroundStyle(CooperationOrderColors.text333)
.padding(.horizontal, 12)
.frame(maxWidth: .infinity, minHeight: 46, alignment: .leading)
.background(CooperationOrderColors.searchBg, in: RoundedRectangle(cornerRadius: 8))
}
VStack(alignment: .leading, spacing: 8) {
Text("验证码")
.font(.system(size: 13))
.foregroundStyle(CooperationOrderColors.text666)
HStack(spacing: 10) {
TextField("请输入验证码", text: $smsCode)
.keyboardType(.numberPad)
.font(.system(size: 15))
.padding(.horizontal, 12)
.frame(height: 46)
.background(CooperationOrderColors.searchBg, in: RoundedRectangle(cornerRadius: 8))
Button(smsButtonTitle) {
onSendSmsCode()
}
.font(.system(size: 13, weight: .medium))
.foregroundStyle(.white)
.frame(width: 104, height: 46)
.background(smsButtonEnabled ? CooperationOrderColors.primary : CooperationOrderColors.primary.opacity(0.45), in: RoundedRectangle(cornerRadius: 8))
.disabled(!smsButtonEnabled)
}
}
HStack(spacing: 12) {
Button("取消") {
onCancel()
}
.font(.system(size: 15, weight: .medium))
.foregroundStyle(CooperationOrderColors.text666)
.frame(maxWidth: .infinity)
.frame(height: 44)
.background(Color(hex: 0xF1F3F5), in: RoundedRectangle(cornerRadius: 8))
Button(submitting ? "提交中..." : "确认修改") {
onConfirm()
}
.font(.system(size: 15, weight: .medium))
.foregroundStyle(.white)
.frame(maxWidth: .infinity)
.frame(height: 44)
.background(CooperationOrderColors.primary, in: RoundedRectangle(cornerRadius: 8))
.disabled(submitting)
}
.padding(.top, 4)
}
.padding(.horizontal, 18)
.padding(.bottom, 20)
}
private var smsButtonTitle: String {
if smsCountdown > 0 { return "\(smsCountdown)" }
return sending ? "发送中" : "获取验证码"
}
private var smsButtonEnabled: Bool {
smsCountdown == 0 && !sending
}
}
struct AcquirerInfoRow: View {
let label: String
let value: String