8/25 dev 权限,sse,账单

This commit is contained in:
Zy
2026-08-27 17:32:23 +08:00
parent b83735e993
commit 2ea75ee5ef
55 changed files with 870 additions and 293 deletions

View File

@@ -151,16 +151,19 @@ function handleVillageChange(val: string) {
queryParams.value.chargeItemId = '-1';
}
const chargeItemList = ref([]);
listChargeType().then((res) => {
chargeItemList.value = [
{
id: '-1',
name: '全部项目'
},
...res.rows
];
});
// 忽略的收费项目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();
@@ -350,6 +353,7 @@ const handleExport = () => {
};
onMounted(() => {
getChargeList();
getList();
handleQueryHouseUse();
getAllVillage();

View File

@@ -111,6 +111,8 @@ const getList = async () => {
rows.value = res.payTypes;
if (res.rows.length > 0) {
AgingList.value = [...res.rows, res.summary];
}else{
AgingList.value = [];
}
total.value = res.total;
})

View File

@@ -4,16 +4,163 @@
<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 label-width="auto" ref="queryFormRef" :model="queryParams" @submit.prevent="handleQuery" :inline="true">
<div class="flex justify-between flex-wrap">
<el-form
:rules="formRules"
label-width="180px"
label-position="right"
ref="queryFormRef"
:model="queryParams"
@submit.prevent="handleQuery"
:inline="true"
>
<div>
<el-form-item label="日期" prop="payTime">
<el-date-picker
v-model="payTime"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
@clear="handleClear()"
@update:model-value="(val: string[]) => handleUpdateLeaseDate(val)"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="户主" prop="residentName">
<el-input v-model.trim="queryParams.residentName" placeholder="请输入户主姓名"></el-input>
</el-form-item>
<el-form-item label="房号" prop="houseName">
<el-input v-model.trim="queryParams.houseName" placeholder="请输入房号"></el-input>
</el-form-item>
<el-form-item label="">
<div v-show="!isShow" class="flex justify-end">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
<div @click="toggleShow" class="flex items-center cursor-pointer hover:color-blue" style="margin-left: 10px; font-size: 13px">
<span>展开</span>
<el-icon style="margin-left: 5px"><ArrowDownBold /></el-icon>
</div>
</div>
</el-form-item>
</div>
<div v-show="isShow">
<el-form-item label="现金" prop="cashAmount">
<el-input v-model.trim="queryParams.cashAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="支付宝" prop="alipayAmount">
<el-input v-model.trim="queryParams.alipayAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="宜当付" prop="yiDangFuAmount">
<el-input v-model.trim="queryParams.yiDangFuAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="银联" prop="unionPayAmount">
<el-input v-model.trim="queryParams.unionPayAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="转账" prop="transferAmount">
<el-input v-model.trim="queryParams.transferAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="微信" prop="wechatAmount">
<el-input v-model.trim="queryParams.wechatAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="押金抵顶" prop="depositAmount">
<el-input v-model.trim="queryParams.depositAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="房产抵顶" prop="propertyOffsetAmount">
<el-input v-model.trim="queryParams.propertyOffsetAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="减免优惠" prop="discountAmount">
<el-input v-model.trim="queryParams.discountAmount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
</div>
<div v-show="isShow">
<el-form-item label="水费" prop="waterFee">
<el-input v-model.trim="queryParams.waterFee" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="电费" prop="electricFee">
<el-input v-model.trim="queryParams.electricFee" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item label="押金" prop="deposit">
<el-input v-model.trim="queryParams.deposit" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
</div>
<div v-show="isShow" class="flex justify-between flex-wrap">
<div v-for="(item, index) in queryParamsList" :key="index">
<el-form-item :label="item[ite].label" :prop="item[ite].parameter" v-for="(ite, ind) in Object.keys(item)" :key="ind">
<el-input v-model.trim="queryParams[item[ite].parameter]" :placeholder="item[ite].placeholder"></el-input>
<el-form-item :label="`${item.chargeTypeName} (金额)`">
<el-input v-model.trim="queryParams.chargeTypeFilters[index].amount" placeholder="区间搜索 1000-10000"></el-input>
</el-form-item>
<el-form-item :label="`${item.chargeTypeName} (开始时间)`">
<el-date-picker
v-model="queryParams.chargeTypeFilters[index].startDate"
@update:model-value="
(val: string[]) => {
if (val.length === 0) {
return;
}
queryParams.chargeTypeFilters[index].startDateBegin = val[0];
queryParams.chargeTypeFilters[index].startDateEnd = val[1];
}
"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
@clear="
() => {
queryParams.chargeTypeFilters[index].startDate = '';
queryParams.chargeTypeFilters[index].startDateBegin = '';
queryParams.chargeTypeFilters[index].startDateEnd = '';
}
"
type="datetimerange"
range-separator="到"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
<el-form-item :label="`${item.chargeTypeName} (结束时间)`">
<el-date-picker
v-model="queryParams.chargeTypeFilters[index].endDate"
type="datetimerange"
@update:model-value="
(val: string[]) => {
if (val.length === 0) {
return;
}
queryParams.chargeTypeFilters[index].endDateBegin = val[0];
queryParams.chargeTypeFilters[index].endDateEnd = val[1];
}
"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
clearable
@clear="
() => {
queryParams.chargeTypeFilters[index].endDate = '';
queryParams.chargeTypeFilters[index].endDateBegin = '';
queryParams.chargeTypeFilters[index].endDateEnd = '';
}
"
range-separator="到"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
</div>
<div>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</div>
<!-- <div v-show="isShow">-->
<!-- <el-form-item label="经办人" prop="handler">-->
<!-- <el-input v-model.trim="queryParams.handler" placeholder="请输入经办人姓名"></el-input>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="备注" prop="remark">-->
<!-- <el-input v-model.trim="queryParams.remark" placeholder="请输入备注"></el-input>-->
<!-- </el-form-item>-->
<!-- </div>-->
<div v-show="isShow" class="flex justify-end">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
<div @click="toggleShow" class="flex items-center cursor-pointer hover:color-blue" style="margin-left: 10px; font-size: 13px">
<span>收起</span>
<el-icon style="margin-left: 5px"><ArrowUpBold /></el-icon>
</div>
</div>
</el-form>
@@ -33,7 +180,6 @@
</el-col>
</el-row>
</template>
<el-table :row-class-name="handleRowClass" v-loading="loading" border :data="ArrearsDetailList">
<el-table-column label="日期" width="100" align="center" fixed="left" prop="payTime" />
<el-table-column label="房屋信息" align="center" fixed="left">
@@ -90,8 +236,8 @@
</el-table-column>
</template>
</el-table-column>
<el-table-column label="经办人" align="center" prop="handler" />
<el-table-column show-overflow-tooltip width="250" label="备注" align="center" prop="remark" />
<!-- <el-table-column label="经办人" align="center" prop="handler" />-->
<!-- <el-table-column show-overflow-tooltip width="250" label="备注" align="center" prop="remark" />-->
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
@@ -106,6 +252,8 @@ import { ColumnConfig, exportToExcel } from '@/utils/xlsx';
import { listHouseUseType } from '@/api/system/houseUse';
import { getDailyFeeReportDynamicList, getDailyFeeReportList } from '@/api/system/report/dailyFeeReport';
import { Datum } from '@/api/system/report/dailyFeeReport/type';
import { FormRules } from 'element-plus';
import { ArrowDownBold, ArrowUpBold } from '@element-plus/icons-vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const ArrearsDetailList = ref<Datum[]>([]);
@@ -130,41 +278,140 @@ function getHouseUseList() {
});
}
const isShow = ref(false);
function toggleShow() {
isShow.value = !isShow.value;
}
const queryParams = ref({
pageNum: 1,
pageSize: 10
pageSize: 10,
startDate: '',
endDate: '',
residentName: '',
houseName: '',
cashAmount: '',
alipayAmount: '',
yiDangFuAmount: '',
unionPayAmount: '',
transferAmount: '',
wechatAmount: '',
depositAmount: '',
propertyOffsetAmount: '',
discountAmount: '',
waterFee: '',
electricFee: '',
deposit: '',
handler: '',
remark: '',
chargeTypeFilters: []
});
const staticSearchKey = [
'cashAmount',
'alipayAmount',
'yiDangFuAmount',
'unionPayAmount',
'transferAmount',
'wechatAmount',
'depositAmount',
'propertyOffsetAmount',
'discountAmount',
'waterFee',
'electricFee',
'deposit'
];
// 动态生成表单验证规则
const formRules = computed<FormRules>(() => {
const dynamicRules: FormRules = {};
staticSearchKey.forEach((item) => {
dynamicRules[item] = [
{
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'
}
];
});
return dynamicRules;
});
const payTime = ref([]);
function handleClear() {
payTime.value = [];
queryParams.value.startDate = '';
queryParams.value.endDate = '';
}
function handleUpdateLeaseDate(val: string[]) {
queryParams.value.startDate = val[0];
queryParams.value.endDate = val[1];
}
// 参数列表
const queryParamsList = ref([]);
function getQueryParams() {
getDailyFeeReportDynamicList().then((res) => {
const obj = {};
const list = res.data.map((item) => {
const obj2 = {};
const list = item.field.split(',') ?? [];
console.log(list);
list.forEach((item2) => {
obj[item2] = '';
obj2[item2] = {
label: item.label,
parameter: item2,
placeholder: item.placeholder,
type: item.type,
subField: item.subField
};
});
return obj2;
});
queryParams.value = {
...queryParams.value,
...obj
};
queryParamsList.value = list;
console.log(list);
queryParamsList.value = res.data;
handleAddQuery();
});
}
function handleAddQuery() {
const list = queryParamsList.value.map((item) => {
return {
'chargeTypeName': item.chargeTypeName,
'chargeTypeId': item.chargeTypeId,
'amount': '',
startDate: '',
endDate: '',
'startDateBegin': '',
'startDateEnd': '',
'endDateBegin': '',
'endDateEnd': ''
};
});
queryParamsList.value = list;
queryParams.value.chargeTypeFilters = list;
}
const rowChargeTypesList = ref([]);
@@ -181,7 +428,7 @@ const getList = async () => {
getDailyFeeReportList(search)
.then((res) => {
ArrearsDetailList.value = [...(res.rows ?? [])];
rowChargeTypesList.value = Object.keys(res.rows[0].chargeTypeAmounts);
rowChargeTypesList.value = Object.keys(res.rows[0].chargeTypeAmounts) ?? [];
total.value = res.total;
})
.finally(() => {
@@ -206,9 +453,30 @@ const handleQuery = () => {
const resetQuery = () => {
queryFormRef.value?.resetFields();
queryParams.value = {
endDate: undefined,
startDate: undefined,
pageNum: 1,
pageSize: 10
pageSize: 10,
residentName: '',
houseName: '',
cashAmount: '',
alipayAmount: '',
yiDangFuAmount: '',
unionPayAmount: '',
transferAmount: '',
wechatAmount: '',
depositAmount: '',
propertyOffsetAmount: '',
discountAmount: '',
waterFee: '',
electricFee: '',
deposit: '',
handler: '',
remark: '',
chargeTypeFilters: []
};
handleAddQuery();
handleClear();
handleQuery();
};
/** 导出Excel */
@@ -272,15 +540,15 @@ const handleExport = () => {
? []
: [
{ label: '金额', prop: `chargeTypeAmounts.${item}.amount` },
{ label: '开始时间', prop: `chargeTypeAmounts.${item}.startTime` },
{ label: '截止时间', prop: `chargeTypeAmounts.${item}.endTime` }
{ label: '开始时间', prop: `chargeTypeAmounts.${item}.startDate` },
{ label: '截止时间', prop: `chargeTypeAmounts.${item}.endDate` }
]
};
})
]
},
{ label: '经办人', prop: 'inspectorName' },
{ label: '备注', prop: 'remark' }
}
// { label: '经办人', prop: 'inspectorName' },
// { label: '备注', prop: 'remark' }
];
console.log(columns);
exportToExcel(ArrearsDetailList.value, columns, `日报_${new Date().getTime()}`);

View File

@@ -27,14 +27,14 @@
<el-form-item label="房号" prop="houseNo">
<el-input v-model.trim="queryParams.houseNo" placeholder="请输入房号" />
</el-form-item>
<el-form-item label="欠费月数" prop="month">
<el-select v-model="queryParams.month" placeholder="请选择">
<el-form-item label="欠费月数" prop="arrearsMonths">
<el-select v-model="queryParams.arrearsMonths" 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-button type="primary" @click="handleQuery">查询</el-button>
<el-button type="primary" :loading="loading" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</div>
</div>
@@ -60,7 +60,7 @@
<el-table :span-method="mergeSpanMethod" v-loading="loading" border :data="ArrearsDetailList">
<el-table-column label="序号" width="80" align="center" prop="serialNumber" />
<el-table-column label="区域" align="center" prop="area" />
<el-table-column label="房号" align="center" prop="houseNo" />
<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" />
@@ -115,13 +115,13 @@ const data = reactive({
startTime: '',
endTime: '',
houseNo: '',
month: '-1'
arrearsMonths: '-1'
}
});
const { queryParams } = toRefs(data);
// 查询小区╬╬zn
// 查询小区
const villageList = ref([]);
function getAllVillage() {
getCommunitylistAPI().then((res) => {
@@ -137,15 +137,15 @@ function getAllVillage() {
// 区域改变时,查询收费项目
function handleVillageChange(val: string) {
queryParams.value.villageId = val;
queryParams.value.houseNo = '-1';
queryParams.value.houseNo = '';
}
// 月份
const MonthList = ref([]);
function getMonthList() {
const arr = Array.from({ length: 12 }).fill((i: number) => {
const arr = Array.from({ length: 12 }).map((_, i: number) => {
return {
id: `${i + 1}`,
name: `${i + 1}月`
name: `${i + 1}个月`
};
});
MonthList.value = [];
@@ -186,7 +186,6 @@ const getList = async () => {
ArrearsDetailList.value = res.rows;
total.value = res.total;
dynamicColumns.value = updateDynamicColumns(res.rows);
ArrearsDetailList.value[ArrearsDetailList.value.length - 1].serialNumber = '合计';
})
.finally(() => {

View File

@@ -53,7 +53,7 @@
<template #header>
<el-row :gutter="10" style="margin-bottom: 30px">
<el-col :span="5">
<span> 收费日报 </span>
<span> 收费月报 </span>
</el-col>
<el-col :span="18"></el-col>
<el-col :span="1">
@@ -67,11 +67,19 @@
<el-table-column label="本月应收" align="center" prop="monthReceivable" />
<el-table-column label="本月已收" align="center" prop="monthReceived" />
<el-table-column label="本月未收" align="center" prop="monthUnpaid" />
<el-table-column label="月收费率" align="center" prop="monthRate" />
<el-table-column label="月收费率" align="center" prop="monthRate">
<template #default="scope">
{{ `${scope.row.monthRate}%` || '0%' }}
</template>
</el-table-column>
<el-table-column label="本年应收" align="center" prop="yearReceivable" />
<el-table-column label="本年已收" align="center" prop="yearReceived" />
<el-table-column label="本年未收" align="center" prop="yearUnpaid" />
<el-table-column label="年收费率" align="center" prop="yearRate" />
<el-table-column label="年收费率" align="center" prop="yearRate">
<template #default="scope">
{{ `${scope.row.yearRate}%` || '0%' }}
</template>
</el-table-column>
<el-table-column label="综合欠收" align="center" prop="totalPrepaid" />
<el-table-column label="综合预收" align="center" prop="totalArrears" />
</el-table>

View File

@@ -75,7 +75,6 @@
import pagination from '@/components/Pagination/index.vue';
import pageHeader from '@/components/Pageheader/index.vue';
import { getCommunitylistAPI } from '@/api/system/community';
import { validator } from '@/utils/Reg';
import { getPaidInExpensesReceivableList } from '@/api/system/report/paidInExpensesReceivable';
import { Detail } from '@/api/system/report/paidInExpensesReceivable/type';
import { listChargeType } from '@/api/system/ChargeType';
@@ -91,16 +90,16 @@ const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const queryTime = ref([]);
function handleQueryTime(val: string[]) {
queryParams.value.startTime = val[0];
queryParams.value.endTime = val[1];
queryParams.value.startDate = val[0];
queryParams.value.endDate = val[1];
}
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
villageId: '-1',
startTime: '',
endTime: '',
startDate: '',
endDate: '',
chargeTypeId: '-1'
}
});
@@ -121,6 +120,8 @@ function getAllVillage() {
});
}
// 忽略的收费项目id, 水费,电费,燃气费,上线前手工导入
const ignoreChargeItemList = ['2049026503017136129', '2064181187503652865', '2091072780916981761', '2049026540430327809'];
// 收费类型
const chargeTypesList = ref([]);
function getChargeTypeList() {
@@ -130,7 +131,7 @@ function getChargeTypeList() {
name: '全部类型',
id: '-1'
},
...res.rows
...res.rows.filter((item) => !ignoreChargeItemList.includes(item.id))
];
});
}

View File

@@ -77,7 +77,7 @@ import { listHouseUseType } from '@/api/system/houseUse';
import { Row } from '@/api/system/report/prepaidBalance/type';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// ╬╬╬2╬╬
// 预收费用余额汇总
const ArrearsDetailList = ref<Row[]>([]);
const loading = ref(true);
const showSearch = ref(true);