feat: Implement the ChatGPT Owner Demotion Console with new frontend and backend components.
This commit is contained in:
@@ -13,7 +13,8 @@ import {
|
||||
Globe,
|
||||
Zap,
|
||||
Monitor,
|
||||
Network
|
||||
Network,
|
||||
UserMinus
|
||||
} from 'lucide-react'
|
||||
import { Card, CardHeader, CardTitle, CardContent, Button, Input } from '../components/common'
|
||||
import { useConfig } from '../hooks/useConfig'
|
||||
@@ -25,6 +26,8 @@ export default function Config() {
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [authMethod, setAuthMethod] = useState<'api' | 'browser'>('browser')
|
||||
const [savingAuthMethod, setSavingAuthMethod] = useState(false)
|
||||
const [demoteAfterUse, setDemoteAfterUse] = useState(false)
|
||||
const [savingDemote, setSavingDemote] = useState(false)
|
||||
const [proxyPoolCount, setProxyPoolCount] = useState<number>(0)
|
||||
const { toasts, toast, removeToast } = useToast()
|
||||
|
||||
@@ -40,6 +43,8 @@ export default function Config() {
|
||||
if (data.data.auth_method) {
|
||||
setAuthMethod(data.data.auth_method === 'api' ? 'api' : 'browser')
|
||||
}
|
||||
// 加载母号降级开关
|
||||
setDemoteAfterUse(data.data.demote_after_use === true)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch config:', error)
|
||||
@@ -113,6 +118,33 @@ export default function Config() {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存母号降级开关
|
||||
const handleToggleDemote = async () => {
|
||||
setSavingDemote(true)
|
||||
const newValue = !demoteAfterUse
|
||||
setDemoteAfterUse(newValue) // 立即更新 UI
|
||||
try {
|
||||
const res = await fetch('/api/config', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ demote_after_use: newValue }),
|
||||
})
|
||||
const data = await res.json()
|
||||
if (data.code === 0) {
|
||||
toast.success(newValue ? '母号降级已开启' : '母号降级已关闭')
|
||||
refreshConfig()
|
||||
} else {
|
||||
setDemoteAfterUse(!newValue) // 回滚
|
||||
toast.error(data.message || '保存失败')
|
||||
}
|
||||
} catch {
|
||||
setDemoteAfterUse(!newValue) // 回滚
|
||||
toast.error('网络错误')
|
||||
} finally {
|
||||
setSavingDemote(false)
|
||||
}
|
||||
}
|
||||
|
||||
const configItems = [
|
||||
{
|
||||
to: '/config/s2a',
|
||||
@@ -287,6 +319,52 @@ export default function Config() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 母号降级开关 */}
|
||||
<div className="pt-4 border-t border-slate-200 dark:border-slate-700">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`p-2 rounded-lg ${demoteAfterUse
|
||||
? 'bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400'
|
||||
: 'bg-slate-100 dark:bg-slate-800 text-slate-500 dark:text-slate-400'
|
||||
}`}>
|
||||
<UserMinus className="h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300">
|
||||
母号使用后自动降级
|
||||
</label>
|
||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||
母号入库完成后自动降级为普通成员
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleToggleDemote}
|
||||
disabled={savingDemote}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2 ${demoteAfterUse
|
||||
? 'bg-orange-500'
|
||||
: 'bg-slate-300 dark:bg-slate-600'
|
||||
} ${savingDemote ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-4 w-4 transform rounded-full bg-white shadow-sm transition-transform duration-200 ${demoteAfterUse ? 'translate-x-6' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
{demoteAfterUse && (
|
||||
<div className="mt-3 p-3 rounded-lg bg-gradient-to-r from-orange-500 to-amber-500 text-white shadow-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserMinus className="h-4 w-4" />
|
||||
<span className="font-medium">母号降级已开启</span>
|
||||
</div>
|
||||
<p className="text-xs text-orange-100 mt-1">
|
||||
母号入库完成后会自动调用 API 将其降级为普通成员,可以防止母号被滥用
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user