use anyhow::Result; use image::EncodableLayout; #[allow(unused_imports)] use tracing::{error, info, warn}; #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct SearchResultItem { name: String, code: String, has_device: String, img_urls: Vec, } #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct FetchResultItem { pub imgs: Vec, pub name: String, pub model:String, pub code :String, pub model_id: String, pub datasheet:String, } /// 访问一次api,得到需要的部分数据 pub async fn search_keyword( keyword: String, cur_page: u32, page_size: u32, ) -> Result> { let mut form_maps = std::collections::HashMap::new(); form_maps.insert("keyword", keyword); let cur_page = format!("{cur_page}"); let page_size = format!("{page_size}"); form_maps.insert("curPage", cur_page); form_maps.insert("pageSize", page_size); let resp = reqwest::Client::new() .post("https://pro.lceda.cn/api/eda/product/search") .form(&form_maps) .send() .await?; let text = resp.text().await?; let j: KeywordSearchRoot = serde_json::from_str(&text)?; let mut r = Vec::new(); for i in j.result.productList.iter() { if let Some(has) = i.hasDevice.clone() { let mut imgs = Vec::new(); if let Some(s) = i.image.clone() { for img in s.imgs() { imgs.push(img.clone()); } } let ii = SearchResultItem { name: i.model.clone(), code:i.code.clone(), has_device: has, img_urls: imgs, }; r.push(ii); } } Ok(r) } pub async fn download_step(id: String) -> Result { let url = format!("https://modules.lceda.cn/qAxj6KHrDKw4blvCG8QJPs7Y/{id}"); let url = url.as_str(); let resp = reqwest::get(url).await?; let text = resp.text().await?; Ok(text) } pub async fn fetch_item(item: SearchResultItem) -> Result { let h = search_has_device(&item.has_device).await?; let mut has_device = String::new(); let v: serde_json::Value = serde_json::from_str(h.as_str())?; let id = v["result"][0]["attributes"]["3D Model"].clone(); if let serde_json::Value::String(id) = id { has_device = id.clone(); } let mut title = String::new(); let mut footprint = String::new(); let mut datasheet = String::new(); if let serde_json::Value::String(t) = v["result"][0]["title"].clone(){ title = t; } if let serde_json::Value::String(t) = v["result"][0]["attributes"]["Supplier Footprint"].clone(){ footprint = t; } if let serde_json::Value::String(t) = v["result"][0]["attributes"]["Datasheet"].clone(){ datasheet = t; } let mut step_id = String::new(); let resp = search_model_id(has_device.as_str()).await?; let mut model = String::new(); let v: serde_json::Value = serde_json::from_str(resp.as_str())?; info!("In search_model_id: The v is : {v:#?}"); let data_str: serde_json::Value = v["result"][0]["dataStr"].clone(); if let serde_json::Value::String(data_str) = data_str { let data_str: DataStr = serde_json::from_str(data_str.as_str())?; if let Some(m) = data_str.model { step_id = m; }else{ return Err(anyhow::Error::msg("Failed to get model")); } } let mut imgs = Vec::new(); for img_url in item.img_urls { info!("Fetching img url: {}", img_url); let img = reqwest::get(img_url).await?.bytes().await?; // let img = image::load_from_memory(&img)?; let img = iced::widget::image::Handle::from_bytes(img.clone()); imgs.push(img); } let rst = FetchResultItem { name: item.name.clone(), model_id: step_id, model:footprint, code:item.code, imgs, datasheet, }; Ok(rst) } async fn search_has_device(has_device: &str) -> Result { let mut form_maps = std::collections::HashMap::new(); form_maps.insert("uuids[]", has_device); let url = "https://pro.lceda.cn/api/devices/searchByIds"; let resp = reqwest::Client::new() .post(url) .form(&form_maps) .send() .await?; let text = resp.text().await?; Ok(text) } async fn search_model_id(uuid: &str) -> Result { let mut form_maps = std::collections::HashMap::new(); form_maps.insert("uuids[]", uuid); form_maps.insert("dataStr", "yes"); let url = "https://pro.lceda.cn/api/components/searchByIds?forceOnline=1"; let resp = reqwest::Client::new() .post(url) .form(&form_maps) .send() .await?; let text = resp.text().await?; info!("In search_model_id: The v is : {}",text.clone()); return Ok(text) } #[derive(Clone, Default, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)] struct KeywordSearchRoot { code: u32, success: bool, result: KeywordSearchResult, } #[allow(non_snake_case)] #[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq)] struct KeywordSearchResult { total: u32, productList: Vec, } #[allow(non_snake_case)] #[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq)] struct KeywordSearchListItem { id: u32, code: String, image: Option, model: String, hasDevice: Option, } #[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq)] struct KeywordChipImages(String); #[allow(dead_code)] impl KeywordChipImages { pub fn imgs(&self) -> Vec { let urls = self.0.clone(); let list = urls.split("<$>"); let mut rst = Vec::new(); for i in list { rst.push(i.to_string()); } rst } } #[derive(Debug, serde::Serialize, serde::Deserialize)] struct KeywordDevInfo { uuid: String, description: String, title: String, images: Vec, attributes: KeywordAttributes, } #[allow(non_snake_case)] #[derive(Debug, serde::Serialize, serde::Deserialize)] struct KeywordAttributes { Datasheet: Option, } #[derive(Debug, serde::Serialize, serde::Deserialize)] struct DataStr { model: Option, src: Option, _type: Option, }