|
|
@@ -199,8 +199,26 @@ const loadIncomeStats = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 获取数据前先销毁旧图表
|
|
|
+ if (chartInstance.value) {
|
|
|
+ try {
|
|
|
+ chartInstance.value.destroy()
|
|
|
+ chartInstance.value = null
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('销毁旧图表实例失败:', e)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const data = await getIncomeStatistics(startDate, endDate, userId)
|
|
|
- incomeStats.value = data
|
|
|
+
|
|
|
+ // 确保数据结构完整
|
|
|
+ incomeStats.value = {
|
|
|
+ dates: data?.dates || [],
|
|
|
+ total: data?.total || [],
|
|
|
+ totalTip: data?.totalTip || [],
|
|
|
+ totalCommission: data?.totalCommission || [],
|
|
|
+ agents: data?.agents || []
|
|
|
+ }
|
|
|
|
|
|
// 渲染图表
|
|
|
renderChart()
|
|
|
@@ -211,88 +229,137 @@ const loadIncomeStats = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 重置画布
|
|
|
+const resetCanvas = () => {
|
|
|
+ const chartContainer = document.querySelector('.chart-wrapper')
|
|
|
+ if (!chartContainer) return null
|
|
|
+
|
|
|
+ // 移除旧画布
|
|
|
+ const oldCanvas = document.getElementById('incomeChart')
|
|
|
+ if (oldCanvas) {
|
|
|
+ oldCanvas.remove()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新画布
|
|
|
+ const newCanvas = document.createElement('canvas')
|
|
|
+ newCanvas.id = 'incomeChart'
|
|
|
+ newCanvas.height = 300
|
|
|
+ chartContainer.appendChild(newCanvas)
|
|
|
+
|
|
|
+ return newCanvas
|
|
|
+}
|
|
|
+
|
|
|
// 渲染图表
|
|
|
const renderChart = () => {
|
|
|
- if (!incomeStats.value) return
|
|
|
-
|
|
|
- const chartElement = document.getElementById('incomeChart')
|
|
|
- if (!chartElement) return
|
|
|
+ if (!incomeStats.value) {
|
|
|
+ console.warn('没有收入统计数据,跳过图表渲染')
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- // 如果已有图表实例,先销毁
|
|
|
- if (chartInstance.value) {
|
|
|
- chartInstance.value.destroy()
|
|
|
- chartInstance.value = null
|
|
|
+ // 重置画布
|
|
|
+ const canvas = resetCanvas()
|
|
|
+ if (!canvas) {
|
|
|
+ console.error('无法创建图表画布')
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- const ctx = chartElement.getContext('2d')
|
|
|
+ // 获取上下文
|
|
|
+ const ctx = canvas.getContext('2d')
|
|
|
+ if (!ctx) {
|
|
|
+ console.error('无法获取图表上下文')
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
// 准备数据并验证
|
|
|
const labels = incomeStats.value.dates || []
|
|
|
- const data = incomeStats.value.total || []
|
|
|
- const tipData = incomeStats.value.totalTip || []
|
|
|
- const commissionData = incomeStats.value.totalCommission || []
|
|
|
-
|
|
|
+
|
|
|
// 验证数据完整性
|
|
|
- if (!labels.length || !data.length) {
|
|
|
- console.warn('图表数据不完整,跳过渲染')
|
|
|
+ if (!labels.length) {
|
|
|
+ console.warn('图表日期数据不完整,跳过渲染')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- const datasets = [
|
|
|
- {
|
|
|
+ // 准备数据集
|
|
|
+ const datasets = []
|
|
|
+
|
|
|
+ // 添加总收入数据集
|
|
|
+ const totalData = incomeStats.value.total || []
|
|
|
+ if (totalData.length > 0) {
|
|
|
+ datasets.push({
|
|
|
label: '总收入',
|
|
|
- data: data,
|
|
|
+ data: [...totalData],
|
|
|
borderColor: '#2563eb',
|
|
|
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
|
|
fill: true,
|
|
|
tension: 0.4
|
|
|
- },
|
|
|
- {
|
|
|
- label: '打赏收入',
|
|
|
- data: tipData,
|
|
|
- borderColor: '#10b981',
|
|
|
- backgroundColor: 'rgba(16, 185, 129, 0.1)',
|
|
|
- fill: true,
|
|
|
- tension: 0.4
|
|
|
- },
|
|
|
- {
|
|
|
- label: '返佣收入',
|
|
|
- data: commissionData,
|
|
|
- borderColor: '#f59e0b',
|
|
|
- backgroundColor: 'rgba(245, 158, 11, 0.1)',
|
|
|
- fill: true,
|
|
|
- tension: 0.4
|
|
|
- }
|
|
|
- ]
|
|
|
+ })
|
|
|
+ }
|
|
|
|
|
|
- // 创建图表
|
|
|
- try {
|
|
|
- chartInstance.value = new Chart(ctx, {
|
|
|
- type: 'line',
|
|
|
- data: { labels, datasets },
|
|
|
- options: {
|
|
|
- responsive: true,
|
|
|
- maintainAspectRatio: false,
|
|
|
- plugins: {
|
|
|
- legend: {
|
|
|
- position: 'top'
|
|
|
- },
|
|
|
- tooltip: {
|
|
|
- mode: 'index',
|
|
|
- intersect: false
|
|
|
- }
|
|
|
+ // 添加打赏收入数据集
|
|
|
+ const tipData = incomeStats.value.totalTip || []
|
|
|
+ datasets.push({
|
|
|
+ label: '打赏收入',
|
|
|
+ data: [...tipData],
|
|
|
+ borderColor: '#10b981',
|
|
|
+ backgroundColor: 'rgba(16, 185, 129, 0.1)',
|
|
|
+ fill: true,
|
|
|
+ tension: 0.4
|
|
|
+ })
|
|
|
+
|
|
|
+ // 添加返佣收入数据集
|
|
|
+ const commissionData = incomeStats.value.totalCommission || []
|
|
|
+ datasets.push({
|
|
|
+ label: '返佣收入',
|
|
|
+ data: [...commissionData],
|
|
|
+ borderColor: '#f59e0b',
|
|
|
+ backgroundColor: 'rgba(245, 158, 11, 0.1)',
|
|
|
+ fill: true,
|
|
|
+ tension: 0.4
|
|
|
+ })
|
|
|
+
|
|
|
+ // 如果没有有效数据集,跳过渲染
|
|
|
+ if (datasets.length === 0) {
|
|
|
+ console.warn('没有有效的数据集,跳过图表渲染')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用requestAnimationFrame确保DOM已更新
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ try {
|
|
|
+ // 创建图表配置
|
|
|
+ const config = {
|
|
|
+ type: 'line',
|
|
|
+ data: {
|
|
|
+ labels: [...labels],
|
|
|
+ datasets: datasets
|
|
|
},
|
|
|
- scales: {
|
|
|
- y: {
|
|
|
- beginAtZero: true
|
|
|
+ options: {
|
|
|
+ responsive: true,
|
|
|
+ maintainAspectRatio: false,
|
|
|
+ plugins: {
|
|
|
+ legend: {
|
|
|
+ position: 'top'
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ mode: 'index',
|
|
|
+ intersect: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ scales: {
|
|
|
+ y: {
|
|
|
+ beginAtZero: true
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- })
|
|
|
- } catch (error) {
|
|
|
- console.error('图表渲染失败:', error)
|
|
|
- chartInstance.value = null
|
|
|
- }
|
|
|
+
|
|
|
+ // 创建图表实例
|
|
|
+ chartInstance.value = new Chart(ctx, config)
|
|
|
+ } catch (error) {
|
|
|
+ console.error('图表渲染失败:', error)
|
|
|
+ chartInstance.value = null
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
// 监听团队选择变化
|