| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| 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;
|
|
|