feat: add backend API for flexible account record upload and validation, including concurrent account_id fetching, and a new frontend upload page.
This commit is contained in:
@@ -7,9 +7,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"codex-pool/internal/client"
|
||||||
"codex-pool/internal/database"
|
"codex-pool/internal/database"
|
||||||
"codex-pool/internal/logger"
|
"codex-pool/internal/logger"
|
||||||
)
|
)
|
||||||
@@ -255,7 +255,10 @@ func normalizeOwner(rec accountRecord, index int) (database.TeamOwner, error) {
|
|||||||
|
|
||||||
// fetchAccountID 通过 token 获取 account_id
|
// fetchAccountID 通过 token 获取 account_id
|
||||||
func fetchAccountID(token string) (string, error) {
|
func fetchAccountID(token string) (string, error) {
|
||||||
client := &http.Client{Timeout: 15 * time.Second}
|
tlsClient, err := client.New("")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("创建 TLS 客户端失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27", nil)
|
req, err := http.NewRequest("GET", "https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -264,9 +267,8 @@ func fetchAccountID(token string) (string, error) {
|
|||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+token)
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := tlsClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("请求失败: %v", err)
|
return "", fmt.Errorf("请求失败: %v", err)
|
||||||
}
|
}
|
||||||
@@ -276,7 +278,7 @@ func fetchAccountID(token string) (string, error) {
|
|||||||
return "", fmt.Errorf("API 返回状态码: %d", resp.StatusCode)
|
return "", fmt.Errorf("API 返回状态码: %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := client.ReadBody(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("读取响应失败: %v", err)
|
return "", fmt.Errorf("读取响应失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export default function Upload() {
|
|||||||
const [status, setStatus] = useState<ProcessStatus | null>(null)
|
const [status, setStatus] = useState<ProcessStatus | null>(null)
|
||||||
const [polling, setPolling] = useState(false)
|
const [polling, setPolling] = useState(false)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
const [importResult, setImportResult] = useState<{
|
const [importResult, setImportResult] = useState<{
|
||||||
imported: number
|
imported: number
|
||||||
total: number
|
total: number
|
||||||
@@ -232,8 +233,13 @@ export default function Upload() {
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => { loadStats(); fetchStatus(); }}
|
disabled={refreshing}
|
||||||
icon={<RefreshCw className={`h-4 w-4 ${polling ? 'animate-spin' : ''}`} />}
|
onClick={async () => {
|
||||||
|
setRefreshing(true)
|
||||||
|
await Promise.all([loadStats(), fetchStatus()])
|
||||||
|
setTimeout(() => setRefreshing(false), 500)
|
||||||
|
}}
|
||||||
|
icon={<RefreshCw className={`h-4 w-4 ${refreshing || polling ? 'animate-spin' : ''}`} />}
|
||||||
>
|
>
|
||||||
刷新
|
刷新
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user