Commit a0f584aaadf595efc6081c9de6d1fb8036413ced
1 parent
f99ceb4f
费用公摊开发完成
Showing
22 changed files
with
2504 additions
and
0 deletions
src/api/fee/floorShareApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 查询楼栋公摊列表 | |
| 5 | +export function listFloorShareMeter(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + request({ | |
| 8 | + url: '/meter.listFloorShareMeter', | |
| 9 | + method: 'get', | |
| 10 | + params: { | |
| 11 | + ...params, | |
| 12 | + communityId: getCommunityId() | |
| 13 | + } | |
| 14 | + }).then(response => { | |
| 15 | + const res = response.data | |
| 16 | + resolve(res) | |
| 17 | + }).catch(error => { | |
| 18 | + reject(error) | |
| 19 | + }) | |
| 20 | + }) | |
| 21 | +} | |
| 22 | + | |
| 23 | +// 添加楼栋公摊 | |
| 24 | +export function saveFloorShareMeter(data) { | |
| 25 | + return new Promise((resolve, reject) => { | |
| 26 | + request({ | |
| 27 | + url: '/meter.saveFloorShareMeter', | |
| 28 | + method: 'post', | |
| 29 | + data: { | |
| 30 | + ...data, | |
| 31 | + communityId: getCommunityId() | |
| 32 | + } | |
| 33 | + }).then(response => { | |
| 34 | + const res = response.data | |
| 35 | + resolve(res) | |
| 36 | + }).catch(error => { | |
| 37 | + reject(error) | |
| 38 | + }) | |
| 39 | + }) | |
| 40 | +} | |
| 41 | + | |
| 42 | +// 修改楼栋公摊 | |
| 43 | +export function updateFloorShareMeter(data) { | |
| 44 | + return new Promise((resolve, reject) => { | |
| 45 | + request({ | |
| 46 | + url: '/meter.updateFloorShareMeter', | |
| 47 | + method: 'post', | |
| 48 | + data: { | |
| 49 | + ...data, | |
| 50 | + communityId: getCommunityId() | |
| 51 | + } | |
| 52 | + }).then(response => { | |
| 53 | + const res = response.data | |
| 54 | + resolve(res) | |
| 55 | + }).catch(error => { | |
| 56 | + reject(error) | |
| 57 | + }) | |
| 58 | + }) | |
| 59 | +} | |
| 60 | + | |
| 61 | +// 删除楼栋公摊 | |
| 62 | +export function deleteFloorShareMeter(data) { | |
| 63 | + return new Promise((resolve, reject) => { | |
| 64 | + request({ | |
| 65 | + url: '/meter.deleteFloorShareMeter', | |
| 66 | + method: 'post', | |
| 67 | + data: { | |
| 68 | + ...data, | |
| 69 | + communityId: getCommunityId() | |
| 70 | + } | |
| 71 | + }).then(response => { | |
| 72 | + const res = response.data | |
| 73 | + resolve(res) | |
| 74 | + }).catch(error => { | |
| 75 | + reject(error) | |
| 76 | + }) | |
| 77 | + }) | |
| 78 | +} | |
| 79 | + | |
| 80 | +// 查询楼栋列表 | |
| 81 | +export function queryFloors(params) { | |
| 82 | + return new Promise((resolve, reject) => { | |
| 83 | + request({ | |
| 84 | + url: '/floor.queryFloors', | |
| 85 | + method: 'get', | |
| 86 | + params: { | |
| 87 | + ...params, | |
| 88 | + communityId: getCommunityId() | |
| 89 | + } | |
| 90 | + }).then(response => { | |
| 91 | + const res = response.data | |
| 92 | + resolve(res) | |
| 93 | + }).catch(error => { | |
| 94 | + reject(error) | |
| 95 | + }) | |
| 96 | + }) | |
| 97 | +} | |
| 98 | + | |
| 99 | +// 查询费用项列表 | |
| 100 | +export function listFeeConfigs(params) { | |
| 101 | + return new Promise((resolve, reject) => { | |
| 102 | + request({ | |
| 103 | + url: '/feeConfig.listFeeConfigs', | |
| 104 | + method: 'get', | |
| 105 | + params: { | |
| 106 | + ...params, | |
| 107 | + communityId: getCommunityId() | |
| 108 | + } | |
| 109 | + }).then(response => { | |
| 110 | + const res = response.data | |
| 111 | + resolve(res) | |
| 112 | + }).catch(error => { | |
| 113 | + reject(error) | |
| 114 | + }) | |
| 115 | + }) | |
| 116 | +} | |
| 0 | 117 | \ No newline at end of file | ... | ... |
src/api/fee/roomFeeImportApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * 查询费用导入列表 | |
| 6 | + * @param {Object} params 查询参数 | |
| 7 | + * @returns {Promise} Promise对象 | |
| 8 | + */ | |
| 9 | +export function queryImportFee(params) { | |
| 10 | + return new Promise((resolve, reject) => { | |
| 11 | + const queryParams = { | |
| 12 | + ...params, | |
| 13 | + communityId: getCommunityId() | |
| 14 | + } | |
| 15 | + request({ | |
| 16 | + url: '/importFee/queryImportFee', | |
| 17 | + method: 'get', | |
| 18 | + params: queryParams | |
| 19 | + }).then(response => { | |
| 20 | + const res = response.data | |
| 21 | + resolve({ | |
| 22 | + data: res.data, | |
| 23 | + total: res.total, | |
| 24 | + records: res.records | |
| 25 | + }) | |
| 26 | + }).catch(error => { | |
| 27 | + reject(error) | |
| 28 | + }) | |
| 29 | + }) | |
| 30 | +} | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * 导入费用数据 | |
| 34 | + * @param {FormData} formData 表单数据 | |
| 35 | + * @returns {Promise} Promise对象 | |
| 36 | + */ | |
| 37 | +export function importRoomFeeData(formData) { | |
| 38 | + return new Promise((resolve, reject) => { | |
| 39 | + request({ | |
| 40 | + url: '/assetImport/importData', | |
| 41 | + method: 'post', | |
| 42 | + data: formData, | |
| 43 | + headers: { | |
| 44 | + 'Content-Type': 'multipart/form-data' | |
| 45 | + } | |
| 46 | + }).then(response => { | |
| 47 | + const res = response.data | |
| 48 | + if (res.code === 0) { | |
| 49 | + resolve(res.data) | |
| 50 | + } else { | |
| 51 | + reject(new Error(res.msg)) | |
| 52 | + } | |
| 53 | + }).catch(error => { | |
| 54 | + reject(error) | |
| 55 | + }) | |
| 56 | + }) | |
| 57 | +} | |
| 58 | + | |
| 59 | +/** | |
| 60 | + * 下载导入模板 | |
| 61 | + * @param {Object} params 查询参数 | |
| 62 | + * @returns {Promise} Promise对象 | |
| 63 | + */ | |
| 64 | +export function downloadImportTemplate(params) { | |
| 65 | + return new Promise((resolve, reject) => { | |
| 66 | + request({ | |
| 67 | + url: '/export.exportData', | |
| 68 | + method: 'get', | |
| 69 | + params: { | |
| 70 | + ...params, | |
| 71 | + communityId: getCommunityId() | |
| 72 | + } | |
| 73 | + }).then(response => { | |
| 74 | + const res = response.data | |
| 75 | + if (res.code === 0) { | |
| 76 | + resolve(res.data) | |
| 77 | + } else { | |
| 78 | + reject(new Error(res.msg)) | |
| 79 | + } | |
| 80 | + }).catch(error => { | |
| 81 | + reject(error) | |
| 82 | + }) | |
| 83 | + }) | |
| 84 | +} | |
| 85 | + | |
| 86 | +/** | |
| 87 | + * 获取费用导入详情 | |
| 88 | + * @param {String} importFeeId 导入ID | |
| 89 | + * @returns {Promise} Promise对象 | |
| 90 | + */ | |
| 91 | +export function getImportFeeDetail(importFeeId) { | |
| 92 | + return new Promise((resolve, reject) => { | |
| 93 | + request({ | |
| 94 | + url: '/importFee/getImportFeeDetail', | |
| 95 | + method: 'get', | |
| 96 | + params: { | |
| 97 | + importFeeId, | |
| 98 | + communityId: getCommunityId() | |
| 99 | + } | |
| 100 | + }).then(response => { | |
| 101 | + const res = response.data | |
| 102 | + if (res.code === 0) { | |
| 103 | + resolve(res.data) | |
| 104 | + } else { | |
| 105 | + reject(new Error(res.msg)) | |
| 106 | + } | |
| 107 | + }).catch(error => { | |
| 108 | + reject(error) | |
| 109 | + }) | |
| 110 | + }) | |
| 111 | +} | |
| 0 | 112 | \ No newline at end of file | ... | ... |
src/api/fee/shareReadingApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 获取公摊抄表列表 | |
| 5 | +export function listFloorShareReading(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + const defaultParams = { | |
| 8 | + communityId: getCommunityId(), | |
| 9 | + page: 1, | |
| 10 | + row: 10 | |
| 11 | + } | |
| 12 | + request({ | |
| 13 | + url: '/meter.listFloorShareReading', | |
| 14 | + method: 'get', | |
| 15 | + params: { ...defaultParams, ...params } | |
| 16 | + }).then(response => { | |
| 17 | + const res = response.data | |
| 18 | + resolve({ | |
| 19 | + data: res.data, | |
| 20 | + total: res.total | |
| 21 | + }) | |
| 22 | + }).catch(error => { | |
| 23 | + reject(error) | |
| 24 | + }) | |
| 25 | + }) | |
| 26 | +} | |
| 27 | + | |
| 28 | +// 获取公摊表列表 | |
| 29 | +export function listFloorShareMeter(params) { | |
| 30 | + return new Promise((resolve, reject) => { | |
| 31 | + const defaultParams = { | |
| 32 | + communityId: getCommunityId(), | |
| 33 | + page: 1, | |
| 34 | + row: 300 | |
| 35 | + } | |
| 36 | + request({ | |
| 37 | + url: '/meter.listFloorShareMeter', | |
| 38 | + method: 'get', | |
| 39 | + params: { ...defaultParams, ...params } | |
| 40 | + }).then(response => { | |
| 41 | + const res = response.data | |
| 42 | + resolve({ | |
| 43 | + data: res.data, | |
| 44 | + total: res.total | |
| 45 | + }) | |
| 46 | + }).catch(error => { | |
| 47 | + reject(error) | |
| 48 | + }) | |
| 49 | + }) | |
| 50 | +} | |
| 51 | + | |
| 52 | +// 添加公摊抄表 | |
| 53 | +export function saveFloorShareReading(data) { | |
| 54 | + return new Promise((resolve, reject) => { | |
| 55 | + request({ | |
| 56 | + url: '/meter.saveFloorShareReading', | |
| 57 | + method: 'post', | |
| 58 | + data: { | |
| 59 | + ...data, | |
| 60 | + communityId: getCommunityId() | |
| 61 | + } | |
| 62 | + }).then(response => { | |
| 63 | + const res = response.data | |
| 64 | + if (res.code === 0) { | |
| 65 | + resolve(res) | |
| 66 | + } else { | |
| 67 | + reject(new Error(res.msg)) | |
| 68 | + } | |
| 69 | + }).catch(error => { | |
| 70 | + reject(error) | |
| 71 | + }) | |
| 72 | + }) | |
| 73 | +} | |
| 74 | + | |
| 75 | +// 审核公摊抄表 | |
| 76 | +export function auditFloorShareReading(data) { | |
| 77 | + return new Promise((resolve, reject) => { | |
| 78 | + request({ | |
| 79 | + url: '/meter.auditFloorShareReading', | |
| 80 | + method: 'post', | |
| 81 | + data: { | |
| 82 | + ...data, | |
| 83 | + communityId: getCommunityId() | |
| 84 | + } | |
| 85 | + }).then(response => { | |
| 86 | + const res = response.data | |
| 87 | + if (res.code === 0) { | |
| 88 | + resolve(res) | |
| 89 | + } else { | |
| 90 | + reject(new Error(res.msg)) | |
| 91 | + } | |
| 92 | + }).catch(error => { | |
| 93 | + reject(error) | |
| 94 | + }) | |
| 95 | + }) | |
| 96 | +} | |
| 97 | + | |
| 98 | +// 删除公摊抄表 | |
| 99 | +export function deleteFloorShareReading(data) { | |
| 100 | + return new Promise((resolve, reject) => { | |
| 101 | + request({ | |
| 102 | + url: '/meter.deleteFloorShareReading', | |
| 103 | + method: 'post', | |
| 104 | + data: { | |
| 105 | + ...data, | |
| 106 | + communityId: getCommunityId() | |
| 107 | + } | |
| 108 | + }).then(response => { | |
| 109 | + const res = response.data | |
| 110 | + if (res.code === 0) { | |
| 111 | + resolve(res) | |
| 112 | + } else { | |
| 113 | + reject(new Error(res.msg)) | |
| 114 | + } | |
| 115 | + }).catch(error => { | |
| 116 | + reject(error) | |
| 117 | + }) | |
| 118 | + }) | |
| 119 | +} | |
| 0 | 120 | \ No newline at end of file | ... | ... |
src/api/fee/shareReadingFeeApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 获取公摊费用列表 | |
| 5 | + * @param {Object} params 查询参数 | |
| 6 | + * @returns {Promise} Promise对象 | |
| 7 | + */ | |
| 8 | +export function listFloorShareFee(params) { | |
| 9 | + return new Promise((resolve, reject) => { | |
| 10 | + request({ | |
| 11 | + url: '/meter.listFloorShareFee', | |
| 12 | + method: 'get', | |
| 13 | + params | |
| 14 | + }).then(response => { | |
| 15 | + const res = response.data | |
| 16 | + resolve(res) | |
| 17 | + }).catch(error => { | |
| 18 | + reject(error) | |
| 19 | + }) | |
| 20 | + }) | |
| 21 | +} | |
| 22 | + | |
| 23 | +/** | |
| 24 | + * 获取社区ID | |
| 25 | + * @returns {Promise} Promise对象 | |
| 26 | + */ | |
| 27 | +export function getCommunityId() { | |
| 28 | + return new Promise((resolve, reject) => { | |
| 29 | + request({ | |
| 30 | + url: '/community.getCommunityId', | |
| 31 | + method: 'get' | |
| 32 | + }).then(response => { | |
| 33 | + const res = response.data | |
| 34 | + resolve(res.communityId) | |
| 35 | + }).catch(error => { | |
| 36 | + reject(error) | |
| 37 | + }) | |
| 38 | + }) | |
| 39 | +} | |
| 0 | 40 | \ No newline at end of file | ... | ... |
src/components/fee/addFloorShare.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('floorShare.addTitle')" :visible.sync="dialogVisible" width="50%" @close="handleClose"> | |
| 3 | + <el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="right"> | |
| 4 | + <el-form-item :label="$t('floorShare.floor')" prop="floorNum"> | |
| 5 | + <el-input v-model="form.floorNum" disabled /> | |
| 6 | + </el-form-item> | |
| 7 | + | |
| 8 | + <el-form-item :label="$t('floorShare.meterType')" prop="meterType"> | |
| 9 | + <el-select v-model="form.meterType" style="width:100%"> | |
| 10 | + <el-option v-for="item in meterTypes" :key="item.value" :label="item.label" :value="item.value" /> | |
| 11 | + </el-select> | |
| 12 | + </el-form-item> | |
| 13 | + | |
| 14 | + <el-form-item :label="$t('floorShare.meterNum')"> | |
| 15 | + <el-input v-model="form.meterNum" :placeholder="$t('floorShare.meterNumPlaceholder')" /> | |
| 16 | + <span class="tip-text">{{ $t('floorShare.meterNumTip') }}</span> | |
| 17 | + </el-form-item> | |
| 18 | + | |
| 19 | + <el-form-item :label="$t('floorShare.feeItem')" prop="configId"> | |
| 20 | + <el-select v-model="form.configId" style="width:100%"> | |
| 21 | + <el-option v-for="item in feeConfigs" :key="item.configId" :label="item.feeName" :value="item.configId" /> | |
| 22 | + </el-select> | |
| 23 | + </el-form-item> | |
| 24 | + | |
| 25 | + <el-form-item :label="$t('floorShare.feePrice')" prop="sharePrice"> | |
| 26 | + <el-input v-model.number="form.sharePrice" type="number" /> | |
| 27 | + </el-form-item> | |
| 28 | + | |
| 29 | + <el-form-item :label="$t('floorShare.shareType')" prop="shareType"> | |
| 30 | + <el-select v-model="form.shareType" style="width:100%" @change="handleShareTypeChange"> | |
| 31 | + <el-option v-for="item in shareTypes" :key="item.value" :label="item.label" :value="item.value" /> | |
| 32 | + </el-select> | |
| 33 | + </el-form-item> | |
| 34 | + | |
| 35 | + <el-form-item v-if="form.shareType === '3003'" :label="$t('floorShare.formula')" prop="formulaValue"> | |
| 36 | + <el-input v-model="form.formulaValue" /> | |
| 37 | + </el-form-item> | |
| 38 | + </el-form> | |
| 39 | + | |
| 40 | + <div slot="footer" class="dialog-footer"> | |
| 41 | + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button> | |
| 42 | + <el-button type="primary" @click="handleSubmit">{{ $t('common.save') }}</el-button> | |
| 43 | + </div> | |
| 44 | + </el-dialog> | |
| 45 | +</template> | |
| 46 | + | |
| 47 | +<script> | |
| 48 | +import { saveFloorShareMeter, listFeeConfigs } from '@/api/fee/floorShareApi' | |
| 49 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 50 | + | |
| 51 | +export default { | |
| 52 | + name: 'AddFloorShare', | |
| 53 | + data() { | |
| 54 | + return { | |
| 55 | + dialogVisible: false, | |
| 56 | + form: { | |
| 57 | + floorId: '', | |
| 58 | + floorNum: '', | |
| 59 | + meterType: '', | |
| 60 | + meterNum: '', | |
| 61 | + shareType: '', | |
| 62 | + formulaValue: '', | |
| 63 | + configId: '', | |
| 64 | + sharePrice: '', | |
| 65 | + communityId: '' | |
| 66 | + }, | |
| 67 | + feeConfigs: [], | |
| 68 | + meterTypes: [ | |
| 69 | + { value: 'D', label: this.$t('floorShare.electricMeter') }, | |
| 70 | + { value: 'S', label: this.$t('floorShare.waterMeter') } | |
| 71 | + ], | |
| 72 | + shareTypes: [ | |
| 73 | + { value: '1001', label: this.$t('floorShare.byArea') }, | |
| 74 | + { value: '2002', label: this.$t('floorShare.byHouse') }, | |
| 75 | + { value: '3003', label: this.$t('floorShare.byFormula') } | |
| 76 | + ], | |
| 77 | + rules: { | |
| 78 | + meterType: [ | |
| 79 | + { required: true, message: this.$t('floorShare.meterTypeRequired'), trigger: 'blur' } | |
| 80 | + ], | |
| 81 | + configId: [ | |
| 82 | + { required: true, message: this.$t('floorShare.feeItemRequired'), trigger: 'blur' } | |
| 83 | + ], | |
| 84 | + sharePrice: [ | |
| 85 | + { required: true, message: this.$t('floorShare.feePriceRequired'), trigger: 'blur' }, | |
| 86 | + { type: 'number', message: this.$t('floorShare.feePriceNumber'), trigger: 'blur' } | |
| 87 | + ], | |
| 88 | + shareType: [ | |
| 89 | + { required: true, message: this.$t('floorShare.shareTypeRequired'), trigger: 'blur' } | |
| 90 | + ], | |
| 91 | + formulaValue: [ | |
| 92 | + { required: true, message: this.$t('floorShare.formulaRequired'), trigger: 'blur' } | |
| 93 | + ] | |
| 94 | + } | |
| 95 | + } | |
| 96 | + }, | |
| 97 | + methods: { | |
| 98 | + open(data) { | |
| 99 | + this.form = { | |
| 100 | + ...this.form, | |
| 101 | + floorId: data.floorId, | |
| 102 | + floorNum: data.floorNum, | |
| 103 | + communityId: getCommunityId() | |
| 104 | + } | |
| 105 | + this.loadFeeConfigs() | |
| 106 | + this.dialogVisible = true | |
| 107 | + this.$nextTick(() => { | |
| 108 | + this.$refs.form && this.$refs.form.clearValidate() | |
| 109 | + }) | |
| 110 | + }, | |
| 111 | + async loadFeeConfigs() { | |
| 112 | + try { | |
| 113 | + const params = { | |
| 114 | + page: 1, | |
| 115 | + row: 500, | |
| 116 | + communityId: this.form.communityId, | |
| 117 | + feeTypeCd: '888800010017', | |
| 118 | + isDefault: 'F', | |
| 119 | + state: 'Y' | |
| 120 | + } | |
| 121 | + const { feeConfigs } = await listFeeConfigs(params) | |
| 122 | + this.feeConfigs = feeConfigs | |
| 123 | + } catch (error) { | |
| 124 | + this.$message.error(this.$t('floorShare.fetchFeeConfigError')) | |
| 125 | + } | |
| 126 | + }, | |
| 127 | + handleShareTypeChange(value) { | |
| 128 | + if (value !== '3003') { | |
| 129 | + this.form.formulaValue = '' | |
| 130 | + } | |
| 131 | + }, | |
| 132 | + handleSubmit() { | |
| 133 | + this.$refs.form.validate(async valid => { | |
| 134 | + if (valid) { | |
| 135 | + try { | |
| 136 | + await saveFloorShareMeter(this.form) | |
| 137 | + this.$message.success(this.$t('floorShare.addSuccess')) | |
| 138 | + this.dialogVisible = false | |
| 139 | + this.$emit('success') | |
| 140 | + } catch (error) { | |
| 141 | + this.$message.error(error.message || this.$t('floorShare.addFailed')) | |
| 142 | + } | |
| 143 | + } | |
| 144 | + }) | |
| 145 | + }, | |
| 146 | + handleClose() { | |
| 147 | + this.$refs.form.resetFields() | |
| 148 | + } | |
| 149 | + } | |
| 150 | +} | |
| 151 | +</script> | |
| 152 | + | |
| 153 | +<style lang="scss" scoped> | |
| 154 | +.tip-text { | |
| 155 | + font-size: 12px; | |
| 156 | + color: #909399; | |
| 157 | + margin-left: 10px; | |
| 158 | +} | |
| 159 | +</style> | |
| 0 | 160 | \ No newline at end of file | ... | ... |
src/components/fee/addShareReading.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('shareReading.add.title')" :visible.sync="dialogVisible" width="50%" @close="handleClose"> | |
| 3 | + <el-form ref="form" :model="form" :rules="rules" label-width="120px"> | |
| 4 | + <el-form-item :label="$t('shareReading.add.meter')" prop="fsmId"> | |
| 5 | + <el-select v-model="form.fsmId" :placeholder="$t('shareReading.add.selectMeter')" style="width:100%" | |
| 6 | + @change="handleMeterChange"> | |
| 7 | + <el-option v-for="(item, index) in floorShares" :key="index" :label="`${item.floorNum}栋-${item.meterTypeName}`" | |
| 8 | + :value="item.fsmId" /> | |
| 9 | + </el-select> | |
| 10 | + </el-form-item> | |
| 11 | + <el-form-item :label="$t('shareReading.add.preDegrees')" prop="preDegrees"> | |
| 12 | + <el-input v-model="form.preDegrees" :placeholder="$t('shareReading.add.inputPreDegrees')" /> | |
| 13 | + </el-form-item> | |
| 14 | + <el-form-item :label="$t('shareReading.add.curDegrees')" prop="curDegrees"> | |
| 15 | + <el-input v-model="form.curDegrees" :placeholder="$t('shareReading.add.inputCurDegrees')" /> | |
| 16 | + </el-form-item> | |
| 17 | + <el-form-item :label="$t('shareReading.add.preReadingTime')" prop="preReadingTime"> | |
| 18 | + <el-date-picker v-model="form.preReadingTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" | |
| 19 | + :placeholder="$t('shareReading.add.selectPreTime')" style="width:100%" /> | |
| 20 | + </el-form-item> | |
| 21 | + <el-form-item :label="$t('shareReading.add.curReadingTime')" prop="curReadingTime"> | |
| 22 | + <el-date-picker v-model="form.curReadingTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" | |
| 23 | + :placeholder="$t('shareReading.add.selectCurTime')" style="width:100%" /> | |
| 24 | + </el-form-item> | |
| 25 | + <el-form-item :label="$t('shareReading.add.remark')"> | |
| 26 | + <el-input v-model="form.remark" type="textarea" :placeholder="$t('shareReading.add.inputRemark')" :rows="3" /> | |
| 27 | + </el-form-item> | |
| 28 | + </el-form> | |
| 29 | + <span slot="footer" class="dialog-footer"> | |
| 30 | + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button> | |
| 31 | + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button> | |
| 32 | + </span> | |
| 33 | + </el-dialog> | |
| 34 | +</template> | |
| 35 | + | |
| 36 | +<script> | |
| 37 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 38 | +import { saveFloorShareReading, listFloorShareMeter } from '@/api/fee/shareReadingApi' | |
| 39 | + | |
| 40 | +export default { | |
| 41 | + name: 'AddShareReading', | |
| 42 | + data() { | |
| 43 | + return { | |
| 44 | + dialogVisible: false, | |
| 45 | + floorShares: [], | |
| 46 | + form: { | |
| 47 | + fsmId: '', | |
| 48 | + preDegrees: '', | |
| 49 | + curDegrees: '', | |
| 50 | + preReadingTime: '', | |
| 51 | + curReadingTime: '', | |
| 52 | + remark: '', | |
| 53 | + communityId: '' | |
| 54 | + }, | |
| 55 | + rules: { | |
| 56 | + fsmId: [ | |
| 57 | + { required: true, message: this.$t('shareReading.validate.selectMeter'), trigger: 'change' } | |
| 58 | + ], | |
| 59 | + preDegrees: [ | |
| 60 | + { required: true, message: this.$t('shareReading.validate.inputPreDegrees'), trigger: 'blur' }, | |
| 61 | + { pattern: /^\d+(\.\d+)?$/, message: this.$t('shareReading.validate.number'), trigger: 'blur' } | |
| 62 | + ], | |
| 63 | + curDegrees: [ | |
| 64 | + { required: true, message: this.$t('shareReading.validate.inputCurDegrees'), trigger: 'blur' }, | |
| 65 | + { pattern: /^\d+(\.\d+)?$/, message: this.$t('shareReading.validate.number'), trigger: 'blur' } | |
| 66 | + ], | |
| 67 | + preReadingTime: [ | |
| 68 | + { required: true, message: this.$t('shareReading.validate.selectPreTime'), trigger: 'change' } | |
| 69 | + ], | |
| 70 | + curReadingTime: [ | |
| 71 | + { required: true, message: this.$t('shareReading.validate.selectCurTime'), trigger: 'change' } | |
| 72 | + ] | |
| 73 | + } | |
| 74 | + } | |
| 75 | + }, | |
| 76 | + methods: { | |
| 77 | + open() { | |
| 78 | + this.dialogVisible = true | |
| 79 | + this.getFloorShares() | |
| 80 | + }, | |
| 81 | + async getFloorShares() { | |
| 82 | + try { | |
| 83 | + const params = { | |
| 84 | + page: 1, | |
| 85 | + row: 300, | |
| 86 | + communityId: getCommunityId() | |
| 87 | + } | |
| 88 | + const { data } = await listFloorShareMeter(params) | |
| 89 | + this.floorShares = data | |
| 90 | + } catch (error) { | |
| 91 | + console.error('获取公摊表列表失败:', error) | |
| 92 | + } | |
| 93 | + }, | |
| 94 | + handleMeterChange(val) { | |
| 95 | + const selectedMeter = this.floorShares.find(item => item.fsmId === val) | |
| 96 | + if (selectedMeter) { | |
| 97 | + this.form.preDegrees = selectedMeter.curDegree | |
| 98 | + this.form.preReadingTime = selectedMeter.curReadingTime | |
| 99 | + } | |
| 100 | + }, | |
| 101 | + handleSubmit() { | |
| 102 | + this.$refs.form.validate(async valid => { | |
| 103 | + if (valid) { | |
| 104 | + try { | |
| 105 | + this.form.communityId = getCommunityId() | |
| 106 | + await saveFloorShareReading(this.form) | |
| 107 | + this.$message.success(this.$t('shareReading.message.addSuccess')) | |
| 108 | + this.dialogVisible = false | |
| 109 | + this.$emit('success') | |
| 110 | + } catch (error) { | |
| 111 | + console.error('添加公摊抄表失败:', error) | |
| 112 | + } | |
| 113 | + } | |
| 114 | + }) | |
| 115 | + }, | |
| 116 | + handleClose() { | |
| 117 | + this.$refs.form.resetFields() | |
| 118 | + this.form = { | |
| 119 | + fsmId: '', | |
| 120 | + preDegrees: '', | |
| 121 | + curDegrees: '', | |
| 122 | + preReadingTime: '', | |
| 123 | + curReadingTime: '', | |
| 124 | + remark: '', | |
| 125 | + communityId: '' | |
| 126 | + } | |
| 127 | + } | |
| 128 | + } | |
| 129 | +} | |
| 130 | +</script> | |
| 0 | 131 | \ No newline at end of file | ... | ... |
src/components/fee/auditShareReading.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('shareReading.audit.title')" | |
| 4 | + :visible.sync="dialogVisible" | |
| 5 | + width="40%" | |
| 6 | + @close="handleClose" | |
| 7 | + > | |
| 8 | + <el-form ref="form" :model="form" :rules="rules" label-width="120px"> | |
| 9 | + <el-form-item :label="$t('shareReading.audit.status')" prop="state"> | |
| 10 | + <el-select | |
| 11 | + v-model="form.state" | |
| 12 | + :placeholder="$t('shareReading.audit.selectStatus')" | |
| 13 | + style="width:100%" | |
| 14 | + > | |
| 15 | + <el-option | |
| 16 | + :label="$t('shareReading.status.passed')" | |
| 17 | + value="C" | |
| 18 | + /> | |
| 19 | + <el-option | |
| 20 | + :label="$t('shareReading.status.rejected')" | |
| 21 | + value="F" | |
| 22 | + /> | |
| 23 | + </el-select> | |
| 24 | + </el-form-item> | |
| 25 | + <el-form-item :label="$t('shareReading.audit.remark')"> | |
| 26 | + <el-input | |
| 27 | + v-model="form.auditRemark" | |
| 28 | + type="textarea" | |
| 29 | + :placeholder="$t('shareReading.audit.inputRemark')" | |
| 30 | + :rows="3" | |
| 31 | + /> | |
| 32 | + </el-form-item> | |
| 33 | + </el-form> | |
| 34 | + <span slot="footer" class="dialog-footer"> | |
| 35 | + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button> | |
| 36 | + <el-button type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</el-button> | |
| 37 | + </span> | |
| 38 | + </el-dialog> | |
| 39 | +</template> | |
| 40 | + | |
| 41 | +<script> | |
| 42 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 43 | +import { auditFloorShareReading } from '@/api/fee/shareReadingApi' | |
| 44 | + | |
| 45 | +export default { | |
| 46 | + name: 'AuditShareReading', | |
| 47 | + data() { | |
| 48 | + return { | |
| 49 | + dialogVisible: false, | |
| 50 | + form: { | |
| 51 | + readingId: '', | |
| 52 | + state: '', | |
| 53 | + auditRemark: '', | |
| 54 | + communityId: '' | |
| 55 | + }, | |
| 56 | + rules: { | |
| 57 | + state: [ | |
| 58 | + { required: true, message: this.$t('shareReading.validate.selectStatus'), trigger: 'change' } | |
| 59 | + ] | |
| 60 | + } | |
| 61 | + } | |
| 62 | + }, | |
| 63 | + methods: { | |
| 64 | + open(data) { | |
| 65 | + this.dialogVisible = true | |
| 66 | + this.form.readingId = data.readingId | |
| 67 | + this.form.communityId = getCommunityId() | |
| 68 | + }, | |
| 69 | + handleSubmit() { | |
| 70 | + this.$refs.form.validate(async valid => { | |
| 71 | + if (valid) { | |
| 72 | + try { | |
| 73 | + await auditFloorShareReading(this.form) | |
| 74 | + this.$message.success(this.$t('shareReading.message.auditSuccess')) | |
| 75 | + this.dialogVisible = false | |
| 76 | + this.$emit('success') | |
| 77 | + } catch (error) { | |
| 78 | + console.error('审核公摊抄表失败:', error) | |
| 79 | + } | |
| 80 | + } | |
| 81 | + }) | |
| 82 | + }, | |
| 83 | + handleClose() { | |
| 84 | + this.$refs.form.resetFields() | |
| 85 | + this.form = { | |
| 86 | + readingId: '', | |
| 87 | + state: '', | |
| 88 | + auditRemark: '', | |
| 89 | + communityId: '' | |
| 90 | + } | |
| 91 | + } | |
| 92 | + } | |
| 93 | +} | |
| 94 | +</script> | |
| 0 | 95 | \ No newline at end of file | ... | ... |
src/components/fee/deleteFloorShare.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('floorShare.deleteConfirm')" | |
| 4 | + :visible.sync="dialogVisible" | |
| 5 | + width="30%" | |
| 6 | + center | |
| 7 | + > | |
| 8 | + <div class="text-center"> | |
| 9 | + <p>{{ $t('floorShare.deleteMessage') }}</p> | |
| 10 | + </div> | |
| 11 | + <div slot="footer" class="dialog-footer"> | |
| 12 | + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button> | |
| 13 | + <el-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('common.confirm') }}</el-button> | |
| 14 | + </div> | |
| 15 | + </el-dialog> | |
| 16 | +</template> | |
| 17 | + | |
| 18 | +<script> | |
| 19 | +import { deleteFloorShareMeter } from '@/api/fee/floorShareApi' | |
| 20 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 21 | + | |
| 22 | +export default { | |
| 23 | + name: 'DeleteFloorShare', | |
| 24 | + data() { | |
| 25 | + return { | |
| 26 | + dialogVisible: false, | |
| 27 | + loading: false, | |
| 28 | + form: { | |
| 29 | + fsmId: '', | |
| 30 | + communityId: '' | |
| 31 | + } | |
| 32 | + } | |
| 33 | + }, | |
| 34 | + methods: { | |
| 35 | + open(data) { | |
| 36 | + this.form = { | |
| 37 | + fsmId: data.fsmId, | |
| 38 | + communityId: getCommunityId() | |
| 39 | + } | |
| 40 | + this.dialogVisible = true | |
| 41 | + }, | |
| 42 | + async handleConfirm() { | |
| 43 | + this.loading = true | |
| 44 | + try { | |
| 45 | + await deleteFloorShareMeter(this.form) | |
| 46 | + this.$message.success(this.$t('floorShare.deleteSuccess')) | |
| 47 | + this.dialogVisible = false | |
| 48 | + this.$emit('success') | |
| 49 | + } catch (error) { | |
| 50 | + this.$message.error(error.message || this.$t('floorShare.deleteFailed')) | |
| 51 | + } finally { | |
| 52 | + this.loading = false | |
| 53 | + } | |
| 54 | + } | |
| 55 | + } | |
| 56 | +} | |
| 57 | +</script> | |
| 58 | + | |
| 59 | +<style lang="scss" scoped> | |
| 60 | +.text-center { | |
| 61 | + text-align: center; | |
| 62 | + font-size: 16px; | |
| 63 | + margin-bottom: 20px; | |
| 64 | +} | |
| 65 | + | |
| 66 | +.dialog-footer { | |
| 67 | + text-align: center; | |
| 68 | +} | |
| 69 | +</style> | |
| 0 | 70 | \ No newline at end of file | ... | ... |
src/components/fee/deleteShareReading.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('shareReading.delete.title')" | |
| 4 | + :visible.sync="dialogVisible" | |
| 5 | + width="30%" | |
| 6 | + @close="handleClose" | |
| 7 | + > | |
| 8 | + <div class="text-center"> | |
| 9 | + <p>{{ $t('shareReading.delete.confirm') }}</p> | |
| 10 | + </div> | |
| 11 | + <span slot="footer" class="dialog-footer"> | |
| 12 | + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button> | |
| 13 | + <el-button type="primary" @click="handleConfirm">{{ $t('common.confirm') }}</el-button> | |
| 14 | + </span> | |
| 15 | + </el-dialog> | |
| 16 | +</template> | |
| 17 | + | |
| 18 | +<script> | |
| 19 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 20 | +import { deleteFloorShareReading } from '@/api/fee/shareReadingApi' | |
| 21 | + | |
| 22 | +export default { | |
| 23 | + name: 'DeleteShareReading', | |
| 24 | + data() { | |
| 25 | + return { | |
| 26 | + dialogVisible: false, | |
| 27 | + readingId: '', | |
| 28 | + communityId: '' | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + methods: { | |
| 32 | + open(data) { | |
| 33 | + this.dialogVisible = true | |
| 34 | + this.readingId = data.readingId | |
| 35 | + this.communityId = getCommunityId() | |
| 36 | + }, | |
| 37 | + async handleConfirm() { | |
| 38 | + try { | |
| 39 | + await deleteFloorShareReading({ | |
| 40 | + readingId: this.readingId, | |
| 41 | + communityId: this.communityId | |
| 42 | + }) | |
| 43 | + this.$message.success(this.$t('shareReading.message.deleteSuccess')) | |
| 44 | + this.dialogVisible = false | |
| 45 | + this.$emit('success') | |
| 46 | + } catch (error) { | |
| 47 | + console.error('删除公摊抄表失败:', error) | |
| 48 | + } | |
| 49 | + }, | |
| 50 | + handleClose() { | |
| 51 | + this.readingId = '' | |
| 52 | + this.communityId = '' | |
| 53 | + } | |
| 54 | + } | |
| 55 | +} | |
| 56 | +</script> | |
| 0 | 57 | \ No newline at end of file | ... | ... |
src/components/fee/editFloorShare.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('floorShare.editTitle')" :visible.sync="dialogVisible" width="50%" @close="handleClose"> | |
| 3 | + <el-form ref="form" :model="form" :rules="rules" label-width="120px" label-position="right"> | |
| 4 | + <el-form-item :label="$t('floorShare.floor')" prop="floorNum"> | |
| 5 | + <el-input v-model="form.floorNum" disabled /> | |
| 6 | + </el-form-item> | |
| 7 | + | |
| 8 | + <el-form-item :label="$t('floorShare.meterType')" prop="meterType"> | |
| 9 | + <el-select v-model="form.meterType" style="width:100%"> | |
| 10 | + <el-option v-for="item in meterTypes" :key="item.value" :label="item.label" :value="item.value" /> | |
| 11 | + </el-select> | |
| 12 | + </el-form-item> | |
| 13 | + | |
| 14 | + <el-form-item :label="$t('floorShare.meterNum')"> | |
| 15 | + <el-input v-model="form.meterNum" :placeholder="$t('floorShare.meterNumPlaceholder')" /> | |
| 16 | + </el-form-item> | |
| 17 | + | |
| 18 | + <el-form-item :label="$t('floorShare.feeItem')" prop="configId"> | |
| 19 | + <el-select v-model="form.configId" style="width:100%"> | |
| 20 | + <el-option v-for="item in feeConfigs" :key="item.configId" :label="item.feeName" :value="item.configId" /> | |
| 21 | + </el-select> | |
| 22 | + </el-form-item> | |
| 23 | + | |
| 24 | + <el-form-item :label="$t('floorShare.feePrice')" prop="sharePrice"> | |
| 25 | + <el-input v-model.number="form.sharePrice" type="number" /> | |
| 26 | + </el-form-item> | |
| 27 | + | |
| 28 | + <el-form-item :label="$t('floorShare.shareType')" prop="shareType"> | |
| 29 | + <el-select v-model="form.shareType" style="width:100%" @change="handleShareTypeChange"> | |
| 30 | + <el-option v-for="item in shareTypes" :key="item.value" :label="item.label" :value="item.value" /> | |
| 31 | + </el-select> | |
| 32 | + </el-form-item> | |
| 33 | + | |
| 34 | + <el-form-item v-if="form.shareType === '3003'" :label="$t('floorShare.formula')" prop="formulaValue"> | |
| 35 | + <el-input v-model="form.formulaValue" /> | |
| 36 | + </el-form-item> | |
| 37 | + </el-form> | |
| 38 | + | |
| 39 | + <div slot="footer" class="dialog-footer"> | |
| 40 | + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button> | |
| 41 | + <el-button type="primary" @click="handleSubmit">{{ $t('common.save') }}</el-button> | |
| 42 | + </div> | |
| 43 | + </el-dialog> | |
| 44 | +</template> | |
| 45 | + | |
| 46 | +<script> | |
| 47 | +import { updateFloorShareMeter, listFeeConfigs } from '@/api/fee/floorShareApi' | |
| 48 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 49 | + | |
| 50 | +export default { | |
| 51 | + name: 'EditFloorShare', | |
| 52 | + data() { | |
| 53 | + return { | |
| 54 | + dialogVisible: false, | |
| 55 | + form: { | |
| 56 | + fsmId: '', | |
| 57 | + floorId: '', | |
| 58 | + floorNum: '', | |
| 59 | + meterType: '', | |
| 60 | + meterNum: '', | |
| 61 | + shareType: '', | |
| 62 | + formulaValue: '', | |
| 63 | + configId: '', | |
| 64 | + sharePrice: '', | |
| 65 | + communityId: '' | |
| 66 | + }, | |
| 67 | + feeConfigs: [], | |
| 68 | + meterTypes: [ | |
| 69 | + { value: 'D', label: this.$t('floorShare.electricMeter') }, | |
| 70 | + { value: 'S', label: this.$t('floorShare.waterMeter') } | |
| 71 | + ], | |
| 72 | + shareTypes: [ | |
| 73 | + { value: '1001', label: this.$t('floorShare.byArea') }, | |
| 74 | + { value: '2002', label: this.$t('floorShare.byHouse') }, | |
| 75 | + { value: '3003', label: this.$t('floorShare.byFormula') } | |
| 76 | + ], | |
| 77 | + rules: { | |
| 78 | + meterType: [ | |
| 79 | + { required: true, message: this.$t('floorShare.meterTypeRequired'), trigger: 'blur' } | |
| 80 | + ], | |
| 81 | + configId: [ | |
| 82 | + { required: true, message: this.$t('floorShare.feeItemRequired'), trigger: 'blur' } | |
| 83 | + ], | |
| 84 | + sharePrice: [ | |
| 85 | + { required: true, message: this.$t('floorShare.feePriceRequired'), trigger: 'blur' }, | |
| 86 | + ], | |
| 87 | + shareType: [ | |
| 88 | + { required: true, message: this.$t('floorShare.shareTypeRequired'), trigger: 'blur' } | |
| 89 | + ], | |
| 90 | + formulaValue: [ | |
| 91 | + { required: true, message: this.$t('floorShare.formulaRequired'), trigger: 'blur' } | |
| 92 | + ], | |
| 93 | + fsmId: [ | |
| 94 | + { required: true, message: this.$t('floorShare.idRequired'), trigger: 'blur' } | |
| 95 | + ] | |
| 96 | + } | |
| 97 | + } | |
| 98 | + }, | |
| 99 | + methods: { | |
| 100 | + open(data) { | |
| 101 | + this.form = { | |
| 102 | + ...this.form, | |
| 103 | + ...data, | |
| 104 | + communityId: getCommunityId() | |
| 105 | + } | |
| 106 | + this.loadFeeConfigs() | |
| 107 | + this.dialogVisible = true | |
| 108 | + this.$nextTick(() => { | |
| 109 | + this.$refs.form && this.$refs.form.clearValidate() | |
| 110 | + }) | |
| 111 | + }, | |
| 112 | + async loadFeeConfigs() { | |
| 113 | + try { | |
| 114 | + const params = { | |
| 115 | + page: 1, | |
| 116 | + row: 500, | |
| 117 | + communityId: this.form.communityId, | |
| 118 | + feeTypeCd: '888800010017', | |
| 119 | + isDefault: 'F', | |
| 120 | + state: 'Y' | |
| 121 | + } | |
| 122 | + const { feeConfigs } = await listFeeConfigs(params) | |
| 123 | + this.feeConfigs = feeConfigs | |
| 124 | + } catch (error) { | |
| 125 | + this.$message.error(this.$t('floorShare.fetchFeeConfigError')) | |
| 126 | + } | |
| 127 | + }, | |
| 128 | + handleShareTypeChange(value) { | |
| 129 | + if (value !== '3003') { | |
| 130 | + this.form.formulaValue = '' | |
| 131 | + } | |
| 132 | + }, | |
| 133 | + handleSubmit() { | |
| 134 | + this.$refs.form.validate(async valid => { | |
| 135 | + if (valid) { | |
| 136 | + try { | |
| 137 | + await updateFloorShareMeter(this.form) | |
| 138 | + this.$message.success(this.$t('floorShare.editSuccess')) | |
| 139 | + this.dialogVisible = false | |
| 140 | + this.$emit('success') | |
| 141 | + } catch (error) { | |
| 142 | + this.$message.error(error.message || this.$t('floorShare.editFailed')) | |
| 143 | + } | |
| 144 | + } | |
| 145 | + }) | |
| 146 | + }, | |
| 147 | + handleClose() { | |
| 148 | + this.$refs.form.resetFields() | |
| 149 | + } | |
| 150 | + } | |
| 151 | +} | |
| 152 | +</script> | |
| 153 | + | |
| 154 | +<style lang="scss" scoped> | |
| 155 | +.dialog-footer { | |
| 156 | + text-align: right; | |
| 157 | +} | |
| 158 | +</style> | |
| 0 | 159 | \ No newline at end of file | ... | ... |
src/components/fee/importRoomFee.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('importRoomFee.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="handleClose" | |
| 7 | + > | |
| 8 | + <el-form | |
| 9 | + ref="form" | |
| 10 | + :model="form" | |
| 11 | + label-width="120px" | |
| 12 | + label-position="right" | |
| 13 | + > | |
| 14 | + <el-form-item | |
| 15 | + :label="$t('importRoomFee.form.feeTypeCd')" | |
| 16 | + prop="feeTypeCd" | |
| 17 | + :rules="[ | |
| 18 | + { required: true, message: $t('importRoomFee.rules.feeTypeCdRequired'), trigger: 'change' } | |
| 19 | + ]" | |
| 20 | + > | |
| 21 | + <el-select | |
| 22 | + v-model="form.feeTypeCd" | |
| 23 | + :placeholder="$t('importRoomFee.placeholder.feeTypeCd')" | |
| 24 | + style="width:100%" | |
| 25 | + @change="handleFeeTypeChange" | |
| 26 | + > | |
| 27 | + <el-option | |
| 28 | + v-for="item in feeTypeCds" | |
| 29 | + :key="item.statusCd" | |
| 30 | + :label="item.name" | |
| 31 | + :value="item.statusCd" | |
| 32 | + /> | |
| 33 | + </el-select> | |
| 34 | + </el-form-item> | |
| 35 | + | |
| 36 | + <el-form-item | |
| 37 | + :label="$t('importRoomFee.form.objType')" | |
| 38 | + prop="objType" | |
| 39 | + :rules="[ | |
| 40 | + { required: true, message: $t('importRoomFee.rules.objTypeRequired'), trigger: 'change' } | |
| 41 | + ]" | |
| 42 | + > | |
| 43 | + <el-select | |
| 44 | + v-model="form.objType" | |
| 45 | + :placeholder="$t('importRoomFee.placeholder.objType')" | |
| 46 | + style="width:100%" | |
| 47 | + > | |
| 48 | + <el-option | |
| 49 | + :label="$t('importRoomFee.options.room')" | |
| 50 | + value="3333" | |
| 51 | + /> | |
| 52 | + <el-option | |
| 53 | + :label="$t('importRoomFee.options.parking')" | |
| 54 | + value="6666" | |
| 55 | + /> | |
| 56 | + </el-select> | |
| 57 | + </el-form-item> | |
| 58 | + | |
| 59 | + <el-form-item | |
| 60 | + :label="$t('importRoomFee.form.file')" | |
| 61 | + prop="file" | |
| 62 | + :rules="[ | |
| 63 | + { required: true, message: $t('importRoomFee.rules.fileRequired'), trigger: 'change' } | |
| 64 | + ]" | |
| 65 | + > | |
| 66 | + <el-upload | |
| 67 | + ref="upload" | |
| 68 | + :auto-upload="false" | |
| 69 | + :limit="1" | |
| 70 | + :on-change="handleFileChange" | |
| 71 | + :on-remove="handleFileRemove" | |
| 72 | + accept=".xls,.xlsx" | |
| 73 | + > | |
| 74 | + <el-button size="small" type="primary"> | |
| 75 | + {{ $t('importRoomFee.button.selectFile') }} | |
| 76 | + </el-button> | |
| 77 | + <div slot="tip" class="el-upload__tip"> | |
| 78 | + {{ $t('importRoomFee.tips.fileFormat') }} | |
| 79 | + </div> | |
| 80 | + </el-upload> | |
| 81 | + </el-form-item> | |
| 82 | + | |
| 83 | + <el-form-item :label="$t('importRoomFee.form.template')"> | |
| 84 | + <span> | |
| 85 | + {{ $t('importRoomFee.tips.downloadTemplate1') }} | |
| 86 | + <el-link type="primary" @click="handleDownloadTemplate"> | |
| 87 | + {{ $t('importRoomFee.tips.downloadTemplate2') }} | |
| 88 | + </el-link> | |
| 89 | + {{ $t('importRoomFee.tips.downloadTemplate3') }} | |
| 90 | + </span> | |
| 91 | + </el-form-item> | |
| 92 | + </el-form> | |
| 93 | + | |
| 94 | + <div slot="footer" class="dialog-footer"> | |
| 95 | + <el-button @click="visible = false"> | |
| 96 | + {{ $t('common.cancel') }} | |
| 97 | + </el-button> | |
| 98 | + <el-button | |
| 99 | + type="primary" | |
| 100 | + :loading="loading" | |
| 101 | + @click="handleSubmit" | |
| 102 | + > | |
| 103 | + {{ $t('common.confirm') }} | |
| 104 | + </el-button> | |
| 105 | + </div> | |
| 106 | + </el-dialog> | |
| 107 | +</template> | |
| 108 | + | |
| 109 | +<script> | |
| 110 | +import { importRoomFeeData, downloadImportTemplate } from '@/api/fee/roomFeeImportApi' | |
| 111 | +import { getDict } from '@/api/community/communityApi' | |
| 112 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 113 | + | |
| 114 | +export default { | |
| 115 | + name: 'ImportRoomFee', | |
| 116 | + data() { | |
| 117 | + return { | |
| 118 | + visible: false, | |
| 119 | + loading: false, | |
| 120 | + form: { | |
| 121 | + feeTypeCd: '', | |
| 122 | + objType: '3333', | |
| 123 | + file: null | |
| 124 | + }, | |
| 125 | + feeTypeCds: [] | |
| 126 | + } | |
| 127 | + }, | |
| 128 | + methods: { | |
| 129 | + open() { | |
| 130 | + this.visible = true | |
| 131 | + this.getDictData() | |
| 132 | + }, | |
| 133 | + async getDictData() { | |
| 134 | + try { | |
| 135 | + const data = await getDict('pay_fee_config', 'fee_type_cd') | |
| 136 | + this.feeTypeCds = data | |
| 137 | + } catch (error) { | |
| 138 | + console.error('获取字典数据失败:', error) | |
| 139 | + } | |
| 140 | + }, | |
| 141 | + handleFeeTypeChange(value) { | |
| 142 | + this.form.feeTypeCd = value | |
| 143 | + }, | |
| 144 | + handleFileChange(file) { | |
| 145 | + this.form.file = file.raw | |
| 146 | + }, | |
| 147 | + handleFileRemove() { | |
| 148 | + this.form.file = null | |
| 149 | + }, | |
| 150 | + async handleSubmit() { | |
| 151 | + try { | |
| 152 | + this.$refs.form.validate(async valid => { | |
| 153 | + if (!valid) return | |
| 154 | + if (!this.form.file) { | |
| 155 | + this.$message.warning(this.$t('importRoomFee.rules.fileRequired')) | |
| 156 | + return | |
| 157 | + } | |
| 158 | + | |
| 159 | + this.loading = true | |
| 160 | + const formData = new FormData() | |
| 161 | + formData.append('uploadFile', this.form.file) | |
| 162 | + formData.append('communityId', getCommunityId()) | |
| 163 | + formData.append('feeTypeCd', this.form.feeTypeCd) | |
| 164 | + formData.append('objType', this.form.objType) | |
| 165 | + formData.append('importAdapt', 'importRoomFee') | |
| 166 | + | |
| 167 | + await importRoomFeeData(formData) | |
| 168 | + this.$message.success(this.$t('importRoomFee.message.importSuccess')) | |
| 169 | + this.$emit('success') | |
| 170 | + this.visible = false | |
| 171 | + }) | |
| 172 | + } catch (error) { | |
| 173 | + console.error('导入失败:', error) | |
| 174 | + this.$message.error(error.message || this.$t('importRoomFee.message.importFailed')) | |
| 175 | + } finally { | |
| 176 | + this.loading = false | |
| 177 | + } | |
| 178 | + }, | |
| 179 | + async handleDownloadTemplate() { | |
| 180 | + try { | |
| 181 | + const params = { | |
| 182 | + communityId: getCommunityId(), | |
| 183 | + objType: this.form.objType, | |
| 184 | + pagePath: 'exportFeeImportTemplate' | |
| 185 | + } | |
| 186 | + await downloadImportTemplate(params) | |
| 187 | + this.$message.success(this.$t('importRoomFee.message.downloadSuccess')) | |
| 188 | + } catch (error) { | |
| 189 | + console.error('下载模板失败:', error) | |
| 190 | + this.$message.error(this.$t('importRoomFee.message.downloadFailed')) | |
| 191 | + } | |
| 192 | + }, | |
| 193 | + handleClose() { | |
| 194 | + this.$refs.form.resetFields() | |
| 195 | + this.$refs.upload.clearFiles() | |
| 196 | + this.form.file = null | |
| 197 | + } | |
| 198 | + } | |
| 199 | +} | |
| 200 | +</script> | |
| 201 | + | |
| 202 | +<style scoped> | |
| 203 | +.el-upload__tip { | |
| 204 | + margin-top: 7px; | |
| 205 | + color: #606266; | |
| 206 | + font-size: 12px; | |
| 207 | +} | |
| 208 | +</style> | |
| 0 | 209 | \ No newline at end of file | ... | ... |
src/i18n/commonLang.js
| ... | ... | @@ -52,6 +52,7 @@ export const messages = { |
| 52 | 52 | year:'Year', |
| 53 | 53 | month:'Month', |
| 54 | 54 | examine:'Examine', |
| 55 | + audit:'Audit', | |
| 55 | 56 | } |
| 56 | 57 | }, |
| 57 | 58 | zh: { |
| ... | ... | @@ -107,6 +108,7 @@ export const messages = { |
| 107 | 108 | year:'年', |
| 108 | 109 | month:'月', |
| 109 | 110 | examine:'审核', |
| 111 | + audit:'审核', | |
| 110 | 112 | } |
| 111 | 113 | } |
| 112 | 114 | } |
| 113 | 115 | \ No newline at end of file | ... | ... |
src/i18n/feeI18n.js
| ... | ... | @@ -10,6 +10,10 @@ import { messages as feeReceiptMessages } from '../views/fee/feeReceiptLang' |
| 10 | 10 | import { messages as printPayFeeMessages } from '../views/fee/printPayFeeLang' |
| 11 | 11 | import { messages as printPayFeeBangTaiMessages } from '../views/fee/printPayFeeBangTaiLang' |
| 12 | 12 | import { messages as printSmallPayFeeMessages } from '../views/fee/printSmallPayFeeLang' |
| 13 | +import { messages as floorShareMessages } from '../views/fee/floorShareLang' | |
| 14 | +import { messages as shareReadingMessages } from '../views/fee/shareReadingLang' | |
| 15 | +import { messages as roomFeeImportMessages } from '../views/fee/roomFeeImportLang' | |
| 16 | +import { messages as shareReadingFeeMessages } from '../views/fee/shareReadingFeeLang' | |
| 13 | 17 | |
| 14 | 18 | export const messages = { |
| 15 | 19 | en: { |
| ... | ... | @@ -25,6 +29,10 @@ export const messages = { |
| 25 | 29 | ...printPayFeeMessages.en, |
| 26 | 30 | ...printPayFeeBangTaiMessages.en, |
| 27 | 31 | ...printSmallPayFeeMessages.en, |
| 32 | + ...floorShareMessages.en, | |
| 33 | + ...shareReadingMessages.en, | |
| 34 | + ...roomFeeImportMessages.en, | |
| 35 | + ...shareReadingFeeMessages.en, | |
| 28 | 36 | }, |
| 29 | 37 | zh: { |
| 30 | 38 | ...contractCreateFeeMessages.zh, |
| ... | ... | @@ -39,5 +47,9 @@ export const messages = { |
| 39 | 47 | ...printPayFeeMessages.zh, |
| 40 | 48 | ...printPayFeeBangTaiMessages.zh, |
| 41 | 49 | ...printSmallPayFeeMessages.zh, |
| 50 | + ...floorShareMessages.zh, | |
| 51 | + ...shareReadingMessages.zh, | |
| 52 | + ...roomFeeImportMessages.zh, | |
| 53 | + ...shareReadingFeeMessages.zh, | |
| 42 | 54 | } |
| 43 | 55 | } |
| 44 | 56 | \ No newline at end of file | ... | ... |
src/router/feeRouter.js
| ... | ... | @@ -44,5 +44,25 @@ export default [ |
| 44 | 44 | name: '/pages/property/feeReceipt', |
| 45 | 45 | component: () => import('@/views/fee/feeReceiptList.vue') |
| 46 | 46 | }, |
| 47 | + { | |
| 48 | + path: '/pages/fee/floorShare', | |
| 49 | + name: '/pages/fee/floorShare', | |
| 50 | + component: () => import('@/views/fee/floorShareList.vue') | |
| 51 | + }, | |
| 52 | + { | |
| 53 | + path: '/pages/fee/shareReading', | |
| 54 | + name: '/pages/fee/shareReading', | |
| 55 | + component: () => import('@/views/fee/shareReadingList.vue') | |
| 56 | + }, | |
| 57 | + { | |
| 58 | + path:'/pages/property/roomFeeImport', | |
| 59 | + name:'/pages/property/roomFeeImport', | |
| 60 | + component: () => import('@/views/fee/roomFeeImportList.vue') | |
| 61 | + }, | |
| 62 | + { | |
| 63 | + path:'/views/fee/shareReadingFee', | |
| 64 | + name:'/views/fee/shareReadingFee', | |
| 65 | + component: () => import('@/views/fee/shareReadingFeeList.vue') | |
| 66 | + }, | |
| 47 | 67 | |
| 48 | 68 | ] |
| 49 | 69 | \ No newline at end of file | ... | ... |
src/views/fee/floorShareLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + floorShare: { | |
| 4 | + title: 'Floor Share', | |
| 5 | + id: 'ID', | |
| 6 | + floor: 'Floor', | |
| 7 | + meterType: 'Meter Type', | |
| 8 | + meterNum: 'Meter Number', | |
| 9 | + shareType: 'Share Type', | |
| 10 | + formula: 'Formula', | |
| 11 | + feeItem: 'Fee Item', | |
| 12 | + feePrice: 'Fee Price', | |
| 13 | + degree: 'Degree', | |
| 14 | + readingTime: 'Reading Time', | |
| 15 | + createTime: 'Create Time', | |
| 16 | + addTitle: 'Add Floor Share', | |
| 17 | + editTitle: 'Edit Floor Share', | |
| 18 | + deleteConfirm: 'Confirm Operation', | |
| 19 | + deleteMessage: 'Are you sure to delete this floor share?', | |
| 20 | + fetchError: 'Failed to fetch floor share data', | |
| 21 | + fetchFloorError: 'Failed to fetch floor data', | |
| 22 | + fetchFeeConfigError: 'Failed to fetch fee config data', | |
| 23 | + addSuccess: 'Floor share added successfully', | |
| 24 | + addFailed: 'Failed to add floor share', | |
| 25 | + editSuccess: 'Floor share updated successfully', | |
| 26 | + editFailed: 'Failed to update floor share', | |
| 27 | + deleteSuccess: 'Floor share deleted successfully', | |
| 28 | + deleteFailed: 'Failed to delete floor share', | |
| 29 | + meterTypeRequired: 'Please select meter type', | |
| 30 | + feeItemRequired: 'Please select fee item', | |
| 31 | + feePriceRequired: 'Please enter fee price', | |
| 32 | + feePriceNumber: 'Fee price must be a number', | |
| 33 | + shareTypeRequired: 'Please select share type', | |
| 34 | + formulaRequired: 'Please enter formula', | |
| 35 | + idRequired: 'ID is required', | |
| 36 | + meterNumPlaceholder: 'Optional, please enter meter number', | |
| 37 | + meterNumTip: 'Enter 1 if no meter number', | |
| 38 | + electricMeter: 'Electric Meter', | |
| 39 | + waterMeter: 'Water Meter', | |
| 40 | + byArea: 'By Area', | |
| 41 | + byHouse: 'By House', | |
| 42 | + byFormula: 'By Formula' | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + zh: { | |
| 46 | + floorShare: { | |
| 47 | + title: '楼栋公摊', | |
| 48 | + id: '编号', | |
| 49 | + floor: '楼栋', | |
| 50 | + meterType: '表类型', | |
| 51 | + meterNum: '表编号', | |
| 52 | + shareType: '公摊方式', | |
| 53 | + formula: '公式', | |
| 54 | + feeItem: '费用项', | |
| 55 | + feePrice: '费用单价', | |
| 56 | + degree: '度数', | |
| 57 | + readingTime: '抄表时间', | |
| 58 | + createTime: '创建时间', | |
| 59 | + addTitle: '添加楼栋公摊', | |
| 60 | + editTitle: '修改楼栋公摊', | |
| 61 | + deleteConfirm: '请确认您的操作', | |
| 62 | + deleteMessage: '确定删除楼栋公摊吗?', | |
| 63 | + fetchError: '获取楼栋公摊数据失败', | |
| 64 | + fetchFloorError: '获取楼栋数据失败', | |
| 65 | + fetchFeeConfigError: '获取费用项数据失败', | |
| 66 | + addSuccess: '楼栋公摊添加成功', | |
| 67 | + addFailed: '楼栋公摊添加失败', | |
| 68 | + editSuccess: '楼栋公摊修改成功', | |
| 69 | + editFailed: '楼栋公摊修改失败', | |
| 70 | + deleteSuccess: '楼栋公摊删除成功', | |
| 71 | + deleteFailed: '楼栋公摊删除失败', | |
| 72 | + meterTypeRequired: '请选择表类型', | |
| 73 | + feeItemRequired: '请选择费用项', | |
| 74 | + feePriceRequired: '请输入费用单价', | |
| 75 | + feePriceNumber: '费用单价必须为数字', | |
| 76 | + shareTypeRequired: '请选择公摊方式', | |
| 77 | + formulaRequired: '请输入公式', | |
| 78 | + idRequired: '编号不能为空', | |
| 79 | + meterNumPlaceholder: '选填,请填写表编号', | |
| 80 | + meterNumTip: '没有表号请填写1', | |
| 81 | + electricMeter: '电表', | |
| 82 | + waterMeter: '水表', | |
| 83 | + byArea: '按面积', | |
| 84 | + byHouse: '按户', | |
| 85 | + byFormula: '按公式' | |
| 86 | + } | |
| 87 | + } | |
| 88 | +} | |
| 0 | 89 | \ No newline at end of file | ... | ... |
src/views/fee/floorShareList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="floor-share-container"> | |
| 3 | + <el-row :gutter="20"> | |
| 4 | + <el-col :span="4"> | |
| 5 | + <select-community-floor ref="selectCommunityFloor" @floor-change="handleFloorChange" /> | |
| 6 | + </el-col> | |
| 7 | + <el-col :span="20"> | |
| 8 | + <el-card class="box-card"> | |
| 9 | + <div slot="header" class="clearfix"> | |
| 10 | + <span>{{ $t('floorShare.title') }}</span> | |
| 11 | + <el-button v-if="floorShareInfo.conditions.floorId" type="primary" size="small" style="float: right;" | |
| 12 | + @click="openAddFloorShareModal"> | |
| 13 | + {{ $t('common.add') }} | |
| 14 | + </el-button> | |
| 15 | + </div> | |
| 16 | + | |
| 17 | + <el-table :data="floorShareInfo.floorShares" border style="width: 100%" v-loading="loading"> | |
| 18 | + <el-table-column prop="fsmId" :label="$t('floorShare.id')" align="center" /> | |
| 19 | + <el-table-column prop="floorNum" :label="$t('floorShare.floor')" align="center" /> | |
| 20 | + <el-table-column prop="meterTypeName" :label="$t('floorShare.meterType')" align="center" /> | |
| 21 | + <el-table-column prop="meterNum" :label="$t('floorShare.meterNum')" align="center" /> | |
| 22 | + <el-table-column prop="shareTypeName" :label="$t('floorShare.shareType')" align="center" /> | |
| 23 | + <el-table-column prop="formulaValue" :label="$t('floorShare.formula')" align="center"> | |
| 24 | + <template slot-scope="scope"> | |
| 25 | + {{ scope.row.formulaValue || '-' }} | |
| 26 | + </template> | |
| 27 | + </el-table-column> | |
| 28 | + <el-table-column prop="configName" :label="$t('floorShare.feeItem')" align="center" /> | |
| 29 | + <el-table-column prop="sharePrice" :label="$t('floorShare.feePrice')" align="center" /> | |
| 30 | + <el-table-column prop="curDegree" :label="$t('floorShare.degree')" align="center" /> | |
| 31 | + <el-table-column prop="curReadingTime" :label="$t('floorShare.readingTime')" align="center" /> | |
| 32 | + <el-table-column prop="createTime" :label="$t('floorShare.createTime')" align="center" /> | |
| 33 | + <el-table-column :label="$t('common.operation')" align="center" width="180"> | |
| 34 | + <template slot-scope="scope"> | |
| 35 | + <el-button size="mini" type="primary" @click="openEditFloorShareModal(scope.row)"> | |
| 36 | + {{ $t('common.edit') }} | |
| 37 | + </el-button> | |
| 38 | + <el-button size="mini" type="danger" @click="openDeleteFloorShareModal(scope.row)"> | |
| 39 | + {{ $t('common.delete') }} | |
| 40 | + </el-button> | |
| 41 | + </template> | |
| 42 | + </el-table-column> | |
| 43 | + </el-table> | |
| 44 | + | |
| 45 | + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size" | |
| 46 | + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" | |
| 47 | + @current-change="handleCurrentChange" /> | |
| 48 | + </el-card> | |
| 49 | + </el-col> | |
| 50 | + </el-row> | |
| 51 | + | |
| 52 | + <add-floor-share ref="addFloorShare" @success="handleSuccess" /> | |
| 53 | + <edit-floor-share ref="editFloorShare" @success="handleSuccess" /> | |
| 54 | + <delete-floor-share ref="deleteFloorShare" @success="handleSuccess" /> | |
| 55 | + </div> | |
| 56 | +</template> | |
| 57 | + | |
| 58 | +<script> | |
| 59 | +import { listFloorShareMeter } from '@/api/fee/floorShareApi' | |
| 60 | +import SelectCommunityFloor from '@/components/report/selectCommunityFloor' | |
| 61 | +import AddFloorShare from '@/components/fee/addFloorShare' | |
| 62 | +import EditFloorShare from '@/components/fee/editFloorShare' | |
| 63 | +import DeleteFloorShare from '@/components/fee/deleteFloorShare' | |
| 64 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 65 | + | |
| 66 | +export default { | |
| 67 | + name: 'FloorShareList', | |
| 68 | + components: { | |
| 69 | + SelectCommunityFloor, | |
| 70 | + AddFloorShare, | |
| 71 | + EditFloorShare, | |
| 72 | + DeleteFloorShare | |
| 73 | + }, | |
| 74 | + data() { | |
| 75 | + return { | |
| 76 | + loading: false, | |
| 77 | + floorShareInfo: { | |
| 78 | + floorShares: [], | |
| 79 | + conditions: { | |
| 80 | + floorId: '', | |
| 81 | + communityId: '' | |
| 82 | + } | |
| 83 | + }, | |
| 84 | + page: { | |
| 85 | + current: 1, | |
| 86 | + size: 10, | |
| 87 | + total: 0 | |
| 88 | + } | |
| 89 | + } | |
| 90 | + }, | |
| 91 | + created() { | |
| 92 | + this.floorShareInfo.conditions.communityId = getCommunityId() | |
| 93 | + setTimeout(() => { | |
| 94 | + this.$refs.selectCommunityFloor.open({ | |
| 95 | + callBack: this.handleFloorChange | |
| 96 | + }) | |
| 97 | + }, 1000) | |
| 98 | + }, | |
| 99 | + methods: { | |
| 100 | + async listFloorShares() { | |
| 101 | + try { | |
| 102 | + this.loading = true | |
| 103 | + const params = { | |
| 104 | + page: this.page.current, | |
| 105 | + row: this.page.size, | |
| 106 | + floorId: this.floorShareInfo.conditions.floorId, | |
| 107 | + communityId: this.floorShareInfo.conditions.communityId | |
| 108 | + } | |
| 109 | + const { data, total } = await listFloorShareMeter(params) | |
| 110 | + this.floorShareInfo.floorShares = data | |
| 111 | + this.page.total = total | |
| 112 | + } catch (error) { | |
| 113 | + this.$message.error(this.$t('floorShare.fetchError')) | |
| 114 | + } finally { | |
| 115 | + this.loading = false | |
| 116 | + } | |
| 117 | + }, | |
| 118 | + handleFloorChange(floor) { | |
| 119 | + this.floorShareInfo.conditions.floorId = floor.floorId | |
| 120 | + this.floorShareInfo.conditions.floorNum = floor.floorNum | |
| 121 | + this.page.current = 1 | |
| 122 | + this.listFloorShares() | |
| 123 | + }, | |
| 124 | + openAddFloorShareModal() { | |
| 125 | + this.$refs.addFloorShare.open({ | |
| 126 | + floorId: this.floorShareInfo.conditions.floorId, | |
| 127 | + floorNum: this.floorShareInfo.conditions.floorNum | |
| 128 | + }) | |
| 129 | + }, | |
| 130 | + openEditFloorShareModal(row) { | |
| 131 | + this.$refs.editFloorShare.open(row) | |
| 132 | + }, | |
| 133 | + openDeleteFloorShareModal(row) { | |
| 134 | + this.$refs.deleteFloorShare.open(row) | |
| 135 | + }, | |
| 136 | + handleSuccess() { | |
| 137 | + this.listFloorShares() | |
| 138 | + }, | |
| 139 | + handleSizeChange(val) { | |
| 140 | + this.page.size = val | |
| 141 | + this.listFloorShares() | |
| 142 | + }, | |
| 143 | + handleCurrentChange(val) { | |
| 144 | + this.page.current = val | |
| 145 | + this.listFloorShares() | |
| 146 | + } | |
| 147 | + } | |
| 148 | +} | |
| 149 | +</script> | |
| 150 | + | |
| 151 | +<style lang="scss" scoped> | |
| 152 | +.floor-share-container { | |
| 153 | + padding: 20px; | |
| 154 | + | |
| 155 | + .box-card { | |
| 156 | + margin-bottom: 20px; | |
| 157 | + } | |
| 158 | + | |
| 159 | + .el-pagination { | |
| 160 | + margin-top: 20px; | |
| 161 | + text-align: right; | |
| 162 | + } | |
| 163 | +} | |
| 164 | +</style> | |
| 0 | 165 | \ No newline at end of file | ... | ... |
src/views/fee/roomFeeImportLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + roomFeeImport: { | |
| 4 | + search: { | |
| 5 | + title: 'Search Conditions', | |
| 6 | + importFeeId: 'Please enter import ID', | |
| 7 | + feeTypeCd: 'Please select fee type' | |
| 8 | + }, | |
| 9 | + table: { | |
| 10 | + title: 'Fee Import', | |
| 11 | + importFeeId: 'Import ID', | |
| 12 | + feeTypeCd: 'Fee Type', | |
| 13 | + createTime: 'Create Time', | |
| 14 | + remark: 'Remark' | |
| 15 | + }, | |
| 16 | + button: { | |
| 17 | + import: 'Import Fee' | |
| 18 | + }, | |
| 19 | + fetchError: 'Failed to fetch fee import data' | |
| 20 | + }, | |
| 21 | + importRoomFee: { | |
| 22 | + title: 'Fee Import', | |
| 23 | + form: { | |
| 24 | + feeTypeCd: 'Fee Type', | |
| 25 | + objType: 'Fee Object', | |
| 26 | + file: 'Select File', | |
| 27 | + template: 'Download Template' | |
| 28 | + }, | |
| 29 | + placeholder: { | |
| 30 | + feeTypeCd: 'Required, please select fee type', | |
| 31 | + objType: 'Required, please select fee object' | |
| 32 | + }, | |
| 33 | + options: { | |
| 34 | + room: 'Room', | |
| 35 | + parking: 'Parking' | |
| 36 | + }, | |
| 37 | + rules: { | |
| 38 | + feeTypeCdRequired: 'Fee type is required', | |
| 39 | + objTypeRequired: 'Fee object is required', | |
| 40 | + fileRequired: 'File is required' | |
| 41 | + }, | |
| 42 | + tips: { | |
| 43 | + fileFormat: 'Only .xls, .xlsx files can be uploaded', | |
| 44 | + downloadTemplate1: 'Please download', | |
| 45 | + downloadTemplate2: 'import template', | |
| 46 | + downloadTemplate3: 'to prepare data before uploading' | |
| 47 | + }, | |
| 48 | + button: { | |
| 49 | + selectFile: 'Select File' | |
| 50 | + }, | |
| 51 | + message: { | |
| 52 | + importSuccess: 'Import successfully', | |
| 53 | + importFailed: 'Import failed', | |
| 54 | + downloadSuccess: 'Download template successfully', | |
| 55 | + downloadFailed: 'Download template failed' | |
| 56 | + } | |
| 57 | + } | |
| 58 | + }, | |
| 59 | + zh: { | |
| 60 | + roomFeeImport: { | |
| 61 | + search: { | |
| 62 | + title: '查询条件', | |
| 63 | + importFeeId: '请输入导入ID', | |
| 64 | + feeTypeCd: '请选择费用类型' | |
| 65 | + }, | |
| 66 | + table: { | |
| 67 | + title: '费用导入', | |
| 68 | + importFeeId: '导入ID', | |
| 69 | + feeTypeCd: '费用类型', | |
| 70 | + createTime: '创建时间', | |
| 71 | + remark: '备注' | |
| 72 | + }, | |
| 73 | + button: { | |
| 74 | + import: '费用导入' | |
| 75 | + }, | |
| 76 | + fetchError: '获取费用导入数据失败' | |
| 77 | + }, | |
| 78 | + importRoomFee: { | |
| 79 | + title: '费用导入', | |
| 80 | + form: { | |
| 81 | + feeTypeCd: '费用类型', | |
| 82 | + objType: '费用对象', | |
| 83 | + file: '选择文件', | |
| 84 | + template: '下载模板' | |
| 85 | + }, | |
| 86 | + placeholder: { | |
| 87 | + feeTypeCd: '必填,请选择费用类型', | |
| 88 | + objType: '必填,请选择费用对象' | |
| 89 | + }, | |
| 90 | + options: { | |
| 91 | + room: '房屋', | |
| 92 | + parking: '车位车辆' | |
| 93 | + }, | |
| 94 | + rules: { | |
| 95 | + feeTypeCdRequired: '费用类型不能为空', | |
| 96 | + objTypeRequired: '费用对象不能为空', | |
| 97 | + fileRequired: '文件不能为空' | |
| 98 | + }, | |
| 99 | + tips: { | |
| 100 | + fileFormat: '只能上传.xls, .xlsx格式文件', | |
| 101 | + downloadTemplate1: '请先下载', | |
| 102 | + downloadTemplate2: '导入模板', | |
| 103 | + downloadTemplate3: '准备数据后上传导入' | |
| 104 | + }, | |
| 105 | + button: { | |
| 106 | + selectFile: '选择文件' | |
| 107 | + }, | |
| 108 | + message: { | |
| 109 | + importSuccess: '导入成功', | |
| 110 | + importFailed: '导入失败', | |
| 111 | + downloadSuccess: '下载模板成功', | |
| 112 | + downloadFailed: '下载模板失败' | |
| 113 | + } | |
| 114 | + } | |
| 115 | + } | |
| 116 | +} | |
| 0 | 117 | \ No newline at end of file | ... | ... |
src/views/fee/roomFeeImportList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="room-fee-import-container animated fadeInRight"> | |
| 3 | + <!-- 查询条件 --> | |
| 4 | + <el-card class="search-card"> | |
| 5 | + <div slot="header" class="flex justify-between"> | |
| 6 | + <span>{{ $t('roomFeeImport.search.title') }}</span> | |
| 7 | + </div> | |
| 8 | + <el-row :gutter="20"> | |
| 9 | + <el-col :span="6"> | |
| 10 | + <el-input | |
| 11 | + v-model="searchForm.importFeeId" | |
| 12 | + :placeholder="$t('roomFeeImport.search.importFeeId')" | |
| 13 | + clearable | |
| 14 | + /> | |
| 15 | + </el-col> | |
| 16 | + <el-col :span="6"> | |
| 17 | + <el-select | |
| 18 | + v-model="searchForm.feeTypeCd" | |
| 19 | + :placeholder="$t('roomFeeImport.search.feeTypeCd')" | |
| 20 | + style="width:100%" | |
| 21 | + > | |
| 22 | + <el-option | |
| 23 | + v-for="item in filteredFeeTypeCds" | |
| 24 | + :key="item.statusCd" | |
| 25 | + :label="item.name" | |
| 26 | + :value="item.statusCd" | |
| 27 | + /> | |
| 28 | + </el-select> | |
| 29 | + </el-col> | |
| 30 | + <el-col :span="6"> | |
| 31 | + <el-button type="primary" @click="handleSearch"> | |
| 32 | + {{ $t('common.search') }} | |
| 33 | + </el-button> | |
| 34 | + </el-col> | |
| 35 | + </el-row> | |
| 36 | + </el-card> | |
| 37 | + | |
| 38 | + <!-- 费用导入列表 --> | |
| 39 | + <el-card class="table-card"> | |
| 40 | + <div slot="header" class="flex justify-between"> | |
| 41 | + <span>{{ $t('roomFeeImport.table.title') }}</span> | |
| 42 | + <el-button | |
| 43 | + type="primary" | |
| 44 | + style="float: right;" | |
| 45 | + @click="handleImport" | |
| 46 | + > | |
| 47 | + {{ $t('roomFeeImport.button.import') }} | |
| 48 | + </el-button> | |
| 49 | + </div> | |
| 50 | + | |
| 51 | + <el-table | |
| 52 | + :data="tableData" | |
| 53 | + border | |
| 54 | + style="width: 100%" | |
| 55 | + v-loading="loading" | |
| 56 | + > | |
| 57 | + <el-table-column | |
| 58 | + prop="importFeeId" | |
| 59 | + :label="$t('roomFeeImport.table.importFeeId')" | |
| 60 | + align="center" | |
| 61 | + /> | |
| 62 | + <el-table-column | |
| 63 | + prop="feeTypeCdName" | |
| 64 | + :label="$t('roomFeeImport.table.feeTypeCd')" | |
| 65 | + align="center" | |
| 66 | + /> | |
| 67 | + <el-table-column | |
| 68 | + prop="createTime" | |
| 69 | + :label="$t('roomFeeImport.table.createTime')" | |
| 70 | + align="center" | |
| 71 | + /> | |
| 72 | + <el-table-column | |
| 73 | + prop="remark" | |
| 74 | + :label="$t('roomFeeImport.table.remark')" | |
| 75 | + align="center" | |
| 76 | + /> | |
| 77 | + <el-table-column | |
| 78 | + :label="$t('common.operation')" | |
| 79 | + align="center" | |
| 80 | + width="150" | |
| 81 | + > | |
| 82 | + <template slot-scope="scope"> | |
| 83 | + <el-button | |
| 84 | + size="mini" | |
| 85 | + @click="handleDetail(scope.row)" | |
| 86 | + > | |
| 87 | + {{ $t('common.detail') }} | |
| 88 | + </el-button> | |
| 89 | + </template> | |
| 90 | + </el-table-column> | |
| 91 | + </el-table> | |
| 92 | + | |
| 93 | + <el-pagination | |
| 94 | + :current-page="pagination.current" | |
| 95 | + :page-sizes="[10, 20, 30, 50]" | |
| 96 | + :page-size="pagination.size" | |
| 97 | + :total="pagination.total" | |
| 98 | + layout="total, sizes, prev, pager, next, jumper" | |
| 99 | + @size-change="handleSizeChange" | |
| 100 | + @current-change="handleCurrentChange" | |
| 101 | + /> | |
| 102 | + </el-card> | |
| 103 | + | |
| 104 | + <!-- 导入组件 --> | |
| 105 | + <import-room-fee ref="importRoomFee" @success="handleSuccess" /> | |
| 106 | + </div> | |
| 107 | +</template> | |
| 108 | + | |
| 109 | +<script> | |
| 110 | +import { queryImportFee } from '@/api/fee/roomFeeImportApi' | |
| 111 | +import { getDict } from '@/api/community/communityApi' | |
| 112 | +import ImportRoomFee from '@/components/fee/importRoomFee' | |
| 113 | + | |
| 114 | +export default { | |
| 115 | + name: 'RoomFeeImportList', | |
| 116 | + components: { | |
| 117 | + ImportRoomFee | |
| 118 | + }, | |
| 119 | + data() { | |
| 120 | + return { | |
| 121 | + loading: false, | |
| 122 | + searchForm: { | |
| 123 | + importFeeId: '', | |
| 124 | + feeTypeCd: '' | |
| 125 | + }, | |
| 126 | + tableData: [], | |
| 127 | + feeTypeCds: [], | |
| 128 | + pagination: { | |
| 129 | + current: 1, | |
| 130 | + size: 10, | |
| 131 | + total: 0 | |
| 132 | + } | |
| 133 | + } | |
| 134 | + }, | |
| 135 | + created() { | |
| 136 | + this.getDictData() | |
| 137 | + this.getList() | |
| 138 | + }, | |
| 139 | + computed: { | |
| 140 | + filteredFeeTypeCds() { | |
| 141 | + return this.feeTypeCds.filter(item => item.statusCd !== '888800010008') | |
| 142 | + } | |
| 143 | + }, | |
| 144 | + methods: { | |
| 145 | + async getDictData() { | |
| 146 | + try { | |
| 147 | + const data = await getDict('pay_fee_config', 'fee_type_cd') | |
| 148 | + this.feeTypeCds = data | |
| 149 | + } catch (error) { | |
| 150 | + console.error('获取字典数据失败:', error) | |
| 151 | + } | |
| 152 | + }, | |
| 153 | + async getList() { | |
| 154 | + try { | |
| 155 | + this.loading = true | |
| 156 | + const params = { | |
| 157 | + page: this.pagination.current, | |
| 158 | + row: this.pagination.size, | |
| 159 | + importFeeId: this.searchForm.importFeeId, | |
| 160 | + feeTypeCd: this.searchForm.feeTypeCd | |
| 161 | + } | |
| 162 | + const { data, total } = await queryImportFee(params) | |
| 163 | + this.tableData = data | |
| 164 | + this.pagination.total = total | |
| 165 | + } catch (error) { | |
| 166 | + this.$message.error(this.$t('roomFeeImport.fetchError')) | |
| 167 | + } finally { | |
| 168 | + this.loading = false | |
| 169 | + } | |
| 170 | + }, | |
| 171 | + handleSearch() { | |
| 172 | + this.pagination.current = 1 | |
| 173 | + this.getList() | |
| 174 | + }, | |
| 175 | + handleSizeChange(val) { | |
| 176 | + this.pagination.size = val | |
| 177 | + this.getList() | |
| 178 | + }, | |
| 179 | + handleCurrentChange(val) { | |
| 180 | + this.pagination.current = val | |
| 181 | + this.getList() | |
| 182 | + }, | |
| 183 | + handleImport() { | |
| 184 | + this.$refs.importRoomFee.open() | |
| 185 | + }, | |
| 186 | + handleDetail(row) { | |
| 187 | + this.$router.push({ | |
| 188 | + path: '/fee/roomFeeImportDetail', | |
| 189 | + query: { importFeeId: row.importFeeId } | |
| 190 | + }) | |
| 191 | + }, | |
| 192 | + handleSuccess() { | |
| 193 | + this.getList() | |
| 194 | + } | |
| 195 | + } | |
| 196 | +} | |
| 197 | +</script> | |
| 198 | + | |
| 199 | +<style lang="scss" scoped> | |
| 200 | +.room-fee-import-container { | |
| 201 | + padding: 20px; | |
| 202 | + | |
| 203 | + .search-card { | |
| 204 | + margin-bottom: 20px; | |
| 205 | + } | |
| 206 | + | |
| 207 | + .table-card { | |
| 208 | + margin-bottom: 20px; | |
| 209 | + } | |
| 210 | +} | |
| 211 | +</style> | |
| 0 | 212 | \ No newline at end of file | ... | ... |
src/views/fee/shareReadingFeeLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + shareReadingFee: { | |
| 4 | + search: { | |
| 5 | + title: 'Search Conditions', | |
| 6 | + roomName: 'Please enter room number', | |
| 7 | + ownerName: 'Please enter owner name' | |
| 8 | + }, | |
| 9 | + list: { | |
| 10 | + title: 'Shared Reading Fees' | |
| 11 | + }, | |
| 12 | + table: { | |
| 13 | + roomName: 'Room', | |
| 14 | + ownerName: 'Owner', | |
| 15 | + feeName: 'Fee Name', | |
| 16 | + degrees: 'Shared Degrees', | |
| 17 | + amount: 'Shared Amount', | |
| 18 | + remark: 'Remark' | |
| 19 | + }, | |
| 20 | + fetchError: 'Failed to fetch shared reading fees' | |
| 21 | + } | |
| 22 | + }, | |
| 23 | + zh: { | |
| 24 | + shareReadingFee: { | |
| 25 | + search: { | |
| 26 | + title: '查询条件', | |
| 27 | + roomName: '请输入房屋编号', | |
| 28 | + ownerName: '请输入业主姓名' | |
| 29 | + }, | |
| 30 | + list: { | |
| 31 | + title: '公摊费用' | |
| 32 | + }, | |
| 33 | + table: { | |
| 34 | + roomName: '房屋', | |
| 35 | + ownerName: '业主', | |
| 36 | + feeName: '费用名称', | |
| 37 | + degrees: '公摊度数', | |
| 38 | + amount: '公摊金额', | |
| 39 | + remark: '说明' | |
| 40 | + }, | |
| 41 | + fetchError: '获取公摊费用失败' | |
| 42 | + } | |
| 43 | + } | |
| 44 | +} | |
| 0 | 45 | \ No newline at end of file | ... | ... |
src/views/fee/shareReadingFeeList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="share-reading-fee-container"> | |
| 3 | + <!-- 查询条件 --> | |
| 4 | + <el-card class="search-card"> | |
| 5 | + <div slot="header" class="flex justify-between"> | |
| 6 | + <span>{{ $t('shareReadingFee.search.title') }}</span> | |
| 7 | + </div> | |
| 8 | + <el-row :gutter="20"> | |
| 9 | + <el-col :span="6"> | |
| 10 | + <el-input v-model="searchForm.roomName" :placeholder="$t('shareReadingFee.search.roomName')" clearable | |
| 11 | + @keyup.enter.native="handleSearch" /> | |
| 12 | + </el-col> | |
| 13 | + <el-col :span="6"> | |
| 14 | + <el-input v-model="searchForm.ownerNameLike" :placeholder="$t('shareReadingFee.search.ownerName')" clearable | |
| 15 | + @keyup.enter.native="handleSearch" /> | |
| 16 | + </el-col> | |
| 17 | + <el-col :span="4"> | |
| 18 | + <el-button type="primary" @click="handleSearch"> | |
| 19 | + {{ $t('common.search') }} | |
| 20 | + </el-button> | |
| 21 | + </el-col> | |
| 22 | + </el-row> | |
| 23 | + </el-card> | |
| 24 | + | |
| 25 | + <!-- 数据列表 --> | |
| 26 | + <el-card class="list-card"> | |
| 27 | + <div slot="header" class="flex justify-between"> | |
| 28 | + <span>{{ $t('shareReadingFee.list.title') }}</span> | |
| 29 | + <el-button style="float: right; padding: 3px 0" type="text" @click="goBack"> | |
| 30 | + {{ $t('common.back') }} | |
| 31 | + </el-button> | |
| 32 | + </div> | |
| 33 | + | |
| 34 | + <el-table v-loading="loading" :data="tableData" border style="width: 100%"> | |
| 35 | + <el-table-column prop="roomName" :label="$t('shareReadingFee.table.roomName')" align="center" /> | |
| 36 | + <el-table-column prop="ownerName" :label="$t('shareReadingFee.table.ownerName')" align="center" /> | |
| 37 | + <el-table-column prop="feeName" :label="$t('shareReadingFee.table.feeName')" align="center" /> | |
| 38 | + <el-table-column prop="degrees" :label="$t('shareReadingFee.table.degrees')" align="center" /> | |
| 39 | + <el-table-column prop="amount" :label="$t('shareReadingFee.table.amount')" align="center" /> | |
| 40 | + <el-table-column prop="remark" :label="$t('shareReadingFee.table.remark')" align="center" /> | |
| 41 | + <el-table-column :label="$t('common.operation')" align="center" width="150"> | |
| 42 | + <template slot-scope="scope"> | |
| 43 | + <el-button size="mini" type="primary" @click="handleDetail(scope.row)"> | |
| 44 | + {{ $t('common.detail') }} | |
| 45 | + </el-button> | |
| 46 | + </template> | |
| 47 | + </el-table-column> | |
| 48 | + </el-table> | |
| 49 | + | |
| 50 | + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size" | |
| 51 | + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" | |
| 52 | + @current-change="handleCurrentChange" /> | |
| 53 | + </el-card> | |
| 54 | + </div> | |
| 55 | +</template> | |
| 56 | + | |
| 57 | +<script> | |
| 58 | +import { listFloorShareFee } from '@/api/fee/shareReadingFeeApi' | |
| 59 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 60 | + | |
| 61 | +export default { | |
| 62 | + name: 'ShareReadingFeeList', | |
| 63 | + data() { | |
| 64 | + return { | |
| 65 | + loading: false, | |
| 66 | + searchForm: { | |
| 67 | + readingId: this.$route.query.readingId || '', | |
| 68 | + roomName: '', | |
| 69 | + ownerNameLike: '', | |
| 70 | + communityId: '' | |
| 71 | + }, | |
| 72 | + tableData: [], | |
| 73 | + page: { | |
| 74 | + current: 1, | |
| 75 | + size: 10, | |
| 76 | + total: 0 | |
| 77 | + } | |
| 78 | + } | |
| 79 | + }, | |
| 80 | + created() { | |
| 81 | + this.searchForm.communityId = getCommunityId() | |
| 82 | + this.getList() | |
| 83 | + }, | |
| 84 | + methods: { | |
| 85 | + async getList() { | |
| 86 | + try { | |
| 87 | + this.loading = true | |
| 88 | + const params = { | |
| 89 | + page: this.page.current, | |
| 90 | + row: this.page.size, | |
| 91 | + ...this.searchForm | |
| 92 | + } | |
| 93 | + const { data, total } = await listFloorShareFee(params) | |
| 94 | + this.tableData = data | |
| 95 | + this.page.total = total | |
| 96 | + } catch (error) { | |
| 97 | + this.$message.error(this.$t('shareReadingFee.fetchError')) | |
| 98 | + } finally { | |
| 99 | + this.loading = false | |
| 100 | + } | |
| 101 | + }, | |
| 102 | + handleSearch() { | |
| 103 | + this.page.current = 1 | |
| 104 | + this.getList() | |
| 105 | + }, | |
| 106 | + handleSizeChange(val) { | |
| 107 | + this.page.size = val | |
| 108 | + this.getList() | |
| 109 | + }, | |
| 110 | + handleCurrentChange(val) { | |
| 111 | + this.page.current = val | |
| 112 | + this.getList() | |
| 113 | + }, | |
| 114 | + handleDetail(row) { | |
| 115 | + this.$router.push({ | |
| 116 | + path: '/fee/feeDetail', | |
| 117 | + query: { feeId: row.feeId } | |
| 118 | + }) | |
| 119 | + }, | |
| 120 | + goBack() { | |
| 121 | + this.$router.go(-1) | |
| 122 | + } | |
| 123 | + } | |
| 124 | +} | |
| 125 | +</script> | |
| 126 | + | |
| 127 | +<style lang="scss" scoped> | |
| 128 | +.share-reading-fee-container { | |
| 129 | + padding: 20px; | |
| 130 | + | |
| 131 | + .search-card { | |
| 132 | + margin-bottom: 20px; | |
| 133 | + } | |
| 134 | + | |
| 135 | + .list-card { | |
| 136 | + margin-bottom: 20px; | |
| 137 | + } | |
| 138 | + | |
| 139 | + .el-pagination { | |
| 140 | + margin-top: 20px; | |
| 141 | + text-align: right; | |
| 142 | + } | |
| 143 | +} | |
| 144 | +</style> | |
| 0 | 145 | \ No newline at end of file | ... | ... |
src/views/fee/shareReadingLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + shareReading: { | |
| 4 | + search: { | |
| 5 | + title: 'Search Conditions', | |
| 6 | + selectMeter: 'Please select shared meter', | |
| 7 | + startTime: 'Please select start time', | |
| 8 | + endTime: 'Please select end time' | |
| 9 | + }, | |
| 10 | + list: { | |
| 11 | + title: 'Shared Meter Reading', | |
| 12 | + addReading: 'Add Reading' | |
| 13 | + }, | |
| 14 | + table: { | |
| 15 | + id: 'ID', | |
| 16 | + name: 'Name', | |
| 17 | + preDegrees: 'Previous Degrees', | |
| 18 | + curDegrees: 'Current Degrees', | |
| 19 | + degrees: 'Degrees', | |
| 20 | + preReadingTime: 'Previous Reading Time', | |
| 21 | + curReadingTime: 'Current Reading Time', | |
| 22 | + reader: 'Reader', | |
| 23 | + status: 'Status', | |
| 24 | + remark: 'Remark', | |
| 25 | + auditor: 'Auditor', | |
| 26 | + auditOpinion: 'Audit Opinion', | |
| 27 | + shareProgress: 'Share Progress', | |
| 28 | + readingTime: 'Reading Time', | |
| 29 | + shareFee: 'Share Fee', | |
| 30 | + operation: 'Operation' | |
| 31 | + }, | |
| 32 | + status: { | |
| 33 | + waiting: 'Waiting', | |
| 34 | + passed: 'Passed', | |
| 35 | + rejected: 'Rejected', | |
| 36 | + all: 'All' | |
| 37 | + }, | |
| 38 | + add: { | |
| 39 | + title: 'Add Shared Reading', | |
| 40 | + meter: 'Shared Meter', | |
| 41 | + selectMeter: 'Please select shared meter', | |
| 42 | + preDegrees: 'Previous Degrees', | |
| 43 | + inputPreDegrees: 'Please input previous degrees', | |
| 44 | + curDegrees: 'Current Degrees', | |
| 45 | + inputCurDegrees: 'Please input current degrees', | |
| 46 | + preReadingTime: 'Previous Reading Time', | |
| 47 | + selectPreTime: 'Please select previous reading time', | |
| 48 | + curReadingTime: 'Current Reading Time', | |
| 49 | + selectCurTime: 'Please select current reading time', | |
| 50 | + remark: 'Remark', | |
| 51 | + inputRemark: 'Please input remark (optional)' | |
| 52 | + }, | |
| 53 | + audit: { | |
| 54 | + title: 'Audit Shared Reading', | |
| 55 | + status: 'Status', | |
| 56 | + selectStatus: 'Please select status', | |
| 57 | + remark: 'Remark', | |
| 58 | + inputRemark: 'Please input remark' | |
| 59 | + }, | |
| 60 | + delete: { | |
| 61 | + title: 'Delete Confirmation', | |
| 62 | + confirm: 'Are you sure to delete this shared reading?' | |
| 63 | + }, | |
| 64 | + validate: { | |
| 65 | + selectMeter: 'Please select shared meter', | |
| 66 | + inputPreDegrees: 'Please input previous degrees', | |
| 67 | + inputCurDegrees: 'Please input current degrees', | |
| 68 | + selectPreTime: 'Please select previous reading time', | |
| 69 | + selectCurTime: 'Please select current reading time', | |
| 70 | + selectStatus: 'Please select audit status', | |
| 71 | + number: 'Please input valid number' | |
| 72 | + }, | |
| 73 | + message: { | |
| 74 | + addSuccess: 'Add shared reading successfully', | |
| 75 | + auditSuccess: 'Audit shared reading successfully', | |
| 76 | + deleteSuccess: 'Delete shared reading successfully' | |
| 77 | + } | |
| 78 | + } | |
| 79 | + }, | |
| 80 | + zh: { | |
| 81 | + shareReading: { | |
| 82 | + search: { | |
| 83 | + title: '查询条件', | |
| 84 | + selectMeter: '请选择公摊表', | |
| 85 | + startTime: '请选择开始时间', | |
| 86 | + endTime: '请选择结束时间' | |
| 87 | + }, | |
| 88 | + list: { | |
| 89 | + title: '公摊抄表', | |
| 90 | + addReading: '抄表' | |
| 91 | + }, | |
| 92 | + table: { | |
| 93 | + id: '编号', | |
| 94 | + name: '名称', | |
| 95 | + preDegrees: '上期度数', | |
| 96 | + curDegrees: '本期度数', | |
| 97 | + degrees: '度数', | |
| 98 | + preReadingTime: '上期读表时间', | |
| 99 | + curReadingTime: '本期读表时间', | |
| 100 | + reader: '抄表人', | |
| 101 | + status: '状态', | |
| 102 | + remark: '说明', | |
| 103 | + auditor: '审核人', | |
| 104 | + auditOpinion: '审核意见', | |
| 105 | + shareProgress: '公摊进度', | |
| 106 | + readingTime: '抄表时间', | |
| 107 | + shareFee: '公摊费用', | |
| 108 | + operation: '操作' | |
| 109 | + }, | |
| 110 | + status: { | |
| 111 | + waiting: '待审核', | |
| 112 | + passed: '审核通过', | |
| 113 | + rejected: '审核不通过', | |
| 114 | + all: '全部' | |
| 115 | + }, | |
| 116 | + add: { | |
| 117 | + title: '公摊抄表', | |
| 118 | + meter: '公摊表', | |
| 119 | + selectMeter: '请选择公摊表', | |
| 120 | + preDegrees: '上期度数', | |
| 121 | + inputPreDegrees: '请填写上期度数', | |
| 122 | + curDegrees: '本期度数', | |
| 123 | + inputCurDegrees: '请填写本期度数', | |
| 124 | + preReadingTime: '上期读表时间', | |
| 125 | + selectPreTime: '请选择上期读表时间', | |
| 126 | + curReadingTime: '本期读表时间', | |
| 127 | + selectCurTime: '请选择本期读表时间', | |
| 128 | + remark: '备注', | |
| 129 | + inputRemark: '请填写备注(选填)' | |
| 130 | + }, | |
| 131 | + audit: { | |
| 132 | + title: '公摊审核', | |
| 133 | + status: '审核', | |
| 134 | + selectStatus: '请选择审核', | |
| 135 | + remark: '说明', | |
| 136 | + inputRemark: '请填写说明' | |
| 137 | + }, | |
| 138 | + delete: { | |
| 139 | + title: '删除确认', | |
| 140 | + confirm: '确定删除公摊抄表?' | |
| 141 | + }, | |
| 142 | + validate: { | |
| 143 | + selectMeter: '请选择公摊表', | |
| 144 | + inputPreDegrees: '请填写上期度数', | |
| 145 | + inputCurDegrees: '请填写本期度数', | |
| 146 | + selectPreTime: '请选择上期读表时间', | |
| 147 | + selectCurTime: '请选择本期读表时间', | |
| 148 | + selectStatus: '请选择审核状态', | |
| 149 | + number: '请输入有效数字' | |
| 150 | + }, | |
| 151 | + message: { | |
| 152 | + addSuccess: '添加公摊抄表成功', | |
| 153 | + auditSuccess: '审核公摊抄表成功', | |
| 154 | + deleteSuccess: '删除公摊抄表成功' | |
| 155 | + } | |
| 156 | + } | |
| 157 | + } | |
| 158 | +} | |
| 0 | 159 | \ No newline at end of file | ... | ... |
src/views/fee/shareReadingList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="share-reading-container"> | |
| 3 | + <el-row :gutter="20"> | |
| 4 | + <el-col :span="4"> | |
| 5 | + <el-card class="tree-card"> | |
| 6 | + <ul class="state-list"> | |
| 7 | + <li v-for="(item, index) in shareReadingInfo.states" :key="index" @click="swatchShareState(item)" | |
| 8 | + :class="{ 'active-state': shareReadingInfo.conditions.state === item.statusCd }"> | |
| 9 | + {{ item.name }} | |
| 10 | + </li> | |
| 11 | + </ul> | |
| 12 | + </el-card> | |
| 13 | + </el-col> | |
| 14 | + <el-col :span="20"> | |
| 15 | + <el-card> | |
| 16 | + <div slot="header" class="clearfix"> | |
| 17 | + <span>{{ $t('shareReading.search.title') }}</span> | |
| 18 | + </div> | |
| 19 | + <div class="search-wrapper"> | |
| 20 | + <el-row :gutter="20"> | |
| 21 | + <el-col :span="6"> | |
| 22 | + <el-select v-model="shareReadingInfo.conditions.fsmId" | |
| 23 | + :placeholder="$t('shareReading.search.selectMeter')" style="width:100%"> | |
| 24 | + <el-option v-for="(item, index) in shareReadingInfo.floorShares" :key="index" | |
| 25 | + :label="`${item.floorNum}栋-${item.meterTypeName}`" :value="item.fsmId" /> | |
| 26 | + </el-select> | |
| 27 | + </el-col> | |
| 28 | + <el-col :span="6"> | |
| 29 | + <el-date-picker v-model="shareReadingInfo.conditions.startTime" type="datetime" | |
| 30 | + :placeholder="$t('shareReading.search.startTime')" style="width:100%" /> | |
| 31 | + </el-col> | |
| 32 | + <el-col :span="6"> | |
| 33 | + <el-date-picker v-model="shareReadingInfo.conditions.endTime" type="datetime" | |
| 34 | + :placeholder="$t('shareReading.search.endTime')" style="width:100%" /> | |
| 35 | + </el-col> | |
| 36 | + <el-col :span="2"> | |
| 37 | + <el-button type="primary" @click="_queryShareReadingMethod"> | |
| 38 | + {{ $t('common.search') }} | |
| 39 | + </el-button> | |
| 40 | + </el-col> | |
| 41 | + </el-row> | |
| 42 | + </div> | |
| 43 | + </el-card> | |
| 44 | + | |
| 45 | + <el-card class="mt-20"> | |
| 46 | + <div slot="header" class="clearfix"> | |
| 47 | + <span>{{ $t('shareReading.list.title') }}</span> | |
| 48 | + <el-button type="primary" size="small" style="float:right" @click="_openAddShareReadingModal"> | |
| 49 | + {{ $t('shareReading.list.addReading') }} | |
| 50 | + </el-button> | |
| 51 | + </div> | |
| 52 | + <el-table :data="shareReadingInfo.shareReadings" border style="width:100%" v-loading="loading"> | |
| 53 | + <el-table-column prop="readingId" :label="$t('shareReading.table.id')" align="center" /> | |
| 54 | + <el-table-column prop="title" :label="$t('shareReading.table.name')" align="center" /> | |
| 55 | + <el-table-column prop="preDegrees" :label="$t('shareReading.table.preDegrees')" align="center" /> | |
| 56 | + <el-table-column prop="curDegrees" :label="$t('shareReading.table.curDegrees')" align="center" /> | |
| 57 | + <el-table-column :label="$t('shareReading.table.degrees')" align="center"> | |
| 58 | + <template slot-scope="scope"> | |
| 59 | + {{ scope.row.curDegrees - scope.row.preDegrees }} | |
| 60 | + </template> | |
| 61 | + </el-table-column> | |
| 62 | + <el-table-column prop="preReadingTime" :label="$t('shareReading.table.preReadingTime')" align="center" /> | |
| 63 | + <el-table-column prop="curReadingTime" :label="$t('shareReading.table.curReadingTime')" align="center" /> | |
| 64 | + <el-table-column prop="createStaffName" :label="$t('shareReading.table.reader')" align="center" /> | |
| 65 | + <el-table-column :label="$t('shareReading.table.status')" align="center"> | |
| 66 | + <template slot-scope="scope"> | |
| 67 | + <span v-if="scope.row.state === 'W'">{{ $t('shareReading.status.waiting') }}</span> | |
| 68 | + <span v-else-if="scope.row.state === 'C'">{{ $t('shareReading.status.passed') }}</span> | |
| 69 | + <span v-else>{{ $t('shareReading.status.rejected') }}</span> | |
| 70 | + </template> | |
| 71 | + </el-table-column> | |
| 72 | + <el-table-column prop="remark" :label="$t('shareReading.table.remark')" align="center"> | |
| 73 | + <template slot-scope="scope"> | |
| 74 | + {{ scope.row.remark || '-' }} | |
| 75 | + </template> | |
| 76 | + </el-table-column> | |
| 77 | + <el-table-column prop="auditStaffName" :label="$t('shareReading.table.auditor')" align="center"> | |
| 78 | + <template slot-scope="scope"> | |
| 79 | + {{ scope.row.auditStaffName || '-' }} | |
| 80 | + </template> | |
| 81 | + </el-table-column> | |
| 82 | + <el-table-column prop="stateMsg" :label="$t('shareReading.table.auditOpinion')" align="center"> | |
| 83 | + <template slot-scope="scope"> | |
| 84 | + {{ scope.row.stateMsg || '-' }} | |
| 85 | + </template> | |
| 86 | + </el-table-column> | |
| 87 | + <el-table-column prop="shareMsg" :label="$t('shareReading.table.shareProgress')" align="center"> | |
| 88 | + <template slot-scope="scope"> | |
| 89 | + {{ scope.row.shareMsg || '-' }} | |
| 90 | + </template> | |
| 91 | + </el-table-column> | |
| 92 | + <el-table-column prop="createTime" :label="$t('shareReading.table.readingTime')" align="center" /> | |
| 93 | + <el-table-column :label="$t('common.operation')" align="center" width="200"> | |
| 94 | + <template slot-scope="scope"> | |
| 95 | + <el-button v-if="scope.row.state === 'W' && hasPrivilege('502025032678040006')" size="mini" | |
| 96 | + type="primary" @click="_openAuditShareReadingModel(scope.row)"> | |
| 97 | + {{ $t('common.audit') }} | |
| 98 | + </el-button> | |
| 99 | + <el-button v-if="scope.row.state === 'W'" size="mini" type="danger" | |
| 100 | + @click="_openDeleteShareReadingModel(scope.row)"> | |
| 101 | + {{ $t('common.delete') }} | |
| 102 | + </el-button> | |
| 103 | + <el-button size="mini" type="success" @click="_openShareFee(scope.row)"> | |
| 104 | + {{ $t('shareReading.table.shareFee') }} | |
| 105 | + </el-button> | |
| 106 | + </template> | |
| 107 | + </el-table-column> | |
| 108 | + </el-table> | |
| 109 | + <el-pagination class="mt-20" :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" | |
| 110 | + :page-size="page.size" :total="page.total" layout="total, sizes, prev, pager, next, jumper" | |
| 111 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | |
| 112 | + </el-card> | |
| 113 | + </el-col> | |
| 114 | + </el-row> | |
| 115 | + | |
| 116 | + <add-share-reading ref="addShareReading" @success="handleSuccess" /> | |
| 117 | + <audit-share-reading ref="auditShareReading" @success="handleSuccess" /> | |
| 118 | + <delete-share-reading ref="deleteShareReading" @success="handleSuccess" /> | |
| 119 | + </div> | |
| 120 | +</template> | |
| 121 | + | |
| 122 | +<script> | |
| 123 | +import { getDict, getCommunityId } from '@/api/community/communityApi' | |
| 124 | +import { listFloorShareReading, listFloorShareMeter } from '@/api/fee/shareReadingApi' | |
| 125 | +import AddShareReading from '@/components/fee/addShareReading' | |
| 126 | +import AuditShareReading from '@/components/fee/auditShareReading' | |
| 127 | +import DeleteShareReading from '@/components/fee/deleteShareReading' | |
| 128 | + | |
| 129 | +export default { | |
| 130 | + name: 'ShareReadingList', | |
| 131 | + components: { | |
| 132 | + AddShareReading, | |
| 133 | + AuditShareReading, | |
| 134 | + DeleteShareReading | |
| 135 | + }, | |
| 136 | + data() { | |
| 137 | + return { | |
| 138 | + loading: false, | |
| 139 | + shareReadingInfo: { | |
| 140 | + shareReadings: [], | |
| 141 | + states: [], | |
| 142 | + floorShares: [], | |
| 143 | + conditions: { | |
| 144 | + fsmId: '', | |
| 145 | + state: '', | |
| 146 | + communityId: '', | |
| 147 | + startTime: '', | |
| 148 | + endTime: '', | |
| 149 | + page: 1, | |
| 150 | + row: 10 | |
| 151 | + } | |
| 152 | + }, | |
| 153 | + page: { | |
| 154 | + current: 1, | |
| 155 | + size: 10, | |
| 156 | + total: 0 | |
| 157 | + } | |
| 158 | + } | |
| 159 | + }, | |
| 160 | + created() { | |
| 161 | + this.initData() | |
| 162 | + }, | |
| 163 | + methods: { | |
| 164 | + async initData() { | |
| 165 | + try { | |
| 166 | + this.loading = true | |
| 167 | + this.shareReadingInfo.conditions.communityId = getCommunityId() | |
| 168 | + | |
| 169 | + // 获取状态字典 | |
| 170 | + const states = await getDict('floor_share_reading', 'state') | |
| 171 | + this.shareReadingInfo.states = [{ statusCd: '', name: this.$t('common.all') }, ...states] | |
| 172 | + | |
| 173 | + await this._listFloorShares() | |
| 174 | + await this._listShareReadings() | |
| 175 | + } catch (error) { | |
| 176 | + console.error('初始化数据失败:', error) | |
| 177 | + } finally { | |
| 178 | + this.loading = false | |
| 179 | + } | |
| 180 | + }, | |
| 181 | + async _listShareReadings() { | |
| 182 | + try { | |
| 183 | + this.loading = true | |
| 184 | + const params = { | |
| 185 | + ...this.shareReadingInfo.conditions, | |
| 186 | + page: this.page.current, | |
| 187 | + row: this.page.size | |
| 188 | + } | |
| 189 | + const { data, total } = await listFloorShareReading(params) | |
| 190 | + this.shareReadingInfo.shareReadings = data | |
| 191 | + this.page.total = total | |
| 192 | + } catch (error) { | |
| 193 | + console.error('获取公摊抄表列表失败:', error) | |
| 194 | + } finally { | |
| 195 | + this.loading = false | |
| 196 | + } | |
| 197 | + }, | |
| 198 | + async _listFloorShares() { | |
| 199 | + try { | |
| 200 | + const params = { | |
| 201 | + page: 1, | |
| 202 | + row: 300, | |
| 203 | + communityId: getCommunityId() | |
| 204 | + } | |
| 205 | + const { data } = await listFloorShareMeter(params) | |
| 206 | + this.shareReadingInfo.floorShares = data | |
| 207 | + } catch (error) { | |
| 208 | + console.error('获取公摊表列表失败:', error) | |
| 209 | + } | |
| 210 | + }, | |
| 211 | + _openAddShareReadingModal() { | |
| 212 | + this.$refs.addShareReading.open() | |
| 213 | + }, | |
| 214 | + _openAuditShareReadingModel(row) { | |
| 215 | + this.$refs.auditShareReading.open(row) | |
| 216 | + }, | |
| 217 | + _openDeleteShareReadingModel(row) { | |
| 218 | + this.$refs.deleteShareReading.open(row) | |
| 219 | + }, | |
| 220 | + _queryShareReadingMethod() { | |
| 221 | + this.page.current = 1 | |
| 222 | + this._listShareReadings() | |
| 223 | + }, | |
| 224 | + swatchShareState(state) { | |
| 225 | + this.shareReadingInfo.conditions.state = state.statusCd | |
| 226 | + this._queryShareReadingMethod() | |
| 227 | + }, | |
| 228 | + _openShareFee(reading) { | |
| 229 | + this.$router.push(`/views/fee/shareReadingFee?readingId=${reading.readingId}`) | |
| 230 | + }, | |
| 231 | + handleSuccess() { | |
| 232 | + this._listShareReadings() | |
| 233 | + }, | |
| 234 | + handleSizeChange(val) { | |
| 235 | + this.page.size = val | |
| 236 | + this._listShareReadings() | |
| 237 | + }, | |
| 238 | + handleCurrentChange(val) { | |
| 239 | + this.page.current = val | |
| 240 | + this._listShareReadings() | |
| 241 | + }, | |
| 242 | + | |
| 243 | + } | |
| 244 | +} | |
| 245 | +</script> | |
| 246 | + | |
| 247 | +<style lang="scss" scoped> | |
| 248 | +.share-reading-container { | |
| 249 | + padding: 20px; | |
| 250 | + | |
| 251 | + .tree-card { | |
| 252 | + height: 100%; | |
| 253 | + | |
| 254 | + .state-list { | |
| 255 | + list-style: none; | |
| 256 | + padding: 0; | |
| 257 | + margin: 0; | |
| 258 | + | |
| 259 | + li { | |
| 260 | + padding: 10px; | |
| 261 | + text-align: center; | |
| 262 | + cursor: pointer; | |
| 263 | + border-radius: 4px; | |
| 264 | + margin-bottom: 5px; | |
| 265 | + | |
| 266 | + &:hover { | |
| 267 | + background-color: #f5f7fa; | |
| 268 | + } | |
| 269 | + | |
| 270 | + &.active-state { | |
| 271 | + background-color: #409eff; | |
| 272 | + color: #fff; | |
| 273 | + } | |
| 274 | + } | |
| 275 | + } | |
| 276 | + } | |
| 277 | + | |
| 278 | + .mt-20 { | |
| 279 | + margin-top: 20px; | |
| 280 | + } | |
| 281 | + | |
| 282 | + .search-wrapper { | |
| 283 | + margin-bottom: 20px; | |
| 284 | + } | |
| 285 | +} | |
| 286 | +</style> | |
| 0 | 287 | \ No newline at end of file | ... | ... |