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.

387 lines
11 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 style="padding: 0 20px;">
<lx-header icon="md-apps" text="预算进展情况" style="margin-bottom: 10px; border: 0px; margin-top: 15px">
<div slot="content" />
<slot>
<span style="padding: 0 6px;word-break: keep-all;">年份</span>
<span>
<DatePicker
:value="select.year"
placeholder="请选择年份"
type="year"
placement="bottom-start"
style="width: 160px"
@on-change="(e)=>select.year = e"
/>
</span>
<span style="padding: 0 6px;word-break: keep-all;">预算类型</span>
<span>
<el-select
v-model="select.type"
size="small"
clearable
placeholder="请选择预算类型"
type="date"
style="width: 160px"
>
<el-option v-for="item in type" :key="item.id" :value="item.id" :label="item.value" />
</el-select>
</span>
<span style="padding: 0 6px;">
科室
</span>
<span>
<el-select v-model="select.department" placeholder="科室选择" clearable size="small" style="width: 160px;">
<el-option v-for="item in departments" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</span>
<span style="padding: 0 6px;word-break: keep-all;">付款日期</span>
<span>
<DatePicker
v-model="select.showDatePicker"
clearable
placeholder="请选择日期"
placement="bottom-start"
style="width: 200px"
type="daterange"
@on-change="datePick"
/>
</span>
<Button
type="primary"
style="margin-left: 10px"
ghost
@click="select = {pageIndex:1,year:'',type:'',department:''}"
>重置</Button>
<Button type="primary" style="margin-left: 10px" @click="getPlanProgress">查询</Button>
</slot>
</lx-header>
<!-- :object-span-method="objectSpanMethod" -->
<xy-table ref="xyTable"
:defaultExpandAll="false" row-key="id"
:table-item="table" :list="list" :show-summary="true" :summary-method="summary">
<template v-slot:btns>
<div />
</template>
</xy-table>
<!-- <div style="display: flex;justify-content: flex-end;">
<Page :total="total" :page-size="select.page_size" show-elevator @on-change="pageChange" />
</div> -->
</div>
</template>
<script>
import {
getProgress
} from '@/api/budget/budget'
import {
listdeptNoAuth
} from '@/api/system/department'
import {
getparameter
} from '@/api/system/dictionary'
import {
moneyFormatter
} from '@/utils'
import {
mergeTableRow
} from '@/utils/mergeTableRow'
export default {
data() {
return {
type: [], // 预算类型
departments: [],
select: {
page_size:999,
pageIndex: 1,
year: '',
type: '',
department: '',
showDatePicker: '',
start_created_at: '',
end_created_at: '',
sort_type: 'asc'
},
rateTotal: '0%',
moneyTotal: 0,
updateMoneyTotal: 0,
useMoneyTotal: 0,
total: 0,
list: [],
table: [{
label: '隶属项目',
prop: 'pid_info_name',
width: 200,
align: 'left',
sortable: false,
fixed: 'left'
},
{
prop: 'name',
label: '项目名称',
width: 200,
align: 'left',
fixed: 'left'
},
{
prop: 'money',
width: 180,
label: '年初预算数(元)',
align: 'right'
},
{
prop: 'update_money',
width: 180,
label: '调整后预算数(元)',
align: 'right'
},
{
prop: 'use_money_total',
label: '使用金额',
align: 'right',
width: 180,
customFn: row => {
return (
<a on={{
'click': _ => {
if(!row.isParent){
this.$router.push({
path: '/contract/paymentRegistrationList_1',
query: {
plan_id: row.id,
plan_name: `[${row.year}]-${row.name}`
}
})
}
}
}}>{ row.use_money_total }</a>
)
}
},
{
prop: 'calculation_result',
label: '进展率',
width: 200,
fixed: 'right',
customFn: (row) => {
const per = (isNaN(Number(row.use_money_total ?? 0)) ? 0 : Number(row.use_money_total ?? 0)) / ((Number(row.update_money)) || (Number(row.money)))
return (<div>
<el-progress percentage = {
Number((per * 100).toFixed(2))
} > </el-progress> </div>
)
}
},
{
prop: 'type',
label: '预算类型',
width: 120,
formatter: (cell, data, value) => {
const res = this.type.filter(item => {
return item.id === value
})
return res[0]?.value || '未知'
}
},
{
prop: 'year',
label: '所属年份',
width: 160
},
{
prop: 'plan_department.name',
label: '相关科室',
width: 180
},
{
prop: 'content',
label: '描述',
align: 'left',
width: 300
},
]
}
},
created() {
this.select.year = this.$moment().format('YYYY')
},
async mounted() {
await this.getType()
await this.getDepartment()
this.select.department = Number(this.$route.query.departmentId) || ''
this.select.type = Number(this.$route.query.type) || ''
await this.getPlanProgress()
},
methods: { // 合并行,
// 日期选择
datePick(e) {
this.select.start_created_at = e[0]
this.select.end_created_at = e[1]
},
objectSpanMethod({
row,
column,
rowIndex,
columnIndex
}) {
const span = column['property'] + '-span'
if (row[span]) {
return row[span]
}
},
toper(m2, m1, m3) {
let per = 0
if (m2 != 0) {
per = ((m3 / m2) * 100).toFixed(2)
} else if (m1 != 0) {
per = ((m3 / m1) * 100).toFixed(2)
}
return per
},
// 统计
summary(param) {
this.$nextTick(() => {
this.$refs['xyTable'].$children[0].doLayout()
})
const {
columns,
data
} = param
const sums = []
columns.map((column, index) => {
if (index === 0) {
sums[index] = '总计'
return
}
if (column.property === 'rate') {
sums[index] = this.rateTotal + '%'
return
}
if (column.property === 'use_money_total') {
sums[index] = moneyFormatter(this.useMoneyTotal)
}
if (column.property === 'money') {
sums[index] = moneyFormatter(this.moneyTotal)
}
if (column.property === 'update_money') {
sums[index] = moneyFormatter(this.updateMoneyTotal)
}
})
return sums
},
async getType() {
const res = await getparameter({
number: 'money_way'
})
this.type = res.detail
},
// 翻页
pageChange(e) {
this.select.pageIndex = e
this.getPlanProgress()
},
// 获取科室
getDepartment() {
listdeptNoAuth().then(res => {
this.departments = res
})
},
async getPlanProgress() {
const res = await getProgress({
page_size: this.select.page_size,
page: this.select.pageIndex,
year: this.select.year,
type: this.select.type,
plan_department_id: this.select.department,
top_pid: 1,
...this.select
})
// for (var m of res.list.data) {
// m.pid_info_name = m.pid_info?.name
// }
// this.list =
// mergeTableRow({
// data: res.list.data,
// mergeColNames: ['pid_info_name'], // 需要合并的列,默认合并列相同的数据
// firstMergeColNames: ['pid_info_name'], // 受影响的列只合并以firstMerge为首的同类型数据
// firstMerge: 'pid_info_name' // 以哪列为基础进行合并,一般为第一列
// })
this.list = this.concactPid(res.list.data)
this.total = res.list.total
this.useMoneyTotal = res.use_money_total
this.moneyTotal = res.money
this.updateMoneyTotal = res.update_money
this.rateTotal = this.toper(this.updateMoneyTotal, this.moneyTotal, this.useMoneyTotal)
console.log("list",this.list)
},
concactPid(arr){
const groupByPid = {};
arr.forEach(item => {
const key = item.pid;
if (!groupByPid[key]) {
groupByPid[key] = [];
}
groupByPid[key].push(item);
});
// 2. 构建合并后的数组
const mergedResult = Object.values(groupByPid).map(children => {
// 从分组的第一项中获取 pid_info因同 pid 的 pid_info 相同)
const pidInfo = children[0].pid_info;
// 计算父级的 use_money_totalchildren 中 use_money_total 之和null 视为 0
const useMoneyTotal = children.reduce((sum, child) => {
const value = child.use_money_total ?? 0; // 处理 null
return parseFloat(sum) + parseFloat(value);
}, 0);
// 构建父级对象
return {
pid: children[0].pid, // 父级 pid 与分组的 pid 一致
id:pidInfo.pid+'-'+pidInfo.id,
pid_info_name: pidInfo.name,
money: parseFloat(pidInfo.money).toFixed(2),
type: pidInfo.type,
isParent:true,
update_money: parseFloat(pidInfo.update_money).toFixed(2),
use_money_total: parseFloat(useMoneyTotal).toFixed(2), // 子项总和
children: children // 保留所有子项
};
});
const arrayWithPer = mergedResult.map(row => {
// 计算 per公式use_money_total / (update_money || money),处理 null 和 NaN
const useMoneyTotal = Number(row.use_money_total ?? 0); // null 视为 0转换为数字
const denominator = Number(row.update_money) || Number(row.money); // 取 update_money 或 money
const calculation_result = isNaN(useMoneyTotal / denominator) ? 0 : useMoneyTotal / denominator;
return {
...row,
calculation_result: calculation_result // 新增 per 字段
};
});
const sortedArray = arrayWithPer.sort((a, b) => b.calculation_result - a.calculation_result);
return sortedArray
}
}
}
</script>
<style scoped lang="scss">
</style>