| | |
| | | <template> |
| | | <div style="padding: 20px;"> |
| | | <!-- 页面标题和日期筛选 --> |
| | | <!-- 页面标题和月份筛选 --> |
| | | <div class="w-full md:w-auto flex items-center gap-3" style="margin-bottom: 20px;"> |
| | | <el-date-picker |
| | | v-model="dateRange" |
| | | type="daterange" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | type="monthrange" |
| | | format="YYYY-MM" |
| | | value-format="YYYY-MM" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | clearable |
| | | start-placeholder="开始月份" |
| | | end-placeholder="结束月份" |
| | | @change="handleDateChange" |
| | | class="w-full md:w-auto" |
| | | style="margin-right: 30px;" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted, reactive } from 'vue'; |
| | | import { ref, computed, onMounted, reactive, nextTick } from 'vue'; |
| | | import 'element-plus/dist/index.css'; |
| | | import Echarts from "@/components/Echarts/echarts.vue"; |
| | | import { reportForms,reportIncome,reportExpense } from "@/api/financialManagement/financialStatements"; |
| | |
| | | left: '60%', |
| | | orient: 'vertical', |
| | | icon: 'circle', |
| | | data: pieData0.value.map(item => item.name), |
| | | data: (pieData0.value || []).filter(item => item && item.name).map(item => item.name), |
| | | formatter: function(name) { |
| | | const item = pieData0.value.find(i => i.name === name); |
| | | if (!name) return ''; |
| | | const item = pieData0.value.find(i => i && i.name === name); |
| | | if (!item) return name; |
| | | return `${name} | ${item.percent} ${item.amount}`; |
| | | }, |
| | |
| | | left: '60%', |
| | | orient: 'vertical', |
| | | icon: 'circle', |
| | | data: pieData1.value.map(item => item.name), |
| | | data: (pieData1.value || []).filter(item => item && item.name).map(item => item.name), |
| | | formatter: function(name) { |
| | | const item = pieData1.value.find(i => i.name === name); |
| | | if (!name) return ''; |
| | | const item = pieData1.value.find(i => i && i.name === name); |
| | | if (!item) return name; |
| | | return `${name} | ${item.percent} ${item.amount}`; |
| | | }, |
| | |
| | | label: { |
| | | show: false |
| | | }, |
| | | data: pieData0.value, |
| | | data: (pieData0.value || []).filter(item => item && item.name), |
| | | color: pieColors |
| | | } |
| | | ]); |
| | |
| | | label: { |
| | | show: false |
| | | }, |
| | | data: pieData1.value, |
| | | data: (pieData1.value || []).filter(item => item && item.name), |
| | | color: pieColors |
| | | } |
| | | ]); |
| | |
| | | const pageInfo = ref({ |
| | | }) |
| | | |
| | | // 获取最近六个月的范围 |
| | | const getLastSixMonths = () => { |
| | | const endMonth = dayjs().format('YYYY-MM'); |
| | | const startMonth = dayjs().subtract(5, 'month').format('YYYY-MM'); |
| | | return [startMonth, endMonth]; |
| | | }; |
| | | |
| | | const getData = async () => { |
| | | if (!dateRange.value || !dateRange.value.length) { |
| | | if (!dateRange.value || !Array.isArray(dateRange.value) || dateRange.value.length !== 2) { |
| | | return; |
| | | } |
| | | const startDateStr = dateRange.value[0]; |
| | | const endDateStr = dateRange.value[1]; |
| | | if (!startDateStr || !endDateStr) { |
| | | return; |
| | | } |
| | | |
| | | // 验证日期格式并转换为完整日期 |
| | | const startDate = dayjs(startDateStr); |
| | | const endDate = dayjs(endDateStr); |
| | | if (!startDate.isValid() || !endDate.isValid()) { |
| | | console.error('无效的日期格式'); |
| | | return; |
| | | } |
| | | |
| | | // 开始月份拼接第一天,结束月份拼接最后一天 |
| | | const entryDateStart = startDate.startOf('month').format('YYYY-MM-DD'); |
| | | const entryDateEnd = endDate.endOf('month').format('YYYY-MM-DD'); |
| | | |
| | | try { |
| | | const {code,data} = await reportForms({entryDateStart:dateRange.value[0], entryDateEnd:dateRange.value[1]}); |
| | | if(code === 200) { |
| | | pageInfo.value = data |
| | | pieData0.value = data.incomeType.map(item=>({ |
| | | name:item.typeName, |
| | | value:item.account, |
| | | percent:`${item.proportion*100}%`, |
| | | amount:`¥${item.account}` |
| | | const {code,data} = await reportForms({entryDateStart, entryDateEnd}); |
| | | if(code === 200 && data) { |
| | | pageInfo.value = data || {}; |
| | | // 安全处理数据,过滤掉 null 或 undefined |
| | | pieData0.value = (data.incomeType || []).filter(item => item && item.typeName).map(item=>({ |
| | | name:item.typeName || '', |
| | | value:item.account || 0, |
| | | percent:`${((item.proportion || 0) * 100).toFixed(2)}%`, |
| | | amount:`¥${(item.account || 0).toFixed(2)}` |
| | | })) |
| | | pieData1.value = data.expenseType.map(item=>({ |
| | | name:item.typeName, |
| | | value:item.account, |
| | | percent:`${item.proportion*100}%`, |
| | | amount:`¥${item.account}` |
| | | pieData1.value = (data.expenseType || []).filter(item => item && item.typeName).map(item=>({ |
| | | name:item.typeName || '', |
| | | value:item.account || 0, |
| | | percent:`${((item.proportion || 0) * 100).toFixed(2)}%`, |
| | | amount:`¥${(item.account || 0).toFixed(2)}` |
| | | })) |
| | | |
| | | } |
| | | } catch (error) { |
| | | console.error('获取财务指标数据失败:', error); |
| | | } |
| | | try{ |
| | | const {code,data} = await reportIncome(); |
| | | if(code==200){ |
| | | lineSeries0.value = data.map(item=>({ |
| | | name:item.typeName, |
| | | const {code,data} = await reportIncome({entryDateStart, entryDateEnd}); |
| | | if(code==200 && data && Array.isArray(data)){ |
| | | lineSeries0.value = data.filter(item => item && item.typeName).map(item=>({ |
| | | name:item.typeName || '', |
| | | type: 'line', |
| | | data:item.account.map(item=>Number(item)) |
| | | data:(item.account || []).map(val => Number(val) || 0) |
| | | })) |
| | | |
| | | } |
| | | }catch (error) { |
| | | console.error('获取财务指标数据失败:', error); |
| | | } |
| | | try{ |
| | | const {code,data} = await reportExpense(); |
| | | if(code==200){ |
| | | lineSeries1.value = data.map(item=>({ |
| | | name:item.typeName, |
| | | const {code,data} = await reportExpense({entryDateStart, entryDateEnd}); |
| | | if(code==200 && data && Array.isArray(data)){ |
| | | lineSeries1.value = data.filter(item => item && item.typeName).map(item=>({ |
| | | name:item.typeName || '', |
| | | type: 'line', |
| | | data:item.account.map(item=>Number(item)) |
| | | data:(item.account || []).map(val => Number(val) || 0) |
| | | })) |
| | | |
| | | } |
| | | }catch (error) { |
| | | console.error('获取财务指标数据失败:', error); |
| | |
| | | |
| | | // 初始化 |
| | | onMounted(() => { |
| | | // 不设置默认日期,由用户手动选择 |
| | | // 设置默认值为最近六个月 |
| | | const defaultRange = getLastSixMonths(); |
| | | dateRange.value = defaultRange; |
| | | // 使用 nextTick 确保组件完全渲染后再调用 |
| | | nextTick(() => { |
| | | getData(); |
| | | }); |
| | | }); |
| | | |
| | | // 处理日期范围变化 |
| | | // 处理月份范围变化 |
| | | const handleDateChange = (newRange) => { |
| | | dateRange.value = newRange; |
| | | if (newRange && newRange.length === 2) { |
| | | getData() |
| | | if (!newRange || !Array.isArray(newRange) || newRange.length !== 2) { |
| | | return; |
| | | } |
| | | dateRange.value = newRange; |
| | | getData(); |
| | | }; |
| | | |
| | | // 重置日期范围 |
| | | // 重置月份范围 |
| | | const resetDateRange = () => { |
| | | dateRange.value = null; |
| | | // 重置为最近六个月 |
| | | dateRange.value = getLastSixMonths(); |
| | | getData(); |
| | | }; |
| | | |
| | | </script> |