8/19 报表-租赁管理
This commit is contained in:
@@ -2,136 +2,116 @@
|
||||
<div class="p-2 h-full flex flex-col">
|
||||
<pageHeader></pageHeader>
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" label-width="140" :model="queryParams" @submit.prevent="handleQuery" :inline="true">
|
||||
<el-form ref="queryFormRef" label-width="140" :rules="formRules" :model="queryParams" @submit.prevent="handleQuery" :inline="true">
|
||||
<div>
|
||||
<el-form-item label="区域(多选)" prop="villageId">
|
||||
<el-date-picker
|
||||
v-model="queryTime"
|
||||
type="daterange"
|
||||
@update:model-value="handleQueryTime"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="承租方" prop="chargeItemId">
|
||||
<el-select @change="handleVillageChange" v-model="queryParams.villageId" placeholder="请选择">
|
||||
<el-form-item label="区域(多选)" prop="villageIds">
|
||||
<el-select v-model="queryParams.villageIds" :multiple="true" placeholder="请选择区域">
|
||||
<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="houseNo">
|
||||
<el-input v-model.trim="queryParams.houseNo" placeholder="关键字查询" />
|
||||
<el-form-item label="承租方" prop="lessee">
|
||||
<el-input v-model.trim="queryParams.lessee" placeholder="请输入承租方" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房号" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="关键字查询">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-form-item label="电话" prop="phone">
|
||||
<el-input type="tel" v-model.trim="queryParams.phone" placeholder="请输入电话" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房号" prop="roomNumber">
|
||||
<el-input v-model.trim="queryParams.roomNumber" placeholder="请输入房号" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<div v-show="showSearch" class="mb-[10px]" style="overflow: auto; overflow-y: hidden">
|
||||
<div>
|
||||
<!-- 搜索条件: 面积/收费模式/收费标准 -->
|
||||
<div>
|
||||
<el-form-item label="面积" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
<el-form-item label="面积" prop="areaSize" style="margin-bottom: 0">
|
||||
<el-input v-model.trim="queryParams.areaSize" placeholder="请输入面积区间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收费模式(多选)" prop="chargeModes" style="margin-bottom: 0">
|
||||
<el-select v-model="queryParams.chargeModes" placeholder="请选择收费模式" :multiple="true">
|
||||
<el-option v-for="item in com_house_rental_pricing_model" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="收费模式(多选)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="收费标准(多选)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="租金(应收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="押金(应收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="区间搜索 1000-10000">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物业管理费(应收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="**(应收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="关键字查询">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="租金(已收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="押金(已收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="区间搜索 1000-10000">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物业管理费(已收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="**(已收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="关键字查询">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
<el-form-item label="租金(未收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="押金(未收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="区间搜索 1000-10000">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物业管理费(未收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="**(未收)" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="关键字查询">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
<el-form-item label="收费标准(多选)" prop="chargeStandards" style="margin-bottom: 0">
|
||||
<el-select v-model="queryParams.chargeStandards" placeholder="请选择收费标准" :multiple="true">
|
||||
<el-option v-for="item in com_house_rental_pricing" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
|
||||
<el-scrollbar>
|
||||
<div style="width: fit-content">
|
||||
<!-- 搜索条件: 应收/已收/未收 -->
|
||||
<div class="queryBox_over">
|
||||
<el-form-item
|
||||
:label="`${item.chargeTypeName}(应收)`"
|
||||
:prop="`chargeTypeFilters[${index}].receivable`"
|
||||
v-for="(item, index) in queryParams.chargeTypeFilters"
|
||||
:key="index"
|
||||
>
|
||||
<el-input v-model.trim="queryParams.chargeTypeFilters[index].receivable" placeholder="区间搜索 示例:100-2000" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="queryBox_over">
|
||||
<el-form-item
|
||||
:label="`${item.chargeTypeName}(已收)`"
|
||||
:prop="`chargeTypeFilters[${index}].received`"
|
||||
v-for="(item, index) in queryParams.chargeTypeFilters"
|
||||
:key="index"
|
||||
>
|
||||
<el-input v-model.trim="queryParams.chargeTypeFilters[index].received" placeholder="区间搜索 示例:100-2000" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="queryBox_over">
|
||||
<el-form-item
|
||||
v-for="(item, index) in [...queryParams.chargeTypeFilters]"
|
||||
style="margin-bottom: 0"
|
||||
:label="`${item.chargeTypeName}(未收)`"
|
||||
:key="index"
|
||||
:prop="`chargeTypeFilters[${index}].uncollected`"
|
||||
>
|
||||
<el-input v-model.trim="queryParams.chargeTypeFilters[index].uncollected" placeholder="区间搜索 示例:100-2000" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<div class="line"></div>
|
||||
<!-- 搜索条件: 租赁起始日期/租赁终止日期 -->
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<el-form-item label="租赁起始日期" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-form-item label="租赁起始日期" prop="leaseStartDate">
|
||||
<el-date-picker
|
||||
v-model="leaseStartDate"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@clear="handleClear('leaseStartDate')"
|
||||
@update:model-value="(val: string[]) => handleUpdateLeaseDate('leaseStartDate', val)"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="租赁终止日期" prop="month">
|
||||
<el-select v-model="queryParams.month" placeholder="请选择">
|
||||
<el-option v-for="item in MonthList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-form-item label="租赁终止日期" prop="leaseEndDate">
|
||||
<el-date-picker
|
||||
v-model="leaseEndDate"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD"
|
||||
@clear="handleClear('leaseEndDate')"
|
||||
@update:model-value="(val: string[]) => handleUpdateLeaseDate('leaseEndDate', val)"
|
||||
placeholder="请选择"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-if="showSearch">
|
||||
<el-form-item label="">
|
||||
<el-button type="primary">查询</el-button>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<div class="arrowBox" style="margin-left: 10px" v-if="showSearch" @click="ChangeShowSearch(false)">
|
||||
<span>收起</span>
|
||||
@@ -149,7 +129,7 @@
|
||||
</transition>
|
||||
<div v-if="!showSearch">
|
||||
<el-form-item label="">
|
||||
<el-button type="primary">查询</el-button>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<div class="arrowBox" style="margin-left: 10px" v-if="showSearch" @click="ChangeShowSearch(false)">
|
||||
<span>收起</span>
|
||||
@@ -175,26 +155,39 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table :span-method="mergeSpanMethod" v-loading="loading" border :data="ArrearsDetailList">
|
||||
<el-table-column label="序号" width="80" align="center" prop="serialNumber" />
|
||||
<el-table v-loading="loading" border :data="ArrearsDetailList">
|
||||
<el-table-column label="区域" align="center" prop="area" />
|
||||
<el-table-column label="房号" align="center" prop="houseNo" />
|
||||
<el-table-column label="客户" align="center" prop="customerName" />
|
||||
<el-table-column label="联系电话" align="center" prop="phone" />
|
||||
<el-table-column label="欠费月数" width="80" align="center" prop="arrearsMonths" />
|
||||
<el-table-column label="应收账期" align="center" prop="billPeriod" />
|
||||
<el-table-column label="欠费项目" align="center">
|
||||
<el-table-column label="承租方" align="center" prop="lessee" />
|
||||
<el-table-column label="电话" width="120" align="center" prop="phone" />
|
||||
<el-table-column label="房号" align="center" prop="roomNumber" />
|
||||
<el-table-column label="面积" width="80" align="center" prop="areaSize" />
|
||||
<el-table-column label="收费模式" align="center" prop="chargeMode" />
|
||||
<el-table-column label="收费标准" align="center" prop="chargeStandard" />
|
||||
<el-table-column label="租赁起始日" align="center" prop="leaseStartDate" />
|
||||
<el-table-column label="租赁终止日" align="center" prop="leaseEndDate" />
|
||||
<el-table-column label="应收项目" align="center">
|
||||
<template #default>
|
||||
<template v-for="(item, index) in dynamicColumns" :key="index">
|
||||
<el-table-column :label="item" align="center">
|
||||
<template #default="scope">
|
||||
{{ scope.row.chargeItemAmounts?.[item] || 0 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<el-table-column label="金额合计" align="center" prop="totalAmount">
|
||||
<el-table-column v-for="(item, index) in dynamicColumns" :key="index" :label="item.chargeTypeName" align="center" prop="totalAmount">
|
||||
<template #default="scope">
|
||||
<span style="color: red">{{ scope.row.totalAmount }}</span>
|
||||
<span>{{ scope.row.receivableAmounts[item.chargeTypeId] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已收项目" align="center">
|
||||
<template #default>
|
||||
<el-table-column v-for="(item, index) in dynamicColumns" :key="index" :label="item.chargeTypeName" align="center" prop="totalAmount">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.receivedAmounts[item.chargeTypeId] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="未收项目" align="center">
|
||||
<template #default>
|
||||
<el-table-column v-for="(item, index) in dynamicColumns" :key="index" :label="item.chargeTypeName" align="center" prop="totalAmount">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.uncollectedAmounts[item.chargeTypeId] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
@@ -204,109 +197,331 @@
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
账龄
|
||||
<script setup name="Arrears" lang="ts">
|
||||
import pagination from '@/components/Pagination/index.vue';
|
||||
import pageHeader from '@/components/Pageheader/index.vue';
|
||||
import { getArrearsDetails } from '@/api/system/report/arrears/arrears';
|
||||
import { getCommunitylistAPI } from '@/api/system/community';
|
||||
import { OwnerArrearsDetailVo } from '@/api/system/report/arrears/type';
|
||||
import { validator } from '@/utils/Reg';
|
||||
import { ColumnConfig, exportToExcel } from '@/utils/xlsx';
|
||||
import { ArrowDownBold, ArrowUpBold } from '@element-plus/icons-vue';
|
||||
import { getLeaseManagementDetailChargeTypesList, getLeaseManagementDetailList } from '@/api/system/report/LeaseManagementDetails';
|
||||
import { Datum, queryParamsType, Row } from '@/api/system/report/LeaseManagementDetails/type';
|
||||
import { FormRules } from 'element-plus';
|
||||
import { validator } from '@/utils/Reg';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const ArrearsDetailList = ref<OwnerArrearsDetailVo[]>([]);
|
||||
const { com_house_rental_pricing_model, com_house_rental_pricing } = toRefs<any>(
|
||||
proxy?.useDict('com_house_rental_pricing_model', 'com_house_rental_pricing')
|
||||
);
|
||||
|
||||
const ArrearsDetailList = ref<Row[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const showSearch = ref(true);
|
||||
function ChangeShowSearch(bol: boolean) {
|
||||
showSearch.value = bol;
|
||||
}
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const queryTime = ref([]);
|
||||
function handleQueryTime(val: string[]) {
|
||||
queryParams.value.startTime = val[0];
|
||||
queryParams.value.endTime = val[1];
|
||||
|
||||
const leaseStartDate = ref([]);
|
||||
const leaseEndDate = ref([]);
|
||||
function handleUpdateLeaseDate(type: 'leaseStartDate' | 'leaseEndDate', val: string[]) {
|
||||
if (type === 'leaseStartDate') {
|
||||
queryParams.value.leaseStartDateBegin = val[0];
|
||||
queryParams.value.leaseStartDateEnd = val[1];
|
||||
} else if (type === 'leaseEndDate') {
|
||||
queryParams.value.leaseEndDateBegin = val[0];
|
||||
queryParams.value.leaseEndDateEnd = val[1];
|
||||
}
|
||||
}
|
||||
const data = reactive({
|
||||
function handleClear(type: 'leaseStartDate' | 'leaseEndDate') {
|
||||
if (type === 'leaseStartDate') {
|
||||
leaseStartDate.value = [];
|
||||
queryParams.value.leaseStartDateBegin = '';
|
||||
queryParams.value.leaseStartDateEnd = '';
|
||||
} else if (type === 'leaseEndDate') {
|
||||
leaseEndDate.value = [];
|
||||
queryParams.value.leaseEndDateBegin = '';
|
||||
queryParams.value.leaseEndDateEnd = '';
|
||||
}
|
||||
}
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const data = reactive<{
|
||||
queryParams: queryParamsType;
|
||||
}>({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
villageId: '-1',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
houseNo: '',
|
||||
month: '-1'
|
||||
},
|
||||
rule: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (arg0?: Error) => any) => {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
return callback();
|
||||
}
|
||||
if (!validator(value, 'fullFilterReg')) {
|
||||
return callback(new Error('请输入正确的房号'));
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
villageIds: [],
|
||||
lessee: undefined,
|
||||
phone: undefined,
|
||||
roomNumber: undefined,
|
||||
areaSize: undefined,
|
||||
chargeTypeFilters: [],
|
||||
chargeModes: [],
|
||||
chargeStandards: [],
|
||||
leaseEndDateBegin: undefined,
|
||||
leaseEndDateEnd: undefined
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams } = toRefs(data);
|
||||
// 动态生成表单验证规则
|
||||
const formRules = computed<FormRules>(() => {
|
||||
const dynamicRules: FormRules = {};
|
||||
queryParams.value.chargeTypeFilters.forEach((_, index) => {
|
||||
dynamicRules[`chargeTypeFilters[${index}].receivable`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
|
||||
dynamicRules[`chargeTypeFilters[${index}].received`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
|
||||
dynamicRules[`chargeTypeFilters[${index}].uncollected`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
});
|
||||
// 面积
|
||||
dynamicRules[`areaSize`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const [min, max] = value.split('-').map(Number);
|
||||
if (Math.abs(min) > MAX_AMOUNT || Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`面积不能超过 ${MAX_AMOUNT}`));
|
||||
} else if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`面积不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-100、-100、0-、100'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
// tel
|
||||
dynamicRules[`tel`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
validator(value, 'phone') ? callback() : callback(new Error('请输入正确的手机号'));
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
// 承租方
|
||||
dynamicRules[`lessee`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
validator(value, 'Character') ? callback() : callback(new Error('请输入正确的承租方姓名'));
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
// 房间号
|
||||
dynamicRules[`roomNumber`] = [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
validator(value, 'Character') ? callback() : callback(new Error('请输入正确的房间号'));
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
];
|
||||
return dynamicRules;
|
||||
});
|
||||
// 查询小区
|
||||
const villageList = ref([]);
|
||||
function getAllVillage() {
|
||||
getCommunitylistAPI().then((res) => {
|
||||
villageList.value = [
|
||||
{
|
||||
villageId: '-1',
|
||||
villageName: '全部区域'
|
||||
},
|
||||
...res.rows
|
||||
];
|
||||
villageList.value = [...res.rows];
|
||||
});
|
||||
}
|
||||
// 区域改变时,查询收费项目
|
||||
function handleVillageChange(val: string) {
|
||||
queryParams.value.villageId = val;
|
||||
queryParams.value.houseNo = '-1';
|
||||
}
|
||||
// 月份
|
||||
const MonthList = ref([]);
|
||||
function getMonthList() {
|
||||
const arr = Array.from({ length: 12 }).fill((i) => {
|
||||
return {
|
||||
id: `${i + 1}`,
|
||||
name: `${i + 1}月`
|
||||
};
|
||||
});
|
||||
MonthList.value = [];
|
||||
MonthList.value = [
|
||||
{
|
||||
id: '-1',
|
||||
name: '全部月数'
|
||||
},
|
||||
...arr
|
||||
];
|
||||
}
|
||||
// 动态列名列表▐╬ .3╬
|
||||
const dynamicColumns = ref<string[]>([]);
|
||||
|
||||
// 动态列名列表
|
||||
const dynamicColumns = ref<Datum[]>([]);
|
||||
// 在获取数据后更新动态列
|
||||
const updateDynamicColumns = (list: any[]) => {
|
||||
const columns = new Set<string>();
|
||||
list.forEach((row) => {
|
||||
if (row.chargeItemAmounts) {
|
||||
Object.keys(row.chargeItemAmounts).forEach((key) => columns.add(key));
|
||||
}
|
||||
const updateDynamicColumns = () => {
|
||||
getLeaseManagementDetailChargeTypesList().then((res) => {
|
||||
dynamicColumns.value = res.data;
|
||||
queryParams.value.chargeTypeFilters = dynamicColumns.value.map((item) => {
|
||||
return {
|
||||
chargeTypeId: item.chargeTypeId,
|
||||
chargeTypeName: item.chargeTypeName,
|
||||
|
||||
receivable: undefined,
|
||||
received: undefined,
|
||||
uncollected: undefined,
|
||||
|
||||
receivableMin: undefined,
|
||||
receivableMax: undefined,
|
||||
receivedMin: undefined,
|
||||
receivedMax: undefined,
|
||||
uncollectedMin: undefined,
|
||||
uncollectedMax: undefined
|
||||
};
|
||||
});
|
||||
});
|
||||
return Array.from(columns);
|
||||
};
|
||||
|
||||
/** 查询电抄记录列表 */
|
||||
const getList = async () => {
|
||||
const getList = () => {
|
||||
loading.value = true;
|
||||
const search = { ...queryParams.value };
|
||||
// 移除空字符串字段
|
||||
@@ -314,14 +529,36 @@ const getList = async () => {
|
||||
if (search[key] === '-1') {
|
||||
search[key] = undefined;
|
||||
}
|
||||
|
||||
if (key === 'chargeTypeFilters') {
|
||||
search[key] = search[key]
|
||||
.map((item) => {
|
||||
// 1000-2000, -1000, 1000-, 1000
|
||||
// 处理空字符串
|
||||
if (!item.receivable && !item.received && !item.uncollected) {
|
||||
return null;
|
||||
}
|
||||
const [receivableMin, receivableMax] = item.receivable ? item.receivable.split('-') : [];
|
||||
const [receivedMin, receivedMax] = item.received ? item.received.split('-') : [];
|
||||
const [uncollectedMin, uncollectedMax] = item.uncollected ? item.uncollected.split('-') : [];
|
||||
return {
|
||||
chargeTypeId: item.chargeTypeId,
|
||||
receivableMin: receivableMin || undefined,
|
||||
receivableMax: receivableMax || undefined,
|
||||
receivedMin: receivedMin || undefined,
|
||||
receivedMax: receivedMax || undefined,
|
||||
uncollectedMin: uncollectedMin || undefined,
|
||||
uncollectedMax: uncollectedMax || undefined
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
});
|
||||
getArrearsDetails(search)
|
||||
|
||||
getLeaseManagementDetailList(search)
|
||||
.then((res) => {
|
||||
ArrearsDetailList.value = res.rows;
|
||||
total.value = res.total;
|
||||
dynamicColumns.value = updateDynamicColumns(res.rows);
|
||||
|
||||
ArrearsDetailList.value[ArrearsDetailList.value.length - 1].serialNumber = '合计';
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
@@ -330,78 +567,158 @@ const getList = async () => {
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
// 校验表单
|
||||
queryFormRef.value?.validate((valid) => {
|
||||
if (valid) {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
leaseStartDate.value = [];
|
||||
leaseEndDate.value = [];
|
||||
queryParams.value = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
villageIds: [],
|
||||
lessee: undefined,
|
||||
phone: undefined,
|
||||
roomNumber: undefined,
|
||||
areaSize: undefined,
|
||||
chargeTypeFilters: [],
|
||||
chargeModes: [],
|
||||
chargeStandards: [],
|
||||
leaseEndDateBegin: undefined,
|
||||
leaseEndDateEnd: undefined
|
||||
};
|
||||
queryParams.value.chargeTypeFilters = dynamicColumns.value.map((item) => {
|
||||
return {
|
||||
chargeTypeId: item.chargeTypeId,
|
||||
chargeTypeName: item.chargeTypeName,
|
||||
receivable: undefined,
|
||||
received: undefined,
|
||||
uncollected: undefined,
|
||||
receivableMin: undefined,
|
||||
receivableMax: undefined,
|
||||
receivedMin: undefined,
|
||||
receivedMax: undefined,
|
||||
uncollectedMin: undefined,
|
||||
uncollectedMax: undefined
|
||||
};
|
||||
});
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 导出Excel */
|
||||
const handleExport = () => {
|
||||
const handleExport = async () => {
|
||||
if (ArrearsDetailList.value.length === 0) {
|
||||
proxy?.$modal.msgWarning('没有可导出的数据');
|
||||
return;
|
||||
}
|
||||
// 显示加载提示
|
||||
// const oldSearch = JSON.parse(
|
||||
// JSON.stringify({
|
||||
// ...queryParams.value,
|
||||
// pageNum: undefined,
|
||||
// pageSize: undefined
|
||||
// })
|
||||
// );
|
||||
loading.value = true;
|
||||
// 使用 setTimeout 让出主线程,避免阻塞UI
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const columns: ColumnConfig[] = [
|
||||
{ label: '序号', prop: 'serialNumber' },
|
||||
{ label: '区域', prop: 'area' },
|
||||
{ label: '房号', prop: 'houseNo' },
|
||||
{ label: '客户', prop: 'customerName' },
|
||||
{ label: '联系方式', prop: 'phone' },
|
||||
{ label: '欠费月数', prop: 'arrearsMonths' },
|
||||
{ label: '应收账期', prop: 'billPeriod' },
|
||||
{
|
||||
label: '欠费项目',
|
||||
children: [
|
||||
...dynamicColumns.value.map((item) => {
|
||||
return { label: item, prop: `chargeItemAmounts.${item}` };
|
||||
})
|
||||
]
|
||||
}
|
||||
];
|
||||
exportToExcel(ArrearsDetailList.value, columns, `应收欠费明细表_${new Date().getTime()}`, mergeSpanMethod);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
console.error('导出错误:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const mergeSpanMethod = ({ columnIndex, rowIndex }) => {
|
||||
if (rowIndex === ArrearsDetailList.value.length - 1) {
|
||||
const rowspan = 6;
|
||||
if (columnIndex === 0) {
|
||||
return { rowspan: 1, colspan: 1 };
|
||||
}
|
||||
if (columnIndex === 1) {
|
||||
return { rowspan: 1, colspan: rowspan };
|
||||
}
|
||||
if (columnIndex < rowspan + 1) {
|
||||
return { rowspan: 0, colspan: 0 };
|
||||
}
|
||||
// let allData = [];
|
||||
try {
|
||||
// const res = await getLeaseManagementDetailList(oldSearch);
|
||||
// allData = res.rows;
|
||||
// 显示加载提示
|
||||
// 使用 setTimeout 让出主线程,避免阻塞UI
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const columns: ColumnConfig[] = [
|
||||
{ label: '区域', prop: 'area' },
|
||||
{ label: '承租方', prop: 'lessee' },
|
||||
{ label: '电话', prop: 'phone' },
|
||||
{ label: '房号', prop: 'roomNumber' },
|
||||
{ label: '面积', prop: 'areaSize' },
|
||||
{ label: '收费模式', prop: 'chargeMode' },
|
||||
{ label: '收费标准', prop: 'chargeStandard' },
|
||||
{ label: '租赁起始日', prop: 'leaseStartDate' },
|
||||
{ label: '租赁终止日', prop: 'leaseEndDate' },
|
||||
{
|
||||
label: '应收项目',
|
||||
children: [
|
||||
...dynamicColumns.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeTypeName,
|
||||
prop: `receivableAmounts.${item.chargeTypeId}`
|
||||
};
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '已收项目',
|
||||
children: [
|
||||
...dynamicColumns.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeTypeName,
|
||||
prop: `receivedAmounts.${item.chargeTypeId}`
|
||||
};
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '未收项目',
|
||||
children: [
|
||||
...dynamicColumns.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeTypeName,
|
||||
prop: `uncollectedAmounts.${item.chargeTypeId}`
|
||||
};
|
||||
})
|
||||
]
|
||||
}
|
||||
];
|
||||
exportToExcel(ArrearsDetailList.value, columns, `租赁管理明细表_${new Date().getTime()}`);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
console.error('导出错误:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
loading.value = false;
|
||||
}
|
||||
// 普通行不合并
|
||||
return { rowspan: 1, colspan: 1 };
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
updateDynamicColumns();
|
||||
getList();
|
||||
getMonthList();
|
||||
getAllVillage();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.line {
|
||||
height: 1px;
|
||||
background: #eee;
|
||||
margin: 15px 0;
|
||||
}
|
||||
.queryBox_over {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.el-table {
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,9 @@ const exportData = () => {
|
||||
proxy?.download(
|
||||
'/businessDailyReport/village/export',
|
||||
{
|
||||
...search
|
||||
...search,
|
||||
// pageNum: undefined,
|
||||
// pageSize: undefined
|
||||
},
|
||||
`营业日报_按小区统计.xlsx`
|
||||
);
|
||||
@@ -169,7 +171,9 @@ const exportData = () => {
|
||||
proxy?.download(
|
||||
'/businessDailyReport/chargeItem/export',
|
||||
{
|
||||
...search
|
||||
...search,
|
||||
// pageNum: undefined,
|
||||
// pageSize: undefined
|
||||
},
|
||||
`营业日报_按收费项目统计.xlsx`
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<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" label-width="80px" :model="queryParams" @submit.prevent="handleQuery" :inline="true">
|
||||
<el-form ref="queryFormRef" label-width="80px" :model="queryParams" :rules="rules" @submit.prevent="handleQuery" :inline="true">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<el-form-item label="楼栋(多选)" prop="buildingIds">
|
||||
@@ -85,11 +85,12 @@ import pagination from '@/components/Pagination/index.vue';
|
||||
import pageHeader from '@/components/Pageheader/index.vue';
|
||||
import { ColumnConfig, exportToExcel } from '@/utils/xlsx';
|
||||
import { listHouseUseType } from '@/api/system/houseUse';
|
||||
import { DailyFeeReportVo } from '@/api/system/report/dailyFeeReport/type';
|
||||
import { getMonthFeeReportList } from '@/api/system/report/monthFeeReport';
|
||||
import { Row } from '@/api/system/report/monthFeeReport/type';
|
||||
import { FormRules } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const ArrearsDetailList = ref<DailyFeeReportVo[]>([]);
|
||||
const ArrearsDetailList = ref<Row[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
@@ -109,10 +110,282 @@ const data = reactive({
|
||||
yearRate: '',
|
||||
totalArrears: '',
|
||||
totalPrepaid: ''
|
||||
},
|
||||
rules: {
|
||||
monthReceivable: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
monthUnpaid: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
yearReceivable: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
yearUnpaid: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
totalArrears: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
totalPrepaid: [
|
||||
{
|
||||
validator: (_: any, value: string, callback: (error?: any) => void) => {
|
||||
if (!value || value === '') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rangePattern = /^(-?\d+(\.\d{1,2})?)-(-?\d+(\.\d{1,2})?)?$/;
|
||||
const singlePattern = /^-?\d+(\.\d{1,2})?$/;
|
||||
const MAX_AMOUNT = 99999999;
|
||||
|
||||
if (rangePattern.test(value)) {
|
||||
const parts = value.split('-');
|
||||
const min = Number(parts[0]);
|
||||
const max = parts[1] !== '' ? Number(parts[1]) : null; // 空字符串才是 null
|
||||
|
||||
// 校验下限
|
||||
if (Math.abs(min) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
|
||||
// 只有当 max 存在时才校验
|
||||
if (max !== null) {
|
||||
if (Math.abs(max) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
}
|
||||
if (min > max) {
|
||||
return callback(new Error('下限不能大于上限'));
|
||||
}
|
||||
}
|
||||
return callback();
|
||||
} else if (singlePattern.test(value)) {
|
||||
const amount = Number(value);
|
||||
if (Math.abs(amount) > MAX_AMOUNT) {
|
||||
return callback(new Error(`金额不能超过 ${MAX_AMOUNT}`));
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
} else {
|
||||
callback(new Error('格式错误,示例: 0-1000、-1000、0-、1000'));
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams } = toRefs(data);
|
||||
// 动态生成表单验证规则╘╬
|
||||
const { queryParams, rules } = toRefs(data);
|
||||
|
||||
// 查询房屋类型列表
|
||||
const allHouseUseList = ref([]);
|
||||
|
||||
@@ -161,45 +161,62 @@ const resetQuery = () => {
|
||||
handleQuery();
|
||||
};
|
||||
/** 导出Excel */
|
||||
const handleExport = () => {
|
||||
const handleExport = async () => {
|
||||
if (ArrearsDetailList.value.length === 0) {
|
||||
proxy?.$modal.msgWarning('没有可导出的数据');
|
||||
return;
|
||||
}
|
||||
|
||||
const search = { ...queryParams.value };
|
||||
// 移除空字符串字段
|
||||
Object.keys(search).forEach((key) => {
|
||||
if (search[key] === '-1') {
|
||||
search[key] = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// 显示加载提示
|
||||
loading.value = true;
|
||||
// 使用 setTimeout 让出主线程,避免阻塞UI
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const columns: ColumnConfig[] = [
|
||||
{ label: '小区名称', prop: 'villageName' },
|
||||
{ label: '房屋类型', prop: 'houseTypeName' },
|
||||
{
|
||||
label: '收费项目',
|
||||
prop: 'chargeItemAmounts',
|
||||
children: [
|
||||
...rowChargeTypesList.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeItemName,
|
||||
prop: `chargeItemAmounts.${item.chargeItemName}`
|
||||
};
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '合计',
|
||||
prop: 'totalAmount'
|
||||
}
|
||||
];
|
||||
exportToExcel(ArrearsDetailList.value, columns, `预收费用余额汇总_${new Date().getTime()}`);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
console.error('导出错误:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}, 100);
|
||||
|
||||
try {
|
||||
// const res = await getPrepaidBalanceList(search);
|
||||
// ArrearsDetailList.value = [...res.rows];
|
||||
// 使用 setTimeout 让出主线程,避免阻塞UI
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const columns: ColumnConfig[] = [
|
||||
{ label: '小区名称', prop: 'villageName' },
|
||||
{ label: '房屋类型', prop: 'houseTypeName' },
|
||||
{
|
||||
label: '收费项目',
|
||||
prop: 'chargeItemAmounts',
|
||||
children: [
|
||||
...rowChargeTypesList.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeItemName,
|
||||
prop: `chargeItemAmounts.${item.chargeItemName}`
|
||||
};
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '合计',
|
||||
prop: 'totalAmount'
|
||||
}
|
||||
];
|
||||
exportToExcel(ArrearsDetailList.value, columns, `预收费用余额汇总_${new Date().getTime()}`);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
console.error('导出错误:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
loading.value = false;
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
return;
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="客户" prop="customerName">
|
||||
<el-input v-model.trim="queryParams.customerName"></el-input>
|
||||
<el-input v-model.trim="queryParams.customerName" placeholder="请输入客户姓名"></el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div>
|
||||
@@ -153,49 +153,62 @@ const resetQuery = () => {
|
||||
handleQuery();
|
||||
};
|
||||
/** 导出Excel */
|
||||
const handleExport = () => {
|
||||
const handleExport = async () => {
|
||||
if (ArrearsDetailList.value.length === 0) {
|
||||
proxy?.$modal.msgWarning('没有可导出的数据');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载提示
|
||||
loading.value = true;
|
||||
// 使用 setTimeout 让出主线程,避免阻塞UI
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const columns: ColumnConfig[] = [
|
||||
{ label: '小区名称', prop: 'villageName' },
|
||||
{ label: '房屋类型', prop: 'houseTypeName' },
|
||||
{ label: '户号', prop: 'houseNo' },
|
||||
{ label: '客户', prop: 'customerName' },
|
||||
{ label: '预收账期', prop: 'prepaidPeriod' },
|
||||
{ label: '预收月份', prop: 'prepaidMonths' },
|
||||
{
|
||||
label: '收费项目',
|
||||
prop: 'chargeItemAmounts',
|
||||
children: [
|
||||
...rowChargeTypesList.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeItemName,
|
||||
prop: `chargeItemAmounts.${item.chargeItemName}`
|
||||
};
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '合计',
|
||||
prop: 'totalAmount'
|
||||
}
|
||||
];
|
||||
exportToExcel(ArrearsDetailList.value, columns, `预收费用余额详细_${new Date().getTime()}`);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
console.error('导出错误:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
const search = { ...queryParams.value, pageNum: undefined, pageSize: undefined };
|
||||
// 移除空字符串字段
|
||||
Object.keys(search).forEach((key) => {
|
||||
if (search[key] === '-1') {
|
||||
search[key] = undefined;
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
loading.value = true;
|
||||
try {
|
||||
// const res = await getPrepaidBalanceDetailList(search);
|
||||
// ArrearsDetailList.value = [...res.rows];
|
||||
// 显示加载提示
|
||||
// 使用 setTimeout 让出主线程,避免阻塞UI
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const columns: ColumnConfig[] = [
|
||||
{ label: '小区名称', prop: 'villageName' },
|
||||
{ label: '房屋类型', prop: 'houseTypeName' },
|
||||
{ label: '户号', prop: 'houseNo' },
|
||||
{ label: '客户', prop: 'customerName' },
|
||||
{ label: '预收账期', prop: 'prepaidPeriod' },
|
||||
{ label: '预收月份', prop: 'prepaidMonths' },
|
||||
{
|
||||
label: '收费项目',
|
||||
prop: 'chargeItemAmounts',
|
||||
children: [
|
||||
...rowChargeTypesList.value.map((item) => {
|
||||
return {
|
||||
label: item.chargeItemName,
|
||||
prop: `chargeItemAmounts.${item.chargeItemName}`
|
||||
};
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '合计',
|
||||
prop: 'totalAmount'
|
||||
}
|
||||
];
|
||||
exportToExcel(ArrearsDetailList.value, columns, `预收费用余额详细_${new Date().getTime()}`);
|
||||
} catch (error) {
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
console.error('导出错误:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
loading.value = false;
|
||||
proxy?.$modal.msgError('导出失败,请重试');
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
|
||||
Reference in New Issue
Block a user