From 3caab77bfdca912248cc6f5632039c344c08d45d Mon Sep 17 00:00:00 2001 From: pikachuim Date: Mon, 9 Mar 2026 14:49:58 +0800 Subject: [PATCH] feat(func): support virtual host --- src/lang/en/entry.ts | 2 + src/lang/en/manage.json | 1 + src/lang/en/virtual_hosts.json | 9 ++ src/pages/manage/routes.tsx | 8 ++ src/pages/manage/sidemenu_items.tsx | 7 + src/pages/manage/virtual_hosts/AddOrEdit.tsx | 127 ++++++++++++++++++ .../manage/virtual_hosts/VirtualHosts.tsx | 115 ++++++++++++++++ src/types/index.ts | 1 + src/types/virtual_host.ts | 7 + 9 files changed, 277 insertions(+) create mode 100644 src/lang/en/virtual_hosts.json create mode 100644 src/pages/manage/virtual_hosts/AddOrEdit.tsx create mode 100644 src/pages/manage/virtual_hosts/VirtualHosts.tsx create mode 100644 src/types/virtual_host.ts diff --git a/src/lang/en/entry.ts b/src/lang/en/entry.ts index c9ab661..238c699 100644 --- a/src/lang/en/entry.ts +++ b/src/lang/en/entry.ts @@ -13,6 +13,7 @@ import shares from "./shares.json" import storages from "./storages.json" import tasks from "./tasks.json" import users from "./users.json" +import virtual_hosts from "./virtual_hosts.json" export const dict = { br, @@ -30,4 +31,5 @@ export const dict = { storages, tasks, users, + virtual_hosts, } diff --git a/src/lang/en/manage.json b/src/lang/en/manage.json index 5829c6e..2269587 100644 --- a/src/lang/en/manage.json +++ b/src/lang/en/manage.json @@ -11,6 +11,7 @@ "storages": "Storages", "shares": "Shares", "metas": "Metas", + "virtual_hosts": "Virtual Hosts", "profile": "Profile", "about": "About", "tasks": "Tasks", diff --git a/src/lang/en/virtual_hosts.json b/src/lang/en/virtual_hosts.json new file mode 100644 index 0000000..7e04017 --- /dev/null +++ b/src/lang/en/virtual_hosts.json @@ -0,0 +1,9 @@ +{ + "domain": "Domain", + "domain_help": "The domain name to bind (e.g. blog.example.com)", + "path": "Path", + "path_help": "The OpenList path to map this domain to", + "enabled": "Enabled", + "web_hosting": "Web Hosting", + "web_hosting_help": "If enabled, HTML files will be served directly instead of the file browser" +} diff --git a/src/pages/manage/routes.tsx b/src/pages/manage/routes.tsx index 5fa444d..9da9377 100644 --- a/src/pages/manage/routes.tsx +++ b/src/pages/manage/routes.tsx @@ -39,6 +39,14 @@ const hide_routes: Route[] = [ to: "/metas/edit/:id", component: lazy(() => import("./metas/AddOrEdit")), }, + { + to: "/virtual_hosts/add", + component: lazy(() => import("./virtual_hosts/AddOrEdit")), + }, + { + to: "/virtual_hosts/edit/:id", + component: lazy(() => import("./virtual_hosts/AddOrEdit")), + }, { to: "/2fa", component: lazy(() => import("./users/2fa")), diff --git a/src/pages/manage/sidemenu_items.tsx b/src/pages/manage/sidemenu_items.tsx index 6776e38..360d1e0 100644 --- a/src/pages/manage/sidemenu_items.tsx +++ b/src/pages/manage/sidemenu_items.tsx @@ -14,6 +14,7 @@ import { BsBucket, BsHddNetwork, BsArrowLeftRight, + BsGlobe, } from "solid-icons/bs" import { FiLogIn } from "solid-icons/fi" import { SiMetabase } from "solid-icons/si" @@ -187,6 +188,12 @@ export const side_menu_items: SideMenuItem[] = [ to: "/@manage/metas", component: lazy(() => import("./metas/Metas")), }, + { + title: "manage.sidemenu.virtual_hosts", + icon: BsGlobe, + to: "/@manage/virtual_hosts", + component: lazy(() => import("./virtual_hosts/VirtualHosts")), + }, { title: "manage.sidemenu.indexes", icon: BsSearch, diff --git a/src/pages/manage/virtual_hosts/AddOrEdit.tsx b/src/pages/manage/virtual_hosts/AddOrEdit.tsx new file mode 100644 index 0000000..ad8d264 --- /dev/null +++ b/src/pages/manage/virtual_hosts/AddOrEdit.tsx @@ -0,0 +1,127 @@ +import { + Button, + Switch as HopeSwitch, + FormControl, + FormHelperText, + FormLabel, + Heading, + Input, + VStack, +} from "@hope-ui/solid" +import { MaybeLoading, FolderChooseInput } from "~/components" +import { useFetch, useRouter, useT } from "~/hooks" +import { handleResp, notify, r } from "~/utils" +import { VirtualHost, PEmptyResp, PResp } from "~/types" +import { createStore } from "solid-js/store" + +const AddOrEdit = () => { + const t = useT() + const { params, back } = useRouter() + const { id } = params + const [vhost, setVhost] = createStore({ + id: 0, + enabled: true, + domain: "", + path: "", + web_hosting: false, + }) + const [vhostLoading, loadVhost] = useFetch( + (): PResp => r.get(`/admin/vhost/get?id=${id}`), + ) + + const initEdit = async () => { + const resp = await loadVhost() + handleResp(resp, setVhost) + } + if (id) { + initEdit() + } + const [okLoading, ok] = useFetch((): PEmptyResp => { + return r.post(`/admin/vhost/${id ? "update" : "create"}`, vhost) + }) + return ( + + + {t(`global.${id ? "edit" : "add"}`)} + + {/* 启用开关 */} + + + {t("virtual_hosts.enabled")} + + setVhost("enabled", e.currentTarget.checked)} + /> + + + {/* 域名 */} + + {t("virtual_hosts.domain")} + setVhost("domain", e.currentTarget.value)} + /> + {t("virtual_hosts.domain_help")} + + + {/* 路径 */} + + {t("virtual_hosts.path")} + setVhost("path", path)} + /> + {t("virtual_hosts.path_help")} + + + {/* Web 托管开关 */} + + + + {t("virtual_hosts.web_hosting")} + + + setVhost("web_hosting", e.currentTarget.checked) + } + /> + + {t("virtual_hosts.web_hosting_help")} + + + + + + ) +} + +export default AddOrEdit diff --git a/src/pages/manage/virtual_hosts/VirtualHosts.tsx b/src/pages/manage/virtual_hosts/VirtualHosts.tsx new file mode 100644 index 0000000..80dc390 --- /dev/null +++ b/src/pages/manage/virtual_hosts/VirtualHosts.tsx @@ -0,0 +1,115 @@ +import { + Box, + Button, + HStack, + Table, + Tbody, + Td, + Th, + Thead, + Tr, + VStack, +} from "@hope-ui/solid" +import { createSignal, For } from "solid-js" +import { + useFetch, + useListFetch, + useManageTitle, + useRouter, + useT, +} from "~/hooks" +import { handleResp, notify, r } from "~/utils" +import { VirtualHost, PEmptyResp, PPageResp } from "~/types" +import { DeletePopover } from "../common/DeletePopover" +import { Wether } from "~/components" + +const VirtualHosts = () => { + const t = useT() + useManageTitle("manage.sidemenu.virtual_hosts") + const { to } = useRouter() + const [getVhostsLoading, getVhosts] = useFetch( + (): PPageResp => r.get("/admin/vhost/list"), + ) + const [vhosts, setVhosts] = createSignal([]) + const refresh = async () => { + const resp = await getVhosts() + handleResp(resp, (data) => setVhosts(data.content)) + } + refresh() + + const [deleting, deleteVhost] = useListFetch( + (id: number): PEmptyResp => r.post(`/admin/vhost/delete?id=${id}`), + ) + return ( + + + + + + + + + + + {(title) => } + + + + + + + {(vhost) => ( + + + + + + + + )} + + +
{t(`virtual_hosts.${title}`)}{t("global.operations")}
{vhost.domain}{vhost.path} + + + + + + + { + const resp = await deleteVhost(vhost.id) + handleResp(resp, () => { + notify.success(t("global.delete_success")) + refresh() + }) + }} + /> + +
+
+
+ ) +} + +export default VirtualHosts diff --git a/src/types/index.ts b/src/types/index.ts index 52f45e9..8241449 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -8,3 +8,4 @@ export * from "./item_type" export * from "./meta" export * from "./task" export * from "./share" +export * from "./virtual_host" diff --git a/src/types/virtual_host.ts b/src/types/virtual_host.ts new file mode 100644 index 0000000..5114e56 --- /dev/null +++ b/src/types/virtual_host.ts @@ -0,0 +1,7 @@ +export interface VirtualHost { + id: number + enabled: boolean + domain: string + path: string + web_hosting: boolean +}