Files
lingxi-web/src/config/constants.ts
T
wmq af49d22ca7 feat: release contextual omnichannel customer platform
Add Telegram, WhatsApp and email account management, realtime messaging, contextual multilingual AI, customer intelligence, knowledge workflows, enterprise controls, a unified design system and complete repository documentation.
2026-07-30 02:29:53 +08:00

292 lines
13 KiB
TypeScript

import type { ChannelType } from '@/types/messaging'
import type { CustomerStage, OpportunityStage, RiskType, TaskPriority, TaskType } from '@/types/crm'
import type { KnowledgeCategory } from '@/types/knowledge'
import type { IntentLevel, Sentiment, ValueLevel } from '@/types/common'
/** 国家/地区 */
export interface CountryMeta {
code: string
zh: string
en: string
flag: string
tzOffset: number // 相对 UTC 小时
lang: string
}
export const COUNTRIES: CountryMeta[] = [
{ code: 'PK', zh: '巴基斯坦', en: 'Pakistan', flag: '🇵🇰', tzOffset: 5, lang: 'ur' },
{ code: 'BD', zh: '孟加拉国', en: 'Bangladesh', flag: '🇧🇩', tzOffset: 6, lang: 'bn' },
{ code: 'AE', zh: '阿联酋', en: 'UAE', flag: '🇦🇪', tzOffset: 4, lang: 'ar' },
{ code: 'SA', zh: '沙特阿拉伯', en: 'Saudi Arabia', flag: '🇸🇦', tzOffset: 3, lang: 'ar' },
{ code: 'US', zh: '美国', en: 'United States', flag: '🇺🇸', tzOffset: -5, lang: 'en' },
{ code: 'GB', zh: '英国', en: 'United Kingdom', flag: '🇬🇧', tzOffset: 0, lang: 'en' },
{ code: 'DE', zh: '德国', en: 'Germany', flag: '🇩🇪', tzOffset: 1, lang: 'de' },
{ code: 'ES', zh: '西班牙', en: 'Spain', flag: '🇪🇸', tzOffset: 1, lang: 'es' },
{ code: 'CN', zh: '中国', en: 'China', flag: '🇨🇳', tzOffset: 8, lang: 'zh' },
]
export function countryMeta(code: string): CountryMeta {
const normalized = String(code || '').trim().toUpperCase()
const known = COUNTRIES.find((c) => c.code === normalized)
if (known) return known
if (!/^[A-Z]{2}$/.test(normalized)) {
return { code: '', zh: '国家待确认', en: 'Country not confirmed', flag: '🌐', tzOffset: Number.NaN, lang: '' }
}
const flag = String.fromCodePoint(
...[...normalized].map((character) => 127397 + character.charCodeAt(0)),
)
const zh = new Intl.DisplayNames(['zh-CN'], { type: 'region' }).of(normalized) || normalized
const en = new Intl.DisplayNames(['en'], { type: 'region' }).of(normalized) || normalized
return { code: normalized, zh, en, flag, tzOffset: Number.NaN, lang: '' }
}
/** 行业 */
export const INDUSTRIES = ['服装纺织', '玻璃制品', '3C电子', '家居用品', '通用外贸']
/** 客户阶段 */
export const CUSTOMER_STAGES: { value: CustomerStage; label: string; color: string }[] = [
{ value: 'initial', label: '初次咨询', color: 'bg-sky-100 text-sky-700' },
{ value: 'comparing', label: '价格比较', color: 'bg-amber-100 text-amber-700' },
{ value: 'sample', label: '样品确认', color: 'bg-violet-100 text-violet-700' },
{ value: 'custom', label: '定制沟通', color: 'bg-cyan-100 text-cyan-700' },
{ value: 'closing', label: '成交推进', color: 'bg-emerald-100 text-emerald-700' },
{ value: 'fulfillment', label: '履约跟踪', color: 'bg-teal-100 text-teal-700' },
{ value: 'aftersales', label: '售后处理', color: 'bg-orange-100 text-orange-700' },
{ value: 'repurchase', label: '复购培育', color: 'bg-rose-100 text-rose-700' },
]
export function customerStageMeta(stage: CustomerStage) {
return CUSTOMER_STAGES.find((s) => s.value === stage) ?? CUSTOMER_STAGES[0]
}
/** 商机阶段 */
export const OPPORTUNITY_STAGES: { value: OpportunityStage; label: string; color: string }[] = [
{ value: 'new', label: '新询盘', color: 'bg-sky-100 text-sky-700' },
{ value: 'requirement', label: '需求确认', color: 'bg-blue-100 text-blue-700' },
{ value: 'quoting', label: '报价中', color: 'bg-amber-100 text-amber-700' },
{ value: 'sample', label: '样品沟通', color: 'bg-violet-100 text-violet-700' },
{ value: 'custom', label: '定制确认', color: 'bg-cyan-100 text-cyan-700' },
{ value: 'negotiation', label: '商务谈判', color: 'bg-orange-100 text-orange-700' },
{ value: 'pending-deal', label: '待成交', color: 'bg-emerald-100 text-emerald-700' },
{ value: 'won', label: '已成交', color: 'bg-green-100 text-green-700' },
{ value: 'fulfillment', label: '履约中', color: 'bg-teal-100 text-teal-700' },
{ value: 'aftersales', label: '售后中', color: 'bg-yellow-100 text-yellow-700' },
{ value: 'repurchase', label: '复购培育', color: 'bg-rose-100 text-rose-700' },
{ value: 'lost', label: '已流失', color: 'bg-gray-200 text-gray-500' },
]
export function opportunityStageMeta(stage: OpportunityStage) {
return OPPORTUNITY_STAGES.find((s) => s.value === stage) ?? OPPORTUNITY_STAGES[0]
}
/** 意向等级 */
export const INTENT_LEVELS: { value: IntentLevel; label: string; color: string; range: string }[] = [
{ value: 'high', label: '高价值', color: 'bg-emerald-100 text-emerald-700', range: '80—100' },
{ value: 'medium-high', label: '中高价值', color: 'bg-teal-100 text-teal-700', range: '60—79' },
{ value: 'medium', label: '中等价值', color: 'bg-amber-100 text-amber-700', range: '40—59' },
{ value: 'low', label: '低价值', color: 'bg-gray-100 text-gray-500', range: '0—39' },
]
export function intentLevelOf(score: number): IntentLevel {
if (score >= 80) return 'high'
if (score >= 60) return 'medium-high'
if (score >= 40) return 'medium'
return 'low'
}
export function intentLevelMeta(level: IntentLevel) {
return INTENT_LEVELS.find((l) => l.value === level) ?? INTENT_LEVELS[3]
}
export const VALUE_LEVELS: { value: ValueLevel; label: string; color: string }[] = [
{ value: 'A', label: 'A级(重点)', color: 'bg-emerald-100 text-emerald-700' },
{ value: 'B', label: 'B级(优质)', color: 'bg-teal-100 text-teal-700' },
{ value: 'C', label: 'C级(普通)', color: 'bg-amber-100 text-amber-700' },
{ value: 'D', label: 'D级(观察)', color: 'bg-gray-100 text-gray-500' },
]
/** 情绪状态 */
export const SENTIMENTS: { value: Sentiment; label: string; color: string; emoji: string }[] = [
{ value: 'positive', label: '积极', color: 'text-emerald-600', emoji: '😊' },
{ value: 'neutral-positive', label: '中性偏积极', color: 'text-teal-600', emoji: '🙂' },
{ value: 'neutral', label: '中性', color: 'text-gray-500', emoji: '😐' },
{ value: 'negative', label: '消极', color: 'text-amber-600', emoji: '😟' },
{ value: 'angry', label: '不满', color: 'text-red-600', emoji: '😠' },
]
export function sentimentMeta(s: Sentiment) {
return SENTIMENTS.find((x) => x.value === s) ?? SENTIMENTS[2]
}
/** 风险等级 */
export const RISK_LEVELS = [
{ value: 'low', label: '低', color: 'bg-gray-100 text-gray-600', dot: 'bg-gray-400' },
{ value: 'medium', label: '中', color: 'bg-amber-100 text-amber-700', dot: 'bg-amber-500' },
{ value: 'high', label: '高', color: 'bg-orange-100 text-orange-700', dot: 'bg-orange-500' },
{ value: 'urgent', label: '紧急', color: 'bg-red-100 text-red-700', dot: 'bg-red-500' },
] as const
export function riskLevelMeta(level: string) {
return RISK_LEVELS.find((l) => l.value === level) ?? RISK_LEVELS[0]
}
/** 风险类型 */
export const RISK_TYPES: { value: RiskType; label: string }[] = [
{ value: 'negative-sentiment', label: '客户负面情绪' },
{ value: 'dispute', label: '潜在交易纠纷' },
{ value: 'price-objection', label: '价格异议' },
{ value: 'delivery', label: '交期风险' },
{ value: 'logistics', label: '物流风险' },
{ value: 'complaint', label: '售后投诉' },
{ value: 'culture', label: '文化敏感表达' },
{ value: 'religion', label: '宗教敏感表达' },
{ value: 'follow-up-delay', label: '高价值客户久未跟进' },
{ value: 'churn', label: '客户可能流失' },
{ value: 'task-overdue', label: '跟进任务逾期' },
{ value: 'account-abnormal', label: '异常账号登录' },
]
export function riskTypeLabel(type: RiskType): string {
return RISK_TYPES.find((t) => t.value === type)?.label ?? type
}
/** 跟进任务类型 */
export const TASK_TYPES: { value: TaskType; label: string }[] = [
{ value: 'quote', label: '发送报价' },
{ value: 'material', label: '发送资料' },
{ value: 'sample', label: '样品确认' },
{ value: 'custom', label: '定制沟通' },
{ value: 'revisit', label: '回访客户' },
{ value: 'urge', label: '催单跟进' },
{ value: 'logistics', label: '物流跟进' },
{ value: 'aftersales', label: '售后处理' },
{ value: 'repurchase', label: '复购提醒' },
{ value: 'custom-task', label: '自定义任务' },
]
export function taskTypeLabel(type: TaskType): string {
return TASK_TYPES.find((t) => t.value === type)?.label ?? type
}
export const TASK_PRIORITIES: { value: TaskPriority; label: string; color: string }[] = [
{ value: 'high', label: '高', color: 'bg-red-100 text-red-700' },
{ value: 'medium', label: '中', color: 'bg-amber-100 text-amber-700' },
{ value: 'low', label: '低', color: 'bg-gray-100 text-gray-600' },
]
export function taskPriorityMeta(p: TaskPriority) {
return TASK_PRIORITIES.find((x) => x.value === p) ?? TASK_PRIORITIES[1]
}
/** 渠道元信息 */
export const CHANNEL_META: Record<ChannelType, { name: string; color: string; bg: string; desc: string }> = {
whatsapp: { name: 'WhatsApp', color: 'text-emerald-600', bg: 'bg-emerald-50', desc: '海外即时沟通主渠道' },
telegram: { name: 'Telegram', color: 'text-sky-600', bg: 'bg-sky-50', desc: '中东/中亚客户常用' },
messenger: { name: 'Messenger', color: 'text-blue-600', bg: 'bg-blue-50', desc: 'Facebook 私信咨询' },
email: { name: '企业邮箱', color: 'text-gray-600', bg: 'bg-gray-100', desc: '正式商务邮件往来' },
gmail: { name: 'Gmail', color: 'text-red-500', bg: 'bg-red-50', desc: 'Google 邮箱账号' },
outlook: { name: 'Outlook', color: 'text-blue-500', bg: 'bg-blue-50', desc: '微软邮箱账号' },
webform: { name: '独立站表单', color: 'text-violet-600', bg: 'bg-violet-50', desc: '独立站询盘表单' },
website: { name: '官网咨询按钮', color: 'text-teal-600', bg: 'bg-teal-50', desc: '官网在线客服入口' },
landing: { name: '广告落地页', color: 'text-amber-600', bg: 'bg-amber-50', desc: '广告投放线索页面' },
social: { name: '社交媒体主页', color: 'text-pink-600', bg: 'bg-pink-50', desc: '社媒主页私信与留言' },
exhibition: { name: '展会二维码', color: 'text-cyan-600', bg: 'bg-cyan-50', desc: '展会扫码留资' },
api: { name: 'API 接口', color: 'text-slate-600', bg: 'bg-slate-100', desc: '开放 API 对接自有系统' },
webhook: { name: 'Webhook', color: 'text-indigo-600', bg: 'bg-indigo-50', desc: '事件推送到自有服务' },
}
/** 回复语气 */
export const REPLY_TONES = [
{ value: 'professional', label: '专业正式' },
{ value: 'friendly', label: '友好自然' },
{ value: 'concise', label: '简洁直接' },
{ value: 'negotiation', label: '商务谈判' },
{ value: 'comfort', label: '售后安抚' },
{ value: 'urge', label: '催单跟进' },
]
/** 翻译场景 */
export const TRANSLATE_SCENARIOS = [
{ value: 'chat', label: '即时聊天' },
{ value: 'email', label: '商务邮件' },
{ value: 'product', label: '产品介绍' },
{ value: 'quote', label: '报价沟通' },
{ value: 'sample', label: '样品沟通' },
{ value: 'custom', label: '定制要求' },
{ value: 'logistics', label: '物流说明' },
{ value: 'contract', label: '合同沟通' },
{ value: 'aftersales', label: '售后处理' },
]
/** 知识库分类 */
export const KNOWLEDGE_CATEGORIES: { value: KnowledgeCategory; label: string }[] = [
{ value: 'product', label: '产品资料' },
{ value: 'pricing', label: '价格规则' },
{ value: 'moq', label: 'MOQ规则' },
{ value: 'customization', label: '定制说明' },
{ value: 'logistics', label: '物流政策' },
{ value: 'payment', label: '付款方式' },
{ value: 'aftersales', label: '售后政策' },
{ value: 'faq', label: 'FAQ' },
{ value: 'company', label: '企业介绍' },
{ value: 'certification', label: '产品认证' },
{ value: 'success-reply', label: '历史成功回复' },
{ value: 'terminology', label: '行业术语' },
{ value: 'culture', label: '文化注意事项' },
]
export function knowledgeCategoryLabel(c: KnowledgeCategory): string {
return KNOWLEDGE_CATEGORIES.find((x) => x.value === c)?.label ?? c
}
/** 客户常用标签 */
export const CUSTOMER_TAGS = [
'重点客户',
'大客户潜力',
'价格敏感',
'交期敏感',
'需要样品',
'定制需求',
'复购客户',
'展会客户',
'老客户',
'高风险',
'斋月注意',
'决策人直联',
]
/** AI 推荐动作 */
export const NEXT_ACTIONS = [
'发送报价',
'补充资料',
'发送认证文件',
'确认样品',
'询问采购时间',
'回访客户',
'提醒重点跟进',
'售后安抚',
'复购提醒',
]
/** 向导用常用语言清单(中文名) */
export const LANGUAGES_LIST = [
'中文', '英语', '阿拉伯语', '乌尔都语', '孟加拉语', '西班牙语', '葡萄牙语',
'俄语', '法语', '德语', '土耳其语', '越南语', '印尼语', '日语', '韩语',
]
/** 企业主营产品选项 */
export const PRODUCTS = [
'双层玻璃杯 350ml',
'高硼硅玻璃杯 500ml',
'定制Logo玻璃水杯',
'玻璃储物罐套装',
'男士纯棉T恤',
'女士针织开衫',
'运动速干POLO衫',
'TWS蓝牙耳机',
'65W氮化镓充电器',
'智能手表',
'北欧棉麻四件套',
'ins风陶瓷餐具套装',
]