From 9cc769fcd5e7efbe363cdaabead04824bf9d7812 Mon Sep 17 00:00:00 2001 From: spring <2396852758@qq.com> Date: 星期五, 08 八月 2025 11:38:28 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/dev_7004' into dev_ai --- src/assets/icons/png/4.png | 0 src/assets/icons/png/支出金额.png | 0 src/assets/fonts/font.css | 7 src/assets/icons/png/2.png | 0 src/assets/icons/png/收入金额.png | 0 src/views/financialManagement/revenueManagement/index.vue | 2 src/assets/icons/png/支出.png | 0 src/api/financialManagement/financialStatements.js | 31 +++ src/assets/fonts/DIN Alternate Bold.ttf | 0 src/views/financialManagement/expenseManagement/index.vue | 2 src/assets/icons/png/收入收款.png | 0 src/components/Echarts/echarts.vue | 9 src/assets/icons/png/5.png | 0 src/main.js | 1 src/assets/icons/png/3.png | 0 src/assets/icons/png/收入列帐.png | 0 src/assets/icons/png/1.png | 0 src/views/financialManagement/financialStatements/index.vue | 511 +++++++++++++++++++++++++++++++++++++++++++++++++++ 18 files changed, 556 insertions(+), 7 deletions(-) diff --git a/src/api/financialManagement/financialStatements.js b/src/api/financialManagement/financialStatements.js new file mode 100644 index 0000000..537d36f --- /dev/null +++ b/src/api/financialManagement/financialStatements.js @@ -0,0 +1,31 @@ +import request from "@/utils/request"; + +// 鏍规嵁鏃ユ湡鏌ヨ +export const reportForms = (params) => { + console.log(params); + return request({ + url: "/account/accountExpense/report/forms", + method: "get", + params, + }); +}; + +// 鏌ヨ姣忔湀鏁版嵁-鏀跺叆 +export const reportIncome = (params) => { + console.log(params); + return request({ + url: "/account/accountExpense/report/income", + method: "get", + params, + }); +}; + +// 鏌ヨ姣忔湀鏁版嵁-鏀嚭 +export const reportExpense = (params) => { + console.log(params); + return request({ + url: "/account/accountExpense/report/expense", + method: "get", + params, + }); +}; diff --git a/src/assets/fonts/DIN Alternate Bold.ttf b/src/assets/fonts/DIN Alternate Bold.ttf new file mode 100644 index 0000000..81f2f7a --- /dev/null +++ b/src/assets/fonts/DIN Alternate Bold.ttf Binary files differ diff --git a/src/assets/fonts/font.css b/src/assets/fonts/font.css new file mode 100644 index 0000000..1a3894a --- /dev/null +++ b/src/assets/fonts/font.css @@ -0,0 +1,7 @@ +@font-face { + font-family: "MyCustomFont"; + src: url("./DIN Alternate Bold.ttf") format("truetype"); + font-weight: 700; /* 绮椾綋 */ + font-style: normal; + font-display: swap; +} diff --git a/src/assets/icons/png/1.png b/src/assets/icons/png/1.png new file mode 100644 index 0000000..1acfa67 --- /dev/null +++ b/src/assets/icons/png/1.png Binary files differ diff --git a/src/assets/icons/png/2.png b/src/assets/icons/png/2.png new file mode 100644 index 0000000..cebdf2c --- /dev/null +++ b/src/assets/icons/png/2.png Binary files differ diff --git a/src/assets/icons/png/3.png b/src/assets/icons/png/3.png new file mode 100644 index 0000000..719912b --- /dev/null +++ b/src/assets/icons/png/3.png Binary files differ diff --git a/src/assets/icons/png/4.png b/src/assets/icons/png/4.png new file mode 100644 index 0000000..b5f5861 --- /dev/null +++ b/src/assets/icons/png/4.png Binary files differ diff --git a/src/assets/icons/png/5.png b/src/assets/icons/png/5.png new file mode 100644 index 0000000..5467146 --- /dev/null +++ b/src/assets/icons/png/5.png Binary files differ diff --git "a/src/assets/icons/png/\346\224\257\345\207\272.png" "b/src/assets/icons/png/\346\224\257\345\207\272.png" new file mode 100644 index 0000000..fc253ae --- /dev/null +++ "b/src/assets/icons/png/\346\224\257\345\207\272.png" Binary files differ diff --git "a/src/assets/icons/png/\346\224\257\345\207\272\351\207\221\351\242\235.png" "b/src/assets/icons/png/\346\224\257\345\207\272\351\207\221\351\242\235.png" new file mode 100644 index 0000000..b0db95a --- /dev/null +++ "b/src/assets/icons/png/\346\224\257\345\207\272\351\207\221\351\242\235.png" Binary files differ diff --git "a/src/assets/icons/png/\346\224\266\345\205\245\345\210\227\345\270\220.png" "b/src/assets/icons/png/\346\224\266\345\205\245\345\210\227\345\270\220.png" new file mode 100644 index 0000000..782bd2f --- /dev/null +++ "b/src/assets/icons/png/\346\224\266\345\205\245\345\210\227\345\270\220.png" Binary files differ diff --git "a/src/assets/icons/png/\346\224\266\345\205\245\346\224\266\346\254\276.png" "b/src/assets/icons/png/\346\224\266\345\205\245\346\224\266\346\254\276.png" new file mode 100644 index 0000000..a1d3272 --- /dev/null +++ "b/src/assets/icons/png/\346\224\266\345\205\245\346\224\266\346\254\276.png" Binary files differ diff --git "a/src/assets/icons/png/\346\224\266\345\205\245\351\207\221\351\242\235.png" "b/src/assets/icons/png/\346\224\266\345\205\245\351\207\221\351\242\235.png" new file mode 100644 index 0000000..b83863a --- /dev/null +++ "b/src/assets/icons/png/\346\224\266\345\205\245\351\207\221\351\242\235.png" Binary files differ diff --git a/src/components/Echarts/echarts.vue b/src/components/Echarts/echarts.vue index 2c51ace..d8264ad 100644 --- a/src/components/Echarts/echarts.vue +++ b/src/components/Echarts/echarts.vue @@ -1,6 +1,7 @@ <template> - <div> + <div style="position: relative;"> <div ref="chartRef" :style="chartStyle"></div> + <slot></slot> </div> </template> @@ -89,7 +90,7 @@ // Methods function generateChart(option) { - const copiedOption = JSON.parse(JSON.stringify(option)) // 鉁� 娣辨嫹璐� + const copiedOption = option if (copiedOption.series && copiedOption.series.length > 0) { copiedOption.series.forEach((s, index) => { @@ -118,7 +119,7 @@ series: props.series, grid: props.grid, legend: props.legend, - tooltip: props.tooltip + tooltip: props.tooltip, } chartInstance.clear() @@ -147,7 +148,7 @@ // Watch all reactive props that affect the chart watch( - () => [props.xAxis, props.series], + () => [props.xAxis, props.series, props.legend, props.tooltip], () => { if (chartInstance) { renderChart() diff --git a/src/main.js b/src/main.js index 014954c..00205af 100644 --- a/src/main.js +++ b/src/main.js @@ -22,6 +22,7 @@ import "virtual:svg-icons-register"; import SvgIcon from "@/components/SvgIcon"; import elementIcons from "@/components/SvgIcon/svgicon"; +import "./assets/fonts/font.css"; import "./permission"; // permission control diff --git a/src/views/financialManagement/expenseManagement/index.vue b/src/views/financialManagement/expenseManagement/index.vue index 0c6cbde..32d906b 100644 --- a/src/views/financialManagement/expenseManagement/index.vue +++ b/src/views/financialManagement/expenseManagement/index.vue @@ -69,7 +69,7 @@ </PIMTable> </div> <Modal ref="modalRef" @success="getTableData"></Modal> - <files-dia ref="filesDia" @close="handleQuery"></files-dia> + <files-dia ref="filesDia"></files-dia> </div> </template> 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> diff --git a/src/views/financialManagement/revenueManagement/index.vue b/src/views/financialManagement/revenueManagement/index.vue index 984d9de..35f3075 100644 --- a/src/views/financialManagement/revenueManagement/index.vue +++ b/src/views/financialManagement/revenueManagement/index.vue @@ -69,7 +69,7 @@ </PIMTable> </div> <Modal ref="modalRef" @success="getTableData"></Modal> - <files-dia ref="filesDia" @close="handleQuery"></files-dia> + <files-dia ref="filesDia"></files-dia> </div> </template> -- Gitblit v1.9.3