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
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>
|