From b2f458f3b83d4be74e755f080e8eee51b32fce20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=9A=E5=AD=90?= <40852301+uiYzzi@users.noreply.github.com> Date: Wed, 22 Jan 2025 20:10:03 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E9=A6=96=E9=A1=B5=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E5=88=97=E8=A1=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/handlers/home.rs | 58 ++++++++++++++++++- src-tauri/src/lib.rs | 2 + src-tauri/src/models/home.rs | 23 ++++++++ src/components/AppCard/index.tsx | 2 +- src/components/HomeCarousel/index.tsx | 2 + src/components/HomeListApps/index.tsx | 63 ++++++++++++++++++++ src/components/ui/base-carousel.tsx | 3 +- src/features/home/Home.tsx | 31 ++++++++-- src/features/home/store.ts | 83 ++++++++++----------------- src/lib/api/home.ts | 24 +++++++- src/types/home.ts | 14 +++++ 11 files changed, 241 insertions(+), 64 deletions(-) create mode 100644 src/components/HomeListApps/index.tsx diff --git a/src-tauri/src/handlers/home.rs b/src-tauri/src/handlers/home.rs index 57ac4e5..564cc93 100644 --- a/src-tauri/src/handlers/home.rs +++ b/src-tauri/src/handlers/home.rs @@ -1,13 +1,13 @@ use crate::handlers::server::get_img_server_url; -use crate::models::home::HomeLink; -use crate::utils::UA; +use crate::models::home::{HomeLink, HomeList, HomeListApp}; +use crate::utils::{format_icon_url, UA}; use super::server::get_json_server_url; #[tauri::command] pub async fn get_home_links() -> Result, String> { let json_server_url = get_json_server_url(); let img_server_url = get_img_server_url(); - let url = format!("{}home/homelinks.json", json_server_url); + let url = format!("{}/home/homelinks.json", json_server_url); let client = reqwest::Client::new(); let response = client @@ -33,4 +33,56 @@ pub async fn get_home_links() -> Result, String> { } Ok(links) +} + +#[tauri::command] +pub async fn get_home_list_apps(json_url: String) -> Result, String> { + let json_server_url = get_json_server_url(); + let url = format!("{}{}", json_server_url, json_url); + + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("User-Agent", UA) + .send() + .await + .map_err(|e| e.to_string())?; + + let response_text = response + .text() + .await + .map_err(|e| e.to_string())?; + + let mut apps: Vec = serde_json::from_str(&response_text) + .map_err(|e| e.to_string())?; + + for app in &mut apps { + app.icon = Some(format_icon_url(&app.category, &app.pkgname)); + } + + Ok(apps) +} + +#[tauri::command] +pub async fn get_home_lists() -> Result, String> { + let json_server_url = get_json_server_url(); + let url = format!("{}/home/homelist.json", json_server_url); + + let client = reqwest::Client::new(); + let response = client + .get(&url) + .header("User-Agent", UA) + .send() + .await + .map_err(|e| e.to_string())?; + + let response_text = response + .text() + .await + .map_err(|e| e.to_string())?; + + let lists: Vec = serde_json::from_str(&response_text) + .map_err(|e| e.to_string())?; + + Ok(lists) } \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5fe8338..70d466f 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -17,6 +17,8 @@ pub fn run() { handlers::app::get_app_info, handlers::app::search_all_apps, handlers::home::get_home_links, + handlers::home::get_home_lists, + handlers::home::get_home_list_apps, utils::get_user_agent, ]) .run(tauri::generate_context!()) diff --git a/src-tauri/src/models/home.rs b/src-tauri/src/models/home.rs index b25c409..37085dc 100644 --- a/src-tauri/src/models/home.rs +++ b/src-tauri/src/models/home.rs @@ -1,5 +1,19 @@ use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct HomeListApp { + #[serde(rename = "Name")] + pub name: String, + #[serde(rename = "Pkgname")] + pub pkgname: String, + #[serde(rename = "Category")] + pub category: String, + #[serde(rename = "More")] + pub more: String, + #[serde(rename = "Icon")] + pub icon: Option, +} + #[derive(Serialize, Deserialize, Clone)] pub struct HomeLink { pub name: String, @@ -9,4 +23,13 @@ pub struct HomeLink { #[serde(rename = "type")] pub link_type: String, pub url: String, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct HomeList { + pub name: String, + #[serde(rename = "type")] + pub list_type: String, + #[serde(rename = "jsonUrl")] + pub json_url: String, } \ No newline at end of file diff --git a/src/components/AppCard/index.tsx b/src/components/AppCard/index.tsx index db8c0d1..8cfd144 100644 --- a/src/components/AppCard/index.tsx +++ b/src/components/AppCard/index.tsx @@ -15,7 +15,7 @@ const AppCard: Component = (props) => { href={`/app/${props.category}/${props.pkgname}`} class="block p-4 rounded-lg border border-border bg-card hover:border-primary/50 transition-colors" > -
+
{props.icon ? ( {props.name} diff --git a/src/components/HomeCarousel/index.tsx b/src/components/HomeCarousel/index.tsx index 353f68c..17b7128 100644 --- a/src/components/HomeCarousel/index.tsx +++ b/src/components/HomeCarousel/index.tsx @@ -6,6 +6,7 @@ import { HomeLink } from '@/types/home'; interface HomeCarouselProps { slides?: HomeLink[]; loading?: boolean; + class?: string; } const HomeCarousel: Component = (props) => { @@ -42,6 +43,7 @@ const HomeCarousel: Component = (props) => { return ( = (props) => { + return ( +
+
+ {props.loading ? ( + + ) : ( +

{props.title}

+ )} +
+
+ {props.loading ? ( + + {() => ( +
+
+
+ +
+
+
+ +
+
+ + +
+
+
+
+ )} +
+ ) : ( + + {(app) => ( + + )} + + )} +
+
+ ); +}; + +export default HomeListApps; \ No newline at end of file diff --git a/src/components/ui/base-carousel.tsx b/src/components/ui/base-carousel.tsx index e8f8416..367ec26 100644 --- a/src/components/ui/base-carousel.tsx +++ b/src/components/ui/base-carousel.tsx @@ -14,11 +14,12 @@ interface BaseCarouselProps { renderItem: (item: any) => JSX.Element; renderSkeleton: () => JSX.Element; items?: any[]; + class?: string; } const BaseCarousel: Component = (props) => { return ( -
+
{ - const { apps, loading, slides } = useHomeStore(); + const { lists, loading, slides } = useHomeStore(); return (
- -

欢迎使用 Spark Store

- + + {loading() ? ( + + {() => ( + + )} + + ) : ( + + {(list) => ( + + )} + + )}
); }; diff --git a/src/features/home/store.ts b/src/features/home/store.ts index 3d7d082..e966e1c 100644 --- a/src/features/home/store.ts +++ b/src/features/home/store.ts @@ -1,54 +1,33 @@ -import { AppItem } from '@/types/app'; import { HomeLink } from '@/types/home'; import { createResource } from 'solid-js'; -import { getHomeLinks } from '@/lib/api/home'; +import { getHomeLinks, getHomeLists, getListApps } from '@/lib/api/home'; -const fetchApps = async (): Promise => { - // 模拟从后端获取数据的延迟 - await new Promise(resolve => setTimeout(resolve, 1000)); - - return [ - { - pkgname: '1', - name: 'Visual Studio Code', - more: '轻量级但功能强大的代码编辑器', - category: 'development', - icon: '/icons/vscode.png', - update: '' - }, - { - pkgname: '2', - name: 'Firefox', - more: '注重隐私的开源浏览器', - category: 'development', - icon: '/icons/firefox.png', - update: '' - }, - { - pkgname: '3', - name: 'GIMP', - more: '功能丰富的图像编辑软件', - category: 'development', - icon: '/icons/gimp.png', - update: '' - }, - { - pkgname: '4', - name: 'Notion', - more: '功能强大的笔记软件', - category: 'development', - icon: '/icons/notion.png', - update: '' - }, - { - pkgname: '5', - name: 'Slack', - more: '团队沟通和协作工具', - category: 'development', - icon: '/icons/slack.png', - update: '' - }, - ]; +const fetchLists = async () => { + try { + // 获取首页列表 + const homeLists = await getHomeLists(); + + // 如果没有列表数据,返回空数组 + if (!homeLists || homeLists.length === 0) { + return []; + } + + // 获取所有列表的应用数据 + const listsWithApps = await Promise.all( + homeLists.map(async (list) => { + const apps = await getListApps(list.jsonUrl); + return { + title: list.name, + apps + }; + }) + ); + + return listsWithApps; + } catch (error) { + console.error('获取应用列表失败:', error); + return []; + } }; const getCarouselSlides = async (): Promise => { @@ -56,16 +35,16 @@ const getCarouselSlides = async (): Promise => { }; export const useHomeStore = () => { - const [apps, { refetch: refetchApps }] = createResource(fetchApps); + const [lists, { refetch: refetchLists }] = createResource(fetchLists); const [slides, { refetch: refetchSlides }] = createResource(getCarouselSlides); - const loading = () => apps.loading || slides.loading; + const loading = () => lists.loading || slides.loading; return { - apps, + lists, slides, loading, refetch: () => { - refetchApps(); + refetchLists(); refetchSlides(); } }; diff --git a/src/lib/api/home.ts b/src/lib/api/home.ts index ffe770a..5c3ed44 100644 --- a/src/lib/api/home.ts +++ b/src/lib/api/home.ts @@ -1,6 +1,6 @@ import { invoke } from "@tauri-apps/api/core"; import { retryOperation } from "../utils"; -import { HomeLink, HomeLinkResponse } from "@/types/home"; +import { HomeLink, HomeLinkResponse, HomeList, HomeListApp } from "@/types/home"; export const getHomeLinks = async (): Promise => { try { @@ -18,4 +18,26 @@ export const getHomeLinks = async (): Promise => { console.error("获取主页链接列表失败:", error); throw new Error("获取主页链接列表失败"); } +}; + +export const getHomeLists = async (): Promise => { + try { + return await retryOperation(async () => { + return await invoke("get_home_lists"); + }); + } catch (error) { + console.error("获取首页列表失败:", error); + throw new Error("获取首页列表失败"); + } +}; + +export const getListApps = async (jsonUrl: string): Promise => { + try { + return await retryOperation(async () => { + return await invoke("get_home_list_apps", { jsonUrl }); + }); + } catch (error) { + console.error("获取列表应用数据失败:", error); + throw new Error("获取列表应用数据失败"); + } }; \ No newline at end of file diff --git a/src/types/home.ts b/src/types/home.ts index deb4a1c..ffc28df 100644 --- a/src/types/home.ts +++ b/src/types/home.ts @@ -13,3 +13,17 @@ export interface HomeLinkResponse { type: string; url: string; } + +export interface HomeList { + name: string; + more: string; + jsonUrl: string; +} + +export interface HomeListApp { + Name: string; + Pkgname: string; + Category: string; + More: string; + Icon: string; +}