mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-29 07:56:37 +08:00
重构前端ui
This commit is contained in:
@@ -145,6 +145,30 @@ generate_random() {
|
||||
LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c16
|
||||
}
|
||||
|
||||
# UI选择函数
|
||||
select_ui() {
|
||||
echo "🎨 请选择前端UI:"
|
||||
echo "1. 新UI"
|
||||
echo "2. 旧UI"
|
||||
read -p "请输入选项 (1-2,默认2): " ui_choice
|
||||
case $ui_choice in
|
||||
1)
|
||||
USE_NEW_UI=true
|
||||
;;
|
||||
*)
|
||||
USE_NEW_UI=false
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 配置前端镜像
|
||||
configure_frontend_image() {
|
||||
if [[ "$USE_NEW_UI" == "true" ]]; then
|
||||
sed -i.bak 's|bqlpfy/vue-frontend|bqlpfy/vite-frontend|g' docker-compose.yml
|
||||
rm -f docker-compose.yml.bak
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取用户输入的配置参数
|
||||
get_config_params() {
|
||||
echo "🔧 请输入配置参数:"
|
||||
@@ -185,6 +209,12 @@ install_panel() {
|
||||
curl -L -o gost.sql "$GOST_SQL_URL"
|
||||
echo "✅ 下载完成"
|
||||
|
||||
# UI选择
|
||||
select_ui
|
||||
|
||||
# 根据UI选择修改docker-compose.yml中的前端镜像
|
||||
configure_frontend_image
|
||||
|
||||
# 自动检测并配置 IPv6 支持
|
||||
if check_ipv6_support; then
|
||||
echo "🚀 系统支持 IPv6,自动启用 IPv6 配置..."
|
||||
@@ -228,6 +258,12 @@ update_panel() {
|
||||
curl -L -o docker-compose.yml "$DOCKER_COMPOSE_URL"
|
||||
echo "✅ 下载完成"
|
||||
|
||||
# UI选择
|
||||
select_ui
|
||||
|
||||
# 根据UI选择修改docker-compose.yml中的前端镜像
|
||||
configure_frontend_image
|
||||
|
||||
# 自动检测并配置 IPv6 支持
|
||||
if check_ipv6_support; then
|
||||
echo "🚀 系统支持 IPv6,自动启用 IPv6 配置..."
|
||||
|
||||
@@ -9,7 +9,7 @@ import TunnelPage from "@/pages/tunnel";
|
||||
import NodePage from "@/pages/node";
|
||||
import UserPage from "@/pages/user";
|
||||
import LimitPage from "@/pages/limit";
|
||||
import PageWrapper from "@/components/page-wrapper";
|
||||
|
||||
import { isLoggedIn } from "@/utils/auth";
|
||||
|
||||
// 路由保护组件 - 使用useNavigate避免循环渲染
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useNavigate, useLocation, Link } from 'react-router-dom';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import { Button } from "@heroui/button";
|
||||
import { Dropdown, DropdownTrigger, DropdownMenu, DropdownItem } from "@heroui/dropdown";
|
||||
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure } from "@heroui/modal";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ export default function DashboardPage() {
|
||||
const ips = ipString.split(',').map(ip => ip.trim()).filter(ip => ip);
|
||||
|
||||
if (ips.length <= 1) {
|
||||
copyToClipboard(formatInAddress(ipString, port), title);
|
||||
copyToClipboard(formatInAddress(ipString, port));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ export default function DashboardPage() {
|
||||
const addresses = remoteAddr.split(',').map(addr => addr.trim()).filter(addr => addr);
|
||||
|
||||
if (addresses.length <= 1) {
|
||||
copyToClipboard(remoteAddr, title);
|
||||
copyToClipboard(remoteAddr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ export default function DashboardPage() {
|
||||
setAddressModalOpen(true);
|
||||
};
|
||||
|
||||
const copyToClipboard = async (text: string, label: string = '内容') => {
|
||||
const copyToClipboard = async (text: string) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
toast.success(`已复制`);
|
||||
@@ -503,7 +503,7 @@ export default function DashboardPage() {
|
||||
setAddressList(prev => prev.map(item =>
|
||||
item.id === addressItem.id ? { ...item, copying: true } : item
|
||||
));
|
||||
await copyToClipboard(addressItem.address, '地址');
|
||||
await copyToClipboard(addressItem.address);
|
||||
} catch (error) {
|
||||
toast.error('复制失败');
|
||||
} finally {
|
||||
@@ -516,7 +516,7 @@ export default function DashboardPage() {
|
||||
const copyAllAddresses = async () => {
|
||||
if (addressList.length === 0) return;
|
||||
const allAddresses = addressList.map(item => item.address).join('\n');
|
||||
await copyToClipboard(allAddresses, '所有地址');
|
||||
await copyToClipboard(allAddresses);
|
||||
};
|
||||
|
||||
const calculateForwardBillingFlow = (forward: Forward): number => {
|
||||
|
||||
@@ -266,16 +266,7 @@ export default function NodePage() {
|
||||
})));
|
||||
};
|
||||
|
||||
// 格式化字节数
|
||||
const formatBytes = (bytes: number): string => {
|
||||
if (bytes === 0) return '0 B';
|
||||
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
|
||||
// 格式化速度
|
||||
const formatSpeed = (bytesPerSecond: number): string => {
|
||||
|
||||
@@ -49,7 +49,7 @@ import {
|
||||
getSpeedLimitList
|
||||
} from '@/api';
|
||||
import { SearchIcon, PlusIcon, EditIcon, DeleteIcon, UserIcon, SettingsIcon } from '@/components/icons';
|
||||
import { CalendarDate, parseDate } from "@internationalized/date";
|
||||
import { parseDate } from "@internationalized/date";
|
||||
import AdminLayout from "@/layouts/admin";
|
||||
|
||||
// 工具函数
|
||||
|
||||
Reference in New Issue
Block a user