Add Lottie-based global loading overlay across key flows.
Introduce GlobalLoadingCenter with reference counting, wire it through RootView and major auth/order/profile screens, and add the loading animation asset plus unit tests. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -15,6 +15,7 @@ struct OrdersView: View {
|
||||
@Environment(RouterPath.self) private var router
|
||||
@Environment(OrdersAPI.self) private var ordersAPI
|
||||
@Environment(ToastCenter.self) private var toastCenter
|
||||
@Environment(\.globalLoading) private var globalLoading
|
||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
|
||||
@State private var viewModel = OrdersViewModel()
|
||||
@ -227,10 +228,10 @@ struct OrdersView: View {
|
||||
|
||||
private var storeList: some View {
|
||||
LazyVStack(spacing: AppMetrics.Spacing.small) {
|
||||
if viewModel.loading {
|
||||
ProgressView()
|
||||
if viewModel.loading && viewModel.storeOrders.isEmpty {
|
||||
Color.clear
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, AppMetrics.Spacing.xxLarge)
|
||||
.frame(minHeight: 260)
|
||||
} else if viewModel.storeOrders.isEmpty {
|
||||
ContentUnavailableView("暂无订单", systemImage: "tray", description: Text("可切换筛选条件或下拉刷新。"))
|
||||
.frame(minHeight: 260)
|
||||
@ -300,10 +301,10 @@ struct OrdersView: View {
|
||||
|
||||
private var writeOffList: some View {
|
||||
LazyVStack(spacing: AppMetrics.Spacing.small) {
|
||||
if viewModel.loading {
|
||||
ProgressView()
|
||||
if viewModel.loading && viewModel.writeOffOrders.isEmpty {
|
||||
Color.clear
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, AppMetrics.Spacing.xxLarge)
|
||||
.frame(minHeight: 260)
|
||||
} else if viewModel.writeOffOrders.isEmpty {
|
||||
ContentUnavailableView("暂无核销订单", systemImage: "tray", description: Text("可下拉刷新或切换景区查看。"))
|
||||
.frame(minHeight: 260)
|
||||
@ -516,18 +517,31 @@ struct OrdersView: View {
|
||||
|
||||
private func reload(showLoading: Bool = true) async {
|
||||
do {
|
||||
try await viewModel.reload(
|
||||
api: ordersAPI,
|
||||
scenicId: currentScenicId,
|
||||
storeId: currentStoreId,
|
||||
roleId: currentRoleId,
|
||||
showLoading: showLoading
|
||||
)
|
||||
try await globalLoading.withOptionalLoading(shouldShowGlobalLoading(showLoading: showLoading), message: "加载中...") {
|
||||
try await viewModel.reload(
|
||||
api: ordersAPI,
|
||||
scenicId: currentScenicId,
|
||||
storeId: currentStoreId,
|
||||
roleId: currentRoleId,
|
||||
showLoading: showLoading
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
toastCenter.show(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断当前订单列表加载是否需要使用全局 Loading。
|
||||
private func shouldShowGlobalLoading(showLoading: Bool) -> Bool {
|
||||
guard showLoading, currentScenicId != nil else { return false }
|
||||
switch viewModel.selectedEntry {
|
||||
case .storeOrders:
|
||||
return viewModel.storeOrders.isEmpty
|
||||
case .verificationOrders:
|
||||
return viewModel.writeOffOrders.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
private func loadMoreStoreOrders() async {
|
||||
do {
|
||||
try await viewModel.loadMoreStoreOrders(api: ordersAPI, scenicId: currentScenicId, roleId: currentRoleId)
|
||||
@ -567,7 +581,9 @@ struct OrdersView: View {
|
||||
private func verify(orderNumber: String) async {
|
||||
guard let scenicId = currentScenicId else { return }
|
||||
do {
|
||||
try await viewModel.verify(api: ordersAPI, scenicId: scenicId, storeId: currentStoreId, orderNumber: orderNumber)
|
||||
try await globalLoading.withLoading(message: "核销中...") {
|
||||
try await viewModel.verify(api: ordersAPI, scenicId: scenicId, storeId: currentStoreId, orderNumber: orderNumber)
|
||||
}
|
||||
manualOrderNumber = ""
|
||||
pendingVerifyOrder = nil
|
||||
pendingVerifyOrderNumber = nil
|
||||
|
||||
Reference in New Issue
Block a user