import { useEffect, useState, useCallback } from 'react' import { UserCircle, History, ChevronRight, ArrowLeft, ChevronDown, Pencil, Plus, Trash2 } from 'lucide-react' import { PageLayout } from '@/components/common/PageLayout' import { EmptyState } from '@/components/common/EmptyState' import { LoadingState } from '@/components/common/LoadingState' 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' /** 用户画像数据 */ interface ProfileData { phone: string industry: string company_size: string role: string common_scenes: string[] common_topics: string[] risk_tolerance: string communication_style: string decision_style: string key_facts: Record interaction_count: number last_active: string } /** 画像历史版本 */ interface ProfileHistory { id: number version: number profile: Record source: string created_at: string } /** 字段中文标签 */ const FIELD_LABELS: Record = { industry: '行业', company_size: '企业规模', role: '角色', risk_tolerance: '风险偏好', communication_style: '沟通偏好', decision_style: '决策风格', } /** 企业规模映射 */ const SIZE_LABELS: Record = { micro: '微型(<10人)', small: '小型(10-50人)', medium: '中型(50-200人)', large: '大型(200+人)', } /** 风险偏好映射 */ const RISK_LABELS: Record = { conservative: '保守型', moderate: '稳健型', aggressive: '进取型', } /** 角色映射 */ const ROLE_LABELS: Record = { owner: '老板/创始人', manager: '管理者', ceo: 'CEO', director: '总监', } /** 决策风格映射 */ const DECISION_STYLE_LABELS: Record = { 'data-driven': '数据驱动型', intuitive: '直觉型', collaborative: '协作型', } /** 沟通偏好映射 */ const COMMUNICATION_STYLE_LABELS: Record = { concise: '简洁', detailed: '详细', structured: '结构化', } /** 行业映射 */ const INDUSTRY_LABELS: Record = { retail: '零售', manufacturing: '制造业', tech: '科技', service: '服务业', finance: '金融', realestate: '房地产', education: '教育', healthcare: '医疗健康', construction: '建筑', logistics: '物流', agriculture: '农业', hospitality: '餐饮酒店', } /** key_facts 的 key 中文映射 */ const KEY_FACT_LABELS: Record = { region: '地区', company_type: '公司类型', team_ability: '团队能力', communication: '沟通情况', medical_proof: '医疗证明', contract_terms: '合同条款', medical_period: '医疗期', financial_status: '财务状况', injury_situation: '工伤情况', legal_procedures: '法律程序', market_potential: '市场潜力', alternative_option: '备选方案', work_injury_details: '工伤详情', alternative_solution: '替代方案', work_injury_insurance: '工伤保险', performance_assessment: '绩效评估', relevant_legal_provisions: '相关法律条款', employee_count: '员工人数', revenue: '营收', profit_status: '盈利状况', business_model: '商业模式', funding_stage: '融资阶段', expansion_plan: '扩张计划', competitor: '竞争对手', customer_concentration: '客户集中度', supply_chain: '供应链', cash_flow: '现金流', asset_status: '资产状况', liability: '负债', contract_dispute: '合同纠纷', debt_amount: '债务金额', tax_risk: '税务风险', litigation_status: '诉讼状态', shareholder_structure: '股权结构', partnership: '合伙关系', salary_status: '薪资状况', social_security: '社保', severance: '经济补偿', working_years: '工作年限', probation_period: '试用期', termination_reason: '解雇原因', overtime_status: '加班情况', export_capability: '出口能力', family_situation: '家庭情况', health_status: '健康状况', travel_plan: '出行计划', important_event: '重要事项', education_background: '教育背景', stress_source: '压力来源', personality: '性格特征', work_time: '工作时间', contract_status: '合同状态', salary_calculation_basis: '薪资计算依据', injury_detail: '受伤详情', treatment_status: '治疗状况', recovery_status: '康复状况', compensation_claim: '赔偿诉求', arbitration_status: '仲裁状态', employment_relationship: '劳动关系', wage_standard: '工资标准', working_hours: '工时', leave_record: '请假记录', discipline_record: '违纪记录', training_agreement: '培训协议', confidentiality_agreement: '保密协议', non_compete: '竞业限制', ip_ownership: '知识产权归属', data_protection: '数据保护', compliance_status: '合规状况', regulatory_requirement: '监管要求', license_status: '许可状态', audit_finding: '审计发现', internal_control: '内部控制', risk_management: '风险管理', insurance_coverage: '保险覆盖', claim_status: '理赔状态', policy_detail: '保单详情', premium_status: '保费状态', beneficiary: '受益人', coverage_amount: '保额', deductible: '免赔额', policy_period: '保险期间', renewal_status: '续保状态', cancellation_reason: '退保原因', loan_purpose: '借款用途', repayment_plan: '还款计划', collateral: '抵押物', guarantor_info: '担保人', interest_rate: '利率', penalty_rate: '罚息率', overdue_days: '逾期天数', collection_status: '催收状态', settlement_status: '结算状态', bankruptcy_status: '破产状态', restructure_plan: '重组方案', liquidation_status: '清算状态', debt_restructuring: '债务重组', asset_disposal: '资产处置', business_transfer: '业务转让', merger_status: '并购状态', acquisition_status: '收购状态', divestiture: '剥离', joint_venture: '合资', strategic_alliance: '战略联盟', ip_valuation: '知识产权估值', technology_transfer: '技术转让', royalty_rate: '许可费率', infringement_scope: '侵权范围', damages_claim: '损害赔偿诉求', injunction_status: '禁令状态', invalidation_request: '无效宣告请求', opposition_status: '异议状态', licensing_term: '许可期限', territory: '地域范围', exclusivity: '排他性', sublicensing: '再许可', warranty_term: '保证条款', indemnity: '补偿条款', limitation_liability: '责任限制', force_majeure: '不可抗力', dispute_resolution: '争议解决', governing_law: '适用法律', jurisdiction: '管辖', arbitration_clause: '仲裁条款', mediation_status: '调解状态', enforcement_status: '执行状态', execution_status: '执行状况', preservation_measure: '保全措施', objection_status: '异议状态', retrial_request: '再审请求', appeal_status: '上诉状态', court_level: '法院层级', case_procedure: '案件程序', hearing_date: '开庭日期', evidence_status: '举证状况', witness_status: '证人状况', expert_evaluation: '专家鉴定', judicial_interpretation: '司法解释', precedent_case: '先例案例', legislation_reference: '法律依据', // 补充:AI 分析维度生成的 key evidence: '证据', amount: '涉及金额', party: '对方当事人', timeline: '时间线', contract: '合同', scale: '决策规模', cashflow: '现金流', alternatives: '备选方案', market: '市场状况', team: '团队', risk_tolerance: '风险承受', profitability: '盈利能力', situation: '情境', people: '涉及人员', duration: '持续时间', attempt: '已尝试方式', goal: '期望结果', feeling: '情绪状态', trigger: '触发事件', time_range: '时间范围', region_policy: '地区政策', employer_status: '雇主身份', has_written_contract_agreement: '是否有书面合同', event_occurrence_and_current_status: '事件发生及现状', notification_negotiation: '通知与协商', labor_contract: '劳动合同', performance_evaluation: '绩效评估', salary_basis: '薪资计算依据', legal_provisions: '法律条款', alternative_plan: '备选方案', replacement_plan: '替代方案', financial_situation: '财务状况', // 个案事实 key 补充 contract_exists: '是否有合同', evidence_available: '是否有证据', internal_procedure_exists: '是否有内部程序', has_contract: '是否有合同', has_evidence: '是否有证据', has_internal_procedure: '是否有内部程序', written_contract: '书面合同', witness: '证人', document_evidence: '书面证据', electronic_evidence: '电子证据', physical_evidence: '物证', damage_amount: '损失金额', dispute_amount: '争议金额', claim_amount: '索赔金额', response_deadline: '答复期限', statute_limitations: '诉讼时效', applicable_law: '适用法律', cause_of_action: '案由', filing_status: '立案状态', court: '法院', judge: '法官', lawyer: '律师', opposing_party: '对方当事人', third_party: '第三方', mediation_attempted: '是否尝试调解', arbitration_attempted: '是否尝试仲裁', litigation_attempted: '是否尝试诉讼', settlement_attempted: '是否尝试和解', negotiation_status: '协商状态', breach_type: '违约类型', breach_severity: '违约程度', damage_type: '损失类型', compensation_type: '赔偿类型', compensation_amount: '赔偿金额', liability_type: '责任类型', liability_amount: '责任金额', insurance_type: '保险类型', policy_number: '保单号', claim_amount_insurance: '保险理赔金额', deductible_amount: '免赔额', coverage_type: '保障类型', renewal_date: '续保日期', beneficiary_name: '受益人', loan_amount: '贷款金额', loan_type: '贷款类型', lender: '出借方', borrower: '借款方', guarantor: '担保人', collateral_type: '抵押物类型', collateral_value: '抵押物价值', interest_rate_type: '利率类型', repayment_method: '还款方式', monthly_payment: '月供', overdue_amount: '逾期金额', overdue_days_count: '逾期天数', collection_method: '催收方式', default_risk: '违约风险', early_repayment: '提前还款', grace_period: '宽限期', penalty_interest: '罚息', liquidated_damages: '违约金', termination_clause: '终止条款', renewal_clause: '续约条款', exclusivity_clause: '排他条款', non_compete_clause: '竞业条款', confidentiality_clause: '保密条款', ip_clause: '知识产权条款', dispute_resolution_clause: '争议解决条款', governing_law_clause: '适用法律条款', force_majeure_clause: '不可抗力条款', assignment_clause: '转让条款', sublease_clause: '转租条款', service_scope: '服务范围', service_period: '服务期限', service_fee: '服务费', payment_terms: '付款条件', payment_method_contract: '合同付款方式', delivery_terms: '交付条件', delivery_method: '交付方式', delivery_address: '交付地址', delivery_date: '交付日期', acceptance_criteria: '验收标准', acceptance_period: '验收期限', warranty_period: '质保期', warranty_scope: '质保范围', maintenance_service: '维护服务', technical_support: '技术支持', training_service: '培训服务', consulting_service: '咨询服务', outsourcing_service: '外包服务', leasing_service: '租赁服务', licensing_service: '许可服务', distribution_service: '分销服务', agency_service: '代理服务', brokerage_service: '经纪服务', freight_service: '货运服务', warehousing_service: '仓储服务', customs_service: '报关服务', inspection_service: '检验服务', certification_service: '认证服务', notarization_service: '公证服务', legal_opinion: '法律意见', legal_review: '法律审查', due_diligence: '尽职调查', compliance_review: '合规审查', risk_assessment: '风险评估', feasibility_study: '可行性研究', market_research: '市场调研', customer_survey: '客户调研', competitor_analysis: '竞品分析', swot_analysis: 'SWOT分析', financial_analysis: '财务分析', cost_analysis: '成本分析', profit_analysis: '利润分析', cashflow_analysis: '现金流分析', roi_analysis: '投资回报分析', break_even_analysis: '盈亏平衡分析', sensitivity_analysis: '敏感性分析', scenario_analysis: '情景分析', valuation: '估值', valuation_method: '估值方法', discount_rate: '折现率', terminal_value: '终值', enterprise_value: '企业价值', equity_value: '股权价值', per_share_value: '每股价值', goodwill: '商誉', intangible_assets: '无形资产', tangible_assets: '有形资产', fixed_assets: '固定资产', current_assets: '流动资产', inventory: '存货', accounts_receivable: '应收账款', accounts_payable: '应付账款', prepaid_expenses: '预付费用', accrued_expenses: '应计费用', deferred_revenue: '递延收入', deferred_tax: '递延税', tax_rate: '税率', tax_type: '税种', tax_period: '税款所属期', tax_filing: '纳税申报', tax_payment: '税款缴纳', tax_refund: '退税', tax_exemption: '免税', tax_deduction: '税前扣除', tax_credit: '税收抵免', transfer_pricing: '转让定价', customs_duty: '关税', vat: '增值税', corporate_tax: '企业所得税', individual_tax: '个人所得税', property_tax: '房产税', land_tax: '土地税', stamp_duty: '印花税', vehicle_tax: '车船税', environmental_tax: '环保税', other_tax: '其他税', // 通用兜底:AI 可能生成的其他 key has_written_contract: '是否有书面合同', has_oral_agreement: '是否有口头协议', has_email_record: '是否有邮件记录', has_chat_record: '是否有聊天记录', has_signed_agreement: '是否有签署协议', has_notarized_document: '是否有公证文件', has_registered_trademark: '是否有注册商标', has_patent: '是否有专利', has_copyright: '是否有版权', has_trade_secret: '是否有商业秘密', has_non_compete: '是否有竞业限制', has_confidentiality: '是否有保密协议', has_employment_contract: '是否有劳动合同', has_service_agreement: '是否有服务协议', has_leasing_agreement: '是否有租赁协议', has_purchase_order: '是否有采购订单', has_sales_contract: '是否有销售合同', has_distribution_agreement: '是否有分销协议', has_agency_agreement: '是否有代理协议', has_partnership_agreement: '是否有合伙协议', has_shareholders_agreement: '是否有股东协议', has_board_resolution: '是否有董事会决议', has_shareholder_resolution: '是否有股东会决议', has_business_license: '是否有营业执照', has_special_permit: '是否有特许经营许可', has_industry_qualification: '是否有行业资质', has_environmental_approval: '是否有环评审批', has_safety_approval: '是否有安全审批', has_fire_approval: '是否有消防审批', has_food_license: '是否有食品经营许可', has_medical_license: '是否有医疗器械许可', has_cosmetic_license: '是否有化妆品许可', has_import_export_license: '是否有进出口许可', has_customs_registration: '是否有海关登记', has_foreign_exchange_registration: '是否有外汇登记', has_tax_registration: '是否有税务登记', has_social_security_registration: '是否有社保登记', has_housing_fund_registration: '是否有公积金登记', } /** key_facts 的值中文映射 */ const KEY_FACT_VALUE_LABELS: Record = { yes: '是', no: '否', true: '是', false: '否', none: '无', unknown: '未知', 'n/a': '不适用', pending: '待定', active: '活跃', inactive: '停用', profit: '盈利', loss: '亏损', expansion: '扩张', contraction: '收缩', stable: '稳定', growth: '增长中', declining: '下滑中', ...SIZE_LABELS, ...RISK_LABELS, ...ROLE_LABELS, ...INDUSTRY_LABELS, // 补充值翻译 employer: '雇主', employee: '员工', 'contract review': '合同审查', 'work-life balance': '工作生活平衡', 'has growth potential': '有增长潜力', 'separate financing': '单独融资', 'change product line': '改变产品线', 'compulsory payment': '强制缴纳', 'can terminate if unqualified': '不合格可以辞退', 'can dismiss if unqualified': '不合格可以解除合同', 'in negotiation': '在协商', 'loss 1 million': '亏损100万', 'has written contract': '有书面合同', 'no written contract': '无书面合同', 'limited company': '有限公司', 'not capable': '不具备', 'can terminate': '可以解除', 'yes, recognized': '是,已认定', 'incompetent': '不胜任', 'communicated': '沟通了', 'not communicated': '未沟通', 'clear standards': '有明确评估标准和记录', '6 months ago': '6个月前', 'last year': '去年', 'has ended': '已结束', 'yes, mandatory': '是,强制', } /** 场景中文映射 */ const SCENE_LABELS: Record = { legal: '私人法务', decision: '经营决策', life: '生活助理', emotion: '情绪中心', } /** 来源映射 */ const SOURCE_LABELS: Record = { auto: 'AI 自动提取', manual: '用户确认', } /** 画像特征 key(稳定的用户属性,直接展示) */ const PROFILE_FACT_KEYS = new Set([ 'region', 'company_type', 'team_ability', 'industry', 'company_size', 'role', 'risk_tolerance', 'communication_style', 'decision_style', 'market_potential', 'financial_status', 'financial_situation', 'cash_flow', 'asset_status', 'liability', 'revenue', 'profit_status', 'business_model', 'funding_stage', 'expansion_plan', 'competitor', 'customer_concentration', 'supply_chain', 'employee_count', 'shareholder_structure', 'partnership', ]) /** 判断 key 属于画像特征还是个案事实 */ function isProfileFact(key: string): boolean { return PROFILE_FACT_KEYS.has(String(key).toLowerCase()) } const TOPIC_LABELS: Record = { 'contract review': '合同审查', 'work-life balance': '工作生活平衡', 'tax': '税务', 'expansion': '扩张', 'financing': '融资', 'labor': '劳动用工', 'employment': '劳动用工', 'litigation': '诉讼', 'contract': '合同', 'shareholder': '股东', 'debt': '债务', 'salary': '薪资', 'social security': '社保', 'work injury': '工伤', 'termination': '辞退', 'decision': '决策', 'pricing': '定价', 'hiring': '招聘', 'layoff': '裁员', 'partnership': '合伙', 'investment': '投资', 'family': '家庭', 'health': '健康', 'stress': '压力', 'sleep': '睡眠', 'parenting': '亲子', 'education': '教育', 'marriage': '婚姻', } /** 翻译常问话题 */ function translateTopic(topic: string): string { const t = String(topic) const lower = t.toLowerCase().trim() return TOPIC_LABELS[lower] || t } /** 格式化字段值 */ function formatValue(key: string, value: string): string { const v = String(value) if (key === 'company_size') return SIZE_LABELS[v] || v if (key === 'risk_tolerance') return RISK_LABELS[v] || v if (key === 'role') return ROLE_LABELS[v] || v if (key === 'decision_style') return DECISION_STYLE_LABELS[v] || v if (key === 'communication_style') return COMMUNICATION_STYLE_LABELS[v] || v if (key === 'industry') return INDUSTRY_LABELS[v] || v return v } /** 翻译 key_facts 的 key */ function translateFactKey(key: string): string { const k = String(key).toLowerCase() return KEY_FACT_LABELS[k] || String(key) } /** 翻译 key_facts 的值 */ function translateFactValue(value: string): string { const v = String(value) const lower = v.toLowerCase().trim() return KEY_FACT_VALUE_LABELS[lower] || v } export function MyProfile() { const [profile, setProfile] = useState(null) const [history, setHistory] = useState([]) const [loading, setLoading] = useState(true) 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 [addingFact, setAddingFact] = useState(false) const [newFactKey, setNewFactKey] = useState('') const [newFactValue, setNewFactValue] = useState('') const [deletingFact, setDeletingFact] = useState<{ key: string; label: string } | null>(null) const load = useCallback(async () => { setLoading(true) setError(null) try { const [profileRes, historyRes] = await Promise.all([ api.getProfile(), api.getProfileHistory(), ]) setProfile(profileRes as unknown as ProfileData) setHistory(historyRes.results) } catch (e) { setError(e instanceof Error ? e.message : '加载失败') } finally { setLoading(false) } }, []) 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) } } /** 删除画像特征(确认后执行) */ const handleDeleteFact = (key: string, label: string) => { setDeletingFact({ key, label }) } /** 确认删除 */ const confirmDeleteFact = async () => { if (!deletingFact || !profile) return try { const newFacts = { ...profile.key_facts } delete newFacts[deletingFact.key] await api.updateProfile({ key_facts: newFacts }) setProfile((prev) => prev ? { ...prev, key_facts: newFacts } : prev) setDeletingFact(null) } catch (e) { setError(e instanceof Error ? e.message : '删除失败') } } /** 添加画像特征 */ const handleAddFact = async () => { if (!newFactKey.trim() || !newFactValue.trim() || !profile) return setSaving(true) try { const key = newFactKey.trim() const newFacts = { ...profile.key_facts, [key]: newFactValue.trim() } await api.updateProfile({ key_facts: newFacts }) setProfile((prev) => prev ? { ...prev, key_facts: newFacts } : prev) setAddingFact(false) setNewFactKey('') setNewFactValue('') } catch (e) { setError(e instanceof Error ? e.message : '添加失败') } finally { setSaving(false) } } if (loading) return if (error) return if (!profile) return null // ===== 历史详情视图 ===== if (currentHistory) { const hp = currentHistory.profile as Record return ( setCurrentHistory(null)}> 返回 } >
{/* 标准字段:多列网格 */}
{Object.entries(FIELD_LABELS).map(([key, label]) => { const val = hp[key] as string if (!val) return null return (
{label} {formatValue(key, val)}
) })}
{Array.isArray(hp.common_topics) && (hp.common_topics as string[]).length > 0 && (

常问话题

{(hp.common_topics as string[]).map((t, i) => ( {translateTopic(String(t))} ))}
)} {Boolean(hp.key_facts && typeof hp.key_facts === 'object' && !Array.isArray(hp.key_facts) && Object.keys(hp.key_facts as Record).length > 0) && (

关键事实

{Object.entries(hp.key_facts as Record).map(([k, v]) => (
{translateFactKey(k)} {translateFactValue(String(v))}
))}
)} {Array.isArray(hp.common_scenes) && (hp.common_scenes as string[]).length > 0 && (
常用场景
{(hp.common_scenes as string[]).map((s, i) => ( {SCENE_LABELS[String(s)] || String(s)} ))}
)}
) } // ===== 画像主视图 ===== return ( {/* 当前画像 */}

当前画像

交互 {profile.interaction_count} 次
{/* 标准字段:多列网格(可编辑) */}
{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)}
) })}
{profile.common_topics && profile.common_topics.length > 0 && (

常问话题

{profile.common_topics.map((t, i) => ( {translateTopic(t)} ))}
)} {profile.key_facts && Object.keys(profile.key_facts).length > 0 && (() => { const entries = Object.entries(profile.key_facts) const profileFacts = entries.filter(([k]) => isProfileFact(k)) const caseFacts = entries.filter(([k]) => !isProfileFact(k)) return ( <> {/* 画像特征:直接展示(可编辑/可增删) */} {profileFacts.length > 0 && (

画像特征

{profileFacts.map(([k, v]) => (
{translateFactKey(k)}
{translateFactValue(v)}
))}
)} {/* 无画像特征时也显示添加按钮 */} {profileFacts.length === 0 && (
)} {/* 个案事实:折叠展示 */} {caseFacts.length > 0 && (
{showCaseFacts && (
{caseFacts.map(([k, v]) => (
{translateFactKey(k)} {translateFactValue(v)}
))}
)}
)} ) })()} {profile.common_scenes && profile.common_scenes.length > 0 && (
常用场景
{profile.common_scenes.map((s, i) => ( {SCENE_LABELS[s] || s} ))}
)} {profile.last_active && (

最后活跃:{formatTime(profile.last_active)}

)}
{/* 版本历史 */}

版本历史

最近 3 个版本
{history.length === 0 ? ( ) : (
{history.slice(0, 3).map((h) => ( setCurrentHistory(h)} >

版本 v{h.version}

{SOURCE_LABELS[h.source] || h.source} {formatTime(h.created_at)}
))}
)}
{/* 编辑弹窗 */} !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()} /> )} {/* 添加画像特征弹窗 */} 添加画像特征 填写特征名称和值,保存后生效
setNewFactKey(e.target.value)} placeholder="如:行业、公司规模、地区" />
setNewFactValue(e.target.value)} placeholder="如:科技、小型、上海" onKeyDown={(e) => e.key === 'Enter' && handleAddFact()} />
{/* 删除确认弹窗 */} !open && setDeletingFact(null)}> 删除画像特征 确定要删除「{deletingFact?.label}」吗?此操作不可撤销。
) }