From 9aae2af6f3937a7d99ec619b51f457002cef969f Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期一, 03 十一月 2025 14:29:37 +0800
Subject: [PATCH] 档案管理-添加导出功能
---
src/views/financialManagement/financialStatements/index.vue | 511 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 510 insertions(+), 1 deletions(-)
diff --git a/src/views/financialManagement/financialStatements/index.vue b/src/views/financialManagement/financialStatements/index.vue
index c272707..430fe6a 100644
--- a/src/views/financialManagement/financialStatements/index.vue
+++ b/src/views/financialManagement/financialStatements/index.vue
@@ -1,4 +1,513 @@
<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"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ :default-value="[new Date(firstDayOfMonth), new Date()]"
+ @change="handleDateChange"
+ class="w-full md:w-auto"
+ style="margin-right: 30px;"
+ />
+
+ <el-button
+ type="primary"
+ icon="Refresh"
+ @click="resetDateRange"
+ size="default"
+ >
+ 閲嶇疆
+ </el-button>
+ </div>
+
+ <main class="container mx-auto px-4 pb-10">
+ <!-- 璐㈠姟鎸囨爣鍗$墖 -->
+ <div class="grid-container">
+ <!-- 鎬绘敹鍏� -->
+ <el-card class="bg1">
+ <p>鎬绘敹鍏�</p>
+ <h3>
+ 楼{{ pageInfo.totalIncome }}
+ </h3>
+ </el-card>
+
+ <!-- 鏀跺叆绗旀暟 -->
+ <el-card class="bg2">
+ <p>鏀跺叆绗旀暟</p>
+ <h3>
+ {{ pageInfo.incomeNumber }}
+ </h3>
+ </el-card>
+
+ <!-- 鎬绘敮鍑� -->
+ <el-card class="bg3">
+ <p>鎬绘敮鍑�</p>
+ <h3>
+ 楼{{ pageInfo.totalExpense }}
+ </h3>
+ </el-card>
+
+ <!-- 鏀嚭绗旀暟 -->
+ <el-card class="bg4">
+ <p>鏀嚭绗旀暟</p>
+ <h3>
+ {{ pageInfo.expenseNumber }}
+ </h3>
+ </el-card>
+
+ <!-- 鍑�鏀跺叆 -->
+ <el-card class="bg5">
+ <p>鍑�鏀跺叆</p>
+ <h3>
+ 楼{{ pageInfo.netRevenue }}
+ </h3>
+ </el-card>
+ </div>
+
+ <!-- 鏀跺叆缁熻鍥捐〃 -->
+ <div class="grid-layout">
+ <el-card style="margin-bottom: 20px;">
+ <h2 class="section-title">鏀跺叆缁熻(鍏�)</h2>
+ <div class="echarts">
+ <Echarts :legend="pieLegend0" :chartStyle="chartStylePie"
+ :series="materialPieSeries0"
+ :tooltip="pieTooltip" style="height: 260px;width: 35%;">
+ <div class="chart-num">
+ <span style="font-size: 22px;">鏀跺叆</span>
+ <span style="font-size: 36px;
+ font-weight: 500;
+ font-family: 'MyCustomFont', sans-serif;">{{ pageInfo.totalIncome }}</span>
+ </div>
+ </Echarts>
+ <Echarts ref="chart"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="lineLegend"
+ :series="lineSeries0"
+ :tooltip="tooltip"
+ :xAxis="xAxis0"
+ :yAxis="yAxis0"
+ style="height: 260px;width: 64%;"></Echarts>
+ </div>
+ </el-card>
+
+ <!-- 鏀嚭缁熻鍥捐〃 -->
+ <el-card>
+ <h2 class="section-title">鏀嚭缁熻(鍏�)</h2>
+ <div class="echarts">
+ <Echarts ref="chart"
+ :legend="pieLegend1"
+ :chartStyle="chartStylePie"
+ :series="materialPieSeries1"
+ :tooltip="pieTooltip"
+ style="height: 260px;width: 35%;">
+ <div class="chart-num">
+ <span style="font-size: 22px;">鏀嚭</span>
+ <span style="font-size: 36px;
+ font-weight: 500;
+ font-family: 'MyCustomFont', sans-serif;">{{ pageInfo.totalExpense }}</span>
+ </div></Echarts>
+ <Echarts ref="chart"
+ :chartStyle="chartStyle"
+ :grid="grid"
+ :legend="lineLegend"
+ :series="lineSeries1"
+ :tooltip="tooltip"
+ :xAxis="xAxis1"
+ :yAxis="yAxis1"
+ style="height: 260px;width: 64%;"></Echarts>
+ </div>
+ </el-card>
+ </div>
+ </main>
+ </div>
</template>
+
<script setup>
-</script>
\ No newline at end of file
+import { ref, computed, onMounted, reactive } from 'vue';
+import 'element-plus/dist/index.css';
+import Echarts from "@/components/Echarts/echarts.vue";
+import { reportForms,reportIncome,reportExpense } from "@/api/financialManagement/financialStatements";
+import dayjs from "dayjs";
+
+// 鏃ユ湡鑼冨洿
+const dateRange = ref([]);
+const firstDayOfMonth = ref(null);
+const chartStyle = {
+ width: '100%',
+ height: '100%', // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+ position:'relative',
+}
+const grid = {
+ left: '3%',
+ right: '4%',
+ bottom: '3%',
+ containLabel: true
+}
+const lineLegend = {
+ show: false,
+}
+// 鎶樼嚎鍥炬彁绀烘
+const tooltip = reactive({
+ trigger: 'axis',
+ axisPointer: {
+ type: 'line',
+ lineStyle: { color: '#aaa' }
+ },
+ // 鑷畾涔夊唴瀹�
+ formatter: function (params) {
+ if (!params || !params.length) return ''
+ const axisLabel = params[0].axisValueLabel || params[0].axisValue || ''
+ const rows = params
+ .map(p => {
+ const colorDot = `<span style="display:inline-block;margin-right:6px;width:8px;height:8px;border-radius:50%;background:${p.color}"></span>`
+ return `${colorDot}${p.seriesName}: ${p.value}`
+ })
+ .join('<br/>')
+ return `<div>${axisLabel}</div><div>${rows}</div>`
+ }
+})
+const months = ['1鏈�','2鏈�','3鏈�','4鏈�','5鏈�','6鏈�','7鏈�','8鏈�','9鏈�','10鏈�','11鏈�','12鏈�'];
+const lineSeries0 = ref([])
+const lineSeries1 = ref([])
+
+const xAxis0 = ref([
+ {
+ type: 'category',
+ axisTick: { show: true, alignWithLabel: true },
+ data: months,
+ },
+]);
+const xAxis1 = ref([
+ {
+ type: 'category',
+ axisTick: { show: true, alignWithLabel: true },
+ data: months,
+ },
+]);
+const yAxis0 = [
+{
+ type: 'value',
+ name: '鏀跺叆缁熻', // 宸︿晶y杞�
+ position: 'left',
+ min: 0,
+ // 鍧愭爣杞村悕绉版牱寮�
+ nameTextStyle: {
+ color: '#000',
+ fontSize: 14,
+ },
+ }
+]
+
+const yAxis1 = [
+{
+ type: 'value',
+ name: '鏀嚭缁熻', // 宸︿晶y杞�
+ position: 'left',
+ min: 0,
+ // 鍧愭爣杞村悕绉版牱寮�
+ nameTextStyle: {
+ color: '#000',
+ fontSize: 14,
+ },
+ }
+]
+
+const chartStylePie = {
+ width: '100%',
+ height: '100%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+}
+const pieColors = ['#F04864','#FACC14', '#8543E0', '#1890FF', '#13C2C2','#2FC25B']; // 鍙牴鎹疄闄呰皟鏁�
+const pieData0 = ref([]);
+const pieData1 = ref([]);
+
+const pieLegend0 = computed(() => ({
+ show: true,
+ top: 'center',
+ left: '60%',
+ orient: 'vertical',
+ icon: 'circle',
+ data: pieData0.value.map(item => item.name),
+ formatter: function(name) {
+ const item = pieData0.value.find(i => i.name === name);
+ if (!item) return name;
+ return `${name} | ${item.percent} ${item.amount}`;
+ },
+ textStyle: {
+ color: '#333',
+ fontSize: 14,
+ lineHeight: 26,
+ }
+}));
+const pieLegend1 = computed(() => ({
+ show: true,
+ top: 'center',
+ left: '60%',
+ orient: 'vertical',
+ icon: 'circle',
+ data: pieData1.value.map(item => item.name),
+ formatter: function(name) {
+ const item = pieData1.value.find(i => i.name === name);
+ if (!item) return name;
+ return `${name} | ${item.percent} ${item.amount}`;
+ },
+ textStyle: {
+ color: '#333',
+ fontSize: 14,
+ lineHeight: 26,
+ }
+}));
+
+const materialPieSeries0 = computed(() => [
+ {
+ type: 'pie',
+ radius: ['50%', '65%'],
+ center: ['25%', '50%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: {
+ show: false
+ },
+ data: pieData0.value,
+ color: pieColors
+ }
+]);
+const materialPieSeries1 = computed(() => [
+ {
+ type: 'pie',
+ radius: ['50%', '65%'],
+ center: ['25%', '50%'],
+ avoidLabelOverlap: false,
+ itemStyle: {
+ borderColor: '#fff',
+ borderWidth: 2
+ },
+ label: {
+ show: false
+ },
+ data: pieData1.value,
+ color: pieColors
+ }
+]);
+const pieTooltip = reactive({
+ trigger: 'item',
+ formatter: function(params) {
+ // 妫�鏌ユ暟鎹槸鍚﹀瓨鍦�
+ if (!params.data) return params.name;
+ // 鎷兼帴瀹屾暣鍐呭
+ return `
+ <div>
+ <div style="color:${params.color};font-size:16px;">鈼�</div>
+ <div>${params.name}</div>
+ <div>鍗犳瘮锛�${params.data.percent}</div>
+ <div>閲戦锛�${params.data.amount}</div>
+ </div>
+ `;
+ }
+})
+
+
+const pageInfo = ref({
+})
+
+const getData = async () => {
+ 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}`
+ }))
+ pieData1.value = data.expenseType.map(item=>({
+ name:item.typeName,
+ value:item.account,
+ percent:`${item.proportion*100}%`,
+ amount:`楼${item.account}`
+ }))
+
+ }
+ } catch (error) {
+ console.error('鑾峰彇璐㈠姟鎸囨爣鏁版嵁澶辫触锛�', error);
+ }
+ try{
+ const {code,data} = await reportIncome();
+ if(code==200){
+ lineSeries0.value = data.map(item=>({
+ name:item.typeName,
+ type: 'line',
+ data:item.account.map(item=>Number(item))
+ }))
+
+ }
+ }catch (error) {
+ console.error('鑾峰彇璐㈠姟鎸囨爣鏁版嵁澶辫触锛�', error);
+ }
+ try{
+ const {code,data} = await reportExpense();
+ if(code==200){
+ lineSeries1.value = data.map(item=>({
+ name:item.typeName,
+ type: 'line',
+ data:item.account.map(item=>Number(item))
+ }))
+
+ }
+ }catch (error) {
+ console.error('鑾峰彇璐㈠姟鎸囨爣鏁版嵁澶辫触锛�', error);
+ }
+};
+
+
+// 鍒濆鍖栨棩鏈熻寖鍥达紙榛樿褰撴湀锛�
+onMounted(() => {
+ const today = new Date();
+ const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
+ firstDayOfMonth.value = firstDay;
+ dateRange.value = [dayjs(firstDay).format("YYYY-MM-DD"), dayjs(today).format("YYYY-MM-DD")];
+ getData()
+
+});
+
+// 澶勭悊鏃ユ湡鑼冨洿鍙樺寲
+const handleDateChange = (newRange) => {
+ if (newRange && newRange.length === 2) {
+ dateRange.value = newRange;
+ getData()
+ }
+};
+
+// 閲嶇疆鏃ユ湡鑼冨洿
+const resetDateRange = () => {
+ const today = new Date();
+ const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
+ dateRange.value = [dayjs(firstDay).format("YYYY-MM-DD"), dayjs(today).format("YYYY-MM-DD")];
+ getData()
+};
+
+</script>
+
+<style scoped lang="scss">
+/* 鍩虹鏍峰紡琛ュ厖 */
+:root {
+ --el-color-primary: #4f46e5;
+}
+.el-card{
+ position: relative;
+ border-radius: 12px;
+ padding: 14px 10px 10px 10px;
+ box-shadow: 0 2px 8px #eee;
+ :deep(.el-card__body){
+ padding: 10px 20px !important;
+ }
+ &.bg1{
+ background: url(@/assets/icons/png/1.png) no-repeat 100% 100% !important;
+ }
+ &.bg2{
+ background: url(@/assets/icons/png/2.png) no-repeat 100% 100% !important;
+ }
+ &.bg3{
+ background: url(@/assets/icons/png/3.png) no-repeat 100% 100% !important;
+ }
+ &.bg4{
+ background: url(@/assets/icons/png/4.png) no-repeat 100% 100% !important;
+ }
+ &.bg5{
+ background: url(@/assets/icons/png/5.png) no-repeat 100% 100% !important;
+ }
+}
+
+.grid-container {
+ /* grid 瀹瑰櫒鍩虹鏍峰紡 */
+ display: grid;
+ gap: 1rem; /* gap-4 瀵瑰簲 1rem (16px) */
+ margin-bottom: 2rem; /* mb-8 瀵瑰簲 2rem (32px) */
+
+ p{
+ font-size: 22px;
+ margin-top: 0px;
+ color: #fff;
+ }
+ h3{
+ font-size: 36px;
+ font-weight: 500;
+ font-family: 'MyCustomFont', sans-serif;
+ margin: 10px 0;
+ color: #fff;
+ }
+
+}
+
+/* 绉诲姩绔粯璁ゆ牱寮� (grid-cols-1) */
+.grid-container {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+}
+
+/* 灏忓睆骞曞強浠ヤ笂 (sm:grid-cols-2) */
+@media (min-width: 640px) {
+ .grid-container {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
+
+/* 澶у睆骞曞強浠ヤ笂 (lg:grid-cols-5) */
+@media (min-width: 1024px) {
+ .grid-container {
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ }
+}
+
+/* 鍗$墖鎮仠鏁堟灉澧炲己 */
+.el-card:hover {
+ transform: translateY(-2px);
+}
+.echarts{
+ display: flex;
+ justify-content: space-between;
+}
+
+/* 鍥捐〃瀹瑰櫒鏍峰紡 */
+.el-chart {
+ width: 100%;
+ height: 100%;
+}
+.section-title {
+ position: relative;
+ font-size: 18px;
+ color: #333;
+ padding-left: 10px;
+ margin-bottom: 10px;
+ font-weight: 700;
+}
+
+.section-title::before {
+ position: absolute;
+ left: 0;
+ top: 0px;
+ content: '';
+ width: 4px;
+ height: 18px;
+ background-color: #002FA7;
+ border-radius: 2px;
+}
+.chart-num{
+ position: absolute;
+ z-index: 3;
+ top: 92px;
+ left: 92px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+</style>
--
Gitblit v1.9.3