106 lines
4.6 KiB
Swift
106 lines
4.6 KiB
Swift
import Foundation
|
|
|
|
/// 门店身份注销依赖;网络服务在主线程协调,ViewModel 自身不绑定 MainActor。
|
|
@MainActor
|
|
protocol StoreAccountDeregistrationStatusServing {
|
|
/// 只读查询当前注销记录,供进入普通业务前核验。
|
|
func status() async throws -> StoreAccountDeregistrationStatus
|
|
}
|
|
|
|
/// 完整注销服务,在状态查询之外提供条件、确认和申请操作。
|
|
@MainActor
|
|
protocol StoreAccountDeregistrationServing: StoreAccountDeregistrationStatusServing {
|
|
/// 获取资产与全部注销条件。
|
|
func eligibility() async throws -> StoreAccountDeregistrationEligibility
|
|
/// 分别确认现金余额。
|
|
func waiveWallet() async throws
|
|
/// 分别确认积分。
|
|
func waivePoints() async throws
|
|
/// 向当前身份的绑定手机号发送短信。
|
|
func sendSMS() async throws
|
|
/// 提交用户输入的验证码与注销原因。
|
|
func apply(smsCode: String, reason: String) async throws
|
|
/// 服务端判定是否允许撤销,不按本机截止时间判断。
|
|
func cancel() async throws
|
|
}
|
|
|
|
/// 旧门店身份注销接口请求层;仅使用提供的 account-deregister 路径和请求字段。
|
|
@MainActor
|
|
final class StoreAccountDeregistrationAPI: StoreAccountDeregistrationServing {
|
|
private let client: APIClient
|
|
private let identity: StoreAccountDeregistrationIdentity
|
|
private let isCurrentIdentity: @MainActor () -> Bool
|
|
private let basePath = "/api/yf-handset-app/account-deregister"
|
|
|
|
/// 注入网络客户端、冻结的门店身份和当前会话校验,便于隔离真实与测试请求。
|
|
init(
|
|
client: APIClient,
|
|
identity: StoreAccountDeregistrationIdentity,
|
|
isCurrentIdentity: @escaping @MainActor () -> Bool
|
|
) {
|
|
self.client = client
|
|
self.identity = identity
|
|
self.isCurrentIdentity = isCurrentIdentity
|
|
}
|
|
|
|
/// 查询当前门店身份的资产、风险期和全部阻断项。
|
|
func eligibility() async throws -> StoreAccountDeregistrationEligibility {
|
|
let value: StoreAccountDeregistrationEligibility = try await send(APIRequest(method: .get, path: basePath + "/eligibility"))
|
|
guard String(value.storeUserID) == identity.userID else {
|
|
throw StoreAccountDeregistrationError.sessionChanged
|
|
}
|
|
return value
|
|
}
|
|
|
|
/// 调用旧现金确认接口;与积分接口的顺序协调由ViewModel负责。
|
|
func waiveWallet() async throws {
|
|
let _: EmptyPayload = try await send(APIRequest(
|
|
method: .post,
|
|
path: basePath + "/waivers/wallet",
|
|
body: StoreAccountDeregistrationWaiverRequest()
|
|
))
|
|
}
|
|
|
|
/// 调用旧积分确认接口;与现金接口的顺序协调由ViewModel负责。
|
|
func waivePoints() async throws {
|
|
let _: EmptyPayload = try await send(APIRequest(
|
|
method: .post,
|
|
path: basePath + "/waivers/points",
|
|
body: StoreAccountDeregistrationWaiverRequest()
|
|
))
|
|
}
|
|
|
|
/// 向当前门店身份绑定手机号发送短信;收件人由后端从 Token 确定。
|
|
func sendSMS() async throws {
|
|
let _: EmptyPayload = try await send(APIRequest(method: .post, path: basePath + "/send-sms"))
|
|
}
|
|
|
|
/// 使用用户输入的验证码和原因提交申请;成功后需查询服务端状态。
|
|
func apply(smsCode: String, reason: String) async throws {
|
|
let _: EmptyPayload = try await send(APIRequest(
|
|
method: .post,
|
|
path: basePath + "/apply",
|
|
body: StoreAccountDeregistrationApplyRequest(smsCode: smsCode, reason: reason)
|
|
))
|
|
}
|
|
|
|
/// 查询当前身份的草稿、冷静期、撤销、阻断或完成状态,不触发重新登录。
|
|
func status() async throws -> StoreAccountDeregistrationStatus {
|
|
try await send(APIRequest(method: .get, path: basePath + "/status"))
|
|
}
|
|
|
|
/// 正式完成前由用户主动撤销;是否可撤销始终由服务端判定。
|
|
func cancel() async throws {
|
|
let _: EmptyPayload = try await send(APIRequest(method: .post, path: basePath + "/cancel"))
|
|
}
|
|
|
|
private func send<Response: Decodable>(_ request: APIRequest<Response>) async throws -> Response {
|
|
guard isCurrentIdentity() else { throw StoreAccountDeregistrationError.sessionChanged }
|
|
var sensitiveRequest = request
|
|
sensitiveRequest.logsPayload = false
|
|
let response = try await client.send(sensitiveRequest, tokenOverride: identity.token)
|
|
guard isCurrentIdentity() else { throw StoreAccountDeregistrationError.sessionChanged }
|
|
return response
|
|
}
|
|
}
|