feat(代理): 代理配置按登录用户隔离——桌面端 current_uid 登录同步 + brand 页 proxy_users[uid] 读写,各用户各自代理池各自计费复用(未登录回退全局 proxy_url 兼容旧配置)
This commit is contained in:
@@ -163,7 +163,7 @@ import {
|
|||||||
type ApiSecretModuleKey,
|
type ApiSecretModuleKey,
|
||||||
type ApiSecretRetention,
|
type ApiSecretRetention,
|
||||||
} from '@/shared/utils/api-secret-store'
|
} from '@/shared/utils/api-secret-store'
|
||||||
import { getPywebviewApi, type ProxyMode } from '@/shared/bridges/pywebview'
|
import { getPywebviewApi, type ProxyMode, type DesktopConfigUpdate } from '@/shared/bridges/pywebview'
|
||||||
|
|
||||||
type SecretState = {
|
type SecretState = {
|
||||||
value: string
|
value: string
|
||||||
@@ -275,6 +275,39 @@ function clearSecret(moduleKey: ApiSecretModuleKey) {
|
|||||||
ElMessage.success('已清空密钥')
|
ElMessage.success('已清空密钥')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function proxyUserId() {
|
||||||
|
if (typeof window === 'undefined') return '0'
|
||||||
|
return window.localStorage.getItem('uid') || '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 代理地址按登录用户隔离:proxy_users[uid],各自计费各自复用;
|
||||||
|
* 未登录(uid=0)回退全局 proxy_url(兼容旧版本已保存的配置)。 */
|
||||||
|
function readUserProxy(config: Record<string, unknown> | null | undefined) {
|
||||||
|
const uid = proxyUserId()
|
||||||
|
if (uid !== '0') {
|
||||||
|
const users = (config?.proxy_users ?? {}) as Record<string, unknown>
|
||||||
|
const own = (users[uid] ?? {}) as Record<string, unknown>
|
||||||
|
return {
|
||||||
|
url: typeof own.proxy_url === 'string' ? own.proxy_url : '',
|
||||||
|
mode: Number(own.proxy_mode) === 2 ? 2 : 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
url: typeof config?.proxy_url === 'string' ? config.proxy_url : '',
|
||||||
|
mode: Number(config?.proxy_mode) === 2 ? 2 : 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function userProxyPatch(nextProxyUrl: string, nextProxyMode: ProxyMode) {
|
||||||
|
const uid = proxyUserId()
|
||||||
|
if (uid === '0') {
|
||||||
|
return { proxy_url: nextProxyUrl, proxy_mode: nextProxyMode }
|
||||||
|
}
|
||||||
|
const users: Record<string, unknown> = {}
|
||||||
|
users[uid] = { proxy_url: nextProxyUrl, proxy_mode: nextProxyMode }
|
||||||
|
return { proxy_users: users }
|
||||||
|
}
|
||||||
|
|
||||||
async function loadProxyConfig() {
|
async function loadProxyConfig() {
|
||||||
const requestId = ++proxyLoadRequestId
|
const requestId = ++proxyLoadRequestId
|
||||||
proxyLoading.value = true
|
proxyLoading.value = true
|
||||||
@@ -294,10 +327,9 @@ async function loadProxyConfig() {
|
|||||||
try {
|
try {
|
||||||
const config = await api.read_config()
|
const config = await api.read_config()
|
||||||
if (requestId !== proxyLoadRequestId || !dialogVisible.value) return
|
if (requestId !== proxyLoadRequestId || !dialogVisible.value) return
|
||||||
const nextUrl = typeof config?.proxy_url === 'string' ? config.proxy_url : ''
|
const own = readUserProxy(config as Record<string, unknown>)
|
||||||
const nextMode: ProxyMode = Number(config?.proxy_mode) === 2 ? 2 : 1
|
proxyUrl.value = own.url
|
||||||
proxyUrl.value = nextUrl
|
proxyMode.value = (own.mode === 2 ? 2 : 1) as ProxyMode
|
||||||
proxyMode.value = nextMode
|
|
||||||
proxyReady.value = true
|
proxyReady.value = true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (requestId !== proxyLoadRequestId || !dialogVisible.value) return
|
if (requestId !== proxyLoadRequestId || !dialogVisible.value) return
|
||||||
@@ -331,10 +363,8 @@ async function saveAll() {
|
|||||||
if (shouldSaveProxy) {
|
if (shouldSaveProxy) {
|
||||||
const api = getPywebviewApi()
|
const api = getPywebviewApi()
|
||||||
if (!api?.save_config) throw new Error('当前客户端未提供代理配置保存能力')
|
if (!api?.save_config) throw new Error('当前客户端未提供代理配置保存能力')
|
||||||
await api.save_config({
|
// 按登录用户保存:proxy_users[uid](未登录回退全局 proxy_url 字段)
|
||||||
proxy_url: nextProxyUrl,
|
await api.save_config(userProxyPatch(nextProxyUrl, nextProxyMode) as DesktopConfigUpdate)
|
||||||
proxy_mode: nextProxyMode,
|
|
||||||
})
|
|
||||||
proxyUrl.value = nextProxyUrl
|
proxyUrl.value = nextProxyUrl
|
||||||
proxyDirty.value = false
|
proxyDirty.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -333,6 +333,17 @@ async function submitLogin() {
|
|||||||
} catch {
|
} catch {
|
||||||
/* 忽略 */
|
/* 忽略 */
|
||||||
}
|
}
|
||||||
|
// 同步登录用户到桌面客户端配置:Python 端按 uid 选用该用户自己的
|
||||||
|
// 代理密钥/代理池(各自计费、各自复用省钱)。网页形态无 pywebview
|
||||||
|
// 桥,静默跳过。
|
||||||
|
try {
|
||||||
|
const bridge = (window as unknown as { pywebview?: { api?: { save_config?: (data: Record<string, unknown>) => Promise<unknown> } } }).pywebview
|
||||||
|
if (bridge?.api && typeof bridge.api.save_config === 'function') {
|
||||||
|
void bridge.api.save_config({ current_uid: String(data.userId) })
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* 忽略 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (data.username) {
|
if (data.username) {
|
||||||
try {
|
try {
|
||||||
@@ -365,6 +376,15 @@ onMounted(() => {
|
|||||||
} catch {
|
} catch {
|
||||||
/* 忽略 */
|
/* 忽略 */
|
||||||
}
|
}
|
||||||
|
// 同步清掉客户端的登录用户标记:Python 端回退到全局/默认代理池
|
||||||
|
try {
|
||||||
|
const bridge = (window as unknown as { pywebview?: { api?: { save_config?: (data: Record<string, unknown>) => Promise<unknown> } } }).pywebview
|
||||||
|
if (bridge?.api && typeof bridge.api.save_config === 'function') {
|
||||||
|
void bridge.api.save_config({ current_uid: '' })
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* 忽略 */
|
||||||
|
}
|
||||||
// 显式登出/切号后不再自动登录(保留记住的账号,仅关闭自动登录)
|
// 显式登出/切号后不再自动登录(保留记住的账号,仅关闭自动登录)
|
||||||
autoLogin.value = false
|
autoLogin.value = false
|
||||||
lsSet(AUTO_LOGIN_KEY, '0')
|
lsSet(AUTO_LOGIN_KEY, '0')
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export interface DesktopConfig {
|
|||||||
export interface DesktopConfigUpdate {
|
export interface DesktopConfigUpdate {
|
||||||
proxy_url?: string;
|
proxy_url?: string;
|
||||||
proxy_mode?: ProxyMode;
|
proxy_mode?: ProxyMode;
|
||||||
|
current_uid?: string;
|
||||||
|
proxy_users?: Record<string, { proxy_url?: string; proxy_mode?: number }>;
|
||||||
aliprice_usename?: string;
|
aliprice_usename?: string;
|
||||||
aliprice_pwd?: string;
|
aliprice_pwd?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user