Files
sunProduct/src/views/system/report/arrears.vue
2026-08-31 18:00:11 +08:00

376 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="p-2 h-full flex flex-col">
<pageHeader></pageHeader>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :inline="true" :model="queryParams" @submit.prevent="handleQuery">
<div class="flex justify-between">
<div>
<el-form-item label="小区" prop="villageId">
<el-select v-model="queryParams.villageId" placeholder="请选择" @change="handleVillageChange">
<el-option v-for="item in villageList" :key="item.villageId" :label="item.villageName" :value="item.villageId" />
</el-select>
</el-form-item>
<el-form-item label="收费项目" prop="chargeItemId">
<el-select v-model="queryParams.chargeItemId" placeholder="请选择">
<el-option v-for="item in chargeItemList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="房屋类型" prop="houseUseId">
<el-select v-model="queryParams.houseUseId" placeholder="请选择">
<el-option v-for="item in houseUseList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</div>
<div>
<el-button type="primary" @click="handleQuery">搜索</el-button>
<el-button @click="resetQuery">重置</el-button>
</div>
</div>
</el-form>
</el-card>
</div>
</transition>
<el-card class="flex-1" shadow="never">
<template #header>
<el-row :gutter="10" style="margin-bottom: 30px">
<el-col :span="5">
<div class="flex items-center">
<div style="width: 200px; font-size: 15px; margin-right: 10px">应收欠费汇总列表</div>
<el-select v-model="queryParams.viewType" placeholder="请选择视图类型" @change="handleViewTypeChange">
<el-option :value="1" label="维度1(按收费类型)" />
<el-option :value="2" label="维度2(按房屋类型)" />
</el-select>
</div>
</el-col>
<el-col :span="18"></el-col>
<el-col :span="1">
<el-button type="primary" @click="handleExport">导出</el-button>
</el-col>
</el-row>
</template>
<el-table
:key="queryParams.viewType"
v-loading="loading"
:data="ArrearsList"
:row-class-name="handleRowClass"
:span-method="mergeSpanMethod"
border
>
<el-table-column align="center" label="小区" prop="villageName" />
<template v-if="queryParams.viewType === 1">
<el-table-column align="center" label="收费项目" prop="chargeItemName" />
<el-table-column v-for="(item, index) in houseTypeKeys" :key="index" :label="item" align="center">
<template #default="scope">
<span>{{ scope.row.houseTypeAmounts?.[item] || '---' }}</span>
</template>
</el-table-column>
</template>
<template v-if="queryParams.viewType === 2">
<el-table-column align="center" label="房屋类型" prop="houseTypeName" />
<el-table-column v-for="(item, index) in houseTypeKeys2" :key="index" :label="item" align="center">
<template #default="scope">
<span>{{ scope.row.chargeItemAmounts?.[item] || '---' }}</span>
</template>
</el-table-column>
</template>
<el-table-column align="center" label="金额" prop="totalAmount" />
</el-table>
<!-- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />-->
</el-card>
</div>
</template>
<script lang="ts" name="Arrears" setup>
// import pagination from '@/components/Pagination/index.vue';
import pageHeader from '@/components/Pageheader/index.vue';
import { getArrearsList } from '@/api/system/report/arrears/arrears';
// import { ArrearsQuery } from '@/api/system/residentReviewProcess/type';
import { listHouseUseType } from '@/api/system/houseUse';
import { listChargeItem } from '@/api/system/SdbChargeItem';
import { getCommunitylistAPI } from '@/api/system/community';
import { ArrearsVO } from '@/api/system/report/arrears/type';
import { exportToExcel } from '@/utils/xlsx';
import { ref } from 'vue';
import { listChargeType } from '@/api/system/ChargeType';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const ArrearsList = ref<ArrearsVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const queryFormRef = ref<ElFormInstance>();
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
viewType: 1,
villageId: '-1',
chargeItemId: '-1',
houseUseId: '-1'
}
});
const { queryParams } = toRefs(data);
// 查询 房屋类型
const houseUseList = ref([]);
function handleQueryHouseUse() {
listHouseUseType().then((res) => {
houseUseList.value = [
{
id: '-1',
name: '全部类型'
},
...res.rows
];
});
}
// 收费项目
// 查询小区
const villageList = ref([]);
function getAllVillage() {
getCommunitylistAPI().then((res) => {
villageList.value = [
{
villageId: '-1',
villageName: '全部小区'
},
...res.rows
];
});
}
// 改变小区
function handleVillageChange(val: string) {
queryParams.value.villageId = val;
queryParams.value.chargeItemId = '-1';
}
const chargeItemList = ref([]);
// 忽略的收费项目id, 水费,电费,燃气费,上线前手工导入
const ignoreChargeItemList = ['2049026503017136129', '2064181187503652865', '2091072780916981761', '2049026540430327809'];
function getChargeList() {
listChargeType().then((res) => {
chargeItemList.value = [
{
id: '-1',
name: '全部项目'
},
...res.rows.filter((item) => !ignoreChargeItemList.includes(item.id))
];
});
}
function handleViewTypeChange(val: number) {
queryParams.value.viewType = val;
getList();
}
/** 查询电抄记录列表 */
const getList = async () => {
loading.value = true;
const search = { ...queryParams.value };
// 移除空字符串字段
Object.keys(search).forEach((key) => {
if (search[key] === '-1') {
search[key] = undefined;
}
});
getArrearsList(search)
.then((res) => {
ArrearsList.value = res.data;
})
.finally(() => {
loading.value = false;
});
};
// 提取全表所有房型,统一所有行列(使用缓存优化)
const houseTypeKeys = computed(() => {
const keys = new Set();
const list = ArrearsList.value;
for (let i = 0; i < list.length; i++) {
const amounts = list[i].houseTypeAmounts;
if (amounts) {
Object.keys(amounts).forEach((k) => keys.add(k));
}
}
return [...keys] as string[];
});
const houseTypeKeys2 = computed(() => {
const keys = new Set();
const list = ArrearsList.value;
for (let i = 0; i < list.length; i++) {
const amounts = list[i].chargeItemAmounts;
if (amounts) {
Object.keys(amounts).forEach((k) => keys.add(k));
}
}
return [...keys] as string[];
});
function handleRowClass({ row }) {
if (queryParams.value.viewType === 1) {
if (row.chargeItemName === '合计') {
// 示例1:收费项目等于物业费的行加深色
return 'bg-dark';
}
return '';
} else {
if (row.houseTypeName === '合计') {
// 示例1:收费项目等于物业费的行加深色
return 'bg-dark';
}
return '';
}
}
const mergeSpanMethod = ({ row, columnIndex, rowIndex }) => {
const lastRowIndex = ArrearsList.value.length - 1;
if (rowIndex === lastRowIndex) {
if (columnIndex === 0) {
return { rowspan: 1, colspan: 2 };
}
if (columnIndex === 1) {
return { rowspan: 0, colspan: 0 };
}
}
if (columnIndex === 0) {
if (rowIndex > 0 && row.villageName === ArrearsList.value[rowIndex - 1].villageName) {
return { rowspan: 0, colspan: 0 };
}
let rowspan = 1;
for (let i = rowIndex + 1; i < ArrearsList.value.length; i++) {
if (ArrearsList.value[i].villageName === row.villageName) {
rowspan++;
} else {
break;
}
}
return { rowspan, colspan: 1 };
}
// 普通行不合并
return { rowspan: 1, colspan: 1 };
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 导出Excel */
const handleExport = () => {
if (ArrearsList.value.length === 0) {
proxy?.$modal.msgWarning('没有可导出的数据');
return;
}
// 显示加载提示
loading.value = true;
// 使用 setTimeout 让出主线程,避免阻塞UI
setTimeout(() => {
try {
const columns: { label: string; prop: string }[] = [{ label: '小区', prop: 'villageName' }];
if (queryParams.value.viewType === 1) {
columns.push({ label: '收费项目', prop: 'chargeItemName' });
houseTypeKeys.value.forEach((type) => {
columns.push({ label: type, prop: `houseTypeAmounts[${type}]` });
});
} else if (queryParams.value.viewType === 2) {
columns.push({ label: '房屋类型', prop: 'houseTypeName' });
houseTypeKeys2.value.forEach((type) => {
columns.push({ label: type, prop: `chargeItemAmounts[${type}]` });
});
}
columns.push({ label: '金额', prop: 'totalAmount' });
const processedData = ArrearsList.value.map((row) => {
const obj: any = {
villageName: row.villageName,
totalAmount: row.totalAmount
};
if (queryParams.value.viewType === 1) {
obj.chargeItemName = row.chargeItemName;
houseTypeKeys.value.forEach((type) => {
obj[`houseTypeAmounts[${type}]`] = row.houseTypeAmounts?.[type] || 0;
});
} else if (queryParams.value.viewType === 2) {
obj.houseTypeName = row.houseTypeName;
houseTypeKeys2.value.forEach((type) => {
obj[`chargeItemAmounts[${type}]`] = row.chargeItemAmounts?.[type] || 0;
});
}
return obj;
});
const mergeSpanMethod = ({ row, columnIndex, rowIndex }) => {
const lastRowIndex = ArrearsList.value.length - 1;
if (rowIndex === lastRowIndex) {
if (columnIndex === 0) {
return { rowspan: 1, colspan: 2 };
}
if (columnIndex === 1) {
return { rowspan: 0, colspan: 0 };
}
}
if (columnIndex === 0) {
if (rowIndex > 0 && row.villageName === ArrearsList.value[rowIndex - 1].villageName) {
return { rowspan: 0, colspan: 0 };
}
let rowspan = 1;
for (let i = rowIndex + 1; i < ArrearsList.value.length; i++) {
if (ArrearsList.value[i].villageName === row.villageName) {
rowspan++;
} else {
break;
}
}
return { rowspan, colspan: 1 };
}
// 普通行不合并
return { rowspan: 1, colspan: 1 };
};
exportToExcel(processedData, columns, `应收欠费汇总_${new Date().getTime()}`, mergeSpanMethod);
} catch (error) {
proxy?.$modal.msgError('导出失败,请重试');
console.error('导出错误:', error);
} finally {
loading.value = false;
}
}, 100);
};
onMounted(() => {
getChargeList();
getList();
handleQueryHouseUse();
getAllVillage();
});
</script>
<style lang="scss" scoped>
.el-table {
height: calc(100% - 80px);
}
/* 深度穿透修改表格行背景 */
:deep(.bg-dark td) {
background-color: #f5f7fa !important;
}
/* hover 悬浮保留深色 */
:deep(.bg-dark:hover td) {
background-color: #d0e4fb !important;
}
</style>