包含功能: - 法务参谋/经营决策/生活助理/情绪中心四大AI对话模块 - 专家咨询系统(用户选定→专家确认→咨询→回复→评价) - 角色登录(用户/专家/管理员)+ ProtectedRoute 权限控制 - 管理后台(用户管理/专家管理/AI使用统计/专家活跃度) - 专家工作台(待确认服务/待回复咨询/已回复咨询/服务中用户) - 服务关系取消(用户和专家均可取消,需自己确认) - 全页面移动端响应式适配 - 知识库RAG检索 - 对话历史(普通/保密模式) Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
55 lines
2.2 KiB
TypeScript
55 lines
2.2 KiB
TypeScript
import { useState } from 'react'
|
|
import { toast } from 'sonner'
|
|
import { Check, Loader2 } from 'lucide-react'
|
|
import { EmptyState } from '@/components/common/EmptyState'
|
|
import { Card, CardContent } from '@/components/ui/card'
|
|
import { Button } from '@/components/ui/button'
|
|
import { api } from '@/lib/api'
|
|
import { useWorkbenchData, WorkbenchShell, maskPhone } from './shared'
|
|
|
|
/** 专家工作台 - 待确认服务:用户选定专家后,专家确认接单 */
|
|
export function WorkbenchPendingServices() {
|
|
const { expert, services, loading, error, loadData } = useWorkbenchData()
|
|
const [accepting, setAccepting] = useState<number | null>(null)
|
|
|
|
const pendingServices = services.filter(s => s.status === 'pending')
|
|
|
|
const handleAccept = async (serviceId: number) => {
|
|
setAccepting(serviceId)
|
|
try {
|
|
await api.acceptService(serviceId)
|
|
toast.success('已确认服务关系')
|
|
loadData()
|
|
} catch (e) {
|
|
toast.error(e instanceof Error ? e.message : '确认失败')
|
|
} finally {
|
|
setAccepting(null)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<WorkbenchShell expert={expert} loading={loading} error={error} title="待确认服务" description="用户选定你后,在此确认接单">
|
|
{pendingServices.length === 0 ? (
|
|
<EmptyState title="暂无待确认的服务" description="用户选定你后会显示在这里" icon={<Check className="h-8 w-8" />} />
|
|
) : (
|
|
<div className="space-y-2">
|
|
{pendingServices.map((s) => (
|
|
<Card key={s.service_id}>
|
|
<CardContent className="flex items-center justify-between gap-2 py-3">
|
|
<div className="min-w-0">
|
|
<p className="text-sm font-medium">用户:{maskPhone(s.user_phone || '')}</p>
|
|
<p className="text-xs text-muted-foreground">请求时间:{s.created_at}</p>
|
|
</div>
|
|
<Button size="sm" className="shrink-0" onClick={() => handleAccept(s.service_id)} disabled={accepting === s.service_id}>
|
|
{accepting === s.service_id ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Check className="h-3.5 w-3.5" />}
|
|
确认接单
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
)}
|
|
</WorkbenchShell>
|
|
)
|
|
}
|