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.

375 lines
12 KiB

<template>
<div>
<Modal
:width="78"
v-model="isShow"
title="绩效自评表">
<div class="detail-achievement-modal__body">
<table id="detail-achievement-table" ref="detail-achievement-table">
<tr>
<th style="text-align: center;font-weight: 600;line-height: 2;font-size: 17px;" colspan="9">江苏省省级项目预算绩效目标表</th>
</tr>
<tr>
<td style="text-align: center;font-weight: 600;" colspan="9">{{ detail.year }} 年度</td>
</tr>
<tr>
<th>{{ type === 1 ? '年度' : '年度' }}绩效目标</th>
<td colspan="8">{{ type === 1 ? detail.year_midst : detail.year_end }}</td>
</tr>
<tr>
<th>{{ type === 1 ? '年度' : '年度' }}绩效目标完成情况</th>
<td colspan="8">{{ type === 1 ? detail.middle_result : detail.end_result }}</td>
</tr>
<!-- <tr>-->
<!-- <th>单位名称</th>-->
<!-- <td colspan="7">江苏省苏州环境监测中心</td>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <th>主要职能</th>-->
<!-- <td colspan="7">{{ detail.content }}</td>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <th>机构设置及人员配置</th>-->
<!-- <td colspan="7"></td>-->
<!-- </tr>-->
<!-- <tr>-->
<!-- <th :rowspan="contractList.length+1">预算安排及支出情况</th>-->
<!-- <td colspan="2">-->
<!-- </td>-->
<!-- <th colspan="3">-->
<!-- 全年预算数-->
<!-- </th>-->
<!-- <th colspan="2">-->
<!-- 实际支出数-->
<!-- </th>-->
<!-- </tr>-->
<!-- <tr v-for="(item, index) in contractList">-->
<!-- <td colspan="2">-->
<!-- {{ item.name }}-->
<!-- </td>-->
<!-- <td colspan="3">-->
<!-- {{ item.plan_price }}-->
<!-- </td>-->
<!-- <td colspan="2">-->
<!-- {{ item.money}}-->
<!-- </td>-->
<!-- </tr>-->
<tr>
<th>一级指标</th>
<th>二级指标</th>
<th>三级指标</th>
<th style="min-width: 100px;">{{ type === 1 ? '半年' : '全年' }}(程)指标值</th>
<th>{{ type === 1 ? '半年实际执行值' : '实际完成值' }}</th>
<th v-if="type === 1">是否偏差(是/否)</th>
<th v-if="type === 1">完成可能性(确定能/有可能/完全不可能)</th>
<th v-if="type !== 1">分值</th>
<th v-if="type !== 1">得分</th>
<th v-if="type !== 1" style="max-width: 30%;">评价要点及评分规则</th>
<th v-if="type !== 1" style="max-width: 24%;">未完成指标原因分析</th>
<th v-if="type !== 1" style="width: 46px;" class="no-export-xlsx">附件</th>
</tr>
<tr v-for="(item, index) in planTargetList" :key="item.id">
<td :rowspan="spanArr[index]" v-if="spanArr[index]" :style="{ 'display': spanArr[index] ? '' : 'none' }">{{ (item.target && item.target.target_type_detail) ? item.target.target_type_detail.name : '' }}</td>
<td :rowspan="spanArr1[index]" v-if="spanArr1[index]" :style="{ 'display': spanArr1[index] ? '' : 'none' }">{{ (item.target && item.target.target_type2_detail) ? item.target.target_type2_detail.name : '' }}</td>
<td>{{ item.target ? item.target.name : '' }}</td>
<td>{{ targetValue(item) }}</td>
<td>{{ actResultFormat(item) }}</td>
<td v-if="type === 1">{{ isDeviation(item) }}</td>
<td v-if="type === 1">{{ endPossibility(item) }}</td>
<td v-if="type !== 1">{{ item.score }}</td>
<td v-if="type !== 1">{{ socre(item) }}</td>
<td v-if="type !== 1" style="max-width: 300px;">{{ evaluationMain(item) }}</td>
<td v-if="type !== 1">{{ remark(item) }}</td>
<td class="no-export-xlsx" v-if="type !== 1">
<el-popover
placement="bottom-start"
title="附件"
width="220"
trigger="hover">
<el-link slot="reference" type="primary">查看</el-link>
<template>
<div v-if="files(item).length > 0">
<div v-for="(file) in files(item)">
<el-link :href="file.url" target="_blank">{{ file.original_name }}</el-link>
</div>
</div>
<div v-else>
<p style="text-align: center;color: #999;">暂无附件</p>
</div>
</template>
</el-popover>
</td>
</tr>
<tr v-if="type !== 1">
<th colspan="5">合计</th>
<td>{{ targetTotal }}</td>
<td>{{ scoreTotal }}</td>
<th colspan="2"></th>
</tr>
<tr v-if="type !== 1">
<th>绩效等级</th>
<td colspan="8">{{ type === 1 ? detail.middle_achievement : detail.end_achievement }}</td>
</tr>
<tr v-if="type !== 1">
<th>主要成效(通过绩效评价总结的成效)</th>
<td colspan="8">{{ type === 1 ? detail.middle_effect : detail.end_effect }}</td>
</tr>
<tr>
<th>{{ type === 1 ? '偏差问题及原因(主要针对偏差指标)' : '存在问题(按照决策、过程、履职、效益分别归类撰写)' }}</th>
<td colspan="8">{{ type === 1 ? detail.middle_question : detail.end_question }}</td>
</tr>
<tr>
<th>整改措施(针对存在的问题,分别提出相关整改措施)</th>
<td colspan="8">{{ type === 1 ? detail.middle_measure : detail.end_measure }}</td>
</tr>
</table>
</div>
<template #footer>
<div>
<Button @click="hide">关闭</Button>
<Button type="primary" icon="ios-download-outline" @click="exportExcel">导出</Button>
</div>
</template>
</Modal>
</div>
</template>
<script>
import { detailBudget } from "@/api/budget/budget";
import { index } from "@/api/budget/planTarget";
import { getContract } from "@/api/contract/contract";
import * as XLSX from "xlsx";
import { saveAs } from "file-saver";
export default {
props: {
//1年中 年末
type: Number
},
data() {
return {
pos: 0,
pos1: 0,
spanArr: [],
spanArr1: [],
isShow: false,
planId: "",
detail: {},
planTargetList: [],
contractList: []
}
},
methods: {
show() {
this.isShow = true;
},
hide() {
this.isShow = false;
},
setPlanId(planId) {
this.planId = planId;
},
async getBudgetDetail() {
this.detail = await detailBudget({ id: this.planId },true)
},
async getPlanTarget() {
const list = (await index({ plan_id: this.planId },true))?.data?.sort((a,b) => a.target.target_type_id - b.target.target_type_id)
this.pos = this.pos1 = 0;
this.spanArr = [];
this.spanArr1 = [];
for(let i in list){
if(i === 0){
this.spanArr.push(1);
this.pos = 0;
this.spanArr1.push(1);
this.pos1 = 0;
}else{
if(list[i]?.target?.target_type_id === list[i-1]?.target?.target_type_id){
this.spanArr[this.pos] += 1;
this.spanArr.push(0)
}else{
this.spanArr.push(1);
this.pos = i;
}
if(list[i]?.target?.target_type2_id === list[i-1]?.target?.target_type2_id){
this.spanArr1[this.pos1] += 1;
this.spanArr1.push(0)
}else{
this.spanArr1.push(1);
this.pos1 = i;
}
}
}
this.planTargetList = list;
},
async getContract () {
const res = (await getContract({
plan_id: this.planId,
page: 1,
page_size: 1000,
}))?.list?.data
this.contractList = res;
},
async exportExcel () {
let tableDom = this.$refs['detail-achievement-table'].cloneNode(true);
tableDom.querySelectorAll(".no-export-xlsx").forEach(item => {
item.parentNode.removeChild(item)
})
let wb = XLSX.utils.table_to_book(tableDom)
let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
// 获取table中的行数
const table = this.$refs['detail-achievement-table'];
const rowCount = table.rows.length;
// 设置行高
const ws = wb.Sheets[wb.SheetNames[0]];
if (!ws['!rows']) ws['!rows'] = [];
const rowHeight = 100; // 行高设置为30
for (let i = 0; i < rowCount; i++) {
ws['!rows'][i] = { hpx: rowHeight };
}
ws['cols'] = Array.from({ length: 8 }, (v, k) => ({ wpx: 200}))
function s2ab(s) {
let buf = new ArrayBuffer(s.length);
let view = new Uint8Array(buf);
for (let i = 0; i < s.length; i++) {
view[i] = s.charCodeAt(i) & 0xff;
}
return buf;
}
await saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), "绩效自评价表.xlsx")
}
},
computed: {
moneyFormat () {
return function(money) {
if (!money) {
return "0.00"
}
if (typeof money === "number") {
return (money / 10000).toFixed(2)
} else {
return (parseFloat(money) / 10000).toFixed(2)
}
}
},
targetValue () {
return function(item) {
if (item.target?.unit_detail?.value !== '无') {
return `${item.target?.symbol_detail?.value}${this.type ? item.target?.half_target : item.target?.year_target}${item.target?.unit_detail?.value}`
} else {
return this.type === 1 ? item.target?.half_target : item.target?.year_target
}
}
},
isDeviation () {
return function(item) {
return item.plan_evaluates?.find(j => (j.plan_target_id === item.id && j.type === this.type))?.is_deviation ? '是' : '否'
}
},
endPossibility () {
const type = new Map([
[0, '确定能'],
[1, '有可能'],
[2, '完全不可能']
])
return function(item) {
return type.get(item.plan_evaluates?.find(j => (j.plan_target_id === item.id && j.type === this.type))?.end_possibility)
}
},
actResultFormat () {
return function(item) {
return item.plan_evaluates?.find(j => (j.plan_target_id === item.id && j.type === this.type))?.result
}
},
socre () {
return function(item) {
return item.plan_evaluates?.find(j => (j.plan_target_id === item.id && j.type === this.type))?.socre
}
},
evaluationMain () {
return function(item) {
return item.plan_evaluates?.find(j => (j.plan_target_id === item.id && j.type === this.type))?.evaluation_main
}
},
files () {
return function(item) {
return item.plan_evaluates?.find(j => j.plan_target_id === item.id)?.files || []
}
},
targetTotal () {
return this.planTargetList.reduce((pre, cur) => {
return pre + (parseFloat(cur.score) || 0)
}, 0).toFixed(2)
},
scoreTotal () {
return this.planTargetList.reduce((pre, cur) => {
return pre + (parseFloat(cur?.plan_evaluates?.find(j => (j.plan_target_id === cur.id && j.type === this.type))?.socre) || 0)
}, 0).toFixed(2)
},
remark () {
return function(item) {
return item.plan_evaluates?.find(j => (j.plan_target_id === item.id && j.type === this.type))?.remark
}
}
},
watch: {
isShow (newVal, oldVal) {
if (newVal) {
this.getBudgetDetail()
this.getPlanTarget()
this.getContract()
}
}
}
}
</script>
<style scoped lang="scss">
.detail-achievement-modal__body {
padding: 10px;
max-height: 62vh;
overflow: scroll;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
thead {
background-color: #f2f2f2;
}
th {
word-break: keep-all;
text-align: center;
height: 40px;
}
</style>