From 973574fd62a1a130a1c229f812e70cfe3763b48e Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 14 十月 2026 09:54:10 +0800
Subject: [PATCH] feat(bi): 增加CRM数据展示功能并优化图表组件
---
src/views/bi/dashboard/index.vue | 38 +++++++++++++++++++++++++++++---------
1 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/src/views/bi/dashboard/index.vue b/src/views/bi/dashboard/index.vue
index c1bbf5c..70b9437 100644
--- a/src/views/bi/dashboard/index.vue
+++ b/src/views/bi/dashboard/index.vue
@@ -23,27 +23,41 @@
const charts = ref<BiDashboardApi.ChartItem[]>([]);
const loading = ref(true);
const lastUpdateTime = ref('');
+let dataRefreshTimer: ReturnType<typeof setInterval> | undefined;
-async function loadData() {
+async function loadData(background = false) {
if (!meta.value) return;
+ if (!background && dataRefreshTimer) clearInterval(dataRefreshTimer);
try {
- loading.value = true;
+ if (!background) loading.value = true;
const data = await getDashboardData(meta.value.code);
charts.value = data.length > 0 ? data : getDefaultCharts();
lastUpdateTime.value = new Date().toLocaleTimeString('zh-CN', { hour12: false });
} catch {
- charts.value = getDefaultCharts();
+ if (!background) charts.value = getDefaultCharts();
} finally {
loading.value = false;
await nextTick();
resizeAllCharts();
+ if (!background && dashboardCode.value === 'purchase-sales') {
+ const intervals = charts.value.map((chart) => chart.refreshInterval).filter((interval) => interval > 0);
+ if (intervals.length) dataRefreshTimer = setInterval(() => {
+ if (!loading.value && document.visibilityState === 'visible') loadData(true);
+ }, Math.max(15, Math.min(...intervals)) * 1000);
+ }
}
}
// ======== 鍒嗙被 ========
-const numberCards = computed(() => charts.value.filter((c) => c.chartType === 'number'));
-const tableCharts = computed(() => charts.value.filter((c) => c.chartType === 'table'));
-const echartsCharts = computed(() => charts.value.filter((c) => !['number', 'table'].includes(c.chartType)));
+const displayCharts = computed(() => {
+ if (dashboardCode.value !== 'purchase-sales') return charts.value;
+ return [...charts.value].sort((a, b) =>
+ Number(b.chartOptions?.dashboardSection === 'crm') - Number(a.chartOptions?.dashboardSection === 'crm'),
+ );
+});
+const numberCards = computed(() => displayCharts.value.filter((c) => c.chartType === 'number'));
+const tableCharts = computed(() => displayCharts.value.filter((c) => c.chartType === 'table'));
+const echartsCharts = computed(() => displayCharts.value.filter((c) => !['number', 'table'].includes(c.chartType)));
// ======== 鍥捐〃 Grid 鍒楄法搴� ========
function isFullWidth(chart: BiDashboardApi.ChartItem): boolean {
@@ -102,6 +116,7 @@
const progress = Math.min((currentTime - startTime) / duration, 1);
const eased = 1 - (1 - progress) ** 3;
el.textContent = (end * eased).toFixed(decimals);
+ if (progress === 1) el.textContent = formatNumber(end);
if (progress < 1) requestAnimationFrame(update);
}
requestAnimationFrame(update);
@@ -110,7 +125,7 @@
function maybeAnimate(el: HTMLElement, cardId: number, value: number) {
if (animatedIds.has(cardId)) return;
animatedIds.add(cardId);
- animateValue(el, value, 0);
+ animateValue(el, value, Number.isInteger(value) ? 0 : 2);
}
watch(() => charts.value, () => {
@@ -157,6 +172,10 @@
// ======== KPI 鍥炬爣/棰滆壊 ========
function getKpiIcon(name: string): string {
+ if (name.includes('瀹㈡埛')) return 'lucide:users';
+ if (name.includes('鍟嗘満')) return 'lucide:target';
+ if (name.includes('鍥炴')) return 'lucide:wallet';
+ if (name.includes('鎶ヤ环')) return 'lucide:receipt-text';
if (name.includes('閲囪喘')) return 'lucide:shopping-cart';
if (name.includes('閿�鍞�')) return 'lucide:trending-up';
if (name.includes('鍞悗')) return 'lucide:headphones';
@@ -181,6 +200,7 @@
loadData();
});
onBeforeUnmount(() => {
+ if (dataRefreshTimer) clearInterval(dataRefreshTimer);
document.removeEventListener('fullscreenchange', onFullscreenChange);
resizeObserver?.disconnect();
});
@@ -249,7 +269,7 @@
<IconifyIcon :icon="getKpiIcon(card.name)" />
</div>
<div class="kpi-body">
- <span class="kpi-label">{{ card.name }}</span>
+ <span class="kpi-label" :title="card.name">{{ card.name }}</span>
<span
class="kpi-value"
:ref="(el: unknown) => {
@@ -514,7 +534,7 @@
.kpi-label {
font-size: 11px; color: var(--text-secondary); letter-spacing: 0.3px;
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
+ white-space: normal; overflow-wrap: anywhere; line-height: 1.4;
}
.kpi-value {
--
Gitblit v1.9.3