feat(largeScreen): 大屏展示功能开发

- 新增 RevenueContractCard 组件,用于展示收入、支出等合同数据
- 实现 bottomboxconpoent 组件的通用化,支持自定义标题、数值等
- 在 centerPage 中集成 RevenueContractCard 组件,展示大屏数据
- 更新 rightPage 组件,添加实际数据请求和展示
- 优化 optionList 中的图表配置,提高图表可读性
This commit is contained in:
tcy
2025-08-22 16:37:14 +08:00
parent c1512c5a34
commit ad04cff917
6 changed files with 144 additions and 76 deletions

View File

@ -0,0 +1,22 @@
import request from '@/utils/request';
// 合同金额
export const totalAmount = () => {
return request({
url: '/money/big/screen/totalAmount',
method: 'get',
});
};
// 资金KPI
export const monthMoney = () => {
return request({
url: '/money/big/screen/monthMoney',
method: 'get',
});
};
// 现金流
export const monthCash = () => {
return request({
url: '/money/big/screen/monthCash',
method: 'get',
});
};

View File

@ -2,28 +2,21 @@
<div class="stat-card" :style="customStyles">
<!-- 标题区域 -->
<div class="stat-card__title">{{ title }}</div>
<!-- 数值区域 -->
<div class="stat-card__value-container">
<span class="stat-card__value">{{ formattedValue }}</span>
<span class="stat-card__value">{{ props.value }}</span>
<span class="stat-card__unit">{{ unit }}</span>
</div>
<!-- 底部信息区域 -->
<div class="stat-card__footer">
<div class="stat-card__footer" v-if="showIcon">
<div class="stat-card__trend">
<img
class="stat-card__trend-icon"
:src="'/src/assets/large/' + trendIcon+'.png'"
:alt="trendDirection === 'up' ? '上升' : '下降'"
>
<img class="stat-card__trend-icon" :src="'/src/assets/large/' + trendIcon + '.png'"
:alt="trendDirection === 'up' ? '上升' : '下降'">
<span class="stat-card__trend-text">{{ trendText }}</span>
</div>
<img
class="stat-card__badge"
:src="'/src/assets/large/'+badgeIcon+'.png'"
alt="徽章图标"
>
<img class="stat-card__badge" :src="'/src/assets/large/' + badgeIcon + '.png'" alt="徽章图标">
</div>
</div>
</template>
@ -78,6 +71,10 @@ const props = defineProps({
customStyles: {
type: Object,
default: () => ({})
},
showIcon: {
type: Boolean,
default: false
}
});
@ -103,22 +100,26 @@ const trendText = computed(() => {
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
padding: 35px 10px;
box-sizing: border-box;
border: 1px solid rgba(29, 214, 255, 0.1);
border-radius: 4px; // 增加轻微圆角,提升视觉效果
text-align: center;
&__title {
font-size: 14px;
color: #8FABBF;
line-height: 20px;
}
&__value-container {
display: flex;
// display: flex;
align-items: baseline;
// align-items: center;
// flex-direction: column;
}
&__value {
font-size: 24px;
color: #fff;
@ -126,34 +127,34 @@ const trendText = computed(() => {
margin-right: 5px;
font-weight: bold;
}
&__unit {
color: #8FABBF;
font-size: 14px;
}
&__footer {
display: flex;
justify-content: space-between;
align-items: center;
}
&__trend {
display: flex;
align-items: center;
}
&__trend-icon {
width: 12px;
height: 12px;
margin-right: 4px;
}
&__trend-text {
font-size: 14px;
color: #8FABBF;
}
&__badge {
width: 40px;
height: 40px;

View File

@ -1,45 +1,65 @@
<template>
<div class="bottom_box">
<div class="bottom_box_title">收入合同</div>
<div>
<span class="bottom_box_number">205,805.17</span>
<span>万元</span>
</div>
<div class="bottom_box_bottom">
<el-progress :percentage="50" color="rgba(255, 147, 42, 1)" />
</div>
<div class="bottom_box_text">
成本率
</div>
<div class="bottom_box">
<div class="bottom_box_title">{{ title }}</div>
<div>
<span class="bottom_box_number">{{ value }}</span>
<span>{{ unit }}</span>
</div>
<div class="bottom_box_bottom">
<el-progress :percentage="50" color="rgba(255, 147, 42, 1)" />
</div>
<div class="bottom_box_text">
{{ period }}
</div>
</div>
</template>
<script setup>
const props = defineProps({
title: {
type: String,
default: '收入合同'
},
value: {
type: Number,
default: 205805.17
},
unit: {
type: String,
default: '万元'
},
growthRate: {
type: Number,
default: 3.2
},
period: {
type: String,
}
})
</script>
<style lang="scss">
.bottom_box {
width: 225px;
height: 147px;
height: 100%;
padding: 10px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-around;
width: 225px;
height: 147px;
height: 100%;
padding: 10px;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-around;
.bottom_box_title,
.bottom_box_text {
color: rgba(143, 171, 191, 1);
font-size: 14px;
line-height: 20px;
}
.bottom_box_number {
font-size: 24px;
color: #fff;
line-height: 30px;
}
.bottom_box_title,
.bottom_box_text {
color: rgba(143, 171, 191, 1);
font-size: 14px;
line-height: 20px;
}
.bottom_box_number {
font-size: 24px;
color: #fff;
line-height: 30px;
}
}
</style>

View File

@ -16,14 +16,19 @@
<img class="top_img" src="@/assets/large/top1.png" alt=""></img>
</div>
</div> -->
<RevenueContractCard title="收入合同" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
<!-- <RevenueContractCard title="收入合同" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
badgeIcon="top1" period="较上月" />
<RevenueContractCard title="支出合同" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
badgeIcon="top2" period="较上月" />
<RevenueContractCard title="合同利润" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="down"
badgeIcon="top3" period="较上月" />
<RevenueContractCard title="工程变更" :value="156234.89" :growthRate="-1.5" trendDirection="up" trendIcon="up"
badgeIcon="top4" period="较上月" />
badgeIcon="top4" period="较上月" /> -->
<RevenueContractCard title="收入合同" :value="bigDataObj.incomeTotalAmount" />
<RevenueContractCard title="支出合同" :value="bigDataObj.expensesTotalAmount" />
<RevenueContractCard title="合同利润" :value="bigDataObj.profitAmount" />
<RevenueContractCard title="工程变更" :value="bigDataObj.changeAmount" unit="%" />
</div>
</div>
<div class="centerPage_map">
@ -44,7 +49,7 @@
成本率
</div>
</div> -->
<bottomboxconpoent> </bottomboxconpoent>
<bottomboxconpoent title="材料成本" unit="万元" :value="1"> </bottomboxconpoent>
<bottomboxconpoent> </bottomboxconpoent>
<bottomboxconpoent> </bottomboxconpoent>
<bottomboxconpoent> </bottomboxconpoent>
@ -59,7 +64,16 @@ import * as echarts from 'echarts';
import china from '@/assets/china.json';
import RevenueContractCard from './RevenueContractCard.vue';
import bottomboxconpoent from './bottomboxconpoent.vue';
const data = ref<any>({});
import { totalAmount } from "@/api/largeScreen/index.js"
const bigDataObj = ref<any>({});
const getTotalAmount = async () => {
const { data: { incomeTotalAmount, expensesTotalAmount, profitAmount, changeAmount } } = await totalAmount()
bigDataObj.value.incomeTotalAmount = incomeTotalAmount || 0;
bigDataObj.value.expensesTotalAmount = expensesTotalAmount || 0;
bigDataObj.value.profitAmount = profitAmount || 0;
bigDataObj.value.changeAmount = changeAmount || 0;
}
// 地图容器引用
const mapRef = ref<HTMLDivElement | null>(null);
@ -181,6 +195,7 @@ const initEcharts = () => {
// 组件挂载时初始化
onMounted(() => {
getTotalAmount()
// 确保DOM渲染完成
nextTick(() => {
initEcharts();
@ -223,6 +238,6 @@ onUnmounted(() => {
height: 60%;
}
}
</style>

View File

@ -862,7 +862,7 @@ export const getBarOptions = (data: any) => {
// 收支合同分析
export const getBarOptions2 = (data: any) => {
const option = {
color:['#FF932A', '#678FE6', '#1DD6FF', '#00E396'],
color: ['#FF932A', '#678FE6', '#1DD6FF', '#00E396'],
title: {
text: '数量(个)',
subtext: '16',
@ -872,7 +872,7 @@ export const getBarOptions2 = (data: any) => {
color: '#9DADB7',
fontSize: 16
},
subtextStyle:{
subtextStyle: {
color: '#707070',
fontSize: 32,
fontWeight: 'bold'
@ -907,7 +907,7 @@ export const getBarOptions2 = (data: any) => {
show: false
},
data: [
{ value: 3, name: '100万下' },
{ value: 3, name: '100万下' },
{ value: 4, name: '100-500万' },
{ value: 5, name: '500-1000万' },
{ value: 4, name: '1000万以上' },

View File

@ -45,38 +45,48 @@ import TitleComponent from './TitleComponent.vue';
import EchartBox from '@/components/EchartBox/index.vue';
import { getLineOption, getBarOptions } from './optionList';
import ProgressComponent from './ProgressComponent.vue';
import { monthMoney, monthCash } from '@/api/largeScreen';
const lineOption = ref();
const barOption = ref();
const getCapitalData = (data?: any) => {
const getCapitalData = async () => {
const { data } = await monthMoney()
const month = data.map((item: any) => item.month);
const income = data.map((item: any) => item.incomeAmount);
const expenses = data.map((item: any) => item.expensesAmount);
const profit = data.map((item: any) => item.profitAmount);
// const xData = data.map((item) => item.time);
// const yData = data.map((item) => item.content);
const lineData = {
xLabel: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
xLabel: month,
line1: [
[100, 200, 150, 300, 250, 350, 400, 350, 450, 500, 400, 550],
[220, 250, 230, 280, 270, 300, 350, 320, 380, 400, 450, 500],
[300, 350, 320, 380, 400, 450, 500, 480, 520, 550, 600, 650]
income,
expenses,
profit
]
// line2: ['20', '50', '12', '65', '30', '60']
};
lineOption.value = getLineOption(lineData);
};
const getTurnoverList = (data?: any) => {
const getTurnoverList = async () => {
// const xData = data.map((item) => item.time);
// const yData = data.map((item) => {
// // 先将content转换为数字再调用toFixed
// const num = Number(item.content);
// return isNaN(num) ? 0 : Number(num.toFixed(2));
// });
const { data } = await monthCash()
const month = data.map((item: any) => item.month);
const income = data.map((item: any) => item.incomeAmount);
const expenses = data.map((item: any) => item.expensesAmount);
// const profit = data.map((item: any) => item.profitAmount);
const barData = {
name: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
name: month,
value: [
[2, 5, 15, 30, 25, 35, 40, 35, 45, 50, 40, 55],
[4, 3, 6, 11, 15, 22, 30, 14, 48, 22, 25, 60]
income,
expenses
]
};
barOption.value = getBarOptions(barData);