From ad6d91f78cb97472c445662919d75b8ccade2189 Mon Sep 17 00:00:00 2001 From: wersd <1523826083@qq.com> Date: Thu, 14 Aug 2025 22:37:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A1=B9=E7=9B=AE=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=90=88=E4=BC=99=E4=BA=BA=E6=97=B6=E5=90=88?= =?UTF-8?q?=E4=BC=99=E4=BA=BA=E4=B8=BA=E7=A9=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/crm/project/ProjectForm.vue | 9 ++--- .../project/component/ProjectCompareChart.vue | 34 ++++++++++++------ .../project/component/ProjectMonthlyChart.vue | 34 ++++++++++++------ .../project/component/ProjectPartnerForm.vue | 35 +++++++++++++------ 4 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/views/crm/project/ProjectForm.vue b/src/views/crm/project/ProjectForm.vue index 697a53371..98deb1845 100644 --- a/src/views/crm/project/ProjectForm.vue +++ b/src/views/crm/project/ProjectForm.vue @@ -8,6 +8,7 @@ v-loading="formLoading" > + {{ formData }} - diff --git a/src/views/crm/project/component/ProjectCompareChart.vue b/src/views/crm/project/component/ProjectCompareChart.vue index 0a79917f8..bd7aff443 100644 --- a/src/views/crm/project/component/ProjectCompareChart.vue +++ b/src/views/crm/project/component/ProjectCompareChart.vue @@ -94,19 +94,30 @@ const getChartData = async () => { updateChartOption() } +function toFixed2(val: any) { + if (val === null || val === undefined || isNaN(val)) return val + return Number(val).toFixed(2) +} + function updateChartOption() { // 站点对比,x轴为站点名 const xData = chartData.value.map(item => item.projectName || '-') - const chargingQuantity = chartData.value.map(item => item.chargingQuantity) - const totalIncome = chartData.value.map(item => item.totalIncome) - const grossProfit = chartData.value.map(item => item.grossProfit) - const grossProfitRate = chartData.value.map(item => item.grossProfitRate) - const perGunCharging = chartData.value.map(item => item.perGunCharging) - const perGunProfit = chartData.value.map(item => item.perGunProfit) - const electricityServiceFee = chartData.value.map(item => item.electricityServiceFee) + const chargingQuantity = chartData.value.map(item => toFixed2(item.chargingQuantity)) + const totalIncome = chartData.value.map(item => toFixed2(item.totalIncome)) + const grossProfit = chartData.value.map(item => toFixed2(item.grossProfit)) + const grossProfitRate = chartData.value.map(item => toFixed2(item.grossProfitRate)) + const perGunCharging = chartData.value.map(item => toFixed2(item.perGunCharging)) + const perGunProfit = chartData.value.map(item => toFixed2(item.perGunProfit)) + const electricityServiceFee = chartData.value.map(item => toFixed2(item.electricityServiceFee)) chartOption.value = { - tooltip: { trigger: 'axis' }, + tooltip: { + trigger: 'axis', + valueFormatter: (value: any) => { + if (value === null || value === undefined || value === '' || isNaN(value)) return value + return Number(value).toFixed(2) + } + }, legend: { data: [ '充电量(万度)', '总营收(万元)', '毛利润(万元)', '毛利率(%)', '单枪充电量(度)', '单枪服务费(元)', '度电服务费(元)' @@ -115,8 +126,11 @@ function updateChartOption() { { type: 'category', data: xData, axisTick: { alignWithLabel: true }} ], yAxis: [ - { type: 'value', name: '金额/充电量', position: 'left', min: null, max: null, alignTicks: true }, - { type: 'value', name: '毛利率', position: 'right', min: null, max: null, axisLabel: { formatter: '{value}%' }, alignTicks: true } + { type: 'value', name: '金额/充电量', position: 'left', min: null, max: null, alignTicks: true, + axisLabel: { formatter: (val: any) => (val === null || val === undefined || isNaN(val) ? val : Number(val).toFixed(2)) } + }, + { type: 'value', name: '毛利率', position: 'right', min: null, max: null, + axisLabel: { formatter: (val: any) => (val === null || val === undefined || isNaN(val) ? val : Number(val).toFixed(2) + '%') }, alignTicks: true } ], series: [ { name: '总营收(万元)', type: 'bar', data: totalIncome, yAxisIndex: 0, barMaxWidth: 28 }, diff --git a/src/views/crm/project/component/ProjectMonthlyChart.vue b/src/views/crm/project/component/ProjectMonthlyChart.vue index b98444862..56c7a655b 100644 --- a/src/views/crm/project/component/ProjectMonthlyChart.vue +++ b/src/views/crm/project/component/ProjectMonthlyChart.vue @@ -91,6 +91,11 @@ const getChartData = async () => { updateChartOption() } +function toFixed2(val: any) { + if (val === null || val === undefined || isNaN(val)) return val + return Number(val).toFixed(2) +} + function updateChartOption() { const xData = chartData.value.map(item => { const str = String(item.statMonth) @@ -99,16 +104,22 @@ function updateChartOption() { } return item.statMonth }) - const chargingQuantity = chartData.value.map(item => item.chargingQuantity) - const totalIncome = chartData.value.map(item => item.totalIncome) - const grossProfit = chartData.value.map(item => item.grossProfit) - const grossProfitRate = chartData.value.map(item => item.grossProfitRate) - const perGunCharging = chartData.value.map(item => item.perGunCharging) - const perGunProfit = chartData.value.map(item => item.perGunProfit) - const electricityServiceFee = chartData.value.map(item => item.electricityServiceFee) + const chargingQuantity = chartData.value.map(item => toFixed2(item.chargingQuantity)) + const totalIncome = chartData.value.map(item => toFixed2(item.totalIncome)) + const grossProfit = chartData.value.map(item => toFixed2(item.grossProfit)) + const grossProfitRate = chartData.value.map(item => toFixed2(item.grossProfitRate)) + const perGunCharging = chartData.value.map(item => toFixed2(item.perGunCharging)) + const perGunProfit = chartData.value.map(item => toFixed2(item.perGunProfit)) + const electricityServiceFee = chartData.value.map(item => toFixed2(item.electricityServiceFee)) chartOption.value = { - tooltip: { trigger: 'axis' }, + tooltip: { + trigger: 'axis', + valueFormatter: (value: any) => { + if (value === null || value === undefined || value === '' || isNaN(value)) return value + return Number(value).toFixed(2) + } + }, legend: { data: [ '充电量(万度)', '总营收(万元)', '毛利润(万元)', '毛利率(%)', '单枪充电量(度)', '单枪服务费(元)', '度电服务费(元)' @@ -117,8 +128,11 @@ function updateChartOption() { { type: 'category', data: xData, axisTick: { alignWithLabel: true }} ], yAxis: [ - { type: 'value', name: '金额/充电量', position: 'left', min: null, max: null, alignTicks: true }, // 0: 总营收/毛利润/充电量/单枪充电量/单枪服务费/度电服务费 - { type: 'value', name: '毛利率', position: 'right', min: null, max: null, axisLabel: { formatter: '{value}%' }, alignTicks: true } // 1: 毛利率 + { type: 'value', name: '金额/充电量', position: 'left', min: null, max: null, alignTicks: true, + axisLabel: { formatter: (val: any) => (val === null || val === undefined || isNaN(val) ? val : Number(val).toFixed(2)) } + }, + { type: 'value', name: '毛利率', position: 'right', min: null, max: null, + axisLabel: { formatter: (val: any) => (val === null || val === undefined || isNaN(val) ? val : Number(val).toFixed(2) + '%') }, alignTicks: true } ], series: [ { name: '总营收(万元)', type: 'bar', data: totalIncome, yAxisIndex: 0, barMaxWidth: 28 }, diff --git a/src/views/crm/project/component/ProjectPartnerForm.vue b/src/views/crm/project/component/ProjectPartnerForm.vue index 91ad3040b..e7e328032 100644 --- a/src/views/crm/project/component/ProjectPartnerForm.vue +++ b/src/views/crm/project/component/ProjectPartnerForm.vue @@ -77,7 +77,15 @@ const emit = defineEmits(['update:partners']) const formLoading = ref(false) const userOptions = ref([]) -const formData = ref([]) +const formData = ref([]) +// 监听 formData 变化,自动同步到父组件 +watch( + formData, + (val) => { + emit('update:partners', val) + }, + { deep: true } +) const formRules = reactive({ userId: [ @@ -99,24 +107,29 @@ const formRules = reactive({ }) const formRef = ref(null) + onMounted(async () => { // 获取用户列表 userOptions.value = await UserApi.getSimpleUserList() + // 初始化合伙人数据 + formData.value = Array.isArray(props.partners) ? props.partners.map(item => ({ ...item })) : [] }) + const handleAdd = () => { - formData.value.push() - const row = { - userId: undefined, - ratio: undefined, - investment: undefined - } + const row = { + userId: undefined, + ratio: undefined, + investment: undefined + } formData.value.push(row) + emit('update:partners', formData.value) } const handleDelete = (index: number) => { formData.value.splice(index, 1) + emit('update:partners', formData.value) } const validate = async () => { @@ -142,12 +155,14 @@ const getMaxRatio = (index: number) => { const used = formData.value.reduce((sum, item, idx) => idx !== index ? sum + (Number(item.ratio) || 0) : sum, 0) return Math.max(0, 100 - used) } + +// 只 watch formData,避免递归 watch( - () => props.partners, + formData, (val) => { - formData.value = val || [] + emit('update:partners', val) }, - { immediate: true } + { deep: true } ) defineExpose({ validate })