You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
5.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div>
<el-main style="padding-top:0px">
<!-- 页面标题和操作 -->
<div class="d-flex justify-between align-center mb-4" style="margin: 0px 0 16px 0;">
<h3 style="display: inline-block;"><i class="el-icon-data-analysis"></i> 科室资金执行率</h3>
<div>
<el-date-picker size="small" v-model="select.year"
value-format="yyyy" format="yyyy" type="year" placeholder="选择年">
</el-date-picker>
<el-button style="margin-left:10px" type="primary" size="small" @click="getProgress">刷新</el-button>
</div>
</div>
<!-- 科室执行率卡片 -->
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="8" v-for="(dept, idx) in list" :key="dept.idx">
<el-card class="department-card" shadow="hover">
<div>
<h4 class="card-title">{{ dept.plan_department?dept.plan_department.name:'' }}</h4>
<div class="mb-2">
<div class="d-flex justify-between mb-1">
<span class="fw-bold">当前执行率</span>
<span class="execution-rate text-primary">{{ getCompletionRate(dept.rate) }}%</span>
</div>
<el-progress :show-text='false' :percentage="getCompletionRate(dept.rate)" :stroke-width="8" color="#409EFF" />
</div>
<div class="mb-2">
<div class="d-flex justify-between mb-1">
<span class="fw-bold">完成后执行率</span>
<span class="execution-rate text-success">{{ getCompletionRate(dept.rate_end) }}%</span>
</div>
<el-progress :show-text='false' :percentage="getCompletionRate(dept.rate_end)" :stroke-width="8" color="#67C23A" />
</div>
<el-row class="text-center" :gutter="0">
<el-col :span="8">
<div class="text-muted">预算总额</div>
<div class="text-muted fw-bold">{{ formatToWan(dept.money_total) }}</div>
</el-col>
<el-col :span="8">
<div class="text-muted">已执行</div>
<div class="text-muted fw-bold text-success">{{ formatToWan(dept.use_money_total) }}</div>
</el-col>
<el-col :span="8">
<div class="text-muted">进行中</div>
<div class="text-muted fw-bold text-warning">{{ getDoingMoneyTotal(dept.money_total,dept.use_money_total) }}</div>
</el-col>
</el-row>
<div class="mt-3 detail" @click="goToDetail(dept)">
<el-button type="text">
<i class="el-icon-view"></i> 查看详情
</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
</el-main>
</el-container>
<departmentProgressDetail ref="departmentProgressDetail"></departmentProgressDetail>
</div>
</template>
<script>
import {
statisticDepartment
} from "@/api/departmentProgress"
import departmentProgressDetail from './components/departmentProgressDetail.vue'
export default {
name: 'DepartmentProgress',
components:{
departmentProgressDetail
},
data() {
return {
select: {
year: new Date().getFullYear()+''
},
list:[]
}
},
created(){
this.getProgress()
},
methods: {
async getProgress() {
const res = await statisticDepartment({
year: this.select.year
},true)
const data = res.departmentList
data.sort((a,b)=>{
return a.plan_department.sortnumber - b.plan_department.sortnumber
})
this.list = data
},
getCompletionRate(dept) {
return dept?Number(dept.toFixed(2)):0
},
formatToWan(num) {
if (num === null || num === undefined) return '0元';
num = Number(num);
if (isNaN(num)) return '0元';
if (Math.abs(num) < 10000) {
return num.toString() + '元'; // 小于1万直接返回原数值
} else {
return (num / 10000).toFixed(2) + '万元'; // 除以1万并保留两位小数
}
},
getDoingMoneyTotal(contractPlanSum, useMoneyTotal) {
// 转换为数字并处理非数字情况
const plan = Number(contractPlanSum) || 0;
const used = Number(useMoneyTotal) || 0;
// 计算差值若小于0则取0
const doing = Math.max(plan - used, 0);
return this.formatToWan(doing)
},
goToDetail(row) {
this.$refs.departmentProgressDetail.row = row
this.$refs.departmentProgressDetail.isShowModal = true
},
}
}
</script>
<style scoped>
.department-card {
border-radius: 8px;
margin-bottom: 15px;
transition: all 0.3s;
}
.department-card:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.card-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
}
.execution-rate {
font-size: 20px;
font-weight: bold;
}
.text-muted {
color: #909399;
text-align: center;
margin-bottom:10px;
font-size: 16px;
}
.fw-bold {
font-weight: bold;
color:#000;
font-size: 16px;
}
.text-success {
color: #67C23A;
}
.text-warning {
color: #E6A23C;
}
.text-primary{
color: #409EFF;
}
.d-flex {
display: flex;
}
.justify-between {
justify-content: space-between;
}
.align-center {
align-items: center;
}
.detail{
border:1px solid #409EFF;
text-align: center;
cursor:pointer
}
.mb-1 {
margin-bottom: 4px;
}
.mb-2 {
margin-bottom: 12px;
}
.mb-4 {
margin-bottom: 24px;
}
.mt-3 {
margin-top: 16px;
}
</style>