sync: soul-admin 页面 | 原因: 前端页面修改

This commit is contained in:
卡若
2026-03-08 16:59:18 +08:00
parent 4be524d8c7
commit 415f9958aa

View File

@@ -5,7 +5,7 @@ import { Label } from '@/components/ui/label'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import {
RefreshCw, Zap, CheckCircle2, XCircle, Smartphone, FileText, ExternalLink,
RefreshCw, Zap, CheckCircle2, XCircle, Smartphone, FileText, ExternalLink, Save,
} from 'lucide-react'
import { get, post } from '@/api/client'
@@ -20,6 +20,10 @@ const typeMap = ['partner', 'investor', 'mentor', 'team']
export function CKBConfigPanel() {
const [testPhone, setTestPhone] = useState('13800000000')
const [testWechat, setTestWechat] = useState('')
const [apiUrl, setApiUrl] = useState('https://ckbapi.quwanzhi.com/v1/api/scenarios')
const [apiKey, setApiKey] = useState('fyngh-ecy9h-qkdae-epwd5-rz6kd')
const [docNotes, setDocNotes] = useState('')
const [isSaving, setIsSaving] = useState(false)
const [tests, setTests] = useState<TestResult[]>([
{ endpoint: '/api/ckb/join', label: '找伙伴', method: 'POST', status: 'idle' },
{ endpoint: '/api/ckb/join', label: '资源对接', method: 'POST', status: 'idle' },
@@ -62,6 +66,36 @@ export function CKBConfigPanel() {
for (let i = 0; i < tests.length; i++) await testOne(i)
}
async function loadConfig() {
try {
const data = await get<{ data?: { apiUrl?: string; apiKey?: string; docNotes?: string } }>('/api/db/config/full?key=ckb_config')
const c = data?.data
if (c?.apiUrl) setApiUrl(c.apiUrl)
if (c?.apiKey) setApiKey(c.apiKey)
if (c?.docNotes) setDocNotes(c.docNotes)
} catch {
// ignore
}
}
async function saveConfig() {
setIsSaving(true)
try {
const res = await post<{ success?: boolean; error?: string }>('/api/db/config', {
key: 'ckb_config',
value: { apiUrl, apiKey, docNotes },
description: '存客宝接口配置',
})
alert(res?.success !== false ? '存客宝配置已保存' : `保存失败: ${res?.error || '未知错误'}`)
} catch (e) {
alert(`保存失败: ${e instanceof Error ? e.message : '网络错误'}`)
} finally {
setIsSaving(false)
}
}
useState(() => { void loadConfig(); return null })
return (
<Card className="bg-[#0f2137] border-orange-500/30 mb-6">
<CardContent className="p-5">
@@ -79,6 +113,22 @@ export function CKBConfigPanel() {
</Button>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 mb-5">
<div className="space-y-1">
<Label className="text-gray-500 text-xs">API </Label>
<Input className="bg-[#0a1628] border-gray-700 text-white h-9 text-sm" value={apiUrl} onChange={e => setApiUrl(e.target.value)} />
</div>
<div className="space-y-1">
<Label className="text-gray-500 text-xs">API Key</Label>
<Input className="bg-[#0a1628] border-gray-700 text-white h-9 text-sm" value={apiKey} onChange={e => setApiKey(e.target.value)} />
</div>
<div className="flex items-end">
<Button onClick={saveConfig} disabled={isSaving} className="bg-[#38bdac] hover:bg-[#2da396] text-white w-full">
<Save className="w-4 h-4 mr-2" /> {isSaving ? '保存中...' : '保存配置'}
</Button>
</div>
</div>
<div className="flex gap-3 mb-4">
<div className="flex items-center gap-2 flex-1">
<Smartphone className="w-4 h-4 text-gray-500 shrink-0" />
@@ -121,7 +171,30 @@ export function CKBConfigPanel() {
<FileText className="w-3 h-3" /> API
</a>
<span className="text-gray-700">|</span>
<span className="text-gray-600">Key: fyngh-ec...</span>
<span className="text-gray-600">Key: {apiKey ? `${apiKey.slice(0, 8)}...` : '未配置'}</span>
</div>
<div className="mt-5 grid grid-cols-1 xl:grid-cols-2 gap-4">
<div className="bg-[#0a1628] rounded-lg border border-gray-700/30 p-4">
<h4 className="text-white text-sm font-medium mb-3"></h4>
<div className="space-y-2 text-xs text-gray-400">
<p><span className="text-gray-300"></span><code className="text-orange-300">POST /v1/api/scenarios</code></p>
<p><span className="text-gray-300"></span><code>apiKey</code><code>sign</code><code>timestamp</code></p>
<p><span className="text-gray-300"></span><code>phone</code> <code>wechatId</code></p>
<p><span className="text-gray-300"></span><code>name</code><code>source</code><code>remark</code><code>tags</code><code>siteTags</code><code>portrait</code></p>
<p><span className="text-gray-300"></span> <code>sign/apiKey/portrait</code> MD5</p>
<p><span className="text-gray-300"></span><code>{"{ code: 200, message: '新增成功|已存在' }"}</code></p>
</div>
</div>
<div className="bg-[#0a1628] rounded-lg border border-gray-700/30 p-4">
<h4 className="text-white text-sm font-medium mb-3"></h4>
<textarea
className="w-full min-h-[140px] bg-[#0f2137] border border-gray-700 rounded-md text-sm text-gray-300 p-3 outline-none focus:border-orange-500/50 resize-y"
value={docNotes}
onChange={(e) => setDocNotes(e.target.value)}
placeholder="这里可记录存客宝 Token、计划说明、接口对接约定、回复率统计规则等。"
/>
</div>
</div>
</CardContent>
</Card>