xt_web_td/src/pages/cal/dh.vue

375 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<t-row style="height: 100%;">
<t-col :flex="5" style="height: 100%;">
<t-card header-bordered style="height: 100%;overflow-y: auto;">
<template #header>
<t-button @click="handleCal" :loading="calLoading">开始计算</t-button>
</template>
<template #content>
<t-form label-align="left" label-width="280px" style="overflow-y: auto;">
<t-form-item style="min-height: 80px;" label="企业技术说明及改造方案">
<t-upload v-model="file6" :autoUpload="false" :max="1" accept=".docx,.pdf,.txt,.doc"/>
</t-form-item>
<t-form-item style="min-height: 80px;" label="数字化与智能控制系统技术方案">
<t-upload v-model="file5" :autoUpload="false" :max="1" accept=".docx,.pdf,.txt,.doc"/>
</t-form-item>
<t-form-item style="min-height: 80px;" label="企业低碳转型战略与总体规划">
<t-upload v-model="file1" :autoUpload="false" :max="1" accept=".docx,.pdf,.txt,.doc" />
</t-form-item>
<t-form-item style="min-height: 80px;" label="碳排放数据监测、核查与信息披露报告">
<t-upload v-model="file2" :autoUpload="false" :max="1" accept=".docx,.pdf,.txt,.doc"/>
</t-form-item>
<t-form-item style="min-height: 80px;" label="环境、社会与治理ESG尽职调查报告" >
<t-upload v-model="file3" :autoUpload="false" :max="1" accept=".docx,.pdf,.txt,.doc"/>
</t-form-item>
<t-form-item style="min-height: 80px;" label="项目融资与可行性研究方案">
<t-upload v-model="file4" :autoUpload="false" :max="1" accept=".docx,.pdf,.txt,.doc"/>
</t-form-item>
</t-form>
</template>
</t-card>
</t-col>
<t-col :flex="7" style="height: 100%;">
<t-card header-bordered style="height: 100%;">
<template #header>
<span v-if="score === null">暂无评分数据,请上传相关文件后计算</span>
<span v-else>
贵企业的双碳贷后得分为
<span class="score-display">{{ score }}</span> 分;
等级: <span class="level-display" :style="levelStyle">
{{ level }}
</span>
</span>
</template>
<template #content>
<!-- 动画容器 -->
<div class="animation-container" v-show="showAnimation">
<div class="particles-container">
<div class="particle" v-for="n in 30" :key="n" :style="particleStyle(n)"></div>
</div>
<div class="loading-circle">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
</div>
<div class="loading-text" :style="{color: loadingTextColor}">{{ loadingText }}</div>
</div>
<!-- 结果展示 -->
<div class="result-container" v-show="showResult">
<div class="score-circle" :style="scoreCircleStyle">
<div class="score-value">{{ score }}</div>
<!-- <div class="score-label">总分</div> -->
</div>
<!-- <div class="level-badge" :style="levelStyle">
{{ level }}
</div> -->
<div class="result-description">
<p>根据您提交的资料我们已完成双碳贷后评估</p>
<p>您的企业评级为 <strong :style="{color: levelColor,fontSize: '24px'}">{{ level }}</strong> </p>
</div>
</div>
</template>
</t-card>
</t-col>
</t-row>
</template>
<script setup>
import { ref, onMounted, watch, computed } from 'vue';
import http from "@/api/request.js";
import { MessagePlugin } from "tdesign-vue-next"
onMounted(() => {
// 初始化代码
})
const file1 = ref([]);
const file2 = ref([]);
const file3 = ref([]);
const file4 = ref([]);
const file5 = ref([]);
const file6 = ref([]);
const calLoading = ref(false);
const score = ref(null);
const level = ref("较差");
const levelColor = ref('#000');
const showAnimation = ref(false);
const showResult = ref(false);
const loadingText = ref("正在计算评分...");
const loadingTextColor = ref("#ee2416");
// 计算等级样式
const levelStyle = computed(() => {
return {
color: levelColor.value,
background: `${levelColor.value}15`,
border: `1px solid ${levelColor.value}30`
};
});
// 计算得分圆环样式
const scoreCircleStyle = computed(() => {
const percentage = score.value ? (score.value / 100) * 360 : 0;
return {
background: `conic-gradient(${levelColor.value} ${percentage}deg, #f0f0f0 ${percentage}deg 360deg)`
};
});
// 粒子样式
const particleStyle = (n) => {
const size = Math.random() * 8 + 4;
const left = Math.random() * 100;
const animationDelay = Math.random() * 2;
const animationDuration = Math.random() * 3 + 2;
return {
width: `${size}px`,
height: `${size}px`,
left: `${left}%`,
animationDelay: `${animationDelay}s`,
animationDuration: `${animationDuration}s`,
background: '#ee2416'
};
};
watch(score, (newScore) => {
if (newScore >= 80) {
level.value = '领先'
levelColor.value = '#4caf50'
} else if (newScore >= 60) {
level.value = '良好'
levelColor.value = '#2196f3'
} else if (newScore >= 30) {
level.value = '一般'
levelColor.value = '#ff9800'
} else {
level.value = '较差'
levelColor.value = '#f44336'
}
}, { immediate: true });
const handleCal = () => {
// 验证是否已上传文件
const files = [file1.value, file2.value, file3.value, file4.value, file5.value, file6.value];
const hasFiles = files.some(fileArray => fileArray && fileArray.length > 0);
if (!hasFiles) {
MessagePlugin.error('请至少上传一个文件后再进行计算');
return;
}
let formData = new FormData();
formData.append('file1', file1.value?.[0]?.raw);
formData.append('file2', file2.value?.[0]?.raw);
formData.append('file3', file3.value?.[0]?.raw);
formData.append('file4', file4.value?.[0]?.raw);
formData.append('file5', file5.value?.[0]?.raw);
formData.append('file6', file6.value?.[0]?.raw);
calLoading.value = true;
showAnimation.value = true;
showResult.value = false;
// 动态变化的加载文本
const loadingTexts = [
"正在分析企业低碳转型战略...",
"正在评估碳排放数据...",
"正在审核ESG尽职调查报告...",
"正在研究项目融资方案...",
"正在分析数字化技术方案...",
"正在评估企业技术说明...",
"正在生成最终评分..."
];
let textIndex = 0;
const minLoadingTime = 5000; // 最小加载时间 5秒
const startTime = Date.now(); // 记录开始时间
const textInterval = setInterval(() => {
loadingText.value = loadingTexts[textIndex];
textIndex = (textIndex + 1) % loadingTexts.length;
}, 800);
http.postForm("/cal_dh/", formData).then(res => {
const elapsedTime = Date.now() - startTime; // 已过去的时间
const remainingTime = Math.max(0, minLoadingTime - elapsedTime); // 还需要等待的时间
setTimeout(() => {
clearInterval(textInterval);
calLoading.value = false;
score.value = res.total_score;
// 动画完成后显示结果
setTimeout(() => {
showAnimation.value = false;
showResult.value = true;
}, 500);
}, remainingTime);
}).catch(e => {
const elapsedTime = Date.now() - startTime;
const remainingTime = Math.max(0, minLoadingTime - elapsedTime);
setTimeout(() => {
clearInterval(textInterval);
calLoading.value = false;
showAnimation.value = false;
}, remainingTime);
});
}
</script>
<style scoped>
.animation-container {
margin-top: 80px;
position: relative;
height: 300px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.particles-container {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
.particle {
position: absolute;
border-radius: 50%;
opacity: 0.7;
animation: floatUp linear infinite;
}
@keyframes floatUp {
0% {
transform: translateY(100px) scale(0);
opacity: 0;
}
10% {
opacity: 0.7;
}
90% {
opacity: 0.7;
}
100% {
transform: translateY(-100px) scale(1);
opacity: 0;
}
}
.loading-circle {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.circle {
width: 15px;
height: 15px;
border-radius: 50%;
background: var(--td-brand-color);
animation: pulse 1.5s ease-in-out infinite;
}
.circle:nth-child(2) {
animation-delay: 0.2s;
}
.circle:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes pulse {
0%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
50% {
transform: scale(1.2);
opacity: 1;
}
}
.loading-text {
font-size: 18px;
font-weight: 500;
transition: all 0.3s ease;
}
.result-container {
margin-top: 80px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 400px;
gap: 20px;
}
.score-circle {
width: 200px;
height: 200px;
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.score-circle::before {
content: '';
position: absolute;
width: 170px;
height: 170px;
border-radius: 50%;
background: white;
}
.score-value {
font-size: 40px;
font-weight: bold;
z-index: 1;
color: #333;
}
.score-label {
font-size: 14px;
color: #666;
z-index: 1;
}
.level-badge {
padding: 8px 20px;
border-radius: 20px;
font-size: 18px;
font-weight: bold;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.result-description {
text-align: center;
max-width: 80%;
line-height: 1.6;
font-size: 18px;
}
.score-display {
font-weight: bold;
font-size: 32px;
color: #2d8cf0;
}
.level-display {
font-weight: bold;
font-size: 32px;
padding: 4px 12px;
border-radius: 8px;
}
</style>