Commit 51f9221ae8a527018890dcec79f18f1979bedfb1

Authored by wuxw
1 parent 31c24e26

加入报表功能

src/api/report/dataReportApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询费用统计数据
  4 +export function queryFeeDataReport(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/dataReport.queryFeeDataReport',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve(res)
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +// 查询工单统计数据
  20 +export function queryOrderDataReport(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/dataReport.queryOrderDataReport',
  24 + method: 'get',
  25 + params
  26 + }).then(response => {
  27 + const res = response.data
  28 + resolve(res)
  29 + }).catch(error => {
  30 + reject(error)
  31 + })
  32 + })
  33 +}
  34 +
  35 +// 查询出入统计数据
  36 +export function queryInoutDataReport(params) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/dataReport.queryInoutDataReport',
  40 + method: 'get',
  41 + params
  42 + }).then(response => {
  43 + const res = response.data
  44 + resolve(res)
  45 + }).catch(error => {
  46 + reject(error)
  47 + })
  48 + })
  49 +}
  50 +
  51 +// 查询其他统计数据
  52 +export function queryOthersDataReport(params) {
  53 + return new Promise((resolve, reject) => {
  54 + request({
  55 + url: '/dataReport.queryOthersDataReport',
  56 + method: 'get',
  57 + params
  58 + }).then(response => {
  59 + const res = response.data
  60 + resolve(res)
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
  66 +
  67 +// 查询实收统计数据
  68 +export function queryReceivedStatistics(params) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/dataReport.queryReceivedStatistics',
  72 + method: 'get',
  73 + params
  74 + }).then(response => {
  75 + const res = response.data
  76 + resolve(res)
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
  82 +
  83 +// 查询实收明细统计数据
  84 +export function queryReceivedDetailStatistics(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/dataReport.queryReceivedDetailStatistics',
  88 + method: 'get',
  89 + params
  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 queryReceivedWayStatistics(params) {
  101 + return new Promise((resolve, reject) => {
  102 + request({
  103 + url: '/dataReport.queryReceivedWayStatistics',
  104 + method: 'get',
  105 + params
  106 + }).then(response => {
  107 + const res = response.data
  108 + resolve(res)
  109 + }).catch(error => {
  110 + reject(error)
  111 + })
  112 + })
  113 +}
  114 +
  115 +// 查询欠费统计数据
  116 +export function queryOweStatistics(params) {
  117 + return new Promise((resolve, reject) => {
  118 + request({
  119 + url: '/dataReport.queryOweStatistics',
  120 + method: 'get',
  121 + params
  122 + }).then(response => {
  123 + const res = response.data
  124 + resolve(res)
  125 + }).catch(error => {
  126 + reject(error)
  127 + })
  128 + })
  129 +}
  130 +
  131 +// 查询欠费明细统计数据
  132 +export function queryOweDetailStatistics(params) {
  133 + return new Promise((resolve, reject) => {
  134 + request({
  135 + url: '/dataReport.queryOweDetailStatistics',
  136 + method: 'get',
  137 + params
  138 + }).then(response => {
  139 + const res = response.data
  140 + resolve(res)
  141 + }).catch(error => {
  142 + reject(error)
  143 + })
  144 + })
  145 +}
  146 +
  147 +// 查询收缴情况统计数据
  148 +export function queryDataReportFeeStatistics(params) {
  149 + return new Promise((resolve, reject) => {
  150 + request({
  151 + url: '/dataReport.queryDataReportFeeStatistics',
  152 + method: 'get',
  153 + params
  154 + }).then(response => {
  155 + const res = response.data
  156 + resolve(res)
  157 + }).catch(error => {
  158 + reject(error)
  159 + })
  160 + })
  161 +}
  162 +
  163 +// 查询月实收明细数据
  164 +export function queryMonthReceivedDetail(params) {
  165 + return new Promise((resolve, reject) => {
  166 + request({
  167 + url: '/dataReport.queryMonthReceivedDetail',
  168 + method: 'get',
  169 + params
  170 + }).then(response => {
  171 + const res = response.data
  172 + resolve(res)
  173 + }).catch(error => {
  174 + reject(error)
  175 + })
  176 + })
  177 +}
  178 +
  179 +// 查询月欠费明细数据
  180 +export function queryMonthOweDetail(params) {
  181 + return new Promise((resolve, reject) => {
  182 + request({
  183 + url: '/dataReport.queryMonthOweDetail',
  184 + method: 'get',
  185 + params
  186 + }).then(response => {
  187 + const res = response.data
  188 + resolve(res)
  189 + }).catch(error => {
  190 + reject(error)
  191 + })
  192 + })
  193 +}
  194 +
  195 +// 查询楼栋列表
  196 +export function queryFloors(params) {
  197 + return new Promise((resolve, reject) => {
  198 + request({
  199 + url: '/floor.queryFloors',
  200 + method: 'get',
  201 + params
  202 + }).then(response => {
  203 + const res = response.data
  204 + resolve(res)
  205 + }).catch(error => {
  206 + reject(error)
  207 + })
  208 + })
  209 +}
  210 +
  211 +// 查询我入驻的小区列表
  212 +export function listMyEnteredCommunitys(params) {
  213 + return new Promise((resolve, reject) => {
  214 + request({
  215 + url: '/community.listMyEnteredCommunitys',
  216 + method: 'get',
  217 + params
  218 + }).then(response => {
  219 + const res = response.data
  220 + resolve(res)
  221 + }).catch(error => {
  222 + reject(error)
  223 + })
  224 + })
  225 +}
  226 +
  227 +// 导出数据
  228 +export function exportData(params) {
  229 + return new Promise((resolve, reject) => {
  230 + request({
  231 + url: '/export.exportData',
  232 + method: 'get',
  233 + params
  234 + }).then(response => {
  235 + const res = response.data
  236 + resolve(res)
  237 + }).catch(error => {
  238 + reject(error)
  239 + })
  240 + })
  241 +}
0 242 \ No newline at end of file
... ...
src/api/report/feeRemindApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询预缴费提醒列表
  4 +export function queryPrePayment(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/reportFeeMonthStatistics.queryPrePayment',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve(res)
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +// 查询到期提醒列表
  20 +export function queryDeadlineFee(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/reportFeeMonthStatistics.queryDeadlineFee',
  24 + method: 'get',
  25 + params
  26 + }).then(response => {
  27 + const res = response.data
  28 + resolve(res)
  29 + }).catch(error => {
  30 + reject(error)
  31 + })
  32 + })
  33 +}
  34 +
  35 +// 导出数据
  36 +export function exportData(params) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/export.exportData',
  40 + method: 'get',
  41 + params
  42 + }).then(response => {
  43 + const res = response.data
  44 + resolve(res)
  45 + }).catch(error => {
  46 + reject(error)
  47 + })
  48 + })
  49 +}
  50 +
  51 +// 查询费用项列表
  52 +export function listFeeConfigs(params) {
  53 + return new Promise((resolve, reject) => {
  54 + request({
  55 + url: '/feeConfig.listFeeConfigs',
  56 + method: 'get',
  57 + params
  58 + }).then(response => {
  59 + const res = response.data
  60 + resolve(res)
  61 + }).catch(error => {
  62 + reject(error)
  63 + })
  64 + })
  65 +}
  66 +
  67 +// 查询已入驻小区列表
  68 +export function listMyEnteredCommunitys(params) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/community.listMyEnteredCommunitys',
  72 + method: 'get',
  73 + params
  74 + }).then(response => {
  75 + const res = response.data
  76 + resolve(res)
  77 + }).catch(error => {
  78 + reject(error)
  79 + })
  80 + })
  81 +}
0 82 \ No newline at end of file
... ...
src/api/report/reportFeeDetailApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询房屋费用明细
  4 +export function queryReportFeeDetailRoom(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/reportFeeMonthStatistics.queryReportFeeDetailRoom',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + resolve({
  13 + data: res.data,
  14 + total: res.total
  15 + })
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +// 查询业主费用明细
  23 +export function queryReportFeeDetailOwner(params) {
  24 + return new Promise((resolve, reject) => {
  25 + request({
  26 + url: '/reportFeeMonthStatistics.queryReportFeeDetailOwner',
  27 + method: 'get',
  28 + params
  29 + }).then(response => {
  30 + const res = response.data
  31 + resolve({
  32 + data: res.data,
  33 + total: res.total
  34 + })
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
  40 +
  41 +// 查询合同费用明细
  42 +export function queryReportFeeDetailContract(params) {
  43 + return new Promise((resolve, reject) => {
  44 + request({
  45 + url: '/reportFeeMonthStatistics.queryReportFeeDetailContract',
  46 + method: 'get',
  47 + params
  48 + }).then(response => {
  49 + const res = response.data
  50 + resolve({
  51 + data: res.data,
  52 + total: res.total
  53 + })
  54 + }).catch(error => {
  55 + reject(error)
  56 + })
  57 + })
  58 +}
  59 +
  60 +// 查询车辆费用明细
  61 +export function queryReportFeeDetailCar(params) {
  62 + return new Promise((resolve, reject) => {
  63 + request({
  64 + url: '/reportFeeMonthStatistics.queryReportFeeDetailCar',
  65 + method: 'get',
  66 + params
  67 + }).then(response => {
  68 + const res = response.data
  69 + resolve({
  70 + data: res.data,
  71 + total: res.total
  72 + })
  73 + }).catch(error => {
  74 + reject(error)
  75 + })
  76 + })
  77 +}
  78 +
  79 +// 导出房屋费用明细
  80 +export function exportReportFeeDetailRoom(params) {
  81 + return new Promise((resolve, reject) => {
  82 + request({
  83 + url: '/export.exportData',
  84 + method: 'get',
  85 + params
  86 + }).then(response => {
  87 + const res = response.data
  88 + resolve(res)
  89 + }).catch(error => {
  90 + reject(error)
  91 + })
  92 + })
  93 +}
  94 +
  95 +// 导出业主费用明细
  96 +export function exportReportFeeDetailOwner(params) {
  97 + return new Promise((resolve, reject) => {
  98 + request({
  99 + url: '/export.exportData',
  100 + method: 'get',
  101 + params
  102 + }).then(response => {
  103 + const res = response.data
  104 + resolve(res)
  105 + }).catch(error => {
  106 + reject(error)
  107 + })
  108 + })
  109 +}
  110 +
  111 +// 导出合同费用明细
  112 +export function exportReportFeeDetailContract(params) {
  113 + return new Promise((resolve, reject) => {
  114 + request({
  115 + url: '/export.exportData',
  116 + method: 'get',
  117 + params
  118 + }).then(response => {
  119 + const res = response.data
  120 + resolve(res)
  121 + }).catch(error => {
  122 + reject(error)
  123 + })
  124 + })
  125 +}
  126 +
  127 +// 导出车辆费用明细
  128 +export function exportReportFeeDetailCar(params) {
  129 + return new Promise((resolve, reject) => {
  130 + request({
  131 + url: '/export.exportData',
  132 + method: 'get',
  133 + params
  134 + }).then(response => {
  135 + const res = response.data
  136 + resolve(res)
  137 + }).catch(error => {
  138 + reject(error)
  139 + })
  140 + })
  141 +}
  142 +
  143 +export function loadStaffCommunitys(params) {
  144 + return new Promise((resolve, reject) => {
  145 + request({
  146 + url: '/community.listMyEnteredCommunitys',
  147 + method: 'get',
  148 + params
  149 + }).then(response => {
  150 + const res = response.data
  151 + resolve(res)
  152 + }).catch(error => {
  153 + reject(error)
  154 + })
  155 + })
  156 +}
0 157 \ No newline at end of file
... ...
src/api/report/reportFeeSummaryApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +/**
  4 + * 查询费用汇总数据
  5 + * @param {Object} params 查询参数
  6 + */
  7 +export function queryReportFeeSummary(params) {
  8 + return new Promise((resolve, reject) => {
  9 + request({
  10 + url: '/reportFeeMonthStatistics.queryReportFeeSummary',
  11 + method: 'get',
  12 + params
  13 + }).then(response => {
  14 + const res = response.data
  15 + resolve(res)
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +/**
  23 + * 查询楼栋费用汇总数据
  24 + * @param {Object} params 查询参数
  25 + */
  26 +export function queryReportFloorFeeSummary(params) {
  27 + return new Promise((resolve, reject) => {
  28 + request({
  29 + url: '/reportFeeMonthStatistics.queryReportFloorFeeSummary',
  30 + method: 'get',
  31 + params
  32 + }).then(response => {
  33 + const res = response.data
  34 + resolve(res)
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
  40 +
  41 +/**
  42 + * 查询费用项汇总数据
  43 + * @param {Object} params 查询参数
  44 + */
  45 +export function queryReportConfigFeeSummary(params) {
  46 + return new Promise((resolve, reject) => {
  47 + request({
  48 + url: '/reportFeeMonthStatistics.queryReportConfigFeeSummary',
  49 + method: 'get',
  50 + params
  51 + }).then(response => {
  52 + const res = response.data
  53 + resolve(res)
  54 + }).catch(error => {
  55 + reject(error)
  56 + })
  57 + })
  58 +}
  59 +
  60 +/**
  61 + * 导出数据
  62 + * @param {Object} params 导出参数
  63 + */
  64 +export function exportData(params) {
  65 + return new Promise((resolve, reject) => {
  66 + request({
  67 + url: '/export.exportData',
  68 + method: 'get',
  69 + params
  70 + }).then(response => {
  71 + const res = response.data
  72 + resolve(res)
  73 + }).catch(error => {
  74 + reject(error)
  75 + })
  76 + })
  77 +}
  78 +
  79 +/**
  80 + * 查询楼栋列表
  81 + * @param {Object} params 查询参数
  82 + */
  83 +export function queryFloors(params) {
  84 + return new Promise((resolve, reject) => {
  85 + request({
  86 + url: '/floor.queryFloors',
  87 + method: 'get',
  88 + params
  89 + }).then(response => {
  90 + const res = response.data
  91 + resolve(res)
  92 + }).catch(error => {
  93 + reject(error)
  94 + })
  95 + })
  96 +}
  97 +
  98 +/**
  99 + * 查询费用配置列表
  100 + * @param {Object} params 查询参数
  101 + */
  102 +export function queryFeeConfigs(params) {
  103 + return new Promise((resolve, reject) => {
  104 + request({
  105 + url: '/feeConfig.listFeeConfigs',
  106 + method: 'get',
  107 + params
  108 + }).then(response => {
  109 + const res = response.data
  110 + resolve(res)
  111 + }).catch(error => {
  112 + reject(error)
  113 + })
  114 + })
  115 +}
  116 +
  117 +/**
  118 + * 查询用户关联的小区列表
  119 + */
  120 +export function queryCommunitys() {
  121 + return new Promise((resolve, reject) => {
  122 + request({
  123 + url: '/community.listMyEnteredCommunitys',
  124 + method: 'get',
  125 + params: {
  126 + _uid: '123mlkdinkldldijdhuudjdjkkd',
  127 + page: 1,
  128 + row: 100
  129 + }
  130 + }).then(response => {
  131 + const res = response.data
  132 + resolve(res)
  133 + }).catch(error => {
  134 + reject(error)
  135 + })
  136 + })
  137 +}
0 138 \ No newline at end of file
... ...
src/components/report/DataMonthOweStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <el-row>
  4 + <el-col :span="3" class="padding-r-0">
  5 + <el-card class="border-radius">
  6 + <div class="treeview attendance-staff" style="height: 650px;">
  7 + <ul class="list-group text-center border-radius">
  8 + <li v-for="(item, index) in dataMonthOweStatisticsInfo.feeTypeCds" :key="index"
  9 + class="list-group-item node-orgTree"
  10 + :class="{ 'vc-node-selected': dataMonthOweStatisticsInfo.feeTypeCd === item.statusCd }"
  11 + @click="_switchMonthOweStatisticsFeeTypeCd(item.statusCd)">
  12 + {{ item.name }}
  13 + </li>
  14 + </ul>
  15 + </div>
  16 + </el-card>
  17 + </el-col>
  18 + <el-col :span="21">
  19 + <el-row>
  20 + <el-col :span="4">
  21 + <el-select v-model="dataMonthOweStatisticsInfo.floorId" :placeholder="$t('dataReport.selectBuilding')"
  22 + clearable style="width: 100%">
  23 + <el-option v-for="(item, index) in dataMonthOweStatisticsInfo.floors" :key="index" :label="item.floorNum"
  24 + :value="item.floorId" />
  25 + </el-select>
  26 + </el-col>
  27 + <el-col :span="4">
  28 + <el-date-picker v-model="dataMonthOweStatisticsInfo.feeStartDate" type="date"
  29 + :placeholder="$t('dataReport.feeStartDate')" style="width: 100%" />
  30 + </el-col>
  31 + <el-col :span="4">
  32 + <el-date-picker v-model="dataMonthOweStatisticsInfo.feeEndDate" type="date"
  33 + :placeholder="$t('dataReport.feeEndDate')" style="width: 100%" />
  34 + </el-col>
  35 + <el-col :span="4">
  36 + <el-button type="primary" size="small" @click="_qureyDataMonthOweStatistics">
  37 + <i class="el-icon-search"></i>
  38 + {{ $t('dataReport.search') }}
  39 + </el-button>
  40 + </el-col>
  41 + <el-col :span="8" class="text-right">
  42 + <el-button type="primary" size="small" @click="_exportReportMonthOweFeeExcel">
  43 + <i class="el-icon-download"></i>
  44 + <span>{{ $t('dataReport.export') }}</span>
  45 + </el-button>
  46 + </el-col>
  47 + </el-row>
  48 +
  49 + <div class="margin-top">
  50 + <el-table :data="dataMonthOweStatisticsInfo.fees" border style="width: 100%">
  51 + <el-table-column prop="objName" :label="$t('dataReport.room')" align="center" />
  52 + <el-table-column :label="$t('dataReport.owner')" align="center">
  53 + <template slot-scope="scope">
  54 + {{ scope.row.ownerName }}({{ scope.row.link }})
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column prop="feeName" :label="$t('dataReport.feeName')" align="center" />
  58 + <el-table-column prop="curYearMonth" :label="$t('dataReport.owePeriod')" align="center" />
  59 + <el-table-column prop="receivableAmount" :label="$t('dataReport.oweAmount')" align="center">
  60 + <template slot-scope="scope">
  61 + {{ scope.row.receivableAmount || 0 }}
  62 + </template>
  63 + </el-table-column>
  64 + </el-table>
  65 +
  66 + <el-row class="margin-top">
  67 + <el-col :span="8">
  68 + <span>{{ $t('dataReport.totalOwe') }}:</span>
  69 + <span>{{ dataMonthOweStatisticsInfo.feeAmount }}</span>
  70 + </el-col>
  71 + <el-col :span="16" class="text-right">
  72 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  73 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  74 + @current-change="handleCurrentChange" />
  75 + </el-col>
  76 + </el-row>
  77 + </div>
  78 + </el-col>
  79 + </el-row>
  80 + </div>
  81 +</template>
  82 +
  83 +<script>
  84 +import { getDict } from '@/api/community/communityApi'
  85 +import { queryMonthOweDetail, exportData, queryFloors } from '@/api/report/dataReportApi'
  86 +
  87 +export default {
  88 + name: 'DataMonthOweStatistics',
  89 +
  90 + data() {
  91 + return {
  92 + dataMonthOweStatisticsInfo: {
  93 + fees: [],
  94 + feeTypeCds: [],
  95 + floors: [],
  96 + floorId: '',
  97 + feeStartDate: '',
  98 + feeEndDate: '',
  99 + feeTypeCd: '',
  100 + feeAmount: '0'
  101 + },
  102 + startDate: '',
  103 + endDate: '',
  104 + communityId: '',
  105 + page: {
  106 + current: 1,
  107 + size: 10,
  108 + total: 0
  109 + }
  110 + }
  111 + },
  112 + created() {
  113 + this._initMethod()
  114 + },
  115 + methods: {
  116 + open(param){
  117 + this.startDate = param.startDate
  118 + this.endDate = param.endDate
  119 + this.communityId = param.communityId
  120 + this._loadMonthOweFloors()
  121 + },
  122 + async _initMethod() {
  123 + try {
  124 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  125 + this.dataMonthOweStatisticsInfo.feeTypeCds = data
  126 + this.dataMonthOweStatisticsInfo.feeTypeCd = data[0].statusCd
  127 + this.dataMonthOweStatisticsInfo.feeStartDate = this.startDate
  128 + this.dataMonthOweStatisticsInfo.feeEndDate = this.endDate
  129 + } catch (error) {
  130 + console.error('Failed to load dictionary:', error)
  131 + }
  132 + },
  133 + async _loadMonthOweFloors() {
  134 + try {
  135 + const params = {
  136 + page: 1,
  137 + row: 100,
  138 + communityId: this.communityId
  139 + }
  140 + const { apiFloorDataVoList } = await queryFloors(params)
  141 + this.dataMonthOweStatisticsInfo.floors = apiFloorDataVoList
  142 + } catch (error) {
  143 + console.error('Failed to load floors:', error)
  144 + }
  145 + },
  146 + async _loadDataMonthOweStatisticsData() {
  147 + try {
  148 + const params = {
  149 + page: this.page.current,
  150 + row: this.page.size,
  151 + communityId: this.communityId,
  152 + feeStartDate: this.dataMonthOweStatisticsInfo.feeStartDate,
  153 + feeEndDate: this.dataMonthOweStatisticsInfo.feeEndDate,
  154 + feeTypeCd: this.dataMonthOweStatisticsInfo.feeTypeCd,
  155 + floorId: this.dataMonthOweStatisticsInfo.floorId
  156 + }
  157 + const { data, records, sumTotal } = await queryMonthOweDetail(params)
  158 + this.dataMonthOweStatisticsInfo.fees = data
  159 + this.page.total = records
  160 + this.dataMonthOweStatisticsInfo.feeAmount = sumTotal
  161 + } catch (error) {
  162 + console.error('Failed to load data:', error)
  163 + }
  164 + },
  165 + async _exportReportMonthOweFeeExcel() {
  166 + try {
  167 + const params = {
  168 + communityId: this.communityId,
  169 + feeStartDate: this.dataMonthOweStatisticsInfo.feeStartDate,
  170 + feeEndDate: this.dataMonthOweStatisticsInfo.feeEndDate,
  171 + feeTypeCd: this.dataMonthOweStatisticsInfo.feeTypeCd,
  172 + floorId: this.dataMonthOweStatisticsInfo.floorId,
  173 + pagePath: 'dataMonthOweStatistics'
  174 + }
  175 + const res = await exportData(params)
  176 + this.$message.success(res.msg)
  177 + if (res.code === 0) {
  178 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  179 + }
  180 + } catch (error) {
  181 + console.error('Export failed:', error)
  182 + }
  183 + },
  184 + _qureyDataMonthOweStatistics() {
  185 + this.page.current = 1
  186 + this._loadDataMonthOweStatisticsData()
  187 + },
  188 + _switchMonthOweStatisticsFeeTypeCd(_feeTypeCd) {
  189 + this.dataMonthOweStatisticsInfo.feeTypeCd = _feeTypeCd
  190 + this._loadDataMonthOweStatisticsData()
  191 + },
  192 + handleSizeChange(val) {
  193 + this.page.size = val
  194 + this._loadDataMonthOweStatisticsData()
  195 + },
  196 + handleCurrentChange(val) {
  197 + this.page.current = val
  198 + this._loadDataMonthOweStatisticsData()
  199 + }
  200 + }
  201 +}
  202 +</script>
  203 +
  204 +<style scoped>
  205 +.margin-top {
  206 + margin-top: 20px;
  207 +}
  208 +
  209 +.text-right {
  210 + text-align: right;
  211 +}
  212 +
  213 +.padding-r-0 {
  214 + padding-right: 0;
  215 +}
  216 +
  217 +.border-radius {
  218 + border-radius: 4px;
  219 +}
  220 +
  221 +.list-group {
  222 + list-style: none;
  223 + padding: 0;
  224 + margin: 0;
  225 +}
  226 +
  227 +.list-group-item {
  228 + padding: 10px;
  229 + cursor: pointer;
  230 + border-bottom: 1px solid #eee;
  231 +}
  232 +
  233 +.list-group-item:hover {
  234 + background-color: #f5f5f5;
  235 +}
  236 +
  237 +.vc-node-selected {
  238 + background-color: #409EFF;
  239 + color: white;
  240 +}
  241 +
  242 +.treeview {
  243 + overflow-y: auto;
  244 +}
  245 +</style>
0 246 \ No newline at end of file
... ...
src/components/report/DataMonthReceivedStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <el-row>
  4 + <el-col :span="3" class="padding-r-0">
  5 + <el-card class="border-radius">
  6 + <div class="treeview attendance-staff" style="height: 650px;">
  7 + <ul class="list-group text-center border-radius">
  8 + <li v-for="(item, index) in dataMonthReceivedStatisticsInfo.feeTypeCds" :key="index"
  9 + class="list-group-item node-orgTree"
  10 + :class="{ 'vc-node-selected': dataMonthReceivedStatisticsInfo.feeTypeCd === item.statusCd }"
  11 + @click="switchMonthReceivedStatisticsFeeTypeCd(item.statusCd)">
  12 + {{ item.name }}
  13 + </li>
  14 + </ul>
  15 + </div>
  16 + </el-card>
  17 + </el-col>
  18 + <el-col :span="21">
  19 + <el-row>
  20 + <el-col :span="4">
  21 + <el-select v-model="dataMonthReceivedStatisticsInfo.floorId" :placeholder="$t('dataReport.selectBuilding')"
  22 + clearable style="width: 100%">
  23 + <el-option v-for="(item, index) in dataMonthReceivedStatisticsInfo.floors" :key="index"
  24 + :label="item.floorNum" :value="item.floorId" />
  25 + </el-select>
  26 + </el-col>
  27 + <el-col :span="4">
  28 + <el-date-picker v-model="dataMonthReceivedStatisticsInfo.feeStartDate" type="date"
  29 + :placeholder="$t('dataReport.feeStartDate')" style="width: 100%" />
  30 + </el-col>
  31 + <el-col :span="4">
  32 + <el-date-picker v-model="dataMonthReceivedStatisticsInfo.feeEndDate" type="date"
  33 + :placeholder="$t('dataReport.feeEndDate')" style="width: 100%" />
  34 + </el-col>
  35 + <el-col :span="4">
  36 + <el-button type="primary" size="small" @click="_qureyDataMonthReceivedStatistics">
  37 + <i class="el-icon-search"></i>
  38 + {{ $t('dataReport.search') }}
  39 + </el-button>
  40 + </el-col>
  41 + <el-col :span="8" class="text-right">
  42 + <el-button type="primary" size="small" @click="_exportReportMonthReceivedFeeExcel">
  43 + <i class="el-icon-download"></i>
  44 + <span>{{ $t('dataReport.export') }}</span>
  45 + </el-button>
  46 + </el-col>
  47 + </el-row>
  48 +
  49 + <div class="margin-top">
  50 + <el-table :data="dataMonthReceivedStatisticsInfo.fees" border style="width: 100%">
  51 + <el-table-column prop="objName" :label="$t('dataReport.room')" align="center" />
  52 + <el-table-column :label="$t('dataReport.owner')" align="center">
  53 + <template slot-scope="scope">
  54 + {{ scope.row.ownerName }}({{ scope.row.link }})
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column prop="receivedAmount" :label="$t('dataReport.receivedAmount')" align="center">
  58 + <template slot-scope="scope">
  59 + {{ scope.row.receivedAmount || 0 }}
  60 + </template>
  61 + </el-table-column>
  62 + <el-table-column prop="feeName" :label="$t('dataReport.feeName')" align="center" />
  63 + <el-table-column prop="curYearMonth" :label="$t('dataReport.receivedPeriod')" align="center" />
  64 + <el-table-column prop="cashierName" :label="$t('dataReport.cashier')" align="center" />
  65 + <el-table-column prop="createTime" :label="$t('dataReport.paymentTime')" align="center" />
  66 + </el-table>
  67 +
  68 + <el-row class="margin-top">
  69 + <el-col :span="8">
  70 + <span>{{ $t('dataReport.totalReceived') }}:</span>
  71 + <span>{{ dataMonthReceivedStatisticsInfo.feeAmount }}</span>
  72 + </el-col>
  73 + <el-col :span="16" class="text-right">
  74 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  75 + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  76 + @current-change="handleCurrentChange" />
  77 + </el-col>
  78 + </el-row>
  79 + </div>
  80 + </el-col>
  81 + </el-row>
  82 + </div>
  83 +</template>
  84 +
  85 +<script>
  86 +import { getDict } from '@/api/community/communityApi'
  87 +import { queryMonthReceivedDetail, exportData, queryFloors } from '@/api/report/dataReportApi'
  88 +
  89 +export default {
  90 + name: 'DataMonthReceivedStatistics',
  91 +
  92 + data() {
  93 + return {
  94 + dataMonthReceivedStatisticsInfo: {
  95 + fees: [],
  96 + feeTypeCds: [],
  97 + floors: [],
  98 + floorId: '',
  99 + feeStartDate: '',
  100 + feeEndDate: '',
  101 + feeTypeCd: '',
  102 + feeAmount: '0'
  103 + },
  104 + startDate: '',
  105 + endDate: '',
  106 + communityId: '',
  107 + page: {
  108 + current: 1,
  109 + size: 10,
  110 + total: 0
  111 + }
  112 + }
  113 + },
  114 + created() {
  115 + this._initMethod()
  116 + },
  117 + methods: {
  118 + open(param){
  119 + this.startDate = param.startDate
  120 + this.endDate = param.endDate
  121 + this.communityId = param.communityId
  122 + this._loadMonthReceivedFloors()
  123 + },
  124 + async _initMethod() {
  125 + try {
  126 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  127 + this.dataMonthReceivedStatisticsInfo.feeTypeCds = data
  128 + this.dataMonthReceivedStatisticsInfo.feeTypeCd = data[0].statusCd
  129 + this.dataMonthReceivedStatisticsInfo.feeStartDate = this.startDate
  130 + this.dataMonthReceivedStatisticsInfo.feeEndDate = this.endDate
  131 + } catch (error) {
  132 + console.error('Failed to load dictionary:', error)
  133 + }
  134 + },
  135 + async _loadMonthReceivedFloors() {
  136 + try {
  137 + const params = {
  138 + page: 1,
  139 + row: 100,
  140 + communityId: this.communityId
  141 + }
  142 + const { apiFloorDataVoList } = await queryFloors(params)
  143 + this.dataMonthReceivedStatisticsInfo.floors = apiFloorDataVoList
  144 + } catch (error) {
  145 + console.error('Failed to load floors:', error)
  146 + }
  147 + },
  148 + async _loadDataMonthReceivedStatisticsData() {
  149 + try {
  150 + const params = {
  151 + page: this.page.current,
  152 + row: this.page.size,
  153 + communityId: this.communityId,
  154 + feeStartDate: this.dataMonthReceivedStatisticsInfo.feeStartDate,
  155 + feeEndDate: this.dataMonthReceivedStatisticsInfo.feeEndDate,
  156 + feeTypeCd: this.dataMonthReceivedStatisticsInfo.feeTypeCd,
  157 + floorId: this.dataMonthReceivedStatisticsInfo.floorId
  158 + }
  159 + const { data, records, sumTotal } = await queryMonthReceivedDetail(params)
  160 + this.dataMonthReceivedStatisticsInfo.fees = data
  161 + this.page.total = records
  162 + this.dataMonthReceivedStatisticsInfo.feeAmount = sumTotal
  163 + } catch (error) {
  164 + console.error('Failed to load data:', error)
  165 + }
  166 + },
  167 + async _exportReportMonthReceivedFeeExcel() {
  168 + try {
  169 + const params = {
  170 + communityId: this.communityId,
  171 + feeStartDate: this.dataMonthReceivedStatisticsInfo.feeStartDate,
  172 + feeEndDate: this.dataMonthReceivedStatisticsInfo.feeEndDate,
  173 + feeTypeCd: this.dataMonthReceivedStatisticsInfo.feeTypeCd,
  174 + floorId: this.dataMonthReceivedStatisticsInfo.floorId,
  175 + pagePath: 'dataMonthReceivedStatistics'
  176 + }
  177 + const res = await exportData(params)
  178 + this.$message.success(res.msg)
  179 + if (res.code === 0) {
  180 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  181 + }
  182 + } catch (error) {
  183 + console.error('Export failed:', error)
  184 + }
  185 + },
  186 + _qureyDataMonthReceivedStatistics() {
  187 + this.page.current = 1
  188 + this._loadDataMonthReceivedStatisticsData()
  189 + },
  190 + switchMonthReceivedStatisticsFeeTypeCd(_feeTypeCd) {
  191 + this.dataMonthReceivedStatisticsInfo.feeTypeCd = _feeTypeCd
  192 + this._loadDataMonthReceivedStatisticsData()
  193 + },
  194 + handleSizeChange(val) {
  195 + this.page.size = val
  196 + this._loadDataMonthReceivedStatisticsData()
  197 + },
  198 + handleCurrentChange(val) {
  199 + this.page.current = val
  200 + this._loadDataMonthReceivedStatisticsData()
  201 + }
  202 + }
  203 +}
  204 +</script>
  205 +
  206 +<style scoped>
  207 +.margin-top {
  208 + margin-top: 20px;
  209 +}
  210 +
  211 +.text-right {
  212 + text-align: right;
  213 +}
  214 +
  215 +.padding-r-0 {
  216 + padding-right: 0;
  217 +}
  218 +
  219 +.border-radius {
  220 + border-radius: 4px;
  221 +}
  222 +
  223 +.list-group {
  224 + list-style: none;
  225 + padding: 0;
  226 + margin: 0;
  227 +}
  228 +
  229 +.list-group-item {
  230 + padding: 10px;
  231 + cursor: pointer;
  232 + border-bottom: 1px solid #eee;
  233 +}
  234 +
  235 +.list-group-item:hover {
  236 + background-color: #f5f5f5;
  237 +}
  238 +
  239 +.vc-node-selected {
  240 + background-color: #409EFF;
  241 + color: white;
  242 +}
  243 +
  244 +.treeview {
  245 + overflow-y: auto;
  246 +}
  247 +</style>
0 248 \ No newline at end of file
... ...
src/components/report/DataReportEarnedDetailStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <el-row class="margin-top-lg">
  4 + <el-col :span="4">
  5 + <el-input v-model="dataReportEarnedDetailStatisticsInfo.objName" :placeholder="$t('dataReport.roomNumber')"
  6 + clearable />
  7 + </el-col>
  8 + <el-col :span="4">
  9 + <el-input v-model="dataReportEarnedDetailStatisticsInfo.ownerName" :placeholder="$t('dataReport.ownerName')"
  10 + clearable />
  11 + </el-col>
  12 + <el-col :span="4">
  13 + <el-input v-model="dataReportEarnedDetailStatisticsInfo.link" :placeholder="$t('dataReport.phoneNumber')"
  14 + clearable />
  15 + </el-col>
  16 + <el-col :span="4">
  17 + <el-button type="primary" size="small" @click="_qureyDataReportEarnedDetailStatistics">
  18 + <i class="el-icon-search"></i>
  19 + {{ $t('dataReport.search') }}
  20 + </el-button>
  21 + </el-col>
  22 + <el-col :span="8" class="text-right">
  23 + <el-button type="primary" size="small" @click="_exportReportEarnedDetailExcel">
  24 + <i class="el-icon-download"></i>
  25 + <span>{{ $t('dataReport.export') }}</span>
  26 + </el-button>
  27 + </el-col>
  28 + </el-row>
  29 +
  30 + <div class="margin-top">
  31 + <el-table :data="dataReportEarnedDetailStatisticsInfo.fees" border style="width: 100%">
  32 + <el-table-column prop="roomName" :label="$t('dataReport.room')" align="center" />
  33 + <el-table-column :label="$t('dataReport.owner')" align="center">
  34 + <template slot-scope="scope">
  35 + {{ scope.row.ownerName }}({{ scope.row.link }})
  36 + </template>
  37 + </el-table-column>
  38 + <el-table-column :label="$t('dataReport.receivedFee')" align="center">
  39 + <template slot-scope="scope">
  40 + {{ scope.row.receivedFee || 0 }}
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column v-for="(item, index) in dataReportEarnedDetailStatisticsInfo.feeTypeCds" :key="index"
  44 + :label="item.name" align="center">
  45 + <template slot-scope="scope">
  46 + <div v-if="scope.row['receivedFee' + item.statusCd]">
  47 + <div v-for="(feeItem, fIndex) in scope.row['receivedFee' + item.statusCd]" :key="fIndex">
  48 + {{ feeItem.feeName }}({{ feeItem.startTime }}~{{ feeItem.endTime }})={{ feeItem.receivedAmount }}
  49 + </div>
  50 + </div>
  51 + <div v-else>
  52 + 0
  53 + </div>
  54 + </template>
  55 + </el-table-column>
  56 + </el-table>
  57 +
  58 + <el-row class="margin-top">
  59 + <el-col :span="24" class="text-right">
  60 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  61 + layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  62 + @current-change="handleCurrentChange" />
  63 + </el-col>
  64 + </el-row>
  65 + </div>
  66 + </div>
  67 +</template>
  68 +
  69 +<script>
  70 +import { getDict } from '@/api/community/communityApi'
  71 +import { queryReceivedDetailStatistics, exportData } from '@/api/report/dataReportApi'
  72 +
  73 +export default {
  74 + name: 'DataReportEarnedDetailStatistics',
  75 +
  76 + data() {
  77 + return {
  78 + dataReportEarnedDetailStatisticsInfo: {
  79 + fees: [],
  80 + feeTypeCds: [],
  81 + objName: '',
  82 + ownerName: '',
  83 + link: '',
  84 + feeAmount: '0'
  85 + },
  86 + startDate: '',
  87 + endDate: '',
  88 + communityId: '',
  89 + page: {
  90 + current: 1,
  91 + size: 10,
  92 + total: 0
  93 + }
  94 + }
  95 + },
  96 + created() {
  97 + this._initMethod()
  98 + },
  99 + methods: {
  100 + open(_param) {
  101 + this.startDate = _param.startDate
  102 + this.endDate = _param.endDate
  103 + this.communityId = _param.communityId
  104 + this._loadDataReportEarnedDetailStatisticsData(this.page.current, this.page.size)
  105 + },
  106 + async _initMethod() {
  107 + try {
  108 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  109 + this.dataReportEarnedDetailStatisticsInfo.feeTypeCds = data
  110 + } catch (error) {
  111 + console.error('Failed to load dictionary:', error)
  112 + }
  113 + },
  114 + async _loadDataReportEarnedDetailStatisticsData(_page, _row) {
  115 + try {
  116 + const params = {
  117 + communityId: this.communityId,
  118 + startDate: this.startDate,
  119 + endDate: this.endDate,
  120 + objName: this.dataReportEarnedDetailStatisticsInfo.objName,
  121 + ownerName: this.dataReportEarnedDetailStatisticsInfo.ownerName,
  122 + link: this.dataReportEarnedDetailStatisticsInfo.link,
  123 + page: _page,
  124 + row: _row
  125 + }
  126 + const { data, records } = await queryReceivedDetailStatistics(params)
  127 + this.dataReportEarnedDetailStatisticsInfo.fees = data
  128 + this.page.total = records
  129 + } catch (error) {
  130 + console.error('Failed to load data:', error)
  131 + }
  132 + },
  133 + async _exportReportEarnedDetailExcel() {
  134 + try {
  135 + const params = {
  136 + communityId: this.communityId,
  137 + startDate: this.startDate,
  138 + endDate: this.endDate,
  139 + objName: this.dataReportEarnedDetailStatisticsInfo.objName,
  140 + ownerName: this.dataReportEarnedDetailStatisticsInfo.ownerName,
  141 + link: this.dataReportEarnedDetailStatisticsInfo.link,
  142 + pagePath: 'dataReportEarnedDetailStatistics'
  143 + }
  144 + const res = await exportData(params)
  145 + this.$message.success(res.msg)
  146 + if (res.code === 0) {
  147 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  148 + }
  149 + } catch (error) {
  150 + console.error('Export failed:', error)
  151 + }
  152 + },
  153 + _qureyDataReportEarnedDetailStatistics() {
  154 + this.page.current = 1
  155 + this._loadDataReportEarnedDetailStatisticsData(this.page.current, this.page.size)
  156 + },
  157 + handleSizeChange(val) {
  158 + this.page.size = val
  159 + this._loadDataReportEarnedDetailStatisticsData(this.page.current, val)
  160 + },
  161 + handleCurrentChange(val) {
  162 + this.page.current = val
  163 + this._loadDataReportEarnedDetailStatisticsData(val, this.page.size)
  164 + }
  165 + }
  166 +}
  167 +</script>
  168 +
  169 +<style scoped>
  170 +.margin-top {
  171 + margin-top: 20px;
  172 +}
  173 +
  174 +.margin-top-lg {
  175 + margin-top: 30px;
  176 +}
  177 +
  178 +.text-right {
  179 + text-align: right;
  180 +}
  181 +</style>
0 182 \ No newline at end of file
... ...
src/components/report/DataReportEarnedStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <div class="text-right">
  4 + <el-button type="primary" size="small" @click="_exportReportEarnedExcel">
  5 + <i class="el-icon-download"></i>
  6 + <span>{{ $t('dataReport.export') }}</span>
  7 + </el-button>
  8 + </div>
  9 + <div class="margin-top">
  10 + <el-table :data="dataReportEarnedStatisticsInfo.fees" border style="width: 100%">
  11 + <el-table-column prop="floorNum" :label="$t('dataReport.building')" align="center" />
  12 + <el-table-column prop="roomCount" :label="$t('dataReport.roomCount')" align="center" />
  13 + <el-table-column prop="feeRoomCount" :label="$t('dataReport.feeRoomCount')" align="center" />
  14 + <el-table-column prop="receivedFee" :label="$t('dataReport.receivedFee')" align="center" />
  15 + <el-table-column v-for="(item, index) in dataReportEarnedStatisticsInfo.feeTypeCds" :key="index"
  16 + :label="item.name" align="center">
  17 + <template slot-scope="scope">
  18 + {{ scope.row['receivedFee' + item.statusCd] || 0 }}
  19 + </template>
  20 + </el-table-column>
  21 + </el-table>
  22 +
  23 + <el-row class="margin-top">
  24 + <el-col :span="8">
  25 + <span>{{ $t('dataReport.totalReceived') }}:</span>
  26 + <span>{{ dataReportEarnedStatisticsInfo.feeAmount }}</span>
  27 + </el-col>
  28 + <el-col :span="16" class="text-right">
  29 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  30 + layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  31 + @current-change="handleCurrentChange" />
  32 + </el-col>
  33 + </el-row>
  34 + </div>
  35 + </div>
  36 +</template>
  37 +
  38 +<script>
  39 +import { getDict } from '@/api/community/communityApi'
  40 +import { queryReceivedStatistics, exportData } from '@/api/report/dataReportApi'
  41 +
  42 +export default {
  43 + name: 'DataReportEarnedStatistics',
  44 + data() {
  45 + return {
  46 + dataReportEarnedStatisticsInfo: {
  47 + fees: [],
  48 + feeTypeCds: [],
  49 + feeAmount: '0'
  50 + },
  51 + startDate: '',
  52 + endDate: '',
  53 + communityId: '',
  54 + page: {
  55 + current: 1,
  56 + size: 10,
  57 + total: 0
  58 + }
  59 + }
  60 + },
  61 + created() {
  62 + this._initMethod()
  63 + },
  64 + methods: {
  65 + open(_param) {
  66 + this.startDate = _param.startDate
  67 + this.endDate = _param.endDate
  68 + this.communityId = _param.communityId
  69 + this._loadDataReportEarnedStatisticsData(this.page.current, this.page.size)
  70 + },
  71 + async _initMethod() {
  72 + try {
  73 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  74 + this.dataReportEarnedStatisticsInfo.feeTypeCds = data
  75 + } catch (error) {
  76 + console.error('Failed to load dictionary:', error)
  77 + }
  78 + },
  79 + async _loadDataReportEarnedStatisticsData(_page, _row) {
  80 + try {
  81 + const params = {
  82 + communityId: this.communityId,
  83 + startDate: this.startDate,
  84 + endDate: this.endDate,
  85 + page: _page,
  86 + row: _row
  87 + }
  88 + const { data, records } = await queryReceivedStatistics(params)
  89 + this.dataReportEarnedStatisticsInfo.fees = data
  90 + this.page.total = records
  91 +
  92 + let _feeAmount = 0.0
  93 + if (data && data.length > 0) {
  94 + data.forEach(item => {
  95 + _feeAmount += parseFloat(item.receivedFee)
  96 + })
  97 + }
  98 + this.dataReportEarnedStatisticsInfo.feeAmount = _feeAmount.toFixed(2)
  99 + } catch (error) {
  100 + console.error('Failed to load data:', error)
  101 + }
  102 + },
  103 + async _exportReportEarnedExcel() {
  104 + try {
  105 + const params = {
  106 + communityId: this.communityId,
  107 + startDate: this.startDate,
  108 + endDate: this.endDate,
  109 + pagePath: 'dataReportEarnedStatistics'
  110 + }
  111 + const res = await exportData(params)
  112 + this.$message.success(res.msg)
  113 + if (res.code === 0) {
  114 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  115 + }
  116 + } catch (error) {
  117 + console.error('Export failed:', error)
  118 + }
  119 + },
  120 + handleSizeChange(val) {
  121 + this.page.size = val
  122 + this._loadDataReportEarnedStatisticsData(this.page.current, val)
  123 + },
  124 + handleCurrentChange(val) {
  125 + this.page.current = val
  126 + this._loadDataReportEarnedStatisticsData(val, this.page.size)
  127 + }
  128 + }
  129 +}
  130 +</script>
  131 +
  132 +<style scoped>
  133 +.margin-top {
  134 + margin-top: 20px;
  135 +}
  136 +
  137 +.text-right {
  138 + text-align: right;
  139 +}
  140 +</style>
0 141 \ No newline at end of file
... ...
src/components/report/DataReportEarnedWayStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <div class="text-right">
  4 + <el-button type="primary" size="small" @click="_exportReportEarnedWayExcel">
  5 + <i class="el-icon-download"></i>
  6 + <span>{{ $t('dataReport.export') }}</span>
  7 + </el-button>
  8 + </div>
  9 + <div class="margin-top">
  10 + <el-table :data="[dataReportEarnedWayStatisticsInfo.fees]" border style="width: 100%">
  11 + <el-table-column v-for="(item, index) in dataReportEarnedWayStatisticsInfo.fees" :key="index" :label="item.name"
  12 + align="center">
  13 + <template>
  14 + {{ item.receivedAmount || 0 }}
  15 + </template>
  16 + </el-table-column>
  17 + </el-table>
  18 + </div>
  19 + </div>
  20 +</template>
  21 +
  22 +<script>
  23 +import { queryReceivedWayStatistics, exportData } from '@/api/report/dataReportApi'
  24 +
  25 +export default {
  26 + name: 'DataReportEarnedWayStatistics',
  27 +
  28 + data() {
  29 + return {
  30 + dataReportEarnedWayStatisticsInfo: {
  31 + fees: []
  32 + },
  33 + startDate: '',
  34 + endDate: '',
  35 + communityId: ''
  36 + }
  37 + },
  38 + created() {
  39 + },
  40 + methods: {
  41 + open(_param) {
  42 + this.startDate = _param.startDate
  43 + this.endDate = _param.endDate
  44 + this.communityId = _param.communityId
  45 + this._loadDataReportEarnedWayStatisticsData()
  46 + },
  47 + async _loadDataReportEarnedWayStatisticsData() {
  48 + try {
  49 + const params = {
  50 + communityId: this.communityId,
  51 + startDate: this.startDate,
  52 + endDate: this.endDate
  53 + }
  54 + const { data } = await queryReceivedWayStatistics(params)
  55 + this.dataReportEarnedWayStatisticsInfo.fees = data
  56 + } catch (error) {
  57 + console.error('Failed to load data:', error)
  58 + }
  59 + },
  60 + async _exportReportEarnedWayExcel() {
  61 + try {
  62 + const params = {
  63 + communityId: this.communityId,
  64 + startDate: this.startDate,
  65 + endDate: this.endDate,
  66 + pagePath: 'dataReportEarnedWayStatistics'
  67 + }
  68 + const res = await exportData(params)
  69 + this.$message.success(res.msg)
  70 + if (res.code === 0) {
  71 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  72 + }
  73 + } catch (error) {
  74 + console.error('Export failed:', error)
  75 + }
  76 + }
  77 + }
  78 +}
  79 +</script>
  80 +
  81 +<style scoped>
  82 +.margin-top {
  83 + margin-top: 20px;
  84 +}
  85 +
  86 +.text-right {
  87 + text-align: right;
  88 +}
  89 +</style>
0 90 \ No newline at end of file
... ...
src/components/report/DataReportFeeStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <el-row>
  4 + <el-col :span="3" class="padding-r-0">
  5 + <el-card class="border-radius">
  6 + <div class="treeview attendance-staff" style="height: 650px;">
  7 + <ul class="list-group text-center border-radius">
  8 + <li v-for="(item, index) in dataReportFeeStatisticsInfo.feeTypeCds" :key="index"
  9 + class="list-group-item node-orgTree"
  10 + :class="{ 'vc-node-selected': dataReportFeeStatisticsInfo.feeTypeCd === item.statusCd }"
  11 + @click="swatchFeeStatisticsFeeTypeCd(item.statusCd)">
  12 + {{ item.name }}
  13 + </li>
  14 + </ul>
  15 + </div>
  16 + </el-card>
  17 + </el-col>
  18 + <el-col :span="21">
  19 + <el-row>
  20 + <el-col :span="24" class="text-right">
  21 + <el-button type="primary" size="small" @click="_exportReportFeeExcel">
  22 + <i class="el-icon-download"></i>
  23 + <span>{{ $t('dataReport.export') }}</span>
  24 + </el-button>
  25 + </el-col>
  26 + </el-row>
  27 + <div class="margin-top">
  28 + <el-table :data="dataReportFeeStatisticsInfo.fees" border style="width: 100%">
  29 + <el-table-column prop="floorNum" :label="$t('dataReport.building')" align="center" />
  30 + <el-table-column prop="roomCount" :label="$t('dataReport.roomCount')" align="center" />
  31 + <el-table-column prop="feeRoomCount" :label="$t('dataReport.feeRoomCount')" align="center" />
  32 + <el-table-column prop="hisMonthOweFee" :label="$t('dataReport.historyOwe')" align="center" />
  33 + <el-table-column prop="oweFee" :label="$t('dataReport.totalOwe')" align="center" />
  34 + <el-table-column prop="todayReceivedRoomCount" :label="$t('dataReport.todayPaidCount')" align="center" />
  35 + <el-table-column prop="todayReceivedRoomAmount" :label="$t('dataReport.todayPaidAmount')" align="center" />
  36 + <el-table-column prop="hisOweReceivedRoomCount" :label="$t('dataReport.historyPaidCount')" align="center" />
  37 + <el-table-column prop="hisOweReceivedRoomAmount" :label="$t('dataReport.historyPaidAmount')" align="center" />
  38 + <el-table-column prop="monthReceivedRoomCount" :label="$t('dataReport.monthPaidCount')" align="center" />
  39 + <el-table-column :label="$t('dataReport.remainingCount')" align="center">
  40 + <template slot-scope="scope">
  41 + {{ (scope.row.feeRoomCount - scope.row.monthReceivedRoomCount).toFixed(0) }}
  42 + </template>
  43 + </el-table-column>
  44 + <el-table-column :label="$t('dataReport.paidRatio')" align="center">
  45 + <template slot-scope="scope">
  46 + {{ scope.row.feeRoomCount > 0 ?
  47 + ((scope.row.monthReceivedRoomCount) / (scope.row.feeRoomCount) * 100).toFixed(2) + '%' : '0%' }}
  48 + </template>
  49 + </el-table-column>
  50 + <el-table-column prop="monthReceivedRoomAmount" :label="$t('dataReport.monthPaidAmount')" align="center" />
  51 + <el-table-column prop="curMonthOweFee" :label="$t('dataReport.monthRemaining')" align="center" />
  52 + <el-table-column :label="$t('dataReport.collectionRate')" align="center">
  53 + <template slot-scope="scope">
  54 + {{ scope.row.curReceivableFee > 0 ?
  55 + ((scope.row.monthReceivedRoomAmount) / (scope.row.curReceivableFee) * 100).toFixed(2) + '%' : '0%' }}
  56 + </template>
  57 + </el-table-column>
  58 + </el-table>
  59 + </div>
  60 + </el-col>
  61 + </el-row>
  62 + </div>
  63 +</template>
  64 +
  65 +<script>
  66 +import { getDict } from '@/api/community/communityApi'
  67 +import { queryDataReportFeeStatistics, exportData, queryFloors } from '@/api/report/dataReportApi'
  68 +
  69 +export default {
  70 + name: 'DataReportFeeStatistics',
  71 +
  72 + data() {
  73 + return {
  74 + dataReportFeeStatisticsInfo: {
  75 + fees: [],
  76 + feeTypeCds: [],
  77 + floors: [],
  78 + feeTypeCd: ''
  79 + },
  80 + startDate: '',
  81 + endDate: '',
  82 + communityId: '',
  83 + }
  84 + },
  85 + created() {
  86 + },
  87 + methods: {
  88 + open(param){
  89 + this.startDate = param.startDate
  90 + this.endDate = param.endDate
  91 + this.communityId = param.communityId
  92 + this._initMethod()
  93 + },
  94 + async _initMethod() {
  95 + try {
  96 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  97 + this.dataReportFeeStatisticsInfo.feeTypeCds = data
  98 + this.dataReportFeeStatisticsInfo.feeTypeCd = data[0].statusCd
  99 + this._loadFloors()
  100 + } catch (error) {
  101 + console.error('Failed to load dictionary:', error)
  102 + }
  103 + },
  104 + async _loadFloors() {
  105 + try {
  106 + const params = {
  107 + page: 1,
  108 + row: 100,
  109 + communityId: this.communityId
  110 + }
  111 + const { apiFloorDataVoList } = await queryFloors(params)
  112 + this.dataReportFeeStatisticsInfo.floors = apiFloorDataVoList
  113 + this.dataReportFeeStatisticsInfo.fees = []
  114 +
  115 + const _floorIds = []
  116 + for (let i = 0; i < apiFloorDataVoList.length; i++) {
  117 + _floorIds.push(apiFloorDataVoList[i].floorId)
  118 + if (_floorIds.length >= 5) {
  119 + await this._loadDataReportFeeStatisticsData(_floorIds.join(','))
  120 + _floorIds.length = 0
  121 + }
  122 + }
  123 +
  124 + if (_floorIds.length > 0) {
  125 + await this._loadDataReportFeeStatisticsData(_floorIds.join(','))
  126 + }
  127 + } catch (error) {
  128 + console.error('Failed to load floors:', error)
  129 + }
  130 + },
  131 + async _loadDataReportFeeStatisticsData(_floorIds) {
  132 + try {
  133 + const params = {
  134 + communityId: this.communityId,
  135 + startDate: this.startDate,
  136 + endDate: this.endDate,
  137 + feeTypeCd: this.dataReportFeeStatisticsInfo.feeTypeCd,
  138 + floorIds: _floorIds
  139 + }
  140 + const { data } = await queryDataReportFeeStatistics(params)
  141 + data.forEach(item => {
  142 + this.dataReportFeeStatisticsInfo.fees.push(item)
  143 + })
  144 + } catch (error) {
  145 + console.error('Failed to load data:', error)
  146 + }
  147 + },
  148 + async _exportReportFeeExcel() {
  149 + try {
  150 + const _floorIds = this.dataReportFeeStatisticsInfo.floors.map(item => item.floorId)
  151 + if (!_floorIds || _floorIds.length < 1) {
  152 + this.$message.warning(this.$t('dataReport.noExportData'))
  153 + return
  154 + }
  155 +
  156 + const params = {
  157 + communityId: this.communityId,
  158 + startDate: this.startDate,
  159 + endDate: this.endDate,
  160 + feeTypeCd: this.dataReportFeeStatisticsInfo.feeTypeCd,
  161 + floorIds: _floorIds.join(','),
  162 + pagePath: 'dataReportFeeStatistics'
  163 + }
  164 + const res = await exportData(params)
  165 + this.$message.success(res.msg)
  166 + if (res.code === 0) {
  167 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  168 + }
  169 + } catch (error) {
  170 + console.error('Export failed:', error)
  171 + }
  172 + },
  173 + swatchFeeStatisticsFeeTypeCd(_feeTypeCd) {
  174 + this.dataReportFeeStatisticsInfo.feeTypeCd = _feeTypeCd
  175 + this._loadFloors()
  176 + }
  177 + }
  178 +}
  179 +</script>
  180 +
  181 +<style scoped>
  182 +.margin-top {
  183 + margin-top: 20px;
  184 +}
  185 +
  186 +.text-right {
  187 + text-align: right;
  188 +}
  189 +
  190 +.padding-r-0 {
  191 + padding-right: 0;
  192 +}
  193 +
  194 +.border-radius {
  195 + border-radius: 4px;
  196 +}
  197 +
  198 +.list-group {
  199 + list-style: none;
  200 + padding: 0;
  201 + margin: 0;
  202 +}
  203 +
  204 +.list-group-item {
  205 + padding: 10px;
  206 + cursor: pointer;
  207 + border-bottom: 1px solid #eee;
  208 +}
  209 +
  210 +.list-group-item:hover {
  211 + background-color: #f5f5f5;
  212 +}
  213 +
  214 +.vc-node-selected {
  215 + background-color: #409EFF;
  216 + color: white;
  217 +}
  218 +
  219 +.treeview {
  220 + overflow-y: auto;
  221 +}</style>
0 222 \ No newline at end of file
... ...
src/components/report/DataReportOweDetailStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <el-row class="margin-top-lg">
  4 + <el-col :span="4">
  5 + <el-input v-model="dataReportOweDetailStatisticsInfo.objName" :placeholder="$t('dataReport.roomNumber')"
  6 + clearable />
  7 + </el-col>
  8 + <el-col :span="4">
  9 + <el-input v-model="dataReportOweDetailStatisticsInfo.ownerName" :placeholder="$t('dataReport.ownerName')"
  10 + clearable />
  11 + </el-col>
  12 + <el-col :span="4">
  13 + <el-input v-model="dataReportOweDetailStatisticsInfo.link" :placeholder="$t('dataReport.phoneNumber')"
  14 + clearable />
  15 + </el-col>
  16 + <el-col :span="4">
  17 + <el-button type="primary" size="small" @click="_qureyDataReportOweDetailStatistics">
  18 + <i class="el-icon-search"></i>
  19 + {{ $t('dataReport.search') }}
  20 + </el-button>
  21 + <el-button type="default" size="small" @click="_resetDataReportOweDetailStatistics">
  22 + <i class="el-icon-refresh"></i>
  23 + {{ $t('dataReport.reset') }}
  24 + </el-button>
  25 + </el-col>
  26 + <el-col :span="8" class="text-right">
  27 + <el-button type="primary" size="small" @click="_exportReportOweDetailExcel">
  28 + <i class="el-icon-download"></i>
  29 + <span>{{ $t('dataReport.export') }}</span>
  30 + </el-button>
  31 + </el-col>
  32 + </el-row>
  33 +
  34 + <div class="margin-top">
  35 + <el-table :data="dataReportOweDetailStatisticsInfo.fees" border style="width: 100%">
  36 + <el-table-column prop="roomName" :label="$t('dataReport.room')" align="center" />
  37 + <el-table-column prop="ownerName" :label="$t('dataReport.owner')" align="center" />
  38 + <el-table-column prop="oweFee" :label="$t('dataReport.oweFee')" align="center" />
  39 + <el-table-column v-for="(item, index) in dataReportOweDetailStatisticsInfo.feeTypeCds" :key="index"
  40 + :label="item.name" align="center">
  41 + <template slot-scope="scope">
  42 + <div v-if="scope.row['oweFee' + item.statusCd]">
  43 + <div v-for="(feeItem, fIndex) in scope.row['oweFee' + item.statusCd]" :key="fIndex">
  44 + {{ feeItem.feeName }}({{ feeItem.endTime }}~{{ feeItem.deadlineTime }})={{ feeItem.amountOwed }}
  45 + </div>
  46 + </div>
  47 + <div v-else>
  48 + 0
  49 + </div>
  50 + </template>
  51 + </el-table-column>
  52 + </el-table>
  53 +
  54 + <el-row class="margin-top">
  55 + <el-col :span="24" class="text-right">
  56 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  57 + layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  58 + @current-change="handleCurrentChange" />
  59 + </el-col>
  60 + </el-row>
  61 + </div>
  62 + </div>
  63 +</template>
  64 +
  65 +<script>
  66 +import { getDict } from '@/api/community/communityApi'
  67 +import { queryOweDetailStatistics, exportData } from '@/api/report/dataReportApi'
  68 +
  69 +export default {
  70 + name: 'DataReportOweDetailStatistics',
  71 +
  72 + data() {
  73 + return {
  74 + dataReportOweDetailStatisticsInfo: {
  75 + fees: [],
  76 + feeTypeCds: [],
  77 + objName: '',
  78 + ownerName: '',
  79 + link: '',
  80 + feeAmount: '0'
  81 + },
  82 + startDate: '',
  83 + endDate: '',
  84 + communityId: '',
  85 + page: {
  86 + current: 1,
  87 + size: 10,
  88 + total: 0
  89 + }
  90 + }
  91 + },
  92 + created() {
  93 + this._initMethod()
  94 + },
  95 + methods: {
  96 + open(param){
  97 + this.startDate = param.startDate
  98 + this.endDate = param.endDate
  99 + this.communityId = param.communityId
  100 + this._loadDataReportOweDetailStatisticsData(this.page.current, this.page.size)
  101 + },
  102 + async _initMethod() {
  103 + try {
  104 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  105 + this.dataReportOweDetailStatisticsInfo.feeTypeCds = data
  106 + } catch (error) {
  107 + console.error('Failed to load dictionary:', error)
  108 + }
  109 + },
  110 + async _loadDataReportOweDetailStatisticsData(_page, _row) {
  111 + try {
  112 + const params = {
  113 + communityId: this.communityId,
  114 + startDate: this.startDate,
  115 + endDate: this.endDate,
  116 + objName: this.dataReportOweDetailStatisticsInfo.objName,
  117 + ownerName: this.dataReportOweDetailStatisticsInfo.ownerName,
  118 + link: this.dataReportOweDetailStatisticsInfo.link,
  119 + page: _page,
  120 + row: _row
  121 + }
  122 + const { data, records } = await queryOweDetailStatistics(params)
  123 + this.dataReportOweDetailStatisticsInfo.fees = data
  124 + this.page.total = records
  125 +
  126 + let _feeAmount = 0.0
  127 + if (data && data.length > 0) {
  128 + data.forEach(item => {
  129 + _feeAmount += parseFloat(item.oweFee)
  130 + })
  131 + }
  132 + this.dataReportOweDetailStatisticsInfo.feeAmount = _feeAmount.toFixed(2)
  133 + } catch (error) {
  134 + console.error('Failed to load data:', error)
  135 + }
  136 + },
  137 + async _exportReportOweDetailExcel() {
  138 + try {
  139 + const params = {
  140 + communityId: this.communityId,
  141 + startDate: this.startDate,
  142 + endDate: this.endDate,
  143 + objName: this.dataReportOweDetailStatisticsInfo.objName,
  144 + ownerName: this.dataReportOweDetailStatisticsInfo.ownerName,
  145 + link: this.dataReportOweDetailStatisticsInfo.link,
  146 + pagePath: 'dataReportOweDetailStatistics'
  147 + }
  148 + const res = await exportData(params)
  149 + this.$message.success(res.msg)
  150 + if (res.code === 0) {
  151 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  152 + }
  153 + } catch (error) {
  154 + console.error('Export failed:', error)
  155 + }
  156 + },
  157 + _qureyDataReportOweDetailStatistics() {
  158 + this.page.current = 1
  159 + this._loadDataReportOweDetailStatisticsData(this.page.current, this.page.size)
  160 + },
  161 + _resetDataReportOweDetailStatistics() {
  162 + this.dataReportOweDetailStatisticsInfo.objName = ''
  163 + this.dataReportOweDetailStatisticsInfo.ownerName = ''
  164 + this.dataReportOweDetailStatisticsInfo.link = ''
  165 + this._qureyDataReportOweDetailStatistics()
  166 + },
  167 + handleSizeChange(val) {
  168 + this.page.size = val
  169 + this._loadDataReportOweDetailStatisticsData(this.page.current, val)
  170 + },
  171 + handleCurrentChange(val) {
  172 + this.page.current = val
  173 + this._loadDataReportOweDetailStatisticsData(val, this.page.size)
  174 + }
  175 + }
  176 +}
  177 +</script>
  178 +
  179 +<style scoped>
  180 +.margin-top {
  181 + margin-top: 20px;
  182 +}
  183 +
  184 +.margin-top-lg {
  185 + margin-top: 30px;
  186 +}
  187 +
  188 +.text-right {
  189 + text-align: right;
  190 +}
  191 +</style>
0 192 \ No newline at end of file
... ...
src/components/report/DataReportOweStatistics.vue 0 → 100644
  1 +<template>
  2 + <div class="margin-top">
  3 + <div class="text-right">
  4 + <el-button type="primary" size="small" @click="_exportReportOweExcel">
  5 + <i class="el-icon-download"></i>
  6 + <span>{{ $t('dataReport.export') }}</span>
  7 + </el-button>
  8 + </div>
  9 + <div class="margin-top">
  10 + <el-table :data="dataReportOweStatisticsInfo.fees" border style="width: 100%">
  11 + <el-table-column prop="floorNum" :label="$t('dataReport.building')" align="center" />
  12 + <el-table-column prop="oweFee" :label="$t('dataReport.oweFee')" align="center" />
  13 + <el-table-column v-for="(item, index) in dataReportOweStatisticsInfo.feeTypeCds" :key="index" :label="item.name"
  14 + align="center">
  15 + <template slot-scope="scope">
  16 + {{ scope.row['oweFee' + item.statusCd] || 0 }}
  17 + </template>
  18 + </el-table-column>
  19 + </el-table>
  20 +
  21 + <el-row class="margin-top">
  22 + <el-col :span="8">
  23 + <span>{{ $t('dataReport.totalOwe') }}:</span>
  24 + <span>{{ dataReportOweStatisticsInfo.feeAmount }}</span>
  25 + </el-col>
  26 + <el-col :span="16" class="text-right">
  27 + <el-pagination :current-page.sync="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size"
  28 + layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  29 + @current-change="handleCurrentChange" />
  30 + </el-col>
  31 + </el-row>
  32 + </div>
  33 + </div>
  34 +</template>
  35 +
  36 +<script>
  37 +import { getDict } from '@/api/community/communityApi'
  38 +import { queryOweStatistics, exportData } from '@/api/report/dataReportApi'
  39 +
  40 +export default {
  41 + name: 'DataReportOweStatistics',
  42 +
  43 + data() {
  44 + return {
  45 + dataReportOweStatisticsInfo: {
  46 + fees: [],
  47 + feeTypeCds: [],
  48 + feeAmount: '0'
  49 + },
  50 + startDate: '',
  51 + endDate: '',
  52 + communityId: '',
  53 + page: {
  54 + current: 1,
  55 + size: 10,
  56 + total: 0
  57 + }
  58 + }
  59 + },
  60 + created() {
  61 + this._initMethod()
  62 + },
  63 + methods: {
  64 + open(param){
  65 + this.startDate = param.startDate
  66 + this.endDate = param.endDate
  67 + this.communityId = param.communityId
  68 + this._loadDataReportOweStatisticsData(this.page.current, this.page.size)
  69 + },
  70 + async _initMethod() {
  71 + try {
  72 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  73 + this.dataReportOweStatisticsInfo.feeTypeCds = data
  74 + } catch (error) {
  75 + console.error('Failed to load dictionary:', error)
  76 + }
  77 + },
  78 + async _loadDataReportOweStatisticsData(_page, _row) {
  79 + try {
  80 + const params = {
  81 + communityId: this.communityId,
  82 + startDate: this.startDate,
  83 + endDate: this.endDate,
  84 + page: _page,
  85 + row: _row
  86 + }
  87 + const { data, records } = await queryOweStatistics(params)
  88 + this.dataReportOweStatisticsInfo.fees = data
  89 + this.page.total = records
  90 +
  91 + let _feeAmount = 0.0
  92 + if (data && data.length > 0) {
  93 + data.forEach(item => {
  94 + _feeAmount += parseFloat(item.oweFee)
  95 + })
  96 + }
  97 + this.dataReportOweStatisticsInfo.feeAmount = _feeAmount.toFixed(2)
  98 + } catch (error) {
  99 + console.error('Failed to load data:', error)
  100 + }
  101 + },
  102 + async _exportReportOweExcel() {
  103 + try {
  104 + const params = {
  105 + communityId: this.communityId,
  106 + startDate: this.startDate,
  107 + endDate: this.endDate,
  108 + pagePath: 'dataReportOweStatistics'
  109 + }
  110 + const res = await exportData(params)
  111 + this.$message.success(res.msg)
  112 + if (res.code === 0) {
  113 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  114 + }
  115 + } catch (error) {
  116 + console.error('Export failed:', error)
  117 + }
  118 + },
  119 + handleSizeChange(val) {
  120 + this.page.size = val
  121 + this._loadDataReportOweStatisticsData(this.page.current, val)
  122 + },
  123 + handleCurrentChange(val) {
  124 + this.page.current = val
  125 + this._loadDataReportOweStatisticsData(val, this.page.size)
  126 + }
  127 + }
  128 +}
  129 +</script>
  130 +
  131 +<style scoped>
  132 +.margin-top {
  133 + margin-top: 20px;
  134 +}
  135 +
  136 +.text-right {
  137 + text-align: right;
  138 +}
  139 +</style>
0 140 \ No newline at end of file
... ...
src/components/report/configFeeSummary.vue 0 → 100644
  1 +<template>
  2 + <el-card class="config-fee-summary-container">
  3 + <div slot="header">
  4 + <span>{{ $t('reportFeeSummary.configFeeSummary') }}</span>
  5 + </div>
  6 + <div id="configFeeSummary" style="height:300px;width:100%;"></div>
  7 + </el-card>
  8 +</template>
  9 +
  10 +<script>
  11 +import * as echarts from 'echarts'
  12 +import { queryReportConfigFeeSummary } from '@/api/report/reportFeeSummaryApi'
  13 +
  14 +export default {
  15 + name: 'ConfigFeeSummary',
  16 + data() {
  17 + return {
  18 + chart: null,
  19 + conditions: {}
  20 + }
  21 + },
  22 + mounted() {
  23 + this.initChart()
  24 + window.addEventListener('resize', this.handleResize)
  25 + },
  26 + beforeDestroy() {
  27 + window.removeEventListener('resize', this.handleResize)
  28 + if (this.chart) {
  29 + this.chart.dispose()
  30 + }
  31 + },
  32 + methods: {
  33 + notify(params) {
  34 + this.conditions = params
  35 + this.loadConfigFeeSummaryRate()
  36 + },
  37 + initChart() {
  38 + this.chart = echarts.init(document.getElementById('configFeeSummary'))
  39 + this.setDefaultOption()
  40 + },
  41 + setDefaultOption() {
  42 + const option = {
  43 + legend: {},
  44 + tooltip: {},
  45 + title: {
  46 + show: true,
  47 + text: this.$t('reportFeeSummary.configFeeRateStatistics')
  48 + },
  49 + color: ['#FFDAB9', '#66CDAA'],
  50 + dataset: {
  51 + source: [
  52 + ['product', this.$t('reportFeeSummary.roomChargeRate'), this.$t('reportFeeSummary.chargeRate')]
  53 + ]
  54 + },
  55 + xAxis: { type: 'category' },
  56 + yAxis: {},
  57 + series: [
  58 + { type: 'bar' },
  59 + { type: 'bar' }
  60 + ]
  61 + }
  62 + this.chart.setOption(option)
  63 + },
  64 + async loadConfigFeeSummaryRate() {
  65 + try {
  66 + const { data } = await queryReportConfigFeeSummary(this.conditions )
  67 + this.initConfigFeeSummaryChart(data)
  68 + } catch (error) {
  69 + console.error('Failed to load config fee summary:', error)
  70 + }
  71 + },
  72 + initConfigFeeSummaryChart(data) {
  73 + if (!this.chart) {
  74 + this.initChart()
  75 + }
  76 +
  77 + const source = [
  78 + ['product', this.$t('reportFeeSummary.roomChargeRate'), this.$t('reportFeeSummary.chargeRate')]
  79 + ]
  80 +
  81 + data.forEach(item => {
  82 + source.push([
  83 + item.name,
  84 + item.feeRoomRate,
  85 + item.feeRate
  86 + ])
  87 + })
  88 +
  89 + this.chart.setOption({
  90 + dataset: {
  91 + source
  92 + }
  93 + })
  94 + },
  95 + handleResize() {
  96 + if (this.chart) {
  97 + this.chart.resize()
  98 + }
  99 + }
  100 + }
  101 +}
  102 +</script>
  103 +
  104 +<style lang="scss" scoped>
  105 +.config-fee-summary-container {
  106 + margin-bottom: 20px;
  107 +}
  108 +</style>
0 109 \ No newline at end of file
... ...
src/components/report/floorFeeSummary.vue 0 → 100644
  1 +<template>
  2 + <el-card class="floor-fee-summary-container">
  3 + <div slot="header">
  4 + <span>{{ $t('reportFeeSummary.floorFeeSummary') }}</span>
  5 + </div>
  6 + <div id="floorFeeSummary" style="height:300px;width:100%;"></div>
  7 + </el-card>
  8 +</template>
  9 +
  10 +<script>
  11 +import * as echarts from 'echarts'
  12 +import { queryReportFloorFeeSummary } from '@/api/report/reportFeeSummaryApi'
  13 +
  14 +export default {
  15 + name: 'FloorFeeSummary',
  16 + data() {
  17 + return {
  18 + chart: null,
  19 + conditions: {}
  20 + }
  21 + },
  22 + mounted() {
  23 + this.initChart()
  24 + window.addEventListener('resize', this.handleResize)
  25 + },
  26 + beforeDestroy() {
  27 + window.removeEventListener('resize', this.handleResize)
  28 + if (this.chart) {
  29 + this.chart.dispose()
  30 + }
  31 + },
  32 + methods: {
  33 + notify(params) {
  34 + this.conditions = params
  35 + this.loadFloorFeeSummaryRate()
  36 + },
  37 + initChart() {
  38 + this.chart = echarts.init(document.getElementById('floorFeeSummary'))
  39 + this.setDefaultOption()
  40 + },
  41 + setDefaultOption() {
  42 + const option = {
  43 + legend: {},
  44 + tooltip: {},
  45 + title: {
  46 + show: true,
  47 + text: this.$t('reportFeeSummary.floorFeeRateStatistics')
  48 + },
  49 + color: ['#FFDAB9', '#66CDAA'],
  50 + dataset: {
  51 + source: [
  52 + ['product', this.$t('reportFeeSummary.roomChargeRate'), this.$t('reportFeeSummary.chargeRate')]
  53 + ]
  54 + },
  55 + xAxis: { type: 'category' },
  56 + yAxis: {},
  57 + series: [
  58 + { type: 'bar' },
  59 + { type: 'bar' }
  60 + ]
  61 + }
  62 + this.chart.setOption(option)
  63 + },
  64 + async loadFloorFeeSummaryRate() {
  65 + try {
  66 + const { data } = await queryReportFloorFeeSummary( this.conditions )
  67 + this.initFloorFeeSummaryChart(data)
  68 + } catch (error) {
  69 + console.error('Failed to load floor fee summary:', error)
  70 + }
  71 + },
  72 + initFloorFeeSummaryChart(data) {
  73 + if (!this.chart) {
  74 + this.initChart()
  75 + }
  76 +
  77 + const source = [
  78 + ['product', this.$t('reportFeeSummary.roomChargeRate'), this.$t('reportFeeSummary.chargeRate')]
  79 + ]
  80 +
  81 + data.forEach(item => {
  82 + source.push([
  83 + item.floorName,
  84 + item.feeRoomRate,
  85 + item.feeRate
  86 + ])
  87 + })
  88 +
  89 + this.chart.setOption({
  90 + dataset: {
  91 + source
  92 + }
  93 + })
  94 + },
  95 + handleResize() {
  96 + if (this.chart) {
  97 + this.chart.resize()
  98 + }
  99 + }
  100 + }
  101 +}
  102 +</script>
  103 +
  104 +<style lang="scss" scoped>
  105 +.floor-fee-summary-container {
  106 + margin-bottom: 20px;
  107 +}
  108 +</style>
0 109 \ No newline at end of file
... ...
src/components/report/reportDeadlineFee.vue 0 → 100644
  1 +<template>
  2 + <div class="report-deadline-fee">
  3 + <div class="text-right">
  4 + <el-button
  5 + type="primary"
  6 + size="small"
  7 + @click="_exportExcel"
  8 + >
  9 + <i class="el-icon-download"></i>
  10 + {{ $t('reportDeadlineFee.export') }}
  11 + </el-button>
  12 + </div>
  13 +
  14 + <el-table
  15 + :data="reportDeadlineFeeInfo.fees"
  16 + border
  17 + style="width: 100%"
  18 + class="margin-top"
  19 + >
  20 + <el-table-column
  21 + prop="index"
  22 + :label="$t('reportDeadlineFee.feeId')"
  23 + align="center"
  24 + >
  25 + <template slot-scope="scope">
  26 + {{ scope.$index + 1 }}
  27 + </template>
  28 + </el-table-column>
  29 + <el-table-column
  30 + prop="objName"
  31 + :label="$t('reportDeadlineFee.objName')"
  32 + align="center"
  33 + />
  34 + <el-table-column
  35 + prop="feeName"
  36 + :label="$t('reportDeadlineFee.feeName')"
  37 + align="center"
  38 + />
  39 + <el-table-column
  40 + prop="deadlineTime"
  41 + :label="$t('reportDeadlineFee.deadlineTime')"
  42 + align="center"
  43 + />
  44 + <el-table-column
  45 + prop="oweDay"
  46 + :label="$t('reportDeadlineFee.oweDay')"
  47 + align="center"
  48 + />
  49 + </el-table>
  50 +
  51 + <el-row class="margin-top">
  52 + <el-col :span="18">
  53 + <div class="tip-text">
  54 + {{ $t('reportDeadlineFee.tip') }}
  55 + </div>
  56 + </el-col>
  57 + <el-col :span="6" class="text-right">
  58 + <el-pagination
  59 + :current-page.sync="pagination.current"
  60 + :page-sizes="[10, 20, 30, 50]"
  61 + :page-size="pagination.size"
  62 + :total="pagination.total"
  63 + layout="total, sizes, prev, pager, next, jumper"
  64 + @size-change="handleSizeChange"
  65 + @current-change="handleCurrentChange"
  66 + />
  67 + </el-col>
  68 + </el-row>
  69 + </div>
  70 +</template>
  71 +
  72 +<script>
  73 +import { getCommunityId } from '@/api/community/communityApi'
  74 +import { queryDeadlineFee, exportData } from '@/api/report/feeRemindApi'
  75 +
  76 +export default {
  77 + name: 'ReportDeadlineFee',
  78 + data() {
  79 + return {
  80 + reportDeadlineFeeInfo: {
  81 + fees: [],
  82 + conditions: {}
  83 + },
  84 + pagination: {
  85 + current: 1,
  86 + size: 10,
  87 + total: 0
  88 + }
  89 + }
  90 + },
  91 + methods: {
  92 + async loadData(conditions) {
  93 + this.reportDeadlineFeeInfo.conditions = { ...conditions }
  94 + await this._listDeadlineFees(this.pagination.current, this.pagination.size)
  95 + },
  96 + async _listDeadlineFees(page, size) {
  97 + try {
  98 + const params = {
  99 + ...this.reportDeadlineFeeInfo.conditions,
  100 + page,
  101 + row: size
  102 + }
  103 + const { data, total } = await queryDeadlineFee(params)
  104 + this.reportDeadlineFeeInfo.fees = data
  105 + this.pagination.total = total
  106 + } catch (error) {
  107 + console.error('Failed to load deadline fees:', error)
  108 + }
  109 + },
  110 + async _exportExcel() {
  111 + try {
  112 + const params = {
  113 + ...this.reportDeadlineFeeInfo.conditions,
  114 + communityId: getCommunityId(),
  115 + pagePath: 'reportDeadlineFee'
  116 + }
  117 + const { code, msg } = await exportData(params)
  118 + this.$message.success(msg)
  119 + if (code === 0) {
  120 + this.$router.push('/pages/property/downloadTempFile?tab=downloadCenter')
  121 + }
  122 + } catch (error) {
  123 + console.error('Failed to export:', error)
  124 + }
  125 + },
  126 + handleSizeChange(val) {
  127 + this.pagination.size = val
  128 + this._listDeadlineFees(this.pagination.current, val)
  129 + },
  130 + handleCurrentChange(val) {
  131 + this.pagination.current = val
  132 + this._listDeadlineFees(val, this.pagination.size)
  133 + }
  134 + }
  135 +}
  136 +</script>
  137 +
  138 +<style lang="scss" scoped>
  139 +.report-deadline-fee {
  140 + .margin-top {
  141 + margin-top: 15px;
  142 + }
  143 +
  144 + .text-right {
  145 + text-align: right;
  146 + }
  147 +
  148 + .tip-text {
  149 + color: #999;
  150 + font-size: 12px;
  151 + padding: 5px 0;
  152 + }
  153 +}
  154 +</style>
0 155 \ No newline at end of file
... ...
src/components/report/reportFeeDetailCar.vue 0 → 100644
  1 +<template>
  2 + <div class="report-fee-detail-car">
  3 + <div class="operation-bar">
  4 + <el-button
  5 + type="primary"
  6 + size="small"
  7 + @click="exportReportFeeDetailCarExcel">
  8 + <i class="el-icon-download"></i>
  9 + {{ $t('common.export') }}
  10 + </el-button>
  11 + </div>
  12 +
  13 + <el-table
  14 + :data="reportFeeDetailCarInfo.fees"
  15 + border
  16 + style="width: 100%"
  17 + v-loading="loading">
  18 + <el-table-column
  19 + prop="carNum"
  20 + :label="$t('reportFeeDetailCar.car')"
  21 + align="center">
  22 + </el-table-column>
  23 + <el-table-column
  24 + prop="ownerName"
  25 + :label="$t('reportFeeDetailCar.owner')"
  26 + align="center">
  27 + <template slot-scope="scope">
  28 + {{ scope.row.ownerName }}({{ scope.row.link }})
  29 + </template>
  30 + </el-table-column>
  31 + <el-table-column
  32 + prop="oweFee"
  33 + :label="$t('reportFeeDetailCar.oweFee')"
  34 + align="center">
  35 + <template slot-scope="scope">
  36 + {{ scope.row.oweFee || '0' }}
  37 + </template>
  38 + </el-table-column>
  39 + <el-table-column
  40 + prop="receivedFee"
  41 + :label="$t('reportFeeDetailCar.receivedFee')"
  42 + align="center">
  43 + <template slot-scope="scope">
  44 + {{ scope.row.receivedFee || '0' }}
  45 + </template>
  46 + </el-table-column>
  47 + <template v-for="(item,index) in reportFeeDetailCarInfo.feeTypeCds">
  48 + <el-table-column
  49 + :key="index+'owe'"
  50 + :label="item.name + $t('reportFeeDetailCar.owe')"
  51 + align="center">
  52 + <template slot-scope="scope">
  53 + {{ scope.row['oweFee'+item.statusCd] || '0' }}
  54 + </template>
  55 + </el-table-column>
  56 + <el-table-column
  57 + :key="index+'received'"
  58 + :label="item.name + $t('reportFeeDetailCar.received')"
  59 + align="center">
  60 + <template slot-scope="scope">
  61 + {{ scope.row['receivedFee'+item.statusCd] || '0' }}
  62 + </template>
  63 + </el-table-column>
  64 + </template>
  65 + </el-table>
  66 +
  67 + <el-pagination
  68 + @size-change="handleSizeChange"
  69 + @current-change="handleCurrentChange"
  70 + :current-page="pagination.current"
  71 + :page-sizes="[10, 20, 30, 50]"
  72 + :page-size="pagination.size"
  73 + layout="total, sizes, prev, pager, next, jumper"
  74 + :total="pagination.total">
  75 + </el-pagination>
  76 + </div>
  77 +</template>
  78 +
  79 +<script>
  80 +import { getDict } from '@/api/community/communityApi'
  81 +import { queryReportFeeDetailCar, exportReportFeeDetailCar } from '@/api/report/reportFeeDetailApi'
  82 +
  83 +export default {
  84 + name: 'ReportFeeDetailCar',
  85 + data() {
  86 + return {
  87 + reportFeeDetailCarInfo: {
  88 + fees: [],
  89 + feeTypeCds: [],
  90 + conditions: {}
  91 + },
  92 + loading: false,
  93 + pagination: {
  94 + current: 1,
  95 + size: 10,
  96 + total: 0
  97 + }
  98 + }
  99 + },
  100 + created() {
  101 + this.getDictData()
  102 + },
  103 + methods: {
  104 + async getDictData() {
  105 + try {
  106 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  107 + this.reportFeeDetailCarInfo.feeTypeCds = data
  108 + } catch (error) {
  109 + console.error('获取字典数据失败:', error)
  110 + }
  111 + },
  112 + async open(conditions) {
  113 + this.reportFeeDetailCarInfo.conditions = conditions
  114 + this.listReportFeeDetailCars()
  115 + },
  116 + async listReportFeeDetailCars() {
  117 + try {
  118 + this.loading = true
  119 + const params = {
  120 + ...this.reportFeeDetailCarInfo.conditions,
  121 + page: this.pagination.current,
  122 + row: this.pagination.size
  123 + }
  124 + const { data, total } = await queryReportFeeDetailCar(params)
  125 + this.reportFeeDetailCarInfo.fees = data
  126 + this.pagination.total = total
  127 + } catch (error) {
  128 + console.error('获取车辆费用明细失败:', error)
  129 + } finally {
  130 + this.loading = false
  131 + }
  132 + },
  133 + async exportReportFeeDetailCarExcel() {
  134 + try {
  135 + const params = {
  136 + ...this.reportFeeDetailCarInfo.conditions,
  137 + pagePath: 'reportFeeDetailCar'
  138 + }
  139 + await exportReportFeeDetailCar(params)
  140 + this.$message.success(this.$t('common.exportSuccess'))
  141 + } catch (error) {
  142 + console.error('导出失败:', error)
  143 + this.$message.error(this.$t('common.exportFailed'))
  144 + }
  145 + },
  146 + handleSizeChange(val) {
  147 + this.pagination.size = val
  148 + this.listReportFeeDetailCars()
  149 + },
  150 + handleCurrentChange(val) {
  151 + this.pagination.current = val
  152 + this.listReportFeeDetailCars()
  153 + }
  154 + }
  155 +}
  156 +</script>
  157 +
  158 +<style lang="scss" scoped>
  159 +.report-fee-detail-car {
  160 + .operation-bar {
  161 + margin-bottom: 20px;
  162 + text-align: right;
  163 + }
  164 +
  165 + .el-pagination {
  166 + margin-top: 20px;
  167 + text-align: right;
  168 + }
  169 +}
  170 +</style>
0 171 \ No newline at end of file
... ...
src/components/report/reportFeeDetailContract.vue 0 → 100644
  1 +<template>
  2 + <div class="report-fee-detail-contract">
  3 + <div class="operation-bar">
  4 + <el-button
  5 + type="primary"
  6 + size="small"
  7 + @click="exportReportFeeDetailContractExcel">
  8 + <i class="el-icon-download"></i>
  9 + {{ $t('common.export') }}
  10 + </el-button>
  11 + </div>
  12 +
  13 + <el-table
  14 + :data="reportFeeDetailContractInfo.fees"
  15 + border
  16 + style="width: 100%"
  17 + v-loading="loading">
  18 + <el-table-column
  19 + prop="contractName"
  20 + :label="$t('reportFeeDetailContract.contract')"
  21 + align="center">
  22 + </el-table-column>
  23 + <el-table-column
  24 + prop="ownerName"
  25 + :label="$t('reportFeeDetailContract.owner')"
  26 + align="center">
  27 + <template slot-scope="scope">
  28 + {{ scope.row.ownerName }}({{ scope.row.link }})
  29 + </template>
  30 + </el-table-column>
  31 + <el-table-column
  32 + prop="oweFee"
  33 + :label="$t('reportFeeDetailContract.oweFee')"
  34 + align="center">
  35 + <template slot-scope="scope">
  36 + {{ scope.row.oweFee || '0' }}
  37 + </template>
  38 + </el-table-column>
  39 + <el-table-column
  40 + prop="receivedFee"
  41 + :label="$t('reportFeeDetailContract.receivedFee')"
  42 + align="center">
  43 + <template slot-scope="scope">
  44 + {{ scope.row.receivedFee || '0' }}
  45 + </template>
  46 + </el-table-column>
  47 + <template v-for="(item,index) in reportFeeDetailContractInfo.feeTypeCds">
  48 + <el-table-column
  49 + :key="index+'owe'"
  50 + :label="item.name + $t('reportFeeDetailContract.owe')"
  51 + align="center">
  52 + <template slot-scope="scope">
  53 + {{ scope.row['oweFee'+item.statusCd] || '0' }}
  54 + </template>
  55 + </el-table-column>
  56 + <el-table-column
  57 + :key="index+'received'"
  58 + :label="item.name + $t('reportFeeDetailContract.received')"
  59 + align="center">
  60 + <template slot-scope="scope">
  61 + {{ scope.row['receivedFee'+item.statusCd] || '0' }}
  62 + </template>
  63 + </el-table-column>
  64 + </template>
  65 + </el-table>
  66 +
  67 + <el-pagination
  68 + @size-change="handleSizeChange"
  69 + @current-change="handleCurrentChange"
  70 + :current-page="pagination.current"
  71 + :page-sizes="[10, 20, 30, 50]"
  72 + :page-size="pagination.size"
  73 + layout="total, sizes, prev, pager, next, jumper"
  74 + :total="pagination.total">
  75 + </el-pagination>
  76 + </div>
  77 +</template>
  78 +
  79 +<script>
  80 +import { getDict } from '@/api/community/communityApi'
  81 +import { queryReportFeeDetailContract, exportReportFeeDetailContract } from '@/api/report/reportFeeDetailApi'
  82 +
  83 +export default {
  84 + name: 'ReportFeeDetailContract',
  85 + data() {
  86 + return {
  87 + reportFeeDetailContractInfo: {
  88 + fees: [],
  89 + feeTypeCds: [],
  90 + conditions: {}
  91 + },
  92 + loading: false,
  93 + pagination: {
  94 + current: 1,
  95 + size: 10,
  96 + total: 0
  97 + }
  98 + }
  99 + },
  100 + created() {
  101 + this.getDictData()
  102 + },
  103 + methods: {
  104 + async getDictData() {
  105 + try {
  106 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  107 + this.reportFeeDetailContractInfo.feeTypeCds = data
  108 + } catch (error) {
  109 + console.error('获取字典数据失败:', error)
  110 + }
  111 + },
  112 + async open(conditions) {
  113 + this.reportFeeDetailContractInfo.conditions = conditions
  114 + this.listReportFeeDetailContracts()
  115 + },
  116 + async listReportFeeDetailContracts() {
  117 + try {
  118 + this.loading = true
  119 + const params = {
  120 + ...this.reportFeeDetailContractInfo.conditions,
  121 + page: this.pagination.current,
  122 + row: this.pagination.size
  123 + }
  124 + const { data, total } = await queryReportFeeDetailContract(params)
  125 + this.reportFeeDetailContractInfo.fees = data
  126 + this.pagination.total = total
  127 + } catch (error) {
  128 + console.error('获取合同费用明细失败:', error)
  129 + } finally {
  130 + this.loading = false
  131 + }
  132 + },
  133 + async exportReportFeeDetailContractExcel() {
  134 + try {
  135 + const params = {
  136 + ...this.reportFeeDetailContractInfo.conditions,
  137 + pagePath: 'reportFeeDetailContract'
  138 + }
  139 + await exportReportFeeDetailContract(params)
  140 + this.$message.success(this.$t('common.exportSuccess'))
  141 + } catch (error) {
  142 + console.error('导出失败:', error)
  143 + this.$message.error(this.$t('common.exportFailed'))
  144 + }
  145 + },
  146 + handleSizeChange(val) {
  147 + this.pagination.size = val
  148 + this.listReportFeeDetailContracts()
  149 + },
  150 + handleCurrentChange(val) {
  151 + this.pagination.current = val
  152 + this.listReportFeeDetailContracts()
  153 + }
  154 + }
  155 +}
  156 +</script>
  157 +
  158 +<style lang="scss" scoped>
  159 +.report-fee-detail-contract {
  160 + .operation-bar {
  161 + margin-bottom: 20px;
  162 + text-align: right;
  163 + }
  164 +
  165 + .el-pagination {
  166 + margin-top: 20px;
  167 + text-align: right;
  168 + }
  169 +}
  170 +</style>
0 171 \ No newline at end of file
... ...
src/components/report/reportFeeDetailOwner.vue 0 → 100644
  1 +<template>
  2 + <div class="report-fee-detail-owner">
  3 + <div class="operation-bar">
  4 + <el-button
  5 + type="primary"
  6 + size="small"
  7 + @click="exportReportFeeDetailOwnerExcel">
  8 + <i class="el-icon-download"></i>
  9 + {{ $t('common.export') }}
  10 + </el-button>
  11 + </div>
  12 +
  13 + <el-table
  14 + :data="reportFeeDetailOwnerInfo.fees"
  15 + border
  16 + style="width: 100%"
  17 + v-loading="loading">
  18 + <el-table-column
  19 + prop="ownerName"
  20 + :label="$t('reportFeeDetailOwner.owner')"
  21 + align="center">
  22 + <template slot-scope="scope">
  23 + {{ scope.row.ownerName }}({{ scope.row.link }})
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column
  27 + prop="objName"
  28 + :label="$t('reportFeeDetailOwner.room')"
  29 + align="center">
  30 + <template slot-scope="scope">
  31 + <div style="max-width: 200px;">{{ scope.row.objName }}</div>
  32 + </template>
  33 + </el-table-column>
  34 + <el-table-column
  35 + prop="oweFee"
  36 + :label="$t('reportFeeDetailOwner.oweFee')"
  37 + align="center">
  38 + <template slot-scope="scope">
  39 + {{ scope.row.oweFee || '0' }}
  40 + </template>
  41 + </el-table-column>
  42 + <el-table-column
  43 + prop="receivedFee"
  44 + :label="$t('reportFeeDetailOwner.receivedFee')"
  45 + align="center">
  46 + <template slot-scope="scope">
  47 + {{ scope.row.receivedFee || '0' }}
  48 + </template>
  49 + </el-table-column>
  50 + <template v-for="(item,index) in reportFeeDetailOwnerInfo.feeTypeCds">
  51 + <el-table-column
  52 + :key="index+'owe'"
  53 + :label="item.name + $t('reportFeeDetailOwner.owe')"
  54 + align="center">
  55 + <template slot-scope="scope">
  56 + {{ scope.row['oweFee'+item.statusCd] || '0' }}
  57 + </template>
  58 + </el-table-column>
  59 + <el-table-column
  60 + :key="index+'received'"
  61 + :label="item.name + $t('reportFeeDetailOwner.received')"
  62 + align="center">
  63 + <template slot-scope="scope">
  64 + {{ scope.row['receivedFee'+item.statusCd] || '0' }}
  65 + </template>
  66 + </el-table-column>
  67 + </template>
  68 + </el-table>
  69 +
  70 + <el-pagination
  71 + @size-change="handleSizeChange"
  72 + @current-change="handleCurrentChange"
  73 + :current-page="pagination.current"
  74 + :page-sizes="[10, 20, 30, 50]"
  75 + :page-size="pagination.size"
  76 + layout="total, sizes, prev, pager, next, jumper"
  77 + :total="pagination.total">
  78 + </el-pagination>
  79 + </div>
  80 +</template>
  81 +
  82 +<script>
  83 +import { getDict } from '@/api/community/communityApi'
  84 +import { queryReportFeeDetailOwner, exportReportFeeDetailOwner } from '@/api/report/reportFeeDetailApi'
  85 +
  86 +export default {
  87 + name: 'ReportFeeDetailOwner',
  88 + data() {
  89 + return {
  90 + reportFeeDetailOwnerInfo: {
  91 + fees: [],
  92 + feeTypeCds: [],
  93 + conditions: {}
  94 + },
  95 + loading: false,
  96 + pagination: {
  97 + current: 1,
  98 + size: 10,
  99 + total: 0
  100 + }
  101 + }
  102 + },
  103 + created() {
  104 + this.getDictData()
  105 + },
  106 + methods: {
  107 + async getDictData() {
  108 + try {
  109 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  110 + this.reportFeeDetailOwnerInfo.feeTypeCds = data
  111 + } catch (error) {
  112 + console.error('获取字典数据失败:', error)
  113 + }
  114 + },
  115 + async open(conditions) {
  116 + this.reportFeeDetailOwnerInfo.conditions = conditions
  117 + this.listReportFeeDetailOwners()
  118 + },
  119 + async listReportFeeDetailOwners() {
  120 + try {
  121 + this.loading = true
  122 + const params = {
  123 + ...this.reportFeeDetailOwnerInfo.conditions,
  124 + page: this.pagination.current,
  125 + row: this.pagination.size
  126 + }
  127 + const { data, total } = await queryReportFeeDetailOwner(params)
  128 + this.reportFeeDetailOwnerInfo.fees = data
  129 + this.pagination.total = total
  130 + } catch (error) {
  131 + console.error('获取业主费用明细失败:', error)
  132 + } finally {
  133 + this.loading = false
  134 + }
  135 + },
  136 + async exportReportFeeDetailOwnerExcel() {
  137 + try {
  138 + const params = {
  139 + ...this.reportFeeDetailOwnerInfo.conditions,
  140 + pagePath: 'reportFeeDetailOwner'
  141 + }
  142 + await exportReportFeeDetailOwner(params)
  143 + this.$message.success(this.$t('common.exportSuccess'))
  144 + } catch (error) {
  145 + console.error('导出失败:', error)
  146 + this.$message.error(this.$t('common.exportFailed'))
  147 + }
  148 + },
  149 + handleSizeChange(val) {
  150 + this.pagination.size = val
  151 + this.listReportFeeDetailOwners()
  152 + },
  153 + handleCurrentChange(val) {
  154 + this.pagination.current = val
  155 + this.listReportFeeDetailOwners()
  156 + }
  157 + }
  158 +}
  159 +</script>
  160 +
  161 +<style lang="scss" scoped>
  162 +.report-fee-detail-owner {
  163 + .operation-bar {
  164 + margin-bottom: 20px;
  165 + text-align: right;
  166 + }
  167 +
  168 + .el-pagination {
  169 + margin-top: 20px;
  170 + text-align: right;
  171 + }
  172 +}
  173 +</style>
0 174 \ No newline at end of file
... ...
src/components/report/reportFeeDetailRoom.vue 0 → 100644
  1 +<template>
  2 + <div class="report-fee-detail-room">
  3 + <el-row :gutter="20">
  4 + <el-col :span="4">
  5 + <el-card class="floor-tree">
  6 + <el-scrollbar style="height: 650px;">
  7 + <el-menu>
  8 + <el-menu-item @click="swatchFloor('')" :class="{ 'is-active': reportFeeDetailRoomInfo.floorId === '' }">
  9 + {{ $t('reportFeeDetailRoom.all') }}
  10 + </el-menu-item>
  11 + <el-menu-item v-for="(item, index) in reportFeeDetailRoomInfo.floors" :key="index"
  12 + @click="swatchFloor(item.floorId)"
  13 + :class="{ 'is-active': reportFeeDetailRoomInfo.floorId === item.floorId }">
  14 + {{ item.floorName }}
  15 + </el-menu-item>
  16 + </el-menu>
  17 + </el-scrollbar>
  18 + </el-card>
  19 + </el-col>
  20 + <el-col :span="20">
  21 + <div class="operation-bar">
  22 + <el-button type="primary" size="small" @click="exportReportFeeDetailRoomExcel">
  23 + <i class="el-icon-download"></i>
  24 + {{ $t('common.export') }}
  25 + </el-button>
  26 + </div>
  27 +
  28 + <el-table :data="reportFeeDetailRoomInfo.fees" border style="width: 100%" v-loading="loading">
  29 + <el-table-column prop="roomName" :label="$t('reportFeeDetailRoom.room')" align="center">
  30 + </el-table-column>
  31 + <el-table-column prop="ownerName" :label="$t('reportFeeDetailRoom.owner')" align="center">
  32 + <template slot-scope="scope">
  33 + {{ scope.row.ownerName }}({{ scope.row.link }})
  34 + </template>
  35 + </el-table-column>
  36 + <el-table-column prop="oweFee" :label="$t('reportFeeDetailRoom.oweFee')" align="center">
  37 + <template slot-scope="scope">
  38 + {{ scope.row.oweFee || '0' }}
  39 + </template>
  40 + </el-table-column>
  41 + <el-table-column prop="receivedFee" :label="$t('reportFeeDetailRoom.receivedFee')" align="center">
  42 + <template slot-scope="scope">
  43 + {{ scope.row.receivedFee || '0' }}
  44 + </template>
  45 + </el-table-column>
  46 + <template v-for="(item, index) in reportFeeDetailRoomInfo.feeTypeCds" >
  47 + <el-table-column :key="index" :label="item.name + $t('reportFeeDetailRoom.owe')" align="center">
  48 + <template slot-scope="scope">
  49 + {{ scope.row['oweFee' + item.statusCd] || '0' }}
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column :key="index+'received'" :label="item.name + $t('reportFeeDetailRoom.received')"
  53 + align="center">
  54 + <template slot-scope="scope">
  55 + {{ scope.row['receivedFee' + item.statusCd] || '0' }}
  56 + </template>
  57 + </el-table-column>
  58 + </template>
  59 + </el-table>
  60 +
  61 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
  62 + :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  63 + layout="total, sizes, prev, pager, next, jumper" :total="pagination.total">
  64 + </el-pagination>
  65 + </el-col>
  66 + </el-row>
  67 + </div>
  68 +</template>
  69 +
  70 +<script>
  71 +import { getDict } from '@/api/community/communityApi'
  72 +import { queryReportFeeDetailRoom, exportReportFeeDetailRoom } from '@/api/report/reportFeeDetailApi'
  73 +import {queryFloors} from '@/api/report/reportFeeSummaryApi'
  74 +
  75 +export default {
  76 + name: 'ReportFeeDetailRoom',
  77 + data() {
  78 + return {
  79 + reportFeeDetailRoomInfo: {
  80 + fees: [],
  81 + floors: [],
  82 + floorId: '',
  83 + feeTypeCds: [],
  84 + conditions: {}
  85 + },
  86 + loading: false,
  87 + pagination: {
  88 + current: 1,
  89 + size: 10,
  90 + total: 0
  91 + }
  92 + }
  93 + },
  94 + created() {
  95 + this.getDictData()
  96 + },
  97 + methods: {
  98 + async getDictData() {
  99 + try {
  100 + const data = await getDict('pay_fee_config', 'fee_type_cd_show')
  101 + this.reportFeeDetailRoomInfo.feeTypeCds = data
  102 + } catch (error) {
  103 + console.error('获取字典数据失败:', error)
  104 + }
  105 + },
  106 + async open(conditions) {
  107 + this.reportFeeDetailRoomInfo.conditions = conditions
  108 + await this.listReportFeeDetailRoomFloors()
  109 + this.listReportFeeDetailRooms()
  110 + },
  111 + async listReportFeeDetailRoomFloors() {
  112 + try {
  113 + const params = {
  114 + page: 1,
  115 + row: 100,
  116 + communityId: this.reportFeeDetailRoomInfo.conditions.communityId
  117 + }
  118 +
  119 + const data = await queryFloors(params)
  120 + this.reportFeeDetailRoomInfo.floors = data.apiFloorDataVoList
  121 + } catch (error) {
  122 + console.error('获取楼层列表失败:', error)
  123 + }
  124 + },
  125 + swatchFloor(floorId) {
  126 + this.reportFeeDetailRoomInfo.floorId = floorId
  127 + this.listReportFeeDetailRooms()
  128 + },
  129 + async listReportFeeDetailRooms() {
  130 + try {
  131 + this.loading = true
  132 + const params = {
  133 + ...this.reportFeeDetailRoomInfo.conditions,
  134 + page: this.pagination.current,
  135 + row: this.pagination.size,
  136 + floorId: this.reportFeeDetailRoomInfo.floorId
  137 + }
  138 + const { data, total } = await queryReportFeeDetailRoom(params)
  139 + this.reportFeeDetailRoomInfo.fees = data
  140 + this.pagination.total = total
  141 + } catch (error) {
  142 + console.error('获取房屋费用明细失败:', error)
  143 + } finally {
  144 + this.loading = false
  145 + }
  146 + },
  147 + async exportReportFeeDetailRoomExcel() {
  148 + try {
  149 + const params = {
  150 + ...this.reportFeeDetailRoomInfo.conditions,
  151 + pagePath: 'reportFeeDetailRoom'
  152 + }
  153 + await exportReportFeeDetailRoom(params)
  154 + this.$message.success(this.$t('common.exportSuccess'))
  155 + } catch (error) {
  156 + console.error('导出失败:', error)
  157 + this.$message.error(this.$t('common.exportFailed'))
  158 + }
  159 + },
  160 + handleSizeChange(val) {
  161 + this.pagination.size = val
  162 + this.listReportFeeDetailRooms()
  163 + },
  164 + handleCurrentChange(val) {
  165 + this.pagination.current = val
  166 + this.listReportFeeDetailRooms()
  167 + }
  168 + }
  169 +}
  170 +</script>
  171 +
  172 +<style lang="scss" scoped>
  173 +.report-fee-detail-room {
  174 + .floor-tree {
  175 + height: 700px;
  176 +
  177 + .el-menu {
  178 + border-right: none;
  179 + }
  180 +
  181 + .is-active {
  182 + color: #409EFF;
  183 + background-color: #ecf5ff;
  184 + }
  185 + }
  186 +
  187 + .operation-bar {
  188 + margin-bottom: 20px;
  189 + text-align: right;
  190 + }
  191 +
  192 + .el-pagination {
  193 + margin-top: 20px;
  194 + text-align: right;
  195 + }
  196 +}
  197 +</style>
0 198 \ No newline at end of file
... ...
src/components/report/reportPrePaymentFee.vue 0 → 100644
  1 +<template>
  2 + <div class="report-pre-payment-fee">
  3 + <div class="text-right">
  4 + <el-button type="primary" size="small" @click="_exportExcel">
  5 + <i class="el-icon-download"></i>
  6 + {{ $t('reportPrePaymentFee.export') }}
  7 + </el-button>
  8 + </div>
  9 +
  10 + <el-table :data="reportPrePaymentFeeInfo.fees" border style="width: 100%" class="margin-top">
  11 + <el-table-column prop="index" :label="$t('reportPrePaymentFee.feeId')" align="center">
  12 + <template slot-scope="scope">
  13 + {{ scope.$index + 1 }}
  14 + </template>
  15 + </el-table-column>
  16 + <el-table-column prop="objName" :label="$t('reportPrePaymentFee.objName')" align="center" />
  17 + <el-table-column prop="feeName" :label="$t('reportPrePaymentFee.feeName')" align="center" />
  18 + <el-table-column prop="endTime" :label="$t('reportPrePaymentFee.startTime')" align="center" />
  19 + <el-table-column prop="oweDay" :label="$t('reportPrePaymentFee.oweDay')" align="center" />
  20 + </el-table>
  21 +
  22 + <el-row class="margin-top">
  23 + <el-col :span="18">
  24 + <div class="tip-text">
  25 + {{ $t('reportPrePaymentFee.tip') }}
  26 + </div>
  27 + </el-col>
  28 + <el-col :span="6" class="text-right">
  29 + <el-pagination :current-page.sync="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size"
  30 + :total="pagination.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
  31 + @current-change="handleCurrentChange" />
  32 + </el-col>
  33 + </el-row>
  34 + </div>
  35 +</template>
  36 +
  37 +<script>
  38 +import { getCommunityId } from '@/api/community/communityApi'
  39 +import { queryPrePayment, exportData } from '@/api/report/feeRemindApi'
  40 +
  41 +export default {
  42 + name: 'ReportPrePaymentFee',
  43 + data() {
  44 + return {
  45 + reportPrePaymentFeeInfo: {
  46 + fees: [],
  47 + conditions: {}
  48 + },
  49 + pagination: {
  50 + current: 1,
  51 + size: 10,
  52 + total: 0
  53 + }
  54 + }
  55 + },
  56 + methods: {
  57 + async loadData(conditions) {
  58 + this.reportPrePaymentFeeInfo.conditions = { ...conditions }
  59 + await this._listPreFees(this.pagination.current, this.pagination.size)
  60 + },
  61 + async _listPreFees(page, size) {
  62 + try {
  63 + const params = {
  64 + ...this.reportPrePaymentFeeInfo.conditions,
  65 + page,
  66 + row: size
  67 + }
  68 + const { data, total } = await queryPrePayment(params)
  69 + this.reportPrePaymentFeeInfo.fees = data
  70 + this.pagination.total = total
  71 + } catch (error) {
  72 + console.error('Failed to load pre payment fees:', error)
  73 + }
  74 + },
  75 + async _exportExcel() {
  76 + try {
  77 + const params = {
  78 + ...this.reportPrePaymentFeeInfo.conditions,
  79 + communityId: getCommunityId(),
  80 + pagePath: 'reportPrePaymentFee'
  81 + }
  82 + const { code, msg } = await exportData(params)
  83 + this.$message.success(msg)
  84 + if (code === 0) {
  85 + this.$router.push('/pages/property/downloadTempFile?tab=downloadCenter')
  86 + }
  87 + } catch (error) {
  88 + console.error('Failed to export:', error)
  89 + }
  90 + },
  91 + handleSizeChange(val) {
  92 + this.pagination.size = val
  93 + this._listPreFees(this.pagination.current, val)
  94 + },
  95 + handleCurrentChange(val) {
  96 + this.pagination.current = val
  97 + this._listPreFees(val, this.pagination.size)
  98 + }
  99 + }
  100 +}
  101 +</script>
  102 +
  103 +<style lang="scss" scoped>
  104 +.report-pre-payment-fee {
  105 + .margin-top {
  106 + margin-top: 15px;
  107 + }
  108 +
  109 + .text-right {
  110 + text-align: right;
  111 + }
  112 +
  113 + .tip-text {
  114 + color: #999;
  115 + font-size: 12px;
  116 + padding: 5px 0;
  117 + }
  118 +}
  119 +</style>
0 120 \ No newline at end of file
... ...
src/components/report/selectCommunityFloor.vue 0 → 100644
  1 +<template>
  2 + <div class="select-community-floor-container">
  3 + <div class="border-radius">
  4 + <div class="margin-xs-r treeview attendance-staff" style="height: 650px;">
  5 + <ul class="list-group text-center border-radius">
  6 + <li v-for="(item, index) in floors" :key="index" class="list-group-item node-orgTree"
  7 + :class="{ 'vc-node-selected': selectedFloorId === item.floorId }" @click="handleSelectFloor(item)">
  8 + {{ item.floorNum }}
  9 + </li>
  10 + </ul>
  11 + </div>
  12 + </div>
  13 + </div>
  14 +</template>
  15 +
  16 +<script>
  17 +import { getCommunityId } from '@/api/community/communityApi'
  18 +import { queryFloors } from '@/api/report/reportFeeSummaryApi'
  19 +
  20 +export default {
  21 + name: 'SelectCommunityFloor',
  22 + data() {
  23 + return {
  24 + floors: [],
  25 + selectedFloorId: '',
  26 + callBack: null
  27 + }
  28 + },
  29 + methods: {
  30 + open(params) {
  31 + this.callBack = params.callBack
  32 + this.loadCommunityFloors()
  33 + },
  34 + async loadCommunityFloors() {
  35 + try {
  36 + const communityId = await getCommunityId()
  37 + const params = {
  38 + _uid: '123mlkdinkldldijdhuudjdjkkd',
  39 + page: 1,
  40 + row: 100,
  41 + communityId
  42 + }
  43 +
  44 + const defaultFloor = {
  45 + floorNum: this.$t('common.all'),
  46 + floorId: ''
  47 + }
  48 +
  49 + const data = await queryFloors(params)
  50 + this.floors = [defaultFloor, ...data.apiFloorDataVoList]
  51 + this.handleSelectFloor(defaultFloor)
  52 + } catch (error) {
  53 + console.error('Failed to load floors:', error)
  54 + }
  55 + },
  56 + handleSelectFloor(floor) {
  57 + this.selectedFloorId = floor.floorId
  58 + if (this.callBack) {
  59 + this.callBack(floor)
  60 + }
  61 + }
  62 + }
  63 +}
  64 +</script>
  65 +
  66 +<style lang="scss" scoped>
  67 +.select-community-floor-container {
  68 + .border-radius {
  69 + border-radius: 4px;
  70 + }
  71 +
  72 + .margin-xs-r {
  73 + margin-right: 5px;
  74 + }
  75 +
  76 + .treeview {
  77 + overflow-y: auto;
  78 + }
  79 +
  80 + .attendance-staff {
  81 + background-color: #fff;
  82 + border: 1px solid #ebeef5;
  83 + }
  84 +
  85 + .list-group {
  86 + padding-left: 0;
  87 + margin-bottom: 0;
  88 + list-style: none;
  89 + }
  90 +
  91 + .list-group-item {
  92 + position: relative;
  93 + display: block;
  94 + padding: 10px 15px;
  95 + margin-bottom: -1px;
  96 + background-color: #fff;
  97 + border: 1px solid #ebeef5;
  98 + cursor: pointer;
  99 +
  100 + &:hover {
  101 + background-color: #f5f7fa;
  102 + }
  103 + }
  104 +
  105 + .vc-node-selected {
  106 + background-color: #ecf5ff;
  107 + color: #409eff;
  108 + }
  109 +
  110 + .text-center {
  111 + text-align: center;
  112 + }
  113 +}
  114 +</style>
0 115 \ No newline at end of file
... ...
src/i18n/reportI18n.js
... ... @@ -5,6 +5,12 @@ import { messages as reportCustomComponentManageMessages } from &#39;../views/report
5 5 import { messages as reportCustomComponentRelManageMessages } from '../views/report/reportCustomComponentRelManageLang'
6 6 import { messages as componentConditionManageMessages } from '../views/report/componentConditionManageLang'
7 7 import { messages as reportCustomComponentFooterManageMessages } from '../views/report/reportCustomComponentFooterManageLang'
  8 +
  9 +import { messages as reportFeeSummaryMessages } from '../views/report/reportFeeSummaryLang'
  10 +import { messages as reportFeeDetailMessages } from '../views/report/reportFeeDetailLang'
  11 +import { messages as feeRemindMessages } from '../views/report/feeRemindLang'
  12 +import { messages as dataReportMessages } from '../views/report/dataReportLang'
  13 +
8 14 export const messages = {
9 15 en: {
10 16  
... ... @@ -14,6 +20,10 @@ export const messages = {
14 20 ...reportCustomManageMessages.en,
15 21 ...reportCustomComponentManageMessages.en,
16 22 ...reportProficientMessages.en,
  23 + ...reportFeeSummaryMessages.en,
  24 + ...reportFeeDetailMessages.en,
  25 + ...feeRemindMessages.en,
  26 + ...dataReportMessages.en,
17 27 },
18 28 zh: {
19 29 ...reportCustomComponentRelManageMessages.zh,
... ... @@ -22,5 +32,9 @@ export const messages = {
22 32 ...reportCustomManageMessages.zh,
23 33 ...reportCustomComponentManageMessages.zh,
24 34 ...reportProficientMessages.zh,
  35 + ...reportFeeSummaryMessages.zh,
  36 + ...reportFeeDetailMessages.zh,
  37 + ...feeRemindMessages.zh,
  38 + ...dataReportMessages.zh,
25 39 }
26 40 }
27 41 \ No newline at end of file
... ...
src/router/reportRouter.js
... ... @@ -4,5 +4,25 @@ export default [
4 4 name: '/pages/property/reportProficient',
5 5 component: () => import('@/views/report/reportProficientList.vue')
6 6 },
  7 + {
  8 + path: '/pages/property/reportFeeSummary',
  9 + name: '/pages/property/reportFeeSummary',
  10 + component: () => import('@/views/report/reportFeeSummaryList.vue')
  11 + },
  12 + {
  13 + path: '/pages/property/reportFeeDetail',
  14 + name: '/pages/property/reportFeeDetail',
  15 + component: () => import('@/views/report/reportFeeDetailList.vue')
  16 + },
  17 + {
  18 + path: '/pages/report/feeRemind',
  19 + name: '/pages/report/feeRemind',
  20 + component: () => import('@/views/report/feeRemindList.vue')
  21 + },
  22 + {
  23 + path:'/pages/report/dataReport',
  24 + name:'/pages/report/dataReport',
  25 + component: () => import('@/views/report/dataReportList.vue')
  26 + },
7 27  
8 28 ]
9 29 \ No newline at end of file
... ...
src/views/report/dataReportLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + dataReport: {
  4 + timeRange: 'Time Range',
  5 + startDate: 'Start Date',
  6 + endDate: 'End Date',
  7 + to: 'to',
  8 + selectCommunity: 'Select Community',
  9 + today: 'Today',
  10 + yesterday: 'Yesterday',
  11 + last7Days: 'Last 7 Days',
  12 + last30Days: 'Last 30 Days',
  13 + feeStatistics: 'Fee Statistics',
  14 + orderStatistics: 'Order Statistics',
  15 + inoutStatistics: 'In/Out Statistics',
  16 + otherStatistics: 'Other Statistics',
  17 + building: 'Building',
  18 + roomCount: 'Room Count',
  19 + feeRoomCount: 'Fee Room Count',
  20 + receivedFee: 'Received Fee',
  21 + totalReceived: 'Total Received',
  22 + export: 'Export',
  23 + roomNumber: 'Room Number',
  24 + ownerName: 'Owner Name',
  25 + phoneNumber: 'Phone Number',
  26 + search: 'Search',
  27 + reset: 'Reset',
  28 + room: 'Room',
  29 + owner: 'Owner',
  30 + oweFee: 'Owe Fee',
  31 + totalOwe: 'Total Owe',
  32 + historyOwe: 'History Owe',
  33 + todayPaidCount: 'Today Paid Count',
  34 + todayPaidAmount: 'Today Paid Amount',
  35 + historyPaidCount: 'History Paid Count',
  36 + historyPaidAmount: 'History Paid Amount',
  37 + monthPaidCount: 'Month Paid Count',
  38 + remainingCount: 'Remaining Count',
  39 + paidRatio: 'Paid Ratio',
  40 + monthPaidAmount: 'Month Paid Amount',
  41 + monthRemaining: 'Month Remaining',
  42 + collectionRate: 'Collection Rate',
  43 + feeName: 'Fee Name',
  44 + receivedPeriod: 'Received Period',
  45 + cashier: 'Cashier',
  46 + paymentTime: 'Payment Time',
  47 + owePeriod: 'Owe Period',
  48 + oweAmount: 'Owe Amount',
  49 + receivedAmount: 'Received Amount',
  50 + selectBuilding: 'Select Building',
  51 + feeStartDate: 'Fee Start Date',
  52 + feeEndDate: 'Fee End Date',
  53 + noExportData: 'No data to export'
  54 + }
  55 + },
  56 + zh: {
  57 + dataReport: {
  58 + timeRange: '统计时间',
  59 + startDate: '开始日期',
  60 + endDate: '结束日期',
  61 + to: '至',
  62 + selectCommunity: '请选择小区',
  63 + today: '今日',
  64 + yesterday: '昨日',
  65 + last7Days: '近7日',
  66 + last30Days: '近30日',
  67 + feeStatistics: '费用类统计',
  68 + orderStatistics: '工单类统计',
  69 + inoutStatistics: '出入统计',
  70 + otherStatistics: '其他统计',
  71 + building: '楼栋',
  72 + roomCount: '户数',
  73 + feeRoomCount: '收费户数',
  74 + receivedFee: '实收',
  75 + totalReceived: '总实收',
  76 + export: '导出',
  77 + roomNumber: '房屋编号',
  78 + ownerName: '业主名称',
  79 + phoneNumber: '手机号',
  80 + search: '查询',
  81 + reset: '重置',
  82 + room: '房屋',
  83 + owner: '业主',
  84 + oweFee: '欠费',
  85 + totalOwe: '总欠费',
  86 + historyOwe: '历史欠费',
  87 + todayPaidCount: '本日已交户数',
  88 + todayPaidAmount: '本日已交金额',
  89 + historyPaidCount: '历史欠费清缴户',
  90 + historyPaidAmount: '历史欠费清缴金额',
  91 + monthPaidCount: '本月已收户数',
  92 + remainingCount: '剩余户数',
  93 + paidRatio: '已收户占比',
  94 + monthPaidAmount: '当月已收金额',
  95 + monthRemaining: '当月剩余未收',
  96 + collectionRate: '收费率',
  97 + feeName: '费用名称',
  98 + receivedPeriod: '实收时间段',
  99 + cashier: '收银员',
  100 + paymentTime: '交费时间',
  101 + owePeriod: '欠费时间段',
  102 + oweAmount: '欠费金额',
  103 + receivedAmount: '实收',
  104 + selectBuilding: '请选择楼栋',
  105 + feeStartDate: '费用开始时间',
  106 + feeEndDate: '费用结束时间',
  107 + noExportData: '没有可以导出的数据'
  108 + }
  109 + }
  110 +}
0 111 \ No newline at end of file
... ...
src/views/report/dataReportList.vue 0 → 100644
  1 +<template>
  2 + <div class="data-report-container">
  3 + <div class="box-card">
  4 + <div class="flex justify-between padding">
  5 + <div class="flex justify-start">
  6 + <div>
  7 + <span>{{ $t('dataReport.timeRange') }}:</span>
  8 + <el-date-picker v-model="dataReportInfo.conditions.startDate" type="date"
  9 + :placeholder="$t('dataReport.startDate')" style="width: 150px" @change="_changeDate" />
  10 + <span>{{ $t('dataReport.to') }}:</span>
  11 + <el-date-picker v-model="dataReportInfo.conditions.endDate" type="date"
  12 + :placeholder="$t('dataReport.endDate')" style="width: 150px" @change="_changeDate" />
  13 + </div>
  14 + <div v-if="dataReportInfo.communitys.length > 1" style="margin-left: 20px">
  15 + <el-select v-model="dataReportInfo.conditions.communityId" :placeholder="$t('dataReport.selectCommunity')"
  16 + style="width: 200px" @change="_changCommunity">
  17 + <el-option v-for="(item, index) in dataReportInfo.communitys" :key="index" :label="item.name"
  18 + :value="item.communityId" />
  19 + </el-select>
  20 + </div>
  21 + </div>
  22 + <div>
  23 + <el-button :type="dataReportInfo.curDay === 'today' ? 'primary' : ''" @click="_changeDate('today')">{{
  24 + $t('dataReport.today') }}</el-button>
  25 + <el-button :type="dataReportInfo.curDay === 'yesterday' ? 'primary' : ''" @click="_changeDate('yesterday')">{{
  26 + $t('dataReport.yesterday') }}</el-button>
  27 + <el-button :type="dataReportInfo.curDay === 'seven' ? 'primary' : ''" @click="_changeDate('seven')">{{
  28 + $t('dataReport.last7Days') }}</el-button>
  29 + <el-button :type="dataReportInfo.curDay === 'thirty' ? 'primary' : ''" @click="_changeDate('thirty')">{{
  30 + $t('dataReport.last30Days') }}</el-button>
  31 + </div>
  32 + </div>
  33 +
  34 + <div class="flex justify-between ">
  35 + <el-card class="data-report-item">
  36 + <div class="data-report-title">{{ $t('dataReport.feeStatistics') }}</div>
  37 + <div class="flex flex-wrap">
  38 + <div v-for="(item, index) in dataReportInfo.fees" :key="index" class="data-report-card">
  39 + <div class="data-report-card-title">{{ item.name }}</div>
  40 + <div class="data-report-card-value">{{ item.value }}</div>
  41 + </div>
  42 + </div>
  43 + </el-card>
  44 +
  45 + <el-card class="data-report-item">
  46 + <div class="data-report-title">{{ $t('dataReport.orderStatistics') }}</div>
  47 + <div class="flex flex-wrap">
  48 + <div v-for="(item, index) in dataReportInfo.orders" :key="index" class="data-report-card">
  49 + <div class="data-report-card-title">{{ item.name }}</div>
  50 + <div class="data-report-card-value">{{ item.value }}</div>
  51 + </div>
  52 + </div>
  53 + </el-card>
  54 +
  55 + <el-card class="data-report-item">
  56 + <div class="data-report-title">{{ $t('dataReport.inoutStatistics') }}</div>
  57 + <div class="flex flex-wrap">
  58 + <div v-for="(item, index) in dataReportInfo.inouts" :key="index" class="data-report-card">
  59 + <div class="data-report-card-title">{{ item.name }}</div>
  60 + <div class="data-report-card-value">{{ item.value }}</div>
  61 + </div>
  62 + </div>
  63 + </el-card>
  64 +
  65 + <el-card class="data-report-item">
  66 + <div class="data-report-title">{{ $t('dataReport.otherStatistics') }}</div>
  67 + <div class="flex flex-wrap">
  68 + <div v-for="(item, index) in dataReportInfo.others" :key="index" class="data-report-card">
  69 + <div class="data-report-card-title">{{ item.name }}</div>
  70 + <div class="data-report-card-value">{{ item.value }}</div>
  71 + </div>
  72 + </div>
  73 + </el-card>
  74 + </div>
  75 +
  76 + <el-card>
  77 + <el-tabs v-model="dataReportInfo._currentTab" @tab-click="changeTab(dataReportInfo._currentTab)">
  78 + <el-tab-pane label="实收统计" name="dataReportEarnedStatistics" />
  79 + <el-tab-pane label="实收明细" name="dataReportEarnedDetailStatistics" />
  80 + <el-tab-pane label="收款方式统计" name="dataReportEarnedWayStatistics" />
  81 + <el-tab-pane label="欠费统计" name="dataReportOweStatistics" />
  82 + <el-tab-pane label="欠费明细" name="dataReportOweDetailStatistics" />
  83 + <el-tab-pane label="收缴情况" name="dataReportFeeStatistics" />
  84 + <el-tab-pane label="月实收明细" name="dataMonthReceivedStatistics" />
  85 + <el-tab-pane label="月欠费明细" name="dataMonthOweStatistics" />
  86 + </el-tabs>
  87 +
  88 + <component :is="dataReportInfo._currentTab" :ref="dataReportInfo._currentTab"/>
  89 + </el-card>
  90 + </div>
  91 + </div>
  92 +</template>
  93 +
  94 +<script>
  95 +import { getCommunityId } from '@/api/community/communityApi'
  96 +import {
  97 + queryFeeDataReport,
  98 + queryOrderDataReport,
  99 + queryInoutDataReport,
  100 + queryOthersDataReport,
  101 + listMyEnteredCommunitys
  102 +} from '@/api/report/dataReportApi'
  103 +import DataReportEarnedStatistics from '@/components/report/DataReportEarnedStatistics'
  104 +import DataReportEarnedDetailStatistics from '@/components/report/DataReportEarnedDetailStatistics'
  105 +import DataReportEarnedWayStatistics from '@/components/report/DataReportEarnedWayStatistics'
  106 +import DataReportOweStatistics from '@/components/report/DataReportOweStatistics'
  107 +import DataReportOweDetailStatistics from '@/components/report/DataReportOweDetailStatistics'
  108 +import DataReportFeeStatistics from '@/components/report/DataReportFeeStatistics'
  109 +import DataMonthReceivedStatistics from '@/components/report/DataMonthReceivedStatistics'
  110 +import DataMonthOweStatistics from '@/components/report/DataMonthOweStatistics'
  111 +
  112 +export default {
  113 + name: 'DataReportList',
  114 + components: {
  115 + DataReportEarnedStatistics,
  116 + DataReportEarnedDetailStatistics,
  117 + DataReportEarnedWayStatistics,
  118 + DataReportOweStatistics,
  119 + DataReportOweDetailStatistics,
  120 + DataReportFeeStatistics,
  121 + DataMonthReceivedStatistics,
  122 + DataMonthOweStatistics
  123 + },
  124 + data() {
  125 + return {
  126 + dataReportInfo: {
  127 + curDay: 'thirty',
  128 + _currentTab: 'dataReportEarnedStatistics',
  129 + fees: [],
  130 + orders: [],
  131 + inouts: [],
  132 + others: [],
  133 + communitys: [],
  134 + conditions: {
  135 + startDate: '',
  136 + endDate: '',
  137 + communityId: ''
  138 + }
  139 + }
  140 + }
  141 + },
  142 + created() {
  143 + this._initDate()
  144 + this.dataReportInfo.conditions.communityId = getCommunityId()
  145 + this._loadStaffCommunitys()
  146 + this._loadDataReportFee()
  147 + this._loadDataReportOrder()
  148 + this._loadDataReportInout()
  149 + this._loadDataReportOthers()
  150 + },
  151 + methods: {
  152 + _initDate() {
  153 + const _data = new Date()
  154 + let _month = _data.getMonth() + 1
  155 + let _newDate = ''
  156 + if (_month < 10) {
  157 + _newDate = _data.getFullYear() + '-0' + _month + '-01'
  158 + } else {
  159 + _newDate = _data.getFullYear() + '-' + _month + '-01'
  160 + }
  161 + this.dataReportInfo.conditions.startDate = _newDate
  162 + _data.setMonth(_data.getMonth() + 1)
  163 + _month = _data.getMonth() + 1
  164 + if (_month < 10) {
  165 + _newDate = _data.getFullYear() + '-0' + _month + '-01'
  166 + } else {
  167 + _newDate = _data.getFullYear() + '-' + _month + '-01'
  168 + }
  169 + this.dataReportInfo.conditions.endDate = _newDate
  170 + },
  171 + _changeDate(_day) {
  172 + this.dataReportInfo.curDay = _day
  173 + const _endDate = new Date()
  174 + if (_day === 'today') {
  175 + this.dataReportInfo.conditions.endDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  176 + this.dataReportInfo.conditions.startDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  177 + } else if (_day === 'yesterday') {
  178 + _endDate.setDate(_endDate.getDate() - 1)
  179 + this.dataReportInfo.conditions.endDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  180 + this.dataReportInfo.conditions.startDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  181 + } else if (_day === 'seven') {
  182 + this.dataReportInfo.conditions.endDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  183 + _endDate.setDate(_endDate.getDate() - 7)
  184 + this.dataReportInfo.conditions.startDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  185 + } else if (_day === 'thirty') {
  186 + this.dataReportInfo.conditions.endDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  187 + _endDate.setDate(_endDate.getDate() - 30)
  188 + this.dataReportInfo.conditions.startDate = _endDate.getFullYear() + '-' + (_endDate.getMonth() + 1) + '-' + _endDate.getDate()
  189 + }
  190 + this._loadDataReportFee()
  191 + this._loadDataReportOrder()
  192 + this._loadDataReportInout()
  193 + this._loadDataReportOthers()
  194 + this.changeTab(this.dataReportInfo._currentTab)
  195 + },
  196 + async _loadDataReportFee() {
  197 + try {
  198 + const { data } = await queryFeeDataReport(this.dataReportInfo.conditions)
  199 + this.dataReportInfo.fees = data
  200 + } catch (error) {
  201 + console.error('Failed to load fee data:', error)
  202 + }
  203 + },
  204 + async _loadDataReportOrder() {
  205 + try {
  206 + const { data } = await queryOrderDataReport(this.dataReportInfo.conditions)
  207 + this.dataReportInfo.orders = data
  208 + } catch (error) {
  209 + console.error('Failed to load order data:', error)
  210 + }
  211 + },
  212 + async _loadDataReportInout() {
  213 + try {
  214 + const { data } = await queryInoutDataReport(this.dataReportInfo.conditions)
  215 + this.dataReportInfo.inouts = data
  216 + } catch (error) {
  217 + console.error('Failed to load inout data:', error)
  218 + }
  219 + },
  220 + async _loadDataReportOthers() {
  221 + try {
  222 + const { data } = await queryOthersDataReport(this.dataReportInfo.conditions)
  223 + this.dataReportInfo.others = data
  224 + } catch (error) {
  225 + console.error('Failed to load other data:', error)
  226 + }
  227 + },
  228 + changeTab(_tab) {
  229 + this.dataReportInfo._currentTab = _tab
  230 + setTimeout(() => {
  231 + this.$refs[_tab].open(this.dataReportInfo.conditions)
  232 + },500)
  233 + },
  234 + async _loadStaffCommunitys() {
  235 + try {
  236 + const { communitys } = await listMyEnteredCommunitys({
  237 + _uid: '123mlkdinkldldijdhuudjdjkkd',
  238 + page: 1,
  239 + row: 100
  240 + })
  241 + this.dataReportInfo.communitys = communitys
  242 + } catch (error) {
  243 + console.error('Failed to load communities:', error)
  244 + }
  245 + },
  246 + _changCommunity() {
  247 + this.changeTab(this.dataReportInfo._currentTab)
  248 + this._loadDataReportFee()
  249 + this._loadDataReportOrder()
  250 + this._loadDataReportInout()
  251 + this._loadDataReportOthers()
  252 + }
  253 + }
  254 +}
  255 +</script>
  256 +
  257 +<style lang="scss" scoped>
  258 +.data-report-container {
  259 + padding: 20px;
  260 +
  261 + .data-report-item {
  262 + width: 24%;
  263 + margin-bottom: 20px;
  264 +
  265 + .data-report-title {
  266 + font-weight: bold;
  267 + margin-bottom: 15px;
  268 + font-size: 16px;
  269 + }
  270 +
  271 + .data-report-card {
  272 + width: 25%;
  273 + margin: 5px;
  274 + padding: 10px;
  275 + border: 1px solid #4297E5;
  276 + border-radius: 4px;
  277 +
  278 + .data-report-card-title {
  279 + font-size: 12px;
  280 + color: #666;
  281 + }
  282 +
  283 + .data-report-card-value {
  284 + font-size: 18px;
  285 + font-weight: bold;
  286 + margin-top: 5px;
  287 + }
  288 + }
  289 + }
  290 +
  291 + .margin-bottom {
  292 + margin-bottom: 20px;
  293 + }
  294 +
  295 + .padding {
  296 + padding: 10px 0;
  297 + }
  298 +
  299 + .flex {
  300 + display: flex;
  301 + }
  302 +
  303 + .justify-between {
  304 + justify-content: space-between;
  305 + }
  306 +
  307 + .justify-start {
  308 + justify-content: flex-start;
  309 + }
  310 +
  311 + .flex-wrap {
  312 + flex-wrap: wrap;
  313 + }
  314 +}
  315 +</style>
0 316 \ No newline at end of file
... ...
src/views/report/feeRemindLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + feeRemind: {
  4 + queryCondition: 'Query Conditions',
  5 + hide: 'Hide',
  6 + more: 'More',
  7 + objNamePlaceholder: 'Please enter room number/contract name/license plate',
  8 + ownerNamePlaceholder: 'Please enter owner name',
  9 + linkPlaceholder: 'Please enter owner phone',
  10 + feeConfigPlaceholder: 'Please select fee item',
  11 + communityPlaceholder: 'Please select community',
  12 + query: 'Query',
  13 + reset: 'Reset',
  14 + prePaymentRemind: 'Pre-payment Reminder',
  15 + deadlineRemind: 'Expiration Reminder'
  16 + },
  17 + reportPrePaymentFee: {
  18 + export: 'Export',
  19 + feeId: 'Fee ID',
  20 + objName: 'Room/Vehicle/Contract',
  21 + feeName: 'Fee Item',
  22 + startTime: 'Fee Start Time',
  23 + oweDay: 'Days Until Start',
  24 + tip: 'Note: This table shows fees starting within 7 days'
  25 + },
  26 + reportDeadlineFee: {
  27 + export: 'Export',
  28 + feeId: 'Fee ID',
  29 + objName: 'Room/Vehicle/Contract',
  30 + feeName: 'Fee Item',
  31 + deadlineTime: 'Fee End Time',
  32 + oweDay: 'Days Until End',
  33 + tip: 'Note: This table shows fees ending within 7 days'
  34 + }
  35 + },
  36 + zh: {
  37 + feeRemind: {
  38 + queryCondition: '查询条件',
  39 + hide: '隐藏',
  40 + more: '更多',
  41 + objNamePlaceholder: '请填写房屋编号/合同名称/车牌号',
  42 + ownerNamePlaceholder: '请填写业主名称',
  43 + linkPlaceholder: '请填写业主手机号',
  44 + feeConfigPlaceholder: '请选择费用项',
  45 + communityPlaceholder: '请选择小区',
  46 + query: '查询',
  47 + reset: '重置',
  48 + prePaymentRemind: '预缴费提醒',
  49 + deadlineRemind: '到期提醒'
  50 + },
  51 + reportPrePaymentFee: {
  52 + export: '导出',
  53 + feeId: '费用编号',
  54 + objName: '房号/车辆/合同',
  55 + feeName: '费用项',
  56 + startTime: '费用开始时间',
  57 + oweDay: '距离开始时间(天)',
  58 + tip: '温馨提示:此表反馈7天内开始缴费的费用'
  59 + },
  60 + reportDeadlineFee: {
  61 + export: '导出',
  62 + feeId: '费用编号',
  63 + objName: '房号/车辆/合同',
  64 + feeName: '费用项',
  65 + deadlineTime: '费用结束时间',
  66 + oweDay: '距离结束时间(天)',
  67 + tip: '温馨提示:此表反馈7天内缴费结束的费用'
  68 + }
  69 + }
  70 +}
0 71 \ No newline at end of file
... ...
src/views/report/feeRemindList.vue 0 → 100644
  1 +<template>
  2 + <div class="fee-remind-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="flex justify-between">
  5 + <span>{{ $t('feeRemind.queryCondition') }}</span>
  6 + <el-button type="text" style="float: right; padding: 3px 0" @click="_moreCondition()">
  7 + {{ feeRemindInfo.moreCondition ? $t('feeRemind.hide') : $t('feeRemind.more') }}
  8 + </el-button>
  9 + </div>
  10 + <el-row :gutter="20">
  11 + <el-col :span="4">
  12 + <el-input v-model.trim="feeRemindInfo.conditions.objName" :placeholder="$t('feeRemind.objNamePlaceholder')"
  13 + clearable />
  14 + </el-col>
  15 + <el-col :span="4">
  16 + <el-input v-model.trim="feeRemindInfo.conditions.ownerName" :placeholder="$t('feeRemind.ownerNamePlaceholder')"
  17 + clearable />
  18 + </el-col>
  19 + <el-col :span="4">
  20 + <el-input v-model.trim="feeRemindInfo.conditions.link" :placeholder="$t('feeRemind.linkPlaceholder')"
  21 + clearable />
  22 + </el-col>
  23 + <el-col :span="4">
  24 + <el-select v-model="feeRemindInfo.conditions.configId" :placeholder="$t('feeRemind.feeConfigPlaceholder')"
  25 + style="width:100%" clearable>
  26 + <el-option v-for="item in feeRemindInfo.feeConfigs" :key="item.configId" :label="item.feeName"
  27 + :value="item.configId" />
  28 + </el-select>
  29 + </el-col>
  30 + <el-col v-if="feeRemindInfo.communitys.length > 1" :span="4">
  31 + <el-select v-model="feeRemindInfo.conditions.communityId" :placeholder="$t('feeRemind.communityPlaceholder')"
  32 + style="width:100%" @change="_changCommunity" clearable>
  33 + <el-option v-for="item in feeRemindInfo.communitys" :key="item.communityId" :label="item.name"
  34 + :value="item.communityId" />
  35 + </el-select>
  36 + </el-col>
  37 + <el-col :span="4">
  38 + <el-button type="primary" @click="_queryMethod">
  39 + <i class="el-icon-search"></i>
  40 + {{ $t('feeRemind.query') }}
  41 + </el-button>
  42 + <el-button @click="_resetMethod">
  43 + <i class="el-icon-refresh"></i>
  44 + {{ $t('feeRemind.reset') }}
  45 + </el-button>
  46 + </el-col>
  47 + </el-row>
  48 + </el-card>
  49 +
  50 + <el-card class="box-card margin-top">
  51 + <el-tabs v-model="feeRemindInfo._currentTab" @tab-click="changeTab">
  52 + <el-tab-pane :label="$t('feeRemind.prePaymentRemind')" name="reportPrePaymentFee">
  53 + <report-pre-payment-fee v-if="feeRemindInfo._currentTab === 'reportPrePaymentFee'" ref="prePaymentFee" />
  54 + </el-tab-pane>
  55 + <el-tab-pane :label="$t('feeRemind.deadlineRemind')" name="reportDeadlineFee">
  56 + <report-deadline-fee v-if="feeRemindInfo._currentTab === 'reportDeadlineFee'" ref="deadlineFee" />
  57 + </el-tab-pane>
  58 + </el-tabs>
  59 + </el-card>
  60 + </div>
  61 +</template>
  62 +
  63 +<script>
  64 +import { getCommunityId } from '@/api/community/communityApi'
  65 +import ReportPrePaymentFee from '@/components/report/reportPrePaymentFee'
  66 +import ReportDeadlineFee from '@/components/report/reportDeadlineFee'
  67 +import {
  68 + listFeeConfigs,
  69 + listMyEnteredCommunitys
  70 +} from '@/api/report/feeRemindApi'
  71 +
  72 +export default {
  73 + name: 'FeeRemindList',
  74 + components: {
  75 + ReportPrePaymentFee,
  76 + ReportDeadlineFee
  77 + },
  78 + data() {
  79 + return {
  80 + feeRemindInfo: {
  81 + _currentTab: 'reportPrePaymentFee',
  82 + feeConfigs: [],
  83 + moreCondition: false,
  84 + communitys: [],
  85 + conditions: {
  86 + objName: '',
  87 + configId: '',
  88 + ownerName: '',
  89 + link: '',
  90 + communityId: ''
  91 + }
  92 + }
  93 + }
  94 + },
  95 + created() {
  96 + this.feeRemindInfo.conditions.communityId = getCommunityId()
  97 + this._loadStaffCommunitys()
  98 + this._listFeeConfigs()
  99 + },
  100 + methods: {
  101 + changeTab(tab) {
  102 + this.feeRemindInfo._currentTab = tab.name || tab
  103 + setTimeout(() => {
  104 + if (tab.name === 'reportPrePaymentFee') {
  105 + this.$refs.prePaymentFee && this.$refs.prePaymentFee.loadData(this.feeRemindInfo.conditions)
  106 + } else {
  107 + this.$refs.deadlineFee && this.$refs.deadlineFee.loadData(this.feeRemindInfo.conditions)
  108 + }
  109 + }, 500)
  110 +
  111 + },
  112 + _queryMethod() {
  113 + this.changeTab(this.feeRemindInfo._currentTab)
  114 + },
  115 + _resetMethod() {
  116 + this.feeRemindInfo.conditions = {
  117 + objName: '',
  118 + configId: '',
  119 + ownerName: '',
  120 + link: '',
  121 + communityId: getCommunityId()
  122 + }
  123 + this.changeTab(this.feeRemindInfo._currentTab)
  124 + },
  125 + async _listFeeConfigs() {
  126 + try {
  127 + const params = {
  128 + page: 1,
  129 + row: 100,
  130 + communityId: this.feeRemindInfo.conditions.communityId,
  131 + isDefault: 'F'
  132 + }
  133 + const data = await listFeeConfigs(params)
  134 + this.feeRemindInfo.feeConfigs = data.feeConfigs
  135 + } catch (error) {
  136 + console.error('Failed to load fee configs:', error)
  137 + }
  138 + },
  139 + _moreCondition() {
  140 + this.feeRemindInfo.moreCondition = !this.feeRemindInfo.moreCondition
  141 + },
  142 + async _loadStaffCommunitys() {
  143 + try {
  144 + const params = {
  145 + _uid: '123mlkdinkldldijdhuudjdjkkd',
  146 + page: 1,
  147 + row: 100
  148 + }
  149 + const data = await listMyEnteredCommunitys(params)
  150 + this.feeRemindInfo.communitys = data.communitys
  151 + } catch (error) {
  152 + console.error('Failed to load communities:', error)
  153 + }
  154 + },
  155 + _changCommunity() {
  156 + this._listFeeConfigs()
  157 + this.changeTab(this.feeRemindInfo._currentTab)
  158 + }
  159 + }
  160 +}
  161 +</script>
  162 +
  163 +<style lang="scss" scoped>
  164 +.fee-remind-container {
  165 + padding: 20px;
  166 +
  167 + .box-card {
  168 + margin-bottom: 20px;
  169 + }
  170 +
  171 + .margin-top {
  172 + margin-top: 20px;
  173 + }
  174 +
  175 + .el-col {
  176 + margin-bottom: 10px;
  177 + }
  178 +
  179 + .el-button+.el-button {
  180 + margin-left: 10px;
  181 + }
  182 +}
  183 +</style>
0 184 \ No newline at end of file
... ...
src/views/report/reportFeeDetailLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + reportFeeDetail: {
  4 + search: {
  5 + title: 'Search Conditions',
  6 + startDate: 'Start Date',
  7 + endDate: 'End Date',
  8 + objName: 'Room No/Contract/Car No',
  9 + ownerName: 'Owner Name',
  10 + link: 'Owner Phone',
  11 + community: 'Community'
  12 + },
  13 + placeholder: {
  14 + startDate: 'Please select start date',
  15 + endDate: 'Please select end date',
  16 + objName: 'Please enter room no/contract name/car no',
  17 + ownerName: 'Please enter owner name',
  18 + link: 'Please enter owner phone',
  19 + community: 'Please select community'
  20 + },
  21 + hide: 'Hide',
  22 + more: 'More',
  23 + tabs: {
  24 + room: 'Room Fee Details',
  25 + owner: 'Owner Fee Details',
  26 + contract: 'Contract Fee Details',
  27 + car: 'Car Fee Details'
  28 + }
  29 + },
  30 + reportFeeDetailRoom: {
  31 + all: 'All',
  32 + room: 'Room',
  33 + owner: 'Owner',
  34 + oweFee: 'Owe Fee',
  35 + receivedFee: 'Received Fee',
  36 + owe: ' (Owe)',
  37 + received: ' (Received)'
  38 + },
  39 + reportFeeDetailOwner: {
  40 + owner: 'Owner',
  41 + room: 'Room',
  42 + oweFee: 'Owe Fee',
  43 + receivedFee: 'Received Fee',
  44 + owe: ' (Owe)',
  45 + received: ' (Received)'
  46 + },
  47 + reportFeeDetailContract: {
  48 + contract: 'Contract',
  49 + owner: 'Owner',
  50 + oweFee: 'Owe Fee',
  51 + receivedFee: 'Received Fee',
  52 + owe: ' (Owe)',
  53 + received: ' (Received)'
  54 + },
  55 + reportFeeDetailCar: {
  56 + car: 'Car',
  57 + owner: 'Owner',
  58 + oweFee: 'Owe Fee',
  59 + receivedFee: 'Received Fee',
  60 + owe: ' (Owe)',
  61 + received: ' (Received)'
  62 + }
  63 + },
  64 + zh: {
  65 + reportFeeDetail: {
  66 + search: {
  67 + title: '查询条件',
  68 + startDate: '开始日期',
  69 + endDate: '结束日期',
  70 + objName: '房屋编号/合同/车牌号',
  71 + ownerName: '业主名称',
  72 + link: '业主手机号',
  73 + community: '小区'
  74 + },
  75 + placeholder: {
  76 + startDate: '请选择开始日期',
  77 + endDate: '请选择结束日期',
  78 + objName: '请输入房屋编号/合同名称/车牌号',
  79 + ownerName: '请输入业主名称',
  80 + link: '请输入业主手机号',
  81 + community: '请选择小区'
  82 + },
  83 + hide: '隐藏',
  84 + more: '更多',
  85 + tabs: {
  86 + room: '房屋费用明细',
  87 + owner: '业主费用明细',
  88 + contract: '合同费用明细',
  89 + car: '车辆费用明细'
  90 + }
  91 + },
  92 + reportFeeDetailRoom: {
  93 + all: '全部',
  94 + room: '房屋',
  95 + owner: '业主',
  96 + oweFee: '欠费',
  97 + receivedFee: '实收',
  98 + owe: ' (欠费)',
  99 + received: ' (实收)'
  100 + },
  101 + reportFeeDetailOwner: {
  102 + owner: '业主',
  103 + room: '房屋',
  104 + oweFee: '欠费',
  105 + receivedFee: '实收',
  106 + owe: ' (欠费)',
  107 + received: ' (实收)'
  108 + },
  109 + reportFeeDetailContract: {
  110 + contract: '合同',
  111 + owner: '业主',
  112 + oweFee: '欠费',
  113 + receivedFee: '实收',
  114 + owe: ' (欠费)',
  115 + received: ' (实收)'
  116 + },
  117 + reportFeeDetailCar: {
  118 + car: '车辆',
  119 + owner: '业主',
  120 + oweFee: '欠费',
  121 + receivedFee: '实收',
  122 + owe: ' (欠费)',
  123 + received: ' (实收)'
  124 + }
  125 + }
  126 +}
0 127 \ No newline at end of file
... ...
src/views/report/reportFeeDetailList.vue 0 → 100644
  1 +<template>
  2 + <div class="report-fee-detail-container">
  3 + <!-- 查询条件 -->
  4 + <el-card class="search-card">
  5 + <div slot="header" class="flex justify-between">
  6 + <span>{{ $t('reportFeeDetail.search.title') }}</span>
  7 + <div class="header-tools">
  8 + <el-button type="text" @click="toggleMoreCondition" style="margin-right:10px;">
  9 + {{ reportFeeDetailInfo.moreCondition ? $t('reportFeeDetail.hide') : $t('reportFeeDetail.more') }}
  10 + </el-button>
  11 + </div>
  12 + </div>
  13 + <el-row :gutter="20">
  14 + <el-col :span="6">
  15 + <el-date-picker v-model="reportFeeDetailInfo.conditions.startDate" type="date"
  16 + :placeholder="$t('reportFeeDetail.placeholder.startDate')" style="width:100%">
  17 + </el-date-picker>
  18 + </el-col>
  19 + <el-col :span="6">
  20 + <el-date-picker v-model="reportFeeDetailInfo.conditions.endDate" type="date"
  21 + :placeholder="$t('reportFeeDetail.placeholder.endDate')" style="width:100%">
  22 + </el-date-picker>
  23 + </el-col>
  24 + <el-col :span="6">
  25 + <el-input v-model.trim="reportFeeDetailInfo.conditions.objName"
  26 + :placeholder="$t('reportFeeDetail.placeholder.objName')">
  27 + </el-input>
  28 + </el-col>
  29 + <el-col :span="6">
  30 + <el-button type="primary" @click="queryMethod">
  31 + <i class="el-icon-search"></i>
  32 + {{ $t('common.search') }}
  33 + </el-button>
  34 + <el-button @click="resetMethod">
  35 + <i class="el-icon-refresh"></i>
  36 + {{ $t('common.reset') }}
  37 + </el-button>
  38 + </el-col>
  39 + </el-row>
  40 + <el-row :gutter="20" v-show="reportFeeDetailInfo.moreCondition">
  41 + <el-col :span="6">
  42 + <el-input v-model.trim="reportFeeDetailInfo.conditions.ownerName"
  43 + :placeholder="$t('reportFeeDetail.placeholder.ownerName')">
  44 + </el-input>
  45 + </el-col>
  46 + <el-col :span="6">
  47 + <el-input v-model.trim="reportFeeDetailInfo.conditions.link"
  48 + :placeholder="$t('reportFeeDetail.placeholder.link')">
  49 + </el-input>
  50 + </el-col>
  51 + <el-col :span="6" v-if="reportFeeDetailInfo.communitys.length > 1">
  52 + <el-select v-model="reportFeeDetailInfo.conditions.communityId" @change="changCommunity" style="width:100%">
  53 + <el-option disabled :value="''" :label="$t('reportFeeDetail.placeholder.community')">
  54 + </el-option>
  55 + <el-option v-for="(item, index) in reportFeeDetailInfo.communitys" :key="index" :label="item.name"
  56 + :value="item.communityId">
  57 + </el-option>
  58 + </el-select>
  59 + </el-col>
  60 + </el-row>
  61 + </el-card>
  62 +
  63 + <!-- 内容区域 -->
  64 + <el-card class="content-card">
  65 + <el-tabs v-model="reportFeeDetailInfo._currentTab" @tab-click="changeTab">
  66 + <el-tab-pane label="房屋费用明细" name="reportFeeDetailRoom">
  67 + <report-fee-detail-room v-if="reportFeeDetailInfo._currentTab === 'reportFeeDetailRoom'"
  68 + ref="reportFeeDetailRoom">
  69 + </report-fee-detail-room>
  70 + </el-tab-pane>
  71 + <el-tab-pane label="业主费用明细" name="reportFeeDetailOwner">
  72 + <report-fee-detail-owner v-if="reportFeeDetailInfo._currentTab === 'reportFeeDetailOwner'"
  73 + ref="reportFeeDetailOwner">
  74 + </report-fee-detail-owner>
  75 + </el-tab-pane>
  76 + <el-tab-pane label="合同费用明细" name="reportFeeDetailContract">
  77 + <report-fee-detail-contract v-if="reportFeeDetailInfo._currentTab === 'reportFeeDetailContract'"
  78 + ref="reportFeeDetailContract">
  79 + </report-fee-detail-contract>
  80 + </el-tab-pane>
  81 + <el-tab-pane label="车辆费用明细" name="reportFeeDetailCar">
  82 + <report-fee-detail-car v-if="reportFeeDetailInfo._currentTab === 'reportFeeDetailCar'" ref="reportFeeDetailCar">
  83 + </report-fee-detail-car>
  84 + </el-tab-pane>
  85 + </el-tabs>
  86 + </el-card>
  87 + </div>
  88 +</template>
  89 +
  90 +<script>
  91 +import { getCommunityId } from '@/api/community/communityApi'
  92 +import ReportFeeDetailRoom from '@/components/report/reportFeeDetailRoom'
  93 +import ReportFeeDetailOwner from '@/components/report/reportFeeDetailOwner'
  94 +import ReportFeeDetailContract from '@/components/report/reportFeeDetailContract'
  95 +import ReportFeeDetailCar from '@/components/report/reportFeeDetailCar'
  96 +import { loadStaffCommunitys } from '@/api/report/reportFeeDetailApi'
  97 +
  98 +export default {
  99 + name: 'ReportFeeDetailList',
  100 + components: {
  101 + ReportFeeDetailRoom,
  102 + ReportFeeDetailOwner,
  103 + ReportFeeDetailContract,
  104 + ReportFeeDetailCar
  105 + },
  106 + data() {
  107 + return {
  108 + reportFeeDetailInfo: {
  109 + _currentTab: 'reportFeeDetailRoom',
  110 + floors: [],
  111 + moreCondition: false,
  112 + communitys: [],
  113 + conditions: {
  114 + floorId: '',
  115 + objName: '',
  116 + startDate: '',
  117 + endDate: '',
  118 + configId: '',
  119 + feeTypeCd: '',
  120 + ownerName: '',
  121 + link: '',
  122 + communityId: ''
  123 + }
  124 + }
  125 + }
  126 + },
  127 + created() {
  128 + this.initDate()
  129 + this.loadStaffCommunitys()
  130 + this.reportFeeDetailInfo.conditions.communityId = getCommunityId()
  131 + this.changeTab(this.reportFeeDetailInfo._currentTab)
  132 + },
  133 + methods: {
  134 + initDate() {
  135 + const now = new Date()
  136 + const year = now.getFullYear()
  137 + let month = now.getMonth() + 1
  138 + month = month < 10 ? `0${month}` : month
  139 +
  140 + this.reportFeeDetailInfo.conditions.startDate = `${year}-${month}-01`
  141 +
  142 + const nextMonth = new Date(year, month, 1)
  143 + const nextYear = nextMonth.getFullYear()
  144 + let nextMonthNum = nextMonth.getMonth() + 1
  145 + nextMonthNum = nextMonthNum < 10 ? `0${nextMonthNum}` : nextMonthNum
  146 +
  147 + this.reportFeeDetailInfo.conditions.endDate = `${nextYear}-${nextMonthNum}-01`
  148 + },
  149 + async loadStaffCommunitys() {
  150 + try {
  151 + const params = {
  152 + _uid: '123mlkdinkldldijdhuudjdjkkd',
  153 + page: 1,
  154 + row: 100
  155 + }
  156 + const data = await loadStaffCommunitys(params)
  157 + this.reportFeeDetailInfo.communitys = data.communitys
  158 + } catch (error) {
  159 + console.error('加载小区列表失败:', error)
  160 + }
  161 + },
  162 + changeTab(tab) {
  163 + this.reportFeeDetailInfo._currentTab = tab.name || tab
  164 + setTimeout(() => {
  165 + this.$refs[tab.name || tab].open(this.reportFeeDetailInfo.conditions)
  166 + },500)
  167 +
  168 + },
  169 + queryMethod() {
  170 + this.changeTab(this.reportFeeDetailInfo._currentTab)
  171 + },
  172 + resetMethod() {
  173 + this.reportFeeDetailInfo.conditions = {
  174 + floorId: '',
  175 + objName: '',
  176 + startDate: '',
  177 + endDate: '',
  178 + configId: '',
  179 + feeTypeCd: '',
  180 + ownerName: '',
  181 + link: '',
  182 + communityId: getCommunityId()
  183 + }
  184 + this.initDate()
  185 + this.changeTab(this.reportFeeDetailInfo._currentTab)
  186 + },
  187 + changCommunity() {
  188 + this.changeTab(this.reportFeeDetailInfo._currentTab)
  189 + },
  190 + toggleMoreCondition() {
  191 + this.reportFeeDetailInfo.moreCondition = !this.reportFeeDetailInfo.moreCondition
  192 + }
  193 + }
  194 +}
  195 +</script>
  196 +
  197 +<style lang="scss" scoped>
  198 +.report-fee-detail-container {
  199 + padding: 20px;
  200 +
  201 + .search-card {
  202 + margin-bottom: 20px;
  203 +
  204 + .header-tools {
  205 + float: right;
  206 + }
  207 + }
  208 +
  209 + .content-card {
  210 + width: 100%;
  211 + }
  212 +}
  213 +</style>
0 214 \ No newline at end of file
... ...
src/views/report/reportFeeSummaryLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + reportFeeSummary: {
  4 + queryCondition: 'Query Conditions',
  5 + selectStartDate: 'Select start date',
  6 + selectEndDate: 'Select end date',
  7 + inputRoomNumber: 'Input room number',
  8 + inputOwnerName: 'Input owner name',
  9 + inputOwnerPhone: 'Input owner phone',
  10 + selectFeeType: 'Select fee type',
  11 + selectCommunity: 'Select community',
  12 + feeSummaryTable: 'Fee Summary Table',
  13 + updateDaily: 'Updated daily',
  14 + totalRooms: 'Total Rooms',
  15 + chargeRooms: 'Charge Rooms',
  16 + arrearsRooms: 'Arrears Rooms',
  17 + arrearsFormula: 'History Arrears + Current Arrears = Total Arrears',
  18 + historyArrears: 'History Arrears',
  19 + currentArrears: 'Current Arrears',
  20 + totalArrears: 'Total Arrears',
  21 + actualPaymentFormula: 'Arrears Recovery + Current Partial + Advance = Actual Payment',
  22 + arrearsRecovery: 'Arrears Recovery',
  23 + currentPartial: 'Current Partial',
  24 + advancePayment: 'Advance Payment',
  25 + actualPayment: 'Actual Payment',
  26 + currentReceivable: 'Current Receivable',
  27 + currentActual: 'Current Actual',
  28 + roomChargeRate: 'Room Charge Rate',
  29 + chargeRate: 'Charge Rate',
  30 + clearanceRate: 'Clearance Rate',
  31 + floorFeeSummary: 'Floor Fee Summary',
  32 + configFeeSummary: 'Config Fee Summary',
  33 + floorFeeRateStatistics: 'Floor Charge Rate Statistics',
  34 + configFeeRateStatistics: 'Config Charge Rate Statistics',
  35 + dateError: 'Start date must be earlier than end date',
  36 + exportSuccess: 'Export success',
  37 + exportFailed: 'Export failed'
  38 + }
  39 + },
  40 + zh: {
  41 + reportFeeSummary: {
  42 + queryCondition: '查询条件',
  43 + selectStartDate: '请选择开始日期',
  44 + selectEndDate: '请选择结束日期',
  45 + inputRoomNumber: '请填写房屋编号',
  46 + inputOwnerName: '请填写业主名称',
  47 + inputOwnerPhone: '请填写业主手机号',
  48 + selectFeeType: '请选择费用大类',
  49 + selectCommunity: '请选择小区',
  50 + feeSummaryTable: '费用汇总表',
  51 + updateDaily: '按天更新',
  52 + totalRooms: '总户数',
  53 + chargeRooms: '收费户',
  54 + arrearsRooms: '欠费户',
  55 + arrearsFormula: '历史欠费+当期欠费=欠费',
  56 + historyArrears: '历史欠费',
  57 + currentArrears: '当期欠费',
  58 + totalArrears: '总欠费',
  59 + actualPaymentFormula: '欠费追回+当期部分+预交=实缴',
  60 + arrearsRecovery: '欠费追回',
  61 + currentPartial: '当期部分',
  62 + advancePayment: '预交',
  63 + actualPayment: '实缴',
  64 + currentReceivable: '当期应收',
  65 + currentActual: '当期实收',
  66 + roomChargeRate: '户收费率',
  67 + chargeRate: '收费率',
  68 + clearanceRate: '清缴率',
  69 + floorFeeSummary: '楼栋费用汇总',
  70 + configFeeSummary: '费用项汇总',
  71 + floorFeeRateStatistics: '楼栋收费率统计',
  72 + configFeeRateStatistics: '费用项收费率统计',
  73 + dateError: '开始日期必须早于结束日期',
  74 + exportSuccess: '导出成功',
  75 + exportFailed: '导出失败'
  76 + }
  77 + }
  78 +}
0 79 \ No newline at end of file
... ...
src/views/report/reportFeeSummaryList.vue 0 → 100644
  1 +<template>
  2 + <div class="report-fee-summary-container animated fadeInRight">
  3 + <el-row class="flex justify-start">
  4 + <el-col :span="2" class="padding-r-0">
  5 + <select-community-floor ref="selectCommunityFloor" />
  6 + </el-col>
  7 + <el-col :span="22">
  8 + <el-card class="box-card">
  9 + <div slot="header" class="flex justify-between">
  10 + <span>{{ $t('reportFeeSummary.queryCondition') }}</span>
  11 + </div>
  12 + <div class="text item">
  13 + <el-row :gutter="20">
  14 + <el-col :span="4">
  15 + <el-date-picker v-model="reportFeeSummaryInfo.conditions.startDate" type="date"
  16 + :placeholder="$t('reportFeeSummary.selectStartDate')" style="width: 100%" @change="handleDateChange" />
  17 + </el-col>
  18 + <el-col :span="4">
  19 + <el-date-picker v-model="reportFeeSummaryInfo.conditions.endDate" type="date"
  20 + :placeholder="$t('reportFeeSummary.selectEndDate')" style="width: 100%" @change="handleDateChange" />
  21 + </el-col>
  22 + <el-col :span="4">
  23 + <el-input v-model.trim="reportFeeSummaryInfo.conditions.objName"
  24 + :placeholder="$t('reportFeeSummary.inputRoomNumber')" clearable />
  25 + </el-col>
  26 + <el-col :span="4">
  27 + <el-input v-model.trim="reportFeeSummaryInfo.conditions.ownerName"
  28 + :placeholder="$t('reportFeeSummary.inputOwnerName')" clearable />
  29 + </el-col>
  30 + <el-col :span="4">
  31 + <el-input v-model.trim="reportFeeSummaryInfo.conditions.link"
  32 + :placeholder="$t('reportFeeSummary.inputOwnerPhone')" clearable />
  33 + </el-col>
  34 + <el-col :span="4">
  35 + <el-button type="primary" @click="_queryMethod">
  36 + <i class="el-icon-search"></i>
  37 + {{ $t('common.search') }}
  38 + </el-button>
  39 + <el-button @click="_resetMethod">
  40 + <i class="el-icon-refresh"></i>
  41 + {{ $t('common.reset') }}
  42 + </el-button>
  43 + </el-col>
  44 + </el-row>
  45 +
  46 + <el-row :gutter="20" class="margin-top">
  47 + <el-col :span="4">
  48 + <el-select v-model="reportFeeSummaryInfo.conditions.feeTypeCd"
  49 + :placeholder="$t('reportFeeSummary.selectFeeType')" style="width: 100%" clearable>
  50 + <el-option v-for="(item, index) in reportFeeSummaryInfo.feeTypeCds" :key="index" :label="item.name"
  51 + :value="item.statusCd" />
  52 + </el-select>
  53 + </el-col>
  54 + <el-col v-if="reportFeeSummaryInfo.communitys.length > 1" :span="4">
  55 + <el-select v-model="reportFeeSummaryInfo.conditions.communityId"
  56 + :placeholder="$t('reportFeeSummary.selectCommunity')" style="width: 100%" @change="_changCommunity">
  57 + <el-option v-for="(item, index) in reportFeeSummaryInfo.communitys" :key="index" :label="item.name"
  58 + :value="item.communityId" />
  59 + </el-select>
  60 + </el-col>
  61 + </el-row>
  62 +
  63 + <el-row v-show="reportFeeSummaryInfo.moreCondition" class="margin-top">
  64 + <el-col :span="24">
  65 + <el-checkbox-group v-model="reportFeeSummaryInfo.configIds">
  66 + <el-checkbox v-for="(item, index) in reportFeeSummaryInfo.feeConfigs" :key="index"
  67 + :label="item.configId">
  68 + {{ item.feeName }}
  69 + </el-checkbox>
  70 + </el-checkbox-group>
  71 + </el-col>
  72 + </el-row>
  73 + </div>
  74 + </el-card>
  75 +
  76 + <el-card class="box-card margin-top">
  77 + <div slot="header" class="flex justify-between">
  78 + <div>
  79 + <span>{{ $t('reportFeeSummary.feeSummaryTable') }}</span>
  80 + <span class="el-icon-info popover-show" style="cursor: pointer;"></span>
  81 + <span>({{ $t('reportFeeSummary.updateDaily') }})</span>
  82 + </div>
  83 + <div style="float: right;">
  84 + <el-button type="primary" size="small" @click="_exportExcel">
  85 + <i class="el-icon-download"></i>
  86 + {{ $t('common.export') }}
  87 + </el-button>
  88 + </div>
  89 + </div>
  90 + <div class="text item">
  91 + <el-table :data="reportFeeSummaryInfo.fees" border style="width: 100%">
  92 + <el-table-column prop="roomCount" :label="$t('reportFeeSummary.totalRooms')" align="center" />
  93 + <el-table-column prop="feeRoomCount" :label="$t('reportFeeSummary.chargeRooms')" align="center" />
  94 + <el-table-column prop="oweRoomCount" :label="$t('reportFeeSummary.arrearsRooms')" align="center" />
  95 + <el-table-column :label="$t('reportFeeSummary.arrearsFormula')" align="center" colspan="3">
  96 + <el-table-column prop="hisOweFee" :label="$t('reportFeeSummary.historyArrears')" align="center" />
  97 + <el-table-column prop="curOweFee" :label="$t('reportFeeSummary.currentArrears')" align="center" />
  98 + <el-table-column :label="$t('reportFeeSummary.totalArrears')" align="center">
  99 + <template slot-scope="scope">
  100 + {{ (scope.row.curOweFee + scope.row.hisOweFee).toFixed(2) }}
  101 + </template>
  102 + </el-table-column>
  103 + </el-table-column>
  104 + <el-table-column :label="$t('reportFeeSummary.actualPaymentFormula')" align="center" colspan="4">
  105 + <el-table-column prop="hisReceivedFee" :label="$t('reportFeeSummary.arrearsRecovery')" align="center" />
  106 + <el-table-column :label="$t('reportFeeSummary.currentPartial')" align="center">
  107 + <template slot-scope="scope">
  108 + {{ (scope.row.receivedFee - scope.row.hisReceivedFee - scope.row.preReceivedFee).toFixed(2) }}
  109 + </template>
  110 + </el-table-column>
  111 + <el-table-column prop="preReceivedFee" :label="$t('reportFeeSummary.advancePayment')" align="center" />
  112 + <el-table-column prop="receivedFee" :label="$t('reportFeeSummary.actualPayment')" align="center" />
  113 + </el-table-column>
  114 + <el-table-column prop="curReceivableFee" :label="$t('reportFeeSummary.currentReceivable')" align="center" />
  115 + <el-table-column :label="$t('reportFeeSummary.currentActual')" align="center">
  116 + <template slot-scope="scope">
  117 + {{ (scope.row.curReceivableFee - scope.row.curOweFee).toFixed(2) }}
  118 + </template>
  119 + </el-table-column>
  120 + <el-table-column :label="$t('reportFeeSummary.roomChargeRate')" align="center">
  121 + <template slot-scope="scope">
  122 + {{ scope.row.feeRoomCount > 0 ? (((scope.row.feeRoomCount - scope.row.oweRoomCount) /
  123 + scope.row.feeRoomCount * 100).toFixed(2) + '%') : '0%' }}
  124 + </template>
  125 + </el-table-column>
  126 + <el-table-column :label="$t('reportFeeSummary.chargeRate')" align="center">
  127 + <template slot-scope="scope">
  128 + {{ scope.row.curReceivableFee > 0 ? (((scope.row.curReceivableFee - scope.row.curOweFee) /
  129 + scope.row.curReceivableFee * 100).toFixed(2) + '%') : '0%' }}
  130 + </template>
  131 + </el-table-column>
  132 + <el-table-column :label="$t('reportFeeSummary.clearanceRate')" align="center">
  133 + <template slot-scope="scope">
  134 + {{ (scope.row.hisReceivedFee + scope.row.hisOweFee) > 0 ? ((scope.row.hisReceivedFee /
  135 + (scope.row.hisReceivedFee + scope.row.hisOweFee) * 100).toFixed(2) + '%') : '0%' }}
  136 + </template>
  137 + </el-table-column>
  138 + </el-table>
  139 + </div>
  140 + </el-card>
  141 +
  142 + <div class="margin-top">
  143 + <floor-fee-summary ref="floorFeeSummary" />
  144 + </div>
  145 + <div class="margin-top">
  146 + <config-fee-summary ref="configFeeSummary" />
  147 + </div>
  148 + </el-col>
  149 + </el-row>
  150 + </div>
  151 +</template>
  152 +
  153 +<script>
  154 +import { getDict, getCommunityId } from '@/api/community/communityApi'
  155 +import { queryReportFeeSummary, exportData, queryCommunitys, queryFeeConfigs } from '@/api/report/reportFeeSummaryApi'
  156 +import SelectCommunityFloor from '@/components/report/selectCommunityFloor'
  157 +import FloorFeeSummary from '@/components/report/floorFeeSummary'
  158 +import ConfigFeeSummary from '@/components/report/configFeeSummary'
  159 +
  160 +export default {
  161 + name: 'ReportFeeSummaryList',
  162 + components: {
  163 + SelectCommunityFloor,
  164 + FloorFeeSummary,
  165 + ConfigFeeSummary
  166 + },
  167 + data() {
  168 + return {
  169 + reportFeeSummaryInfo: {
  170 + fees: [],
  171 + feeConfigs: [],
  172 + floors: [],
  173 + configIds: [],
  174 + feeTypeCds: [],
  175 + communitys: [],
  176 + moreCondition: false,
  177 + conditions: {
  178 + floorId: '',
  179 + objName: '',
  180 + startDate: '',
  181 + endDate: '',
  182 + configId: '',
  183 + feeTypeCd: '',
  184 + ownerName: '',
  185 + link: '',
  186 + communityId: ''
  187 + }
  188 + }
  189 + }
  190 + },
  191 + created() {
  192 + this.initData()
  193 + },
  194 + methods: {
  195 + async initData() {
  196 + this.reportFeeSummaryInfo.conditions.communityId = await getCommunityId()
  197 + this._initDate()
  198 + this._loadStaffCommunitys()
  199 + this._listFeeConfigs()
  200 + this.getFeeTypeDict()
  201 + this.$refs.selectCommunityFloor.open({
  202 + callBack: (floor) => {
  203 + this.reportFeeSummaryInfo.conditions.floorId = floor.floorId
  204 + this._listFees()
  205 + }
  206 + })
  207 + this._listFees()
  208 + },
  209 + _initDate() {
  210 + const now = new Date()
  211 + const year = now.getFullYear()
  212 + const month = now.getMonth() + 1
  213 + const lastDay = new Date(year, month, 0).getDate()
  214 +
  215 + this.reportFeeSummaryInfo.conditions.startDate = `${year}-${month.toString().padStart(2, '0')}-01`
  216 + this.reportFeeSummaryInfo.conditions.endDate = `${year}-${month.toString().padStart(2, '0')}-${lastDay}`
  217 + },
  218 + handleDateChange() {
  219 + if (this.reportFeeSummaryInfo.conditions.startDate && this.reportFeeSummaryInfo.conditions.endDate) {
  220 + const start = new Date(this.reportFeeSummaryInfo.conditions.startDate)
  221 + const end = new Date(this.reportFeeSummaryInfo.conditions.endDate)
  222 +
  223 + if (start > end) {
  224 + this.$message.error(this.$t('reportFeeSummary.dateError'))
  225 + this.reportFeeSummaryInfo.conditions.endDate = ''
  226 + }
  227 + }
  228 + },
  229 + async getFeeTypeDict() {
  230 + try {
  231 + this.reportFeeSummaryInfo.feeTypeCds = await getDict('pay_fee_config', 'fee_type_cd')
  232 + } catch (error) {
  233 + console.error('Failed to get fee type dict:', error)
  234 + }
  235 + },
  236 + async _listFees() {
  237 + try {
  238 + const params = {
  239 + page: 1,
  240 + row: 100,
  241 + ...this.reportFeeSummaryInfo.conditions,
  242 + configIds: this.reportFeeSummaryInfo.configIds.join(',')
  243 + }
  244 +
  245 + const { data } = await queryReportFeeSummary(params)
  246 + this.reportFeeSummaryInfo.fees = data
  247 +
  248 + // Notify child components
  249 + this.$refs.floorFeeSummary.notify(params)
  250 + this.$refs.configFeeSummary.notify(params)
  251 + } catch (error) {
  252 + console.error('Failed to query fee summary:', error)
  253 + }
  254 + },
  255 + async _loadStaffCommunitys() {
  256 + try {
  257 + const { data } = await queryCommunitys()
  258 + this.reportFeeSummaryInfo.communitys = data.communitys
  259 + } catch (error) {
  260 + console.error('Failed to load communities:', error)
  261 + }
  262 + },
  263 + async _listFeeConfigs() {
  264 + try {
  265 + const params = {
  266 + page: 1,
  267 + row: 100,
  268 + communityId: this.reportFeeSummaryInfo.conditions.communityId,
  269 + isDefault: 'F'
  270 + }
  271 +
  272 + const { data } = await queryFeeConfigs(params)
  273 + this.reportFeeSummaryInfo.feeConfigs = data.feeConfigs
  274 + } catch (error) {
  275 + console.error('Failed to list fee configs:', error)
  276 + }
  277 + },
  278 + _queryMethod() {
  279 + this._listFees()
  280 + },
  281 + _resetMethod() {
  282 + this.reportFeeSummaryInfo.conditions = {
  283 + ...this.reportFeeSummaryInfo.conditions,
  284 + roomNum: '',
  285 + ownerName: '',
  286 + link: '',
  287 + feeTypeCd: '',
  288 + floorName: '',
  289 + floorId: '',
  290 + unitId: '',
  291 + configId: ''
  292 + }
  293 + this.reportFeeSummaryInfo.configIds = []
  294 + this._listFees()
  295 + },
  296 + async _exportExcel() {
  297 + try {
  298 + const params = {
  299 + ...this.reportFeeSummaryInfo.conditions,
  300 + pagePath: 'reportFeeSummary'
  301 + }
  302 +
  303 + await exportData(params)
  304 + this.$message.success(this.$t('reportFeeSummary.exportSuccess'))
  305 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  306 + } catch (error) {
  307 + console.error('Failed to export:', error)
  308 + this.$message.error(this.$t('reportFeeSummary.exportFailed'))
  309 + }
  310 + },
  311 + _changCommunity() {
  312 + this._listFeeConfigs()
  313 + this._listFees()
  314 + }
  315 + }
  316 +}
  317 +</script>
  318 +
  319 +<style lang="scss" scoped>
  320 +.report-fee-summary-container {
  321 + padding: 20px;
  322 +
  323 + .margin-top {
  324 + margin-top: 20px;
  325 + }
  326 +
  327 + .padding-r-0 {
  328 + padding-right: 0;
  329 + }
  330 +
  331 + .popover-show {
  332 + margin-left: 10px;
  333 + color: #409EFF;
  334 + }
  335 +
  336 + .el-checkbox {
  337 + margin-right: 15px;
  338 + }
  339 +}
  340 +</style>
0 341 \ No newline at end of file
... ...