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

This commit is contained in:
卡若
2026-03-08 16:21:28 +08:00
parent 6951ae0c26
commit bf0c5ee879

View File

@@ -0,0 +1,129 @@
import { useState } from 'react'
import { Card, CardContent } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
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,
} from 'lucide-react'
import { get, post } from '@/api/client'
interface TestResult {
endpoint: string; label: string
method: 'GET' | 'POST'; status: 'idle' | 'testing' | 'success' | 'error'
message?: string; responseTime?: number
}
const typeMap = ['partner', 'investor', 'mentor', 'team']
export function CKBConfigPanel() {
const [testPhone, setTestPhone] = useState('13800000000')
const [testWechat, setTestWechat] = useState('')
const [tests, setTests] = useState<TestResult[]>([
{ endpoint: '/api/ckb/join', label: '找伙伴', method: 'POST', status: 'idle' },
{ endpoint: '/api/ckb/join', label: '资源对接', method: 'POST', status: 'idle' },
{ endpoint: '/api/ckb/join', label: '导师顾问', method: 'POST', status: 'idle' },
{ endpoint: '/api/ckb/join', label: '团队招募', method: 'POST', status: 'idle' },
{ endpoint: '/api/ckb/match', label: '匹配上报', method: 'POST', status: 'idle' },
{ endpoint: '/api/miniprogram/ckb/lead', label: '链接卡若', method: 'POST', status: 'idle' },
{ endpoint: '/api/match/config', label: '匹配配置', method: 'GET', status: 'idle' },
])
const getBody = (idx: number) => {
const phone = testPhone.trim(); const wechat = testWechat.trim()
if (idx <= 3) return { type: typeMap[idx], phone: phone || undefined, wechat: wechat || undefined, userId: 'admin_test', name: '后台测试' }
if (idx === 4) return { matchType: 'partner', phone: phone || undefined, wechat: wechat || undefined, userId: 'admin_test', nickname: '后台测试', matchedUser: { id: 'test', nickname: '测试', matchScore: 88 } }
if (idx === 5) return { phone: phone || undefined, wechatId: wechat || undefined, userId: 'admin_test', name: '后台测试' }
return {}
}
const testOne = async (idx: number) => {
const t = tests[idx]
if (t.method === 'POST' && !testPhone.trim() && !testWechat.trim()) { alert('请填写测试手机号'); return }
const next = [...tests]; next[idx] = { ...t, status: 'testing', message: undefined, responseTime: undefined }; setTests(next)
const start = performance.now()
try {
const res = t.method === 'GET'
? await get<{ success?: boolean; message?: string }>(t.endpoint)
: await post<{ success?: boolean; message?: string }>(t.endpoint, getBody(idx))
const elapsed = Math.round(performance.now() - start)
const msg = res?.message || ''
const ok = res?.success === true || msg.includes('已存在') || msg.includes('已加入') || msg.includes('已提交')
const n = [...tests]; n[idx] = { ...t, status: ok ? 'success' : 'error', message: msg || (ok ? '正常' : '异常'), responseTime: elapsed }; setTests(n)
} catch (e: unknown) {
const elapsed = Math.round(performance.now() - start)
const n = [...tests]; n[idx] = { ...t, status: 'error', message: e instanceof Error ? e.message : '失败', responseTime: elapsed }; setTests(n)
}
}
const testAll = async () => {
if (!testPhone.trim() && !testWechat.trim()) { alert('请填写测试手机号'); return }
for (let i = 0; i < tests.length; i++) await testOne(i)
}
return (
<Card className="bg-[#0f2137] border-orange-500/30 mb-6">
<CardContent className="p-5">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-3">
<h3 className="text-white font-semibold"></h3>
<Badge className="bg-orange-500/20 text-orange-400 border-0 text-xs">CKB</Badge>
<a href="https://ckbapi.quwanzhi.com" target="_blank" rel="noreferrer"
className="text-orange-400/60 text-xs hover:text-orange-400 flex items-center gap-1">
<ExternalLink className="w-3 h-3" /> API
</a>
</div>
<Button onClick={testAll} size="sm" className="bg-orange-500 hover:bg-orange-600 text-white">
<Zap className="w-3.5 h-3.5 mr-1" />
</Button>
</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" />
<div className="flex-1">
<Label className="text-gray-500 text-xs"></Label>
<Input className="bg-[#0a1628] border-gray-700 text-white h-8 text-sm mt-0.5" value={testPhone} onChange={e => setTestPhone(e.target.value)} />
</div>
</div>
<div className="flex items-center gap-2 flex-1">
<span className="text-gray-500 text-sm shrink-0">💬</span>
<div className="flex-1">
<Label className="text-gray-500 text-xs"></Label>
<Input className="bg-[#0a1628] border-gray-700 text-white h-8 text-sm mt-0.5" value={testWechat} onChange={e => setTestWechat(e.target.value)} />
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2">
{tests.map((t, idx) => (
<div key={`${t.endpoint}-${idx}`} className="flex items-center justify-between bg-[#0a1628] rounded-lg px-3 py-2 border border-gray-700/30">
<div className="flex items-center gap-2 min-w-0">
{t.status === 'idle' && <div className="w-2 h-2 rounded-full bg-gray-600 shrink-0" />}
{t.status === 'testing' && <RefreshCw className="w-3 h-3 text-yellow-400 animate-spin shrink-0" />}
{t.status === 'success' && <CheckCircle2 className="w-3 h-3 text-green-400 shrink-0" />}
{t.status === 'error' && <XCircle className="w-3 h-3 text-red-400 shrink-0" />}
<span className="text-white text-xs truncate">{t.label}</span>
</div>
<div className="flex items-center gap-1.5 shrink-0">
{t.responseTime !== undefined && <span className="text-gray-600 text-[10px]">{t.responseTime}ms</span>}
<button type="button" onClick={() => testOne(idx)} disabled={t.status === 'testing'}
className="text-orange-400/60 hover:text-orange-400 text-[10px] disabled:opacity-50"></button>
</div>
</div>
))}
</div>
<div className="flex gap-3 mt-3 text-xs">
<a href="https://ckbapi.quwanzhi.com/v1/api/scenarios" target="_blank" rel="noreferrer"
className="text-gray-500 hover:text-orange-400 flex items-center gap-1">
<FileText className="w-3 h-3" /> API
</a>
<span className="text-gray-700">|</span>
<span className="text-gray-600">Key: fyngh-ec...</span>
</div>
</CardContent>
</Card>
)
}