diff --git a/my-vue-app/src/views/person/components/PersonalDashboard.vue b/my-vue-app/src/views/person/components/PersonalDashboard.vue index 0ab5ff4..a2403f8 100644 --- a/my-vue-app/src/views/person/components/PersonalDashboard.vue +++ b/my-vue-app/src/views/person/components/PersonalDashboard.vue @@ -263,6 +263,9 @@ async function CenterGetSecondOrderAnalysisReport(time) { // Chart.js 实例 const chartInstances = {}; +// 添加组件挂载状态跟踪 +const isComponentMounted = ref(true); + // DOM 元素引用 const personalFunnelChartCanvas = ref(null); const contactTimeChartCanvas = ref(null); @@ -288,7 +291,7 @@ const kpiDescriptions = { }, avgDuration: { title: '平均通话时长', - description: '所有通话总时长 ÷ 拨打电话次数。' + description: '所有通话总时长 ÷ 拨打的电话次数。' }, conversionRate: { title: '成交转化率', @@ -327,7 +330,8 @@ const createOrUpdateChart = (chartId, canvasRef, config) => { if (chartInstances[chartId]) { chartInstances[chartId].destroy(); } - if (canvasRef.value) { + // 确保组件仍然挂载且canvas引用存在 + if (isComponentMounted.value && canvasRef.value) { const ctx = canvasRef.value.getContext('2d'); chartInstances[chartId] = new Chart(ctx, config); } @@ -335,6 +339,9 @@ const createOrUpdateChart = (chartId, canvasRef, config) => { // Chart.js: 渲染销售漏斗图 const renderPersonalFunnelChart = () => { + // 确保组件仍然挂载 + if (!isComponentMounted.value) return; + const config = { type: 'bar', data: { @@ -359,6 +366,9 @@ const renderPersonalFunnelChart = () => { // Chart.js: 渲染黄金联络时段图 const renderContactTimeChart = () => { + // 确保组件仍然挂载 + if (!isComponentMounted.value) return; + if (!props.contactTimeData || !props.contactTimeData.gold_contact_success_rate) { return; } @@ -450,11 +460,13 @@ watch(() => props.contactTimeData, () => { // --- 生命周期钩子 --- onMounted(() => { + isComponentMounted.value = true; renderPersonalFunnelChart(); renderContactTimeChart(); }); onBeforeUnmount(() => { + isComponentMounted.value = false; Object.values(chartInstances).forEach(chart => chart.destroy()); }); diff --git a/my-vue-app/src/views/person/sale.vue b/my-vue-app/src/views/person/sale.vue index 5b6e1a2..8e6388c 100644 --- a/my-vue-app/src/views/person/sale.vue +++ b/my-vue-app/src/views/person/sale.vue @@ -920,19 +920,6 @@ async function CenterGetSalesFunnel() { const res = await getSalesFunnel(hasParams ? params : undefined) if(res.code === 200){ SalesFunnel.value = res.data - /** - * "data": { - "user_name": "常琳", - "user_level": 1, - "sale_funnel": { - "线索总数": 11, - "有效沟通": 9, - "到课数据": 8, - "预付定金": 0, - "成功签单": 0 - } - } - */ } } // 黄金联络时间段 diff --git a/my-vue-app/src/views/senorManger/components/CustomerDetail.vue b/my-vue-app/src/views/senorManger/components/CustomerDetail.vue index c23b3eb..242b89a 100644 --- a/my-vue-app/src/views/senorManger/components/CustomerDetail.vue +++ b/my-vue-app/src/views/senorManger/components/CustomerDetail.vue @@ -27,18 +27,25 @@ const contextPanelRef = ref(null); const sentimentChartCanvas = ref(null); const chartInstances = {}; +// 添加组件挂载状态跟踪 +const isComponentMounted = ref(true); + // CHARTING const createOrUpdateChart = (chartId, canvasRef, config) => { if (chartInstances[chartId]) { chartInstances[chartId].destroy(); } - if (canvasRef.value) { + // 确保组件仍然挂载且canvas引用存在 + if (isComponentMounted.value && canvasRef.value) { const ctx = canvasRef.value.getContext('2d'); chartInstances[chartId] = new Chart(ctx, config); } }; const renderSentimentChart = (history) => { + // 确保组件仍然挂载 + if (!isComponentMounted.value) return; + if (!sentimentChartCanvas.value) return; const ctx = sentimentChartCanvas.value.getContext('2d'); const gradient = ctx.createLinearGradient(0, 0, 0, 120); @@ -126,6 +133,21 @@ watch(() => props.selectedContact, (newContact) => { }); } }, { immediate: true }); + +// LIFECYCLE HOOKS +onMounted(() => { + isComponentMounted.value = true; +}); + +onBeforeUnmount(() => { + isComponentMounted.value = false; + // 清理所有图表实例 + Object.values(chartInstances).forEach(chart => { + if (chart) { + chart.destroy(); + } + }); +});