From ca8869db66419a0fa47ae5f92e1b9bd0a57e7e65 Mon Sep 17 00:00:00 2001 From: lbw_9527443 <780139497@qq.com> Date: Thu, 5 Feb 2026 11:31:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(leads):=20=E5=AE=9E=E7=8E=B0=E7=BA=BF?= =?UTF-8?q?=E7=B4=A2=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加线索列表展示、筛选和详情查看功能 - 修改API请求配置,将baseURL设为本地开发地址 - 更新接口类型定义,增加线索相关类型 - 添加加载状态、错误处理和自动刷新逻辑 - 移除系统设置菜单项,专注核心功能 --- 247_Contry/src/api/index.ts | 34 ++++- 247_Contry/src/utils/https.ts | 2 +- 247_Contry/src/views/index/index.vue | 190 ++++++++++++++++++++++++++- 3 files changed, 216 insertions(+), 10 deletions(-) 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]!; });