import SwiftUI import Combine struct PhotoView: View { let albumId: String @StateObject private var viewModel: PhotoViewModel init(albumId: String) { self.albumId = albumId self._viewModel = StateObject(wrappedValue: PhotoViewModel(albumId: albumId)) } var body: some View { ZStack { if viewModel.isLoading { ProgressView() } else if let album = viewModel.album { ScrollView { VStack(alignment: .leading, spacing: 8) { Text(album.name) .font(.headline) Text("作者: \(album.authors.joined(separator: ", "))") .font(.subheadline) Text("标签: \(album.tags.joined(separator: ", "))") .font(.caption) .foregroundColor(.gray) } .padding() .frame(maxWidth: .infinity, alignment: .leading) .background(Color(.systemBackground)) LazyVStack(spacing: 0) { // 去掉图片间距 ForEach(Array(album.image_urls.enumerated()), id: \.offset) { index, url in AsyncImageView( url: url, nums: album.nums, index: index ) .frame(maxWidth: .infinity) // 强制图片填充父视图宽度 .aspectRatio(contentMode: .fill) // 确保图片填充整个区域 .clipped() // 防止图片超出边界 } } } .edgesIgnoringSafeArea(.all) // 让内容填充整个屏幕 } else if let error = viewModel.error { Text("加载失败: \(error.localizedDescription)") } } .alert(isPresented: $viewModel.showAlert) { Alert( title: Text(viewModel.alertTitle), message: Text(viewModel.alertMessage), dismissButton: .default(Text("确定")) ) } } } // 其余代码保持不变(PhotoView, PhotoViewModel, Album结构体等) class PhotoViewModel: ObservableObject { let albumId: String @Published var album: Album? @Published var isLoading = false @Published var error: Error? @Published var scrollPosition: Double = 0 @Published var showAlert = false @Published var alertTitle = "" @Published var alertMessage = "" private var cancellables = Set() init(albumId: String) { self.albumId = albumId loadAlbumData() } func loadAlbumData() { isLoading = true error = nil let urlString = "https://jms.godserver.cn/album/\(albumId)/" guard let url = URL(string: urlString) else { error = NSError(domain: "无效的URL", code: 0, userInfo: nil) isLoading = false return } print("正在加载相册数据: \(urlString)") URLSession.shared.dataTaskPublisher(for: url) .map(\.data) .decode(type: Album.self, decoder: JSONDecoder()) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { [weak self] completion in self?.isLoading = false if case .failure(let error) = completion { self?.error = error print("相册加载失败: \(error.localizedDescription)") } }, receiveValue: { [weak self] album in self?.album = album print("成功加载相册: \(album.name), 包含 \(album.image_urls.count) 张图片") }) .store(in: &cancellables) } func showAlert(title: String, message: String) { alertTitle = title alertMessage = message showAlert = true } } struct Album: Codable { let album_id: String let name: String let authors: [String] let actors: [String] let tags: [String] let image_urls: [String] let nums: [Int] enum CodingKeys: String, CodingKey { case album_id, name, authors, actors, tags case image_urls = "image_urls" case nums } }