fix popup ui

This commit is contained in:
go0p
2026-08-06 15:11:35 +08:00
committed by go0p
parent 08c12c2959
commit c9660ae269
7 changed files with 495 additions and 127 deletions
+24
View File
@@ -350,3 +350,27 @@ body {
.ant-menu .ant-menu-item.ant-menu-item-selected.active-item::after { .ant-menu .ant-menu-item.ant-menu-item-selected.active-item::after {
color: white; color: white;
} }
.active-item {
background-color: #F28B44 !important;
color: white !important;
font-weight: 500;
transition: background-color 0.2s ease-in-out !important;
}
.active-item img {
filter: brightness(0) invert(1);
}
.active-item .anticon {
color: white !important;
}
.proxy-menu .ant-menu-item {
transition: all 0.2s ease-in-out !important;
}
/* 添加悬停效果 */
.proxy-menu .ant-menu-item:hover {
background-color: rgba(242, 139, 68, 0.1) !important;
}
+35 -32
View File
@@ -5,6 +5,7 @@ import {browser,} from 'wxt/browser';
import type {MenuProps} from 'antd'; import type {MenuProps} from 'antd';
import type {ProxyConfig} from '@/types/proxy'; import type {ProxyConfig} from '@/types/proxy';
import {ContentActionType, ProxyActionType} from '@/types/action'; import {ContentActionType, ProxyActionType} from '@/types/action';
import { getAllProxyConfigs, getCurrentProxy } from '@/utils/storage';
import './index.css'; import './index.css';
@@ -58,6 +59,7 @@ export const ProxySwitch: React.FC = () => {
const handleMessage = (message: any) => { const handleMessage = (message: any) => {
if (message.action === ContentActionType.PROXY_CONFIGS_UPDATED && message.source !== 'proxy_switch') { if (message.action === ContentActionType.PROXY_CONFIGS_UPDATED && message.source !== 'proxy_switch') {
loadCustomProxies(); loadCustomProxies();
loadProxyStatus();
} }
}; };
@@ -80,18 +82,23 @@ export const ProxySwitch: React.FC = () => {
// 获取当前代理状态 // 获取当前代理状态
const loadProxyStatus = async () => { const loadProxyStatus = async () => {
try { try {
// 先尝试从后台脚本获取当前代理状态
const response = await browser.runtime.sendMessage({ const response = await browser.runtime.sendMessage({
action: ProxyActionType.GET_PROXY_STATUS action: ProxyActionType.GET_PROXY_STATUS
}); });
if (!response) { if (response && response.success) {
console.log('No response from background script'); const activeMode = response.data.mode;
setCurrentMode(activeMode);
return; return;
} }
if (response.success) { // 如果后台脚本没有返回,则从存储中获取当前代理
const activeMode = response.data.mode; const currentProxy = await getCurrentProxy();
setCurrentMode(activeMode); if (currentProxy) {
setCurrentMode(currentProxy.id);
} else {
setCurrentMode('direct');
} }
} catch (error) { } catch (error) {
console.error('Error loading proxy status:', error); console.error('Error loading proxy status:', error);
@@ -102,33 +109,12 @@ export const ProxySwitch: React.FC = () => {
// 加载自定义代理配置 // 加载自定义代理配置
const loadCustomProxies = async () => { const loadCustomProxies = async () => {
try { try {
const DB_NAME = 'yaklang_extension'; // 使用存储API获取所有代理配置
const STORE_NAME = 'proxy_configs'; const configs = await getAllProxyConfigs();
// 打开数据库
const db = await new Promise<IDBDatabase>((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
});
// 从数据库读取代理配置
const configs = await new Promise<ProxyConfig[]>((resolve, reject) => {
try {
const transaction = db.transaction([STORE_NAME], 'readonly');
const store = transaction.objectStore(STORE_NAME);
const request = store.getAll();
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result || []);
} catch (error) {
reject(error);
}
});
// 处理代理配置 // 处理代理配置
const proxies = configs const proxies = configs
.filter((proxy: ProxyConfig) => !FIXED_MODES.some(mode => mode.key === proxy.id)) .filter((proxy: ProxyConfig) => !['direct', 'system'].includes(proxy.id))
.map((proxy: ProxyConfig): CustomProxy => ({ .map((proxy: ProxyConfig): CustomProxy => ({
key: proxy.id, key: proxy.id,
name: proxy.name, name: proxy.name,
@@ -138,6 +124,7 @@ export const ProxySwitch: React.FC = () => {
})); }));
setCustomProxies(proxies); setCustomProxies(proxies);
// 查找并设置已启用的代理
const enabledProxy = configs.find((proxy: ProxyConfig) => proxy.enabled); const enabledProxy = configs.find((proxy: ProxyConfig) => proxy.enabled);
if (enabledProxy) { if (enabledProxy) {
setCurrentMode(enabledProxy.id); setCurrentMode(enabledProxy.id);
@@ -182,6 +169,8 @@ export const ProxySwitch: React.FC = () => {
} }
try { try {
// 先更新UI状态,避免闪烁
setCurrentMode(mode);
setIsLoading(true); setIsLoading(true);
// 发送切换代理请求 // 发送切换代理请求
@@ -190,11 +179,17 @@ export const ProxySwitch: React.FC = () => {
mode mode
}); });
if (response && response.success) { if (!response || !response.success) {
setCurrentMode(mode); // 如果失败,恢复原状态
console.error('Failed to switch proxy mode');
await loadProxyStatus(); // 重新加载正确的状态
} else {
// 成功时刷新代理列表状态
await loadCustomProxies();
} }
} catch (error) { } catch (error) {
console.error(`Error switching to proxy mode ${mode}:`, error); console.error(`Error switching to proxy mode ${mode}:`, error);
await loadProxyStatus(); // 出错时重新加载正确的状态
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@@ -218,7 +213,15 @@ export const ProxySwitch: React.FC = () => {
...customProxies.map(proxy => ({ ...customProxies.map(proxy => ({
key: proxy.key, key: proxy.key,
label: proxy.name, label: proxy.name,
icon: <img src={YAK_ICON_URL} alt="YAK" style={{width: 24, height: 24}}/>, icon: <img
src={YAK_ICON_URL}
alt="YAK"
style={{
width: 20,
height: 20,
filter: currentMode === proxy.key ? 'brightness(0) invert(1)' : 'none'
}}
/>,
className: `${currentMode === proxy.key ? 'active-item' : ''} menu-id-${proxy.key}`, className: `${currentMode === proxy.key ? 'active-item' : ''} menu-id-${proxy.key}`,
})) }))
); );
+38 -1
View File
@@ -1,11 +1,32 @@
import { browser, type Browser } from 'wxt/browser'; import { browser, type Browser } from 'wxt/browser';
import {ContentActionType, ProxyActionType} from '@/types/action'; import {ContentActionType, ProxyActionType} from '@/types/action';
import { getCurrentProxyMode, switchProxyMode } from '@/utils/proxy'; import { getCurrentProxyMode, switchProxyMode } from '@/utils/proxy';
import { getProxyConfig, saveProxyConfig } from '@/utils/storage';
import type { ProxyConfig } from '@/types/proxy';
// 固定的代理模式配置
const FIXED_MODES = [
{
id: 'direct',
name: '[直接连接]',
proxyType: 'direct',
enabled: false
},
{
id: 'system',
name: '[系统代理]',
proxyType: 'system',
enabled: false
}
];
export default defineBackground({ export default defineBackground({
type: 'module', type: 'module',
main() { async main() {
// 初始化固定模式的代理配置
await initializeFixedModes();
// 初始化代理状态监听 // 初始化代理状态监听
browser.runtime.onMessage.addListener((message: any, sender: Browser.runtime.MessageSender, sendResponse: (response?: any) => void) => { browser.runtime.onMessage.addListener((message: any, sender: Browser.runtime.MessageSender, sendResponse: (response?: any) => void) => {
if (message.action === ProxyActionType.GET_PROXY_STATUS) { if (message.action === ProxyActionType.GET_PROXY_STATUS) {
@@ -34,3 +55,19 @@ export default defineBackground({
console.log('代理管理后台服务已启动'); console.log('代理管理后台服务已启动');
}, },
}); });
// 初始化固定模式的代理配置
async function initializeFixedModes() {
try {
// 确保固定模式的配置已保存到数据库
for (const modeConfig of FIXED_MODES) {
const existingConfig = await getProxyConfig(modeConfig.id);
if (!existingConfig) {
console.log(`初始化固定模式配置: ${modeConfig.id}`);
await saveProxyConfig(modeConfig as ProxyConfig);
}
}
} catch (error) {
console.error('初始化固定模式配置失败:', error);
}
}
+20
View File
@@ -60,6 +60,26 @@
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
} }
.add-proxy-card .ant-modal-footer {
display: flex;
justify-content: flex-end;
padding: 10px 24px;
border-top: 1px solid #f0f0f0;
}
.add-proxy-card .ant-modal-footer button {
margin-left: 8px;
}
.required-label::before {
content: '* ';
color: #ff4d4f;
}
.ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional)::before {
display: none !important;
}
.ant-space { .ant-space {
width: 100%; width: 100%;
} }
+147 -32
View File
@@ -47,20 +47,68 @@ export default function App() {
try { try {
setLoading(true); setLoading(true);
const newProxy: ProxyConfig = { const newProxy: Partial<ProxyConfig> = {
id: uuidv4(), id: uuidv4(),
name: values.name, name: values.name,
proxyType: "fixed_servers",
scheme: values.proxyType,
host: values.host,
port: Number(values.port),
enabled: false enabled: false
}; };
if (values.proxyType === 'fixed_servers') {
newProxy.proxyType = 'fixed_servers';
newProxy.scheme = values.scheme;
newProxy.host = values.host;
newProxy.port = Number(values.port);
// 处理不经过代理的地址
if (values.bypassList) {
newProxy.bypassList = values.bypassList
.split('\n')
.map((line: string) => line.trim())
.filter((line: string) => line.length > 0);
} else {
newProxy.bypassList = [];
}
} else if (values.proxyType === 'pac_script') {
newProxy.proxyType = 'pac_script';
newProxy.mode = 'pac_script';
// 处理PAC脚本匹配域名
if (values.matchList) {
newProxy.matchList = values.matchList
.split('\n')
.map((line: string) => line.trim())
.filter((line: string) => line.length > 0);
}
// 创建PAC脚本
newProxy.pacScript = {
data: `function FindProxyForURL(url, host) {
// 匹配域名列表
const domains = ${JSON.stringify(newProxy.matchList || [])};
// 检查是否匹配任何域名
for (let i = 0; i < domains.length; i++) {
const domain = domains[i];
// 支持通配符
if (domain.startsWith('*.') && host.endsWith(domain.substring(1))) {
return 'PROXY ${values.host}:${values.port}';
} else if (host === domain) {
return 'PROXY ${values.host}:${values.port}';
}
}
// 默认直接连接
return 'DIRECT';
}`,
mandatory: true
};
}
// 添加认证信息
if (values.username) newProxy.username = values.username; if (values.username) newProxy.username = values.username;
if (values.password) newProxy.password = values.password; if (values.password) newProxy.password = values.password;
await saveProxyConfig(newProxy); await saveProxyConfig(newProxy as ProxyConfig);
// 重新加载代理列表 // 重新加载代理列表
await loadProxies(); await loadProxies();
@@ -111,6 +159,12 @@ export default function App() {
// 重新加载代理列表 // 重新加载代理列表
await loadProxies(); await loadProxies();
// 通知后台脚本
browser.runtime.sendMessage({
action: ContentActionType.PROXY_CONFIGS_UPDATED,
source: 'options'
});
} catch (error) { } catch (error) {
console.error(`Error activating proxy ${id}:`, error); console.error(`Error activating proxy ${id}:`, error);
} }
@@ -179,9 +233,14 @@ export default function App() {
key={proxy.id} key={proxy.id}
actions={[ actions={[
<Button <Button
type="primary" type={proxy.enabled ? "default" : "primary"}
onClick={() => handleActivate(proxy.id)} onClick={() => handleActivate(proxy.id)}
disabled={proxy.enabled} disabled={proxy.enabled}
style={proxy.enabled ? {
backgroundColor: "#F28B44",
color: "white",
borderColor: "#F28B44"
} : undefined}
> >
{proxy.enabled ? '已启用' : '启用'} {proxy.enabled ? '已启用' : '启用'}
</Button>, </Button>,
@@ -207,7 +266,19 @@ export default function App() {
open={isModalOpen} open={isModalOpen}
className='add-proxy-card' className='add-proxy-card'
onCancel={handleCancel} onCancel={handleCancel}
footer={null} footer={[
<Button key="cancel" onClick={handleCancel}>
Cancel
</Button>,
<Button
key="submit"
type="primary"
onClick={() => form.submit()}
loading={loading}
>
OK
</Button>
]}
destroyOnClose destroyOnClose
> >
<Form <Form
@@ -217,17 +288,38 @@ export default function App() {
> >
<Form.Item <Form.Item
name="name" name="name"
label="代理名称" label={<span className="required-label">名称</span>}
rules={[{ required: true, message: '请输入代理名称' }]} rules={[{ required: true, message: '请输入代理名称' }]}
> >
<Input placeholder="例如: 公司内网代理" /> <Input placeholder="为此代理添加一个名称" />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="proxyType" name="proxyType"
label="代理类型" label={<span className="required-label">类型</span>}
initialValue="http" initialValue="fixed_servers"
rules={[{ required: true, message: '请选择代理类型' }]} rules={[{ required: true, message: '请选择代理类型' }]}
>
<Select>
<Option value="fixed_servers">代理服务器</Option>
<Option value="pac_script">PAC 脚本</Option>
</Select>
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, currentValues) => prevValues.proxyType !== currentValues.proxyType}
>
{({ getFieldValue }) => {
const proxyType = getFieldValue('proxyType');
if (proxyType === 'fixed_servers') {
return (
<>
<Form.Item
name="scheme"
label={<span className="required-label">协议</span>}
initialValue="http"
rules={[{ required: true, message: '请选择代理协议' }]}
> >
<Select> <Select>
<Option value="http">HTTP</Option> <Option value="http">HTTP</Option>
@@ -237,25 +329,60 @@ export default function App() {
</Select> </Select>
</Form.Item> </Form.Item>
<Space style={{ display: 'flex' }}>
<Form.Item <Form.Item
name="host" name="host"
label="主机地址" label={<span className="required-label">主机</span>}
rules={[{ required: true, message: '请输入主机地址' }]} rules={[{ required: true, message: '请输入主机地址' }]}
style={{ flex: 3 }}
> >
<Input placeholder="例如: proxy.example.com 或 192.168.1.100" /> <Input placeholder="127.0.0.1" />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="port" name="port"
label="端口" label={<span className="required-label">端口</span>}
rules={[{ required: true, message: '请输入端口' }]} rules={[{ required: true, message: '请输入端口' }]}
style={{ flex: 1 }}
> >
<Input placeholder="例如: 8080" /> <Input placeholder="8080" />
</Form.Item>
<Form.Item
name="bypassList"
label="不经过代理的地址"
>
<Input.TextArea
rows={4}
placeholder={`例如:
localhost
127.0.0.1
*.example.com`}
/>
<div style={{ marginTop: 8, fontSize: 12, color: '#999' }}>每行一个地址,支持通配符 *</div>
</Form.Item>
</>
);
} else if (proxyType === 'pac_script') {
return (
<>
<Form.Item
name="matchList"
label={<span className="required-label">匹配域名</span>}
rules={[{ required: true, message: '请输入至少一个匹配域名' }]}
>
<Input.TextArea
rows={4}
placeholder={`例如:
*.example.com
google.com
github.com`}
/>
<div style={{ marginTop: 8, fontSize: 12, color: '#999' }}>每行一个域名,支持通配符 *</div>
</Form.Item>
</>
);
}
return null;
}}
</Form.Item> </Form.Item>
</Space>
<Space style={{ display: 'flex' }}> <Space style={{ display: 'flex' }}>
<Form.Item <Form.Item
@@ -274,18 +401,6 @@ export default function App() {
<Input.Password placeholder="认证密码" /> <Input.Password placeholder="认证密码" />
</Form.Item> </Form.Item>
</Space> </Space>
<Form.Item>
<Button
type="primary"
htmlType="submit"
icon={<PlusOutlined />}
loading={loading}
block
>
添加代理
</Button>
</Form.Item>
</Form> </Form>
</Modal> </Modal>
</Content> </Content>
+28 -22
View File
@@ -1,6 +1,6 @@
import { browser } from 'wxt/browser'; import { browser } from 'wxt/browser';
import type { ProxyConfig } from '../types/proxy'; import type { ProxyConfig } from '../types/proxy';
import { getAllProxyConfigs, getProxyConfig, enableProxyConfig, disableAllProxies } from './storage'; import { getAllProxyConfigs, getProxyConfig, enableProxyConfig, disableAllProxies, getCurrentProxy, setCurrentProxy } from './storage';
/** /**
* 获取当前激活的代理模式 * 获取当前激活的代理模式
@@ -8,10 +8,19 @@ import { getAllProxyConfigs, getProxyConfig, enableProxyConfig, disableAllProxie
*/ */
export async function getCurrentProxyMode(): Promise<string> { export async function getCurrentProxyMode(): Promise<string> {
try { try {
// 首先尝试从当前代理存储中获取
const currentProxyConfig = await getCurrentProxy();
if (currentProxyConfig) {
return currentProxyConfig.id;
}
// 如果没有当前代理记录,则从配置列表查找已启用的代理
const configs = await getAllProxyConfigs(); const configs = await getAllProxyConfigs();
const enabledProxy = configs.find(config => config.enabled); const enabledProxy = configs.find(config => config.enabled);
if (enabledProxy) { if (enabledProxy) {
// 如果找到已启用的代理,更新当前代理存储
await setCurrentProxy(enabledProxy);
return enabledProxy.id; return enabledProxy.id;
} }
@@ -30,23 +39,6 @@ export async function getCurrentProxyMode(): Promise<string> {
*/ */
export async function switchProxyMode(mode: string): Promise<boolean> { export async function switchProxyMode(mode: string): Promise<boolean> {
try { try {
if (mode === 'direct') {
// 清除所有代理设置
await disableAllProxies();
await browser.proxy.settings.clear({});
return true;
}
if (mode === 'system') {
// 使用系统代理
await disableAllProxies();
await browser.proxy.settings.set({
value: { mode: 'system' },
scope: 'regular'
});
return true;
}
// 使用自定义代理 // 使用自定义代理
const config = await getProxyConfig(mode); const config = await getProxyConfig(mode);
if (!config) { if (!config) {
@@ -59,14 +51,16 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
// 设置代理 // 设置代理
if (config.proxyType === 'direct') { if (config.proxyType === 'direct') {
// 直接连接模式
await browser.proxy.settings.clear({}); await browser.proxy.settings.clear({});
} else if (config.proxyType === 'system') { } else if (config.proxyType === 'system') {
// 系统代理模式
await browser.proxy.settings.set({ await browser.proxy.settings.set({
value: { mode: 'system' }, value: { mode: 'system' },
scope: 'regular' scope: 'regular'
}); });
} else { } else if (config.proxyType === 'fixed_servers') {
// 构建代理配置 // 固定服务器代理
const proxyConfig = { const proxyConfig = {
mode: 'fixed_servers', mode: 'fixed_servers',
rules: {} rules: {}
@@ -74,7 +68,7 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
// 添加代理规则 // 添加代理规则
const proxyRule = { const proxyRule = {
scheme: config.proxyType, scheme: config.scheme,
host: config.host || '', host: config.host || '',
port: config.port || 80 port: config.port || 80
}; };
@@ -88,7 +82,7 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
// 设置代理规则 // 设置代理规则
proxyConfig.rules = { proxyConfig.rules = {
singleProxy: proxyRule, singleProxy: proxyRule,
bypassList: ['localhost', '127.0.0.1'] bypassList: config.bypassList || ['localhost', '127.0.0.1']
}; };
// 应用代理设置 // 应用代理设置
@@ -96,6 +90,18 @@ export async function switchProxyMode(mode: string): Promise<boolean> {
value: proxyConfig, value: proxyConfig,
scope: 'regular' scope: 'regular'
}); });
} else if (config.proxyType === 'pac_script') {
// PAC脚本代理
const pacConfig = {
mode: 'pac_script',
pacScript: config.pacScript
};
// 应用PAC脚本设置
await browser.proxy.settings.set({
value: pacConfig,
scope: 'regular'
});
} }
return true; return true;
+186 -23
View File
@@ -2,21 +2,35 @@ import type { ProxyConfig } from '../types/proxy';
// 数据库名称和存储名称 // 数据库名称和存储名称
const DB_NAME = 'yaklang_extension'; const DB_NAME = 'yaklang_extension';
const PROXY_STORE_NAME = 'proxy_configs'; const STORES = {
PROXY_CONFIGS: 'proxy_configs', // 代理配置列表存储
CURRENT_PROXY: 'current_proxy', // 当前代理配置存储
PROXY_AUTH: 'proxy_auth' // 代理认证信息存储
};
const DB_VERSION = 2; // 增加版本号以触发数据库升级
// 打开数据库 // 打开数据库
async function openDB(): Promise<IDBDatabase> { async function openDB(): Promise<IDBDatabase> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const request = indexedDB.open(DB_NAME, 1); const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = () => reject(request.error); request.onerror = () => reject(request.error);
request.onupgradeneeded = (event) => { request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result; const db = (event.target as IDBOpenDBRequest).result;
// 如果存储不存在,创建它 // 检查并创建各个存储对象
if (!db.objectStoreNames.contains(PROXY_STORE_NAME)) { if (!db.objectStoreNames.contains(STORES.PROXY_CONFIGS)) {
db.createObjectStore(PROXY_STORE_NAME, { keyPath: 'id' }); db.createObjectStore(STORES.PROXY_CONFIGS, { keyPath: 'id' });
}
if (!db.objectStoreNames.contains(STORES.CURRENT_PROXY)) {
db.createObjectStore(STORES.CURRENT_PROXY, { keyPath: 'id' });
}
if (!db.objectStoreNames.contains(STORES.PROXY_AUTH)) {
db.createObjectStore(STORES.PROXY_AUTH, { keyPath: 'id' });
} }
}; };
@@ -29,8 +43,8 @@ export async function getAllProxyConfigs(): Promise<ProxyConfig[]> {
try { try {
const db = await openDB(); const db = await openDB();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transaction = db.transaction([PROXY_STORE_NAME], 'readonly'); const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readonly');
const store = transaction.objectStore(PROXY_STORE_NAME); const store = transaction.objectStore(STORES.PROXY_CONFIGS);
const request = store.getAll(); const request = store.getAll();
request.onerror = () => reject(request.error); request.onerror = () => reject(request.error);
@@ -47,8 +61,8 @@ export async function getProxyConfig(id: string): Promise<ProxyConfig | null> {
try { try {
const db = await openDB(); const db = await openDB();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transaction = db.transaction([PROXY_STORE_NAME], 'readonly'); const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readonly');
const store = transaction.objectStore(PROXY_STORE_NAME); const store = transaction.objectStore(STORES.PROXY_CONFIGS);
const request = store.get(id); const request = store.get(id);
request.onerror = () => reject(request.error); request.onerror = () => reject(request.error);
@@ -65,12 +79,18 @@ export async function saveProxyConfig(config: ProxyConfig): Promise<boolean> {
try { try {
const db = await openDB(); const db = await openDB();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transaction = db.transaction([PROXY_STORE_NAME], 'readwrite'); const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
const store = transaction.objectStore(PROXY_STORE_NAME); const store = transaction.objectStore(STORES.PROXY_CONFIGS);
const request = store.put(config); const request = store.put(config);
request.onerror = () => reject(request.error); request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(true); request.onsuccess = () => {
// 如果代理被启用,更新当前代理
if (config.enabled) {
setCurrentProxy(config).catch(console.error);
}
resolve(true);
};
}); });
} catch (error) { } catch (error) {
console.error('Error saving proxy config:', error); console.error('Error saving proxy config:', error);
@@ -78,13 +98,70 @@ export async function saveProxyConfig(config: ProxyConfig): Promise<boolean> {
} }
} }
// 批量保存代理配置
export async function saveProxyConfigs(configs: ProxyConfig[]): Promise<boolean> {
try {
const db = await openDB();
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
// 获取所有现有配置
const existingConfigs = await getAllProxyConfigs();
// 保留固定模式配置(direct和system)
const fixedModeConfigs = existingConfigs.filter(config =>
config.id === 'direct' || config.id === 'system'
);
// 确保新保存的配置不会覆盖固定模式的enabled状态
const nonFixedConfigs = configs.filter(config =>
config.id !== 'direct' && config.id !== 'system'
);
// 合并配置
const allConfigs = [...fixedModeConfigs, ...nonFixedConfigs];
// 更新enabled状态
const updatedConfigs = allConfigs.map(config => ({
...config,
enabled: configs.some(c => c.id === config.id && c.enabled)
}));
// 清除所有配置
await new Promise<void>((resolve, reject) => {
const clearRequest = store.clear();
clearRequest.onerror = () => reject(clearRequest.error);
clearRequest.onsuccess = () => resolve();
});
// 保存所有配置
for (const config of updatedConfigs) {
await new Promise<void>((resolve, reject) => {
const putRequest = store.put(config);
putRequest.onerror = () => reject(putRequest.error);
putRequest.onsuccess = () => resolve();
});
// 如果代理被启用,更新当前代理
if (config.enabled) {
await setCurrentProxy(config);
}
}
return true;
} catch (error) {
console.error('Error saving proxy configs:', error);
return false;
}
}
// 删除代理配置 // 删除代理配置
export async function deleteProxyConfig(id: string): Promise<boolean> { export async function deleteProxyConfig(id: string): Promise<boolean> {
try { try {
const db = await openDB(); const db = await openDB();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const transaction = db.transaction([PROXY_STORE_NAME], 'readwrite'); const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
const store = transaction.objectStore(PROXY_STORE_NAME); const store = transaction.objectStore(STORES.PROXY_CONFIGS);
const request = store.delete(id); const request = store.delete(id);
request.onerror = () => reject(request.error); request.onerror = () => reject(request.error);
@@ -96,16 +173,99 @@ export async function deleteProxyConfig(id: string): Promise<boolean> {
} }
} }
// 设置当前代理
export async function setCurrentProxy(proxy: ProxyConfig): Promise<boolean> {
try {
const db = await openDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([STORES.CURRENT_PROXY], 'readwrite');
const store = transaction.objectStore(STORES.CURRENT_PROXY);
const request = store.put({ ...proxy, id: 'current' });
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(true);
});
} catch (error) {
console.error('Error setting current proxy:', error);
return false;
}
}
// 获取当前代理
export async function getCurrentProxy(): Promise<ProxyConfig | null> {
try {
const db = await openDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([STORES.CURRENT_PROXY], 'readonly');
const store = transaction.objectStore(STORES.CURRENT_PROXY);
const request = store.get('current');
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result || null);
});
} catch (error) {
console.error('Error getting current proxy:', error);
return null;
}
}
// 清除当前代理
export async function clearCurrentProxy(): Promise<boolean> {
try {
const db = await openDB();
return new Promise((resolve, reject) => {
const transaction = db.transaction([STORES.CURRENT_PROXY], 'readwrite');
const store = transaction.objectStore(STORES.CURRENT_PROXY);
const request = store.delete('current');
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(true);
});
} catch (error) {
console.error('Error clearing current proxy:', error);
return false;
}
}
// 启用指定的代理,禁用其他 // 启用指定的代理,禁用其他
export async function enableProxyConfig(id: string): Promise<boolean> { export async function enableProxyConfig(id: string): Promise<boolean> {
try { try {
// 获取所有配置
const configs = await getAllProxyConfigs(); const configs = await getAllProxyConfigs();
for (const config of configs) { // 查找目标代理
const updated = { ...config, enabled: config.id === id }; const targetProxy = configs.find(config => config.id === id);
await saveProxyConfig(updated); if (!targetProxy) {
console.error(`找不到ID为 ${id} 的代理配置`);
return false;
} }
// 创建更新后的代理配置
const updatedConfigs = configs.map(config => ({
...config,
enabled: config.id === id
}));
// 保存到数据库
const db = await openDB();
const transaction = db.transaction([STORES.PROXY_CONFIGS], 'readwrite');
const store = transaction.objectStore(STORES.PROXY_CONFIGS);
// 逐个更新配置
for (const config of updatedConfigs) {
await new Promise<void>((resolve, reject) => {
const request = store.put(config);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}
// 设置当前代理
await setCurrentProxy({
...targetProxy,
enabled: true
});
return true; return true;
} catch (error) { } catch (error) {
console.error(`Error enabling proxy config ${id}:`, error); console.error(`Error enabling proxy config ${id}:`, error);
@@ -117,13 +277,16 @@ export async function enableProxyConfig(id: string): Promise<boolean> {
export async function disableAllProxies(): Promise<boolean> { export async function disableAllProxies(): Promise<boolean> {
try { try {
const configs = await getAllProxyConfigs(); const configs = await getAllProxyConfigs();
const updatedConfigs = configs.map(config => ({
...config,
enabled: false
}));
for (const config of configs) { // 保存更新后的配置列表
if (config.enabled) { await saveProxyConfigs(updatedConfigs);
const updated = { ...config, enabled: false };
await saveProxyConfig(updated); // 清除当前代理
} await clearCurrentProxy();
}
return true; return true;
} catch (error) { } catch (error) {