swiftUI 中来自不同数据模型(API 响应)的详细视图

Detail View from different Data Model (API response) in swiftUI

用代码深入阐述问题

我有一个数据模型(API 响应),我正在使用它来创建列表。列表项还应在详细视图中显示其详细信息。问题是列表项的详细信息来自不同的 API,而不是用于创建列表的 API。一项的 ID 被传递给 API,后者作为响应提供该项目的详细信息。

这是数据模型(仅包含特定问题的项目):

struct TrackSample : Codable, Identifiable {
    let id = UUID()
    let success : Bool
    let message : String
    let trackResponse : [TrackResponse]

    enum CodingKeys: String, CodingKey{
    case success = "IsSuccess"
    case message = "Message"
    case trackResponse = "ResponseData"
    }}

struct TrackResponse : Codable, Identifiable {
    let id = UUID()
    let patientID : String
    let name : String
    let testCount : Int
//..some more//

enum CodingKeys: String, CodingKey {
    case patientID = "PatientId"
    case name = "Name"
    case status = "Status"
case testCount = "NoOfTests"
    }}

ViewModel 获取 API 响应(TrackResource() 是一个不同的 class,它实现了网络调用):

class TrackViewModel : ObservableObject
    {
        @Published var trackReport = [TrackResponse]()
        @Published var navigate:Bool = false
        //other var
        private let trackResource = TrackResource()

    func getTrack()
    {
    //code to get data based on which button is clicked in Options 
    screen. 
    There are five options to choose:
    if else statement follows//
        
    centerID = "100"
    
        let trackRequest = TrackRequest(CenterId:centerID, 
    SearchText:searchText, StartDate:startDate, EndDate:endDate)
     trackResource.track(trackRequest: trackRequest)
        {
         response in
         if(response?.success==true)
          {
                DispatchQueue.main.async {
                self.navigate = true
                self.trackReport = response?.trackResponse ?? []
            }
        }
        else
        {
            DispatchQueue.main.async {
                self.errorMessage = response?.message ?? "No Data"
             //   self.isPresentingAlert
            }
        }}}}

表示列表的视图 YdaySample :

struct YdaySample: View {

@ObservedObject var tracking : TrackViewModel

    var body: some View {

    NavigationView{

        List{
         ForEach(tracking.trackReport)
            { truck in
             NavigationLink(destination: TrackDetail(track:truck))
                        {
                            YdayRow(truck: truck)
                        }
                }
         if(tracking.trackReport.isEmpty){
        Text("No Record Found !")
            //formatting
        }}}}}

struct YdaySample_Previews: PreviewProvider {
static var previews: some View {
 YdaySample(tracking: TrackViewModel())
         }}

YdayRow() :

      struct YdayRow: View {
     var truck : TrackResponse
     var body: some View {
     VStack{
         HStack{
                Text(truck.name)
            //formatting//
        }
    HStack{
            Text("P.Id:")
            //formatting//
            Text(truck.patientID)
            //formatting//
    
        Spacer()
        Text("Total Test:")
            //formatting//
        Text("\(truck.testCount)")
            //formatting//
    }}}}

  struct YdayRow_Previews: PreviewProvider {
         static var previews: some View {
        YdayRow(truck: TrackResponse(patientID: "1", name: "test", 
  status: "null", crmNo: "null", 
      recordDate: "somedate", uniqueID: "null", testCount: 4))
        }
    }

TrackDetail() 已更新:

 struct TrackDetail: View {

 var track: TrackResponse
 @State var patientDetail: DetailResponse
 
 var body: some View {
        VStack{
            HStack{
                Text(track.name)
                   //formatting
                    }.frame(maxWidth: .infinity, alignment: .center)
            
                HStack{
                Text("P.Id:")
                        //formatting
                    Text(track.patientId)
                       //formatting
               
               }
           
                List{ForEach(patientDetail.detailResponse)
                        {detail in
                            HStack
                        { Text("Barcode: ")
                            Text(detail.barcode)
                        }
                    }
                }.onAppear{
                    Task{
                        do{
                            try await getDetail()
                        }catch{
                Alert(title: Text("Error"),message: Text("Not Found"), 
            dismissButton: .cancel())
                        }}}}}

func getDetail() async throws{
    
  
    var urlComponents = URLComponents()
    urlComponents.scheme = "http"
    urlComponents.host = "xx.xxx.xx.xx"
    urlComponents.path = "/api/reports/getalltests"
    urlComponents.queryItems = [URLQueryItem(name: "centerId", value: 
    ("\(668)")),URLQueryItem(name: "patientId", value: "\ 
    (track.patientId)")]

    let url = urlComponents.url

    var request = URLRequest(url: url!)
    print(request)
    request.setValue("application/json", forHTTPHeaderField: "Accept")
    request.setValue("application/json", forHTTPHeaderField: "Content- 
    Type")
    request.setValue("Basic xcvgjhalddjdj",forHTTPHeaderField: 
    "Authorization")
    // Send HTTP Request
    let task = URLSession.shared.dataTask(with: request) { (data, 
     response, error) in
        
        // Check if Error took place
        if let error = error {
            print("Error took place \(error)")
            return
        }
        
        // Read HTTP Response Status code
        if let response = response as? HTTPURLResponse {
            print("Response HTTP Status code: \(response.statusCode)")
        }
        
       if let data = data
        
        {
           
              let dataString = String(data:data,encoding: .utf8)
              print(dataString!)
            
             do{
                let json = try JSONDecoder().decode(DetailResponse.self, 
               from: data)
               print(json)
                DispatchQueue.main.async {
                    self.patientDetail = json
                }
             
    
            }catch{
                print("error \(error)")
            }
                      
        }
    };task.resume()
        }}



    struct TrackDetail_Previews: PreviewProvider {
    static var previews: some View {
    TrackDetail(track: TrackResponse(patientId: "4193716", name: "Dummy 
    Report HCV RNA", status: "null", crmNo: "null", recordDate: "2022- 
     04-15", uniqueId: "null", testCount: 10), patientDetail: 
     DetailResponse(success: false, message: "mess", detailResponse: 
       []))
    }}

print(request) 正在根据需要正确打印 URL url 中的 patientID 也是正确的 (http://xxx..x.x/api/reports/getalltests/centerId=668&patientId=(tapped id))

但它在解码时抛出错误 说“此请求已被拒绝授权”错误 keynotfound(codingkeys(stringvalue: "ResponseData", intvalue:nil), Swift.decodingerror.context(codingpath: [],debugdescription: "No value associated with key CodingKeys(stringvalue: "ResponseData", intvalue:nil)("ResponseData", underlyingError:nil)

struct DetailResponse : Codable{
    let success : Bool ?
    let message : String
    let detailResponse : [PatResponse]

    enum CodingKeys: String, CodingKey{
    case success = "IsSuccess"
    case message = "Message"
    case patResponse = "ResponseData"
    }}

struct PatResponse : Codable, Identifiable {    
    var barcode: String
    var:id String {barcode} 
    let testname : String?
    let packageName : String?
    let status: String?
    let sampleRecievedTime: String?
    let recordDate: String

enum CodingKeys: String, CodingKey {
    case packageName = "PackageName"
    case testname = "TestName"
    case status = "Status"
    case sampleRecievedTime = "SampleRecievedTime"
    case recordDate = "RecordDate"
    case barcode = "Barcode"
    }}

///////**************////////////////// 详细视图显示名称和 ID,因为它们来自 TrackResponse 但是状态和条形码不是来自不同的API。

当用户 click/tap 列表中的项目时,patientID 和 centerId 作为 GET 请求中的查询参数发送,作为响应将提供与给定 patientId 关联的详细信息(中心 ID 是常量)。如何实现?

这样的怎么样?

struct TrackDetail: View{
    
    var track: TrackResponse
    @State var details: TrackDetails?
    
    var body: some View{
        HStack{
            //Detail implementation
        }.onAppear{
            Task{
                do{
                    try await doStuff()
                }catch{
                    //Alert
                }
            }
        }
    }
    
    func doStuff() async throws{
        // pull Details from Api
        
    }
}