feat: 完成carbon页面

This commit is contained in:
caoqianming 2026-01-19 10:31:17 +08:00
parent c0a15fb752
commit db009ca954
6 changed files with 1296 additions and 6 deletions

44
src/api/model/carbon.js Normal file
View File

@ -0,0 +1,44 @@
import config from "@/config"
import http from "@/utils/request"
export default {
work: {
list: {
url: `${config.API_URL}/carbon/work/`,
name: "获取列表",
req: async function(data){
return await http.get(this.url, data);
}
},
my: {
url: `${config.API_URL}/carbon/work/my/`,
name: "获取列表",
req: async function(data){
return await http.get(this.url, data);
}
},
item: {
name: "获取单个核算工作",
req: async function(id){
return await http.get(`${config.API_URL}/carbon/work/${id}/`);
}
},
create: {
url: `${config.API_URL}/carbon/work/`,
name: "新增",
req: async function(data){
return await http.post(this.url,data);
}
},
cal_dq: {
req: async function(id, data){
return await http.post(`${config.API_URL}/carbon/work/${id}/cal_dq/`, data);
}
},
cal_dh: {
req: async function(id, data){
return await http.post(`${config.API_URL}/carbon/work/${id}/cal_dh/`, data);
}
}
},
}

View File

@ -54,7 +54,7 @@ const DEFAULT_CONFIG = {
//主题颜色 //主题颜色
// COLOR: '#536DFE',//gx、gz、tkx // COLOR: '#536DFE',//gx、gz、tkx
COLOR: '#0052d9',//bx COLOR: '#ee2416',//bx
//是否加密localStorage, 为空不加密可填写AES(模式ECB,移位Pkcs7)加密 //是否加密localStorage, 为空不加密可填写AES(模式ECB,移位Pkcs7)加密
LS_ENCRYPTION: '', LS_ENCRYPTION: '',

55
src/views/carbon/work.vue Normal file
View File

@ -0,0 +1,55 @@
<template>
<el-container>
<el-header>
<div class="right-panel">
<el-input v-model="query.search" placeholder="名称" @keyup.enter="handleQuery"></el-input>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.carbon.work.list"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="ID" prop="id" width="160"></el-table-column>
<el-table-column label="核算名称" prop="name" width="200"></el-table-column>
<el-table-column label="核算类型" prop="type" width="100"></el-table-column>
<el-table-column label="贷前得分" prop="score_dq" width="100"></el-table-column>
<el-table-column label="贷后得分" prop="score_dh" width="100"></el-table-column>
<el-table-column label="创建人" prop="create_by_name" width="100"></el-table-column>
<el-table-column label="所属单位" prop="belong_dept_name" width="200" show-overflow-tooltip></el-table-column>
<el-table-column label="工作描述" prop="description" show-overflow-tooltip></el-table-column>
<el-table-column label="创建时间" prop="create_time" width="160"></el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="核算工作" v-model="drawerVisible" :size="'90%'" destroy-on-close @close="table.refresh()">
<work_form :mode="mode" :t_id="t_id"></work_form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue';
import API from '@/api'
import work_form from './work_form.vue';
const drawerVisible = ref(false);
const mode = ref('show');
const table = ref();
const query = ref({
search: ''
});
const t_id = ref(null);
function addWork(){
drawerVisible.value = true;
}
function handleQuery(){
table.value.refresh();
}
</script>

View File

@ -0,0 +1,610 @@
<template>
<el-card style="width: 100%;" shadow="hover">
<el-form :form="formData" :disabled="localMode != 'add'">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="核算名称" required>
<el-input v-model="formData.name" placeholder="请输入核算名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="核算类型" required>
<el-select v-model="formData.type" placeholder="请选择核算类型" style="width: 100%;">
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="详细描述" required>
<el-input
type="textarea"
:rows="2"
v-model="formData.description"
placeholder="请输入描述"
></el-input>
</el-form-item>
</el-form>
<div style="text-align: right;">
<el-button type="primary" v-if="localMode=='add'" @click="handleSave">保存</el-button>
</div>
</el-card>
<el-row style="margin-top: 12px" v-if="formData.id">
<el-button type="primary" @click="changeCal('dq')">贷前计算</el-button>
<el-button type="primary" @click="changeCal('dh')" style="margin-left: 12px;" >贷后计算</el-button>
</el-row>
<el-row style="margin-top: 12px" v-if="formData.id" :gutter="10">
<el-col :span="10" v-if="currentCal==='dq'">
<el-card shadow="hover" width="100%">
<template #header>
<div style="display: flex; justify-content: space-between; align-items: center;border-bottom: 1px solid #ebeef5; padding-bottom: 4px;">
<span>贷前计算器</span>
<span><el-button type="primary" @click="handleDqCal" :disabled="calDisabled" :loading="calLoading">开始计算</el-button></span>
</div>
</template>
<el-form :form="formData" label-width="270px" :disabled="calDisabled">
<el-form-item label="企业技术说明及改造方案">
<sc-upload-filed
v-model="formData.dq_file6"
:file_ = "formData.dq_file6_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="企业低碳转型战略与总体规划">
<sc-upload-filed
v-model="formData.dq_file1"
:file_ = "formData.dq_file1_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="碳排放数据监测、核查与信息披露报告">
<sc-upload-filed
v-model="formData.dq_file2"
:file_ = "formData.dq_file2_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="数字化与智能控制系统技术方案">
<sc-upload-filed
v-model="formData.dq_file5"
:file_ = "formData.dq_file5_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="环境、社会与治理ESG尽职调查报告">
<sc-upload-filed
v-model="formData.dq_file3"
:file_ = "formData.dq_file3_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="项目融资与可行性研究方案">
<sc-upload-filed
v-model="formData.dq_file4"
:file_ = "formData.dq_file4_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
</el-form>
</el-card>
</el-col>
<el-col :span="10" v-if="currentCal==='dh'">
<el-card shadow="hover" width="100%">
<template #header>
<div style="display: flex; justify-content: space-between; align-items: center;border-bottom: 1px solid #ebeef5; padding-bottom: 4px;">
<span>贷后计算器</span>
<span><el-button type="primary" @click="handleDhCal" :disabled="calDisabled" :loading="calLoading">开始计算</el-button></span>
</div>
</template>
<el-form :form="formData" label-width="270px" :disabled="calDisabled">
<el-form-item label="企业技术说明及改造方案">
<sc-upload-filed
v-model="formData.dh_file6"
:file_ = "formData.dh_file6_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="数字化与智能控制系统技术方案">
<sc-upload-filed
v-model="formData.dh_file5"
:file_ = "formData.dh_file5_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="企业低碳转型战略与总体规划">
<sc-upload-filed
v-model="formData.dh_file1"
:file_ = "formData.dh_file1_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="碳排放数据监测、核查与信息披露报告">
<sc-upload-filed
v-model="formData.dh_file2"
:file_ = "formData.dh_file2_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="环境、社会与治理ESG尽职调查报告">
<sc-upload-filed
v-model="formData.dh_file3"
:file_ = "formData.dh_file3_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
<el-form-item label="项目融资与可行性研究方案">
<sc-upload-filed
v-model="formData.dh_file4"
:file_ = "formData.dh_file4_"
:multiple="false"
:limit="1"
accept=".txt,.doc,.docx"
/>
</el-form-item>
</el-form>
</el-card>
</el-col>
<el-col :span="14">
<el-card style="width: 100%;">
<template #header>
<span v-if="score === null">暂无评分数据请上传相关文件后计算</span>
<span v-else>
贵企业的转型金融{{currentCal==='dq'?'贷前':'贷后'}}评估得分为
<span class="score-display">{{ score }}</span> ;
等级: <span class="level-display" :style="levelStyle">
{{ level }}
</span>
</span>
</template>
<!-- 动画容器 -->
<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>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import {nextTick, onMounted, ref, watch, computed} from 'vue';
import TOOL from "@/utils/tool.js";
import API from '@/api'
import { ElMessage } from 'element-plus'
const props = defineProps({
mode: {
type: String,
default: 'show'
},
t_id: {
type: String,
default: null
}
});
const localMode = ref("show");
const formData = ref({});
const typeOptions = ref([
{label: '企业', value: '企业'},
{label: '项目', value: '项目'}
]);
const handleSave = () => {
if (localMode.value == 'add') {
API.carbon.work.create.req(formData.value).then(res => {
formData.value = res;
localMode.value = 'show';
});
}
}
onMounted(() => {
if (props.t_id) {
API.carbon.work.item.req(props.t_id).then(res => {
formData.value = res;
if (res.score_dq && currentCal.value==='dq') {
score.value = res.score_dq;
showResult.value = true
}
if (res.create_by == TOOL.data.get("USER_INFO").id) {
calDisabled.value = false;
}
});
} else {
localMode.value = 'add';
formData.value = {}
}
});
const currentCal = ref("dq");
const calDisabled = ref(true);
const changeCal = (type) => {
currentCal.value = type;
showResult.value = false;
if (type==='dq' && formData.value.score_dq) {
score.value = formData.value.score_dq;
showResult.value = true
} else if (type==='dh' && formData.value.score_dh) {
score.value = formData.value.score_dh;
showResult.value = true
} else {
score.value = null;
}
};
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 handleDqCal = () => {
//
if (formData.value.dq_file1 || formData.value.dq_file2 || formData.value.dq_file3 ||
formData.value.dq_file4 || formData.value.dq_file5 || formData.value.dq_file6) {
} else {
ElMessage.info('请至少上传一个文件后再进行计算');
return
}
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);
API.carbon.work.cal_dq.req(formData.value.id, formData.value).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);
});
}
const handleDhCal = () => {
//
if (formData.value.dh_file1 || formData.value.dh_file2 || formData.value.dh_file3 ||
formData.value.dh_file4 || formData.value.dh_file5 || formData.value.dh_file6) {
} else {
ElMessage.info('请至少上传一个文件后再进行计算');
return
}
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);
API.carbon.work.cal_dh.req(formData.value.id, formData.value).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>

View File

@ -0,0 +1,65 @@
<template>
<el-container>
<el-header>
<div class="left-panel">
<el-button
type="primary"
icon="el-icon-plus"
@click="addWork"
v-auth="'carbon_work.create'"
>新建核算工作</el-button>
</div>
<div class="right-panel">
<el-input v-model="query.search" placeholder="名称" @keyup.enter="handleQuery"></el-input>
<el-button
type="primary"
icon="el-icon-search"
@click="handleQuery"
></el-button>
</div>
</el-header>
<el-main class="nopadding">
<scTable
ref="table"
:apiObj="API.carbon.work.my"
row-key="id"
stripe
:query="query"
@row-click="(row)=>{t_id=row.id;mode='show';drawerVisible=true;}"
>
<el-table-column label="ID" prop="id" width="160"></el-table-column>
<el-table-column label="核算名称" prop="name" width="200"></el-table-column>
<el-table-column label="核算类型" prop="type" width="100"></el-table-column>
<el-table-column label="贷前得分" prop="score_dq" width="100"></el-table-column>
<el-table-column label="贷后得分" prop="score_dh" width="100"></el-table-column>
<el-table-column label="创建人" prop="create_by_name" width="100"></el-table-column>
<el-table-column label="所属单位" prop="belong_dept_name" width="200" show-overflow-tooltip></el-table-column>
<el-table-column label="工作描述" prop="description" show-overflow-tooltip></el-table-column>
<el-table-column label="创建时间" prop="create_time" width="160"></el-table-column>
</scTable>
</el-main>
</el-container>
<el-drawer title="核算工作" v-model="drawerVisible" :size="'90%'" destroy-on-close @close="table.refresh()">
<work_form :mode="mode" :t_id="t_id"></work_form>
</el-drawer>
</template>
<script setup>
import { ref } from 'vue';
import API from '@/api'
import work_form from './work_form.vue';
const drawerVisible = ref(false);
const mode = ref('show');
const table = ref();
const query = ref({
search: ''
});
const t_id = ref(null);
function addWork(){
mode.value = 'add';
t_id.value = null;
drawerVisible.value = true;
}
function handleQuery(){
table.value.refresh();
}
</script>

View File

@ -1,7 +1,523 @@
<template> <template>
<el-container> <el-row>
<h1>hello world</h1> <el-col :sm="12" :md="12">
</el-container> <el-card shadow="hover" header-bordered>
<template #header>
<div style="display: flex; justify-content: space-between">
<div class="redTitle" @click="goDq">转型金融贷前计算器</div>
<div>
<el-button style="margin-right:2px" @click="showDq">指标说明</el-button>
<el-button @click="goDq" type="primary">前往测算</el-button>
</div>
</div>
</template>
<div style="height:400px" v-if="!chartShow"></div>
<xt-chart :option="option" height="400px" v-else></xt-chart>
<!-- 原生表格实现 -->
<div class="table-container">
<table class="score-table">
<thead>
<tr>
<th>
<div>项目碳排放量</div>
<div style="font-size: 12px;">与基准线相比</div>
</th>
<th>企业分值区间</th>
<th>项目/企业等级</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in tableData"
:key="index"
:class="['score-row', { 'current-row': item.isCurrent }]"
>
<td :style="{ color: item.color, fontWeight: 'bold' }">{{ item.pf }}</td>
<td :style="{ color: item.color, fontWeight: 'bold' }">{{ item.score }}</td>
<td :style="{ color: item.color, fontWeight: 'bold' }">{{ item.level }}</td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :sm="12" :md="12">
<el-card shadow="hover" header-bordered>
<template #header>
<div style="display: flex; justify-content: space-between">
<div class="redTitle" @click="goDh">转型金融贷后计算器</div>
<div>
<el-button style="margin-right:2px" @click="showDh">指标说明</el-button>
<el-button @click="goDh" type="primary">前往测算</el-button>
</div>
</div>
</template>
<div style="height:400px" v-if="!chartShow"></div>
<xt-chart :option="option_dh" height="400px" v-else></xt-chart>
<div class="table-container">
<table class="score-table">
<thead>
<tr>
<th>
<div>项目碳排放量</div>
<div style="font-size: 12px;">与基准线相比</div>
</th>
<th>企业分值区间</th>
<th>项目/企业等级</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in tableData_dh"
:key="index"
:class="['score-row', { 'current-row': item.isCurrent }]"
>
<td :style="{ color: item.color, fontWeight: 'bold' }">{{ item.pf }}</td>
<td :style="{ color: item.color, fontWeight: 'bold' }">{{ item.score }}</td>
<td :style="{ color: item.color, fontWeight: 'bold' }">{{ item.level }}</td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
</el-row>
<el-dialog
v-model="dialogVisible"
>
<div v-for="(item, key) in descriptions" v-bind:key="key">
<div style="font-size:16px; font-weight: bold;">{{ key }}</div>
<div >{{ item }}</div>
</div>
</el-dialog>
</template> </template>
<script>
<script setup>
import router from '@/router'
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import xtChart from "@/components/xtChart/index.vue";
const goDq = () => {
router.push('/carbon/work/my')
}
const goDh = () => {
router.push('/carbon/work/my')
}
//
const currentData = ref([35, 20, 10, 10, 10, 8, 7]);
const currentData_dh = ref([35, 25, 13, 9, 9, 5, 2, 2]);
const dialogVisible = ref(false);
//
const descriptions = ref({});
const showDq = () => {
dialogVisible.value = true;
descriptions.value = {
'技术路径': '评估企业采用的技术方案是否先进、可行,是否符合低碳转型要求。包括技术创新性、成熟度、实施路径清晰度等维度。',
'碳排放': '衡量企业碳排放水平和减排潜力。包括碳排放总量、碳强度、减排目标达成率等关键指标。',
'企业碳治理': '评估企业碳管理体系和治理能力。包括碳管理制度、管理机构、信息披露、碳资产管理等方面。',
'融资计划': '分析转型项目融资方案的合理性和可行性。包括资金需求、融资结构、成本控制、风险防范等要素。',
'社会与治理协同效益': '评估项目对社会发展和公司治理的协同促进作用。包括就业创造、社区发展、治理结构优化等。',
'数字化与智能化水平': '衡量企业数字化转型和智能化应用程度。包括数字化基础设施、数据应用、智能化改造等方面。',
'环境协同效益': '评估项目对环境保护和生态改善的协同效应。包括污染物减排、资源循环利用、生态保护等。'
}
}
const showDh = () => {
dialogVisible.value = true;
descriptions.value = {
"减碳量": "核心指标,直接体现转型成效",
"技术成熟度": "决定技术可行性与推广价值",
"企业碳治理": "反映企业长期减碳意愿与能力",
"融资计划": "体现项目落地与资金保障能力",
"环境协同效益": "综合评价项目的社会与环境价值",
"社会与治理协同效益": "体现企业全面可持续发展的能力",
"创新与可持续竞争力": "体现企业是否具备持续引领行业绿色转型的能力",
"数字化与智能化水平": "体现企业是否具备持续引领行业绿色转型的能力"
}
}
//
const currentScore = computed(() => {
return currentData.value.reduce((sum, value) => sum + value, 0);
});
const currentScore_dh = computed(() => {
return currentData_dh.value.reduce((sum, value) => sum + value, 0);
})
const tableData = computed(() => [
{
pf: "低于10%及以上",
score: "80~100",
level: "领先",
color: "rgba(76, 175, 80, 0.7)",
isCurrent: currentScore.value >= 80
},
{
pf: "低于5%(含)~0%",
score: "60~79",
level: "良好",
color: "rgba(33, 150, 243, 0.7)",
isCurrent: currentScore.value >= 60 && currentScore.value < 80
},
{
pf: "低于0~5%",
score: "30~59",
level: "一般",
color: "rgba(255, 152, 0, 0.7)",
isCurrent: currentScore.value >= 30 && currentScore.value < 60
},
{
pf: "高于基准线",
score: "0~29",
level: "较差",
color: "rgba(244, 67, 54, 0.7)",
isCurrent: currentScore.value < 30
}
]);
const tableData_dh = computed(() => [
{
pf: "低于10%及以上",
score: "80~100",
level: "领先",
color: "rgba(76, 175, 80, 0.7)",
isCurrent: currentScore_dh.value >= 80
},
{
pf: "低于5%(含)~0%",
score: "60~79",
level: "良好",
color: "rgba(33, 150, 243, 0.7)",
isCurrent: currentScore_dh.value >= 60 && currentScore_dh.value < 80
},
{
pf: "低于0~5%",
score: "30~59",
level: "一般",
color: "rgba(255, 152, 0, 0.7)",
isCurrent: currentScore_dh.value >= 30 && currentScore_dh.value < 60
},
{
pf: "高于基准线",
score: "0~29",
level: "较差",
color: "rgba(244, 67, 54, 0.7)",
isCurrent: currentScore_dh.value < 30
}
]);
// Watchers to update chart colors based on score
watch(currentScore, (score) => {
if (score >= 80) {
option.value.series[0].data[0].areaStyle.color = 'rgba(76, 175, 80, 0.3)';
} else if (score >= 60) {
option.value.series[0].data[0].areaStyle.color = 'rgba(33, 150, 243, 0.3)';
} else if (score >= 30) {
option.value.series[0].data[0].areaStyle.color = 'rgba(255, 152, 0, 0.3)';
} else {
option.value.series[0].data[0].areaStyle.color = 'rgba(244, 67, 54, 0.3)';
}
});
watch(currentScore_dh, (score) => {
if (score >= 80) {
option_dh.value.series[0].data[0].areaStyle.color = 'rgba(76, 175, 80, 0.3)';
} else if (score >= 60) {
option_dh.value.series[0].data[0].areaStyle.color = 'rgba(33, 150, 243, 0.3)';
} else if (score >= 30) {
option_dh.value.series[0].data[0].areaStyle.color = 'rgba(255, 152, 0, 0.3)';
} else {
option_dh.value.series[0].data[0].areaStyle.color = 'rgba(244, 67, 54, 0.3)';
}
});
//
const option = ref({
title: {
text: '核算雷达图',
textStyle: {
color: '#c23531'
}
},
// tooltip: {
// },
radar: {
center: ['50%', '55%'],
radius: '70%',
indicator: [
{ name: '技术路径', max: 35 },
{ name: '碳排放', max: 20 },
{ name: '企业碳治理', max: 10 },
{ name: '融资计划', max: 10 },
{ name: '社会与治理协同效益', max: 10 },
{ name: '数字化与智能化水平', max: 8 },
{ name: '环境协同效益', max: 7 }
],
axisName: {
color: '#c23531',
// fontWeight: 'bold',
fontSize: 16
},
splitLine: {
lineStyle: {
color: ['rgba(194, 53, 49, 0.3)']
}
},
splitArea: {
areaStyle: {
color: ['rgba(194, 53, 49, 0.05)', 'rgba(194, 53, 49, 0.1)']
}
},
axisLine: {
lineStyle: {
color: 'rgba(194, 53, 49, 0.5)'
}
}
},
series: [
{
type: 'radar',
data: [
{
value: currentData.value,
name: '企业评估',
areaStyle: {
color: 'rgba(194, 53, 49, 0.4)'
},
lineStyle: {
color: '#c23531',
width: 2
},
itemStyle: {
color: '#c23531'
}
}
]
}
]
});
const option_dh = ref({
title: {
text: '核算雷达图',
textStyle: {
color: '#c23531'
}
},
// tooltip: {
// },
radar: {
center: ['50%', '55%'],
radius: '70%',
indicator: [
{ name: '减碳量', max: 35 },
{ name: '技术成熟度', max: 25 },
{ name: '企业碳治理', max: 13 },
{ name: '融资计划', max: 9 },
{ name: '环境协同效益', max: 9 },
{ name: '社会与治理协同效益', max: 5 },
{ name: '创新与可持续竞争力', max: 2 },
{ name: '数字化与智能化水平', max: 2 }
],
axisName: {
color: '#c23531',
// fontWeight: 'bold',
fontSize: 16
},
splitLine: {
lineStyle: {
color: ['rgba(194, 53, 49, 0.3)']
}
},
splitArea: {
areaStyle: {
color: ['rgba(194, 53, 49, 0.05)', 'rgba(194, 53, 49, 0.1)']
}
},
axisLine: {
lineStyle: {
color: 'rgba(194, 53, 49, 0.5)'
}
}
},
series: [
{
type: 'radar',
data: [
{
value: currentData_dh.value,
name: '企业评估',
areaStyle: {
color: 'rgba(194, 53, 49, 0.4)'
},
lineStyle: {
color: '#c23531',
width: 2
},
itemStyle: {
color: '#c23531'
}
}
]
}
]
});
//
const updateRadarData = () => {
//
const newData = currentData.value.map((value, index) => {
const maxValue = option.value.radar.indicator[index].max;
const minValue = option.value.radar.indicator[index].max * 0.2; //
const fluctuationRange = maxValue * 0.5; // 10%
const fluctuation = (Math.random() - 0.5) * 2 * fluctuationRange;
let newValue = value + fluctuation;
//
newValue = Math.min(newValue, maxValue);
// 0
newValue = Math.max(newValue, minValue);
return Math.round(newValue * 10) / 10; //
});
currentData.value = newData;
//
option.value.series[0].data[0].value = newData;
};
//
const updateRadarData_dh = () => {
//
const newData = currentData_dh.value.map((value, index) => {
const maxValue = option_dh.value.radar.indicator[index].max;
const minValue = option_dh.value.radar.indicator[index].max * 0.2; //
const fluctuationRange = maxValue * 0.5; // 10%
const fluctuation = (Math.random() - 0.5) * 2 * fluctuationRange;
let newValue = value + fluctuation;
//
newValue = Math.min(newValue, maxValue);
// 0
newValue = Math.max(newValue, minValue);
return Math.round(newValue * 10) / 10; //
});
currentData_dh.value = newData;
//
option_dh.value.series[0].data[0].value = newData;
};
//
let timer = null;
let timer_dh = null;
const chartShow = ref(false);
onMounted(() => {
// 4
setTimeout(() =>{ chartShow.value = true;}, 200);
timer = setInterval(updateRadarData, 4000);
setTimeout(()=>{
timer_dh = setInterval(updateRadarData_dh, 4000);
}, 2000);
});
onUnmounted(() => {
//
if (timer) {
clearInterval(timer);
}
if (timer_dh) {
clearInterval(timer_dh);
}
});
</script> </script>
<style scoped>
.bigNav {
font-size: 20px;
font-weight: 500;
color: #ee2416;
height: 180px;
display: flex;
align-items: center;
justify-content: center;
}
.redTitle {
color: #ee2416;
font-size: 20px;
font-weight: 500;
cursor: pointer;
}
/* 表格容器样式 */
.table-container {
margin-top: 20px;
background-color: #f5f5f5;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 原生表格样式 */
.score-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
/* 表头样式 */
.score-table thead {
background-color: #f7f6f6;
}
.score-table th {
/* color: #fff; */
color: black;
font-weight: bold;
padding: 12px 16px;
text-align: center;
border-bottom: 2px solid #555;
}
/* 表格行样式 */
.score-table tbody tr {
transition: all 0.3s ease;
background-color: white;
}
.score-table td {
padding: 12px 16px;
text-align: center;
border-bottom: 1px solid #e0e0e0;
color: #333;
font-weight: 500;
}
/* 当前行高亮样式 */
.current-row {
transform: scale(1.02);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
position: relative;
z-index: 1;
}
.current-row td {
font-weight: bold;
color: #000;
}
/* 鼠标悬停效果 */
.score-table tbody tr:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 2;
}
</style>