From 4f58d81493c174bd48023f72a6577eef66d2d7d4 Mon Sep 17 00:00:00 2001 From: selfrelease Date: Mon, 31 Aug 2026 15:17:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=BB=E5=83=8F=E7=89=B9=E5=BE=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=A1=8C=E5=86=85=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 标准字段(行业/规模/角色/风险偏好/沟通偏好/决策风格)hover显示编辑图标 - 画像特征(地区/公司类型/团队等)同样可编辑 - 标准字段用下拉选择,画像特征用文本输入 - 保存后调用 PUT /profile/me 更新,生成新版本快照 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- web2/src/pages/MyProfile.tsx | 115 ++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 7 deletions(-) diff --git a/web2/src/pages/MyProfile.tsx b/web2/src/pages/MyProfile.tsx index add0d81..b4f4071 100644 --- a/web2/src/pages/MyProfile.tsx +++ b/web2/src/pages/MyProfile.tsx @@ -1,5 +1,5 @@ import { useEffect, useState, useCallback } from 'react' -import { UserCircle, History, ChevronRight, ArrowLeft, ChevronDown } from 'lucide-react' +import { UserCircle, History, ChevronRight, ArrowLeft, ChevronDown, Pencil } from 'lucide-react' import { PageLayout } from '@/components/common/PageLayout' import { EmptyState } from '@/components/common/EmptyState' import { LoadingState } from '@/components/common/LoadingState' @@ -7,6 +7,11 @@ import { ErrorState } from '@/components/common/ErrorState' import { Card, CardContent } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Input } from '@/components/ui/input' +import { + Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, +} from '@/components/ui/dialog' import { api } from '@/lib/api' import { cn, formatTime } from '@/lib/utils' @@ -424,6 +429,9 @@ export function MyProfile() { const [error, setError] = useState(null) const [currentHistory, setCurrentHistory] = useState(null) const [showCaseFacts, setShowCaseFacts] = useState(false) + const [editing, setEditing] = useState<{ field: string; label: string; value: string; type: 'select' | 'text' } | null>(null) + const [editValue, setEditValue] = useState('') + const [saving, setSaving] = useState(false) const load = useCallback(async () => { setLoading(true) @@ -444,6 +452,46 @@ export function MyProfile() { useEffect(() => { load() }, [load]) + /** 标准字段选项(下拉选择) */ + const FIELD_OPTIONS: Record = { + industry: Object.entries(INDUSTRY_LABELS).map(([v, l]) => ({ value: v, label: l })), + company_size: Object.entries(SIZE_LABELS).map(([v, l]) => ({ value: v, label: l })), + role: Object.entries(ROLE_LABELS).map(([v, l]) => ({ value: v, label: l })), + risk_tolerance: Object.entries(RISK_LABELS).map(([v, l]) => ({ value: v, label: l })), + communication_style: Object.entries(COMMUNICATION_STYLE_LABELS).map(([v, l]) => ({ value: v, label: l })), + decision_style: Object.entries(DECISION_STYLE_LABELS).map(([v, l]) => ({ value: v, label: l })), + } + + /** 打开编辑 */ + const handleEdit = (field: string, label: string, value: string) => { + const isSelect = !!FIELD_OPTIONS[field] + setEditing({ field, label, value, type: isSelect ? 'select' : 'text' }) + setEditValue(value) + } + + /** 保存编辑 */ + const handleSave = async () => { + if (!editing || !editValue.trim()) { setEditing(null); return } + setSaving(true) + try { + const field = editing.field + if (FIELD_LABELS[field]) { + // 标准字段 + await api.updateProfile({ [field]: editValue }) + setProfile((prev) => prev ? { ...prev, [field]: editValue } : prev) + } else { + // key_facts + await api.updateProfile({ key_facts: { [field]: editValue } }) + setProfile((prev) => prev ? { ...prev, key_facts: { ...prev.key_facts, [field]: editValue } } : prev) + } + setEditing(null) + } catch (e) { + setError(e instanceof Error ? e.message : '保存失败') + } finally { + setSaving(false) + } + } + if (loading) return if (error) return if (!profile) return null @@ -537,15 +585,24 @@ export function MyProfile() {
- {/* 标准字段:多列网格 */} + {/* 标准字段:多列网格(可编辑) */}
{Object.entries(FIELD_LABELS).map(([key, label]) => { const val = profile[key as keyof ProfileData] as string if (!val) return null return ( -
+
{label} - {formatValue(key, val)} +
+ {formatValue(key, val)} + +
) })} @@ -568,15 +625,24 @@ export function MyProfile() { const caseFacts = entries.filter(([k]) => !isProfileFact(k)) return ( <> - {/* 画像特征:直接展示 */} + {/* 画像特征:直接展示(可编辑) */} {profileFacts.length > 0 && (

画像特征

{profileFacts.map(([k, v]) => ( -
+
{translateFactKey(k)} - {translateFactValue(v)} +
+ {translateFactValue(v)} + +
))}
@@ -677,6 +743,41 @@ export function MyProfile() {
)}
+ + {/* 编辑弹窗 */} + !open && setEditing(null)}> + + + 编辑{editing?.label} + 修改后将保存为新的画像版本 + + {editing?.type === 'select' && editing.field in FIELD_OPTIONS ? ( + + ) : ( + setEditValue(e.target.value)} + placeholder={`请输入${editing?.label}`} + onKeyDown={(e) => e.key === 'Enter' && handleSave()} + /> + )} + + + + + + ) }