diff --git a/247_Contry/src/api/index.ts b/247_Contry/src/api/index.ts index d09fc90..b11e78c 100644 --- a/247_Contry/src/api/index.ts +++ b/247_Contry/src/api/index.ts @@ -5,17 +5,45 @@ type AdminUserStatusParams = { max_limit?: number page?: number size?: number - mode?: 'SSE' | 'BLOCK' + mode?: 'SSE' | 'BLOCK' +} + +export type LeadItem = { + hook_user_id: string + id: number + avatar_url: string + sex: number + follow_up_user_id: string + wechat_add_time: string + auto_status: number + is_synced: number + created_at: string + nickname: string + phone: string + follow_up_name: string + source_type: number + status: number + wechat_status: number + extended_info: Record + updated_at: string + last_active_at: string | null +} + +export type LeadListResponse = { + page: number + size: number + total: number + items: LeadItem[] } export const getAdminUserStatus = (params: AdminUserStatusParams = {}) => { - return http.get('/api/v1/admin/user/status', { + return http.get('/api/v1/admin/user/status', { params: { interval: 2, max_limit: 100, page: 1, size: 30, - mode: 'SSE', + mode: 'BLOCK', ...params, }, headers: { diff --git a/247_Contry/src/utils/https.ts b/247_Contry/src/utils/https.ts index bb68eb0..c948f09 100644 --- a/247_Contry/src/utils/https.ts +++ b/247_Contry/src/utils/https.ts @@ -8,7 +8,7 @@ import type { } from 'axios' const http: AxiosInstance = axios.create({ - baseURL: import.meta.env.VITE_API_BASE_URL || '', + baseURL: 'http://127.0.0.1:8000', timeout: 10000, }) diff --git a/247_Contry/src/views/index/index.vue b/247_Contry/src/views/index/index.vue index e64c548..040efd7 100644 --- a/247_Contry/src/views/index/index.vue +++ b/247_Contry/src/views/index/index.vue @@ -10,14 +10,138 @@ -
-
线索管理
-
功能建设中
+
+
+
+
线索管理
+
共 {{ leadsMeta.total }} 条 · 当前 {{ filteredLeads.length }} 条
+
+
+
+ + + +
+ +
+
+ +
+ + 加载中 +
+ +
+ {{ leadsError }} +
+ +
+
+
+ +
+
暂无数据
+
+
+
+ 请选择一个客户查看详情 +
+
+
+
+
+ + {{ (selectedLead.nickname || 'U').slice(0, 1) }} +
+
+
+
{{ selectedLead.nickname || '未命名' }}
+
{{ selectedLead.hook_user_id }}
+
+
+
+ {{ sourceTypeLabel(selectedLead.source_type) }} + status: {{ selectedLead.status }} + wx: {{ selectedLead.wechat_status }} + auto: {{ selectedLead.auto_status }} + sync: {{ selectedLead.is_synced }} +
+
+
+ 手机号 + {{ selectedLead.phone || '-' }} +
+
+ 跟进人 + {{ selectedLead.follow_up_name || '-' }} +
+
+ 跟进人ID + {{ selectedLead.follow_up_user_id || '-' }} +
+
+ 添加时间 + {{ formatTime(selectedLead.wechat_add_time) }} +
+
+ 最后活跃 + {{ formatTime(selectedLead.last_active_at) }} +
+
+ 创建时间 + {{ formatTime(selectedLead.created_at) }} +
+
+ 更新时间 + {{ formatTime(selectedLead.updated_at) }} +
+
+
+
+
-
+
@@ -32,6 +156,8 @@ import SidebarNav from './components/SidebarNav.vue'; import DashboardView from './components/DashboardView.vue'; import StrategyView from './components/StrategyView.vue'; import MonitorView from './components/MonitorView.vue'; +import { getAdminUserStatus } from '@/api'; +import type { LeadListResponse, LeadItem } from '@/api'; const router = useRouter(); const route = useRoute(); @@ -46,7 +172,7 @@ const navItems = [ { id: 'monitor', label: '会话监控', icon: 'ph-chats-teardrop' }, { id: 'strategy', label: 'SOP配置', icon: 'ph-sliders-horizontal' }, { id: 'leads', label: '线索管理', icon: 'ph-users' }, - { id: 'system', label: '系统设置', icon: 'ph-gear' } + // { id: 'system', label: '系统设置', icon: 'ph-gear' } ]; const handleSelect = (id: string) => { @@ -55,6 +181,52 @@ const handleSelect = (id: string) => { } }; +const leadData = ref(null); +const leadsLoading = ref(false); +const leadsError = ref(''); +const leadsItems = computed(() => leadData.value?.items ?? []); +const leadsMeta = computed(() => ({ + page: leadData.value?.page ?? 1, + size: leadData.value?.size ?? 30, + total: leadData.value?.total ?? 0, +})); +const leadsFilter = ref<'all' | 'external' | 'internal'>('all'); +const selectedLead = ref(null); +const filteredLeads = computed(() => { + if (leadsFilter.value === 'external') { + return leadsItems.value.filter((item) => item.source_type === 1); + } + if (leadsFilter.value === 'internal') { + return leadsItems.value.filter((item) => item.source_type === 0); + } + return leadsItems.value; +}); + +const normalizeAvatarUrl = (url: string) => url.replace(/`/g, '').trim(); +const sourceTypeLabel = (value: number) => (value === 1 ? '外部联系人' : '内部联系人'); + +const formatTime = (value: string | null) => { + if (!value) return '-'; + const date = new Date(value); + return Number.isNaN(date.getTime()) ? value : date.toLocaleString(); +}; + +const fetchLeads = async () => { + if (leadsLoading.value) return; + leadsLoading.value = true; + leadsError.value = ''; + try { + leadData.value = await getAdminUserStatus(); + if (!selectedLead.value && leadData.value.items.length > 0) { + selectedLead.value = leadData.value.items[0] ?? null; + } + } catch (error) { + leadsError.value = error instanceof Error ? error.message : '请求失败'; + } finally { + leadsLoading.value = false; + } +}; + // 1. 销售阶段 (SOP) const salesStages = [ { id: 'connect', name: '1. 浅建联 (加微/破冰)', desc: '初步接触,建立信任,发送欢迎语' }, @@ -121,6 +293,12 @@ watch(currentStageId, (newId) => { } }, { immediate: true }); +watch(currentView, (value) => { + if (value === 'leads' && !leadData.value) { + fetchLeads(); + } +}, { immediate: true }); + const currentConfig = computed((): Config => { return configs.value[currentStageId.value]!; });