Commit 10d3499d1187318a4b2a02d42ab69d95107f31a8
1 parent
f99fb9c6
开发完成 admin 台账功能
Showing
18 changed files
with
1880 additions
and
10 deletions
src/api/fee/adminOweFeeDetailApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | + | ||
| 3 | +// 查询欠费明细 | ||
| 4 | +export function queryAdminOweFeeDetail(params) { | ||
| 5 | + return new Promise((resolve, reject) => { | ||
| 6 | + request({ | ||
| 7 | + url: '/fee.queryAdminOweFeeDetail', | ||
| 8 | + method: 'get', | ||
| 9 | + params | ||
| 10 | + }).then(response => { | ||
| 11 | + const res = response.data | ||
| 12 | + if (res.code === 0) { | ||
| 13 | + resolve({ | ||
| 14 | + data: res.data, | ||
| 15 | + total: res.total | ||
| 16 | + }) | ||
| 17 | + } else { | ||
| 18 | + reject(new Error(res.msg || '查询欠费明细失败')) | ||
| 19 | + } | ||
| 20 | + }).catch(error => { | ||
| 21 | + reject(error) | ||
| 22 | + }) | ||
| 23 | + }) | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +// 查询小区楼层树 | ||
| 27 | +export function queryCommunityFloorTree(params) { | ||
| 28 | + return new Promise((resolve, reject) => { | ||
| 29 | + request({ | ||
| 30 | + url: '/community.queryCommunityFloorTree', | ||
| 31 | + method: 'get', | ||
| 32 | + params | ||
| 33 | + }).then(response => { | ||
| 34 | + const res = response.data | ||
| 35 | + if (res.code === 0) { | ||
| 36 | + resolve(res) | ||
| 37 | + } else { | ||
| 38 | + reject(new Error(res.msg || '查询小区楼层树失败')) | ||
| 39 | + } | ||
| 40 | + }).catch(error => { | ||
| 41 | + reject(error) | ||
| 42 | + }) | ||
| 43 | + }) | ||
| 44 | +} | ||
| 0 | \ No newline at end of file | 45 | \ No newline at end of file |
src/api/fee/adminPayFeeDetailApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | + | ||
| 3 | +// 查询缴费明细列表 | ||
| 4 | +export function queryAdminPayFeeDetail(params) { | ||
| 5 | + return new Promise((resolve, reject) => { | ||
| 6 | + request({ | ||
| 7 | + url: '/fee.queryAdminPayFeeDetail', | ||
| 8 | + method: 'get', | ||
| 9 | + params | ||
| 10 | + }).then(response => { | ||
| 11 | + const res = response.data | ||
| 12 | + console.log(res) | ||
| 13 | + if (res.code == 0) { | ||
| 14 | + resolve(res) | ||
| 15 | + } else { | ||
| 16 | + reject(new Error(res.msg || '查询缴费明细失败')) | ||
| 17 | + } | ||
| 18 | + }).catch(error => { | ||
| 19 | + reject(error) | ||
| 20 | + }) | ||
| 21 | + }) | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +// 导出缴费明细 | ||
| 25 | +export function exportFeeData(params) { | ||
| 26 | + return new Promise((resolve, reject) => { | ||
| 27 | + request({ | ||
| 28 | + url: '/export.exportData', | ||
| 29 | + method: 'get', | ||
| 30 | + params | ||
| 31 | + }).then(response => { | ||
| 32 | + const res = response.data | ||
| 33 | + if (res.code === 0) { | ||
| 34 | + resolve(res) | ||
| 35 | + } else { | ||
| 36 | + reject(new Error(res.msg || '导出缴费明细失败')) | ||
| 37 | + } | ||
| 38 | + }).catch(error => { | ||
| 39 | + reject(error) | ||
| 40 | + }) | ||
| 41 | + }) | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +// 获取管理员小区列表 | ||
| 45 | +export function listAdminCommunitys(params) { | ||
| 46 | + return new Promise((resolve, reject) => { | ||
| 47 | + request({ | ||
| 48 | + url: '/community.listAdminCommunitys', | ||
| 49 | + method: 'get', | ||
| 50 | + params | ||
| 51 | + }).then(response => { | ||
| 52 | + const res = response.data | ||
| 53 | + if (res.code === 0) { | ||
| 54 | + resolve({ | ||
| 55 | + data: res.data, | ||
| 56 | + total: res.total | ||
| 57 | + }) | ||
| 58 | + } else { | ||
| 59 | + reject(new Error(res.msg || '获取小区列表失败')) | ||
| 60 | + } | ||
| 61 | + }).catch(error => { | ||
| 62 | + reject(error) | ||
| 63 | + }) | ||
| 64 | + }) | ||
| 65 | +} | ||
| 0 | \ No newline at end of file | 66 | \ No newline at end of file |
src/api/report/communityFeeSummaryApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | + | ||
| 3 | +// 获取费用汇总数据 | ||
| 4 | +export function getCommunityFeeSummary(params) { | ||
| 5 | + return new Promise((resolve, reject) => { | ||
| 6 | + request({ | ||
| 7 | + url: '/admin.getCommunityFeeSummary', | ||
| 8 | + method: 'get', | ||
| 9 | + params | ||
| 10 | + }).then(response => { | ||
| 11 | + const res = response.data | ||
| 12 | + if (res.code === 0) { | ||
| 13 | + resolve(res) | ||
| 14 | + } else { | ||
| 15 | + reject(new Error(res.msg || '获取费用汇总数据失败')) | ||
| 16 | + } | ||
| 17 | + }).catch(error => { | ||
| 18 | + reject(error) | ||
| 19 | + }) | ||
| 20 | + }) | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +// 获取管理员社区列表 | ||
| 24 | +export function listAdminCommunitys(params) { | ||
| 25 | + return new Promise((resolve, reject) => { | ||
| 26 | + request({ | ||
| 27 | + url: '/community.listAdminCommunitys', | ||
| 28 | + method: 'get', | ||
| 29 | + params | ||
| 30 | + }).then(response => { | ||
| 31 | + const res = response.data | ||
| 32 | + if (res.code === 0) { | ||
| 33 | + resolve(res) | ||
| 34 | + } else { | ||
| 35 | + reject(new Error(res.msg || '获取管理员社区列表失败')) | ||
| 36 | + } | ||
| 37 | + }).catch(error => { | ||
| 38 | + reject(error) | ||
| 39 | + }) | ||
| 40 | + }) | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +// 导出数据 | ||
| 44 | +export function exportCommunityFeeSummary(params) { | ||
| 45 | + return new Promise((resolve, reject) => { | ||
| 46 | + request({ | ||
| 47 | + url: '/export.exportData', | ||
| 48 | + method: 'get', | ||
| 49 | + params: { | ||
| 50 | + ...params, | ||
| 51 | + pagePath: 'communityFeeSummary' | ||
| 52 | + } | ||
| 53 | + }).then(response => { | ||
| 54 | + const res = response.data | ||
| 55 | + if (res.code === 0) { | ||
| 56 | + resolve(res) | ||
| 57 | + } else { | ||
| 58 | + reject(new Error(res.msg || '导出费用汇总数据失败')) | ||
| 59 | + } | ||
| 60 | + }).catch(error => { | ||
| 61 | + reject(error) | ||
| 62 | + }) | ||
| 63 | + }) | ||
| 64 | +} | ||
| 0 | \ No newline at end of file | 65 | \ No newline at end of file |
src/api/report/operationalAnalysisApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | ||
| 2 | + | ||
| 3 | +// 获取运营分析数据 | ||
| 4 | +export function getCommunityOperationalAnalysis(params) { | ||
| 5 | + return new Promise((resolve, reject) => { | ||
| 6 | + request({ | ||
| 7 | + url: '/admin.getCommunityOperationalAnalysis', | ||
| 8 | + method: 'get', | ||
| 9 | + params | ||
| 10 | + }).then(response => { | ||
| 11 | + const res = response.data | ||
| 12 | + if (res.code === 0) { | ||
| 13 | + resolve(res) | ||
| 14 | + } else { | ||
| 15 | + reject(new Error(res.msg || '获取运营分析数据失败')) | ||
| 16 | + } | ||
| 17 | + }).catch(error => { | ||
| 18 | + reject(error) | ||
| 19 | + }) | ||
| 20 | + }) | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +// 获取管理员小区列表 | ||
| 24 | +export function listAdminCommunitys(params) { | ||
| 25 | + return new Promise((resolve, reject) => { | ||
| 26 | + request({ | ||
| 27 | + url: '/community.listAdminCommunitys', | ||
| 28 | + method: 'get', | ||
| 29 | + params | ||
| 30 | + }).then(response => { | ||
| 31 | + const res = response.data | ||
| 32 | + if (res.code === 0) { | ||
| 33 | + resolve(res) | ||
| 34 | + } else { | ||
| 35 | + reject(new Error(res.msg || '获取小区列表失败')) | ||
| 36 | + } | ||
| 37 | + }).catch(error => { | ||
| 38 | + reject(error) | ||
| 39 | + }) | ||
| 40 | + }) | ||
| 41 | +} | ||
| 0 | \ No newline at end of file | 42 | \ No newline at end of file |
src/components/fee/SelectAdminCommunity.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card> | ||
| 3 | + <div class="community-selector"> | ||
| 4 | + <el-scrollbar style="height: 650px"> | ||
| 5 | + <ul class="community-list"> | ||
| 6 | + <li | ||
| 7 | + v-for="(item, index) in communitys" | ||
| 8 | + :key="index" | ||
| 9 | + class="community-item" | ||
| 10 | + :class="{ 'selected': communityId === item.communityId }" | ||
| 11 | + @click="handleSelectCommunity(item)" | ||
| 12 | + > | ||
| 13 | + {{ item.name }} | ||
| 14 | + </li> | ||
| 15 | + </ul> | ||
| 16 | + </el-scrollbar> | ||
| 17 | + </div> | ||
| 18 | + </el-card> | ||
| 19 | +</template> | ||
| 20 | + | ||
| 21 | +<script> | ||
| 22 | +import { listAdminCommunitys } from '@/api/fee/adminPayFeeDetailApi' | ||
| 23 | + | ||
| 24 | +export default { | ||
| 25 | + name: 'SelectAdminCommunity', | ||
| 26 | + data() { | ||
| 27 | + return { | ||
| 28 | + communitys: [ | ||
| 29 | + { name: this.$t('adminPayFeeDetail.allCommunities'), communityId: '' } | ||
| 30 | + ], | ||
| 31 | + communityId: '' | ||
| 32 | + } | ||
| 33 | + }, | ||
| 34 | + created() { | ||
| 35 | + this.loadCommunities() | ||
| 36 | + }, | ||
| 37 | + methods: { | ||
| 38 | + async loadCommunities() { | ||
| 39 | + try { | ||
| 40 | + const params = { | ||
| 41 | + page: 1, | ||
| 42 | + row: 100 | ||
| 43 | + } | ||
| 44 | + const { data } = await listAdminCommunitys(params) | ||
| 45 | + this.communitys = [...this.communitys, ...data] | ||
| 46 | + } catch (error) { | ||
| 47 | + this.$message.error(this.$t('adminPayFeeDetail.fetchCommunityError')) | ||
| 48 | + } | ||
| 49 | + }, | ||
| 50 | + handleSelectCommunity(community) { | ||
| 51 | + this.communityId = community.communityId | ||
| 52 | + this.$emit('changeCommunity', community) | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | +} | ||
| 56 | +</script> | ||
| 57 | + | ||
| 58 | +<style lang="scss" scoped> | ||
| 59 | +.community-selector { | ||
| 60 | + .community-list { | ||
| 61 | + list-style: none; | ||
| 62 | + padding: 0; | ||
| 63 | + margin: 0; | ||
| 64 | + | ||
| 65 | + .community-item { | ||
| 66 | + padding: 12px 15px; | ||
| 67 | + cursor: pointer; | ||
| 68 | + text-align: center; | ||
| 69 | + border-bottom: 1px solid #ebeef5; | ||
| 70 | + transition: all 0.3s; | ||
| 71 | + | ||
| 72 | + &:hover { | ||
| 73 | + background-color: #f5f7fa; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + &.selected { | ||
| 77 | + background-color: #409eff; | ||
| 78 | + color: white; | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | +} | ||
| 83 | +</style> | ||
| 0 | \ No newline at end of file | 84 | \ No newline at end of file |
src/components/fee/communityFloorTree.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <el-card class="tree-card"> | ||
| 3 | + <el-tree ref="tree" :data="treeData" node-key="id" :props="defaultProps" :highlight-current="true" | ||
| 4 | + :expand-on-click-node="false" @node-click="handleNodeClick" /> | ||
| 5 | + </el-card> | ||
| 6 | +</template> | ||
| 7 | + | ||
| 8 | +<script> | ||
| 9 | +import { queryCommunityFloorTree } from '@/api/fee/adminOweFeeDetailApi' | ||
| 10 | + | ||
| 11 | +export default { | ||
| 12 | + name: 'CommunityFloorTree', | ||
| 13 | + data() { | ||
| 14 | + return { | ||
| 15 | + treeData: [], | ||
| 16 | + defaultProps: { | ||
| 17 | + children: 'children', | ||
| 18 | + label: 'text' | ||
| 19 | + }, | ||
| 20 | + callName: '' | ||
| 21 | + } | ||
| 22 | + }, | ||
| 23 | + mounted() { | ||
| 24 | + this.initCommunityFloorTree() | ||
| 25 | + }, | ||
| 26 | + methods: { | ||
| 27 | + async initCommunityFloorTree() { | ||
| 28 | + await this.loadCommunityFloorTree() | ||
| 29 | + }, | ||
| 30 | + async loadCommunityFloorTree() { | ||
| 31 | + try { | ||
| 32 | + // 这里应该是从API获取树形数据 | ||
| 33 | + const {data} = await queryCommunityFloorTree() | ||
| 34 | + console.log(data) | ||
| 35 | + // 模拟数据 | ||
| 36 | + this.treeData = data | ||
| 37 | + } catch (error) { | ||
| 38 | + console.error(error) | ||
| 39 | + } | ||
| 40 | + }, | ||
| 41 | + handleNodeClick(data) { | ||
| 42 | + if (data.id.startsWith('c_')) { | ||
| 43 | + this.$emit('chooseFloor', { | ||
| 44 | + communityName: data.communityName, | ||
| 45 | + communityId: data.communityId, | ||
| 46 | + floorNum: '', | ||
| 47 | + floorId: '' | ||
| 48 | + }) | ||
| 49 | + } else if (data.id.startsWith('f_')) { | ||
| 50 | + this.$emit('chooseFloor', { | ||
| 51 | + communityName:'', | ||
| 52 | + communityId: '', | ||
| 53 | + floorNum: data.floorNum, | ||
| 54 | + floorId: data.floorId | ||
| 55 | + }) | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | +} | ||
| 60 | +</script> | ||
| 61 | + | ||
| 62 | +<style scoped> | ||
| 63 | +.tree-card { | ||
| 64 | + height: 100%; | ||
| 65 | +} | ||
| 66 | +</style> | ||
| 0 | \ No newline at end of file | 67 | \ No newline at end of file |
src/components/report/SelectAdminCommunity.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="select-admin-community"> | ||
| 3 | + <el-card class="border-radius"> | ||
| 4 | + <div class="treeview attendance-staff" style="height: 650px;"> | ||
| 5 | + <ul class="list-group text-center border-radius"> | ||
| 6 | + <li | ||
| 7 | + v-for="(item, index) in communityList" | ||
| 8 | + :key="index" | ||
| 9 | + class="list-group-item node-orgTree" | ||
| 10 | + :class="{ 'vc-node-selected': selectedCommunityId === item.communityId }" | ||
| 11 | + @click="handleCommunityClick(item)" | ||
| 12 | + > | ||
| 13 | + {{ item.name }} | ||
| 14 | + </li> | ||
| 15 | + </ul> | ||
| 16 | + </div> | ||
| 17 | + </el-card> | ||
| 18 | + </div> | ||
| 19 | +</template> | ||
| 20 | + | ||
| 21 | +<script> | ||
| 22 | +import { listAdminCommunitys } from '@/api/report/communityFeeSummaryApi' | ||
| 23 | + | ||
| 24 | +export default { | ||
| 25 | + name: 'SelectAdminCommunity', | ||
| 26 | + data() { | ||
| 27 | + return { | ||
| 28 | + communityList: [ | ||
| 29 | + { name: this.$t('communityFeeSummary.allCommunities'), communityId: '' } | ||
| 30 | + ], | ||
| 31 | + selectedCommunityId: '' | ||
| 32 | + } | ||
| 33 | + }, | ||
| 34 | + created() { | ||
| 35 | + this.loadAdminCommunities() | ||
| 36 | + }, | ||
| 37 | + methods: { | ||
| 38 | + async loadAdminCommunities() { | ||
| 39 | + try { | ||
| 40 | + const params = { | ||
| 41 | + _uid: '123mlkdinkldldijdhuudjdjkkd', | ||
| 42 | + page: 1, | ||
| 43 | + row: 100 | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + const { data } = await listAdminCommunitys(params) | ||
| 47 | + this.communityList = [...this.communityList, ...data] | ||
| 48 | + } catch (error) { | ||
| 49 | + console.error('Failed to load communities:', error) | ||
| 50 | + } | ||
| 51 | + }, | ||
| 52 | + handleCommunityClick(community) { | ||
| 53 | + this.selectedCommunityId = community.communityId | ||
| 54 | + this.$emit('changeCommunity', community) | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | +} | ||
| 58 | +</script> | ||
| 59 | + | ||
| 60 | +<style lang="scss" scoped> | ||
| 61 | +.select-admin-community { | ||
| 62 | + .border-radius { | ||
| 63 | + border-radius: 4px; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + .treeview { | ||
| 67 | + overflow-y: auto; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + .list-group { | ||
| 71 | + padding-left: 0; | ||
| 72 | + margin-bottom: 0; | ||
| 73 | + | ||
| 74 | + &-item { | ||
| 75 | + position: relative; | ||
| 76 | + display: block; | ||
| 77 | + padding: 10px 15px; | ||
| 78 | + margin-bottom: -1px; | ||
| 79 | + background-color: #fff; | ||
| 80 | + border: 1px solid #ddd; | ||
| 81 | + cursor: pointer; | ||
| 82 | + | ||
| 83 | + &:first-child { | ||
| 84 | + border-top-left-radius: 4px; | ||
| 85 | + border-top-right-radius: 4px; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + &:last-child { | ||
| 89 | + margin-bottom: 0; | ||
| 90 | + border-bottom-right-radius: 4px; | ||
| 91 | + border-bottom-left-radius: 4px; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + &.vc-node-selected { | ||
| 95 | + background-color: #409EFF; | ||
| 96 | + color: #fff; | ||
| 97 | + border-color: #409EFF; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + &:hover:not(.vc-node-selected) { | ||
| 101 | + background-color: #f5f5f5; | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | +</style> | ||
| 0 | \ No newline at end of file | 107 | \ No newline at end of file |
src/i18n/commonLang.js
| @@ -31,7 +31,8 @@ export const messages = { | @@ -31,7 +31,8 @@ export const messages = { | ||
| 31 | female: 'Female', | 31 | female: 'Female', |
| 32 | male: 'Male', | 32 | male: 'Male', |
| 33 | all: 'All', | 33 | all: 'All', |
| 34 | - refresh: 'Refresh' | 34 | + refresh: 'Refresh', |
| 35 | + export: 'Export' | ||
| 35 | } | 36 | } |
| 36 | }, | 37 | }, |
| 37 | zh: { | 38 | zh: { |
| @@ -66,7 +67,8 @@ export const messages = { | @@ -66,7 +67,8 @@ export const messages = { | ||
| 66 | female: '女', | 67 | female: '女', |
| 67 | male: '男', | 68 | male: '男', |
| 68 | all: '全部', | 69 | all: '全部', |
| 69 | - refresh: '刷新' | 70 | + refresh: '刷新', |
| 71 | + export: '导出' | ||
| 70 | } | 72 | } |
| 71 | } | 73 | } |
| 72 | } | 74 | } |
| 73 | \ No newline at end of file | 75 | \ No newline at end of file |
src/i18n/index.js
| @@ -84,6 +84,10 @@ import { messages as adminInoutMessages } from '../views/iot/adminInoutLang' | @@ -84,6 +84,10 @@ import { messages as adminInoutMessages } from '../views/iot/adminInoutLang' | ||
| 84 | import { messages as adminCarInoutMessages } from '../views/iot/adminCarInoutLang' | 84 | import { messages as adminCarInoutMessages } from '../views/iot/adminCarInoutLang' |
| 85 | import { messages as adminChargeOrderMessages } from '../views/iot/adminChargeOrderLang' | 85 | import { messages as adminChargeOrderMessages } from '../views/iot/adminChargeOrderLang' |
| 86 | import { messages as adminMeterRechargeMessages } from '../views/iot/adminMeterRechargeLang' | 86 | import { messages as adminMeterRechargeMessages } from '../views/iot/adminMeterRechargeLang' |
| 87 | +import { messages as operationalAnalysisMessages } from '../views/report/operationalAnalysisLang' | ||
| 88 | +import { messages as communityFeeSummaryMessages } from '../views/report/communityFeeSummaryLang' | ||
| 89 | +import { messages as adminPayFeeDetailMessages } from '../views/fee/adminPayFeeDetailLang' | ||
| 90 | +import { messages as adminOweFeeDetailMessages } from '../views/fee/adminOweFeeDetailLang' | ||
| 87 | 91 | ||
| 88 | Vue.use(VueI18n) | 92 | Vue.use(VueI18n) |
| 89 | 93 | ||
| @@ -172,6 +176,10 @@ const messages = { | @@ -172,6 +176,10 @@ const messages = { | ||
| 172 | ...adminCarInoutMessages.en, | 176 | ...adminCarInoutMessages.en, |
| 173 | ...adminChargeOrderMessages.en, | 177 | ...adminChargeOrderMessages.en, |
| 174 | ...adminMeterRechargeMessages.en, | 178 | ...adminMeterRechargeMessages.en, |
| 179 | + ...operationalAnalysisMessages.en, | ||
| 180 | + ...communityFeeSummaryMessages.en, | ||
| 181 | + ...adminPayFeeDetailMessages.en, | ||
| 182 | + ...adminOweFeeDetailMessages.en, | ||
| 175 | }, | 183 | }, |
| 176 | zh: { | 184 | zh: { |
| 177 | ...loginMessages.zh, | 185 | ...loginMessages.zh, |
| @@ -256,6 +264,10 @@ const messages = { | @@ -256,6 +264,10 @@ const messages = { | ||
| 256 | ...adminCarInoutMessages.zh, | 264 | ...adminCarInoutMessages.zh, |
| 257 | ...adminChargeOrderMessages.zh, | 265 | ...adminChargeOrderMessages.zh, |
| 258 | ...adminMeterRechargeMessages.zh, | 266 | ...adminMeterRechargeMessages.zh, |
| 267 | + ...operationalAnalysisMessages.zh, | ||
| 268 | + ...communityFeeSummaryMessages.zh, | ||
| 269 | + ...adminPayFeeDetailMessages.zh, | ||
| 270 | + ...adminOweFeeDetailMessages.zh, | ||
| 259 | } | 271 | } |
| 260 | } | 272 | } |
| 261 | 273 |
src/router/index.js
| @@ -397,15 +397,35 @@ const routes = [ | @@ -397,15 +397,35 @@ const routes = [ | ||
| 397 | component: () => import('@/views/iot/adminCarInoutList.vue') | 397 | component: () => import('@/views/iot/adminCarInoutList.vue') |
| 398 | }, | 398 | }, |
| 399 | { | 399 | { |
| 400 | - path:'/pages/iot/adminChargeOrder', | ||
| 401 | - name:'/pages/iot/adminChargeOrder', | 400 | + path: '/pages/iot/adminChargeOrder', |
| 401 | + name: '/pages/iot/adminChargeOrder', | ||
| 402 | component: () => import('@/views/iot/adminChargeOrderList.vue') | 402 | component: () => import('@/views/iot/adminChargeOrderList.vue') |
| 403 | - }, | ||
| 404 | - { | ||
| 405 | - path:'/pages/iot/adminMeterRecharge', | ||
| 406 | - name:'/pages/iot/adminMeterRecharge', | ||
| 407 | - component: () => import('@/views/iot/adminMeterRechargeList.vue') | ||
| 408 | - }, | 403 | + }, |
| 404 | + { | ||
| 405 | + path: '/pages/iot/adminMeterRecharge', | ||
| 406 | + name: '/pages/iot/adminMeterRecharge', | ||
| 407 | + component: () => import('@/views/iot/adminMeterRechargeList.vue') | ||
| 408 | + }, | ||
| 409 | + { | ||
| 410 | + path: '/pages/report/operationalAnalysis', | ||
| 411 | + name: '/pages/report/operationalAnalysis', | ||
| 412 | + component: () => import('@/views/report/operationalAnalysisList.vue') | ||
| 413 | + }, | ||
| 414 | + { | ||
| 415 | + path: '/pages/report/communityFeeSummary', | ||
| 416 | + name: '/pages/report/communityFeeSummary', | ||
| 417 | + component: () => import('@/views/report/communityFeeSummaryList.vue') | ||
| 418 | + }, | ||
| 419 | + { | ||
| 420 | + path: '/pages/fee/adminPayFeeDetail', | ||
| 421 | + name: '/pages/fee/adminPayFeeDetail', | ||
| 422 | + component: () => import('@/views/fee/adminPayFeeDetailList.vue') | ||
| 423 | + }, | ||
| 424 | + { | ||
| 425 | + path: '/pages/fee/adminOweFeeDetail', | ||
| 426 | + name: '/pages/fee/adminOweFeeDetail', | ||
| 427 | + component: () => import('@/views/fee/adminOweFeeDetailList.vue') | ||
| 428 | + }, | ||
| 409 | // 其他子路由可以在这里添加 | 429 | // 其他子路由可以在这里添加 |
| 410 | ] | 430 | ] |
| 411 | }, | 431 | }, |
src/views/fee/adminOweFeeDetailLang.js
0 → 100644
| 1 | +export const messages = { | ||
| 2 | + en: { | ||
| 3 | + adminOweFeeDetail: { | ||
| 4 | + search: { | ||
| 5 | + title: 'Search Conditions', | ||
| 6 | + feeTypeCd: 'Please select fee type', | ||
| 7 | + objNameLike: 'Please enter room number', | ||
| 8 | + startTime: 'Please select start time', | ||
| 9 | + endTime: 'Please select end time', | ||
| 10 | + ownerNameLike: 'Please enter owner name' | ||
| 11 | + }, | ||
| 12 | + list: { | ||
| 13 | + title: 'Arrears Details' | ||
| 14 | + }, | ||
| 15 | + table: { | ||
| 16 | + index: 'No.', | ||
| 17 | + communityName: 'Community Name', | ||
| 18 | + objName: 'Room Number', | ||
| 19 | + ownerName: 'Owner', | ||
| 20 | + ownerTel: 'Owner Tel', | ||
| 21 | + builtUpArea: 'Area', | ||
| 22 | + feeName: 'Fee Item', | ||
| 23 | + startTime: 'Start Time', | ||
| 24 | + endTime: 'End Time', | ||
| 25 | + oweDay: 'Arrears Days', | ||
| 26 | + oweAmount: 'Arrears Amount' | ||
| 27 | + }, | ||
| 28 | + summary: { | ||
| 29 | + subtotal: 'Subtotal', | ||
| 30 | + total: 'Total', | ||
| 31 | + owe: 'Arrears', | ||
| 32 | + yuan: 'Yuan' | ||
| 33 | + }, | ||
| 34 | + tips: { | ||
| 35 | + startTime: 'Start time: the billing start time of the created fee', | ||
| 36 | + oweDayDeposit: 'Arrears days (days): The arrears days of the deposit fee item is the number of days from the start time of the fee to the current day', | ||
| 37 | + oweDayOther: 'For fee items other than deposits, the arrears days are the number of days from the start time to the end time of the fee', | ||
| 38 | + oweAmount: 'Arrears amount: the fee payable during the arrears period' | ||
| 39 | + }, | ||
| 40 | + feeType: { | ||
| 41 | + property: 'Property Fee', | ||
| 42 | + parking: 'Parking Fee' | ||
| 43 | + }, | ||
| 44 | + fetchError: 'Failed to fetch arrears details' | ||
| 45 | + } | ||
| 46 | + }, | ||
| 47 | + zh: { | ||
| 48 | + adminOweFeeDetail: { | ||
| 49 | + search: { | ||
| 50 | + title: '查询条件', | ||
| 51 | + feeTypeCd: '请选择费用大类', | ||
| 52 | + objNameLike: '请填写房屋编号', | ||
| 53 | + startTime: '请选择开始时间', | ||
| 54 | + endTime: '请选择结束时间', | ||
| 55 | + ownerNameLike: '请填写业主名称' | ||
| 56 | + }, | ||
| 57 | + list: { | ||
| 58 | + title: '欠费明细表' | ||
| 59 | + }, | ||
| 60 | + table: { | ||
| 61 | + index: '费用编号', | ||
| 62 | + communityName: '小区名称', | ||
| 63 | + objName: '房号', | ||
| 64 | + ownerName: '业主', | ||
| 65 | + ownerTel: '业主电话', | ||
| 66 | + builtUpArea: '面积', | ||
| 67 | + feeName: '费用项', | ||
| 68 | + startTime: '开始时间', | ||
| 69 | + endTime: '结束时间', | ||
| 70 | + oweDay: '欠费时长(天)', | ||
| 71 | + oweAmount: '欠费金额' | ||
| 72 | + }, | ||
| 73 | + summary: { | ||
| 74 | + subtotal: '小计', | ||
| 75 | + total: '大计', | ||
| 76 | + owe: '欠费', | ||
| 77 | + yuan: '元' | ||
| 78 | + }, | ||
| 79 | + tips: { | ||
| 80 | + startTime: '费用开始时间:所创建费用的计费起始时间', | ||
| 81 | + oweDayDeposit: '欠费时长(天):押金费用项欠费时长是费用开始时间到当天的天数', | ||
| 82 | + oweDayOther: '除押金外的费用项欠费时长是费用的开始时间到费用的结束时间的天数', | ||
| 83 | + oweAmount: '欠费金额:欠费周期内应缴费用' | ||
| 84 | + }, | ||
| 85 | + feeType: { | ||
| 86 | + property: '物业费', | ||
| 87 | + parking: '停车费' | ||
| 88 | + }, | ||
| 89 | + fetchError: '获取欠费明细失败' | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | +} | ||
| 0 | \ No newline at end of file | 93 | \ No newline at end of file |
src/views/fee/adminOweFeeDetailList.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="admin-owe-fee-detail-container animated fadeInRight"> | ||
| 3 | + <el-row :gutter="20" class="flex justify-start"> | ||
| 4 | + <el-col :span="4" class="room-floor-unit-tree"> | ||
| 5 | + <community-floor-tree ref="communityFloorTree" @chooseFloor="handleChooseFloor" /> | ||
| 6 | + </el-col> | ||
| 7 | + <el-col :span="20" class="margin-top-xs"> | ||
| 8 | + <el-card class="box-card"> | ||
| 9 | + <div slot="header" class="clearfix text-left"> | ||
| 10 | + <span>{{ $t('adminOweFeeDetail.search.title') }}</span> | ||
| 11 | + </div> | ||
| 12 | + <el-row :gutter="20"> | ||
| 13 | + <el-col :span="4"> | ||
| 14 | + <el-select v-model="searchForm.feeTypeCd" :placeholder="$t('adminOweFeeDetail.search.feeTypeCd')" clearable | ||
| 15 | + class="w-full"> | ||
| 16 | + <el-option v-for="item in feeTypeCds" :key="item.statusCd" :label="item.name" :value="item.statusCd" /> | ||
| 17 | + </el-select> | ||
| 18 | + </el-col> | ||
| 19 | + <el-col :span="4"> | ||
| 20 | + <el-input v-model="searchForm.objNameLike" :placeholder="$t('adminOweFeeDetail.search.objNameLike')" | ||
| 21 | + clearable /> | ||
| 22 | + </el-col> | ||
| 23 | + <el-col :span="4"> | ||
| 24 | + <el-date-picker v-model="searchForm.startTime" type="date" | ||
| 25 | + :placeholder="$t('adminOweFeeDetail.search.startTime')" class="w-full" /> | ||
| 26 | + </el-col> | ||
| 27 | + <el-col :span="4"> | ||
| 28 | + <el-date-picker v-model="searchForm.endTime" type="date" | ||
| 29 | + :placeholder="$t('adminOweFeeDetail.search.endTime')" class="w-full" /> | ||
| 30 | + </el-col> | ||
| 31 | + <el-col :span="4"> | ||
| 32 | + <el-input v-model="searchForm.ownerNameLike" :placeholder="$t('adminOweFeeDetail.search.ownerNameLike')" | ||
| 33 | + clearable /> | ||
| 34 | + </el-col> | ||
| 35 | + <el-col :span="4"> | ||
| 36 | + <el-button type="primary" @click="handleSearch"> | ||
| 37 | + {{ $t('common.search') }} | ||
| 38 | + </el-button> | ||
| 39 | + <el-button @click="handleReset" style="margin-left: 10px;"> | ||
| 40 | + {{ $t('common.reset') }} | ||
| 41 | + </el-button> | ||
| 42 | + </el-col> | ||
| 43 | + </el-row> | ||
| 44 | + </el-card> | ||
| 45 | + | ||
| 46 | + <el-card class="box-card margin-top"> | ||
| 47 | + <div slot="header" class="clearfix text-left" > | ||
| 48 | + <span>{{ $t('adminOweFeeDetail.list.title') }}</span> | ||
| 49 | + </div> | ||
| 50 | + <el-table :data="tableData" border style="width: 100%" v-loading="loading"> | ||
| 51 | + <el-table-column prop="index" :label="$t('adminOweFeeDetail.table.index')" width="80" align="center" /> | ||
| 52 | + <el-table-column prop="communityName" :label="$t('adminOweFeeDetail.table.communityName')" align="center" /> | ||
| 53 | + <el-table-column prop="objName" :label="$t('adminOweFeeDetail.table.objName')" align="center" /> | ||
| 54 | + <el-table-column prop="ownerName" :label="$t('adminOweFeeDetail.table.ownerName')" align="center" /> | ||
| 55 | + <el-table-column prop="ownerTel" :label="$t('adminOweFeeDetail.table.ownerTel')" align="center" /> | ||
| 56 | + <el-table-column prop="builtUpArea" :label="$t('adminOweFeeDetail.table.builtUpArea')" align="center" /> | ||
| 57 | + <el-table-column prop="feeName" :label="$t('adminOweFeeDetail.table.feeName')" align="center" /> | ||
| 58 | + <el-table-column prop="startTime" :label="$t('adminOweFeeDetail.table.startTime')" align="center" /> | ||
| 59 | + <el-table-column prop="endTime" :label="$t('adminOweFeeDetail.table.endTime')" align="center" /> | ||
| 60 | + <el-table-column prop="oweDay" :label="$t('adminOweFeeDetail.table.oweDay')" align="center" /> | ||
| 61 | + <el-table-column prop="oweAmount" :label="$t('adminOweFeeDetail.table.oweAmount')" align="center" /> | ||
| 62 | + </el-table> | ||
| 63 | + | ||
| 64 | + <el-row class="margin-top text-left"> | ||
| 65 | + <el-col :span="24"> | ||
| 66 | + <div> | ||
| 67 | + <span class="font-bold">{{ $t('adminOweFeeDetail.summary.subtotal') }}</span> | ||
| 68 | + <span class="margin-left"> | ||
| 69 | + {{ $t('adminOweFeeDetail.summary.owe') }}: {{ totalPreferentialAmount }} | ||
| 70 | + {{ $t('adminOweFeeDetail.summary.yuan') }} | ||
| 71 | + </span> | ||
| 72 | + </div> | ||
| 73 | + <div> | ||
| 74 | + <span class="font-bold">{{ $t('adminOweFeeDetail.summary.total') }}</span> | ||
| 75 | + <span class="margin-left"> | ||
| 76 | + {{ $t('adminOweFeeDetail.summary.owe') }}: {{ allOweAmount }} | ||
| 77 | + {{ $t('adminOweFeeDetail.summary.yuan') }} | ||
| 78 | + </span> | ||
| 79 | + </div> | ||
| 80 | + </el-col> | ||
| 81 | + </el-row> | ||
| 82 | + | ||
| 83 | + <el-row class="margin-top text-left"> | ||
| 84 | + <el-col :span="12"> | ||
| 85 | + <div>{{ $t('adminOweFeeDetail.tips.startTime') }}</div> | ||
| 86 | + <div>{{ $t('adminOweFeeDetail.tips.oweDayDeposit') }}</div> | ||
| 87 | + <div>{{ $t('adminOweFeeDetail.tips.oweDayOther') }}</div> | ||
| 88 | + <div>{{ $t('adminOweFeeDetail.tips.oweAmount') }}</div> | ||
| 89 | + </el-col> | ||
| 90 | + <el-col :span="12" class="text-right"> | ||
| 91 | + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" | ||
| 92 | + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" | ||
| 93 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 94 | + </el-col> | ||
| 95 | + </el-row> | ||
| 96 | + </el-card> | ||
| 97 | + </el-col> | ||
| 98 | + </el-row> | ||
| 99 | + </div> | ||
| 100 | +</template> | ||
| 101 | + | ||
| 102 | +<script> | ||
| 103 | +import { queryAdminOweFeeDetail } from '@/api/fee/adminOweFeeDetailApi' | ||
| 104 | +import CommunityFloorTree from '@/components/fee/communityFloorTree' | ||
| 105 | + | ||
| 106 | +export default { | ||
| 107 | + name: 'AdminOweFeeDetailList', | ||
| 108 | + components: { | ||
| 109 | + CommunityFloorTree | ||
| 110 | + }, | ||
| 111 | + data() { | ||
| 112 | + return { | ||
| 113 | + loading: false, | ||
| 114 | + searchForm: { | ||
| 115 | + floorId: '', | ||
| 116 | + floorName: '', | ||
| 117 | + roomNum: '', | ||
| 118 | + objNameLike: '', | ||
| 119 | + feeTypeCd: '', | ||
| 120 | + startTime: '', | ||
| 121 | + endTime: '', | ||
| 122 | + communityId: '', | ||
| 123 | + ownerNameLike: '' | ||
| 124 | + }, | ||
| 125 | + feeTypeCds: [], | ||
| 126 | + tableData: [], | ||
| 127 | + totalPreferentialAmount: 0, | ||
| 128 | + allOweAmount: 0, | ||
| 129 | + pagination: { | ||
| 130 | + current: 1, | ||
| 131 | + size: 10, | ||
| 132 | + total: 0 | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + }, | ||
| 136 | + created() { | ||
| 137 | + this.initData() | ||
| 138 | + }, | ||
| 139 | + methods: { | ||
| 140 | + async initData() { | ||
| 141 | + try { | ||
| 142 | + this.loading = true | ||
| 143 | + await this.getFeeTypeCds() | ||
| 144 | + await this.getList() | ||
| 145 | + } catch (error) { | ||
| 146 | + console.error(error) | ||
| 147 | + } finally { | ||
| 148 | + this.loading = false | ||
| 149 | + } | ||
| 150 | + }, | ||
| 151 | + async getFeeTypeCds() { | ||
| 152 | + // 这里应该是获取费用类型的字典数据 | ||
| 153 | + // 假设从字典接口获取数据 | ||
| 154 | + this.feeTypeCds = [ | ||
| 155 | + { statusCd: '1', name: this.$t('adminOweFeeDetail.feeType.property') }, | ||
| 156 | + { statusCd: '2', name: this.$t('adminOweFeeDetail.feeType.parking') } | ||
| 157 | + ] | ||
| 158 | + }, | ||
| 159 | + async getList() { | ||
| 160 | + try { | ||
| 161 | + this.loading = true | ||
| 162 | + const params = { | ||
| 163 | + ...this.searchForm, | ||
| 164 | + page: this.pagination.current, | ||
| 165 | + row: this.pagination.size | ||
| 166 | + } | ||
| 167 | + const { data, total } = await queryAdminOweFeeDetail(params) | ||
| 168 | + this.tableData = data.map((item, index) => ({ | ||
| 169 | + ...item, | ||
| 170 | + index: index + 1 | ||
| 171 | + })) | ||
| 172 | + this.pagination.total = total | ||
| 173 | + | ||
| 174 | + // 计算小计 | ||
| 175 | + let _totalPreferentialAmount = 0.0 | ||
| 176 | + data.forEach(item => { | ||
| 177 | + _totalPreferentialAmount += parseFloat(item.oweAmount) | ||
| 178 | + }) | ||
| 179 | + this.totalPreferentialAmount = _totalPreferentialAmount.toFixed(2) | ||
| 180 | + | ||
| 181 | + if (data.length > 0) { | ||
| 182 | + this.allOweAmount = data[0].allOweAmount || 0.0.toFixed(2) | ||
| 183 | + } else { | ||
| 184 | + this.allOweAmount = 0.0.toFixed(2) | ||
| 185 | + } | ||
| 186 | + } catch (error) { | ||
| 187 | + console.error(error) | ||
| 188 | + this.$message.error(this.$t('adminOweFeeDetail.fetchError')) | ||
| 189 | + } finally { | ||
| 190 | + this.loading = false | ||
| 191 | + } | ||
| 192 | + }, | ||
| 193 | + handleSearch() { | ||
| 194 | + this.pagination.current = 1 | ||
| 195 | + this.getList() | ||
| 196 | + }, | ||
| 197 | + handleReset() { | ||
| 198 | + this.searchForm = { | ||
| 199 | + floorId: '', | ||
| 200 | + floorName: '', | ||
| 201 | + roomNum: '', | ||
| 202 | + objNameLike: '', | ||
| 203 | + feeTypeCd: '', | ||
| 204 | + startTime: '', | ||
| 205 | + endTime: '', | ||
| 206 | + communityId: '', | ||
| 207 | + ownerNameLike: '' | ||
| 208 | + } | ||
| 209 | + this.handleSearch() | ||
| 210 | + }, | ||
| 211 | + handleSizeChange(val) { | ||
| 212 | + this.pagination.size = val | ||
| 213 | + this.getList() | ||
| 214 | + }, | ||
| 215 | + handleCurrentChange(val) { | ||
| 216 | + this.pagination.current = val | ||
| 217 | + this.getList() | ||
| 218 | + }, | ||
| 219 | + handleChooseFloor(floor) { | ||
| 220 | + this.searchForm.floorId = floor.floorId | ||
| 221 | + this.searchForm.floorName = floor.floorNum | ||
| 222 | + this.searchForm.communityId = floor.communityId | ||
| 223 | + this.searchForm.communityName = floor.communityName | ||
| 224 | + this.handleSearch() | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | +} | ||
| 228 | +</script> | ||
| 229 | + | ||
| 230 | +<style lang="scss" scoped> | ||
| 231 | +.admin-owe-fee-detail-container { | ||
| 232 | + padding: 20px; | ||
| 233 | + | ||
| 234 | + .margin-top { | ||
| 235 | + margin-top: 20px; | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + .margin-left { | ||
| 239 | + margin-left: 10px; | ||
| 240 | + } | ||
| 241 | + | ||
| 242 | + .font-bold { | ||
| 243 | + font-weight: bold; | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + .text-right { | ||
| 247 | + text-align: right; | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + .room-floor-unit-tree { | ||
| 251 | + padding-right: 0; | ||
| 252 | + } | ||
| 253 | +} | ||
| 254 | +</style> | ||
| 0 | \ No newline at end of file | 255 | \ No newline at end of file |
src/views/fee/adminPayFeeDetailLang.js
0 → 100644
| 1 | +export const messages = { | ||
| 2 | + en: { | ||
| 3 | + adminPayFeeDetail: { | ||
| 4 | + search: { | ||
| 5 | + title: 'Search Conditions', | ||
| 6 | + startTime: 'Payment Start Time', | ||
| 7 | + startTimePlaceholder: 'Please select payment start time', | ||
| 8 | + endTime: 'Payment End Time', | ||
| 9 | + endTimePlaceholder: 'Please select payment end time', | ||
| 10 | + paymentMethod: 'Payment Method', | ||
| 11 | + paymentMethodPlaceholder: 'Please select payment method', | ||
| 12 | + feeStatus: 'Fee Status', | ||
| 13 | + feeStatusPlaceholder: 'Please select fee status', | ||
| 14 | + feeType: 'Fee Type', | ||
| 15 | + feeTypePlaceholder: 'Please select fee type', | ||
| 16 | + feeStartTime: 'Fee Start Time', | ||
| 17 | + feeStartTimePlaceholder: 'Please select fee start time', | ||
| 18 | + feeEndTime: 'Fee End Time', | ||
| 19 | + feeEndTimePlaceholder: 'Please select fee end time', | ||
| 20 | + payerObjName: 'Room/Car Number', | ||
| 21 | + payerObjNamePlaceholder: 'Room number or license plate number' | ||
| 22 | + }, | ||
| 23 | + list: { | ||
| 24 | + title: 'Payment Records', | ||
| 25 | + tooltip: 'All room payment record details' | ||
| 26 | + }, | ||
| 27 | + table: { | ||
| 28 | + orderId: 'Order No', | ||
| 29 | + payerInfo: 'Room/Owner', | ||
| 30 | + feeInfo: 'Fee Type>Fee Item', | ||
| 31 | + feeStatus: 'Fee Status', | ||
| 32 | + paymentMethod: 'Payment Method', | ||
| 33 | + feePeriod: 'Payment Period', | ||
| 34 | + paymentTime: 'Payment Time', | ||
| 35 | + cashier: 'Cashier', | ||
| 36 | + payableAmount: 'Payable/Receivable Amount(Yuan)', | ||
| 37 | + receivedAmount: 'Received Amount(Yuan)', | ||
| 38 | + withholdAmount: 'Account Deduction(Yuan)', | ||
| 39 | + discountAmount: 'Discount/Deduction Amount(Yuan)', | ||
| 40 | + giftAmount: 'Gift Amount(Yuan)', | ||
| 41 | + lateFee: 'Late Fee(Yuan)', | ||
| 42 | + area: 'Area(sqm)', | ||
| 43 | + parkingSpace: 'Parking Space', | ||
| 44 | + remark: 'Remark' | ||
| 45 | + }, | ||
| 46 | + summary: { | ||
| 47 | + subtotal: 'Subtotal', | ||
| 48 | + total: 'Total', | ||
| 49 | + receivable: 'Receivable', | ||
| 50 | + received: 'Received', | ||
| 51 | + discount: 'Discount', | ||
| 52 | + deduction: 'Deduction', | ||
| 53 | + gift: 'Gift', | ||
| 54 | + lateFee: 'Late Fee', | ||
| 55 | + yuan: 'Yuan', | ||
| 56 | + discountDesc: 'Discount amount: discount amount generated under discount rules and no arrears discount rules', | ||
| 57 | + deductionDesc: 'Deduction amount: deduction amount generated under deduction rules', | ||
| 58 | + giftDesc: 'Gift amount: payable amount of gift months under gift rules', | ||
| 59 | + lateFeeDesc: 'Late fee: default late fee generated under default late fee rules, additional late fee to be paid' | ||
| 60 | + }, | ||
| 61 | + allCommunities: 'All Communities', | ||
| 62 | + fetchError: 'Failed to fetch payment details', | ||
| 63 | + fetchCommunityError: 'Failed to fetch community list', | ||
| 64 | + exportSuccess: 'Export started successfully', | ||
| 65 | + exportError: 'Failed to export data' | ||
| 66 | + } | ||
| 67 | + }, | ||
| 68 | + zh: { | ||
| 69 | + adminPayFeeDetail: { | ||
| 70 | + search: { | ||
| 71 | + title: '查询条件', | ||
| 72 | + startTime: '缴费开始时间', | ||
| 73 | + startTimePlaceholder: '请选择缴费开始时间', | ||
| 74 | + endTime: '缴费结束时间', | ||
| 75 | + endTimePlaceholder: '请选择缴费结束时间', | ||
| 76 | + paymentMethod: '支付方式', | ||
| 77 | + paymentMethodPlaceholder: '请选择支付方式', | ||
| 78 | + feeStatus: '费用状态', | ||
| 79 | + feeStatusPlaceholder: '请选择费用状态', | ||
| 80 | + feeType: '费用类型', | ||
| 81 | + feeTypePlaceholder: '请选择费用类型', | ||
| 82 | + feeStartTime: '收费开始时间', | ||
| 83 | + feeStartTimePlaceholder: '请选择收费开始时间', | ||
| 84 | + feeEndTime: '收费结束时间', | ||
| 85 | + feeEndTimePlaceholder: '请选择收费结束时间', | ||
| 86 | + payerObjName: '房屋/车牌号', | ||
| 87 | + payerObjNamePlaceholder: '房屋编号或者车牌号' | ||
| 88 | + }, | ||
| 89 | + list: { | ||
| 90 | + title: '缴费记录', | ||
| 91 | + tooltip: '所有房屋缴费记录明细' | ||
| 92 | + }, | ||
| 93 | + table: { | ||
| 94 | + orderId: '订单号', | ||
| 95 | + payerInfo: '房号/业主', | ||
| 96 | + feeInfo: '费用类型>费用项', | ||
| 97 | + feeStatus: '费用状态', | ||
| 98 | + paymentMethod: '支付方式', | ||
| 99 | + feePeriod: '缴费时间段', | ||
| 100 | + paymentTime: '缴费时间', | ||
| 101 | + cashier: '收银员', | ||
| 102 | + payableAmount: '应缴/应收金额(元)', | ||
| 103 | + receivedAmount: '实收金额(元)', | ||
| 104 | + withholdAmount: '账户抵扣(元)', | ||
| 105 | + discountAmount: '优惠/减免金额(元)', | ||
| 106 | + giftAmount: '赠送金额(元)', | ||
| 107 | + lateFee: '滞纳金(元)', | ||
| 108 | + area: '面积(平方米)', | ||
| 109 | + parkingSpace: '车位', | ||
| 110 | + remark: '说明' | ||
| 111 | + }, | ||
| 112 | + summary: { | ||
| 113 | + subtotal: '小计', | ||
| 114 | + total: '大计', | ||
| 115 | + receivable: '应收', | ||
| 116 | + received: '实收', | ||
| 117 | + discount: '优惠', | ||
| 118 | + deduction: '减免', | ||
| 119 | + gift: '赠送', | ||
| 120 | + lateFee: '滞纳金', | ||
| 121 | + yuan: '元', | ||
| 122 | + discountDesc: '优惠金额:打折规则和打折无欠费规则下产生的优惠金额', | ||
| 123 | + deductionDesc: '减免金额:减免规则下产生的减免金额', | ||
| 124 | + giftDesc: '赠送金额:赠送规则下赠送月份应缴的金额', | ||
| 125 | + lateFeeDesc: '滞纳金:违约滞纳金规则下产生的违约金额,需额外缴纳的滞纳金' | ||
| 126 | + }, | ||
| 127 | + allCommunities: '全部小区', | ||
| 128 | + fetchError: '获取缴费明细失败', | ||
| 129 | + fetchCommunityError: '获取小区列表失败', | ||
| 130 | + exportSuccess: '导出成功', | ||
| 131 | + exportError: '导出失败' | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | +} | ||
| 0 | \ No newline at end of file | 135 | \ No newline at end of file |
src/views/fee/adminPayFeeDetailList.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="admin-pay-fee-detail-container animated fadeInRight"> | ||
| 3 | + <el-row :gutter="20"> | ||
| 4 | + <el-col :span="4"> | ||
| 5 | + <select-admin-community ref="selectCommunity" @changeCommunity="handleCommunityChange" /> | ||
| 6 | + </el-col> | ||
| 7 | + <el-col :span="20"> | ||
| 8 | + <el-card> | ||
| 9 | + <div slot="header" class="clearfix flex justify-between"> | ||
| 10 | + <span>{{ $t('adminPayFeeDetail.search.title') }}</span> | ||
| 11 | + </div> | ||
| 12 | + <el-form :model="searchForm" label-width="auto"> | ||
| 13 | + <el-row :gutter="20"> | ||
| 14 | + <el-col :span="6"> | ||
| 15 | + <el-form-item :label="$t('adminPayFeeDetail.search.startTime')"> | ||
| 16 | + <el-date-picker v-model="searchForm.startTime" type="datetime" | ||
| 17 | + :placeholder="$t('adminPayFeeDetail.search.startTimePlaceholder')" style="width: 100%" /> | ||
| 18 | + </el-form-item> | ||
| 19 | + </el-col> | ||
| 20 | + <el-col :span="6"> | ||
| 21 | + <el-form-item :label="$t('adminPayFeeDetail.search.endTime')"> | ||
| 22 | + <el-date-picker v-model="searchForm.endTime" type="datetime" | ||
| 23 | + :placeholder="$t('adminPayFeeDetail.search.endTimePlaceholder')" style="width: 100%" /> | ||
| 24 | + </el-form-item> | ||
| 25 | + </el-col> | ||
| 26 | + <el-col :span="6"> | ||
| 27 | + <el-form-item :label="$t('adminPayFeeDetail.search.paymentMethod')"> | ||
| 28 | + <el-select v-model="searchForm.primeRate" | ||
| 29 | + :placeholder="$t('adminPayFeeDetail.search.paymentMethodPlaceholder')" style="width: 100%"> | ||
| 30 | + <el-option v-for="item in paymentMethods" :key="item.statusCd" :label="item.name" | ||
| 31 | + :value="item.statusCd" /> | ||
| 32 | + </el-select> | ||
| 33 | + </el-form-item> | ||
| 34 | + </el-col> | ||
| 35 | + <el-col :span="6"> | ||
| 36 | + <el-form-item :label="$t('adminPayFeeDetail.search.feeStatus')"> | ||
| 37 | + <el-select v-model="searchForm.state" :placeholder="$t('adminPayFeeDetail.search.feeStatusPlaceholder')" | ||
| 38 | + style="width: 100%"> | ||
| 39 | + <el-option v-for="item in feeStatuses" :key="item.statusCd" :label="item.name" | ||
| 40 | + :value="item.statusCd" /> | ||
| 41 | + </el-select> | ||
| 42 | + </el-form-item> | ||
| 43 | + </el-col> | ||
| 44 | + </el-row> | ||
| 45 | + <el-row :gutter="20"> | ||
| 46 | + <el-col :span="6"> | ||
| 47 | + <el-form-item :label="$t('adminPayFeeDetail.search.feeType')"> | ||
| 48 | + <el-select v-model="searchForm.feeTypeCd" | ||
| 49 | + :placeholder="$t('adminPayFeeDetail.search.feeTypePlaceholder')" style="width: 100%"> | ||
| 50 | + <el-option v-for="item in feeTypes" :key="item.statusCd" :label="item.name" :value="item.statusCd" /> | ||
| 51 | + </el-select> | ||
| 52 | + </el-form-item> | ||
| 53 | + </el-col> | ||
| 54 | + <el-col :span="6"> | ||
| 55 | + <el-form-item :label="$t('adminPayFeeDetail.search.feeStartTime')"> | ||
| 56 | + <el-date-picker v-model="searchForm.feeStartTime" type="datetime" | ||
| 57 | + :placeholder="$t('adminPayFeeDetail.search.feeStartTimePlaceholder')" style="width: 100%" /> | ||
| 58 | + </el-form-item> | ||
| 59 | + </el-col> | ||
| 60 | + <el-col :span="6"> | ||
| 61 | + <el-form-item :label="$t('adminPayFeeDetail.search.feeEndTime')"> | ||
| 62 | + <el-date-picker v-model="searchForm.feeEndTime" type="datetime" | ||
| 63 | + :placeholder="$t('adminPayFeeDetail.search.feeEndTimePlaceholder')" style="width: 100%" /> | ||
| 64 | + </el-form-item> | ||
| 65 | + </el-col> | ||
| 66 | + <el-col :span="6"> | ||
| 67 | + <el-form-item :label="$t('adminPayFeeDetail.search.payerObjName')"> | ||
| 68 | + <el-input v-model="searchForm.payerObjName" | ||
| 69 | + :placeholder="$t('adminPayFeeDetail.search.payerObjNamePlaceholder')" /> | ||
| 70 | + </el-form-item> | ||
| 71 | + </el-col> | ||
| 72 | + </el-row> | ||
| 73 | + <el-row> | ||
| 74 | + <el-col :span="24" style="text-align: right"> | ||
| 75 | + <el-button type="primary" @click="handleSearch">{{ $t('common.search') }}</el-button> | ||
| 76 | + <el-button @click="handleReset">{{ $t('common.reset') }}</el-button> | ||
| 77 | + </el-col> | ||
| 78 | + </el-row> | ||
| 79 | + </el-form> | ||
| 80 | + </el-card> | ||
| 81 | + | ||
| 82 | + <el-card style="margin-top: 20px"> | ||
| 83 | + <div slot="header" class="text-left"> | ||
| 84 | + <span>{{ $t('adminPayFeeDetail.list.title') }}</span> | ||
| 85 | + <el-tooltip :content="$t('adminPayFeeDetail.list.tooltip')" placement="top"> | ||
| 86 | + <i class="el-icon-info" style="margin-left: 10px; cursor: pointer" /> | ||
| 87 | + </el-tooltip> | ||
| 88 | + <div style="float: right"> | ||
| 89 | + <el-button type="primary" size="small" @click="handleExport"> | ||
| 90 | + {{ $t('common.export') }} | ||
| 91 | + </el-button> | ||
| 92 | + </div> | ||
| 93 | + </div> | ||
| 94 | + <el-table :data="tableData" border style="width: 100%"> | ||
| 95 | + <el-table-column prop="oId" :label="$t('adminPayFeeDetail.table.orderId')" align="center" /> | ||
| 96 | + <el-table-column :label="$t('adminPayFeeDetail.table.payerInfo')" align="center" width="150"> | ||
| 97 | + <template slot-scope="scope"> | ||
| 98 | + <div>{{ scope.row.payerObjName }}/{{ scope.row.ownerName }}</div> | ||
| 99 | + <div>{{ scope.row.communityName }}</div> | ||
| 100 | + </template> | ||
| 101 | + </el-table-column> | ||
| 102 | + <el-table-column :label="$t('adminPayFeeDetail.table.feeInfo')" align="center"> | ||
| 103 | + <template slot-scope="scope"> | ||
| 104 | + {{ scope.row.feeTypeCdName }}>{{ scope.row.feeName }} | ||
| 105 | + </template> | ||
| 106 | + </el-table-column> | ||
| 107 | + <el-table-column prop="stateName" :label="$t('adminPayFeeDetail.table.feeStatus')" align="center" /> | ||
| 108 | + <el-table-column prop="primeRate" :label="$t('adminPayFeeDetail.table.paymentMethod')" align="center" /> | ||
| 109 | + <el-table-column :label="$t('adminPayFeeDetail.table.feePeriod')" align="center" width="150"> | ||
| 110 | + <template slot-scope="scope"> | ||
| 111 | + <div>{{ formatDate(scope.row.startTime) }}</div> | ||
| 112 | + <div>~</div> | ||
| 113 | + <div>{{ formatDate(scope.row.endTime) }}</div> | ||
| 114 | + </template> | ||
| 115 | + </el-table-column> | ||
| 116 | + <el-table-column prop="createTime" :label="$t('adminPayFeeDetail.table.paymentTime')" align="center" /> | ||
| 117 | + <el-table-column prop="cashierName" :label="$t('adminPayFeeDetail.table.cashier')" align="center" /> | ||
| 118 | + <el-table-column :label="$t('adminPayFeeDetail.table.payableAmount')" align="center"> | ||
| 119 | + <template slot-scope="scope"> | ||
| 120 | + {{ scope.row.payableAmount }}/{{ scope.row.receivableAmount }} | ||
| 121 | + </template> | ||
| 122 | + </el-table-column> | ||
| 123 | + <el-table-column prop="receivedAmount" :label="$t('adminPayFeeDetail.table.receivedAmount')" align="center" /> | ||
| 124 | + <el-table-column prop="withholdAmount" :label="$t('adminPayFeeDetail.table.withholdAmount')" align="center" /> | ||
| 125 | + <el-table-column :label="$t('adminPayFeeDetail.table.discountAmount')" align="center"> | ||
| 126 | + <template slot-scope="scope"> | ||
| 127 | + {{ scope.row.preferentialAmount }}/{{ scope.row.deductionAmount }} | ||
| 128 | + </template> | ||
| 129 | + </el-table-column> | ||
| 130 | + <el-table-column prop="giftAmount" :label="$t('adminPayFeeDetail.table.giftAmount')" align="center" /> | ||
| 131 | + <el-table-column prop="lateFee" :label="$t('adminPayFeeDetail.table.lateFee')" align="center" /> | ||
| 132 | + <el-table-column prop="builtUpArea" :label="$t('adminPayFeeDetail.table.area')" align="center" /> | ||
| 133 | + <el-table-column prop="psName" :label="$t('adminPayFeeDetail.table.parkingSpace')" align="center" /> | ||
| 134 | + <el-table-column prop="remark" :label="$t('adminPayFeeDetail.table.remark')" align="center" width="200" /> | ||
| 135 | + </el-table> | ||
| 136 | + | ||
| 137 | + <div style="margin-top: 20px"> | ||
| 138 | + <el-row> | ||
| 139 | + <el-col :span="2"> | ||
| 140 | + <div>{{ $t('adminPayFeeDetail.summary.subtotal') }}</div> | ||
| 141 | + <div>{{ $t('adminPayFeeDetail.summary.total') }}</div> | ||
| 142 | + </el-col> | ||
| 143 | + <el-col :span="2"> | ||
| 144 | + <div> | ||
| 145 | + {{ $t('adminPayFeeDetail.summary.receivable') }}: {{ summary.totalReceivableAmount }} | ||
| 146 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 147 | + </div> | ||
| 148 | + <div> | ||
| 149 | + {{ $t('adminPayFeeDetail.summary.receivable') }}: {{ summary.allReceivableAmount }} | ||
| 150 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 151 | + </div> | ||
| 152 | + </el-col> | ||
| 153 | + <el-col :span="2"> | ||
| 154 | + <div> | ||
| 155 | + {{ $t('adminPayFeeDetail.summary.received') }}: {{ summary.totalReceivedAmount }} | ||
| 156 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 157 | + </div> | ||
| 158 | + <div> | ||
| 159 | + {{ $t('adminPayFeeDetail.summary.received') }}: {{ summary.allReceivedAmount }} | ||
| 160 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 161 | + </div> | ||
| 162 | + </el-col> | ||
| 163 | + <el-col :span="2"> | ||
| 164 | + <div> | ||
| 165 | + {{ $t('adminPayFeeDetail.summary.discount') }}: {{ summary.totalPreferentialAmount }} | ||
| 166 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 167 | + </div> | ||
| 168 | + <div> | ||
| 169 | + {{ $t('adminPayFeeDetail.summary.discount') }}: {{ summary.allPreferentialAmount }} | ||
| 170 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 171 | + </div> | ||
| 172 | + </el-col> | ||
| 173 | + <el-col :span="2"> | ||
| 174 | + <div> | ||
| 175 | + {{ $t('adminPayFeeDetail.summary.deduction') }}: {{ summary.totalDeductionAmount }} | ||
| 176 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 177 | + </div> | ||
| 178 | + <div> | ||
| 179 | + {{ $t('adminPayFeeDetail.summary.deduction') }}: {{ summary.allDeductionAmount }} | ||
| 180 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 181 | + </div> | ||
| 182 | + </el-col> | ||
| 183 | + <el-col :span="2"> | ||
| 184 | + <div> | ||
| 185 | + {{ $t('adminPayFeeDetail.summary.gift') }}: {{ summary.totalGiftAmount }} | ||
| 186 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 187 | + </div> | ||
| 188 | + <div> | ||
| 189 | + {{ $t('adminPayFeeDetail.summary.gift') }}: {{ summary.allGiftAmount }} | ||
| 190 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 191 | + </div> | ||
| 192 | + </el-col> | ||
| 193 | + <el-col :span="2"> | ||
| 194 | + <div> | ||
| 195 | + {{ $t('adminPayFeeDetail.summary.lateFee') }}: {{ summary.totalLateFee }} | ||
| 196 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 197 | + </div> | ||
| 198 | + <div> | ||
| 199 | + {{ $t('adminPayFeeDetail.summary.lateFee') }}: {{ summary.allLateFee }} | ||
| 200 | + {{ $t('adminPayFeeDetail.summary.yuan') }} | ||
| 201 | + </div> | ||
| 202 | + </el-col> | ||
| 203 | + </el-row> | ||
| 204 | + </div> | ||
| 205 | + | ||
| 206 | + <div style="margin-top: 20px" class="text-left"> | ||
| 207 | + <el-row> | ||
| 208 | + <el-col :span="18"> | ||
| 209 | + <div>{{ $t('adminPayFeeDetail.summary.discountDesc') }}</div> | ||
| 210 | + <div>{{ $t('adminPayFeeDetail.summary.deductionDesc') }}</div> | ||
| 211 | + <div>{{ $t('adminPayFeeDetail.summary.giftDesc') }}</div> | ||
| 212 | + <div>{{ $t('adminPayFeeDetail.summary.lateFeeDesc') }}</div> | ||
| 213 | + </el-col> | ||
| 214 | + <el-col :span="6"> | ||
| 215 | + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" | ||
| 216 | + :page-size="pagination.size" :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" | ||
| 217 | + @size-change="handleSizeChange" @current-change="handleCurrentChange" /> | ||
| 218 | + </el-col> | ||
| 219 | + </el-row> | ||
| 220 | + </div> | ||
| 221 | + </el-card> | ||
| 222 | + </el-col> | ||
| 223 | + </el-row> | ||
| 224 | + </div> | ||
| 225 | +</template> | ||
| 226 | + | ||
| 227 | +<script> | ||
| 228 | +import { queryAdminPayFeeDetail, exportFeeData } from '@/api/fee/adminPayFeeDetailApi' | ||
| 229 | +import SelectAdminCommunity from '@/components/community/selectAdminCommunity' | ||
| 230 | +import { getDict } from '@/api/community/communityApi' | ||
| 231 | +import {dateFormat} from '@/utils/dateUtil' | ||
| 232 | + | ||
| 233 | +export default { | ||
| 234 | + name: 'AdminPayFeeDetailList', | ||
| 235 | + components: { | ||
| 236 | + SelectAdminCommunity | ||
| 237 | + }, | ||
| 238 | + data() { | ||
| 239 | + return { | ||
| 240 | + searchForm: { | ||
| 241 | + communityId: '', | ||
| 242 | + floorId: '', | ||
| 243 | + roomNum: '', | ||
| 244 | + payerObjName: '', | ||
| 245 | + configId: '', | ||
| 246 | + primeRate: '', | ||
| 247 | + state: '', | ||
| 248 | + feeTypeCd: '', | ||
| 249 | + startTime: '', | ||
| 250 | + endTime: '', | ||
| 251 | + feeStartTime: '', | ||
| 252 | + feeEndTime: '', | ||
| 253 | + page: 1, | ||
| 254 | + row: 10 | ||
| 255 | + }, | ||
| 256 | + tableData: [], | ||
| 257 | + paymentMethods: [], | ||
| 258 | + feeStatuses: [], | ||
| 259 | + feeTypes: [], | ||
| 260 | + summary: { | ||
| 261 | + totalReceivableAmount: '0.00', | ||
| 262 | + totalReceivedAmount: '0.00', | ||
| 263 | + allReceivableAmount: '0.00', | ||
| 264 | + allReceivedAmount: '0.00', | ||
| 265 | + totalPreferentialAmount: '0.00', | ||
| 266 | + totalDeductionAmount: '0.00', | ||
| 267 | + totalLateFee: '0.00', | ||
| 268 | + totalVacantHousingDiscount: '0.00', | ||
| 269 | + totalVacantHousingReduction: '0.00', | ||
| 270 | + totalNoDeduction: '0.00', | ||
| 271 | + totalCashDeduction: '0.00', | ||
| 272 | + totalPointDeduction: '0.00', | ||
| 273 | + totalDiscountCouponDeduction: '0.00', | ||
| 274 | + allPreferentialAmount: '0.00', | ||
| 275 | + allDeductionAmount: '0.00', | ||
| 276 | + allLateFee: '0.00', | ||
| 277 | + allVacantHousingDiscount: '0.00', | ||
| 278 | + allVacantHousingReduction: '0.00', | ||
| 279 | + allGiftAmount: '0.00', | ||
| 280 | + allNoDeduction: '0.00', | ||
| 281 | + allCashDeduction: '0.00', | ||
| 282 | + allPointDeduction: '0.00', | ||
| 283 | + allDiscountCouponDeduction: '0.00', | ||
| 284 | + totalGiftAmount: '0.00' | ||
| 285 | + }, | ||
| 286 | + pagination: { | ||
| 287 | + current: 1, | ||
| 288 | + size: 10, | ||
| 289 | + total: 0 | ||
| 290 | + } | ||
| 291 | + } | ||
| 292 | + }, | ||
| 293 | + created() { | ||
| 294 | + this.loadDictData() | ||
| 295 | + this.fetchData() | ||
| 296 | + }, | ||
| 297 | + methods: { | ||
| 298 | + async loadDictData() { | ||
| 299 | + this.paymentMethods = await getDict('pay_fee_detail', 'prime_rate') | ||
| 300 | + this.feeStatuses = await getDict('pay_fee_detail', 'state') | ||
| 301 | + this.feeTypes = await getDict('pay_fee_config', 'fee_type_cd') | ||
| 302 | + }, | ||
| 303 | + async fetchData() { | ||
| 304 | + try { | ||
| 305 | + const params = { ...this.searchForm } | ||
| 306 | + const { data, total, sumTotal } = await queryAdminPayFeeDetail(params) | ||
| 307 | + | ||
| 308 | + this.tableData = data.map(item => ({ | ||
| 309 | + ...item, | ||
| 310 | + lateFee: (item.lateFee * -1).toFixed(2) | ||
| 311 | + })) | ||
| 312 | + | ||
| 313 | + this.pagination.total = total | ||
| 314 | + this.updateSummary(sumTotal) | ||
| 315 | + } catch (error) { | ||
| 316 | + //this.$message.error(this.$t('adminPayFeeDetail.fetchError')) | ||
| 317 | + } | ||
| 318 | + }, | ||
| 319 | + updateSummary(sumTotal) { | ||
| 320 | + const defaultZero = '0.00' | ||
| 321 | + | ||
| 322 | + this.summary = { | ||
| 323 | + totalReceivableAmount: sumTotal.totalReceivableAmount || defaultZero, | ||
| 324 | + totalReceivedAmount: sumTotal.totalReceivedAmount || defaultZero, | ||
| 325 | + allReceivableAmount: sumTotal.allReceivableAmount || defaultZero, | ||
| 326 | + allReceivedAmount: sumTotal.allReceivedAmount || defaultZero, | ||
| 327 | + totalPreferentialAmount: sumTotal.totalPreferentialAmount || defaultZero, | ||
| 328 | + totalDeductionAmount: sumTotal.totalDeductionAmount || defaultZero, | ||
| 329 | + totalLateFee: sumTotal.totalLateFee ? (sumTotal.totalLateFee * -1).toFixed(2) : defaultZero, | ||
| 330 | + allPreferentialAmount: sumTotal.allPreferentialAmount || defaultZero, | ||
| 331 | + allDeductionAmount: sumTotal.allDeductionAmount || defaultZero, | ||
| 332 | + allLateFee: sumTotal.allLateFee ? (sumTotal.allLateFee * -1).toFixed(2) : defaultZero, | ||
| 333 | + allGiftAmount: sumTotal.allGiftAmount || defaultZero, | ||
| 334 | + totalGiftAmount: sumTotal.totalGiftAmount || defaultZero | ||
| 335 | + } | ||
| 336 | + }, | ||
| 337 | + handleSearch() { | ||
| 338 | + this.searchForm.page = 1 | ||
| 339 | + this.fetchData() | ||
| 340 | + }, | ||
| 341 | + handleReset() { | ||
| 342 | + this.searchForm = { | ||
| 343 | + communityId: this.searchForm.communityId, | ||
| 344 | + floorId: '', | ||
| 345 | + roomNum: '', | ||
| 346 | + payerObjName: '', | ||
| 347 | + configId: '', | ||
| 348 | + primeRate: '', | ||
| 349 | + state: '', | ||
| 350 | + feeTypeCd: '', | ||
| 351 | + startTime: '', | ||
| 352 | + endTime: '', | ||
| 353 | + feeStartTime: '', | ||
| 354 | + feeEndTime: '', | ||
| 355 | + page: 1, | ||
| 356 | + row: this.searchForm.row | ||
| 357 | + } | ||
| 358 | + this.fetchData() | ||
| 359 | + }, | ||
| 360 | + handleCommunityChange(community) { | ||
| 361 | + this.searchForm.communityId = community.communityId | ||
| 362 | + this.fetchData() | ||
| 363 | + }, | ||
| 364 | + handleSizeChange(size) { | ||
| 365 | + this.searchForm.row = size | ||
| 366 | + this.fetchData() | ||
| 367 | + }, | ||
| 368 | + handleCurrentChange(page) { | ||
| 369 | + this.searchForm.page = page | ||
| 370 | + this.fetchData() | ||
| 371 | + }, | ||
| 372 | + async handleExport() { | ||
| 373 | + try { | ||
| 374 | + const params = { | ||
| 375 | + ...this.searchForm, | ||
| 376 | + pagePath: 'adminPayFeeDetail' | ||
| 377 | + } | ||
| 378 | + await exportFeeData(params) | ||
| 379 | + this.$message.success(this.$t('adminPayFeeDetail.exportSuccess')) | ||
| 380 | + // 这里可以添加跳转到下载页面的逻辑 | ||
| 381 | + // this.$router.push('/pages/property/downloadTempFile?tab=下载中心') | ||
| 382 | + } catch (error) { | ||
| 383 | + this.$message.error(this.$t('adminPayFeeDetail.exportError')) | ||
| 384 | + } | ||
| 385 | + }, | ||
| 386 | + formatDate(date) { | ||
| 387 | + if (!date) return '-' | ||
| 388 | + return dateFormat(date) | ||
| 389 | + } | ||
| 390 | + } | ||
| 391 | +} | ||
| 392 | +</script> | ||
| 393 | + | ||
| 394 | +<style lang="scss" scoped> | ||
| 395 | +.admin-pay-fee-detail-container { | ||
| 396 | + padding: 20px; | ||
| 397 | + | ||
| 398 | + .el-card { | ||
| 399 | + margin-bottom: 20px; | ||
| 400 | + | ||
| 401 | + .el-card__header { | ||
| 402 | + font-weight: bold; | ||
| 403 | + background-color: #f5f7fa; | ||
| 404 | + } | ||
| 405 | + } | ||
| 406 | + | ||
| 407 | + .el-table { | ||
| 408 | + margin-top: 20px; | ||
| 409 | + | ||
| 410 | + .cell { | ||
| 411 | + white-space: pre-line; | ||
| 412 | + } | ||
| 413 | + } | ||
| 414 | + | ||
| 415 | + .el-pagination { | ||
| 416 | + margin-top: 20px; | ||
| 417 | + text-align: right; | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + .summary-row { | ||
| 421 | + margin-top: 20px; | ||
| 422 | + padding: 10px; | ||
| 423 | + background-color: #f5f7fa; | ||
| 424 | + border-radius: 4px; | ||
| 425 | + | ||
| 426 | + .summary-item { | ||
| 427 | + margin-right: 20px; | ||
| 428 | + } | ||
| 429 | + } | ||
| 430 | +} | ||
| 431 | +</style> | ||
| 0 | \ No newline at end of file | 432 | \ No newline at end of file |
src/views/report/communityFeeSummaryLang.js
0 → 100644
| 1 | +export const messages = { | ||
| 2 | + en: { | ||
| 3 | + communityFeeSummary: { | ||
| 4 | + search: { | ||
| 5 | + title: 'Search Conditions', | ||
| 6 | + startDate: 'Start Date', | ||
| 7 | + endDate: 'End Date', | ||
| 8 | + feeType: 'Fee Type', | ||
| 9 | + selectFeeType: 'Please select fee type', | ||
| 10 | + allCommunities: 'All Communities' | ||
| 11 | + }, | ||
| 12 | + table: { | ||
| 13 | + title: 'Fee Summary Report', | ||
| 14 | + tooltip: 'Summarize fee information by month', | ||
| 15 | + updateDaily: 'Updated daily', | ||
| 16 | + totalRooms: 'Total Rooms', | ||
| 17 | + feeRooms: 'Fee Rooms', | ||
| 18 | + oweRooms: 'Owe Rooms', | ||
| 19 | + oweFeeFormula: 'History Owe + Current Owe = Total Owe', | ||
| 20 | + hisOweFee: 'History Owe', | ||
| 21 | + curOweFee: 'Current Owe', | ||
| 22 | + totalOweFee: 'Total Owe', | ||
| 23 | + receivedFeeFormula: 'Owe Recovery + Current Partial + Prepayment = Actual Payment', | ||
| 24 | + hisReceivedFee: 'Owe Recovery', | ||
| 25 | + curPartialFee: 'Current Partial', | ||
| 26 | + preReceivedFee: 'Prepayment', | ||
| 27 | + totalReceivedFee: 'Actual Payment', | ||
| 28 | + curReceivableFee: 'Current Receivable', | ||
| 29 | + curReceivedFee: 'Current Received', | ||
| 30 | + roomFeeRate: 'Paid Rooms/Fee Rooms = Room Fee Rate', | ||
| 31 | + feeRate: 'Current Received/Current Receivable = Fee Rate', | ||
| 32 | + clearRate: 'Owe Recovery/(Owe Recovery + History Owe) = Clear Rate' | ||
| 33 | + }, | ||
| 34 | + fetchError: 'Failed to fetch fee summary data' | ||
| 35 | + } | ||
| 36 | + }, | ||
| 37 | + zh: { | ||
| 38 | + communityFeeSummary: { | ||
| 39 | + search: { | ||
| 40 | + title: '查询条件', | ||
| 41 | + startDate: '开始时间', | ||
| 42 | + endDate: '结束时间', | ||
| 43 | + feeType: '费用大类', | ||
| 44 | + selectFeeType: '请选择费用大类', | ||
| 45 | + allCommunities: '全部小区' | ||
| 46 | + }, | ||
| 47 | + table: { | ||
| 48 | + title: '费用汇总表', | ||
| 49 | + tooltip: '以月份为维度,进行费用情况汇总', | ||
| 50 | + updateDaily: '按天更新', | ||
| 51 | + totalRooms: '总户数', | ||
| 52 | + feeRooms: '收费户', | ||
| 53 | + oweRooms: '欠费户', | ||
| 54 | + oweFeeFormula: '历史欠费+当期欠费=欠费', | ||
| 55 | + hisOweFee: '历史欠费', | ||
| 56 | + curOweFee: '当期欠费', | ||
| 57 | + totalOweFee: '总欠费', | ||
| 58 | + receivedFeeFormula: '欠费追回+当期部分+预交=实缴', | ||
| 59 | + hisReceivedFee: '欠费追回', | ||
| 60 | + curPartialFee: '当期部分', | ||
| 61 | + preReceivedFee: '预交', | ||
| 62 | + totalReceivedFee: '实缴', | ||
| 63 | + curReceivableFee: '当期应收', | ||
| 64 | + curReceivedFee: '当期实收', | ||
| 65 | + roomFeeRate: '已交户/收费户=户收费率', | ||
| 66 | + feeRate: '当期实收/当期应收=收费率', | ||
| 67 | + clearRate: '欠费追回/(欠费追回+历史欠费)=清缴率' | ||
| 68 | + }, | ||
| 69 | + fetchError: '获取费用汇总数据失败' | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | +} | ||
| 0 | \ No newline at end of file | 73 | \ No newline at end of file |
src/views/report/communityFeeSummaryList.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="community-fee-summary-container"> | ||
| 3 | + <el-row class="animated fadeInRight" :gutter="20"> | ||
| 4 | + <el-col :span="4"> | ||
| 5 | + <select-admin-community @changeCommunity="handleCommunityChange" /> | ||
| 6 | + </el-col> | ||
| 7 | + <el-col :span="20"> | ||
| 8 | + <el-card class="box-card"> | ||
| 9 | + <div slot="header" class="clearfix flex justify-between"> | ||
| 10 | + <span>{{ $t('communityFeeSummary.search.title') }}</span> | ||
| 11 | + </div> | ||
| 12 | + <el-row :gutter="20"> | ||
| 13 | + <el-col :span="6"> | ||
| 14 | + <el-date-picker v-model="searchForm.startDate" type="date" | ||
| 15 | + :placeholder="$t('communityFeeSummary.search.startDate')" class="w-100" /> | ||
| 16 | + </el-col> | ||
| 17 | + <el-col :span="6"> | ||
| 18 | + <el-date-picker v-model="searchForm.endDate" type="date" | ||
| 19 | + :placeholder="$t('communityFeeSummary.search.endDate')" class="w-100" /> | ||
| 20 | + </el-col> | ||
| 21 | + <el-col :span="6"> | ||
| 22 | + <el-select v-model="searchForm.feeTypeCd" :placeholder="$t('communityFeeSummary.search.feeType')" | ||
| 23 | + class="w-100"> | ||
| 24 | + <el-option :label="$t('communityFeeSummary.search.selectFeeType')" value="" /> | ||
| 25 | + <el-option v-for="item in feeTypeOptions" :key="item.statusCd" :label="item.name" | ||
| 26 | + :value="item.statusCd" /> | ||
| 27 | + </el-select> | ||
| 28 | + </el-col> | ||
| 29 | + <el-col :span="6"> | ||
| 30 | + <el-button type="primary" @click="handleSearch"> | ||
| 31 | + {{ $t('common.search') }} | ||
| 32 | + </el-button> | ||
| 33 | + </el-col> | ||
| 34 | + </el-row> | ||
| 35 | + </el-card> | ||
| 36 | + | ||
| 37 | + <el-card class="box-card mt-20"> | ||
| 38 | + <div slot="header" class="clearfix text-left"> | ||
| 39 | + <span>{{ $t('communityFeeSummary.table.title') }}</span> | ||
| 40 | + <el-tooltip effect="dark" :content="$t('communityFeeSummary.table.tooltip')" placement="top"> | ||
| 41 | + <i class="el-icon-info" style="cursor: pointer;"></i> | ||
| 42 | + </el-tooltip> | ||
| 43 | + <span style="font-size: 10px;">({{ $t('communityFeeSummary.table.updateDaily') }})</span> | ||
| 44 | + </div> | ||
| 45 | + <el-table :data="tableData" border style="width: 100%"> | ||
| 46 | + <el-table-column prop="roomCount" :label="$t('communityFeeSummary.table.totalRooms')" align="center" /> | ||
| 47 | + <el-table-column prop="feeRoomCount" :label="$t('communityFeeSummary.table.feeRooms')" align="center" /> | ||
| 48 | + <el-table-column prop="oweRoomCount" :label="$t('communityFeeSummary.table.oweRooms')" align="center" /> | ||
| 49 | + <el-table-column :label="$t('communityFeeSummary.table.oweFeeFormula')" align="center"> | ||
| 50 | + <el-table-column prop="hisOweFee" :label="$t('communityFeeSummary.table.hisOweFee')" align="center" /> | ||
| 51 | + <el-table-column prop="curOweFee" :label="$t('communityFeeSummary.table.curOweFee')" align="center" /> | ||
| 52 | + <el-table-column :label="$t('communityFeeSummary.table.totalOweFee')" align="center"> | ||
| 53 | + <template slot-scope="scope"> | ||
| 54 | + {{ (scope.row.curOweFee + scope.row.hisOweFee).toFixed(2) }} | ||
| 55 | + </template> | ||
| 56 | + </el-table-column> | ||
| 57 | + </el-table-column> | ||
| 58 | + <el-table-column :label="$t('communityFeeSummary.table.receivedFeeFormula')" align="center"> | ||
| 59 | + <el-table-column prop="hisReceivedFee" :label="$t('communityFeeSummary.table.hisReceivedFee')" | ||
| 60 | + align="center" /> | ||
| 61 | + <el-table-column :label="$t('communityFeeSummary.table.curPartialFee')" align="center"> | ||
| 62 | + <template slot-scope="scope"> | ||
| 63 | + {{ (scope.row.receivedFee - scope.row.hisReceivedFee - scope.row.preReceivedFee).toFixed(2) }} | ||
| 64 | + </template> | ||
| 65 | + </el-table-column> | ||
| 66 | + <el-table-column prop="preReceivedFee" :label="$t('communityFeeSummary.table.preReceivedFee')" | ||
| 67 | + align="center" /> | ||
| 68 | + <el-table-column prop="receivedFee" :label="$t('communityFeeSummary.table.totalReceivedFee')" | ||
| 69 | + align="center" /> | ||
| 70 | + </el-table-column> | ||
| 71 | + <el-table-column prop="curReceivableFee" :label="$t('communityFeeSummary.table.curReceivableFee')" | ||
| 72 | + align="center" /> | ||
| 73 | + <el-table-column :label="$t('communityFeeSummary.table.curReceivedFee')" align="center"> | ||
| 74 | + <template slot-scope="scope"> | ||
| 75 | + {{ (scope.row.curReceivableFee - scope.row.curOweFee).toFixed(2) }} | ||
| 76 | + </template> | ||
| 77 | + </el-table-column> | ||
| 78 | + <el-table-column :label="$t('communityFeeSummary.table.roomFeeRate')" align="center"> | ||
| 79 | + <template slot-scope="scope"> | ||
| 80 | + {{ scope.row.feeRoomCount > 0 ? | ||
| 81 | + (((scope.row.feeRoomCount - scope.row.oweRoomCount) / scope.row.feeRoomCount * 100).toFixed(2) + '%') : | ||
| 82 | + '0%' }} | ||
| 83 | + </template> | ||
| 84 | + </el-table-column> | ||
| 85 | + <el-table-column :label="$t('communityFeeSummary.table.feeRate')" align="center"> | ||
| 86 | + <template slot-scope="scope"> | ||
| 87 | + {{ scope.row.curReceivableFee > 0 ? | ||
| 88 | + (((scope.row.curReceivableFee - scope.row.curOweFee) / scope.row.curReceivableFee * 100).toFixed(2) + '%'): '0%' }} | ||
| 89 | + </template> | ||
| 90 | + </el-table-column> | ||
| 91 | + <el-table-column :label="$t('communityFeeSummary.table.clearRate')" align="center"> | ||
| 92 | + <template slot-scope="scope"> | ||
| 93 | + {{ (scope.row.hisReceivedFee + scope.row.hisOweFee) > 0 ? | ||
| 94 | + ((scope.row.hisReceivedFee / (scope.row.hisReceivedFee + scope.row.hisOweFee) * 100).toFixed(2) + '%') : | ||
| 95 | + '0%' }} | ||
| 96 | + </template> | ||
| 97 | + </el-table-column> | ||
| 98 | + </el-table> | ||
| 99 | + </el-card> | ||
| 100 | + </el-col> | ||
| 101 | + </el-row> | ||
| 102 | + </div> | ||
| 103 | +</template> | ||
| 104 | + | ||
| 105 | +<script> | ||
| 106 | +import { getCommunityFeeSummary } from '@/api/report/communityFeeSummaryApi' | ||
| 107 | +import SelectAdminCommunity from '@/components/community/selectAdminCommunity' | ||
| 108 | + | ||
| 109 | +export default { | ||
| 110 | + name: 'CommunityFeeSummaryList', | ||
| 111 | + components: { | ||
| 112 | + SelectAdminCommunity | ||
| 113 | + }, | ||
| 114 | + data() { | ||
| 115 | + return { | ||
| 116 | + searchForm: { | ||
| 117 | + startDate: '', | ||
| 118 | + endDate: '', | ||
| 119 | + feeTypeCd: '', | ||
| 120 | + communityId: '' | ||
| 121 | + }, | ||
| 122 | + feeTypeOptions: [], | ||
| 123 | + tableData: [], | ||
| 124 | + loading: false | ||
| 125 | + } | ||
| 126 | + }, | ||
| 127 | + created() { | ||
| 128 | + this.initDate() | ||
| 129 | + this.loadFeeTypes() | ||
| 130 | + }, | ||
| 131 | + methods: { | ||
| 132 | + initDate() { | ||
| 133 | + const today = new Date() | ||
| 134 | + const firstDay = new Date(today.getFullYear(), today.getMonth(), 1) | ||
| 135 | + const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0) | ||
| 136 | + | ||
| 137 | + this.searchForm.startDate = firstDay | ||
| 138 | + this.searchForm.endDate = lastDay | ||
| 139 | + }, | ||
| 140 | + loadFeeTypes() { | ||
| 141 | + this.$store.dispatch('dict/getDict', { | ||
| 142 | + dictType: 'pay_fee_config', | ||
| 143 | + dictName: 'fee_type_cd' | ||
| 144 | + }).then(data => { | ||
| 145 | + this.feeTypeOptions = data | ||
| 146 | + }) | ||
| 147 | + }, | ||
| 148 | + handleCommunityChange(community) { | ||
| 149 | + this.searchForm.communityId = community.communityId | ||
| 150 | + this.handleSearch() | ||
| 151 | + }, | ||
| 152 | + async handleSearch() { | ||
| 153 | + try { | ||
| 154 | + this.loading = true | ||
| 155 | + const params = { | ||
| 156 | + startDate: this.formatDate(this.searchForm.startDate), | ||
| 157 | + endDate: this.formatDate(this.searchForm.endDate), | ||
| 158 | + feeTypeCd: this.searchForm.feeTypeCd, | ||
| 159 | + communityId: this.searchForm.communityId | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + const { data } = await getCommunityFeeSummary(params) | ||
| 163 | + this.tableData = data | ||
| 164 | + } catch (error) { | ||
| 165 | + this.$message.error(this.$t('communityFeeSummary.fetchError')) | ||
| 166 | + } finally { | ||
| 167 | + this.loading = false | ||
| 168 | + } | ||
| 169 | + }, | ||
| 170 | + formatDate(date) { | ||
| 171 | + if (!date) return '' | ||
| 172 | + const d = new Date(date) | ||
| 173 | + let month = '' + (d.getMonth() + 1) | ||
| 174 | + let day = '' + d.getDate() | ||
| 175 | + const year = d.getFullYear() | ||
| 176 | + | ||
| 177 | + if (month.length < 2) month = '0' + month | ||
| 178 | + if (day.length < 2) day = '0' + day | ||
| 179 | + | ||
| 180 | + return [year, month, day].join('-') | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | +} | ||
| 184 | +</script> | ||
| 185 | + | ||
| 186 | +<style lang="scss" scoped> | ||
| 187 | +.community-fee-summary-container { | ||
| 188 | + padding: 20px; | ||
| 189 | + | ||
| 190 | + .box-card { | ||
| 191 | + margin-bottom: 20px; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + .mt-20 { | ||
| 195 | + margin-top: 20px; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + .w-100 { | ||
| 199 | + width: 100%; | ||
| 200 | + } | ||
| 201 | +} | ||
| 202 | +</style> | ||
| 0 | \ No newline at end of file | 203 | \ No newline at end of file |
src/views/report/operationalAnalysisLang.js
0 → 100644
| 1 | +export const messages = { | ||
| 2 | + en: { | ||
| 3 | + operationalAnalysis: { | ||
| 4 | + allCommunities: 'All Communities', | ||
| 5 | + fetchError: 'Failed to fetch operational analysis data', | ||
| 6 | + fetchCommunityError: 'Failed to fetch community list', | ||
| 7 | + chart: { | ||
| 8 | + payFee: 'Payment Orders', | ||
| 9 | + repair: 'Repair Orders', | ||
| 10 | + inspection: 'Inspections', | ||
| 11 | + maintainance: 'Maintenance', | ||
| 12 | + itemIn: 'Purchase Orders', | ||
| 13 | + itemOut: 'Withdrawal Orders', | ||
| 14 | + carIn: 'Vehicle Entries', | ||
| 15 | + personIn: 'Door Openings', | ||
| 16 | + contract: 'Contracts' | ||
| 17 | + } | ||
| 18 | + } | ||
| 19 | + }, | ||
| 20 | + zh: { | ||
| 21 | + operationalAnalysis: { | ||
| 22 | + allCommunities: '全部小区', | ||
| 23 | + fetchError: '获取运营分析数据失败', | ||
| 24 | + fetchCommunityError: '获取小区列表失败', | ||
| 25 | + chart: { | ||
| 26 | + payFee: '缴费订单数', | ||
| 27 | + repair: '报修订单数', | ||
| 28 | + inspection: '巡检数', | ||
| 29 | + maintainance: '保养数', | ||
| 30 | + itemIn: '采购订单数', | ||
| 31 | + itemOut: '领用订单数', | ||
| 32 | + carIn: '车辆进场数', | ||
| 33 | + personIn: '开门记录', | ||
| 34 | + contract: '签订合同数' | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | +} | ||
| 0 | \ No newline at end of file | 39 | \ No newline at end of file |
src/views/report/operationalAnalysisList.vue
0 → 100644
| 1 | +<template> | ||
| 2 | + <div class="operational-analysis-container"> | ||
| 3 | + <el-row class="animated fadeInRight ecommerce"> | ||
| 4 | + <el-col :span="4"> | ||
| 5 | + <select-admin-community @changeCommunity="handleCommunityChange" /> | ||
| 6 | + </el-col> | ||
| 7 | + <el-col :span="20"> | ||
| 8 | + <el-row> | ||
| 9 | + <el-col v-for="(chart, index) in charts" :key="index" :span="8" class="margin-bottom"> | ||
| 10 | + <el-card class="box-card"> | ||
| 11 | + <div :id="chart.id" style="width: 100%; height: 300px;"></div> | ||
| 12 | + </el-card> | ||
| 13 | + </el-col> | ||
| 14 | + </el-row> | ||
| 15 | + </el-col> | ||
| 16 | + </el-row> | ||
| 17 | + </div> | ||
| 18 | +</template> | ||
| 19 | + | ||
| 20 | +<script> | ||
| 21 | +import SelectAdminCommunity from '@/components/community/selectAdminCommunity' | ||
| 22 | +import { getCommunityOperationalAnalysis } from '@/api/report/operationalAnalysisApi' | ||
| 23 | +import * as echarts from 'echarts' | ||
| 24 | + | ||
| 25 | +export default { | ||
| 26 | + name: 'OperationalAnalysisList', | ||
| 27 | + components: { | ||
| 28 | + SelectAdminCommunity | ||
| 29 | + }, | ||
| 30 | + data() { | ||
| 31 | + return { | ||
| 32 | + charts: [ | ||
| 33 | + { id: 'communityPayFeeDetail', title: this.$t('operationalAnalysis.chart.payFee') }, | ||
| 34 | + { id: 'communityRepair', title: this.$t('operationalAnalysis.chart.repair') }, | ||
| 35 | + { id: 'communityInspection', title: this.$t('operationalAnalysis.chart.inspection') }, | ||
| 36 | + { id: 'communityMaintainance', title: this.$t('operationalAnalysis.chart.maintainance') }, | ||
| 37 | + { id: 'communityItemIn', title: this.$t('operationalAnalysis.chart.itemIn') }, | ||
| 38 | + { id: 'communityItemOut', title: this.$t('operationalAnalysis.chart.itemOut') }, | ||
| 39 | + { id: 'communityCarIn', title: this.$t('operationalAnalysis.chart.carIn') }, | ||
| 40 | + { id: 'communityPersonIn', title: this.$t('operationalAnalysis.chart.personIn') }, | ||
| 41 | + { id: 'communityContract', title: this.$t('operationalAnalysis.chart.contract') } | ||
| 42 | + ], | ||
| 43 | + communityId: '' | ||
| 44 | + } | ||
| 45 | + }, | ||
| 46 | + methods: { | ||
| 47 | + handleCommunityChange(community) { | ||
| 48 | + this.communityId = community.communityId | ||
| 49 | + this.loadOperationalAnalysisData() | ||
| 50 | + }, | ||
| 51 | + async loadOperationalAnalysisData() { | ||
| 52 | + try { | ||
| 53 | + const params = { | ||
| 54 | + communityId: this.communityId | ||
| 55 | + } | ||
| 56 | + const res = await getCommunityOperationalAnalysis(params) | ||
| 57 | + this.initCharts(res.data) | ||
| 58 | + } catch (error) { | ||
| 59 | + this.$message.error(this.$t('operationalAnalysis.fetchError')) | ||
| 60 | + } | ||
| 61 | + }, | ||
| 62 | + initCharts(data) { | ||
| 63 | + this.initAnalysisChart(data.feeDetailData, 'communityPayFeeDetail', this.$t('operationalAnalysis.chart.payFee'), this.$t('operationalAnalysis.chart.payFee')) | ||
| 64 | + this.initAnalysisChart(data.repairData, 'communityRepair', this.$t('operationalAnalysis.chart.repair'), this.$t('operationalAnalysis.chart.repair')) | ||
| 65 | + this.initAnalysisChart(data.inspectionData, 'communityInspection', this.$t('operationalAnalysis.chart.inspection'), this.$t('operationalAnalysis.chart.inspection')) | ||
| 66 | + this.initAnalysisChart(data.maintainanceData, 'communityMaintainance', this.$t('operationalAnalysis.chart.maintainance'), this.$t('operationalAnalysis.chart.maintainance')) | ||
| 67 | + this.initAnalysisChart(data.itemInData, 'communityItemIn', this.$t('operationalAnalysis.chart.itemIn'), this.$t('operationalAnalysis.chart.itemIn')) | ||
| 68 | + this.initAnalysisChart(data.itemOutData, 'communityItemOut', this.$t('operationalAnalysis.chart.itemOut'), this.$t('operationalAnalysis.chart.itemOut')) | ||
| 69 | + this.initAnalysisChart(data.carInData, 'communityCarIn', this.$t('operationalAnalysis.chart.carIn'), this.$t('operationalAnalysis.chart.carIn')) | ||
| 70 | + this.initAnalysisChart(data.personInData, 'communityPersonIn', this.$t('operationalAnalysis.chart.personIn'), this.$t('operationalAnalysis.chart.personIn')) | ||
| 71 | + this.initAnalysisChart(data.contractData, 'communityContract', this.$t('operationalAnalysis.chart.contract'), this.$t('operationalAnalysis.chart.contract')) | ||
| 72 | + }, | ||
| 73 | + initAnalysisChart(data, elementId, title, lineName) { | ||
| 74 | + const dom = document.getElementById(elementId) | ||
| 75 | + if (!dom) return | ||
| 76 | + | ||
| 77 | + const myChart = echarts.init(dom) | ||
| 78 | + const createTime = [] | ||
| 79 | + const countValues = [] | ||
| 80 | + | ||
| 81 | + data.forEach(item => { | ||
| 82 | + createTime.push(item.createTime) | ||
| 83 | + countValues.push(item.countValue) | ||
| 84 | + }) | ||
| 85 | + | ||
| 86 | + const option = { | ||
| 87 | + title: { | ||
| 88 | + text: title | ||
| 89 | + }, | ||
| 90 | + tooltip: { | ||
| 91 | + trigger: 'axis' | ||
| 92 | + }, | ||
| 93 | + legend: { | ||
| 94 | + data: createTime | ||
| 95 | + }, | ||
| 96 | + grid: { | ||
| 97 | + left: '3%', | ||
| 98 | + right: '4%', | ||
| 99 | + bottom: '3%', | ||
| 100 | + containLabel: true | ||
| 101 | + }, | ||
| 102 | + toolbox: { | ||
| 103 | + feature: { | ||
| 104 | + saveAsImage: {} | ||
| 105 | + } | ||
| 106 | + }, | ||
| 107 | + xAxis: { | ||
| 108 | + type: 'category', | ||
| 109 | + boundaryGap: false, | ||
| 110 | + data: createTime | ||
| 111 | + }, | ||
| 112 | + yAxis: { | ||
| 113 | + type: 'value' | ||
| 114 | + }, | ||
| 115 | + series: [{ | ||
| 116 | + name: lineName, | ||
| 117 | + type: 'line', | ||
| 118 | + stack: 'Total', | ||
| 119 | + data: countValues | ||
| 120 | + }] | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + myChart.setOption(option) | ||
| 124 | + window.addEventListener('resize', () => { | ||
| 125 | + myChart.resize() | ||
| 126 | + }) | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | +} | ||
| 130 | +</script> | ||
| 131 | + | ||
| 132 | +<style lang="scss" scoped> | ||
| 133 | +.operational-analysis-container { | ||
| 134 | + padding: 20px; | ||
| 135 | + | ||
| 136 | + .margin-bottom { | ||
| 137 | + margin-bottom: 20px; | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + .box-card { | ||
| 141 | + margin: 0 10px; | ||
| 142 | + } | ||
| 143 | +} | ||
| 144 | +</style> | ||
| 0 | \ No newline at end of file | 145 | \ No newline at end of file |