8/10 新增删除账单功能,收费分类-关联

This commit is contained in:
Zy
2026-08-10 08:57:24 +08:00
parent f66c0fb145
commit 1c11add746
10 changed files with 262 additions and 39 deletions

View File

@@ -1,6 +1,6 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { ChargeTypeVO, ChargeTypeForm, ChargeTypeQuery } from './type';
import { ChargeTypeVO, ChargeTypeForm, ChargeTypeQuery, ChargeTypeRelationQuery } from './type';
/**
* 查询收费类型列表
@@ -61,3 +61,37 @@ export const delChargeType = (id: string | number | Array<string | number>) => {
method: 'delete'
});
};
/**
* 查询收费类型关联列表
* @param query
*/
export const getChargeTypeRelation = (query?: ChargeTypeRelationQuery) => {
return request({
url: '/chargeType/relation/list',
method: 'get'
});
};
/**
* 新增收费类型关联
* @param data
*/
export const addChargeTypeRelation = (data: ChargeTypeRelationQuery) => {
return request({
url: '/chargeType/relation',
method: 'POST',
data: data
});
};
/**
* 新增收费类型关联
* @param data
*/
export const editChargeTypeRelation = (data: ChargeTypeRelationQuery) => {
return request({
url: '/chargeType/relation',
method: 'PUT',
data: data
});
};

View File

@@ -64,3 +64,20 @@ export interface ChargeType2Query extends PageQuery {
*/
params?: any;
}
export interface ChargeTypeRelationQuery {
/**
* 主收费类型表id
*/
masterTypeId?: string;
/**
* 子收费类型表id
*/
slaveTypeIds?: string;
id?: string;
// 状态 0启用 1停用
status?: string;
}

View File

@@ -77,6 +77,14 @@ export const billPrint = (data: { 'detailsIds': string[]; 'residentId': string }
});
};
// 删除账单
export const billDelete = (ids: string | string[]) => {
return request({
url: `/cash/bill/${ids}`,
method: 'DELETE'
});
};
export type BillPrintType = {
'totalAccount': string;
'residentName': string;

View File

@@ -5,11 +5,11 @@ import { addBuildingType, addHouseType, BuildingUnit, BuildingVo } from './type'
// 楼栋---------------------------------------------------------------------------------------
/** 根据 小区id 和 类型 查询楼栋信息 */
export function getBuildinglistAPI(): AxiosPromise<BuildingVo[]> {
export function getBuildinglistAPI(query = {}): AxiosPromise<BuildingVo[]> {
return request({
url: '/building/byVillage',
method: 'get',
params: {}
params: query
});
}
/** 获取所有楼栋 */

View File

@@ -124,6 +124,7 @@ export interface HouseRentalSigningVO {
'tenantPhone': string;
'chargeMode': string;
'chargeStandard': string;
'contractName': string;
'contractStatus': string;
'leaseStartDate': string;
'leaseEndDate': string;

View File

@@ -20,16 +20,22 @@
<el-card class="flex-1" shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar
:disable-delete="multiple"
:disable-edit="single"
:show-add="checkPermi(['chargeType:chargeType:add'])"
:show-edit="false"
:show-delete="false"
@update:add="handleAdd"
@update:edit="handleUpdate()"
@update:delete="handleDelete()"
></right-toolbar>
<el-col :span="22"> </el-col>
<el-col :span="2">
<div class="flex justify-end items-center">
<el-button style="margin-right: 10px" type="primary" @click="handleContainer">关联收费</el-button>
<right-toolbar
:disable-delete="multiple"
:disable-edit="single"
:show-add="checkPermi(['chargeType:chargeType:add'])"
:show-edit="false"
:show-delete="false"
@update:add="handleAdd"
@update:edit="handleUpdate()"
@update:delete="handleDelete()"
></right-toolbar>
</div>
</el-col>
</el-row>
</template>
@@ -70,15 +76,64 @@
</div>
</template>
</el-dialog>
<el-dialog :title="dialog2.title" v-model="dialog2.visible" width="500px" append-to-body>
<el-form ref="chargeTypeForm2Ref" :model="form2" :rules="rules2" label-width="100px">
<el-form-item label="主收费类型">
<el-select
@change="handleChangeMasterType"
style="width: 220px; margin-right: 10px"
v-model="form2.masterTypeId"
placeholder="请选择收费类型"
>
<el-option v-for="item in TypeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="次收费类型" v-for="(_, index) in slaveTypeIdsList" :key="index">
<div class="flex flex-items-center">
<el-select
@change="handleChangeMasterType"
style="width: 220px; margin-right: 10px"
v-model="slaveTypeIdsList[index]"
placeholder="请选择收费类型"
>
<el-option :disabled="item.disabled" v-for="item in TypeList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<div class="addBox" @click="handleAddType" v-if="index === 0 && slaveTypeIdsList.length < TypeList.length - 1">
<el-icon size="23" color="#ffffff"><Plus /></el-icon>
</div>
<el-icon @click="deleteType(index)" v-else-if="slaveTypeIdsList.length > 1" size="24" color="red"><Delete /></el-icon>
</div>
</el-form-item>
<el-form-item label="是否启用关联">
<el-switch v-model="form2.status" active-value="0" inactive-value="1" active-text="启用" inactive-text="禁用" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading2" type="primary" @click="submitForm2"> </el-button>
<el-button @click="cancel2"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="ChargeType" lang="ts">
import PageHeader from '@/components/Pageheader/index.vue';
import pagination from '@/components/Pagination/index.vue';
import { listChargeType, getChargeType, delChargeType, addChargeType, updateChargeType } from '@/api/system/ChargeType';
import {
listChargeType,
getChargeType,
delChargeType,
addChargeType,
updateChargeType,
getChargeTypeRelation,
addChargeTypeRelation,
editChargeTypeRelation
} from '@/api/system/ChargeType';
import { ChargeTypeVO, ChargeTypeForm, ChargeType2Query } from '@/api/system/ChargeType/type';
import { checkPermi } from '@/utils/permission';
import { Delete, Plus } from '@element-plus/icons-vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -110,8 +165,7 @@ const data = reactive<PageData<ChargeTypeForm, ChargeType2Query>>({
pageNum: 1,
pageSize: 10,
name: undefined,
status: undefined,
params: {}
status: undefined
}
});
@@ -209,6 +263,85 @@ const handleDelete = async (row?: ChargeTypeVO) => {
await getList();
};
const dialog2 = ref({
visible: false,
title: ''
});
const form2 = ref({
'id': undefined,
'masterTypeId': undefined,
'status': '0',
'slaveTypeIds': undefined,
'remark': undefined
});
const rules2 = {};
// 子收费类型
const slaveTypeIdsList = ref([null]);
// 收费类型
const TypeList = ref([]);
// 关联收费
function handleContainer() {
TypeList.value = chargeTypeList.value.map((item) => {
return {
...item,
disabled: false
};
});
getChargeTypeRelation().then((res) => {
if (res.rows.length > 0) {
form2.value = res.rows[0];
slaveTypeIdsList.value = form2.value.slaveTypeIds.split(',');
handleChangeMasterType();
}
});
dialog2.value.visible = true;
dialog2.value.title = '关联收费';
}
function handleChangeMasterType() {
const selectedValues = [form2.value.masterTypeId, ...slaveTypeIdsList.value.filter((item) => item !== null && item !== undefined && item !== '')];
// 根据当前选中状态重新计算 disabled
TypeList.value.forEach((item) => {
item.disabled = selectedValues.includes(item.id);
});
}
function handleAddType() {
slaveTypeIdsList.value.length++;
}
function deleteType(index: number) {
slaveTypeIdsList.value.splice(index, 1);
}
function cancel2() {
dialog2.value.visible = false;
TypeList.value = [];
slaveTypeIdsList.value = [null];
dialog2.value.title = '';
}
const buttonLoading2 = ref(false);
function submitForm2() {
form2.value.slaveTypeIds = slaveTypeIdsList.value.filter((item) => item !== null).join(',');
buttonLoading2.value = true;
if (form2.value.id) {
// edit
editChargeTypeRelation(form2.value)
.then(() => {
proxy?.$modal.msgSuccess('操作成功');
cancel2();
getList();
})
.finally(() => (buttonLoading2.value = false));
} else {
// add
addChargeTypeRelation(form2.value)
.then(() => {
proxy?.$modal.msgSuccess('操作成功');
cancel2();
getList();
})
.finally(() => (buttonLoading2.value = false));
}
}
onMounted(() => {
getList();
});
@@ -218,4 +351,13 @@ onMounted(() => {
.el-table {
height: calc(100% - 80px);
}
.addBox {
width: 24px;
height: 24px;
background-color: rgba(26, 117, 255, 1);
line-height: 24px;
text-align: center;
border-radius: 50%;
}
</style>

View File

@@ -101,6 +101,7 @@
<div class="actions">
<el-button @click="handleIncome(false)" :disabled="!single">收费</el-button>
<el-button @click="printPIaoJuByOnly(false)" :disabled="!printSingle">打印票据</el-button>
<el-button @click="handleDelete(false)">批量删除</el-button>
</div>
</div>
<el-card class="flex-1" shadow="never">
@@ -153,14 +154,11 @@
<el-table-column label="缴费人" width="120" align="center" prop="residentName" />
<el-table-column label="缴费时间" width="200" align="center" prop="payTime" />
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column label="操作" width="110" align="center" fixed="right" class-name="small-padding fixed-width">
<el-table-column label="操作" width="150" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" v-if="scope.row.payStatus !== '1'" @click="handleIncome(scope.row)" v-has-permi="['bill:bill:edit']"
>收款</el-button
>
<el-button link type="success" v-if="scope.row.payStatus === '1'" @click="printPIaoJuByOnly(scope.row)" v-has-permi="['bill:bill:query']"
>打印票据</el-button
>
<el-button link type="primary" v-if="scope.row.payStatus !== '1'" @click="handleIncome(scope.row)">收款</el-button>
<el-button link type="success" v-if="scope.row.payStatus === '1'" @click="printPIaoJuByOnly(scope.row)">打印票据</el-button>
<el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -431,7 +429,7 @@ import pagination from '@/components/Pagination/index.vue';
import DictTag from '@/components/DictTag/index.vue';
import { getBuildinglistAPI, getHouselistAPI } from '@/api/system/house';
import { getCommunitylistAPI } from '@/api/system/community';
import { billEdit, billlistType, billPrint, BillPrintType, billQuery } from '@/api/system/SdbCashier';
import { billDelete, billEdit, billlistType, billPrint, BillPrintType, billQuery } from '@/api/system/SdbCashier';
import { listChargeItem } from '@/api/system/SdbChargeItem';
import { ref } from 'vue';
import { add, div, eq, eqMoney, gtMoney, ltMoney, minMoney, moneyAdd, mul, sub, sum, toBig } from '@/utils/money';
@@ -541,7 +539,9 @@ function handleChangeVillage(val: string) {
buildingList.value = [];
unitList.value = [];
if (val) {
getBuildinglistAPI().then((res) => {
getBuildinglistAPI({
villageId: val
}).then((res) => {
buildingList.value = res.data;
handleChargeItem(val);
});
@@ -1042,6 +1042,26 @@ function conFimPrint() {
}, 100);
}
// 删除
async function handleDelete(row: billlistType | false) {
if (row) {
await proxy?.$modal.confirm('该信息删除后无法恢复,确定要删除吗?');
billDelete(row.detailsId).then(() => {
ElMessage.success('删除成功');
getList();
});
} else {
if (ids.value.length <= 0) {
return ElMessage.warning('请选择账单!');
}
await proxy?.$modal.confirm('该信息删除后无法恢复,确定要删除吗?');
billDelete(ids.value.map((item) => item.detailsId)).then(() => {
ElMessage.success('删除成功');
getList();
});
}
}
onMounted(() => {
queryParams.value.villageId = villageId;
getList();
@@ -1143,10 +1163,7 @@ function handlePayListIsEmpt() {
item.payAmount === undefined ||
item.payAmount === ''
);
if (invalidIndex !== -1) {
return false;
}
return true;
return invalidIndex === -1;
}
// 校验数字

View File

@@ -216,6 +216,7 @@ type HouseRentalFormType = HouseRentalSigningVO & {
};
const initFormData: HouseRentalFormType = {
contractName: '',
'createTime': undefined,
'id': undefined,
'rentalId': undefined,
@@ -290,7 +291,7 @@ const data = reactive<PageData<HouseRentalFormType, HouseRentalQuery>>({
const { queryParams, form, rules } = toRefs(data);
/** 查询房屋租赁管理列表╬₧2╬╬ */
/** 查询房屋租赁管理列表 */
const getList = async () => {
loading.value = true;
listHouseRental(queryParams.value)
@@ -402,10 +403,11 @@ function sign(row: HouseRentalVO) {
form.value.villageId = info.villageId;
form.value.rentalId = row.id;
if (row.signingList && row.signingList.length > 0) {
const names = row.signingList[0].contractName ? row.signingList[0].contractName.split(',') : [];
showImgList.value = row.signingList[0].contractUrl.split(',').map((item, index) => {
return {
uid: index,
name: item.split('.com/')[1].split('/')[3],
name: names[index] || item.split('.com/')[1].split('/')[3],
url: item,
isLink: true
};

View File

@@ -4,7 +4,7 @@
<div class="iconbox">
<div
class="icon_box_text"
:title="`${weather_icon.title} ${weather_icon.wind_direction} ${weather_icon.wind_power} 温度${weather_icon.temperature}°C`"
:title="`${weather_icon.title} ${weather_icon.wind_direction} ${weather_icon.wind_power} 温度${weather_icon.temperature ?? ''}°C`"
>
{{ getWeatherIcon(weather_icon.iconvalue) }}
</div>
@@ -15,7 +15,9 @@
</div>
</div>
<div class="villageinfo flex-1">
<div class="villagename">{{ props.villageinfo.villageName }}</div>
<div class="villagename" :title="props.villageinfo.villageName">
{{ props.villageinfo.villageName }}
</div>
<div class="week">
<span style="padding-right: 10px">{{
new Intl.DateTimeFormat('zh-cn', {
@@ -74,7 +76,6 @@ const weather_icon = ref({
gap: 30px;
.tips {
font-size: small;
color: #ffffff77;
margin-top: 10px;
font-size: 0.8rem;
@@ -91,14 +92,11 @@ const weather_icon = ref({
position: relative;
z-index: 2;
cursor: default;
margin-right: 20px;
margin: 0 auto;
.icon_box_text {
width: 100%;
height: 100%;
line-height: 1;
font-size: 70px;
text-align: center;
display: flex;
justify-content: center;
@@ -113,6 +111,10 @@ const weather_icon = ref({
.villageinfo {
margin-left: 20px;
.villagename {
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 30px;
font-weight: 500;
font-size: 1.2rem;