114 lines
4.1 KiB
Swift
114 lines
4.1 KiB
Swift
//
|
||
// ScenicPromotionSettingsView.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/7/2.
|
||
//
|
||
|
||
import SwiftUI
|
||
|
||
/// 宣传页设置视图,管理排队绑定、素材点与 Mock 上传。
|
||
struct ScenicPromotionSettingsView: View {
|
||
@StateObject private var viewModel = ScenicPromotionSettingsViewModel()
|
||
@State private var showSelectMaterialPointAlert = false
|
||
@State private var showSubmitAlert = false
|
||
@State private var submitMessage = ""
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
AppDesign.background.ignoresSafeArea()
|
||
|
||
Group {
|
||
switch viewModel.pageState {
|
||
case .idle, .loading:
|
||
ScenicPromotionSettingsLoadingView()
|
||
.transition(.opacity.combined(with: .scale(scale: 0.98)))
|
||
case .empty:
|
||
ScenicPromotionSettingsFullStateView(
|
||
icon: "tray",
|
||
title: "暂无设置数据",
|
||
message: "当前没有可配置的排队打卡点和素材打卡点",
|
||
buttonTitle: "重新加载"
|
||
) {
|
||
Task { await viewModel.load() }
|
||
}
|
||
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
||
case .error(let message):
|
||
ScenicPromotionSettingsFullStateView(
|
||
icon: "wifi.exclamationmark",
|
||
title: "加载失败",
|
||
message: message,
|
||
buttonTitle: "重试"
|
||
) {
|
||
Task { await viewModel.load() }
|
||
}
|
||
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
||
case .normal:
|
||
ScenicPromotionSettingsContentView(
|
||
viewModel: viewModel,
|
||
onUploadFailed: { showSelectMaterialPointAlert = true }
|
||
)
|
||
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
||
}
|
||
}
|
||
.animation(.easeInOut(duration: 0.24), value: viewModel.pageState)
|
||
}
|
||
.navigationTitle("宣传页设置")
|
||
.navigationBarTitleDisplayMode(.inline)
|
||
.appNavigationDestination(item: $viewModel.previewMaterial) { material in
|
||
ScenicPromotionMaterialPreviewView(material: material)
|
||
}
|
||
.safeAreaInset(edge: .bottom) {
|
||
if case .normal = viewModel.pageState {
|
||
ScenicPromotionSettingsSubmitBarView(onSubmit: handleSubmit)
|
||
}
|
||
}
|
||
.toolbar {
|
||
ToolbarItem(placement: .navigationBarTrailing) {
|
||
Menu {
|
||
ForEach(ScenicPromotionSettingsDemoScenario.allCases) { scenario in
|
||
Button(scenario.title) {
|
||
viewModel.applyScenario(scenario)
|
||
}
|
||
}
|
||
} label: {
|
||
Image(systemName: "ellipsis.circle")
|
||
.font(.system(size: 18, weight: .semibold))
|
||
}
|
||
.accessibilityLabel("设置页演示状态")
|
||
}
|
||
}
|
||
.alert("请选择素材打卡点", isPresented: $showSelectMaterialPointAlert) {
|
||
Button("知道了", role: .cancel) {}
|
||
} message: {
|
||
Text("视频宣传素材和图片素材上传前,需要先选择素材所属打卡点。")
|
||
}
|
||
.alert("提交结果", isPresented: $showSubmitAlert) {
|
||
Button("知道了", role: .cancel) {}
|
||
} message: {
|
||
Text(submitMessage)
|
||
}
|
||
.task {
|
||
await viewModel.loadIfNeeded()
|
||
}
|
||
}
|
||
|
||
/// 提交设置并展示 Mock 结果提示。
|
||
private func handleSubmit() {
|
||
if viewModel.submit() {
|
||
submitMessage = "宣传页设置已保存,当前为 Mock 演示数据。"
|
||
} else {
|
||
submitMessage = "请至少绑定一个排队打卡点。"
|
||
}
|
||
showSubmitAlert = true
|
||
}
|
||
}
|
||
|
||
#if DEBUG
|
||
#Preview("宣传页设置") {
|
||
NavigationStack {
|
||
ScenicPromotionSettingsView()
|
||
}
|
||
}
|
||
#endif
|