diff --git a/api.py b/api.py index a292d04..e8fc827 100644 --- a/api.py +++ b/api.py @@ -1282,9 +1282,32 @@ class RatingRequest(BaseModel): @app.get("/experts") -def list_experts(category: str | None = None): - """列出专家,支持按分类筛选(legal/decision/emotion/life)。""" - return {"results": expert_store.list_experts(category=category, status="active")} +def list_experts(category: str | None = None, authorization: str | None = Header(default=None)): + """列出专家,支持按分类筛选(legal/decision/emotion/life)。 + 登录后额外返回 connected 字段(是否已建立服务联系)。 + """ + results = expert_store.list_experts(category=category, status="active") + # 查询当前用户已建立联系的专家ID集合 + phone = get_current_phone(authorization) + if phone and results: + conn = _matter_dsn() + try: + cur = conn.cursor() + expert_ids = [r["id"] for r in results] + cur.execute( + "SELECT DISTINCT expert_id FROM expert_consultations " + "WHERE user_phone = %s AND expert_id = ANY(%s)", + (phone, expert_ids), + ) + connected_ids = {r[0] for r in cur.fetchall()} + for r in results: + r["connected"] = r["id"] in connected_ids + finally: + conn.close() + else: + for r in results: + r["connected"] = False + return {"results": results} @app.get("/experts/{expert_id}") diff --git a/web2/src/pages/Experts.tsx b/web2/src/pages/Experts.tsx index 7d678cc..d04843c 100644 --- a/web2/src/pages/Experts.tsx +++ b/web2/src/pages/Experts.tsx @@ -1,9 +1,10 @@ /** 专家库:浏览所有专家,选择后跳转到对应智囊场景咨询 * 卡片样式参考管理端专家管理:长方形头像 + 姓名/评分 + 简介 + 专长标签 + * 已建立服务联系的可直接咨询,未建立的需先建立联系 */ import { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' -import { Users, Star, ChevronRight, Briefcase } from 'lucide-react' +import { Users, Star, ChevronRight, Briefcase, Link2, CheckCircle2 } from 'lucide-react' import { PageLayout } from '@/components/common/PageLayout' import { Card, CardContent } from '@/components/ui/card' import { Button } from '@/components/ui/button' @@ -30,6 +31,7 @@ export function Experts() { const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [filter, setFilter] = useState('all') + const [connecting, setConnecting] = useState(null) const load = () => { setLoading(true); setError('') @@ -40,6 +42,20 @@ export function Experts() { useEffect(load, [filter]) + /** 建立服务联系 */ + const handleConnect = async (ex: Expert) => { + setConnecting(ex.id) + try { + await api.selectExpert(ex.id) + // 更新本地状态 + setExperts((prev) => prev.map((e) => e.id === ex.id ? { ...e, connected: true } : e)) + } catch (e: any) { + setError(e.message || '建立联系失败') + } finally { + setConnecting(null) + } + } + if (loading) return if (error) return @@ -73,6 +89,7 @@ export function Experts() {
{experts.map((ex) => { const stars = (ex.rate / 100).toFixed(1) + const isConnected = !!ex.connected return ( @@ -88,6 +105,11 @@ export function Experts() {

{ex.name}

+ {isConnected && ( + + 已联系 + + )}

{ex.title}

{ex.rating_count > 0 && ( @@ -112,18 +134,30 @@ export function Experts() {
- {/* 底部:分类 + 咨询按钮 */} + {/* 底部:分类 + 咨询/建立联系按钮 */}
{SCENE_LABELS[ex.category] || ex.category} - + {isConnected ? ( + + ) : ( + + )}
diff --git a/web2/src/types/index.ts b/web2/src/types/index.ts index 964e3fc..91deb33 100644 --- a/web2/src/types/index.ts +++ b/web2/src/types/index.ts @@ -90,6 +90,7 @@ export interface Expert { status: 'active' | 'inactive' created_at?: string ratings?: ExpertRating[] + connected?: boolean } /** 专家评价 */