| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import React, { useEffect, useState } from 'react'; |
| import { useTranslation } from 'react-i18next'; |
| import { |
| Modal, |
| Button, |
| Space, |
| Typography, |
| Input, |
| Banner, |
| } from '@douyinfe/semi-ui'; |
| import { API, copy, showError, showSuccess } from '../../../../helpers'; |
|
|
| const { Text } = Typography; |
|
|
| const CodexOAuthModal = ({ visible, onCancel, onSuccess }) => { |
| const { t } = useTranslation(); |
| const [loading, setLoading] = useState(false); |
| const [authorizeUrl, setAuthorizeUrl] = useState(''); |
| const [input, setInput] = useState(''); |
|
|
| const startOAuth = async () => { |
| setLoading(true); |
| try { |
| const res = await API.post( |
| '/api/channel/codex/oauth/start', |
| {}, |
| { skipErrorHandler: true }, |
| ); |
| if (!res?.data?.success) { |
| console.error('Codex OAuth start failed:', res?.data?.message); |
| throw new Error(t('启动授权失败')); |
| } |
| const url = res?.data?.data?.authorize_url || ''; |
| if (!url) { |
| console.error( |
| 'Codex OAuth start response missing authorize_url:', |
| res?.data, |
| ); |
| throw new Error(t('响应缺少授权链接')); |
| } |
| setAuthorizeUrl(url); |
| window.open(url, '_blank', 'noopener,noreferrer'); |
| showSuccess(t('已打开授权页面')); |
| } catch (error) { |
| showError(error?.message || t('启动授权失败')); |
| } finally { |
| setLoading(false); |
| } |
| }; |
|
|
| const completeOAuth = async () => { |
| if (!input || !input.trim()) { |
| showError(t('请先粘贴回调 URL')); |
| return; |
| } |
|
|
| setLoading(true); |
| try { |
| const res = await API.post( |
| '/api/channel/codex/oauth/complete', |
| { input }, |
| { skipErrorHandler: true }, |
| ); |
| if (!res?.data?.success) { |
| console.error('Codex OAuth complete failed:', res?.data?.message); |
| throw new Error(t('授权失败')); |
| } |
|
|
| const key = res?.data?.data?.key || ''; |
| if (!key) { |
| console.error('Codex OAuth complete response missing key:', res?.data); |
| throw new Error(t('响应缺少凭据')); |
| } |
|
|
| onSuccess && onSuccess(key); |
| showSuccess(t('已生成授权凭据')); |
| onCancel && onCancel(); |
| } catch (error) { |
| showError(error?.message || t('授权失败')); |
| } finally { |
| setLoading(false); |
| } |
| }; |
|
|
| useEffect(() => { |
| if (!visible) return; |
| setAuthorizeUrl(''); |
| setInput(''); |
| }, [visible]); |
|
|
| return ( |
| <Modal |
| title={t('Codex 授权')} |
| visible={visible} |
| onCancel={onCancel} |
| maskClosable={false} |
| closeOnEsc |
| width={720} |
| footer={ |
| <Space> |
| <Button theme='borderless' onClick={onCancel} disabled={loading}> |
| {t('取消')} |
| </Button> |
| <Button |
| theme='solid' |
| type='primary' |
| onClick={completeOAuth} |
| loading={loading} |
| > |
| {t('生成并填入')} |
| </Button> |
| </Space> |
| } |
| > |
| <Space vertical spacing='tight' style={{ width: '100%' }}> |
| <Banner |
| type='info' |
| description={t( |
| '1) 点击「打开授权页面」完成登录;2) 浏览器会跳转到 localhost(页面打不开也没关系);3) 复制地址栏完整 URL 粘贴到下方;4) 点击「生成并填入」。', |
| )} |
| /> |
| |
| <Space wrap> |
| <Button type='primary' onClick={startOAuth} loading={loading}> |
| {t('打开授权页面')} |
| </Button> |
| <Button |
| theme='outline' |
| disabled={!authorizeUrl || loading} |
| onClick={() => copy(authorizeUrl)} |
| > |
| {t('复制授权链接')} |
| </Button> |
| </Space> |
| |
| <Input |
| value={input} |
| onChange={(value) => setInput(value)} |
| placeholder={t('请粘贴完整回调 URL(包含 code 与 state)')} |
| showClear |
| /> |
| |
| <Text type='tertiary' size='small'> |
| {t( |
| '说明:生成结果是可直接粘贴到渠道密钥里的 JSON(包含 access_token / refresh_token / account_id)。', |
| )} |
| </Text> |
| </Space> |
| </Modal> |
| ); |
| }; |
|
|
| export default CodexOAuthModal; |
|
|