mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-07 18:26:37 +08:00
fix: stabilize federation forward runtime cleanup and wire frontend version update UX
This commit is contained in:
@@ -33,6 +33,11 @@ import {
|
||||
clearConfigCache,
|
||||
updateSiteConfig,
|
||||
} from "@/config/site";
|
||||
import {
|
||||
type UpdateReleaseChannel,
|
||||
getUpdateReleaseChannel,
|
||||
setUpdateReleaseChannel,
|
||||
} from "@/utils/version-update";
|
||||
|
||||
// 简单的保存图标组件
|
||||
const SaveIcon = ({ className }: { className?: string }) => (
|
||||
@@ -182,6 +187,9 @@ export default function ConfigPage() {
|
||||
});
|
||||
const [announcementLoading, setAnnouncementLoading] = useState(true);
|
||||
const [announcementSaving, setAnnouncementSaving] = useState(false);
|
||||
const [updateChannel, setUpdateChannel] = useState<UpdateReleaseChannel>(
|
||||
getUpdateReleaseChannel(),
|
||||
);
|
||||
|
||||
// 权限检查
|
||||
useEffect(() => {
|
||||
@@ -267,6 +275,14 @@ export default function ConfigPage() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateChannelChange = (channel: UpdateReleaseChannel) => {
|
||||
setUpdateChannel(channel);
|
||||
setUpdateReleaseChannel(channel);
|
||||
toast.success(
|
||||
`更新通道已切换为${channel === "stable" ? "稳定版" : "开发版"}`,
|
||||
);
|
||||
};
|
||||
|
||||
const handleConfigChange = (key: string, value: string) => {
|
||||
const newConfigs = { ...configs, [key]: value };
|
||||
|
||||
@@ -643,6 +659,42 @@ export default function ConfigPage() {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
<Divider className="my-2" />
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
更新通道
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
稳定版仅匹配纯数字版本;开发版仅匹配包含 alpha / beta / rc
|
||||
的版本。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
selectedKeys={[updateChannel]}
|
||||
size="md"
|
||||
variant="bordered"
|
||||
onSelectionChange={(keys) => {
|
||||
const selected =
|
||||
(Array.from(keys)[0] as UpdateReleaseChannel) || "stable";
|
||||
|
||||
handleUpdateChannelChange(selected);
|
||||
}}
|
||||
>
|
||||
<SelectItem key="stable" description="仅纯数字版本,如 2.1.4">
|
||||
稳定版
|
||||
</SelectItem>
|
||||
<SelectItem
|
||||
key="dev"
|
||||
description="仅 alpha / beta / rc 关键字版本"
|
||||
>
|
||||
开发版
|
||||
</SelectItem>
|
||||
</Select>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
|
||||
@@ -3199,7 +3199,7 @@ export default function ForwardPage() {
|
||||
<ModalBody>
|
||||
<div className="flex flex-col gap-4 py-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-sm font-medium">按用户筛选</label>
|
||||
<p className="text-sm font-medium">按用户筛选</p>
|
||||
<Select
|
||||
aria-label="筛选用户"
|
||||
className="w-full"
|
||||
@@ -3220,7 +3220,7 @@ export default function ForwardPage() {
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-sm font-medium">按隧道筛选</label>
|
||||
<p className="text-sm font-medium">按隧道筛选</p>
|
||||
<Select
|
||||
aria-label="筛选隧道"
|
||||
className="w-full"
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Input } from "@/shadcn-bridge/heroui/input";
|
||||
import { Button } from "@/shadcn-bridge/heroui/button";
|
||||
import { siteConfig } from "@/config/site";
|
||||
import { title } from "@/components/primitives";
|
||||
import { VersionFooter } from "@/components/version-footer";
|
||||
import DefaultLayout from "@/layouts/default";
|
||||
import { login, LoginData, checkCaptcha, getConfigByName } from "@/api";
|
||||
import { writeLoginSession } from "@/utils/session";
|
||||
@@ -213,22 +214,13 @@ export default function IndexPage() {
|
||||
|
||||
{/* 版权信息 - 固定在底部,不占据布局空间 */}
|
||||
|
||||
<div className="fixed inset-x-0 bottom-4 text-center py-4">
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500">
|
||||
Powered by{" "}
|
||||
<a
|
||||
className="text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
href={siteConfig.github_repo}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
FLVX
|
||||
</a>
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
v{isWebView ? siteConfig.app_version : siteConfig.version}
|
||||
</p>
|
||||
</div>
|
||||
<VersionFooter
|
||||
containerClassName="fixed inset-x-0 bottom-4 text-center py-4"
|
||||
poweredClassName="text-xs text-gray-400 dark:text-gray-500"
|
||||
updateBadgeClassName="ml-2 inline-flex items-center rounded-full bg-rose-500/90 px-2 py-0.5 text-[10px] font-semibold tracking-wide text-white"
|
||||
version={isWebView ? siteConfig.app_version : siteConfig.version}
|
||||
versionClassName="text-xs text-gray-400 dark:text-gray-500 mt-1"
|
||||
/>
|
||||
|
||||
{/* 验证码弹层 */}
|
||||
{showCaptcha && siteKey && (
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { Input } from "@/shadcn-bridge/heroui/input";
|
||||
import { isWebViewFunc } from "@/utils/panel";
|
||||
import { siteConfig } from "@/config/site";
|
||||
import { VersionFooter } from "@/components/version-footer";
|
||||
import { updatePassword } from "@/api";
|
||||
import { safeLogout } from "@/utils/logout";
|
||||
import { getAdminFlag, getSessionName } from "@/utils/session";
|
||||
@@ -312,22 +313,15 @@ export default function ProfilePage() {
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
<div className="fixed inset-x-0 bottom-20 text-center py-4">
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500">
|
||||
Powered by{" "}
|
||||
<a
|
||||
className="text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
|
||||
href={siteConfig.github_repo}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
FLVX
|
||||
</a>
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mt-1">
|
||||
v{isWebViewFunc() ? siteConfig.app_version : siteConfig.version}
|
||||
</p>
|
||||
</div>
|
||||
<VersionFooter
|
||||
containerClassName="fixed inset-x-0 bottom-20 text-center py-4"
|
||||
poweredClassName="text-xs text-gray-400 dark:text-gray-500"
|
||||
updateBadgeClassName="ml-2 inline-flex items-center rounded-full bg-rose-500/90 px-2 py-0.5 text-[10px] font-semibold tracking-wide text-white"
|
||||
version={
|
||||
isWebViewFunc() ? siteConfig.app_version : siteConfig.version
|
||||
}
|
||||
versionClassName="text-xs text-gray-400 dark:text-gray-500 mt-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 修改密码弹窗 */}
|
||||
|
||||
@@ -5,7 +5,13 @@ import toast from "react-hot-toast";
|
||||
import { Input } from "@/shadcn-bridge/heroui/input";
|
||||
import { Button } from "@/shadcn-bridge/heroui/button";
|
||||
import { Card, CardBody } from "@/shadcn-bridge/heroui/card";
|
||||
import { Select, SelectItem } from "@/shadcn-bridge/heroui/select";
|
||||
import { reinitializeBaseURL } from "@/api/network";
|
||||
import {
|
||||
type UpdateReleaseChannel,
|
||||
getUpdateReleaseChannel,
|
||||
setUpdateReleaseChannel,
|
||||
} from "@/utils/version-update";
|
||||
import {
|
||||
getPanelAddresses,
|
||||
savePanelAddress,
|
||||
@@ -25,6 +31,9 @@ export const SettingsPage = () => {
|
||||
const [panelAddresses, setPanelAddresses] = useState<PanelAddress[]>([]);
|
||||
const [newName, setNewName] = useState("");
|
||||
const [newAddress, setNewAddress] = useState("");
|
||||
const [updateChannel, setUpdateChannel] = useState<UpdateReleaseChannel>(
|
||||
getUpdateReleaseChannel(),
|
||||
);
|
||||
|
||||
const setPanelAddressesFunc = (newAddress: PanelAddress[]) => {
|
||||
setPanelAddresses(newAddress);
|
||||
@@ -79,6 +88,14 @@ export const SettingsPage = () => {
|
||||
loadPanelAddresses();
|
||||
}, []);
|
||||
|
||||
const handleUpdateChannelChange = (channel: UpdateReleaseChannel) => {
|
||||
setUpdateChannel(channel);
|
||||
setUpdateReleaseChannel(channel);
|
||||
toast.success(
|
||||
`更新通道已切换为${channel === "stable" ? "稳定版" : "开发版"}`,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-black">
|
||||
{/* 顶部导航 */}
|
||||
@@ -117,6 +134,36 @@ export const SettingsPage = () => {
|
||||
{/* 内容区域 */}
|
||||
<div className="max-w-4xl mx-auto px-4 py-6">
|
||||
<div className="space-y-6">
|
||||
<Card className="border border-gray-200 dark:border-gray-700">
|
||||
<CardBody className="p-6">
|
||||
<h2 className="text-lg font-medium text-gray-900 dark:text-white mb-4">
|
||||
更新设置
|
||||
</h2>
|
||||
<div className="space-y-2">
|
||||
<Select
|
||||
label="更新通道"
|
||||
selectedKeys={[updateChannel]}
|
||||
onSelectionChange={(keys) => {
|
||||
const selected =
|
||||
(Array.from(keys)[0] as UpdateReleaseChannel) || "stable";
|
||||
|
||||
handleUpdateChannelChange(selected);
|
||||
}}
|
||||
>
|
||||
<SelectItem key="stable" textValue="stable">
|
||||
稳定版(纯数字版本,如 2.1.4)
|
||||
</SelectItem>
|
||||
<SelectItem key="dev" textValue="dev">
|
||||
开发版(含 alpha / beta / rc)
|
||||
</SelectItem>
|
||||
</Select>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
版本提示会根据该通道检查最新版本。
|
||||
</p>
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
{/* 添加新地址 */}
|
||||
<Card className="border border-gray-200 dark:border-gray-700">
|
||||
<CardBody className="p-6">
|
||||
|
||||
@@ -638,7 +638,6 @@ export default function UserPage() {
|
||||
) : (
|
||||
<div className="flex w-full items-center gap-2 animate-appearance-in">
|
||||
<Input
|
||||
autoFocus
|
||||
classNames={{
|
||||
base: "bg-default-100",
|
||||
input: "bg-transparent",
|
||||
|
||||
Reference in New Issue
Block a user