Commit 24d3590fc5bddf07c6a7d20044b8caa3577abff5

Authored by wuxw
1 parent 7a03ee5c

房屋收费页面开发完成

Showing 114 changed files with 10063 additions and 624 deletions

Too many changes.

To preserve performance only 100 of 114 files are displayed.

src/api/fee/addProxyFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function saveProxyFee(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/meterWater.saveProxyFee',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to save proxy fee'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function listFeeConfigs(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/feeConfig.listFeeConfigs',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code === 0) {
  31 + resolve(res)
  32 + } else {
  33 + reject(new Error(res.msg || 'Failed to list fee configs'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
src/api/fee/batchPayFeeOrderApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询批量缴费列表
  4 +export function listFee(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/fee.listFee',
  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 listFeeObj(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/feeApi/listFeeObj',
  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 queryCommunityOwnerAccount(params) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/account.queryCommunityOwnerAccount',
  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 queryFeeDeposit(params) {
  53 + return new Promise((resolve, reject) => {
  54 + request({
  55 + url: '/fee.queryFeeDeposit',
  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 refundFeeDeposit(data) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/fee.refundFeeDeposit',
  72 + method: 'post',
  73 + data
  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 payBatchFee(data) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/fee.payBatchFee',
  88 + method: 'post',
  89 + data
  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 qrCodePayment(data) {
  101 + return new Promise((resolve, reject) => {
  102 + request({
  103 + url: '/payment.qrCodePayment',
  104 + method: 'post',
  105 + data
  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 checkPayFinish(data) {
  117 + return new Promise((resolve, reject) => {
  118 + request({
  119 + url: '/payment.checkPayFinish',
  120 + method: 'post',
  121 + data
  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 listFeePrintPage(params) {
  133 + return new Promise((resolve, reject) => {
  134 + request({
  135 + url: '/feePrintPage.listFeePrintPage',
  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 +}
0 \ No newline at end of file 146 \ No newline at end of file
src/api/fee/carDetailOwnerApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryOwners(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/owner.queryOwners',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code == 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to query owners'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/deleteFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function deleteFee(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/fee.deleteFee',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '删除费用失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/deleteFeeRuleApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function deletePayFeeRule(data) {
  4 + return request({
  5 + url: '/payFeeRule.deletePayFeeRule',
  6 + method: 'post',
  7 + data
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/deleteOweFeeCallableApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function deleteOweFeeCallable(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/oweFeeCallable.deleteOweFeeCallable',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code == 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to delete owe fee callable'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/doImportCreateFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function importData(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/assetImport/importData',
  7 + method: 'post',
  8 + data,
  9 + headers: {
  10 + 'Content-Type': 'multipart/form-data'
  11 + }
  12 + }).then(response => {
  13 + const res = response.data
  14 + if (res.code === 0) {
  15 + resolve(res)
  16 + } else {
  17 + reject(new Error(res.msg || 'Failed to import data'))
  18 + }
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
0 \ No newline at end of file 24 \ No newline at end of file
src/api/fee/downloadCollectionLetterOrderApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function exportData(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/export.exportData',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to export data'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function queryFloors(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/floor.queryFloors',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code === 0) {
  31 + resolve(res)
  32 + } else {
  33 + reject(new Error(res.msg || 'Failed to query floors'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
src/api/fee/editFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function updateFee(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/fee.updateFee',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '更新费用失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/editFeeRuleApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function updatePayFeeRule(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/payFeeRule.updatePayFeeRule',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '更新费用规则失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/exportFeeImportExcelApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function exportData(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/export.exportData',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to export data'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function listFeeConfigs(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/feeConfig.listFeeConfigs',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code === 0) {
  31 + resolve(res)
  32 + } else {
  33 + reject(new Error(res.msg || 'Failed to list fee configs'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
  40 +
  41 +export function queryFloors(params) {
  42 + return new Promise((resolve, reject) => {
  43 + request({
  44 + url: '/floor.queryFloors',
  45 + method: 'get',
  46 + params
  47 + }).then(response => {
  48 + const res = response.data
  49 + if (res.code === 0) {
  50 + resolve(res)
  51 + } else {
  52 + reject(new Error(res.msg || 'Failed to query floors'))
  53 + }
  54 + }).catch(error => {
  55 + reject(error)
  56 + })
  57 + })
  58 +}
0 \ No newline at end of file 59 \ No newline at end of file
src/api/fee/feeDetailFeeRuleApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listPayFeeRule(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/payFeeRule.listPayFeeRule',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '获取费用规则列表失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/feeDetailRuleBillApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listPayFeeRuleBill(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/payFeeRule.listPayFeeRuleBill',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '获取账单列表失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/finishFeeRuleApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function updatePayFeeRule(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/payFeeRule.updatePayFeeRule',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '结束费用规则失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/inputSearchRoomApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryRooms(params) {
  4 + return request({
  5 + url: '/room.queryRooms',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/inputSearchRoomByOwnerApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryRoomsByOwner(params) {
  4 + return request({
  5 + url: '/room.queryRoomsByOwner',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/ownerDetailAccountApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryCommunityOwnerAccount(params) {
  4 + return request({
  5 + url: '/account.queryCommunityOwnerAccount',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/ownerDetailAccountReceiptApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listAccountReceipt(params) {
  4 + return request({
  5 + url: '/receipt.listAccountReceipt',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/prestoreAccountApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function ownerPrestoreAccount(data) {
  4 + return request({
  5 + url: '/account.ownerPrestoreAccount',
  6 + method: 'post',
  7 + data
  8 + })
  9 +}
  10 +
  11 +export function queryOwners(params) {
  12 + return request({
  13 + url: '/owner.queryOwners',
  14 + method: 'get',
  15 + params
  16 + })
  17 +}
  18 +
  19 +export function queryRoomsByOwner(params) {
  20 + return request({
  21 + url: '/room.queryRoomsByOwner',
  22 + method: 'get',
  23 + params
  24 + })
  25 +}
0 \ No newline at end of file 26 \ No newline at end of file
src/api/fee/propertyFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询费用明细列表
  4 +export function queryFeeDetail(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/fee.queryFeeDetail',
  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 listFee(params) {
  21 + return new Promise((resolve, reject) => {
  22 + request({
  23 + url: '/fee.listFee',
  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 queryRooms(params) {
  37 + return new Promise((resolve, reject) => {
  38 + request({
  39 + url: '/room.queryRooms',
  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 saveReturnPayFee(data) {
  69 + return new Promise((resolve, reject) => {
  70 + request({
  71 + url: '/returnPayFee.saveReturnPayFee',
  72 + method: 'post',
  73 + data
  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 queryFeeDetailDiscount(params) {
  85 + return new Promise((resolve, reject) => {
  86 + request({
  87 + url: '/feeDiscount/queryFeeDetailDiscount',
  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 +}
0 \ No newline at end of file 98 \ No newline at end of file
src/api/fee/roomCreateFeeAddApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function saveRoomCreateFee(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/fee.saveRoomCreateFee',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to save room create fee'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function listFeeConfigs(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/feeConfig.listFeeConfigs',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code === 0) {
  31 + resolve(res)
  32 + } else {
  33 + reject(new Error(res.msg || 'Failed to list fee configs'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
src/api/fee/roomCreateFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询房间列表
  4 +export function queryRooms(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/room.queryRooms',
  8 + method: 'get',
  9 + params
  10 + })
  11 + .then(response => {
  12 + const res = response.data
  13 + resolve(res)
  14 + })
  15 + .catch(error => {
  16 + reject(error)
  17 + })
  18 + })
  19 +}
  20 +
  21 +// 导出费用导入模板
  22 +export function exportFeeImportExcel(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/export.exportData',
  26 + method: 'get',
  27 + params
  28 + })
  29 + .then(response => {
  30 + const res = response.data
  31 + if (res.code === 0) {
  32 + resolve(res)
  33 + } else {
  34 + reject(new Error(res.msg || '导出模板失败'))
  35 + }
  36 + })
  37 + .catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +// 导入费用数据
  44 +export function importCreateFee(data) {
  45 + return new Promise((resolve, reject) => {
  46 + request({
  47 + url: '/fee.importCreateFee',
  48 + method: 'post',
  49 + data
  50 + })
  51 + .then(response => {
  52 + const res = response.data
  53 + if (res.code === 0) {
  54 + resolve(res)
  55 + } else {
  56 + reject(new Error(res.msg || '导入费用失败'))
  57 + }
  58 + })
  59 + .catch(error => {
  60 + reject(error)
  61 + })
  62 + })
  63 +}
  64 +
  65 +// 批量创建费用
  66 +export function batchCreateFee(data) {
  67 + return new Promise((resolve, reject) => {
  68 + request({
  69 + url: '/fee.batchCreateFee',
  70 + method: 'post',
  71 + data
  72 + })
  73 + .then(response => {
  74 + const res = response.data
  75 + if (res.code === 0) {
  76 + resolve(res)
  77 + } else {
  78 + reject(new Error(res.msg || '批量创建费用失败'))
  79 + }
  80 + })
  81 + .catch(error => {
  82 + reject(error)
  83 + })
  84 + })
  85 +}
  86 +
  87 +// 下载催缴单
  88 +export function downloadCollectionLetter(params) {
  89 + return new Promise((resolve, reject) => {
  90 + request({
  91 + url: '/fee.downloadCollectionLetter',
  92 + method: 'get',
  93 + params
  94 + })
  95 + .then(response => {
  96 + const res = response.data
  97 + if (res.code === 0) {
  98 + resolve(res)
  99 + } else {
  100 + reject(new Error(res.msg || '下载催缴单失败'))
  101 + }
  102 + })
  103 + .catch(error => {
  104 + reject(error)
  105 + })
  106 + })
  107 +}
0 \ No newline at end of file 108 \ No newline at end of file
src/api/fee/simplifyCallableApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listOweFeeCallable(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/oweFeeCallable.listOweFeeCallable',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code == 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to list owe fee callable'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/fee/simplifyFeeReceiptApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryFeeReceipt(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/feeReceipt/queryFeeReceipt',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code == 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to query fee receipt'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function listFeePrintPage(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/feePrintPage.listFeePrintPage',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code == 0) {
  31 + resolve(res)
  32 + } else {
  33 + reject(new Error(res.msg || 'Failed to list fee print pages'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
  40 +
  41 +export function queryOwnerCars(params) {
  42 + return new Promise((resolve, reject) => {
  43 + request({
  44 + url: '/owner.queryOwnerCars',
  45 + method: 'get',
  46 + params
  47 + }).then(response => {
  48 + const res = response.data
  49 + if (res.code == 0) {
  50 + resolve(res)
  51 + } else {
  52 + reject(new Error(res.msg || 'Failed to query owner cars'))
  53 + }
  54 + }).catch(error => {
  55 + reject(error)
  56 + })
  57 + })
  58 +}
  59 +
  60 +export function queryContract(params) {
  61 + return new Promise((resolve, reject) => {
  62 + request({
  63 + url: '/contract/queryContract',
  64 + method: 'get',
  65 + params
  66 + }).then(response => {
  67 + const res = response.data
  68 + if (res.code == 0) {
  69 + resolve(res)
  70 + } else {
  71 + reject(new Error(res.msg || 'Failed to query contract'))
  72 + }
  73 + }).catch(error => {
  74 + reject(error)
  75 + })
  76 + })
  77 +}
0 \ No newline at end of file 78 \ No newline at end of file
src/api/fee/simplifyHisFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryFeeDetail(params) {
  4 + return request({
  5 + url: '/fee.queryFeeDetail',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
  10 +
  11 +export function generatorReceipt(data) {
  12 + return request({
  13 + url: '/receipt.generatorReceipt',
  14 + method: 'post',
  15 + data
  16 + })
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
src/api/fee/simplifyMeterWaterLogApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listMeterWaters(params) {
  4 + return request({
  5 + url: '/meterWater.listMeterWaters',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
  10 +
  11 +export function listMeterTypes(params) {
  12 + return request({
  13 + url: '/meterType.listMeterType',
  14 + method: 'get',
  15 + params
  16 + })
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
src/api/fee/simplifyOwnerRoomsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryRoomsByOwner(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/room.queryRoomsByOwner',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 +
  12 + resolve(res)
  13 +
  14 + }).catch(error => {
  15 + reject(error)
  16 + })
  17 + })
  18 +}
0 \ No newline at end of file 19 \ No newline at end of file
src/api/fee/simplifyRefundDepositApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryFeeDeposit(params) {
  4 + return request({
  5 + url: '/fee.queryFeeDeposit',
  6 + method: 'get',
  7 + params
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/simplifyRoomFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listFee(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/fee.listFee',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + resolve(res)
  12 +
  13 + }).catch(error => {
  14 + reject(error)
  15 + })
  16 + })
  17 +}
  18 +
  19 +export function listFeeConfigs(params) {
  20 + return new Promise((resolve, reject) => {
  21 + request({
  22 + url: '/feeConfig.listFeeConfigs',
  23 + method: 'get',
  24 + params
  25 + }).then(response => {
  26 + const res = response.data
  27 + resolve(res)
  28 +
  29 + }).catch(error => {
  30 + reject(error)
  31 + })
  32 + })
  33 +}
  34 +
  35 +export function listMonthFee(params) {
  36 + return new Promise((resolve, reject) => {
  37 + request({
  38 + url: '/fee.listMonthFee',
  39 + method: 'get',
  40 + params
  41 + }).then(response => {
  42 + const res = response.data
  43 +
  44 + resolve(res)
  45 +
  46 + }).catch(error => {
  47 + reject(error)
  48 + })
  49 + })
  50 +}
0 \ No newline at end of file 51 \ No newline at end of file
src/api/fee/tempImportRoomFeeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function importTempData(data) {
  4 + return request({
  5 + url: '/importRoomFee/importTempData',
  6 + method: 'post',
  7 + data
  8 + })
  9 +}
0 \ No newline at end of file 10 \ No newline at end of file
src/api/fee/writeOweFeeCallableApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function writeOweFeeCallable(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/oweFeeCallable.writeOweFeeCallable',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code == 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || 'Failed to write owe fee callable'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function listFee(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/fee.listFee',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code == 0) {
  31 + resolve(res)
  32 + } else {
  33 + reject(new Error(res.msg || 'Failed to list fees'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
src/components/contract/searchOwner.vue
1 <template> 1 <template>
2 - <el-dialog  
3 - :title="$t('contract.selectOwner')"  
4 - :visible.sync="visible"  
5 - width="80%"  
6 - :before-close="handleClose">  
7 - 2 + <el-dialog :title="$t('contract.selectOwner')" :visible.sync="visible" width="80%" :before-close="handleClose">
  3 +
8 <div class="search-wrapper"> 4 <div class="search-wrapper">
9 <el-row :gutter="20"> 5 <el-row :gutter="20">
10 <el-col :span="8"> 6 <el-col :span="8">
11 - <el-input  
12 - v-model="searchOwnerInfo.roomName"  
13 - :placeholder="$t('contract.inputRoomFullNum')"> 7 + <el-input v-model="searchOwnerInfo.roomName" :placeholder="$t('contract.inputRoomFullNum')">
14 </el-input> 8 </el-input>
15 </el-col> 9 </el-col>
16 <el-col :span="8"> 10 <el-col :span="8">
17 - <el-input  
18 - v-model="searchOwnerInfo._currentOwnerName"  
19 - :placeholder="$t('contract.inputOwnerName')"> 11 + <el-input v-model="searchOwnerInfo._currentOwnerName" :placeholder="$t('contract.inputOwnerName')">
20 </el-input> 12 </el-input>
21 </el-col> 13 </el-col>
22 <el-col :span="8"> 14 <el-col :span="8">
@@ -27,65 +19,32 @@ @@ -27,65 +19,32 @@
27 </el-col> 19 </el-col>
28 </el-row> 20 </el-row>
29 </div> 21 </div>
30 -  
31 - <el-table  
32 - :data="searchOwnerInfo.owners"  
33 - border  
34 - style="width: 100%"  
35 - height="400">  
36 - <el-table-column  
37 - prop="memberId"  
38 - :label="$t('contract.ownerId')"  
39 - align="center"> 22 +
  23 + <el-table :data="searchOwnerInfo.owners" border style="width: 100%" height="400">
  24 + <el-table-column prop="memberId" :label="$t('contract.ownerId')" align="center">
40 </el-table-column> 25 </el-table-column>
41 - <el-table-column  
42 - prop="name"  
43 - :label="$t('contract.name')"  
44 - align="center"> 26 + <el-table-column prop="name" :label="$t('contract.name')" align="center">
45 </el-table-column> 27 </el-table-column>
46 - <el-table-column  
47 - prop="personTypeName"  
48 - :label="$t('contract.personType')"  
49 - align="center"> 28 + <el-table-column prop="personTypeName" :label="$t('contract.personType')" align="center">
50 </el-table-column> 29 </el-table-column>
51 - <el-table-column  
52 - prop="personRoleName"  
53 - :label="$t('contract.personRole')"  
54 - align="center"> 30 + <el-table-column prop="personRoleName" :label="$t('contract.personRole')" align="center">
55 </el-table-column> 31 </el-table-column>
56 - <el-table-column  
57 - prop="idCard"  
58 - :label="$t('contract.idCard')"  
59 - align="center"> 32 + <el-table-column prop="idCard" :label="$t('contract.idCard')" align="center">
60 </el-table-column> 33 </el-table-column>
61 - <el-table-column  
62 - prop="link"  
63 - :label="$t('contract.contact')"  
64 - align="center"> 34 + <el-table-column prop="link" :label="$t('contract.contact')" align="center">
65 </el-table-column> 35 </el-table-column>
66 - <el-table-column  
67 - :label="$t('common.operation')"  
68 - align="center"  
69 - width="120"> 36 + <el-table-column :label="$t('common.operation')" align="center" width="120">
70 <template slot-scope="scope"> 37 <template slot-scope="scope">
71 - <el-button  
72 - type="primary"  
73 - size="mini"  
74 - @click="chooseOwner(scope.row)"> 38 + <el-button type="primary" size="mini" @click="chooseOwner(scope.row)">
75 {{ $t('contract.select') }} 39 {{ $t('contract.select') }}
76 </el-button> 40 </el-button>
77 </template> 41 </template>
78 </el-table-column> 42 </el-table-column>
79 </el-table> 43 </el-table>
80 - 44 +
81 <div class="pagination-wrapper"> 45 <div class="pagination-wrapper">
82 - <el-pagination  
83 - @size-change="handleSizeChange"  
84 - @current-change="handleCurrentChange"  
85 - :current-page="page.current"  
86 - :page-sizes="[10, 20, 30, 50]"  
87 - :page-size="page.size"  
88 - layout="total, sizes, prev, pager, next, jumper" 46 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page.current"
  47 + :page-sizes="[10, 20, 30, 50]" :page-size="page.size" layout="total, sizes, prev, pager, next, jumper"
89 :total="page.total"> 48 :total="page.total">
90 </el-pagination> 49 </el-pagination>
91 </div> 50 </div>
@@ -94,6 +53,7 @@ @@ -94,6 +53,7 @@
94 53
95 <script> 54 <script>
96 import { queryOwners } from '@/api/contract/addContractApi' 55 import { queryOwners } from '@/api/contract/addContractApi'
  56 +import { getCommunityId } from '@/api/community/communityApi'
97 57
98 export default { 58 export default {
99 name: 'SearchOwner', 59 name: 'SearchOwner',
@@ -133,12 +93,12 @@ export default { @@ -133,12 +93,12 @@ export default {
133 const params = { 93 const params = {
134 page: _page, 94 page: _page,
135 row: _row, 95 row: _row,
136 - communityId: this.$store.getters.communityId, 96 + communityId: getCommunityId(),
137 name: this.searchOwnerInfo._currentOwnerName.trim(), 97 name: this.searchOwnerInfo._currentOwnerName.trim(),
138 roomName: this.searchOwnerInfo.roomName.trim(), 98 roomName: this.searchOwnerInfo.roomName.trim(),
139 ownerTypeCd: this.searchOwnerInfo.ownerTypeCd 99 ownerTypeCd: this.searchOwnerInfo.ownerTypeCd
140 } 100 }
141 - 101 +
142 queryOwners(params).then(response => { 102 queryOwners(params).then(response => {
143 this.searchOwnerInfo.owners = response.data 103 this.searchOwnerInfo.owners = response.data
144 this.page.total = response.records 104 this.page.total = response.records
@@ -190,7 +150,7 @@ export default { @@ -190,7 +150,7 @@ export default {
190 text-align: right; 150 text-align: right;
191 } 151 }
192 152
193 -.el-button + .el-button { 153 +.el-button+.el-button {
194 margin-left: 10px; 154 margin-left: 10px;
195 } 155 }
196 </style> 156 </style>
197 \ No newline at end of file 157 \ No newline at end of file
src/components/fee/addApplyRoomDiscount.vue
@@ -66,6 +66,7 @@ @@ -66,6 +66,7 @@
66 <script> 66 <script>
67 import { queryApplyRoomDiscountType ,listRoomsWhereFeeSet} from '@/api/fee/applyRoomDiscountManageApi' 67 import { queryApplyRoomDiscountType ,listRoomsWhereFeeSet} from '@/api/fee/applyRoomDiscountManageApi'
68 import UploadImageUrl from '@/components/upload/UploadImageUrl' 68 import UploadImageUrl from '@/components/upload/UploadImageUrl'
  69 +import { getCommunityId } from '@/api/community/communityApi'
69 70
70 export default { 71 export default {
71 name: 'AddApplyRoomDiscount', 72 name: 'AddApplyRoomDiscount',
@@ -231,7 +232,7 @@ export default { @@ -231,7 +232,7 @@ export default {
231 }, 232 },
232 async saveApplyRoomDiscount() { 233 async saveApplyRoomDiscount() {
233 try { 234 try {
234 - this.form.communityId = this.$store.getters.communityId 235 + this.form.communityId = getCommunityId()
235 await this.$api.applyRoomDiscount.saveApplyRoomDiscount(this.form) 236 await this.$api.applyRoomDiscount.saveApplyRoomDiscount(this.form)
236 this.$message.success(this.$t('applyRoomDiscount.message.saveSuccess')) 237 this.$message.success(this.$t('applyRoomDiscount.message.saveSuccess'))
237 this.visible = false 238 this.visible = false
src/components/fee/addProxyFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog :title="$t('addProxyFee.title')" :visible.sync="visible" width="70%" :before-close="handleClose">
  3 + <el-form ref="form" :model="formData" label-width="120px">
  4 + <el-form-item :label="$t('addProxyFee.feeType')" prop="feeTypeCd">
  5 + <el-select v-model="formData.feeTypeCd" @change="handleFeeTypeChange"
  6 + :placeholder="$t('addProxyFee.feeTypePlaceholder')" style="width: 100%">
  7 + <el-option v-for="item in feeTypeOptions" :key="item.value" :label="item.label"
  8 + :value="item.value"></el-option>
  9 + </el-select>
  10 + </el-form-item>
  11 +
  12 + <el-form-item :label="$t('addProxyFee.feeItem')" prop="configId">
  13 + <el-select v-model="formData.configId" @change="handleConfigChange"
  14 + :placeholder="$t('addProxyFee.feeItemPlaceholder')" style="width: 100%">
  15 + <el-option v-for="item in feeConfigOptions" :key="item.configId" :label="item.feeName"
  16 + :value="item.configId"></el-option>
  17 + </el-select>
  18 + <span class="tip">{{ $t('addProxyFee.feeItemTip') }}</span>
  19 + </el-form-item>
  20 +
  21 + <el-form-item :label="$t('addProxyFee.chargeObject')">
  22 + <el-input v-model="formData.ownerName" disabled
  23 + :placeholder="$t('addProxyFee.chargeObjectPlaceholder')"></el-input>
  24 + </el-form-item>
  25 +
  26 + <template v-if="formData.feeTypeCd !== '888800010014'">
  27 + <el-form-item :label="$t('addProxyFee.consumption')" prop="consumption">
  28 + <el-input v-model="formData.consumption" @blur="handleConsumptionBlur"
  29 + :placeholder="$t('addProxyFee.consumptionPlaceholder')"></el-input>
  30 + </el-form-item>
  31 +
  32 + <el-form-item :label="$t('addProxyFee.amount')" prop="amount">
  33 + <el-input v-model="formData.amount" @blur="handleAmountBlur"
  34 + :placeholder="$t('addProxyFee.amountPlaceholder')"></el-input>
  35 + </el-form-item>
  36 + </template>
  37 +
  38 + <template v-else>
  39 + <el-form-item :label="$t('addProxyFee.quantity')" prop="consumption">
  40 + <el-input v-model="formData.consumption" @blur="handleConsumptionBlur"
  41 + :placeholder="$t('addProxyFee.consumptionPlaceholder')"></el-input>
  42 + </el-form-item>
  43 +
  44 + <el-form-item :label="$t('addProxyFee.amount')">
  45 + <el-input v-model="formData.amount" disabled :placeholder="$t('addProxyFee.amountPlaceholder')"></el-input>
  46 + </el-form-item>
  47 + </template>
  48 +
  49 + <el-form-item :label="$t('addProxyFee.startTime')" prop="startTime">
  50 + <el-date-picker v-model="formData.startTime" type="date" :placeholder="$t('addProxyFee.startTimePlaceholder')"
  51 + value-format="yyyy-MM-dd" @change="validateStartTime"></el-date-picker>
  52 + </el-form-item>
  53 +
  54 + <el-form-item :label="$t('addProxyFee.endTime')" prop="endTime">
  55 + <el-date-picker v-model="formData.endTime" type="date" :placeholder="$t('addProxyFee.endTimePlaceholder')"
  56 + value-format="yyyy-MM-dd" @change="validateEndTime"></el-date-picker>
  57 + </el-form-item>
  58 + </el-form>
  59 +
  60 + <span slot="footer" class="dialog-footer">
  61 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  62 + <el-button type="primary" @click="handleSubmit">{{ $t('common.save') }}</el-button>
  63 + </span>
  64 + </el-dialog>
  65 +</template>
  66 +
  67 +<script>
  68 +import { saveProxyFee, listFeeConfigs } from '@/api/fee/addProxyFeeApi'
  69 +import { getCommunityId } from '@/api/community/communityApi'
  70 +import { dateFormat } from '@/utils/dateUtil'
  71 +
  72 +export default {
  73 + name: 'AddProxyFee',
  74 + props: {
  75 + callBackListener: String,
  76 + callBackFunction: String
  77 + },
  78 + data() {
  79 + return {
  80 + visible: false,
  81 + formData: {
  82 + remark: '',
  83 + roomId: '',
  84 + objId: '',
  85 + objName: '',
  86 + feeTypeCd: '',
  87 + feeConfigs: [],
  88 + amount: '',
  89 + consumption: '',
  90 + configId: '',
  91 + ownerName: '',
  92 + objType: '3333',
  93 + startTime: dateFormat(new Date()),
  94 + endTime: dateFormat(new Date())
  95 + },
  96 + feeTypeOptions: [
  97 + { value: '888800010015', label: this.$t('addProxyFee.waterFee') },
  98 + { value: '888800010016', label: this.$t('addProxyFee.electricityFee') },
  99 + { value: '888800010014', label: this.$t('addProxyFee.otherFee') }
  100 + ],
  101 + feeConfigOptions: [],
  102 + rules: {
  103 + amount: [
  104 + { required: true, message: this.$t('addProxyFee.validate.amountRequired'), trigger: 'blur' },
  105 + { pattern: /^\d+(\.\d{1,2})?$/, message: this.$t('addProxyFee.validate.amountFormat'), trigger: 'blur' }
  106 + ],
  107 + consumption: [
  108 + { required: true, message: this.$t('addProxyFee.validate.consumptionRequired'), trigger: 'blur' },
  109 + { pattern: /^\d+(\.\d{1,2})?$/, message: this.$t('addProxyFee.validate.consumptionFormat'), trigger: 'blur' }
  110 + ],
  111 + objId: [
  112 + { required: true, message: this.$t('addProxyFee.validate.roomRequired'), trigger: 'blur' }
  113 + ],
  114 + configId: [
  115 + { required: true, message: this.$t('addProxyFee.validate.feeRequired'), trigger: 'change' }
  116 + ],
  117 + startTime: [
  118 + { required: true, message: this.$t('addProxyFee.validate.startTimeRequired'), trigger: 'blur' }
  119 + ],
  120 + endTime: [
  121 + { required: true, message: this.$t('addProxyFee.validate.endTimeRequired'), trigger: 'blur' }
  122 + ]
  123 + }
  124 + }
  125 + },
  126 + methods: {
  127 + open(params) {
  128 + this.resetForm()
  129 + if (params.objType) {
  130 + this.formData.objType = params.objType
  131 + }
  132 + this.formData.roomId = params.roomId
  133 + this.formData.objId = params.roomId
  134 + this.formData.objName = params.roomName
  135 + this.formData.ownerName = `${params.roomName}(${params.ownerName})`
  136 + this.visible = true
  137 + },
  138 +
  139 + handleFeeTypeChange(value) {
  140 + this.formData.amount = ''
  141 + this.formData.consumption = ''
  142 + this.formData.configId = ''
  143 + this.loadFeeConfigs(value)
  144 + },
  145 +
  146 + loadFeeConfigs(feeTypeCd) {
  147 + listFeeConfigs({
  148 + page: 1,
  149 + row: 20,
  150 + communityId: getCommunityId(),
  151 + feeTypeCd,
  152 + isDefault: 'F',
  153 + computingFormula: '6006',
  154 + valid: '1'
  155 + }).then(response => {
  156 + this.feeConfigOptions = response.data.feeConfigs
  157 + })
  158 + },
  159 +
  160 + handleConfigChange() {
  161 + this.formData.amount = ''
  162 + this.formData.consumption = ''
  163 + },
  164 +
  165 + getCurrentConfig() {
  166 + return this.feeConfigOptions.find(
  167 + item => this.formData.configId === item.configId && item.computingFormula === '6006'
  168 + )
  169 + },
  170 +
  171 + handleAmountBlur() {
  172 + const config = this.getCurrentConfig()
  173 + const amount = parseFloat(this.formData.amount)
  174 +
  175 + if (!config) {
  176 + this.$message.error(this.$t('addProxyFee.validate.invalidConfig'))
  177 + this.formData.amount = ''
  178 + this.formData.consumption = ''
  179 + return
  180 + }
  181 +
  182 + if (amount < config.additionalAmount) {
  183 + this.$message.error(this.$t('addProxyFee.validate.amountTooSmall'))
  184 + this.formData.amount = ''
  185 + this.formData.consumption = ''
  186 + return
  187 + }
  188 +
  189 + const consumption = (amount - config.additionalAmount) / config.squarePrice
  190 + this.formData.consumption = consumption.toFixed(2)
  191 + },
  192 +
  193 + handleConsumptionBlur() {
  194 + const config = this.getCurrentConfig()
  195 + const consumption = parseFloat(this.formData.consumption)
  196 +
  197 + if (!config) {
  198 + this.$message.error(this.$t('addProxyFee.validate.invalidConfig'))
  199 + this.formData.amount = ''
  200 + this.formData.consumption = ''
  201 + return
  202 + }
  203 +
  204 + const amount = config.squarePrice * consumption + parseFloat(config.additionalAmount)
  205 + this.formData.amount = amount.toFixed(2)
  206 + },
  207 +
  208 + validateStartTime(value) {
  209 + const start = new Date(value)
  210 + const end = new Date(this.formData.endTime)
  211 + if (start >= end) {
  212 + this.$message.error(this.$t('addProxyFee.validate.startBeforeEnd'))
  213 + this.formData.startTime = ''
  214 + }
  215 + },
  216 +
  217 + validateEndTime(value) {
  218 + const start = new Date(this.formData.startTime)
  219 + const end = new Date(value)
  220 + if (start >= end) {
  221 + this.$message.error(this.$t('addProxyFee.validate.endAfterStart'))
  222 + this.formData.endTime = ''
  223 + }
  224 + },
  225 +
  226 + handleSubmit() {
  227 + this.$refs.form.validate(valid => {
  228 + if (!valid) return
  229 +
  230 + const params = {
  231 + ...this.formData,
  232 + communityId: getCommunityId()
  233 + }
  234 +
  235 +
  236 +
  237 + saveProxyFee(params).then(() => {
  238 + this.$message.success(this.$t('addProxyFee.successMessage'))
  239 + this.$emit('success')
  240 + this.handleClose()
  241 + }).catch(error => {
  242 + this.$message.error(error.message)
  243 + })
  244 + })
  245 + },
  246 +
  247 + resetForm() {
  248 + if (this.$refs.form) {
  249 + this.$refs.form.resetFields()
  250 + }
  251 + this.formData = {
  252 + remark: '',
  253 + roomId: '',
  254 + objId: '',
  255 + objName: '',
  256 + feeTypeCd: '',
  257 + feeConfigs: [],
  258 + amount: '',
  259 + consumption: '',
  260 + configId: '',
  261 + ownerName: '',
  262 + objType: '3333',
  263 + startTime: dateFormat(new Date()),
  264 + endTime: dateFormat(new Date())
  265 + }
  266 + },
  267 +
  268 + handleClose() {
  269 + this.visible = false
  270 + this.resetForm()
  271 + }
  272 + }
  273 +}
  274 +</script>
  275 +
  276 +<style scoped>
  277 +.tip {
  278 + font-size: 12px;
  279 + color: #909399;
  280 +}
  281 +</style>
0 \ No newline at end of file 282 \ No newline at end of file
src/components/fee/addProxyFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('addProxyFeeDemo.openModal') }}</el-button>
  4 + <add-proxy-fee ref="addProxyFee" @success="handleSuccess"></add-proxy-fee>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import AddProxyFee from './addProxyFee'
  10 +
  11 +export default {
  12 + name: 'AddProxyFeeDemo',
  13 + components: {
  14 + AddProxyFee
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.addProxyFee.open({
  19 + roomId: '123',
  20 + roomName: '1-2-101',
  21 + ownerName: 'Test Owner'
  22 + })
  23 + },
  24 + handleSuccess() {
  25 + this.$message.success(this.$t('addProxyFeeDemo.successMessage'))
  26 + }
  27 + }
  28 +}
  29 +</script>
0 \ No newline at end of file 30 \ No newline at end of file
src/components/fee/batchFeeCycle.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="batchFeeCycleInfo.fee.feeName"
  4 + :visible.sync="visible"
  5 + width="500px"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form label-width="120px">
  9 + <el-form-item :label="$t('batchFeeCycle.paymentCycle')">
  10 + <el-select
  11 + v-model="batchFeeCycleInfo.tempCycle"
  12 + @change="changeTempCycle"
  13 + style="width:100%"
  14 + :placeholder="$t('batchFeeCycle.selectCycleTip')"
  15 + >
  16 + <el-option
  17 + value="-100"
  18 + :label="$t('batchFeeCycle.default')"
  19 + ></el-option>
  20 + <el-option
  21 + value="-102"
  22 + :label="$t('batchFeeCycle.customCycle')"
  23 + ></el-option>
  24 + <el-option
  25 + value="-101"
  26 + :label="$t('batchFeeCycle.customAmount')"
  27 + ></el-option>
  28 + <el-option
  29 + value="-103"
  30 + :label="$t('batchFeeCycle.customEndTime')"
  31 + ></el-option>
  32 + </el-select>
  33 + </el-form-item>
  34 +
  35 + <el-form-item
  36 + v-if="batchFeeCycleInfo.tempCycle === '-101'"
  37 + :label="$t('batchFeeCycle.customAmount')"
  38 + >
  39 + <el-input
  40 + type="number"
  41 + v-model="batchFeeCycleInfo.receivedAmount"
  42 + :placeholder="$t('batchFeeCycle.enterCustomAmount')"
  43 + ></el-input>
  44 + </el-form-item>
  45 +
  46 + <el-form-item
  47 + v-if="batchFeeCycleInfo.tempCycle === '-102'"
  48 + :label="$t('batchFeeCycle.actualCycle')"
  49 + >
  50 + <el-input
  51 + type="number"
  52 + v-model="batchFeeCycleInfo.cycles"
  53 + :placeholder="$t('batchFeeCycle.enterActualCycle')"
  54 + ></el-input>
  55 + </el-form-item>
  56 +
  57 + <el-form-item
  58 + v-if="batchFeeCycleInfo.tempCycle === '-103'"
  59 + :label="$t('batchFeeCycle.endTime')"
  60 + >
  61 + <el-date-picker
  62 + v-model="batchFeeCycleInfo.custEndTime"
  63 + type="date"
  64 + style="width:100%"
  65 + :placeholder="$t('batchFeeCycle.selectEndTime')"
  66 + value-format="yyyy-MM-dd"
  67 + ></el-date-picker>
  68 + </el-form-item>
  69 + </el-form>
  70 +
  71 + <span slot="footer" class="dialog-footer">
  72 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  73 + <el-button type="primary" @click="_doSubmitFeeCycle">{{ $t('common.confirm') }}</el-button>
  74 + </span>
  75 + </el-dialog>
  76 +</template>
  77 +
  78 +<script>
  79 +export default {
  80 + name: 'BatchFeeCycle',
  81 + data() {
  82 + return {
  83 + visible: false,
  84 + batchFeeCycleInfo: {
  85 + cycles: '',
  86 + tempCycle: '',
  87 + custEndTime: '',
  88 + receivedAmount: '',
  89 + fee: {}
  90 + }
  91 + }
  92 + },
  93 + methods: {
  94 + open(fee) {
  95 + this.batchFeeCycleInfo = {
  96 + cycles: fee.cycles,
  97 + tempCycle: fee.tempCycle,
  98 + receivedAmount: fee.receivedAmount,
  99 + fee: { ...fee }
  100 + }
  101 + this.visible = true
  102 + },
  103 +
  104 + handleClose() {
  105 + this.visible = false
  106 + },
  107 +
  108 + changeTempCycle() {
  109 + const tempCycle = this.batchFeeCycleInfo.tempCycle + ""
  110 + if (tempCycle !== '-100') {
  111 + this.batchFeeCycleInfo.cycles = "1"
  112 + }
  113 + },
  114 +
  115 + _doSubmitFeeCycle() {
  116 + const updatedFee = {
  117 + ...this.batchFeeCycleInfo.fee,
  118 + tempCycle: this.batchFeeCycleInfo.tempCycle,
  119 + cycles: this.batchFeeCycleInfo.cycles,
  120 + custEndTime: this.batchFeeCycleInfo.custEndTime,
  121 + receivedAmount: this.batchFeeCycleInfo.receivedAmount
  122 + }
  123 +
  124 + this.$emit('changeMonth', updatedFee)
  125 + this.handleClose()
  126 + }
  127 + }
  128 +}
  129 +</script>
  130 +
  131 +<style lang="scss" scoped>
  132 +::v-deep .el-dialog__body {
  133 + padding: 20px;
  134 +}
  135 +</style>
0 \ No newline at end of file 136 \ No newline at end of file
src/components/fee/batchPayConfirm.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-dialog :title="$t('batchPayConfirm.title')" :visible.sync="visible" width="600px" :before-close="handleClose">
  4 + <el-form label-width="120px">
  5 + <el-form-item :label="$t('batchPayConfirm.amount')">
  6 + <span>{{ batchPayConfirmInfo.feePrices }} {{ $t('batchPayConfirm.yuan') }}</span>
  7 + </el-form-item>
  8 + <el-form-item :label="$t('batchPayConfirm.accountAmount')">
  9 + <span>{{ batchPayConfirmInfo.accountAmount }} {{ $t('batchPayConfirm.yuan') }}</span>
  10 + </el-form-item>
  11 + <el-form-item :label="$t('batchPayConfirm.paymentMethod')">
  12 + <el-select v-model="batchPayConfirmInfo.primeRate" style="width:100%"
  13 + :placeholder="$t('batchPayConfirm.selectPaymentMethod')">
  14 + <el-option v-for="item in filteredPrimeRates" :key="item.statusCd" :label="item.name"
  15 + :value="item.statusCd"></el-option>
  16 + </el-select>
  17 + </el-form-item>
  18 + <el-form-item v-if="batchPayConfirmInfo.payType === 'qrCode'">
  19 + <el-input v-model="batchPayConfirmInfo.authCode" :placeholder="$t('batchPayConfirm.scanCodeTip')"
  20 + @keyup.enter.native="_qrCodePayFee"></el-input>
  21 + </el-form-item>
  22 + </el-form>
  23 + <span slot="footer" class="dialog-footer">
  24 + <el-button @click="handleClose">{{ $t('common.close') }}</el-button>
  25 + <el-button type="primary" @click="_doPayFee" v-if="batchPayConfirmInfo.payType === 'common'">{{
  26 + $t('batchPayConfirm.confirmPay') }}</el-button>
  27 + </span>
  28 + </el-dialog>
  29 +
  30 + <el-dialog :title="$t('batchPayConfirm.payResult')" :visible.sync="resultVisible" width="500px">
  31 + <div class="result-content">
  32 + <p>{{ $t('batchPayConfirm.paySuccess') }}</p>
  33 + </div>
  34 + <span slot="footer" class="dialog-footer">
  35 + <el-button @click="_back">{{ $t('common.back') }}</el-button>
  36 + <el-button type="primary" @click="_printAndBack('ON')">{{ $t('batchPayConfirm.mergePrint') }}</el-button>
  37 + <el-button type="primary" @click="_printAndBack('OFF')">{{ $t('batchPayConfirm.printReceipt') }}</el-button>
  38 + </span>
  39 + </el-dialog>
  40 + </div>
  41 +</template>
  42 +
  43 +<script>
  44 +import { getCommunityId, getDict } from '@/api/community/communityApi'
  45 +import { payBatchFee, qrCodePayment, checkPayFinish, listFeePrintPage } from '@/api/fee/batchPayFeeOrderApi'
  46 +
  47 +export default {
  48 + name: 'BatchPayConfirm',
  49 + data() {
  50 + return {
  51 + visible: false,
  52 + resultVisible: false,
  53 + batchPayConfirmInfo: {
  54 + payType: '',
  55 + fees: [],
  56 + primeRate: '',
  57 + primeRates: [],
  58 + payerObjName: '',
  59 + orderId: '',
  60 + paymentPoolId: '',
  61 + authCode: '',
  62 + feePrices: '',
  63 + detailIds: '',
  64 + printUrl: '/print.html#/pages/property/printPayFee',
  65 + accountAmount: '',
  66 + acctId: ''
  67 + }
  68 + }
  69 + },
  70 + computed: {
  71 + filteredPrimeRates() {
  72 + if (this.batchPayConfirmInfo.payType === 'qrCode') {
  73 + return this.batchPayConfirmInfo.primeRates.filter(
  74 + item => item.statusCd === '3' || item.statusCd === '4'
  75 + )
  76 + } else {
  77 + return this.batchPayConfirmInfo.primeRates.filter(
  78 + item => item.statusCd !== '5' && item.statusCd !== '6' && item.statusCd !== '8'
  79 + )
  80 + }
  81 + }
  82 + },
  83 + created() {
  84 + this._initDictData()
  85 + this._listFeePrintPages()
  86 + },
  87 + methods: {
  88 + async _initDictData() {
  89 + try {
  90 + const data = await getDict('pay_fee_detail', 'prime_rate')
  91 + this.batchPayConfirmInfo.primeRates = data
  92 + } catch (error) {
  93 + console.error('获取字典数据失败:', error)
  94 + }
  95 + },
  96 +
  97 + async _listFeePrintPages() {
  98 + try {
  99 + const params = {
  100 + page: 1,
  101 + row: 1,
  102 + state: 'T',
  103 + communityId: getCommunityId()
  104 + }
  105 + const res = await listFeePrintPage(params)
  106 + if (res.code === 0 && res.data && res.data.length > 0) {
  107 + this.batchPayConfirmInfo.printUrl = res.data[0].url
  108 + }
  109 + } catch (error) {
  110 + console.error('请求失败:', error)
  111 + }
  112 + },
  113 +
  114 + open(params) {
  115 + this.batchPayConfirmInfo = {
  116 + ...this.batchPayConfirmInfo,
  117 + ...params
  118 + }
  119 + this.visible = true
  120 +
  121 + if (params.payType === 'qrCode') {
  122 + this.$nextTick(() => {
  123 + document.getElementById("authCode").focus()
  124 + })
  125 + }
  126 + },
  127 +
  128 + handleClose() {
  129 + this.visible = false
  130 + },
  131 +
  132 + async _doPayFee() {
  133 + if (!this.batchPayConfirmInfo.primeRate) {
  134 + this.$message.warning(this.$t('batchPayConfirm.selectPaymentMethodTip'))
  135 + return
  136 + }
  137 +
  138 + const fees = this.batchPayConfirmInfo.fees.map(fee => ({
  139 + ...fee,
  140 + primeRate: this.batchPayConfirmInfo.primeRate
  141 + }))
  142 +
  143 + try {
  144 + const data = {
  145 + communityId: getCommunityId(),
  146 + fees,
  147 + acctId: this.batchPayConfirmInfo.acctId,
  148 + accountAmount: this.batchPayConfirmInfo.accountAmount
  149 + }
  150 +
  151 + const res = await payBatchFee(data)
  152 + if (res.code === 0) {
  153 + this._doDealPayResult(res)
  154 + } else {
  155 + this.$message.error(res.msg)
  156 + }
  157 + } catch (error) {
  158 + console.error('请求失败:', error)
  159 + this.handleClose()
  160 + this.$message.error('缴费失败')
  161 + }
  162 + },
  163 +
  164 + async _qrCodePayFee() {
  165 + if (!this.batchPayConfirmInfo.primeRate) {
  166 + this.$message.warning(this.$t('batchPayConfirm.selectPaymentMethodTip'))
  167 + return
  168 + }
  169 +
  170 + const fees = this.batchPayConfirmInfo.fees.map(fee => ({
  171 + ...fee,
  172 + primeRate: this.batchPayConfirmInfo.primeRate
  173 + }))
  174 +
  175 + try {
  176 + const data = {
  177 + communityId: getCommunityId(),
  178 + fees,
  179 + acctId: this.batchPayConfirmInfo.acctId,
  180 + accountAmount: this.batchPayConfirmInfo.accountAmount,
  181 + authCode: this.batchPayConfirmInfo.authCode,
  182 + receivedAmount: this.batchPayConfirmInfo.feePrices,
  183 + payerObjName: this.batchPayConfirmInfo.payerObjName,
  184 + subServiceCode: 'fee.payBatchFee'
  185 + }
  186 +
  187 + const res = await qrCodePayment(data)
  188 + if (res.code === 404) {
  189 + this.$message.warning(res.msg)
  190 + if (res.data && res.data.orderId) {
  191 + this.batchPayConfirmInfo.orderId = res.data.orderId
  192 + this.batchPayConfirmInfo.paymentPoolId = res.data.paymentPoolId
  193 + setTimeout(() => this._qrCodeCheckPayFinish(), 5000)
  194 + }
  195 + } else if (res.code === 0) {
  196 + this._doDealPayResult(res)
  197 + } else {
  198 + this.$message.error(res.msg)
  199 + }
  200 + } catch (error) {
  201 + console.error('请求失败:', error)
  202 + this.$message.error('扫码支付失败')
  203 + }
  204 + },
  205 +
  206 + async _qrCodeCheckPayFinish() {
  207 + const fees = this.batchPayConfirmInfo.fees.map(fee => ({
  208 + ...fee,
  209 + primeRate: this.batchPayConfirmInfo.primeRate
  210 + }))
  211 +
  212 + try {
  213 + const data = {
  214 + communityId: getCommunityId(),
  215 + fees,
  216 + acctId: this.batchPayConfirmInfo.acctId,
  217 + accountAmount: this.batchPayConfirmInfo.accountAmount,
  218 + authCode: this.batchPayConfirmInfo.authCode,
  219 + receivedAmount: this.batchPayConfirmInfo.feePrices,
  220 + subServiceCode: 'fee.payBatchFee',
  221 + orderId: this.batchPayConfirmInfo.orderId,
  222 + paymentPoolId: this.batchPayConfirmInfo.paymentPoolId
  223 + }
  224 +
  225 + const res = await checkPayFinish(data)
  226 + if (res.code === 404) {
  227 + this.$message.warning(res.msg)
  228 + } else if (res.code === 41) {
  229 + setTimeout(() => this._qrCodeCheckPayFinish(), 5000)
  230 + } else {
  231 + this._doDealPayResult(res)
  232 + }
  233 + } catch (error) {
  234 + console.error('请求失败:', error)
  235 + this.$message.error('支付状态查询失败')
  236 + }
  237 + },
  238 +
  239 + _doDealPayResult(res) {
  240 + this.handleClose()
  241 + const detailIds = res.data.details.join(',')
  242 + this.batchPayConfirmInfo.detailIds = detailIds
  243 +
  244 + setTimeout(() => {
  245 + this.resultVisible = true
  246 + }, 2000)
  247 + },
  248 +
  249 + _printAndBack(merge) {
  250 + this.resultVisible = false
  251 + window.open(`${this.batchPayConfirmInfo.printUrl}?detailIds=${this.batchPayConfirmInfo.detailIds}&merge=${merge}`)
  252 + },
  253 +
  254 + _back() {
  255 + this.resultVisible = false
  256 + this.$router.go(-1)
  257 + }
  258 + }
  259 +}
  260 +</script>
  261 +
  262 +<style lang="scss" scoped>
  263 +.result-content {
  264 + text-align: center;
  265 + font-size: 16px;
  266 + padding: 20px;
  267 +}
  268 +</style>
0 \ No newline at end of file 269 \ No newline at end of file
src/components/fee/carDetailOwner.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row>
  4 + <el-col :span="24" class="text-right"></el-col>
  5 + </el-row>
  6 + <div class="margin-top">
  7 + <el-table :data="carDetailOwnerInfo.owners" border stripe>
  8 + <el-table-column :label="$t('carDetailOwner.ownerFace')" align="center">
  9 + <template slot-scope="scope">
  10 + <el-image
  11 + style="width: 60px; height: 60px; border-radius: 4px;"
  12 + :src="scope.row.url || '/img/noPhoto.jpg'"
  13 + :preview-src-list="[scope.row.url]"
  14 + v-if="scope.row.url"
  15 + ></el-image>
  16 + <el-image
  17 + style="width: 60px; height: 60px; border-radius: 4px;"
  18 + src="/img/noPhoto.jpg"
  19 + v-else
  20 + ></el-image>
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column :label="$t('carDetailOwner.name')" align="center">
  24 + <template slot-scope="scope">
  25 + {{scope.row.name}}({{scope.row.link}})
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column :label="$t('carDetailOwner.gender')" align="center">
  29 + <template slot-scope="scope">
  30 + {{scope.row.sex == 0 ? $t('carDetailOwner.male') : $t('carDetailOwner.female')}}
  31 + </template>
  32 + </el-table-column>
  33 + <el-table-column prop="idCard" :label="$t('carDetailOwner.idCard')" align="center">
  34 + <template slot-scope="scope">
  35 + {{scope.row.idCard || '-'}}
  36 + </template>
  37 + </el-table-column>
  38 + <el-table-column prop="address" :label="$t('carDetailOwner.address')" align="center">
  39 + <template slot-scope="scope">
  40 + {{scope.row.address || '-'}}
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column prop="roomCount" :label="$t('carDetailOwner.roomCount')" align="center">
  44 + <template slot-scope="scope">
  45 + {{scope.row.roomCount || 0}}
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column prop="memberCount" :label="$t('carDetailOwner.memberCount')" align="center">
  49 + <template slot-scope="scope">
  50 + {{scope.row.memberCount || 0}}
  51 + </template>
  52 + </el-table-column>
  53 + <el-table-column prop="carCount" :label="$t('carDetailOwner.carCount')" align="center">
  54 + <template slot-scope="scope">
  55 + {{scope.row.carCount || 0}}
  56 + </template>
  57 + </el-table-column>
  58 + <el-table-column prop="complaintCount" :label="$t('carDetailOwner.complaintCount')" align="center">
  59 + <template slot-scope="scope">
  60 + {{scope.row.complaintCount || 0}}
  61 + </template>
  62 + </el-table-column>
  63 + <el-table-column prop="repairCount" :label="$t('carDetailOwner.repairCount')" align="center">
  64 + <template slot-scope="scope">
  65 + {{scope.row.repairCount || 0}}
  66 + </template>
  67 + </el-table-column>
  68 + <el-table-column prop="oweFee" :label="$t('carDetailOwner.oweFee')" align="center">
  69 + <template slot-scope="scope">
  70 + {{scope.row.oweFee || '0.00'}}
  71 + </template>
  72 + </el-table-column>
  73 + <el-table-column prop="contractCount" :label="$t('carDetailOwner.contractCount')" align="center">
  74 + <template slot-scope="scope">
  75 + {{scope.row.contractCount || 0}}
  76 + </template>
  77 + </el-table-column>
  78 + <el-table-column :label="$t('carDetailOwner.actions')" align="center">
  79 + <template slot-scope="scope">
  80 + <el-button-group>
  81 + <el-button size="mini" @click="_toCarDetailOwnerDetail(scope.row)">
  82 + {{ $t('carDetailOwner.detail') }}
  83 + </el-button>
  84 + </el-button-group>
  85 + </template>
  86 + </el-table-column>
  87 + </el-table>
  88 + <el-pagination
  89 + @current-change="handleCurrentChange"
  90 + :current-page="currentPage"
  91 + :page-size="pageSize"
  92 + layout="total, prev, pager, next"
  93 + :total="total">
  94 + </el-pagination>
  95 + </div>
  96 + </div>
  97 +</template>
  98 +
  99 +<script>
  100 +import { getCommunityId } from '@/api/community/communityApi'
  101 +import { queryOwners } from '@/api/fee/carDetailOwnerApi'
  102 +
  103 +export default {
  104 + name: 'CarDetailOwner',
  105 + data() {
  106 + return {
  107 + DEFAULT_PAGE: 1,
  108 + DEFAULT_ROWS: 10,
  109 + carDetailOwnerInfo: {
  110 + owners: [],
  111 + ownerId: ''
  112 + },
  113 + currentPage: 1,
  114 + pageSize: 10,
  115 + total: 0
  116 + }
  117 + },
  118 + created() {
  119 + this._initEvent()
  120 + },
  121 + methods: {
  122 + _initEvent() {
  123 + this.$on('switch', this.handleSwitch)
  124 + this.$on('notify', this._loadCarDetailOwnerData)
  125 + },
  126 + handleSwitch(data) {
  127 + this.carDetailOwnerInfo.ownerId = data.ownerId
  128 + this._loadCarDetailOwnerData(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  129 + },
  130 + handleCurrentChange(val) {
  131 + this._loadCarDetailOwnerData(val, this.DEFAULT_ROWS)
  132 + },
  133 + async _loadCarDetailOwnerData(page, row) {
  134 + try {
  135 + const res = await queryOwners({
  136 + ownerId: this.carDetailOwnerInfo.ownerId,
  137 + communityId: getCommunityId(),
  138 + ownerTypeCd: '1001',
  139 + page,
  140 + row
  141 + })
  142 + this.carDetailOwnerInfo.owners = res.data
  143 + this.total = res.records
  144 + } catch (error) {
  145 + console.error('Request failed:', error)
  146 + }
  147 + },
  148 + _toCarDetailOwnerDetail(owner) {
  149 + window.open(`/#/pages/owner/ownerDetail?ownerId=${owner.ownerId}`)
  150 + },
  151 + open(params) {
  152 + this.handleSwitch(params)
  153 + }
  154 + }
  155 +}
  156 +</script>
  157 +
  158 +<style scoped>
  159 +.margin-top {
  160 + margin-top: 15px;
  161 +}
  162 +.text-right {
  163 + text-align: right;
  164 +}
  165 +</style>
0 \ No newline at end of file 166 \ No newline at end of file
src/components/fee/carDetailOwnerDemo.vue 0 → 100644
  1 +<template>
  2 + <car-detail-owner ref="carDetailOwner"></car-detail-owner>
  3 +</template>
  4 +
  5 +<script>
  6 +import CarDetailOwner from './carDetailOwner'
  7 +
  8 +export default {
  9 + name: 'CarDetailOwnerDemo',
  10 + components: {
  11 + CarDetailOwner
  12 + },
  13 + mounted() {
  14 + this.$refs.carDetailOwner.$emit('switch', {
  15 + ownerId: '123'
  16 + })
  17 + }
  18 +}
  19 +</script>
0 \ No newline at end of file 20 \ No newline at end of file
src/components/fee/deleteApplyRoomDiscount.vue
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
26 26
27 <script> 27 <script>
28 import { deleteApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi' 28 import { deleteApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi'
  29 +import { getCommunityId } from '@/api/community/communityApi'
29 30
30 export default { 31 export default {
31 name: 'DeleteApplyRoomDiscount', 32 name: 'DeleteApplyRoomDiscount',
@@ -43,7 +44,7 @@ export default { @@ -43,7 +44,7 @@ export default {
43 open(data) { 44 open(data) {
44 this.form = { 45 this.form = {
45 ardId: data.ardId, 46 ardId: data.ardId,
46 - communityId: this.$store.getters.communityId 47 + communityId: getCommunityId()
47 } 48 }
48 this.visible = true 49 this.visible = true
49 }, 50 },
src/components/fee/deleteFee.vue
1 <template> 1 <template>
2 - <el-dialog :title="$t('deleteFee.title')" :visible.sync="visible" width="30%">  
3 - <div>  
4 - <p>{{ $t('deleteFee.confirmDelete') }}</p>  
5 - </div> 2 + <el-dialog
  3 + :title="$t('deleteFee.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + :before-close="handleClose"
  7 + >
  8 + <p>{{ $t('deleteFee.confirmMessage') }}</p>
6 <span slot="footer" class="dialog-footer"> 9 <span slot="footer" class="dialog-footer">
7 - <el-button @click="close">{{ $t('common.cancel') }}</el-button> 10 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
8 <el-button type="primary" @click="deleteFee">{{ $t('common.confirm') }}</el-button> 11 <el-button type="primary" @click="deleteFee">{{ $t('common.confirm') }}</el-button>
9 </span> 12 </span>
10 </el-dialog> 13 </el-dialog>
11 </template> 14 </template>
12 15
13 <script> 16 <script>
14 -import { deleteFee } from '@/api/fee/listCarFeeApi' 17 +import { deleteFee } from '@/api/fee/deleteFeeApi'
  18 +import { getCommunityId } from '@/api/community/communityApi'
15 19
16 export default { 20 export default {
17 name: 'DeleteFee', 21 name: 'DeleteFee',
@@ -22,25 +26,29 @@ export default { @@ -22,25 +26,29 @@ export default {
22 } 26 }
23 }, 27 },
24 methods: { 28 methods: {
25 - open(info) {  
26 - this.deleteFeeInfo = info 29 + open(params) {
  30 + this.deleteFeeInfo = params
27 this.visible = true 31 this.visible = true
28 }, 32 },
29 - close() { 33 + handleClose() {
30 this.visible = false 34 this.visible = false
31 }, 35 },
32 - deleteFee() {  
33 - deleteFee(this.deleteFeeInfo).then(response => {  
34 - if (response.code === 0) {  
35 - this.$message.success(this.$t('common.deleteSuccess')) 36 + async deleteFee() {
  37 + this.deleteFeeInfo.communityId = getCommunityId()
  38 +
  39 + try {
  40 + const res = await deleteFee(this.deleteFeeInfo)
  41 + if (res.code === 0) {
  42 + this.$message.success(this.$t('common.operateSuccess'))
36 this.$emit('success') 43 this.$emit('success')
37 - this.close() 44 + this.handleClose()
38 } else { 45 } else {
39 - this.$message.error(response.msg) 46 + this.$message.error(res.msg)
40 } 47 }
41 - }).catch(error => {  
42 - this.$message.error(error.message)  
43 - }) 48 + } catch (error) {
  49 + console.error('请求失败:', error)
  50 + this.$message.error(this.$t('common.operateFail'))
  51 + }
44 } 52 }
45 } 53 }
46 } 54 }
src/components/fee/deleteFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('deleteFeeDemo.openModal') }}</el-button>
  4 + <delete-fee ref="deleteFee" @success="handleSuccess"></delete-fee>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import DeleteFee from './deleteFee'
  10 +
  11 +export default {
  12 + name: 'DeleteFeeDemo',
  13 + components: {
  14 + DeleteFee
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.deleteFee.open({
  19 + feeId: '123'
  20 + })
  21 + },
  22 + handleSuccess() {
  23 + this.$message.success(this.$t('deleteFeeDemo.successMessage'))
  24 + }
  25 + }
  26 +}
  27 +</script>
0 \ No newline at end of file 28 \ No newline at end of file
src/components/fee/deleteFeeRule.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('deleteFeeRule.confirmTitle')"
  4 + :visible.sync="dialogVisible"
  5 + width="30%"
  6 + >
  7 + <div class="text-center">
  8 + <p>{{ $t('deleteFeeRule.confirmMessage') }}</p>
  9 + </div>
  10 + <span slot="footer" class="dialog-footer">
  11 + <el-button @click="closeDeleteFeeRuleModel">{{ $t('deleteFeeRule.cancel') }}</el-button>
  12 + <el-button type="primary" @click="deleteFeeRule">{{ $t('deleteFeeRule.confirmDelete') }}</el-button>
  13 + </span>
  14 + </el-dialog>
  15 +</template>
  16 +
  17 +<script>
  18 +import { deletePayFeeRule } from '@/api/fee/deleteFeeRuleApi'
  19 +import { getCommunityId } from '@/api/community/communityApi'
  20 +
  21 +export default {
  22 + name: 'DeleteFeeRule',
  23 + data() {
  24 + return {
  25 + dialogVisible: false,
  26 + deleteFeeRuleInfo: {},
  27 + communityId: ''
  28 + }
  29 + },
  30 + created() {
  31 + this.communityId = getCommunityId()
  32 + },
  33 + methods: {
  34 + open(params) {
  35 + this.deleteFeeRuleInfo = params
  36 + this.dialogVisible = true
  37 + },
  38 + deleteFeeRule() {
  39 + const params = {
  40 + ...this.deleteFeeRuleInfo,
  41 + communityId: this.communityId
  42 + }
  43 +
  44 + deletePayFeeRule(params).then(response => {
  45 + if (response.code === 0) {
  46 + this.dialogVisible = false
  47 + this.$emit('delete-success')
  48 + this.$message.success(this.$t('deleteFeeRule.deleteSuccess'))
  49 + } else {
  50 + this.$message.error(response.msg)
  51 + }
  52 + }).catch(error => {
  53 + console.error('请求失败:', error)
  54 + this.$message.error(this.$t('deleteFeeRule.deleteFailed'))
  55 + })
  56 + },
  57 + closeDeleteFeeRuleModel() {
  58 + this.dialogVisible = false
  59 + }
  60 + }
  61 +}
  62 +</script>
  63 +
  64 +<style scoped>
  65 +.text-center {
  66 + text-align: center;
  67 +}
  68 +</style>
0 \ No newline at end of file 69 \ No newline at end of file
src/components/fee/deleteFeeRuleDemo.vue 0 → 100644
  1 +<template>
  2 + <el-button @click="openModal">{{ $t('deleteFeeRuleDemo.openModal') }}</el-button>
  3 + <delete-fee-rule ref="deleteFeeRule" @delete-success="handleDeleteSuccess"></delete-fee-rule>
  4 +</template>
  5 +
  6 +<script>
  7 +import DeleteFeeRule from './deleteFeeRule'
  8 +
  9 +export default {
  10 + name: 'DeleteFeeRuleDemo',
  11 + components: {
  12 + DeleteFeeRule
  13 + },
  14 + methods: {
  15 + openModal() {
  16 + this.$refs.deleteFeeRule.open({
  17 + feeRuleId: '123'
  18 + })
  19 + },
  20 + handleDeleteSuccess() {
  21 + console.log('Delete success')
  22 + }
  23 + }
  24 +}
  25 +</script>
0 \ No newline at end of file 26 \ No newline at end of file
src/components/fee/deleteOweFeeCallable.vue
1 <template> 1 <template>
2 <el-dialog 2 <el-dialog
3 - :title="$t('oweFeeCallable.delete.title')" 3 + :title="$t('deleteOweFeeCallable.title')"
4 :visible.sync="dialogVisible" 4 :visible.sync="dialogVisible"
5 width="30%" 5 width="30%"
6 - @close="handleClose">  
7 - <div class="delete-content">  
8 - <p>{{ $t('oweFeeCallable.delete.confirm') }}</p> 6 + :before-close="handleClose"
  7 + >
  8 + <div align="center">
  9 + <h4>{{ $t('deleteOweFeeCallable.confirmDelete') }}</h4>
9 </div> 10 </div>
10 <span slot="footer" class="dialog-footer"> 11 <span slot="footer" class="dialog-footer">
11 - <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>  
12 - <el-button type="primary" @click="handleConfirm">{{ $t('common.confirm') }}</el-button> 12 + <el-button @click="closeDeleteOweFeeCallableModel">{{ $t('deleteOweFeeCallable.cancel') }}</el-button>
  13 + <el-button type="primary" @click="deleteOweFeeCallable">{{ $t('deleteOweFeeCallable.confirm') }}</el-button>
13 </span> 14 </span>
14 </el-dialog> 15 </el-dialog>
15 </template> 16 </template>
16 17
17 <script> 18 <script>
18 -import { deleteOweFeeCallable } from '@/api/fee/oweFeeCallableApi'  
19 import { getCommunityId } from '@/api/community/communityApi' 19 import { getCommunityId } from '@/api/community/communityApi'
  20 +import { deleteOweFeeCallable } from '@/api/fee/deleteOweFeeCallableApi'
20 21
21 export default { 22 export default {
22 name: 'DeleteOweFeeCallable', 23 name: 'DeleteOweFeeCallable',
23 data() { 24 data() {
24 return { 25 return {
25 dialogVisible: false, 26 dialogVisible: false,
26 - currentItem: null 27 + deleteOweFeeCallableInfo: {}
27 } 28 }
28 }, 29 },
  30 + created() {
  31 + this._initEvent()
  32 + },
29 methods: { 33 methods: {
30 - open(item) {  
31 - this.currentItem = {  
32 - ...item,  
33 - communityId: getCommunityId()  
34 - } 34 + _initEvent() {
  35 + this.$on('openDeleteOweFeeCallableModal', this.open)
  36 + },
  37 + open(params) {
  38 + this.deleteOweFeeCallableInfo = params
35 this.dialogVisible = true 39 this.dialogVisible = true
36 }, 40 },
37 - async handleConfirm() { 41 + handleClose(done) {
  42 + this.closeDeleteOweFeeCallableModel()
  43 + done()
  44 + },
  45 + async deleteOweFeeCallable() {
38 try { 46 try {
39 - await deleteOweFeeCallable(this.currentItem)  
40 - this.$message.success(this.$t('oweFeeCallable.delete.success'))  
41 - this.dialogVisible = false  
42 - this.$emit('success') 47 + const params = {
  48 + ...this.deleteOweFeeCallableInfo,
  49 + communityId: getCommunityId()
  50 + }
  51 + const res = await deleteOweFeeCallable(params)
  52 + if (res.code === 0) {
  53 + this.dialogVisible = false
  54 + this.$emit('listOweFeeCallable', {})
  55 + this.$emit('listOwnerData', {})
  56 + this.$message.success(this.$t('deleteOweFeeCallable.success'))
  57 + } else {
  58 + this.$message.error(res.msg)
  59 + }
43 } catch (error) { 60 } catch (error) {
44 - console.error('删除失败:', error)  
45 - this.$message.error(error.message || this.$t('oweFeeCallable.delete.error')) 61 + console.error('Request failed:', error)
  62 + this.$message.error(error.message)
46 } 63 }
47 }, 64 },
48 - handleClose() {  
49 - this.currentItem = null 65 + closeDeleteOweFeeCallableModel() {
  66 + this.dialogVisible = false
50 } 67 }
51 } 68 }
52 } 69 }
53 -</script>  
54 -  
55 -<style lang="scss" scoped>  
56 -.delete-content {  
57 - text-align: center;  
58 - font-size: 16px;  
59 - padding: 20px 0;  
60 -}  
61 -</style>  
62 \ No newline at end of file 70 \ No newline at end of file
  71 +</script>
63 \ No newline at end of file 72 \ No newline at end of file
src/components/fee/deleteOweFeeCallableDemo.vue 0 → 100644
  1 +<template>
  2 + <el-button @click="openModal">{{$t('deleteOweFeeCallableDemo.openModal')}}</el-button>
  3 + <delete-owe-fee-callable ref="deleteOweFeeCallable"></delete-owe-fee-callable>
  4 +</template>
  5 +
  6 +<script>
  7 +import DeleteOweFeeCallable from './deleteOweFeeCallable'
  8 +
  9 +export default {
  10 + name: 'DeleteOweFeeCallableDemo',
  11 + components: {
  12 + DeleteOweFeeCallable
  13 + },
  14 + methods: {
  15 + openModal() {
  16 + this.$refs.deleteOweFeeCallable.open({
  17 + ofcId: '123'
  18 + })
  19 + }
  20 + }
  21 +}
  22 +</script>
0 \ No newline at end of file 23 \ No newline at end of file
src/components/fee/doImportCreateFee.vue
1 <template> 1 <template>
2 - <el-dialog  
3 - :title="$t('doImportCreateFee.customCreateFee')"  
4 - :visible.sync="visible"  
5 - width="50%" 2 + <el-dialog
  3 + :title="$t('doImportCreateFee.title')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + :before-close="handleClose"
6 > 7 >
7 - <el-form label-width="150px"> 8 + <el-form label-width="120px">
8 <el-form-item :label="$t('doImportCreateFee.selectFile')"> 9 <el-form-item :label="$t('doImportCreateFee.selectFile')">
9 <el-upload 10 <el-upload
10 class="upload-demo" 11 class="upload-demo"
11 - :before-upload="beforeUpload" 12 + action=""
  13 + :auto-upload="false"
  14 + :on-change="handleFileChange"
12 :show-file-list="false" 15 :show-file-list="false"
  16 + accept=".xls,.xlsx"
13 > 17 >
14 - <el-button size="small" type="primary">  
15 - <i class="el-icon-upload"></i>  
16 - {{ $t('common.selectFile') }}  
17 - </el-button>  
18 - <div slot="tip" class="el-upload__tip" style="margin-top:10px">  
19 - {{ fileName || $t('doImportCreateFee.requiredFile') }} 18 + <el-button size="small" type="primary">{{ $t('doImportCreateFee.clickUpload') }}</el-button>
  19 + <div slot="tip" class="el-upload__tip">
  20 + {{ fileName || $t('doImportCreateFee.fileTip') }}
20 </div> 21 </div>
21 </el-upload> 22 </el-upload>
22 </el-form-item> 23 </el-form-item>
23 </el-form> 24 </el-form>
24 -  
25 - <div slot="footer" class="dialog-footer">  
26 - <el-button @click="visible = false">{{ $t('doImportCreateFee.cancel') }}</el-button>  
27 - <el-button type="primary" @click="handleImport" :disabled="!file">  
28 - {{ $t('doImportCreateFee.import') }}  
29 - </el-button>  
30 - </div> 25 +
  26 + <span slot="footer" class="dialog-footer">
  27 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  28 + <el-button
  29 + type="primary"
  30 + @click="handleImport"
  31 + :disabled="!fileName"
  32 + >{{ $t('common.import') }}</el-button>
  33 + </span>
31 </el-dialog> 34 </el-dialog>
32 </template> 35 </template>
33 36
34 <script> 37 <script>
35 -import { importCustomFee } from '@/api/fee/carCreateFeeApi' 38 +import { importData } from '@/api/fee/doImportCreateFeeApi'
  39 +import { getCommunityId } from '@/api/community/communityApi'
36 40
37 export default { 41 export default {
38 name: 'DoImportCreateFee', 42 name: 'DoImportCreateFee',
@@ -43,52 +47,69 @@ export default { @@ -43,52 +47,69 @@ export default {
43 fileName: '' 47 fileName: ''
44 } 48 }
45 }, 49 },
  50 + computed: {
  51 + communityId() {
  52 + return getCommunityId()
  53 + }
  54 + },
46 methods: { 55 methods: {
47 open() { 56 open() {
48 this.visible = true 57 this.visible = true
49 - this.file = null  
50 - this.fileName = '' 58 + this.reset()
51 }, 59 },
52 - beforeUpload(file) {  
53 - const validTypes = ['xlsx', 'xls']  
54 - const fileType = file.name.split('.').pop().toLowerCase()  
55 - const isExcel = validTypes.includes(fileType)  
56 - const isLt2M = file.size / 1024 / 1024 < 2  
57 -  
58 - if (!isExcel) {  
59 - this.$message.error(this.$t('common.invalidExcelType')) 60 +
  61 + handleFileChange(file) {
  62 + if (!this.checkFileType(file.name)) {
  63 + this.$message.error(this.$t('doImportCreateFee.validate.invalidFileType'))
60 return false 64 return false
61 } 65 }
62 - if (!isLt2M) {  
63 - this.$message.error(this.$t('common.fileSizeExceed')) 66 +
  67 + if (!this.checkFileSize(file.size)) {
  68 + this.$message.error(this.$t('doImportCreateFee.validate.fileTooLarge'))
64 return false 69 return false
65 } 70 }
66 71
67 - this.file = file 72 + this.file = file.raw
68 this.fileName = file.name 73 this.fileName = file.name
69 - return false // 阻止自动上传  
70 }, 74 },
71 - async handleImport() {  
72 - if (!this.file) {  
73 - this.$message.warning(this.$t('doImportCreateFee.requiredFile'))  
74 - return  
75 - } 75 +
  76 + checkFileType(filename) {
  77 + const ext = filename.split('.').pop().toLowerCase()
  78 + return ['xls', 'xlsx'].includes(ext)
  79 + },
  80 +
  81 + checkFileSize(size) {
  82 + return size <= 2 * 1024 * 1024 // 2MB
  83 + },
  84 +
  85 + handleImport() {
  86 + const formData = new FormData()
  87 + formData.append('uploadFile', this.file)
  88 + formData.append('communityId', this.communityId)
  89 + formData.append('importAdapt', 'importCustomFee')
76 90
77 - try {  
78 - const res = await importCustomFee({  
79 - file: this.file  
80 - })  
81 - 91 + importData(formData).then(response => {
  92 + const res = response.data
82 if (res.code === 0) { 93 if (res.code === 0) {
83 - this.$message.success(this.$t('common.importSuccess'))  
84 - this.visible = false  
85 - this.$emit('success') 94 + this.$message.success(this.$t('doImportCreateFee.successMessage'))
  95 + this.handleClose()
  96 + this.$router.push(`/pages/property/assetImportLogDetail?logId=${res.data.logId}&logType=importCustomFee`)
86 } else { 97 } else {
87 - this.$message.error(res.msg || this.$t('common.importError')) 98 + this.$message.error(res.msg)
88 } 99 }
89 - } catch (error) {  
90 - this.$message.error(this.$t('common.importError'))  
91 - } 100 + }).catch(error => {
  101 + this.$message.error(error.message)
  102 + })
  103 + },
  104 +
  105 + handleClose() {
  106 + this.visible = false
  107 + this.reset()
  108 + },
  109 +
  110 + reset() {
  111 + this.file = null
  112 + this.fileName = ''
92 } 113 }
93 } 114 }
94 } 115 }
src/components/fee/doImportCreateFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('doImportCreateFeeDemo.openModal') }}</el-button>
  4 + <do-import-create-fee ref="doImportCreateFee"></do-import-create-fee>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import DoImportCreateFee from './doImportCreateFee'
  10 +
  11 +export default {
  12 + name: 'DoImportCreateFeeDemo',
  13 + components: {
  14 + DoImportCreateFee
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.doImportCreateFee.open()
  19 + }
  20 + }
  21 +}
  22 +</script>
0 \ No newline at end of file 23 \ No newline at end of file
src/components/fee/downloadCollectionLetterOrder.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('downloadCollectionLetterOrder.title')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form label-width="120px">
  9 + <template v-if="roomId">
  10 + <el-alert
  11 + :title="$t('downloadCollectionLetterOrder.confirmExport')"
  12 + type="info"
  13 + show-icon
  14 + ></el-alert>
  15 + </template>
  16 + <template v-else>
  17 + <el-form-item :label="$t('downloadCollectionLetterOrder.selectFloor')">
  18 + <el-select
  19 + v-model="floorId"
  20 + :placeholder="$t('downloadCollectionLetterOrder.floorPlaceholder')"
  21 + style="width: 100%"
  22 + >
  23 + <el-option
  24 + v-for="item in floors"
  25 + :key="item.floorId"
  26 + :label="item.floorNum"
  27 + :value="item.floorId"
  28 + ></el-option>
  29 + </el-select>
  30 + </el-form-item>
  31 + </template>
  32 + </el-form>
  33 +
  34 + <span slot="footer" class="dialog-footer">
  35 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  36 + <el-button
  37 + type="primary"
  38 + @click="handleExport"
  39 + :disabled="!floorId && !roomId"
  40 + >{{ $t('common.export') }}</el-button>
  41 + </span>
  42 + </el-dialog>
  43 +</template>
  44 +
  45 +<script>
  46 +import { exportData, queryFloors } from '@/api/fee/downloadCollectionLetterOrderApi'
  47 +import { getCommunityId } from '@/api/community/communityApi'
  48 +
  49 +export default {
  50 + name: 'DownloadCollectionLetterOrder',
  51 + data() {
  52 + return {
  53 + visible: false,
  54 + roomId: '',
  55 + floorId: '',
  56 + floors: []
  57 + }
  58 + },
  59 + computed: {
  60 + communityId() {
  61 + return getCommunityId()
  62 + }
  63 + },
  64 + methods: {
  65 + open(params) {
  66 + this.visible = true
  67 + this.roomId = params.roomId || ''
  68 + this.loadFloors()
  69 + },
  70 +
  71 + loadFloors() {
  72 + queryFloors({
  73 + page: 1,
  74 + row: 100,
  75 + communityId: this.communityId
  76 + }).then(response => {
  77 + this.floors = response.data.apiFloorDataVoList
  78 + })
  79 + },
  80 +
  81 + handleExport() {
  82 + const params = {
  83 + communityId: this.communityId,
  84 + pagePath: 'dataFeeManualCollection',
  85 + floorId: this.floorId,
  86 + roomId: this.roomId
  87 + }
  88 +
  89 + exportData(params).then(response => {
  90 + const res = response.data
  91 + this.$message.success(res.msg)
  92 + if (res.code === 0) {
  93 + this.handleClose()
  94 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  95 + }
  96 + }).catch(error => {
  97 + this.$message.error(error.message)
  98 + })
  99 + },
  100 +
  101 + handleClose() {
  102 + this.visible = false
  103 + this.reset()
  104 + },
  105 +
  106 + reset() {
  107 + this.roomId = ''
  108 + this.floorId = ''
  109 + }
  110 + }
  111 +}
  112 +</script>
0 \ No newline at end of file 113 \ No newline at end of file
src/components/fee/downloadCollectionLetterOrderDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('downloadCollectionLetterOrderDemo.openModal') }}</el-button>
  4 + <download-collection-letter-order ref="downloadCollectionLetterOrder"></download-collection-letter-order>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import DownloadCollectionLetterOrder from './downloadCollectionLetterOrder'
  10 +
  11 +export default {
  12 + name: 'DownloadCollectionLetterOrderDemo',
  13 + components: {
  14 + DownloadCollectionLetterOrder
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.downloadCollectionLetterOrder.open({
  19 + roomId: '123' // Optional, remove if you want to select floor
  20 + })
  21 + }
  22 + }
  23 +}
  24 +</script>
0 \ No newline at end of file 25 \ No newline at end of file
src/components/fee/editApplyRoomDiscount.vue
@@ -48,6 +48,7 @@ @@ -48,6 +48,7 @@
48 <script> 48 <script>
49 import { updateApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi' 49 import { updateApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi'
50 import UploadImageUrl from '@/components/upload/UploadImageUrl' 50 import UploadImageUrl from '@/components/upload/UploadImageUrl'
  51 +import { getCommunityId } from '@/api/community/communityApi'
51 52
52 export default { 53 export default {
53 name: 'EditApplyRoomDiscount', 54 name: 'EditApplyRoomDiscount',
@@ -90,7 +91,7 @@ export default { @@ -90,7 +91,7 @@ export default {
90 this.form = { 91 this.form = {
91 ...this.form, 92 ...this.form,
92 ...data, 93 ...data,
93 - communityId: this.$store.getters.communityId 94 + communityId: getCommunityId()
94 } 95 }
95 this.$nextTick(() => { 96 this.$nextTick(() => {
96 if (this.$refs.uploadImage) { 97 if (this.$refs.uploadImage) {
src/components/fee/editApplyRoomDiscountRecord.vue
@@ -113,6 +113,7 @@ @@ -113,6 +113,7 @@
113 113
114 <script> 114 <script>
115 import { updateApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi' 115 import { updateApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi'
  116 +import { getCommunityId } from '@/api/community/communityApi'
116 117
117 export default { 118 export default {
118 name: 'EditApplyRoomDiscountRecord', 119 name: 'EditApplyRoomDiscountRecord',
@@ -164,7 +165,7 @@ export default { @@ -164,7 +165,7 @@ export default {
164 this.form = { 165 this.form = {
165 ...this.form, 166 ...this.form,
166 ...data, 167 ...data,
167 - communityId: this.$store.getters.communityId 168 + communityId: getCommunityId()
168 } 169 }
169 this.visible = true 170 this.visible = true
170 }, 171 },
src/components/fee/editFee.vue
1 <template> 1 <template>
2 - <el-dialog :title="$t('editFee.title')" :visible.sync="visible" width="50%"> 2 + <el-dialog
  3 + :title="$t('editFee.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
3 <el-form :model="editFeeInfo" label-width="120px"> 8 <el-form :model="editFeeInfo" label-width="120px">
4 - <el-form-item :label="$t('editFee.startTime')" required>  
5 - <el-date-picker v-model="editFeeInfo.startTime" type="datetime" :placeholder="$t('editFee.startTimePlaceholder')"  
6 - value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">  
7 - </el-date-picker> 9 + <el-form-item :label="$t('editFee.startTime')" prop="startTime">
  10 + <el-date-picker
  11 + v-model="editFeeInfo.startTime"
  12 + type="datetime"
  13 + :placeholder="$t('editFee.startTimePlaceholder')"
  14 + value-format="yyyy-MM-dd HH:mm:ss"
  15 + @change="validateStartTime"
  16 + ></el-date-picker>
8 </el-form-item> 17 </el-form-item>
9 - <el-form-item :label="$t('editFee.endTime')" required>  
10 - <el-date-picker v-model="editFeeInfo.endTime" type="datetime" :placeholder="$t('editFee.endTimePlaceholder')"  
11 - value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">  
12 - </el-date-picker> 18 + <el-form-item :label="$t('editFee.endTime')" prop="endTime">
  19 + <el-date-picker
  20 + v-model="editFeeInfo.endTime"
  21 + type="date"
  22 + :placeholder="$t('editFee.endTimePlaceholder')"
  23 + value-format="yyyy-MM-dd"
  24 + @change="validateEndTime"
  25 + ></el-date-picker>
13 </el-form-item> 26 </el-form-item>
14 - <el-form-item :label="$t('editFee.maxEndTime')" required>  
15 - <el-date-picker v-model="editFeeInfo.maxEndTime" type="datetime"  
16 - :placeholder="$t('editFee.maxEndTimePlaceholder')" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">  
17 - </el-date-picker> 27 + <el-form-item :label="$t('editFee.maxEndTime')" prop="maxEndTime">
  28 + <el-date-picker
  29 + v-model="editFeeInfo.maxEndTime"
  30 + type="date"
  31 + :placeholder="$t('editFee.maxEndTimePlaceholder')"
  32 + value-format="yyyy-MM-dd"
  33 + @change="validateMaxEndTime"
  34 + ></el-date-picker>
18 </el-form-item> 35 </el-form-item>
19 - <template v-if="editFeeInfo.computingFormula == '1102'">  
20 - <el-form-item :label="$t('editFee.rateCycle')" required>  
21 - <el-input v-model="editFeeInfo.rateCycle" :placeholder="$t('editFee.rateCyclePlaceholder')"></el-input> 36 + <template v-if="editFeeInfo.computingFormula === '1102'">
  37 + <el-form-item :label="$t('editFee.rateCycle')" prop="rateCycle">
  38 + <el-input
  39 + v-model="editFeeInfo.rateCycle"
  40 + :placeholder="$t('editFee.rateCyclePlaceholder')"
  41 + ></el-input>
22 </el-form-item> 42 </el-form-item>
23 - <el-form-item :label="$t('editFee.rate')" required>  
24 - <el-input v-model="editFeeInfo.rate" :placeholder="$t('editFee.ratePlaceholder')"></el-input> 43 + <el-form-item :label="$t('editFee.rate')" prop="rate">
  44 + <el-input
  45 + v-model="editFeeInfo.rate"
  46 + :placeholder="$t('editFee.ratePlaceholder')"
  47 + ></el-input>
25 </el-form-item> 48 </el-form-item>
26 - <el-form-item :label="$t('editFee.rateStartTime')" required>  
27 - <el-date-picker v-model="editFeeInfo.rateStartTime" type="datetime"  
28 - :placeholder="$t('editFee.rateStartTimePlaceholder')" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%">  
29 - </el-date-picker> 49 + <el-form-item :label="$t('editFee.rateStartTime')" prop="rateStartTime">
  50 + <el-date-picker
  51 + v-model="editFeeInfo.rateStartTime"
  52 + type="date"
  53 + :placeholder="$t('editFee.rateStartTimePlaceholder')"
  54 + value-format="yyyy-MM-dd"
  55 + @change="validateRateStartTime"
  56 + ></el-date-picker>
30 </el-form-item> 57 </el-form-item>
31 </template> 58 </template>
32 </el-form> 59 </el-form>
33 <span slot="footer" class="dialog-footer"> 60 <span slot="footer" class="dialog-footer">
34 - <el-button @click="close">{{ $t('common.cancel') }}</el-button> 61 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
35 <el-button type="primary" @click="_doEidtFee">{{ $t('common.submit') }}</el-button> 62 <el-button type="primary" @click="_doEidtFee">{{ $t('common.submit') }}</el-button>
36 </span> 63 </span>
37 </el-dialog> 64 </el-dialog>
38 </template> 65 </template>
39 66
40 <script> 67 <script>
41 -import { updateFee } from '@/api/fee/listCarFeeApi' 68 +import { updateFee } from '@/api/fee/editFeeApi'
  69 +import { getCommunityId } from '@/api/community/communityApi'
42 70
43 export default { 71 export default {
44 name: 'EditFee', 72 name: 'EditFee',
@@ -60,25 +88,97 @@ export default { @@ -60,25 +88,97 @@ export default {
60 }, 88 },
61 methods: { 89 methods: {
62 open(fee) { 90 open(fee) {
63 - this.editFeeInfo = { ...fee } 91 + this.editFeeInfo = {
  92 + feeId: fee.feeId,
  93 + startTime: fee.startTime.indexOf(":") === -1 ? fee.startTime + " 00:00:00" : fee.startTime,
  94 + endTime: fee.endTime.split(' ')[0],
  95 + feeFlag: fee.feeFlag,
  96 + maxEndTime: fee.maxEndTime,
  97 + computingFormula: fee.computingFormula,
  98 + rateCycle: fee.rateCycle,
  99 + rate: fee.rate,
  100 + rateStartTime: fee.rateStartTime
  101 + }
64 this.visible = true 102 this.visible = true
65 }, 103 },
66 - close() { 104 + handleClose() {
67 this.visible = false 105 this.visible = false
  106 + this.clearAddFeeConfigInfo()
  107 + },
  108 + validateStartTime(value) {
  109 + const start = new Date(value)
  110 + const end = new Date(this.editFeeInfo.endTime)
  111 + if (start >= end) {
  112 + this.$message.error(this.$t('editFee.startTimeError'))
  113 + this.editFeeInfo.startTime = ''
  114 + }
  115 + },
  116 + validateEndTime(value) {
  117 + const start = new Date(this.editFeeInfo.startTime)
  118 + const end = new Date(value)
  119 + if (start >= end) {
  120 + this.$message.error(this.$t('editFee.endTimeError'))
  121 + this.editFeeInfo.endTime = ''
  122 + }
  123 + },
  124 + validateMaxEndTime(value) {
  125 + const start = new Date(this.editFeeInfo.startTime)
  126 + const end = new Date(value)
  127 + if (start >= end) {
  128 + this.$message.error(this.$t('editFee.maxEndTimeError'))
  129 + this.editFeeInfo.maxEndTime = ''
  130 + }
  131 + },
  132 + validateRateStartTime(value) {
  133 + const start = new Date(this.editFeeInfo.startTime)
  134 + const end = new Date(value)
  135 + if (start >= end) {
  136 + this.$message.error(this.$t('editFee.rateStartTimeError'))
  137 + this.editFeeInfo.rateStartTime = ''
  138 + }
  139 + },
  140 + editFeeValidate() {
  141 + if (!this.editFeeInfo.startTime) {
  142 + this.$message.error(this.$t('editFee.startTimeRequired'))
  143 + return false
  144 + }
  145 + if (!this.editFeeInfo.endTime) {
  146 + this.$message.error(this.$t('editFee.endTimeRequired'))
  147 + return false
  148 + }
  149 + return true
68 }, 150 },
69 - _doEidtFee() {  
70 - // 验证逻辑  
71 - updateFee(this.editFeeInfo).then(response => {  
72 - if (response.code === 0) {  
73 - this.$message.success(this.$t('common.updateSuccess')) 151 + async _doEidtFee() {
  152 + if (!this.editFeeValidate()) return
  153 +
  154 + this.editFeeInfo.communityId = getCommunityId()
  155 +
  156 + try {
  157 + const res = await updateFee(this.editFeeInfo)
  158 + if (res.code === 0) {
  159 + this.$message.success(this.$t('common.operateSuccess'))
74 this.$emit('success') 160 this.$emit('success')
75 - this.close() 161 + this.handleClose()
76 } else { 162 } else {
77 - this.$message.error(response.msg) 163 + this.$message.error(res.msg)
78 } 164 }
79 - }).catch(error => {  
80 - this.$message.error(error.message)  
81 - }) 165 + } catch (error) {
  166 + console.error('请求失败:', error)
  167 + this.$message.error(this.$t('common.operateFail'))
  168 + }
  169 + },
  170 + clearAddFeeConfigInfo() {
  171 + this.editFeeInfo = {
  172 + feeId: '',
  173 + startTime: '',
  174 + endTime: '',
  175 + feeFlag: '',
  176 + maxEndTime: '',
  177 + computingFormula: '',
  178 + rateCycle: '',
  179 + rate: '',
  180 + rateStartTime: ''
  181 + }
82 } 182 }
83 } 183 }
84 } 184 }
src/components/fee/editFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('editFeeDemo.openModal') }}</el-button>
  4 + <edit-fee ref="editFee" @success="handleSuccess"></edit-fee>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import EditFee from './editFee'
  10 +
  11 +export default {
  12 + name: 'EditFeeDemo',
  13 + components: {
  14 + EditFee
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.editFee.open({
  19 + feeId: '123',
  20 + startTime: '2023-01-01 00:00:00',
  21 + endTime: '2023-01-01',
  22 + maxEndTime: '2023-12-31',
  23 + computingFormula: '1102',
  24 + rateCycle: '12',
  25 + rate: '0.05',
  26 + rateStartTime: '2023-01-01'
  27 + })
  28 + },
  29 + handleSuccess() {
  30 + this.$message.success(this.$t('editFeeDemo.successMessage'))
  31 + }
  32 + }
  33 +}
  34 +</script>
0 \ No newline at end of file 35 \ No newline at end of file
src/components/fee/editFeeRule.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('editFeeRule.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form :model="editFeeRuleInfo" label-width="120px">
  9 + <el-form-item :label="$t('editFeeRule.maxTime')" prop="maxTime">
  10 + <el-date-picker
  11 + v-model="editFeeRuleInfo.maxTime"
  12 + type="datetime"
  13 + :placeholder="$t('editFeeRule.maxTimePlaceholder')"
  14 + value-format="yyyy-MM-dd HH:mm:ss"
  15 + ></el-date-picker>
  16 + </el-form-item>
  17 + <el-form-item :label="$t('editFeeRule.curYearMonth')" prop="curYearMonth">
  18 + <el-date-picker
  19 + v-model="editFeeRuleInfo.curYearMonth"
  20 + type="date"
  21 + :placeholder="$t('editFeeRule.curYearMonthPlaceholder')"
  22 + value-format="yyyy-MM-dd"
  23 + @change="validateCurYearMonth"
  24 + ></el-date-picker>
  25 + </el-form-item>
  26 + </el-form>
  27 + <span slot="footer" class="dialog-footer">
  28 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  29 + <el-button type="primary" @click="_doEidtFee">{{ $t('common.submit') }}</el-button>
  30 + </span>
  31 + </el-dialog>
  32 +</template>
  33 +
  34 +<script>
  35 +import { updatePayFeeRule } from '@/api/fee/editFeeRuleApi'
  36 +import { getCommunityId } from '@/api/community/communityApi'
  37 +
  38 +export default {
  39 + name: 'EditFeeRule',
  40 + data() {
  41 + return {
  42 + visible: false,
  43 + editFeeRuleInfo: {
  44 + ruleId: '',
  45 + maxTime: '',
  46 + curYearMonth: '',
  47 + oldCurYearMonth: ''
  48 + }
  49 + }
  50 + },
  51 + methods: {
  52 + open(fee) {
  53 + this.editFeeRuleInfo = {
  54 + ruleId: fee.ruleId,
  55 + maxTime: fee.maxTime,
  56 + curYearMonth: fee.curYearMonth,
  57 + oldCurYearMonth: fee.curYearMonth
  58 + }
  59 + this.visible = true
  60 + },
  61 + handleClose() {
  62 + this.visible = false
  63 + this.clearEditFeeRuleInfoData()
  64 + },
  65 + validateCurYearMonth(value) {
  66 + const start = new Date(this.editFeeRuleInfo.oldCurYearMonth)
  67 + const end = new Date(value)
  68 + if (start >= end) {
  69 + this.$message.error(this.$t('editFeeRule.dateError', { date: this.editFeeRuleInfo.oldCurYearMonth }))
  70 + this.editFeeRuleInfo.curYearMonth = ''
  71 + }
  72 + },
  73 + editFeeRuleValidate() {
  74 + if (!this.editFeeRuleInfo.maxTime) {
  75 + this.$message.error(this.$t('editFeeRule.maxTimeRequired'))
  76 + return false
  77 + }
  78 + if (!this.editFeeRuleInfo.curYearMonth) {
  79 + this.$message.error(this.$t('editFeeRule.curYearMonthRequired'))
  80 + return false
  81 + }
  82 + return true
  83 + },
  84 + async _doEidtFee() {
  85 + if (!this.editFeeRuleValidate()) return
  86 +
  87 + this.editFeeRuleInfo.communityId = getCommunityId()
  88 +
  89 + try {
  90 + const res = await updatePayFeeRule(this.editFeeRuleInfo)
  91 + if (res.code === 0) {
  92 + this.$message.success(this.$t('common.operateSuccess'))
  93 + this.$emit('success')
  94 + this.handleClose()
  95 + } else {
  96 + this.$message.error(res.msg)
  97 + }
  98 + } catch (error) {
  99 + console.error('请求失败:', error)
  100 + this.$message.error(this.$t('common.operateFail'))
  101 + }
  102 + },
  103 + clearEditFeeRuleInfoData() {
  104 + this.editFeeRuleInfo = {
  105 + ruleId: '',
  106 + maxTime: '',
  107 + curYearMonth: '',
  108 + oldCurYearMonth: ''
  109 + }
  110 + }
  111 + }
  112 +}
  113 +</script>
0 \ No newline at end of file 114 \ No newline at end of file
src/components/fee/editFeeRuleDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('editFeeRuleDemo.openModal') }}</el-button>
  4 + <edit-fee-rule ref="editFeeRule" @success="handleSuccess"></edit-fee-rule>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import EditFeeRule from './editFeeRule'
  10 +
  11 +export default {
  12 + name: 'EditFeeRuleDemo',
  13 + components: {
  14 + EditFeeRule
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.editFeeRule.open({
  19 + ruleId: '123',
  20 + maxTime: '2023-12-31 23:59:59',
  21 + curYearMonth: '2023-01-01'
  22 + })
  23 + },
  24 + handleSuccess() {
  25 + this.$message.success(this.$t('editFeeRuleDemo.successMessage'))
  26 + }
  27 + }
  28 +}
  29 +</script>
0 \ No newline at end of file 30 \ No newline at end of file
src/components/fee/exportFeeImportExcel.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('exportFeeImportExcel.title')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form label-width="120px">
  9 + <el-form-item :label="$t('exportFeeImportExcel.floor')">
  10 + <div>
  11 + <el-checkbox
  12 + v-model="isFloorAll"
  13 + @change="toggleAllFloors"
  14 + >{{ $t('exportFeeImportExcel.all') }}</el-checkbox>
  15 + <el-checkbox
  16 + v-for="item in floors"
  17 + :key="item.floorId"
  18 + v-model="selectedFloorIds"
  19 + :label="item.floorId"
  20 + @change="handleFloorChange"
  21 + class="margin-left"
  22 + >{{ item.floorName }}</el-checkbox>
  23 + </div>
  24 + </el-form-item>
  25 +
  26 + <el-form-item :label="$t('exportFeeImportExcel.feeItem')">
  27 + <div>
  28 + <el-checkbox
  29 + v-model="isConfigAll"
  30 + @change="toggleAllConfigs"
  31 + >{{ $t('exportFeeImportExcel.all') }}</el-checkbox>
  32 + <el-checkbox
  33 + v-for="item in configs"
  34 + :key="item.configId"
  35 + v-model="selectedConfigIds"
  36 + :label="item.configId"
  37 + @change="handleConfigChange"
  38 + class="margin-left"
  39 + >{{ item.feeName }}</el-checkbox>
  40 + </div>
  41 + </el-form-item>
  42 + </el-form>
  43 +
  44 + <span slot="footer" class="dialog-footer">
  45 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  46 + <el-button type="primary" @click="handleExport">{{ $t('common.export') }}</el-button>
  47 + </span>
  48 + </el-dialog>
  49 +</template>
  50 +
  51 +<script>
  52 +import { exportData, listFeeConfigs, queryFloors } from '@/api/fee/exportFeeImportExcelApi'
  53 +import { getCommunityId } from '@/api/community/communityApi'
  54 +
  55 +export default {
  56 + name: 'ExportFeeImportExcel',
  57 + data() {
  58 + return {
  59 + visible: false,
  60 + isFloorAll: true,
  61 + isConfigAll: true,
  62 + selectedFloorIds: [],
  63 + selectedConfigIds: [],
  64 + floors: [],
  65 + configs: []
  66 + }
  67 + },
  68 + computed: {
  69 + communityId() {
  70 + return getCommunityId()
  71 + }
  72 + },
  73 + methods: {
  74 + open() {
  75 + this.visible = true
  76 + this.loadFloors()
  77 + this.loadConfigs()
  78 + },
  79 +
  80 + loadFloors() {
  81 + queryFloors({
  82 + page: 1,
  83 + row: 150,
  84 + communityId: this.communityId
  85 + }).then(response => {
  86 + this.floors = response.data.apiFloorDataVoList
  87 + this.selectedFloorIds = this.floors.map(item => item.floorId)
  88 + })
  89 + },
  90 +
  91 + loadConfigs() {
  92 + listFeeConfigs({
  93 + page: 1,
  94 + row: 100,
  95 + communityId: this.communityId,
  96 + isDefault: 'F'
  97 + }).then(response => {
  98 + this.configs = response.data.feeConfigs
  99 + this.selectedConfigIds = this.configs.map(item => item.configId)
  100 + })
  101 + },
  102 +
  103 + toggleAllFloors() {
  104 + this.selectedFloorIds = this.isFloorAll
  105 + ? this.floors.map(item => item.floorId)
  106 + : []
  107 + },
  108 +
  109 + toggleAllConfigs() {
  110 + this.selectedConfigIds = this.isConfigAll
  111 + ? this.configs.map(item => item.configId)
  112 + : []
  113 + },
  114 +
  115 + handleFloorChange() {
  116 + this.isFloorAll = this.selectedFloorIds.length === this.floors.length
  117 + },
  118 +
  119 + handleConfigChange() {
  120 + this.isConfigAll = this.selectedConfigIds.length === this.configs.length
  121 + },
  122 +
  123 + handleExport() {
  124 + const params = {
  125 + floorIds: this.selectedFloorIds.join(','),
  126 + configIds: this.selectedConfigIds.join(','),
  127 + communityId: this.communityId,
  128 + type: '1001',
  129 + pagePath: 'exportCreateFeeTemplate'
  130 + }
  131 +
  132 + exportData(params).then(response => {
  133 + this.$message.success(response.data.msg)
  134 + if (response.data.code === 0) {
  135 + this.handleClose()
  136 + this.$router.push('/pages/property/downloadTempFile?tab=下载中心')
  137 + }
  138 + }).catch(error => {
  139 + this.$message.error(error.message)
  140 + })
  141 + },
  142 +
  143 + handleClose() {
  144 + this.visible = false
  145 + this.reset()
  146 + },
  147 +
  148 + reset() {
  149 + this.isFloorAll = true
  150 + this.isConfigAll = true
  151 + this.selectedFloorIds = []
  152 + this.selectedConfigIds = []
  153 + }
  154 + }
  155 +}
  156 +</script>
  157 +
  158 +<style scoped>
  159 +.margin-left {
  160 + margin-left: 15px;
  161 +}
  162 +</style>
0 \ No newline at end of file 163 \ No newline at end of file
src/components/fee/exportFeeImportExcelDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('exportFeeImportExcelDemo.openModal') }}</el-button>
  4 + <export-fee-import-excel ref="exportFeeImportExcel"></export-fee-import-excel>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import ExportFeeImportExcel from './exportFeeImportExcel'
  10 +
  11 +export default {
  12 + name: 'ExportFeeImportExcelDemo',
  13 + components: {
  14 + ExportFeeImportExcel
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.exportFeeImportExcel.open()
  19 + }
  20 + }
  21 +}
  22 +</script>
0 \ No newline at end of file 23 \ No newline at end of file
src/components/fee/feeDetailFeeRule.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table :data="feeDetailFeeRuleInfo.rules" border style="width: 100%">
  4 + <el-table-column prop="ruleId" :label="$t('feeDetailFeeRule.ruleId')" align="center"></el-table-column>
  5 + <el-table-column :label="$t('feeDetailFeeRule.feeItem')" align="center">
  6 + <template slot-scope="scope">
  7 + {{ scope.row.feeTypeCdName }}>{{ scope.row.feeName }}
  8 + </template>
  9 + </el-table-column>
  10 + <el-table-column prop="feeFlagName" :label="$t('feeDetailFeeRule.feeFlag')" align="center"></el-table-column>
  11 + <el-table-column prop="startTime" :label="$t('feeDetailFeeRule.createTime')" align="center"></el-table-column>
  12 + <el-table-column :label="$t('feeDetailFeeRule.validPeriod')" align="center">
  13 + <template slot-scope="scope">
  14 + {{ scope.row.endTime }}~{{ scope.row.maxTime }}
  15 + </template>
  16 + </el-table-column>
  17 + <el-table-column prop="computingFormulaName" :label="$t('feeDetailFeeRule.formula')" align="center"></el-table-column>
  18 + <el-table-column :label="$t('feeDetailFeeRule.price')" align="center">
  19 + <template slot-scope="scope">
  20 + {{ scope.row.computingFormula === '2002' ? '-' : scope.row.squarePrice }}
  21 + </template>
  22 + </el-table-column>
  23 + <el-table-column prop="additionalAmount" :label="$t('feeDetailFeeRule.additionalFee')" align="center"></el-table-column>
  24 + <el-table-column :label="$t('feeDetailFeeRule.status')" align="center">
  25 + <template slot-scope="scope">
  26 + {{ scope.row.state === '2008001' ? $t('common.valid') : $t('common.invalid') }}
  27 + </template>
  28 + </el-table-column>
  29 + <el-table-column prop="curYearMonth" :label="$t('feeDetailFeeRule.billDay')" align="center"></el-table-column>
  30 + <el-table-column :label="$t('feeDetailFeeRule.billCycle')" align="center">
  31 + <template>按月</template>
  32 + </el-table-column>
  33 + <el-table-column :label="$t('common.operation')" align="center" v-if="hasPrivilege">
  34 + <template slot-scope="scope">
  35 + <el-button
  36 + v-if="hasPrivilege('502020090427190001')"
  37 + type="text"
  38 + size="small"
  39 + @click="_updateFeeRule(scope.row)"
  40 + >
  41 + {{ $t('common.edit') }}
  42 + </el-button>
  43 + <el-button
  44 + v-if="hasPrivilege('502021070488970005')"
  45 + type="text"
  46 + size="small"
  47 + @click="_finishFeeRule(scope.row)"
  48 + >
  49 + {{ $t('common.manualFinish') }}
  50 + </el-button>
  51 + <el-button
  52 + v-if="hasPrivilege('502020090604200029')"
  53 + type="text"
  54 + size="small"
  55 + @click="_deleteFeeRule(scope.row)"
  56 + >
  57 + {{ $t('common.cancel') }}
  58 + </el-button>
  59 + </template>
  60 + </el-table-column>
  61 + </el-table>
  62 +
  63 + <el-pagination
  64 + @size-change="handleSizeChange"
  65 + @current-change="handleCurrentChange"
  66 + :current-page="currentPage"
  67 + :page-sizes="[10, 20, 30, 50]"
  68 + :page-size="pageSize"
  69 + layout="total, sizes, prev, pager, next, jumper"
  70 + :total="total"
  71 + ></el-pagination>
  72 +
  73 + <edit-fee-rule ref="editFeeRule" @success="loadData"></edit-fee-rule>
  74 + <finish-fee-rule ref="finishFeeRule" @success="loadData"></finish-fee-rule>
  75 + <delete-fee ref="deleteFee" @success="loadData"></delete-fee>
  76 + </div>
  77 +</template>
  78 +
  79 +<script>
  80 +import { listPayFeeRule } from '@/api/fee/feeDetailFeeRuleApi'
  81 +import EditFeeRule from './editFeeRule'
  82 +import FinishFeeRule from './finishFeeRule'
  83 +import DeleteFee from './deleteFee'
  84 +import { getCommunityId } from '@/api/community/communityApi'
  85 +
  86 +export default {
  87 + name: 'FeeDetailFeeRule',
  88 + components: {
  89 + EditFeeRule,
  90 + FinishFeeRule,
  91 + DeleteFee
  92 + },
  93 + props: {
  94 + feeId: {
  95 + type: String,
  96 + default: ''
  97 + },
  98 + roomId: {
  99 + type: String,
  100 + default: ''
  101 + }
  102 + },
  103 + data() {
  104 + return {
  105 + feeDetailFeeRuleInfo: {
  106 + rules: [],
  107 + feeId: '',
  108 + roomId: ''
  109 + },
  110 + currentPage: 1,
  111 + pageSize: 10,
  112 + total: 0
  113 + }
  114 + },
  115 + computed: {
  116 + },
  117 + methods: {
  118 + async loadData() {
  119 + const params = {
  120 + communityId: getCommunityId(),
  121 + feeId: this.feeDetailFeeRuleInfo.feeId,
  122 + payerObjId: this.feeDetailFeeRuleInfo.roomId,
  123 + detailId: '-1',
  124 + page: this.currentPage,
  125 + row: this.pageSize
  126 + }
  127 +
  128 + try {
  129 + const res = await listPayFeeRule(params)
  130 + if (res.code === 0) {
  131 + this.feeDetailFeeRuleInfo.rules = res.data
  132 + this.total = res.records
  133 + } else {
  134 + this.$message.error(res.msg)
  135 + }
  136 + } catch (error) {
  137 + console.error('请求失败:', error)
  138 + }
  139 + },
  140 + handleSizeChange(val) {
  141 + this.pageSize = val
  142 + this.loadData()
  143 + },
  144 + handleCurrentChange(val) {
  145 + this.currentPage = val
  146 + this.loadData()
  147 + },
  148 + _deleteFeeRule(fee) {
  149 + this.$refs.deleteFee.open(fee)
  150 + },
  151 + _updateFeeRule(fee) {
  152 + this.$refs.editFeeRule.open(fee)
  153 + },
  154 + _finishFeeRule(fee) {
  155 + this.$refs.finishFeeRule.open(fee)
  156 + },
  157 + open(params) {
  158 + // 这个方法用于接收参数并初始化组件
  159 + if (params.feeId) {
  160 + this.feeDetailFeeRuleInfo.feeId = params.feeId
  161 + }
  162 + if (params.roomId) {
  163 + this.feeDetailFeeRuleInfo.roomId = params.roomId
  164 + }
  165 + this.loadData()
  166 + }
  167 + },
  168 + watch: {
  169 + feeId(newVal) {
  170 + this.feeDetailFeeRuleInfo.feeId = newVal
  171 + this.loadData()
  172 + },
  173 + roomId(newVal) {
  174 + this.feeDetailFeeRuleInfo.roomId = newVal
  175 + this.loadData()
  176 + }
  177 + }
  178 +}
  179 +</script>
0 \ No newline at end of file 180 \ No newline at end of file
src/components/fee/feeDetailFeeRuleDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="switchData">{{ $t('feeDetailFeeRuleDemo.switchData') }}</el-button>
  4 + <fee-detail-fee-rule ref="feeDetailFeeRule"></fee-detail-fee-rule>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import FeeDetailFeeRule from './feeDetailFeeRule'
  10 +
  11 +export default {
  12 + name: 'FeeDetailFeeRuleDemo',
  13 + components: {
  14 + FeeDetailFeeRule
  15 + },
  16 + methods: {
  17 + switchData() {
  18 + this.$refs.feeDetailFeeRule.loadData({
  19 + feeId: '123',
  20 + roomId: '456'
  21 + })
  22 + }
  23 + }
  24 +}
  25 +</script>
0 \ No newline at end of file 26 \ No newline at end of file
src/components/fee/feeDetailRuleBill.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-table :data="feeDetailRuleBillInfo.bills" border style="width: 100%">
  4 + <el-table-column prop="billName" :label="$t('feeDetailRuleBill.billName')" align="center"></el-table-column>
  5 + <el-table-column :label="$t('feeDetailRuleBill.feeItem')" align="center">
  6 + <template slot-scope="scope">
  7 + {{ scope.row.feeTypeCdName }}>{{ scope.row.feeName }}
  8 + </template>
  9 + </el-table-column>
  10 + <el-table-column :label="$t('feeDetailRuleBill.receivablePeriod')" align="center">
  11 + <template slot-scope="scope">
  12 + {{ scope.row.endTime }}~{{ scope.row.deadlineTime }}
  13 + </template>
  14 + </el-table-column>
  15 + <el-table-column prop="feeTotalPrice" :label="$t('feeDetailRuleBill.receivableAmount')" align="center"></el-table-column>
  16 + <el-table-column prop="ruleId" :label="$t('feeDetailRuleBill.ruleId')" align="center"></el-table-column>
  17 + <el-table-column prop="feeId" :label="$t('feeDetailRuleBill.feeId')" align="center"></el-table-column>
  18 + <el-table-column prop="stateName" :label="$t('feeDetailRuleBill.status')" align="center"></el-table-column>
  19 + <el-table-column :label="$t('feeDetailRuleBill.description')" align="center">
  20 + <template slot-scope="scope">
  21 + <div>{{ $t('feeDetailRuleBill.price') }}: {{ scope.row.squarePrice }}</div>
  22 + <div>{{ $t('feeDetailRuleBill.fixedFee') }}: {{ scope.row.additionalAmount }}</div>
  23 + </template>
  24 + </el-table-column>
  25 + <el-table-column :label="$t('common.operation')" align="center">
  26 + <template slot-scope="scope">
  27 + <el-button type="text" size="small">
  28 + <a :href="'/#/pages/fee/feeDetail?feeId=' + scope.row.feeId" target="_blank">
  29 + {{ $t('common.detail') }}
  30 + </a>
  31 + </el-button>
  32 + </template>
  33 + </el-table-column>
  34 + </el-table>
  35 +
  36 + <el-pagination
  37 + @size-change="handleSizeChange"
  38 + @current-change="handleCurrentChange"
  39 + :current-page="currentPage"
  40 + :page-sizes="[10, 20, 30, 50]"
  41 + :page-size="pageSize"
  42 + layout="total, sizes, prev, pager, next, jumper"
  43 + :total="total"
  44 + ></el-pagination>
  45 + </div>
  46 +</template>
  47 +
  48 +<script>
  49 +import { listPayFeeRuleBill } from '@/api/fee/feeDetailRuleBillApi'
  50 +import { getCommunityId } from '@/api/community/communityApi'
  51 +
  52 +export default {
  53 + name: 'FeeDetailRuleBill',
  54 + props: {
  55 + feeId: {
  56 + type: String,
  57 + default: ''
  58 + },
  59 + roomId: {
  60 + type: String,
  61 + default: ''
  62 + }
  63 + },
  64 + data() {
  65 + return {
  66 + feeDetailRuleBillInfo: {
  67 + bills: [],
  68 + feeId: '',
  69 + roomId: ''
  70 + },
  71 + currentPage: 1,
  72 + pageSize: 10,
  73 + total: 0
  74 + }
  75 + },
  76 + methods: {
  77 + async loadData() {
  78 + const params = {
  79 + communityId: getCommunityId(),
  80 + feeId: this.feeDetailRuleBillInfo.feeId,
  81 + payerObjId: this.feeDetailRuleBillInfo.roomId,
  82 + page: this.currentPage,
  83 + row: this.pageSize
  84 + }
  85 +
  86 + try {
  87 + const res = await listPayFeeRuleBill(params)
  88 + if (res.code === 0) {
  89 + this.feeDetailRuleBillInfo.bills = res.data
  90 + this.total = res.records
  91 + } else {
  92 + this.$message.error(res.msg)
  93 + }
  94 + } catch (error) {
  95 + console.error('请求失败:', error)
  96 + }
  97 + },
  98 + handleSizeChange(val) {
  99 + this.pageSize = val
  100 + this.loadData()
  101 + },
  102 + handleCurrentChange(val) {
  103 + this.currentPage = val
  104 + this.loadData()
  105 + },
  106 + open(params) {
  107 + // 这个方法用于接收参数并初始化组件
  108 + if (params.feeId) {
  109 + this.feeDetailRuleBillInfo.feeId = params.feeId
  110 + }
  111 + if (params.roomId) {
  112 + this.feeDetailRuleBillInfo.roomId = params.roomId
  113 + }
  114 + this.loadData()
  115 + }
  116 + },
  117 + watch: {
  118 + feeId(newVal) {
  119 + this.feeDetailRuleBillInfo.feeId = newVal
  120 + this.loadData()
  121 + },
  122 + roomId(newVal) {
  123 + this.feeDetailRuleBillInfo.roomId = newVal
  124 + this.loadData()
  125 + }
  126 + }
  127 +}
  128 +</script>
0 \ No newline at end of file 129 \ No newline at end of file
src/components/fee/feeDetailRuleBillDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="switchData">{{ $t('feeDetailRuleBillDemo.switchData') }}</el-button>
  4 + <fee-detail-rule-bill ref="feeDetailRuleBill"></fee-detail-rule-bill>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import FeeDetailRuleBill from './feeDetailRuleBill'
  10 +
  11 +export default {
  12 + name: 'FeeDetailRuleBillDemo',
  13 + components: {
  14 + FeeDetailRuleBill
  15 + },
  16 + methods: {
  17 + switchData() {
  18 + this.$refs.feeDetailRuleBill.loadData({
  19 + feeId: '123',
  20 + roomId: '456'
  21 + })
  22 + }
  23 + }
  24 +}
  25 +</script>
0 \ No newline at end of file 26 \ No newline at end of file
src/components/fee/finishFeeRule.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('finishFeeRule.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + :before-close="handleClose"
  7 + >
  8 + <p>{{ $t('finishFeeRule.confirmMessage') }}</p>
  9 + <span slot="footer" class="dialog-footer">
  10 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  11 + <el-button type="primary" @click="finishFeeRule">{{ $t('common.confirm') }}</el-button>
  12 + </span>
  13 + </el-dialog>
  14 +</template>
  15 +
  16 +<script>
  17 +import { updatePayFeeRule } from '@/api/fee/finishFeeRuleApi'
  18 +import { getCommunityId } from '@/api/community/communityApi'
  19 +
  20 +export default {
  21 + name: 'FinishFeeRule',
  22 + data() {
  23 + return {
  24 + visible: false,
  25 + finishFeeRuleInfo: {}
  26 + }
  27 + },
  28 + methods: {
  29 + open(params) {
  30 + this.finishFeeRuleInfo = params
  31 + this.visible = true
  32 + },
  33 + handleClose() {
  34 + this.visible = false
  35 + },
  36 + async finishFeeRule() {
  37 + const data = {
  38 + ruleId: this.finishFeeRuleInfo.ruleId,
  39 + state: '2009001',
  40 + communityId: getCommunityId()
  41 + }
  42 +
  43 + try {
  44 + const res = await updatePayFeeRule(data)
  45 + if (res.code === 0) {
  46 + this.$message.success(this.$t('common.operateSuccess'))
  47 + this.$emit('success')
  48 + this.handleClose()
  49 + } else {
  50 + this.$message.error(res.msg)
  51 + }
  52 + } catch (error) {
  53 + console.error('请求失败:', error)
  54 + this.$message.error(this.$t('common.operateFail'))
  55 + }
  56 + }
  57 + }
  58 +}
  59 +</script>
0 \ No newline at end of file 60 \ No newline at end of file
src/components/fee/inputSearchRoom.vue 0 → 100644
  1 +<template>
  2 + <div
  3 + class="vc-input-search text-left"
  4 + @mouseleave="doInputSearchRoomClose"
  5 + v-if="rooms && rooms.length>0"
  6 + >
  7 + <div class="close">
  8 + <i class="el-icon-close" @click="doInputSearchRoomClose"></i>
  9 + </div>
  10 + <div
  11 + class="padding-left-sm padding-top-sm"
  12 + style="cursor:pointer;"
  13 + v-for="(item,index) in rooms"
  14 + :key="index"
  15 + @click="inputSearchRoomChooseRoom(item)"
  16 + >
  17 + <span>{{item.floorNum}}-{{item.unitNum}}-{{item.roomNum}}</span>
  18 + </div>
  19 + </div>
  20 +</template>
  21 +
  22 +<script>
  23 +import { queryRooms } from '@/api/fee/inputSearchRoomApi'
  24 +import { getCommunityId } from '@/api/community/communityApi'
  25 +
  26 +export default {
  27 + name: 'InputSearchRoom',
  28 + data() {
  29 + return {
  30 + rooms: [],
  31 + callComponent: '',
  32 + communityId: ''
  33 + }
  34 + },
  35 + created() {
  36 + this.communityId = getCommunityId()
  37 + this.$on('searchRoom', this.handleSearchRoom)
  38 + this.$on('close', this.handleClose)
  39 + },
  40 + methods: {
  41 + handleSearchRoom(param) {
  42 + if (!param.roomName) return
  43 + this.loadRoomInfo(param.roomName)
  44 + this.callComponent = param.callComponent
  45 + },
  46 + handleClose() {
  47 + this.rooms = []
  48 + },
  49 + async loadRoomInfo(roomName) {
  50 + try {
  51 + const res = await queryRooms({
  52 + page: 1,
  53 + row: 10,
  54 + flag: 1,
  55 + roomNum: roomName,
  56 + communityId: this.communityId
  57 + })
  58 + this.rooms = res.rooms
  59 + if (res.rooms.length <= 0) {
  60 + this.$message.warning(this.$t('inputSearchRoom.noRoomFound'))
  61 + }
  62 + } catch (error) {
  63 + console.error('请求失败:', error)
  64 + }
  65 + },
  66 + inputSearchRoomChooseRoom(room) {
  67 + this.$emit(this.callComponent, 'notifyRoom', room)
  68 + this.rooms = []
  69 + },
  70 + doInputSearchRoomClose() {
  71 + this.rooms = []
  72 + }
  73 + }
  74 +}
  75 +</script>
  76 +
  77 +<style scoped>
  78 +.vc-input-search {
  79 + position: absolute;
  80 + z-index: 999;
  81 + background: #fff;
  82 + border: 1px solid #dcdfe6;
  83 + border-radius: 4px;
  84 + box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
  85 + padding: 10px;
  86 +}
  87 +.close {
  88 + text-align: right;
  89 + cursor: pointer;
  90 +}
  91 +.padding-left-sm {
  92 + padding-left: 10px;
  93 +}
  94 +.padding-top-sm {
  95 + padding-top: 5px;
  96 +}
  97 +</style>
0 \ No newline at end of file 98 \ No newline at end of file
src/components/fee/inputSearchRoomByOwner.vue 0 → 100644
  1 +<template>
  2 + <div
  3 + class="vc-input-search text-left"
  4 + v-if="rooms && rooms.length>0"
  5 + >
  6 + <div class="close">
  7 + <i class="el-icon-close" @click="doInputSearchRoomByOwnerClose"></i>
  8 + </div>
  9 + <div
  10 + class="padding-left-sm padding-top-sm"
  11 + style="cursor:pointer;"
  12 + v-for="(item,index) in rooms"
  13 + :key="index"
  14 + @click="inputSearchRoomChooseRoomByOwner(item)"
  15 + >
  16 + <span>{{item.floorNum}}-{{item.unitNum}}-{{item.roomNum}}({{item.ownerName}})</span>
  17 + </div>
  18 + </div>
  19 +</template>
  20 +
  21 +<script>
  22 +import { queryRoomsByOwner } from '@/api/fee/inputSearchRoomByOwnerApi'
  23 +import { getCommunityId } from '@/api/community/communityApi'
  24 +
  25 +export default {
  26 + name: 'InputSearchRoomByOwner',
  27 + data() {
  28 + return {
  29 + rooms: [],
  30 + callComponent: '',
  31 + communityId: ''
  32 + }
  33 + },
  34 + created() {
  35 + this.communityId = getCommunityId()
  36 + this.$on('searchRoom', this.handleSearchRoom)
  37 + this.$on('close', this.handleClose)
  38 + },
  39 + methods: {
  40 + handleSearchRoom(param) {
  41 + if (!param.ownerName) return
  42 + this.loadRoomByOwnerInfo(param.ownerName)
  43 + this.callComponent = param.callComponent
  44 + },
  45 + handleClose() {
  46 + this.rooms = []
  47 + },
  48 + async loadRoomByOwnerInfo(ownerName) {
  49 + try {
  50 + const res = await queryRoomsByOwner({
  51 + page: 1,
  52 + row: 10,
  53 + ownerNameLike: ownerName,
  54 + communityId: this.communityId
  55 + })
  56 + this.rooms = res.rooms
  57 + } catch (error) {
  58 + console.error('请求失败:', error)
  59 + }
  60 + },
  61 + inputSearchRoomChooseRoomByOwner(room) {
  62 + this.$emit(this.callComponent, 'notifyRoomByOwner', room)
  63 + this.rooms = []
  64 + },
  65 + doInputSearchRoomByOwnerClose() {
  66 + this.rooms = []
  67 + }
  68 + }
  69 +}
  70 +</script>
  71 +
  72 +<style scoped>
  73 +.vc-input-search {
  74 + position: absolute;
  75 + z-index: 999;
  76 + background: #fff;
  77 + border: 1px solid #dcdfe6;
  78 + border-radius: 4px;
  79 + box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);
  80 + padding: 10px;
  81 +}
  82 +.close {
  83 + text-align: right;
  84 + cursor: pointer;
  85 +}
  86 +.padding-left-sm {
  87 + padding-left: 10px;
  88 +}
  89 +.padding-top-sm {
  90 + padding-top: 5px;
  91 +}
  92 +</style>
0 \ No newline at end of file 93 \ No newline at end of file
src/components/fee/inputSearchRoomByOwnerDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-input
  4 + v-model="ownerName"
  5 + :placeholder="$t('inputSearchRoomByOwnerDemo.searchPlaceholder')"
  6 + @input="handleSearch"
  7 + ></el-input>
  8 + <input-search-room-by-owner ref="inputSearchRoomByOwner"></input-search-room-by-owner>
  9 + </div>
  10 +</template>
  11 +
  12 +<script>
  13 +import InputSearchRoomByOwner from './inputSearchRoomByOwner'
  14 +
  15 +export default {
  16 + name: 'InputSearchRoomByOwnerDemo',
  17 + components: {
  18 + InputSearchRoomByOwner
  19 + },
  20 + data() {
  21 + return {
  22 + ownerName: ''
  23 + }
  24 + },
  25 + methods: {
  26 + handleSearch() {
  27 + this.$refs.inputSearchRoomByOwner.$emit('searchRoom', {
  28 + ownerName: this.ownerName,
  29 + callComponent: 'yourComponentName'
  30 + })
  31 + }
  32 + }
  33 +}
  34 +</script>
0 \ No newline at end of file 35 \ No newline at end of file
src/components/fee/inputSearchRoomDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-input
  4 + v-model="roomName"
  5 + :placeholder="$t('inputSearchRoomDemo.searchPlaceholder')"
  6 + @input="handleSearch"
  7 + ></el-input>
  8 + <input-search-room ref="inputSearchRoom"></input-search-room>
  9 + </div>
  10 +</template>
  11 +
  12 +<script>
  13 +import InputSearchRoom from './inputSearchRoom'
  14 +
  15 +export default {
  16 + name: 'InputSearchRoomDemo',
  17 + components: {
  18 + InputSearchRoom
  19 + },
  20 + data() {
  21 + return {
  22 + roomName: ''
  23 + }
  24 + },
  25 + methods: {
  26 + handleSearch() {
  27 + this.$refs.inputSearchRoom.$emit('searchRoom', {
  28 + roomName: this.roomName,
  29 + callComponent: 'yourComponentName'
  30 + })
  31 + }
  32 + }
  33 +}
  34 +</script>
0 \ No newline at end of file 35 \ No newline at end of file
src/components/fee/payFeeDeposit.vue 0 → 100644
  1 +<template>
  2 + <el-card v-if="payFeeDepositInfo.fees.length > 0" class="deposit-card">
  3 + <div slot="header" class="clearfix">
  4 + <span>{{ $t('payFeeDeposit.title') }}</span>
  5 + <el-button type="primary" size="small" class="float-right" @click="_queryPayFeeDeposit">
  6 + <i class="el-icon-refresh"></i>
  7 + {{ $t('common.refresh') }}
  8 + </el-button>
  9 + </div>
  10 +
  11 + <el-table :data="payFeeDepositInfo.fees" border style="width: 100%" v-loading="loading">
  12 + <el-table-column prop="payerObjName" :label="$t('payFeeDeposit.payerObj')" align="center"></el-table-column>
  13 + <el-table-column prop="feeName" :label="$t('payFeeDeposit.feeItem')" align="center"></el-table-column>
  14 + <el-table-column :label="$t('payFeeDeposit.timePeriod')" align="center" width="220">
  15 + <template slot-scope="scope">
  16 + {{ scope.row.startTime }} ~ {{ scope.row.endTime }}
  17 + </template>
  18 + </el-table-column>
  19 + <el-table-column prop="receivedAmount" :label="$t('payFeeDeposit.amount')" align="center"></el-table-column>
  20 + <el-table-column prop="createTime" :label="$t('payFeeDeposit.payTime')" align="center"
  21 + width="180"></el-table-column>
  22 + <el-table-column :label="$t('common.operation')" align="center" width="120">
  23 + <template slot-scope="scope">
  24 + <el-button type="primary" size="mini" @click="_openRefundDeposit(scope.row)">
  25 + {{ $t('payFeeDeposit.refund') }}
  26 + </el-button>
  27 + </template>
  28 + </el-table-column>
  29 + </el-table>
  30 +
  31 + <refund-deposit-fee ref="refundDepositFee"></refund-deposit-fee>
  32 + </el-card>
  33 +</template>
  34 +
  35 +<script>
  36 +import { getCommunityId } from '@/api/community/communityApi'
  37 +import { queryFeeDeposit } from '@/api/fee/batchPayFeeOrderApi'
  38 +import RefundDepositFee from './refundDepositFee'
  39 +
  40 +export default {
  41 + name: 'PayFeeDeposit',
  42 + components: {
  43 + RefundDepositFee
  44 + },
  45 + data() {
  46 + return {
  47 + loading: false,
  48 + payFeeDepositInfo: {
  49 + fees: [],
  50 + payerObjId: '',
  51 + payerObjType: '',
  52 + ownerId: '',
  53 + communityId: ''
  54 + }
  55 + }
  56 + },
  57 + created() {
  58 + this.payFeeDepositInfo.communityId = getCommunityId()
  59 + },
  60 + methods: {
  61 + async _listFeeDeposit(page = 1, rows = 20) {
  62 + this.loading = true
  63 + try {
  64 + const params = {
  65 + page,
  66 + row: rows,
  67 + payerObjId: this.payFeeDepositInfo.payerObjId,
  68 + ownerId: this.payFeeDepositInfo.ownerId,
  69 + communityId: this.payFeeDepositInfo.communityId,
  70 + state: '1400'
  71 + }
  72 +
  73 + const res = await queryFeeDeposit(params)
  74 + if (res.code === 0) {
  75 + this.payFeeDepositInfo.fees = res.data || []
  76 + }
  77 + } catch (error) {
  78 + console.error('请求失败:', error)
  79 + } finally {
  80 + this.loading = false
  81 + }
  82 + },
  83 +
  84 + _queryPayFeeDeposit() {
  85 + this._listFeeDeposit()
  86 + },
  87 +
  88 + _openRefundDeposit(fee) {
  89 + this.$refs.refundDepositFee.open(fee)
  90 + },
  91 +
  92 + open(params) {
  93 + this.payFeeDepositInfo = {
  94 + ...this.payFeeDepositInfo,
  95 + ...params
  96 + }
  97 + this._listFeeDeposit()
  98 + },
  99 +
  100 + refresh() {
  101 + this._listFeeDeposit()
  102 + }
  103 + }
  104 +}
  105 +</script>
  106 +
  107 +<style lang="scss" scoped>
  108 +.deposit-card {
  109 + margin-bottom: 20px;
  110 +}
  111 +</style>
0 \ No newline at end of file 112 \ No newline at end of file
src/components/fee/payFeeUserAccount.vue 0 → 100644
  1 +<template>
  2 + <el-card v-if="payFeeUserAccountInfo.accountList.length > 0" class="account-card">
  3 + <div slot="header" class="flex justify-between">
  4 + <span>{{ $t('payFeeUserAccount.title') }}</span>
  5 + <el-button type="primary" size="small" class="float-right" @click="_queryPayFeeUserAccount">
  6 + <i class="el-icon-refresh"></i>
  7 + {{ $t('common.refresh') }}
  8 + </el-button>
  9 + </div>
  10 +
  11 + <el-table :data="payFeeUserAccountInfo.accountList" border style="width: 100%" v-loading="loading">
  12 + <el-table-column width="55" align="center">
  13 + <template slot-scope="scope">
  14 + <el-radio v-model="payFeeUserAccountInfo.selectAccountIds" :label="scope.row.acctId"
  15 + @change="_computeFeeUserAmount(scope.row)"></el-radio>
  16 + </template>
  17 + </el-table-column>
  18 + <el-table-column prop="acctTypeName" :label="$t('payFeeUserAccount.accountType')"
  19 + align="center"></el-table-column>
  20 + <el-table-column prop="acctName" :label="$t('payFeeUserAccount.accountName')" align="center"></el-table-column>
  21 + <el-table-column :label="$t('payFeeUserAccount.accountAmount')" align="center">
  22 + <template slot-scope="scope">
  23 + {{ scope.row.amount }} {{ $t('payFeeUserAccount.yuan') }}
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column :label="$t('common.operation')" align="center" width="150">
  27 + <template slot-scope="scope">
  28 + <el-button type="primary" size="mini" @click="_openAddUserAmountModal(scope.row)">
  29 + <i class="el-icon-plus"></i>
  30 + {{ $t('payFeeUserAccount.preSave') }}
  31 + </el-button>
  32 + </template>
  33 + </el-table-column>
  34 + </el-table>
  35 + </el-card>
  36 +</template>
  37 +
  38 +<script>
  39 +import { getCommunityId } from '@/api/community/communityApi'
  40 +import { queryCommunityOwnerAccount } from '@/api/fee/batchPayFeeOrderApi'
  41 +
  42 +export default {
  43 + name: 'PayFeeUserAccount',
  44 + data() {
  45 + return {
  46 + loading: false,
  47 + payFeeUserAccountInfo: {
  48 + accountList: [],
  49 + feeId: '',
  50 + ownerId: '',
  51 + communityId: '',
  52 + quanAccount: false,
  53 + selectAccountIds: [],
  54 + integralAmount: '',
  55 + cashAmount: '',
  56 + couponAmount: ''
  57 + }
  58 + }
  59 + },
  60 + created() {
  61 + this.payFeeUserAccountInfo.communityId = getCommunityId()
  62 + },
  63 + methods: {
  64 + async _listUserAccount(page = 1, rows = 20) {
  65 + this.loading = true
  66 + try {
  67 + const params = {
  68 + page,
  69 + row: rows,
  70 + feeId: this.payFeeUserAccountInfo.feeId,
  71 + ownerId: this.payFeeUserAccountInfo.ownerId,
  72 + communityId: this.payFeeUserAccountInfo.communityId
  73 + }
  74 +
  75 + const res = await queryCommunityOwnerAccount(params)
  76 + if (res.code === 0) {
  77 + this.payFeeUserAccountInfo.accountList = res.data || []
  78 + }
  79 + } catch (error) {
  80 + console.error('请求失败:', error)
  81 + } finally {
  82 + this.loading = false
  83 + }
  84 + },
  85 +
  86 + _queryPayFeeUserAccount() {
  87 + this._listUserAccount()
  88 + },
  89 +
  90 + _openAddUserAmountModal(userAccount) {
  91 + window.open(`/#/pages/owner/ownerDetail?ownerId=${userAccount.objId}&currentTab=ownerDetailAccount`)
  92 + },
  93 +
  94 + _computeFeeUserAmount(acct) {
  95 + let _totalUserAmount = 0.0
  96 + let _selectAccount = []
  97 +
  98 + this.payFeeUserAccountInfo.accountList.forEach(item => {
  99 + if (acct.acctId === item.acctId && item.amount != 0) {
  100 + _totalUserAmount += parseFloat(item.amount)
  101 + _selectAccount.push(item)
  102 + this.payFeeUserAccountInfo.cashAmount = item.amount
  103 + }
  104 + })
  105 +
  106 + this.$emit('changeUserAmountPrice', {
  107 + totalUserAmount: _totalUserAmount,
  108 + accountList: this.payFeeUserAccountInfo.accountList,
  109 + integralAmount: 0,
  110 + cashAmount: this.payFeeUserAccountInfo.cashAmount,
  111 + couponAmount: 0,
  112 + selectAccount: _selectAccount
  113 + })
  114 + },
  115 +
  116 + open(params) {
  117 + this.payFeeUserAccountInfo = {
  118 + ...this.payFeeUserAccountInfo,
  119 + ...params
  120 + }
  121 + this._listUserAccount()
  122 + },
  123 +
  124 + refresh() {
  125 + this._listUserAccount()
  126 + },
  127 +
  128 + refreshAndChoose() {
  129 + this.payFeeUserAccountInfo.accountList = []
  130 + this.payFeeUserAccountInfo.selectAccountIds = []
  131 + this._listUserAccount()
  132 + setTimeout(() => {
  133 + this.payFeeUserAccountInfo.accountList.forEach(item => {
  134 + if (item.acctType === '2003') {
  135 + this.payFeeUserAccountInfo.selectAccountIds.push(item.acctId)
  136 + }
  137 + })
  138 + }, 2000)
  139 + },
  140 +
  141 + clear() {
  142 + this.payFeeUserAccountInfo.accountList = []
  143 + this.payFeeUserAccountInfo.selectAccountIds = []
  144 + }
  145 + }
  146 +}
  147 +</script>
  148 +
  149 +<style lang="scss" scoped>
  150 +.account-card {
  151 + margin-bottom: 20px;
  152 +}
  153 +</style>
0 \ No newline at end of file 154 \ No newline at end of file
src/components/fee/prestoreAccount.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('prestoreAccount.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="50%"
  6 + >
  7 + <el-form :model="prestoreAccountInfo" label-width="120px">
  8 + <el-form-item :label="$t('prestoreAccount.accountType')" required>
  9 + <el-select
  10 + v-model="prestoreAccountInfo.acctType"
  11 + style="width: 100%"
  12 + >
  13 + <el-option
  14 + :label="$t('prestoreAccount.selectAccountType')"
  15 + value=""
  16 + disabled
  17 + ></el-option>
  18 + <el-option
  19 + v-for="(type,index) in prestoreAccountInfo.acctTypes"
  20 + :key="index"
  21 + :label="type.name"
  22 + :value="type.statusCd"
  23 + ></el-option>
  24 + </el-select>
  25 + </el-form-item>
  26 +
  27 + <el-form-item :label="$t('prestoreAccount.ownerPhone')" required>
  28 + <el-input
  29 + v-model="prestoreAccountInfo.tel"
  30 + :placeholder="$t('prestoreAccount.ownerPhonePlaceholder')"
  31 + @blur="_changeTel"
  32 + ></el-input>
  33 + </el-form-item>
  34 +
  35 + <el-form-item :label="$t('prestoreAccount.ownerName')" required>
  36 + <el-select
  37 + v-model="prestoreAccountInfo.ownerId"
  38 + style="width: 100%"
  39 + @change="_loadOwnerRooms"
  40 + >
  41 + <el-option
  42 + :label="$t('prestoreAccount.selectOwner')"
  43 + value=""
  44 + disabled
  45 + ></el-option>
  46 + <el-option
  47 + v-for="(owner,index) in prestoreAccountInfo.owners"
  48 + :key="index"
  49 + :label="owner.name"
  50 + :value="owner.ownerId"
  51 + ></el-option>
  52 + </el-select>
  53 + </el-form-item>
  54 +
  55 + <el-form-item
  56 + v-if="prestoreAccountInfo.acctType == '2004' || prestoreAccountInfo.acctType == '2005'"
  57 + :label="$t('prestoreAccount.deductionRoom')"
  58 + required
  59 + >
  60 + <el-select v-model="prestoreAccountInfo.roomId" style="width: 100%">
  61 + <el-option
  62 + :label="$t('prestoreAccount.selectRoom')"
  63 + value=""
  64 + disabled
  65 + ></el-option>
  66 + <el-option
  67 + v-for="(room,index) in prestoreAccountInfo.rooms"
  68 + :key="index"
  69 + :label="room.roomName"
  70 + :value="room.roomId"
  71 + ></el-option>
  72 + </el-select>
  73 + </el-form-item>
  74 +
  75 + <el-form-item :label="$t('prestoreAccount.prestoreAmount')" required>
  76 + <el-input
  77 + v-model="prestoreAccountInfo.amount"
  78 + :placeholder="$t('prestoreAccount.prestoreAmountPlaceholder')"
  79 + ></el-input>
  80 + </el-form-item>
  81 +
  82 + <el-form-item :label="$t('prestoreAccount.paymentMethod')" required>
  83 + <el-select v-model="prestoreAccountInfo.primeRate" style="width: 100%">
  84 + <el-option
  85 + :label="$t('prestoreAccount.selectPaymentMethod')"
  86 + value=""
  87 + disabled
  88 + ></el-option>
  89 + <el-option
  90 + v-for="(item,index) in prestoreAccountInfo.primeRates"
  91 + v-if="item.statusCd != '5' && item.statusCd != '6'"
  92 + :key="index"
  93 + :label="item.name"
  94 + :value="item.statusCd"
  95 + ></el-option>
  96 + </el-select>
  97 + </el-form-item>
  98 +
  99 + <el-form-item :label="$t('prestoreAccount.remark')">
  100 + <el-input
  101 + type="textarea"
  102 + :rows="3"
  103 + v-model="prestoreAccountInfo.remark"
  104 + :placeholder="$t('prestoreAccount.remarkPlaceholder')"
  105 + ></el-input>
  106 + </el-form-item>
  107 + </el-form>
  108 +
  109 + <span slot="footer" class="dialog-footer">
  110 + <el-button @click="dialogVisible = false">{{ $t('prestoreAccount.cancel') }}</el-button>
  111 + <el-button type="primary" @click="savePrestoreAccountInfo">{{ $t('prestoreAccount.save') }}</el-button>
  112 + </span>
  113 + </el-dialog>
  114 +</template>
  115 +
  116 +<script>
  117 +import { ownerPrestoreAccount, queryOwners, queryRoomsByOwner } from '@/api/fee/prestoreAccountApi'
  118 +import { getDict } from '@/api/community/communityApi'
  119 +import { getCommunityId } from '@/api/community/communityApi'
  120 +
  121 +export default {
  122 + name: 'PrestoreAccount',
  123 + data() {
  124 + return {
  125 + dialogVisible: false,
  126 + prestoreAccountInfo: {
  127 + tel: '',
  128 + ownerId: '',
  129 + owners: [],
  130 + amount: '',
  131 + remark: '',
  132 + acctTypes: [],
  133 + acctType: '2003',
  134 + primeRate: '',
  135 + primeRates: [],
  136 + rooms: [],
  137 + roomId: '',
  138 + },
  139 + communityId: ''
  140 + }
  141 + },
  142 + created() {
  143 + this.communityId = getCommunityId()
  144 + this._initPrimeRates()
  145 + },
  146 + methods: {
  147 + open(params) {
  148 + this.dialogVisible = true
  149 + this._initAcctTypes()
  150 +
  151 + if (params) {
  152 + this.prestoreAccountInfo.tel = params.tel || ''
  153 + this.prestoreAccountInfo.ownerId = params.ownerId || ''
  154 + this.prestoreAccountInfo.acctType = params.acctType || '2003'
  155 + this.prestoreAccountInfo.roomId = params.roomId || ''
  156 +
  157 + if (params.tel) {
  158 + this._changeTel()
  159 + this._loadOwnerRooms()
  160 + }
  161 + }
  162 + },
  163 + _initPrimeRates() {
  164 + getDict('pay_fee_detail', 'prime_rate').then(data => {
  165 + this.prestoreAccountInfo.primeRates = data
  166 + })
  167 + },
  168 + _initAcctTypes() {
  169 + getDict('account', 'acct_type').then(data => {
  170 + this.prestoreAccountInfo.acctTypes = data
  171 + })
  172 + },
  173 + prestoreAccountValidate() {
  174 + if (!this.prestoreAccountInfo.ownerId) {
  175 + this.$message.error(this.$t('prestoreAccount.validateOwner'))
  176 + return false
  177 + }
  178 + if (!this.prestoreAccountInfo.amount) {
  179 + this.$message.error(this.$t('prestoreAccount.validateAmount'))
  180 + return false
  181 + }
  182 + if (!this.prestoreAccountInfo.acctType) {
  183 + this.$message.error(this.$t('prestoreAccount.validateAccountType'))
  184 + return false
  185 + }
  186 + if (this.prestoreAccountInfo.remark && this.prestoreAccountInfo.remark.length > 200) {
  187 + this.$message.error(this.$t('prestoreAccount.validateRemark'))
  188 + return false
  189 + }
  190 + return true
  191 + },
  192 + savePrestoreAccountInfo() {
  193 + if (!this.prestoreAccountValidate()) return
  194 +
  195 + const params = {
  196 + ...this.prestoreAccountInfo,
  197 + communityId: this.communityId
  198 + }
  199 +
  200 + ownerPrestoreAccount(params).then(response => {
  201 + if (response.code === 0) {
  202 + this.$message.success(this.$t('prestoreAccount.saveSuccess'))
  203 + this.dialogVisible = false
  204 + this.clearPrestoreAccountInfo()
  205 + this.$emit('save-success')
  206 + } else {
  207 + this.$message.error(response.msg)
  208 + }
  209 + }).catch(error => {
  210 + console.error('请求失败:', error)
  211 + this.$message.error(this.$t('prestoreAccount.saveFailed'))
  212 + })
  213 + },
  214 + clearPrestoreAccountInfo() {
  215 + const primeRates = this.prestoreAccountInfo.primeRates
  216 + this.prestoreAccountInfo = {
  217 + tel: '',
  218 + ownerId: '',
  219 + owners: [],
  220 + amount: '',
  221 + remark: '',
  222 + acctTypes: [],
  223 + acctType: '2003',
  224 + primeRate: '',
  225 + primeRates: primeRates,
  226 + rooms: [],
  227 + roomId: '',
  228 + }
  229 + },
  230 + _changeTel() {
  231 + if (!this.prestoreAccountInfo.tel) return
  232 +
  233 + const params = {
  234 + communityId: this.communityId,
  235 + row: 50,
  236 + page: 1,
  237 + link: this.prestoreAccountInfo.tel,
  238 + ownerTypeCd: '1001'
  239 + }
  240 +
  241 + queryOwners(params).then(response => {
  242 + this.prestoreAccountInfo.owners = response.data
  243 + }).catch(error => {
  244 + console.error('请求失败:', error)
  245 + this.prestoreAccountInfo.owners = []
  246 + })
  247 + },
  248 + _loadOwnerRooms() {
  249 + if (!this.prestoreAccountInfo.ownerId) return
  250 +
  251 + const params = {
  252 + communityId: this.communityId,
  253 + row: 50,
  254 + page: 1,
  255 + ownerId: this.prestoreAccountInfo.ownerId,
  256 + }
  257 +
  258 + queryRoomsByOwner(params).then(response => {
  259 + this.prestoreAccountInfo.rooms = response.rooms
  260 + }).catch(error => {
  261 + console.error('请求失败:', error)
  262 + this.prestoreAccountInfo.rooms = []
  263 + })
  264 + }
  265 + }
  266 +}
  267 +</script>
0 \ No newline at end of file 268 \ No newline at end of file
src/components/fee/prestoreAccountDemo.vue 0 → 100644
  1 +<template>
  2 + <el-button @click="openModal">{{ $t('prestoreAccountDemo.openModal') }}</el-button>
  3 + <prestore-account ref="prestoreAccount"></prestore-account>
  4 +</template>
  5 +
  6 +<script>
  7 +import PrestoreAccount from './prestoreAccount'
  8 +
  9 +export default {
  10 + name: 'PrestoreAccountDemo',
  11 + components: {
  12 + PrestoreAccount
  13 + },
  14 + methods: {
  15 + openModal() {
  16 + this.$refs.prestoreAccount.open({
  17 + tel: '13800138000',
  18 + ownerId: '123',
  19 + acctType: '2003',
  20 + roomId: '456'
  21 + })
  22 + }
  23 + }
  24 +}
  25 +</script>
0 \ No newline at end of file 26 \ No newline at end of file
src/components/fee/refundDepositFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('refundDepositFee.title')"
  4 + :visible.sync="visible"
  5 + width="500px"
  6 + :before-close="handleClose"
  7 + >
  8 + <div class="dialog-content">
  9 + <p>{{ $t('refundDepositFee.confirmText') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  13 + <el-button type="primary" @click="refundDepositFee">{{ $t('common.confirm') }}</el-button>
  14 + </span>
  15 + </el-dialog>
  16 +</template>
  17 +
  18 +<script>
  19 +import { getCommunityId } from '@/api/community/communityApi'
  20 +import { refundFeeDeposit } from '@/api/fee/batchPayFeeOrderApi'
  21 +
  22 +export default {
  23 + name: 'RefundDepositFee',
  24 + data() {
  25 + return {
  26 + visible: false,
  27 + refundDepositFeeInfo: {}
  28 + }
  29 + },
  30 + methods: {
  31 + open(fee) {
  32 + this.refundDepositFeeInfo = { ...fee }
  33 + this.visible = true
  34 + },
  35 +
  36 + handleClose() {
  37 + this.visible = false
  38 + },
  39 +
  40 + async refundDepositFee() {
  41 + try {
  42 + const params = {
  43 + ...this.refundDepositFeeInfo,
  44 + communityId: getCommunityId()
  45 + }
  46 +
  47 + const res = await refundFeeDeposit(params)
  48 + if (res.code === 0) {
  49 + this.$message.success('退押金成功')
  50 + this.visible = false
  51 + this.$emit('success')
  52 + this.$emit('refresh')
  53 + } else {
  54 + this.$message.error(res.msg)
  55 + }
  56 + } catch (error) {
  57 + console.error('请求失败:', error)
  58 + this.$message.error('退押金失败')
  59 + }
  60 + }
  61 + }
  62 +}
  63 +</script>
  64 +
  65 +<style lang="scss" scoped>
  66 +.dialog-content {
  67 + padding: 20px;
  68 + text-align: center;
  69 + font-size: 16px;
  70 + line-height: 1.6;
  71 +}
  72 +</style>
0 \ No newline at end of file 73 \ No newline at end of file
src/components/fee/returnPayFee.vue
1 <template> 1 <template>
2 - <el-dialog  
3 - :title="$t('returnPayFee.refundTitle')" 2 + <el-dialog
  3 + :title="$t('returnPayFee.fillRefundReason')"
4 :visible.sync="visible" 4 :visible.sync="visible"
5 width="50%" 5 width="50%"
6 - @close="handleClose" 6 + center
7 > 7 >
8 - <el-form ref="form" :model="form" :rules="rules" label-width="150px">  
9 - <el-form-item :label="`${$t('returnPayFee.fee')}ID`">  
10 - <el-input v-model="form.detailId" readonly /> 8 + <el-form :model="returnFeeDetailInfo" label-width="120px">
  9 + <el-form-item :label="$t('returnPayFee.paymentId')">
  10 + <el-input v-model="returnFeeDetailInfo.detailId" readonly />
11 </el-form-item> 11 </el-form-item>
12 - <el-form-item :label="`${$t('returnPayFee.cycle')}(${$t('returnPayFee.month')})`">  
13 - <el-input v-model="form.cycles" readonly /> 12 +
  13 + <el-form-item :label="`${$t('returnPayFee.cycle')}(单位月)`">
  14 + <el-input v-model="returnFeeDetailInfo.cycles" readonly />
14 </el-form-item> 15 </el-form-item>
  16 +
15 <el-form-item :label="$t('returnPayFee.receivableAmount')"> 17 <el-form-item :label="$t('returnPayFee.receivableAmount')">
16 - <el-input v-model="form.receivableAmount" readonly /> 18 + <el-input v-model="returnFeeDetailInfo.receivableAmount" readonly />
17 </el-form-item> 19 </el-form-item>
  20 +
18 <el-form-item :label="$t('returnPayFee.receivedAmount')"> 21 <el-form-item :label="$t('returnPayFee.receivedAmount')">
19 - <el-input v-model="form.receivedAmount" readonly /> 22 + <el-input v-model="returnFeeDetailInfo.receivedAmount" readonly />
20 </el-form-item> 23 </el-form-item>
21 - <el-form-item :label="$t('returnPayFee.payTime')">  
22 - <el-input v-model="form.payTime" readonly /> 24 +
  25 + <el-form-item :label="$t('returnPayFee.paymentTime')">
  26 + <el-input v-model="returnFeeDetailInfo.payTime" readonly />
23 </el-form-item> 27 </el-form-item>
24 - <el-form-item  
25 - :label="`<span style='color:red'>*</span>${$t('returnPayFee.refundReason')}`"  
26 - prop="reason"  
27 - > 28 +
  29 + <el-form-item :label="$t('returnPayFee.refundReason')" required>
28 <el-input 30 <el-input
29 - v-model="form.reason"  
30 type="textarea" 31 type="textarea"
31 - :rows="4"  
32 - :placeholder="$t('returnPayFee.inputReason')"  
33 - /> 32 + :rows="3"
  33 + v-model="returnFeeDetailInfo.reason"
  34 + :placeholder="$t('returnPayFee.enterRefundReason')"
  35 + ></el-input>
34 </el-form-item> 36 </el-form-item>
35 </el-form> 37 </el-form>
  38 +
36 <span slot="footer" class="dialog-footer"> 39 <span slot="footer" class="dialog-footer">
37 <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button> 40 <el-button @click="visible = false">{{ $t('common.cancel') }}</el-button>
38 - <el-button type="primary" @click="handleSubmit">{{ $t('returnPayFee.submitRefund') }}</el-button> 41 + <el-button type="primary" @click="submitReturnPayFee">{{ $t('returnPayFee.submitRefund') }}</el-button>
39 </span> 42 </span>
40 </el-dialog> 43 </el-dialog>
41 </template> 44 </template>
42 45
43 <script> 46 <script>
44 -import { saveReturnPayFee } from '@/api/fee/payFeeAuditManageApi'  
45 import { getCommunityId } from '@/api/community/communityApi' 47 import { getCommunityId } from '@/api/community/communityApi'
  48 +import { saveReturnPayFee } from '@/api/fee/propertyFeeApi'
46 49
47 export default { 50 export default {
48 - name: 'ReturnPayFeeModal', 51 + name: 'ReturnPayFee',
49 data() { 52 data() {
50 return { 53 return {
51 visible: false, 54 visible: false,
52 - form: { 55 + returnFeeDetailInfo: {
53 detailId: '', 56 detailId: '',
54 cycles: '', 57 cycles: '',
55 receivableAmount: '', 58 receivableAmount: '',
@@ -61,47 +64,63 @@ export default { @@ -61,47 +64,63 @@ export default {
61 feeTypeCd: '', 64 feeTypeCd: '',
62 configId: '' 65 configId: ''
63 }, 66 },
64 - rules: {  
65 - reason: [  
66 - { required: true, message: this.$t('returnPayFee.reasonRequired'), trigger: 'blur' },  
67 - { min: 1, max: 200, message: this.$t('returnPayFee.reasonLength'), trigger: 'blur' }  
68 - ]  
69 - } 67 + communityId: ''
70 } 68 }
71 }, 69 },
  70 + created() {
  71 + this.communityId = getCommunityId()
  72 + },
72 methods: { 73 methods: {
73 - open(row) {  
74 - this.form = {  
75 - detailId: row.detailId,  
76 - cycles: row.cycles,  
77 - receivableAmount: row.receivableAmount,  
78 - receivedAmount: row.receivedAmount,  
79 - payTime: row.createTime,  
80 - reason: '',  
81 - communityId: row.communityId,  
82 - feeId: row.feeId,  
83 - feeTypeCd: row.feeTypeCd,  
84 - configId: row.configId 74 + open(params) {
  75 + this.returnFeeDetailInfo = {
  76 + ...this.returnFeeDetailInfo,
  77 + communityId: params.communityId || this.communityId,
  78 + payTime: params.createTime,
  79 + detailId: params.detailId,
  80 + cycles: params.cycles,
  81 + receivableAmount: params.receivableAmount,
  82 + receivedAmount: params.receivedAmount,
  83 + feeId: params.mainFeeInfo.feeId || '',
  84 + feeTypeCd: params.mainFeeInfo.feeTypeCd || '',
  85 + configId: params.mainFeeInfo.configId || '',
  86 + remark: params.remark || ''
85 } 87 }
86 this.visible = true 88 this.visible = true
87 }, 89 },
88 - handleClose() {  
89 - this.$refs.form.resetFields() 90 + returnPayFeeValidate() {
  91 + if (!this.returnFeeDetailInfo.reason) {
  92 + this.$message.error(this.$t('returnPayFee.refundReasonRequired'))
  93 + return false
  94 + }
  95 + if (this.returnFeeDetailInfo.reason.length > 200) {
  96 + this.$message.error(this.$t('returnPayFee.refundReasonTooLong'))
  97 + return false
  98 + }
  99 + return true
90 }, 100 },
91 - async handleSubmit() { 101 + async submitReturnPayFee() {
  102 + if (!this.returnPayFeeValidate()) return
  103 +
92 try { 104 try {
93 - await this.$refs.form.validate()  
94 - this.form.communityId = getCommunityId()  
95 - await saveReturnPayFee(this.form)  
96 - this.$message.success(this.$t('common.operateSuccess'))  
97 - this.$emit('success')  
98 - this.visible = false  
99 - } catch (error) {  
100 - if (error.message) {  
101 - this.$message.error(error.message) 105 + const res = await saveReturnPayFee(this.returnFeeDetailInfo)
  106 + if (res.code === 0) {
  107 + this.$message.success(this.$t('common.operateSuccess'))
  108 + this.visible = false
  109 + this.$emit('success')
  110 + } else {
  111 + this.$message.error(res.msg || this.$t('common.operateFailed'))
102 } 112 }
  113 + } catch (error) {
  114 + console.error('提交退费申请失败:', error)
  115 + this.$message.error(this.$t('common.operateFailed'))
103 } 116 }
104 } 117 }
105 } 118 }
106 } 119 }
107 -</script>  
108 \ No newline at end of file 120 \ No newline at end of file
  121 +</script>
  122 +
  123 +<style scoped>
  124 +.el-input, .el-textarea {
  125 + width: 100%;
  126 +}
  127 +</style>
109 \ No newline at end of file 128 \ No newline at end of file
src/components/fee/reviewApplyRoomDiscount.vue
@@ -102,6 +102,7 @@ @@ -102,6 +102,7 @@
102 //import { getDict } from '@/api/community/communityApi' 102 //import { getDict } from '@/api/community/communityApi'
103 import { queryFeeDiscount, updateReviewApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi' 103 import { queryFeeDiscount, updateReviewApplyRoomDiscount } from '@/api/fee/applyRoomDiscountManageApi'
104 import ViewImage from '@/components/system/viewImage' 104 import ViewImage from '@/components/system/viewImage'
  105 +import { getCommunityId } from '@/api/community/communityApi'
105 106
106 export default { 107 export default {
107 name: 'ReviewApplyRoomDiscount', 108 name: 'ReviewApplyRoomDiscount',
@@ -182,7 +183,7 @@ export default { @@ -182,7 +183,7 @@ export default {
182 this.form = { 183 this.form = {
183 ...this.form, 184 ...this.form,
184 ...data, 185 ...data,
185 - communityId: this.$store.getters.communityId, 186 + communityId: getCommunityId(),
186 selectedFees: [], 187 selectedFees: [],
187 refundAmount: '' 188 refundAmount: ''
188 } 189 }
src/components/fee/roomCreateFeeAdd.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('roomCreateFeeAdd.title')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="formData" label-width="120px">
  9 + <el-form-item :label="$t('roomCreateFeeAdd.location')">
  10 + <el-input
  11 + v-model="formData.locationTypeCdName"
  12 + disabled
  13 + :placeholder="$t('roomCreateFeeAdd.locationPlaceholder')"
  14 + ></el-input>
  15 + </el-form-item>
  16 +
  17 + <el-form-item :label="$t('roomCreateFeeAdd.feeType')" prop="feeTypeCd">
  18 + <el-select
  19 + v-model="formData.feeTypeCd"
  20 + @change="handleFeeTypeChange"
  21 + :placeholder="$t('roomCreateFeeAdd.feeTypePlaceholder')"
  22 + style="width: 100%"
  23 + >
  24 + <template v-for="item in feeTypeOptions">
  25 + <el-option
  26 + v-if="item.statusCd !='888800010017'"
  27 + :key="item.statusCd"
  28 + :label="item.name"
  29 + :value="item.statusCd"
  30 + ></el-option>
  31 + </template>
  32 + </el-select>
  33 + </el-form-item>
  34 +
  35 + <el-form-item
  36 + v-if="formData.feeTypeCd"
  37 + :label="$t('roomCreateFeeAdd.feeItem')"
  38 + prop="configId"
  39 + >
  40 + <el-select
  41 + v-model="formData.configId"
  42 + @change="handleConfigChange"
  43 + :placeholder="$t('roomCreateFeeAdd.feeItemPlaceholder')"
  44 + style="width: 100%"
  45 + >
  46 + <el-option
  47 + v-for="item in feeConfigOptions"
  48 + :key="item.configId"
  49 + :label="item.feeName"
  50 + :value="item.configId"
  51 + ></el-option>
  52 + </el-select>
  53 + </el-form-item>
  54 +
  55 + <el-form-item
  56 + v-if="formData.computingFormula == '4004'"
  57 + :label="$t('roomCreateFeeAdd.amount')"
  58 + prop="amount"
  59 + >
  60 + <el-input
  61 + v-model="formData.amount"
  62 + :placeholder="$t('roomCreateFeeAdd.amountPlaceholder')"
  63 + ></el-input>
  64 + </el-form-item>
  65 +
  66 + <el-form-item :label="$t('roomCreateFeeAdd.startTime')" prop="startTime">
  67 + <el-date-picker
  68 + v-model="formData.startTime"
  69 + type="date"
  70 + :placeholder="$t('roomCreateFeeAdd.startTimePlaceholder')"
  71 + value-format="yyyy-MM-dd"
  72 + @change="validateStartTime"
  73 + ></el-date-picker>
  74 + </el-form-item>
  75 +
  76 + <el-form-item :label="$t('roomCreateFeeAdd.endTime')" prop="endTime">
  77 + <el-date-picker
  78 + v-model="formData.endTime"
  79 + type="date"
  80 + :placeholder="$t('roomCreateFeeAdd.endTimePlaceholder')"
  81 + value-format="yyyy-MM-dd"
  82 + @change="validateEndTime"
  83 + ></el-date-picker>
  84 + </el-form-item>
  85 +
  86 + <el-form-item
  87 + v-show="formData.computingFormula == '1102'"
  88 + :label="$t('roomCreateFeeAdd.rateCycle')"
  89 + prop="rateCycle"
  90 + >
  91 + <el-input
  92 + v-model="formData.rateCycle"
  93 + :placeholder="$t('roomCreateFeeAdd.rateCyclePlaceholder')"
  94 + ></el-input>
  95 + </el-form-item>
  96 +
  97 + <el-form-item
  98 + v-show="formData.computingFormula == '1102'"
  99 + :label="$t('roomCreateFeeAdd.rate')"
  100 + prop="rate"
  101 + >
  102 + <el-input
  103 + v-model="formData.rate"
  104 + :placeholder="$t('roomCreateFeeAdd.ratePlaceholder')"
  105 + ></el-input>
  106 + </el-form-item>
  107 +
  108 + <el-form-item
  109 + v-show="formData.computingFormula == '1102'"
  110 + :label="$t('roomCreateFeeAdd.rateStartTime')"
  111 + prop="rateStartTime"
  112 + >
  113 + <el-date-picker
  114 + v-model="formData.rateStartTime"
  115 + type="date"
  116 + :placeholder="$t('roomCreateFeeAdd.rateStartTimePlaceholder')"
  117 + value-format="yyyy-MM-dd"
  118 + ></el-date-picker>
  119 + </el-form-item>
  120 + </el-form>
  121 +
  122 + <span slot="footer" class="dialog-footer">
  123 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  124 + <el-button type="primary" @click="handleSubmit">{{ $t('common.submit') }}</el-button>
  125 + </span>
  126 + </el-dialog>
  127 +</template>
  128 +
  129 +<script>
  130 +import { saveRoomCreateFee, listFeeConfigs } from '@/api/fee/roomCreateFeeAddApi'
  131 +import { getDict, getCommunityId } from '@/api/community/communityApi'
  132 +
  133 +export default {
  134 + name: 'RoomCreateFeeAdd',
  135 + data() {
  136 + return {
  137 + visible: false,
  138 + formData: {
  139 + feeTypeCds: [],
  140 + feeConfigs: [],
  141 + locationTypeCd: '',
  142 + locationObjId: '',
  143 + feeTypeCd: '',
  144 + configId: '',
  145 + locationTypeCdName: '',
  146 + startTime: '',
  147 + endTime: '2050-01-01',
  148 + computingFormula: '',
  149 + amount: '',
  150 + rateCycle: '',
  151 + rate: '',
  152 + rateStartTime: '',
  153 + feeFlag: ''
  154 + },
  155 + feeTypeOptions: [],
  156 + feeConfigOptions: [],
  157 + rules: {
  158 + locationObjId: [
  159 + { required: true, message: this.$t('roomCreateFeeAdd.validate.locationRequired'), trigger: 'blur' }
  160 + ],
  161 + feeTypeCd: [
  162 + { required: true, message: this.$t('roomCreateFeeAdd.validate.feeTypeRequired'), trigger: 'change' }
  163 + ],
  164 + configId: [
  165 + { required: true, message: this.$t('roomCreateFeeAdd.validate.feeItemRequired'), trigger: 'change' }
  166 + ],
  167 + startTime: [
  168 + { required: true, message: this.$t('roomCreateFeeAdd.validate.startTimeRequired'), trigger: 'blur' }
  169 + ]
  170 + }
  171 + }
  172 + },
  173 + methods: {
  174 + open(room) {
  175 + this.resetForm()
  176 + this.formData.locationObjId = room.roomId
  177 + this.formData.locationTypeCdName = `${room.floorNum}-${room.unitNum}-${room.roomNum}(${room.ownerName})`
  178 +
  179 + if (room.roomName) {
  180 + this.formData.locationTypeCdName = room.roomName
  181 + }
  182 +
  183 + this.formData.roomType = room.roomType
  184 + if (room.roomType === '2020602') {
  185 + this.formData.locationTypeCdName = `${room.floorNum}-${room.roomNum}(${room.ownerName})`
  186 + }
  187 +
  188 + this.loadFeeTypes()
  189 + this.visible = true
  190 + },
  191 +
  192 + loadFeeTypes() {
  193 + getDict('pay_fee_config', 'fee_type_cd').then(data => {
  194 + this.feeTypeOptions = data.filter(item =>
  195 + item.statusCd !== '888800010015' && item.statusCd !== '888800010016'
  196 + )
  197 + })
  198 + },
  199 +
  200 + handleFeeTypeChange(value) {
  201 + if (value === '888800010006' || value === '888800010014') {
  202 + this.formData.startTime = this.$dayjs().format('YYYY-MM-DD')
  203 + this.formData.endTime = this.$dayjs().add(1, 'month').format('YYYY-MM-DD')
  204 + }
  205 +
  206 + this.formData.configId = ''
  207 + this.loadFeeConfigs(value)
  208 + },
  209 +
  210 + loadFeeConfigs(feeTypeCd) {
  211 + listFeeConfigs({
  212 + page: 1,
  213 + row: 500,
  214 + communityId: getCommunityId(),
  215 + feeTypeCd,
  216 + isDefault: 'F',
  217 + state: 'Y'
  218 + }).then(response => {
  219 + this.feeConfigOptions = response.data.feeConfigs
  220 + })
  221 + },
  222 +
  223 + handleConfigChange(configId) {
  224 + if (this.formData.feeTypeCd !== '888800010006' &&
  225 + this.formData.feeTypeCd !== '888800010014' &&
  226 + this.formData.feeFlag === '1003006') {
  227 + this.formData.endTime = ''
  228 + }
  229 +
  230 + const config = this.feeConfigOptions.find(item => item.configId === configId)
  231 + if (config) {
  232 + this.formData.feeFlag = config.feeFlag
  233 + this.formData.computingFormula = config.computingFormula
  234 + }
  235 + },
  236 +
  237 + validateStartTime(value) {
  238 + if (!this.formData.feeFlag && !this.formData.feeTypeCd) {
  239 + const start = new Date(value)
  240 + const end = new Date(this.formData.endTime)
  241 + if (start >= end) {
  242 + this.$message.error(this.$t('roomCreateFeeAdd.validate.startBeforeEnd'))
  243 + this.formData.startTime = ''
  244 + }
  245 + }
  246 + },
  247 +
  248 + validateEndTime(value) {
  249 + const start = new Date(this.formData.startTime)
  250 + const end = new Date(value)
  251 + if (start >= end) {
  252 + this.$message.error(this.$t('roomCreateFeeAdd.validate.endAfterStart'))
  253 + this.formData.endTime = ''
  254 + }
  255 + },
  256 +
  257 + handleSubmit() {
  258 + this.$refs.form.validate(valid => {
  259 + if (!valid) return
  260 +
  261 + if (this.formData.feeTypeCd !== '888800010006' && this.formData.feeFlag !== '1003006') {
  262 + if (!this.formData.endTime) {
  263 + this.$message.error(this.$t('roomCreateFeeAdd.validate.endTimeRequired'))
  264 + return
  265 + }
  266 + }
  267 +
  268 + const params = {
  269 + ...this.formData,
  270 + communityId: getCommunityId()
  271 + }
  272 +
  273 + saveRoomCreateFee(params).then(() => {
  274 + this.$message.success(this.$t('roomCreateFeeAdd.successMessage'))
  275 + this.$emit('success')
  276 + this.handleClose()
  277 + }).catch(error => {
  278 + this.$message.error(error.message)
  279 + })
  280 + })
  281 + },
  282 +
  283 + resetForm() {
  284 + if (this.$refs.form) {
  285 + this.$refs.form.resetFields()
  286 + }
  287 + this.formData = {
  288 + feeTypeCds: [],
  289 + feeConfigs: [],
  290 + locationTypeCd: '',
  291 + locationObjId: '',
  292 + feeTypeCd: '',
  293 + configId: '',
  294 + locationTypeCdName: '',
  295 + startTime: '',
  296 + endTime: '2050-01-01',
  297 + computingFormula: '',
  298 + amount: '',
  299 + rateCycle: '',
  300 + rate: '',
  301 + rateStartTime: '',
  302 + feeFlag: ''
  303 + }
  304 + },
  305 +
  306 + handleClose() {
  307 + this.visible = false
  308 + this.resetForm()
  309 + }
  310 + }
  311 +}
  312 +</script>
0 \ No newline at end of file 313 \ No newline at end of file
src/components/fee/roomCreateFeeAddDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{ $t('roomCreateFeeAddDemo.openModal') }}</el-button>
  4 + <room-create-fee-add ref="roomCreateFeeAdd" @success="handleSuccess"></room-create-fee-add>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import RoomCreateFeeAdd from './roomCreateFeeAdd'
  10 +
  11 +export default {
  12 + name: 'RoomCreateFeeAddDemo',
  13 + components: {
  14 + RoomCreateFeeAdd
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.roomCreateFeeAdd.open({
  19 + roomId: '123',
  20 + floorNum: '1',
  21 + unitNum: '2',
  22 + roomNum: '101',
  23 + ownerName: 'Test Owner',
  24 + roomType: '2020601'
  25 + })
  26 + },
  27 + handleSuccess() {
  28 + this.$message.success(this.$t('roomCreateFeeAddDemo.successMessage'))
  29 + }
  30 + }
  31 +}
  32 +</script>
0 \ No newline at end of file 33 \ No newline at end of file
src/components/fee/roomTreeDiv.vue deleted
1 -<template>  
2 - <el-card class="tree-card">  
3 - <el-tree  
4 - :data="treeData"  
5 - :props="defaultProps"  
6 - node-key="id"  
7 - default-expand-all  
8 - highlight-current  
9 - @node-click="handleNodeClick"  
10 - :expand-on-click-node="false">  
11 - <span class="custom-tree-node" slot-scope="{ node, data }">  
12 - <span>{{ node.label }}</span>  
13 - </span>  
14 - </el-tree>  
15 - </el-card>  
16 -</template>  
17 -  
18 -<script>  
19 -import { queryUnits, queryRoomsTree } from '@/api/property/roomApi'  
20 -import { getCommunityId } from '@/api/community/communityApi'  
21 -  
22 -export default {  
23 - name: 'RoomTreeDiv',  
24 - data() {  
25 - return {  
26 - treeData: [],  
27 - defaultProps: {  
28 - children: 'children',  
29 - label: 'text'  
30 - },  
31 - communityId: ''  
32 - }  
33 - },  
34 - created() {  
35 - this.communityId = getCommunityId()  
36 - this.loadTreeData()  
37 - },  
38 - methods: {  
39 - async loadTreeData() {  
40 - try {  
41 - const units = await this.getUnits()  
42 - this.treeData = this.buildTreeData(units)  
43 - } catch (error) {  
44 - console.error('加载树数据失败:', error)  
45 - }  
46 - },  
47 - async getUnits() {  
48 - const params = {  
49 - communityId: this.communityId  
50 - }  
51 - const response = await queryUnits(params)  
52 - return response.data  
53 - },  
54 - buildTreeData(units) {  
55 - const floors = {}  
56 -  
57 - // 按楼层分组  
58 - units.forEach(unit => {  
59 - if (!floors[unit.floorId]) {  
60 - floors[unit.floorId] = {  
61 - id: `f_${unit.floorId}`,  
62 - floorId: unit.floorId,  
63 - floorNum: unit.floorNum,  
64 - text: `${unit.floorNum}栋`,  
65 - icon: 'el-icon-office-building',  
66 - children: []  
67 - }  
68 - }  
69 -  
70 - floors[unit.floorId].children.push({  
71 - id: `u_${unit.unitId}`,  
72 - unitId: unit.unitId,  
73 - text: `${unit.unitNum}单元`,  
74 - icon: 'el-icon-collection',  
75 - children: []  
76 - })  
77 - })  
78 -  
79 - return Object.values(floors)  
80 - },  
81 - async handleNodeClick(data) {  
82 - if (data.id.startsWith('u_')) {  
83 - await this.loadRooms(data.unitId, data)  
84 - } else if (data.id.startsWith('r_')) {  
85 - this.$emit('selectRoom', {  
86 - roomId: data.roomId,  
87 - roomName: data.text  
88 - })  
89 - }  
90 - },  
91 - async loadRooms(unitId, node) {  
92 - try {  
93 - if (node.children && node.children.length > 0) return  
94 -  
95 - const params = {  
96 - unitId: unitId,  
97 - communityId: this.communityId,  
98 - page: 1,  
99 - row: 1000  
100 - }  
101 -  
102 - const response = await queryRoomsTree(params)  
103 - const rooms = response.data.rooms || []  
104 -  
105 - rooms.forEach(room => {  
106 - let label = room.roomNum  
107 - if (room.ownerName) {  
108 - label += `(${room.ownerName})`  
109 - }  
110 -  
111 - node.children.push({  
112 - id: `r_${room.roomId}`,  
113 - roomId: room.roomId,  
114 - text: label,  
115 - icon: 'el-icon-house',  
116 - roomName: `${room.floorNum}-${room.unitNum}-${room.roomNum}`  
117 - })  
118 - })  
119 -  
120 - // 默认选择第一个房间  
121 - if (rooms.length > 0) {  
122 - const firstRoom = rooms[0]  
123 - this.$emit('selectRoom', {  
124 - roomId: firstRoom.roomId,  
125 - roomName: `${firstRoom.floorNum}-${firstRoom.unitNum}-${firstRoom.roomNum}`  
126 - })  
127 - }  
128 - } catch (error) {  
129 - console.error('加载房间数据失败:', error)  
130 - }  
131 - }  
132 - }  
133 -}  
134 -</script>  
135 -  
136 -<style lang="scss" scoped>  
137 -.tree-card {  
138 - height: 100%;  
139 - /deep/ .el-card__body {  
140 - padding: 10px;  
141 - }  
142 - .custom-tree-node {  
143 - flex: 1;  
144 - display: flex;  
145 - align-items: center;  
146 - justify-content: space-between;  
147 - font-size: 14px;  
148 - padding-right: 8px;  
149 - }  
150 -}  
151 -</style>  
152 \ No newline at end of file 0 \ No newline at end of file
src/components/fee/simplifyCallable.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top">
  4 + <el-col :span="24" class="text-right">
  5 + <el-button
  6 + type="primary"
  7 + size="small"
  8 + v-if="simplifyCallableInfo.roomId"
  9 + @click="_openWritePrintOweFeeCallableModal"
  10 + >
  11 + <i class="el-icon-plus"></i>
  12 + {{ $t('simplifyCallable.register') }}
  13 + </el-button>
  14 + <el-button
  15 + type="primary"
  16 + size="small"
  17 + v-if="simplifyCallableInfo.roomId"
  18 + @click="_openAddOweFeeCallableModal"
  19 + >
  20 + <i class="el-icon-plus"></i>
  21 + {{ $t('simplifyCallable.callable') }}
  22 + </el-button>
  23 + <el-button
  24 + type="primary"
  25 + size="small"
  26 + v-if="simplifyCallableInfo.roomId"
  27 + @click="_printOwnOrder"
  28 + >
  29 + <i class="el-icon-plus"></i>
  30 + {{ $t('simplifyCallable.callableOrder') }}
  31 + </el-button>
  32 + </el-col>
  33 + </el-row>
  34 + <div>
  35 + <el-table
  36 + :data="simplifyCallableInfo.callables"
  37 + style="margin-top:10px"
  38 + border
  39 + stripe
  40 + >
  41 + <el-table-column prop="ofcId" :label="$t('simplifyCallable.id')" align="center"></el-table-column>
  42 + <el-table-column prop="ownerName" :label="$t('simplifyCallable.ownerName')" align="center"></el-table-column>
  43 + <el-table-column prop="payerObjName" :label="$t('simplifyCallable.payerObjName')" align="center"></el-table-column>
  44 + <el-table-column prop="feeName" :label="$t('simplifyCallable.feeName')" align="center"></el-table-column>
  45 + <el-table-column prop="amountdOwed" :label="$t('simplifyCallable.amount')" align="center"></el-table-column>
  46 + <el-table-column :label="$t('simplifyCallable.timePeriod')" align="center">
  47 + <template slot-scope="scope">
  48 + {{scope.row.startTime}}<br>~{{scope.row.endTime}}
  49 + </template>
  50 + </el-table-column>
  51 + <el-table-column prop="callableWayName" :label="$t('simplifyCallable.callableWay')" align="center"></el-table-column>
  52 + <el-table-column prop="staffName" :label="$t('simplifyCallable.staffName')" align="center"></el-table-column>
  53 + <el-table-column prop="stateName" :label="$t('simplifyCallable.status')" align="center"></el-table-column>
  54 + <el-table-column prop="remark" :label="$t('simplifyCallable.remark')" align="center">
  55 + <template slot-scope="scope">
  56 + <div class="textAuto" style="max-width: 200px;">{{scope.row.remark}}</div>
  57 + </template>
  58 + </el-table-column>
  59 + <el-table-column prop="createTime" :label="$t('simplifyCallable.createTime')" align="center"></el-table-column>
  60 + <el-table-column :label="$t('simplifyCallable.actions')" align="center">
  61 + <template slot-scope="scope">
  62 + <el-button-group>
  63 + <el-button size="mini" @click="_openDeleteOweFeeCallableModel(scope.row)">
  64 + {{ $t('simplifyCallable.delete') }}
  65 + </el-button>
  66 + </el-button-group>
  67 + </template>
  68 + </el-table-column>
  69 + </el-table>
  70 + <el-pagination
  71 + @current-change="handleCurrentChange"
  72 + :current-page="currentPage"
  73 + :page-size="pageSize"
  74 + layout="total, prev, pager, next"
  75 + :total="total">
  76 + </el-pagination>
  77 + </div>
  78 + <write-owe-fee-callable ref="writeOweFeeCallable"></write-owe-fee-callable>
  79 + <delete-owe-fee-callable ref="deleteOweFeeCallable"></delete-owe-fee-callable>
  80 + </div>
  81 +</template>
  82 +
  83 +<script>
  84 +import { getCommunityId } from '@/api/community/communityApi'
  85 +import { listOweFeeCallable } from '@/api/fee/simplifyCallableApi'
  86 +import WriteOweFeeCallable from './writeOweFeeCallable'
  87 +import DeleteOweFeeCallable from './deleteOweFeeCallable'
  88 +
  89 +export default {
  90 + name: 'SimplifyCallable',
  91 + components: {
  92 + WriteOweFeeCallable,
  93 + DeleteOweFeeCallable
  94 + },
  95 + data() {
  96 + return {
  97 + DEFAULT_PAGE: 1,
  98 + DEFAULT_ROWS: 10,
  99 + simplifyCallableInfo: {
  100 + callables: [],
  101 + ownerId: '',
  102 + roomId: '',
  103 + roomName: '',
  104 + total: 0,
  105 + records: 0
  106 + },
  107 + currentPage: 1,
  108 + pageSize: 10,
  109 + total: 0
  110 + }
  111 + },
  112 + created() {
  113 + this._initEvent()
  114 + },
  115 + methods: {
  116 + _initEvent() {
  117 + this.$on('switch', this.handleSwitch)
  118 + this.$on('listOwnerData', this._listSimplifyCallable)
  119 + },
  120 + handleSwitch(param) {
  121 + if (!param.roomId) return
  122 + this.clearSimplifyCallableInfo()
  123 + Object.assign(this.simplifyCallableInfo, param)
  124 + this._listSimplifyCallable(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  125 + },
  126 + handleCurrentChange(val) {
  127 + this._listSimplifyCallable(val, this.DEFAULT_ROWS)
  128 + },
  129 + async _listSimplifyCallable(page, row) {
  130 + try {
  131 + const res = await listOweFeeCallable({
  132 + page,
  133 + row,
  134 + payerObjId: this.simplifyCallableInfo.roomId,
  135 + communityId: getCommunityId()
  136 + })
  137 + this.simplifyCallableInfo.total = res.total
  138 + this.simplifyCallableInfo.records = res.records
  139 + this.simplifyCallableInfo.callables = res.data
  140 + this.total = res.records
  141 + } catch (error) {
  142 + console.error('Request failed:', error)
  143 + }
  144 + },
  145 + clearSimplifyCallableInfo() {
  146 + this.simplifyCallableInfo = {
  147 + callables: [],
  148 + ownerId: '',
  149 + roomId: '',
  150 + roomName: '',
  151 + total: 0,
  152 + records: 0
  153 + }
  154 + },
  155 + _printOwnOrder() {
  156 + window.open(`/print.html#/pages/property/printOweFee?payObjId=${this.simplifyCallableInfo.roomId}&payObjType=3333&payObjName=${this.simplifyCallableInfo.roomName}`)
  157 + },
  158 + _openWritePrintOweFeeCallableModal() {
  159 + if (!this.simplifyCallableInfo.roomId) {
  160 + this.$message.warning(this.$t('simplifyCallable.noRoomSelected'))
  161 + return
  162 + }
  163 + this.$refs.writeOweFeeCallable.open({
  164 + roomId: this.simplifyCallableInfo.roomId,
  165 + roomName: this.simplifyCallableInfo.roomName
  166 + })
  167 + },
  168 + _openAddOweFeeCallableModal() {
  169 + this.$router.push(`/fee/roomOweFeeCallable?roomId=${this.simplifyCallableInfo.roomId}`)
  170 + },
  171 + _openDeleteOweFeeCallableModel(oweFeeCallable) {
  172 + this.$refs.deleteOweFeeCallable.open(oweFeeCallable)
  173 + },
  174 + open(params) {
  175 + this.handleSwitch(params)
  176 + }
  177 + }
  178 +}
  179 +</script>
  180 +
  181 +<style scoped>
  182 +.margin-top {
  183 + margin-top: 15px;
  184 +}
  185 +.text-right {
  186 + text-align: right;
  187 +}
  188 +.textAuto {
  189 + white-space: nowrap;
  190 + overflow: hidden;
  191 + text-overflow: ellipsis;
  192 +}
  193 +</style>
0 \ No newline at end of file 194 \ No newline at end of file
src/components/fee/simplifyCallableDemo.vue 0 → 100644
  1 +<template>
  2 + <simplify-callable ref="simplifyCallable"></simplify-callable>
  3 +</template>
  4 +
  5 +<script>
  6 +import SimplifyCallable from './simplifyCallable'
  7 +
  8 +export default {
  9 + name: 'SimplifyCallableDemo',
  10 + components: {
  11 + SimplifyCallable
  12 + },
  13 + mounted() {
  14 + this.$refs.simplifyCallable.$emit('switch', {
  15 + roomId: '123',
  16 + roomName: 'Test Room',
  17 + ownerId: '456'
  18 + })
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/fee/simplifyFeeReceipt.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top-lg">
  4 + <el-col :span="4" class="padding-right-xs padding-left-xl">
  5 + <el-select v-model="simplifyFeeReceiptInfo.objType" size="small" @change="_changeSimplifyFeeReceiptFeeTypeCd"
  6 + :placeholder="$t('simplifyFeeReceipt.selectFeeType')">
  7 + <el-option v-for="(item, index) in simplifyFeeReceiptInfo.objTypes" :key="index" :label="item.name"
  8 + :value="item.statusCd"></el-option>
  9 + </el-select>
  10 + </el-col>
  11 + <el-col :span="4" class="padding-right-xs padding-left-xl" v-if="simplifyFeeReceiptInfo.objType == '6666'">
  12 + <el-select v-model="simplifyFeeReceiptInfo.carId" size="small" @change="changeSimplifyFeeReceiptCar"
  13 + :placeholder="$t('simplifyFeeReceipt.selectCar')">
  14 + <el-option v-for="(item, index) in simplifyFeeReceiptInfo.ownerCars" :key="index" :label="item.carNum"
  15 + :value="item.carId"></el-option>
  16 + </el-select>
  17 + </el-col>
  18 + <el-col :span="4" class="padding-right-xs padding-left-xl" v-else-if="simplifyFeeReceiptInfo.objType == '7777'">
  19 + <el-select v-model="simplifyFeeReceiptInfo.contractId" size="small" @change="changeSimplifyFeeReceiptCar"
  20 + :placeholder="$t('simplifyFeeReceipt.selectContract')">
  21 + <el-option v-for="(item, index) in simplifyFeeReceiptInfo.ownerContracts" :key="index"
  22 + :label="item.contractCode" :value="item.contractId"></el-option>
  23 + </el-select>
  24 + </el-col>
  25 + <el-col :span="4" class="padding-right-xs padding-left-xl" v-if="simplifyFeeReceiptInfo.objType != '7777'">
  26 + <el-select v-model="simplifyFeeReceiptInfo.ownerFlag" size="small" @change="_queryFeeReceiptMethod">
  27 + <el-option
  28 + :label="$t('simplifyFeeReceipt.current') + (simplifyFeeReceiptInfo.objType == '6666' ? $t('simplifyFeeReceipt.car') : $t('simplifyFeeReceipt.room'))"
  29 + value="F"></el-option>
  30 + <el-option
  31 + :label="$t('simplifyFeeReceipt.all') + (simplifyFeeReceiptInfo.objType == '6666' ? $t('simplifyFeeReceipt.car') : $t('simplifyFeeReceipt.room'))"
  32 + value="T"></el-option>
  33 + </el-select>
  34 + </el-col>
  35 + <el-col :span="4" class="padding-right-xs padding-left-xl">
  36 + <el-input v-model="simplifyFeeReceiptInfo.receiptCode" size="small"
  37 + :placeholder="$t('simplifyFeeReceipt.receiptCode')"></el-input>
  38 + </el-col>
  39 + <el-col :span="4" class="padding-right-xs padding-left-xl">
  40 + <el-button type="primary" size="small" @click="_queryFeeReceiptMethod">
  41 + {{ $t('simplifyFeeReceipt.query') }}
  42 + </el-button>
  43 + </el-col>
  44 + <el-col :span="8" class="text-right padding-right-lg">
  45 + <el-button type="primary" size="small" @click="_printFeeReceipt('OFF')">
  46 + {{ $t('simplifyFeeReceipt.print') }}
  47 + </el-button>
  48 + <el-button type="primary" size="small" @click="_printFeeReceipt('ON')">
  49 + {{ $t('simplifyFeeReceipt.mergePrint') }}
  50 + </el-button>
  51 + <el-button type="primary" size="small" @click="_printFeeSmallReceipt">
  52 + {{ $t('simplifyFeeReceipt.printSmall') }}
  53 + </el-button>
  54 + <el-button type="primary" size="small" @click="_printApplyFeeReceipt">
  55 + {{ $t('simplifyFeeReceipt.apply') }}
  56 + </el-button>
  57 + </el-col>
  58 + </el-row>
  59 + <div class="margin-top">
  60 + <el-table :data="simplifyFeeReceiptInfo.feeReceipts" border stripe>
  61 + <el-table-column type="selection" width="55" align="center"></el-table-column>
  62 + <el-table-column prop="receiptCode" :label="$t('simplifyFeeReceipt.receiptCode')"
  63 + align="center"></el-table-column>
  64 + <el-table-column :label="$t('simplifyFeeReceipt.feeType')" align="center">
  65 + <template slot-scope="scope">
  66 + {{ _getFeeObjName(scope.row.objType) }}{{ $t('simplifyFeeReceipt.fee') }}
  67 + </template>
  68 + </el-table-column>
  69 + <el-table-column prop="objName" :label="_getFeeObjName(simplifyFeeReceiptInfo.objType)"
  70 + align="center"></el-table-column>
  71 + <el-table-column prop="payObjName" :label="$t('simplifyFeeReceipt.owner')" align="center"></el-table-column>
  72 + <el-table-column prop="feeName" :label="$t('simplifyFeeReceipt.feeItem')" align="center"></el-table-column>
  73 + <el-table-column :label="$t('simplifyFeeReceipt.timePeriod')" align="center">
  74 + <template slot-scope="scope">
  75 + {{ dateFormat(scope.row.startTime) }}~<br>
  76 + <span v-if="scope.row.startTime >= scope.row.endTime">
  77 + {{ dateFormat(scope.row.endTime) }}
  78 + </span>
  79 + <span v-else>
  80 + {{ dateFormat(scope.row.endTime) }}
  81 + </span>
  82 + </template>
  83 + </el-table-column>
  84 + <el-table-column prop="amount" :label="$t('simplifyFeeReceipt.totalAmount')" align="center">
  85 + <template slot-scope="scope">
  86 + {{ scope.row.amount }}{{ $t('simplifyFeeReceipt.yuan') }}
  87 + </template>
  88 + </el-table-column>
  89 + <el-table-column prop="createTime" :label="$t('simplifyFeeReceipt.payTime')" align="center"></el-table-column>
  90 + <el-table-column prop="receiptId" :label="$t('simplifyFeeReceipt.receiptId')" align="center"></el-table-column>
  91 + </el-table>
  92 + <el-pagination @current-change="handleCurrentChange" :current-page="currentPage" :page-size="pageSize"
  93 + layout="total, prev, pager, next" :total="total">
  94 + </el-pagination>
  95 + </div>
  96 + </div>
  97 +</template>
  98 +
  99 +<script>
  100 +import { getCommunityId, getDict } from '@/api/community/communityApi'
  101 +import { queryFeeReceipt, listFeePrintPage } from '@/api/fee/simplifyFeeReceiptApi'
  102 +import { queryOwnerCars } from '@/api/room/ownerCarsApi'
  103 +import { queryContract } from '@/api/contract/contractChangeDetailApi'
  104 +import { dateFormat } from '@/utils/dateUtil'
  105 +
  106 +export default {
  107 + name: 'SimplifyFeeReceipt',
  108 + data() {
  109 + return {
  110 + DEFAULT_PAGE: 1,
  111 + DEFAULT_ROWS: 50,
  112 + simplifyFeeReceiptInfo: {
  113 + feeReceipts: [],
  114 + objType: '3333',
  115 + objId: '',
  116 + payObjId: '',
  117 + roomId: '',
  118 + carId: '',
  119 + receiptCode: '',
  120 + total: '',
  121 + records: '',
  122 + ownerId: '',
  123 + objTypes: [],
  124 + ownerCars: [],
  125 + ownerContracts: [],
  126 + selectReceipts: [],
  127 + ownerFlag: 'F',
  128 + contractId: '',
  129 + quan: false,
  130 + printUrl: '/print.html#/pages/property/printPayFee'
  131 + },
  132 + currentPage: 1,
  133 + pageSize: 10,
  134 + total: 0
  135 + }
  136 + },
  137 + watch: {
  138 + 'simplifyFeeReceiptInfo.selectReceipts': {
  139 + handler(newVal) {
  140 + this.simplifyFeeReceiptInfo.quan = newVal.length === this.simplifyFeeReceiptInfo.feeReceipts.length
  141 + },
  142 + deep: true
  143 + }
  144 + },
  145 + created() {
  146 + this._loadDictData()
  147 + },
  148 + methods: {
  149 + handleSwitch(param) {
  150 + if (param.roomId === '') return
  151 + this.clearSimplifyFeeReceiptInfo()
  152 + this._listFeePrintPages()
  153 + Object.assign(this.simplifyFeeReceiptInfo, param)
  154 + this.simplifyFeeReceiptInfo.objId = param.roomId
  155 + this.simplifyFeeReceiptInfo.payObjId = param.ownerId
  156 + this._listSimplifyFeeReceipt(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  157 + },
  158 + handleCurrentChange(val) {
  159 + this._listSimplifyFeeReceipt(val, this.DEFAULT_ROWS)
  160 + },
  161 + async _loadDictData() {
  162 + try {
  163 + const data = await getDict('fee_receipt', 'obj_type')
  164 + this.simplifyFeeReceiptInfo.objTypes = data
  165 + } catch (error) {
  166 + console.error('Failed to load dict data:', error)
  167 + }
  168 + },
  169 + async _listSimplifyFeeReceipt(page, rows) {
  170 + this.simplifyFeeReceiptInfo.selectReceipts = []
  171 + this.simplifyFeeReceiptInfo.quan = false
  172 + let objId = ''
  173 + if (this.simplifyFeeReceiptInfo.objType === '3333') {
  174 + objId = this.simplifyFeeReceiptInfo.roomId
  175 + } else if (this.simplifyFeeReceiptInfo.objType === '6666') {
  176 + objId = this.simplifyFeeReceiptInfo.carId
  177 + } else {
  178 + objId = this.simplifyFeeReceiptInfo.contractId
  179 + }
  180 +
  181 + const params = {
  182 + page,
  183 + row: rows,
  184 + objType: this.simplifyFeeReceiptInfo.objType,
  185 + objId,
  186 + receiptCode: this.simplifyFeeReceiptInfo.receiptCode,
  187 + communityId: getCommunityId()
  188 + }
  189 +
  190 + if (this.simplifyFeeReceiptInfo.ownerFlag === 'T') {
  191 + params.objId = ''
  192 + params.payObjId = this.simplifyFeeReceiptInfo.payObjId
  193 + }
  194 +
  195 + try {
  196 + const res = await queryFeeReceipt(params)
  197 + this.simplifyFeeReceiptInfo.total = res.total
  198 + this.simplifyFeeReceiptInfo.records = res.records
  199 + this.simplifyFeeReceiptInfo.feeReceipts = res.data
  200 + this.total = res.records
  201 + } catch (error) {
  202 + console.error('Request failed:', error)
  203 + }
  204 + },
  205 + _queryFeeReceiptMethod() {
  206 + this._listSimplifyFeeReceipt(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  207 + },
  208 + _printFeeReceipt(merge) {
  209 + if (this.simplifyFeeReceiptInfo.selectReceipts.length < 1) {
  210 + this.$message.warning(this.$t('simplifyFeeReceipt.selectReceipt'))
  211 + return
  212 + }
  213 + const receiptids = this.simplifyFeeReceiptInfo.selectReceipts.join(',')
  214 + window.open(`${this.simplifyFeeReceiptInfo.printUrl}?receiptIds=${receiptids}&apply=N&merge=${merge}`)
  215 + },
  216 + _printApplyFeeReceipt() {
  217 + if (this.simplifyFeeReceiptInfo.selectReceipts.length < 1) {
  218 + this.$message.warning(this.$t('simplifyFeeReceipt.selectReceipt'))
  219 + return
  220 + }
  221 + const receiptids = this.simplifyFeeReceiptInfo.selectReceipts.join(',')
  222 + window.open(`/print.html#/pages/property/printPayFee?receiptIds=${receiptids}&apply=Y`)
  223 + },
  224 + _printFeeSmallReceipt() {
  225 + if (this.simplifyFeeReceiptInfo.selectReceipts.length < 1) {
  226 + this.$message.warning(this.$t('simplifyFeeReceipt.selectReceipt'))
  227 + return
  228 + }
  229 + const receiptids = this.simplifyFeeReceiptInfo.selectReceipts.join(',')
  230 + window.open(`/smallPrint.html#/pages/property/printSmallPayFee?receiptIds=${receiptids}`)
  231 + },
  232 + clearSimplifyFeeReceiptInfo() {
  233 + this.simplifyFeeReceiptInfo = {
  234 + feeReceipts: [],
  235 + objType: '3333',
  236 + objId: '',
  237 + roomId: '',
  238 + carId: '',
  239 + receiptCode: '',
  240 + total: '',
  241 + records: '',
  242 + ownerId: '',
  243 + objTypes: [],
  244 + ownerCars: [],
  245 + ownerContracts: [],
  246 + selectReceipts: [],
  247 + ownerFlag: 'F',
  248 + contractId: '',
  249 + quan: false,
  250 + printUrl: '/print.html#/pages/property/printPayFee'
  251 + }
  252 + },
  253 + async _changeSimplifyFeeReceiptFeeTypeCd(objType) {
  254 + if (objType === '3333') {
  255 + this.$emit('notify', {})
  256 + } else if (objType === '6666') {
  257 + try {
  258 + await this._listSimplifyFeeReceiptOwnerCar()
  259 + this.$emit('notify', {})
  260 + } catch (error) {
  261 + console.error(error)
  262 + }
  263 + } else {
  264 + try {
  265 + await this._listSimplifyFeeReceiptOwnerContract()
  266 + this.$emit('notify', {})
  267 + } catch (error) {
  268 + console.error(error)
  269 + }
  270 + }
  271 + },
  272 + changeSimplifyFeeReceiptCar() {
  273 + this._changeSimplifyFeeReceiptFeeTypeCd(this.simplifyFeeReceiptInfo.objType)
  274 + },
  275 + async _listSimplifyFeeReceiptOwnerCar() {
  276 + try {
  277 + const res = await queryOwnerCars({
  278 + page: 1,
  279 + row: 50,
  280 + ownerId: this.simplifyFeeReceiptInfo.ownerId,
  281 + carTypeCd: '1001',
  282 + communityId: getCommunityId()
  283 + })
  284 + this.simplifyFeeReceiptInfo.ownerCars = res.data
  285 + if (res.data.length > 0) {
  286 + this.simplifyFeeReceiptInfo.carId = res.data[0].carId
  287 + return res.data
  288 + }
  289 + throw new Error(this.$t('simplifyFeeReceipt.noCar'))
  290 + } catch (error) {
  291 + console.error('Request failed:', error)
  292 + throw error
  293 + }
  294 + },
  295 + async _listSimplifyFeeReceiptOwnerContract() {
  296 + try {
  297 + const res = await queryContract({
  298 + page: 1,
  299 + row: 50,
  300 + objId: this.simplifyFeeReceiptInfo.ownerId,
  301 + communityId: getCommunityId()
  302 + })
  303 + this.simplifyFeeReceiptInfo.ownerContracts = res.data
  304 + if (res.data.length > 0) {
  305 + this.simplifyFeeReceiptInfo.contractId = res.data[0].contractId
  306 + return res.data
  307 + }
  308 + throw new Error(this.$t('simplifyFeeReceipt.noContract'))
  309 + } catch (error) {
  310 + console.error('Request failed:', error)
  311 + throw error
  312 + }
  313 + },
  314 + checkAllReceipt(e) {
  315 + const checkObj = document.querySelectorAll('.checReceiptItem')
  316 + if (e.target.checked) {
  317 + checkObj.forEach(item => {
  318 + if (!item.checked) {
  319 + this.simplifyFeeReceiptInfo.selectReceipts.push(item.value)
  320 + }
  321 + })
  322 + } else {
  323 + this.simplifyFeeReceiptInfo.selectReceipts = []
  324 + }
  325 + },
  326 + _getFeeObjName(feeTypeCd) {
  327 + if (feeTypeCd === '3333') {
  328 + return this.$t('simplifyFeeReceipt.room')
  329 + } else if (feeTypeCd === '6666') {
  330 + return this.$t('simplifyFeeReceipt.car')
  331 + } else {
  332 + return this.$t('simplifyFeeReceipt.contract')
  333 + }
  334 + },
  335 + async _listFeePrintPages() {
  336 + try {
  337 + const res = await listFeePrintPage({
  338 + page: 1,
  339 + row: 1,
  340 + state: 'T',
  341 + communityId: getCommunityId()
  342 + })
  343 + const feePrintPages = res.data
  344 + if (feePrintPages && feePrintPages.length > 0) {
  345 + this.simplifyFeeReceiptInfo.printUrl = feePrintPages[0].url
  346 + }
  347 + } catch (error) {
  348 + console.error('Request failed:', error)
  349 + }
  350 + },
  351 + open(params) {
  352 + this.handleSwitch(params)
  353 + },
  354 + dateFormat(date) {
  355 + return dateFormat(date)
  356 + }
  357 + }
  358 +}
  359 +</script>
  360 +
  361 +<style scoped>
  362 +.margin-top-lg {
  363 + margin-top: 20px;
  364 +}
  365 +
  366 +.padding-right-xs {
  367 + padding-right: 5px;
  368 +}
  369 +
  370 +.padding-left-xl {
  371 + padding-left: 20px;
  372 +}
  373 +
  374 +.text-right {
  375 + text-align: right;
  376 +}
  377 +
  378 +.padding-right-lg {
  379 + padding-right: 20px;
  380 +}
  381 +</style>
0 \ No newline at end of file 382 \ No newline at end of file
src/components/fee/simplifyFeeReceiptDemo.vue 0 → 100644
  1 +<template>
  2 + <simplify-fee-receipt ref="simplifyFeeReceipt"></simplify-fee-receipt>
  3 +</template>
  4 +
  5 +<script>
  6 +import SimplifyFeeReceipt from './simplifyFeeReceipt'
  7 +
  8 +export default {
  9 + name: 'SimplifyFeeReceiptDemo',
  10 + components: {
  11 + SimplifyFeeReceipt
  12 + },
  13 + mounted() {
  14 + this.$refs.simplifyFeeReceipt.$emit('switch', {
  15 + roomId: '123',
  16 + ownerId: '456'
  17 + })
  18 + }
  19 +}
  20 +</script>
0 \ No newline at end of file 21 \ No newline at end of file
src/components/fee/simplifyHisFee.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top">
  4 + <el-col :span="24">
  5 + <el-table
  6 + :data="simplifyHisFeeInfo.feeDetails"
  7 + style="width: 100%; margin-top: 10px"
  8 + border
  9 + stripe
  10 + >
  11 + <el-table-column prop="feeName" :label="$t('simplifyHisFee.feeItem')" align="center"></el-table-column>
  12 + <el-table-column prop="payerObjName" :label="$t('simplifyHisFee.payerObject')" align="center"></el-table-column>
  13 + <el-table-column :label="$t('simplifyHisFee.receiptNumber')" align="center">
  14 + <template slot-scope="scope">
  15 + <div v-if="scope.row.receiptCode">{{ scope.row.receiptCode }}</div>
  16 + <div v-else>
  17 + <el-link
  18 + v-if="scope.row.state === '1400'"
  19 + type="primary"
  20 + @click="_openGeneratorReceiptCode(scope.row)"
  21 + >
  22 + {{ $t('simplifyHisFee.manualGenerate') }}
  23 + </el-link>
  24 + <span v-else>-</span>
  25 + </div>
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column prop="cycles" :label="$t('simplifyHisFee.cycle')" align="center"></el-table-column>
  29 + <el-table-column :label="$t('simplifyHisFee.receivableReceived')" align="center">
  30 + <template slot-scope="scope">
  31 + <div v-if="scope.row.state === '1500'">
  32 + {{ scope.row.payerObjName }}{{ $t('simplifyHisFee.viewInFee') }}
  33 + </div>
  34 + <div v-else>
  35 + {{ scope.row.receivableAmount }}/{{ scope.row.receivedAmount }}<br>
  36 + <div v-if="scope.row.acctAmount > 0">
  37 + {{ $t('simplifyHisFee.accountDeduction') }}: {{ scope.row.acctAmount }}<br>
  38 + </div>
  39 + <div
  40 + v-for="(item, index) in scope.row.payFeeDetailDiscountDtoList"
  41 + :key="index"
  42 + >
  43 + {{ item.discountName }}: {{ Math.abs(item.discountPrice) }}<br>
  44 + </div>
  45 + </div>
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column prop="primeRateName" :label="$t('simplifyHisFee.paymentMethod')" align="center"></el-table-column>
  49 + <el-table-column :label="$t('simplifyHisFee.paymentPeriod')" align="center">
  50 + <template slot-scope="scope">
  51 + {{ formatDate(scope.row.startTime) }}~<br>
  52 + {{ formatDate(scope.row.endTime) }}
  53 + </template>
  54 + </el-table-column>
  55 + <el-table-column prop="createTime" :label="$t('simplifyHisFee.paymentTime')" align="center"></el-table-column>
  56 + <el-table-column prop="cashierName" :label="$t('simplifyHisFee.cashier')" align="center">
  57 + <template slot-scope="scope">
  58 + {{ scope.row.cashierName || '-' }}
  59 + </template>
  60 + </el-table-column>
  61 + <el-table-column prop="stateName" :label="$t('simplifyHisFee.status')" align="center"></el-table-column>
  62 + <el-table-column prop="remark" :label="$t('simplifyHisFee.remark')" align="center"></el-table-column>
  63 + <el-table-column :label="$t('simplifyHisFee.operation')" align="center">
  64 + <template slot-scope="scope">
  65 + <el-button
  66 + size="mini"
  67 + type="primary"
  68 + plain
  69 + @click="_toHisFeeDetail(scope.row)"
  70 + >
  71 + {{ $t('simplifyHisFee.detail') }}
  72 + </el-button>
  73 + </template>
  74 + </el-table-column>
  75 + </el-table>
  76 + <el-pagination
  77 + @current-change="handleCurrentChange"
  78 + :current-page="currentPage"
  79 + :page-size="pageSize"
  80 + layout="total, prev, pager, next"
  81 + :total="simplifyHisFeeInfo.total"
  82 + class="pagination-container"
  83 + ></el-pagination>
  84 + </el-col>
  85 + </el-row>
  86 +
  87 + <el-dialog
  88 + :title="$t('simplifyHisFee.generateReceipt')"
  89 + :visible.sync="receiptDialogVisible"
  90 + width="50%"
  91 + >
  92 + <el-form label-position="left" label-width="120px">
  93 + <el-form-item :label="$t('simplifyHisFee.receiptNumber')">
  94 + <el-select
  95 + v-model="simplifyHisFeeInfo.receiptType"
  96 + class="w-100"
  97 + :placeholder="$t('simplifyHisFee.receiptNumberRequired')"
  98 + >
  99 + <el-option disabled value="">{{ $t('simplifyHisFee.receiptNumberRequired') }}</el-option>
  100 + <el-option value="Y" :label="$t('simplifyHisFee.systemGenerate')"></el-option>
  101 + <el-option value="N" :label="$t('simplifyHisFee.custom')"></el-option>
  102 + </el-select>
  103 + </el-form-item>
  104 + <el-form-item
  105 + v-if="simplifyHisFeeInfo.receiptType === 'N'"
  106 + :label="$t('simplifyHisFee.receiptNumber')"
  107 + >
  108 + <el-input
  109 + v-model="simplifyHisFeeInfo.receiptCode"
  110 + :placeholder="$t('simplifyHisFee.receiptNumberRequired')"
  111 + ></el-input>
  112 + </el-form-item>
  113 + </el-form>
  114 + <div slot="footer" class="dialog-footer">
  115 + <el-button @click="receiptDialogVisible = false">{{ $t('simplifyHisFee.cancel') }}</el-button>
  116 + <el-button type="primary" @click="_generatorReceiptCode">{{ $t('simplifyHisFee.generate') }}</el-button>
  117 + </div>
  118 + </el-dialog>
  119 + </div>
  120 +</template>
  121 +
  122 +<script>
  123 +import { queryFeeDetail, generatorReceipt } from '@/api/fee/simplifyHisFeeApi'
  124 +import { getCommunityId } from '@/api/community/communityApi'
  125 +import { dateFormat } from '@/utils/dateUtil'
  126 +
  127 +export default {
  128 + name: 'SimplifyHisFee',
  129 + data() {
  130 + return {
  131 + DEFAULT_PAGE: 1,
  132 + DEFAULT_ROWS: 10,
  133 + currentPage: 1,
  134 + pageSize: 10,
  135 + receiptDialogVisible: false,
  136 + simplifyHisFeeInfo: {
  137 + total: 0,
  138 + records: 1,
  139 + feeDetails: [],
  140 + ownerId: '',
  141 + feeDetail: {},
  142 + receiptType: 'Y',
  143 + receiptCode: ''
  144 + }
  145 + }
  146 + },
  147 + created() {
  148 + this.communityId = getCommunityId()
  149 + },
  150 + methods: {
  151 + open(param) {
  152 + this.handleSwitch(param)
  153 + },
  154 + handleSwitch(param) {
  155 + this.clearSimplifyHisFeeInfo()
  156 + if (!param.ownerId) {
  157 + return
  158 + }
  159 + Object.assign(this.simplifyHisFeeInfo, param)
  160 + this._listSimplifyFeeDetails(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  161 + },
  162 + handleNotify() {
  163 + this._listSimplifyFeeDetails(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  164 + },
  165 + handleCurrentChange(page) {
  166 + this._listSimplifyFeeDetails(page, this.DEFAULT_ROWS)
  167 + },
  168 + formatDate(date) {
  169 + if (!date) return ''
  170 + return dateFormat(date)
  171 + },
  172 + _listSimplifyFeeDetails(page, row) {
  173 + const params = {
  174 + page,
  175 + row,
  176 + communityId: this.communityId,
  177 + ownerId: this.simplifyHisFeeInfo.ownerId
  178 + }
  179 +
  180 + queryFeeDetail(params)
  181 + .then(response => {
  182 + const res = response.data
  183 + this.simplifyHisFeeInfo.total = res.total
  184 + this.simplifyHisFeeInfo.records = res.records
  185 + this.simplifyHisFeeInfo.feeDetails = res.feeDetails
  186 + this.currentPage = page
  187 + })
  188 + .catch(error => {
  189 + console.error('请求失败处理', error)
  190 + })
  191 + },
  192 + clearSimplifyHisFeeInfo() {
  193 + this.simplifyHisFeeInfo = {
  194 + total: 0,
  195 + records: 1,
  196 + feeDetails: [],
  197 + ownerId: '',
  198 + feeDetail: {},
  199 + receiptType: 'Y',
  200 + receiptCode: ''
  201 + }
  202 + },
  203 + _toHisFeeDetail(detail) {
  204 + this.$router.push(`/views/fee/propertyFee?feeId=${detail.feeId}`)
  205 + },
  206 + _openGeneratorReceiptCode(detail) {
  207 + this.simplifyHisFeeInfo.feeDetail = detail
  208 + this.receiptDialogVisible = true
  209 + },
  210 + _generatorReceiptCode() {
  211 + const data = {
  212 + detailId: this.simplifyHisFeeInfo.feeDetail.detailId,
  213 + communityId: this.communityId,
  214 + receiptCode: this.simplifyHisFeeInfo.receiptCode
  215 + }
  216 +
  217 + generatorReceipt(data)
  218 + .then(response => {
  219 + const res = response.data
  220 + this.$message.success(res.msg)
  221 + if (res.code !== '0') {
  222 + return
  223 + }
  224 + this.receiptDialogVisible = false
  225 + setTimeout(() => {
  226 + this.$emit('doSearch')
  227 + }, 1000)
  228 + })
  229 + .catch(error => {
  230 + console.error('请求失败处理', error)
  231 + this.$message.error(error.message || '操作失败')
  232 + })
  233 + }
  234 + }
  235 +}
  236 +</script>
  237 +
  238 +<style scoped>
  239 +.margin-top {
  240 + margin-top: 20px;
  241 +}
  242 +.w-100 {
  243 + width: 100%;
  244 +}
  245 +.pagination-container {
  246 + margin-top: 20px;
  247 + text-align: right;
  248 +}
  249 +</style>
0 \ No newline at end of file 250 \ No newline at end of file
src/components/fee/simplifyHisFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <simplify-his-fee ref="simplifyHisFee"></simplify-his-fee>
  4 + </div>
  5 +</template>
  6 +
  7 +<script>
  8 +import SimplifyHisFee from './simplifyHisFee'
  9 +
  10 +export default {
  11 + name: 'SimplifyHisFeeDemo',
  12 + components: {
  13 + SimplifyHisFee
  14 + },
  15 + mounted() {
  16 + this.$refs.simplifyHisFee.$emit('switch', {
  17 + ownerId: '123'
  18 + })
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/fee/simplifyMeterWaterLog.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top-lg">
  4 + <el-col :span="4" class="padding-right-xs padding-left-xl">
  5 + <el-select v-model="simplifyMeterWaterFeeInfo.meterType" size="small" @change="_listSimplifyMeterWaterFee(1, 10)">
  6 + <el-option :label="$t('simplifyMeterWaterLog.selectMeterType')" value=""></el-option>
  7 + <el-option v-for="(item, index) in simplifyMeterWaterFeeInfo.meterTypes" :key="index" :label="item.typeName"
  8 + :value="item.typeId"></el-option>
  9 + </el-select>
  10 + </el-col>
  11 + <el-col :span="20" class="text-right" v-if="simplifyMeterWaterFeeInfo.roomId">
  12 + <el-button type="primary" size="small" style="margin-left:10px" @click="_openAddMeterWaterModal()">
  13 + <i class="el-icon-plus"></i> {{ $t('simplifyMeterWaterLog.addMeterReading') }}
  14 + </el-button>
  15 + </el-col>
  16 + </el-row>
  17 +
  18 + <div class="margin-top">
  19 + <el-table :data="simplifyMeterWaterFeeInfo.meterWaters" style="width: 100%; margin-top:10px" border>
  20 + <el-table-column prop="meterTypeName" :label="$t('simplifyMeterWaterLog.meterType')"
  21 + align="center"></el-table-column>
  22 + <el-table-column prop="objName" :label="$t('simplifyMeterWaterLog.objectName')" align="center"></el-table-column>
  23 + <el-table-column prop="preDegrees" :label="$t('simplifyMeterWaterLog.previousReading')"
  24 + align="center"></el-table-column>
  25 + <el-table-column prop="curDegrees" :label="$t('simplifyMeterWaterLog.currentReading')"
  26 + align="center"></el-table-column>
  27 + <el-table-column prop="preReadingTime" :label="$t('simplifyMeterWaterLog.previousReadingTime')"
  28 + align="center"></el-table-column>
  29 + <el-table-column prop="curReadingTime" :label="$t('simplifyMeterWaterLog.currentReadingTime')"
  30 + align="center"></el-table-column>
  31 + <el-table-column prop="createTime" :label="$t('simplifyMeterWaterLog.createTime')"
  32 + align="center"></el-table-column>
  33 + </el-table>
  34 +
  35 + <el-row>
  36 + <el-col :span="12"></el-col>
  37 + <el-col :span="12" class="text-right">
  38 + <el-pagination @current-change="handleCurrentChange" :current-page="currentPage" :page-size="pageSize"
  39 + layout="total, prev, pager, next" :total="simplifyMeterWaterFeeInfo.total"></el-pagination>
  40 + </el-col>
  41 + </el-row>
  42 + </div>
  43 + </div>
  44 +</template>
  45 +
  46 +<script>
  47 +import { listMeterWaters, listMeterTypes } from '@/api/fee/simplifyMeterWaterLogApi'
  48 +import { getCommunityId } from '@/api/community/communityApi'
  49 +
  50 +export default {
  51 + name: 'SimplifyMeterWaterLog',
  52 + data() {
  53 + return {
  54 + simplifyMeterWaterFeeInfo: {
  55 + meterTypes: [],
  56 + meterWaters: [],
  57 + total: 0,
  58 + records: 1,
  59 + roomId: '',
  60 + roomName: '',
  61 + ownerName: '',
  62 + floorNum: '',
  63 + unitNum: '',
  64 + roomNum: '',
  65 + meterType: ""
  66 + },
  67 + currentPage: 1,
  68 + pageSize: 10
  69 + }
  70 + },
  71 + created() {
  72 + this.communityId = getCommunityId()
  73 + },
  74 + methods: {
  75 + handleCurrentChange(val) {
  76 + this.currentPage = val
  77 + this._listSimplifyMeterWaterFee(val, this.pageSize)
  78 + },
  79 + _listSimplifyMeterWaterFee(page, row) {
  80 + const param = {
  81 + page,
  82 + row,
  83 + communityId: this.communityId,
  84 + roomNum: `${this.simplifyMeterWaterFeeInfo.floorNum}-${this.simplifyMeterWaterFeeInfo.unitNum}-${this.simplifyMeterWaterFeeInfo.roomNum}`,
  85 + meterType: this.simplifyMeterWaterFeeInfo.meterType
  86 + }
  87 +
  88 + listMeterWaters(param).then(response => {
  89 + const data = response.data
  90 + this.simplifyMeterWaterFeeInfo.total = data.total
  91 + this.simplifyMeterWaterFeeInfo.records = data.records
  92 + this.simplifyMeterWaterFeeInfo.meterWaters = data.data
  93 + }).catch(error => {
  94 + console.error('请求失败:', error)
  95 + })
  96 + },
  97 + _openAddMeterWaterModal() {
  98 + this.$emit('openAddModal', {
  99 + roomId: this.simplifyMeterWaterFeeInfo.roomId,
  100 + roomName: this.simplifyMeterWaterFeeInfo.roomName,
  101 + ownerName: this.simplifyMeterWaterFeeInfo.ownerName
  102 + })
  103 + },
  104 + clearSimplifyMeterWaterFeeInfo() {
  105 + this.simplifyMeterWaterFeeInfo = {
  106 + meterTypes: [],
  107 + meterWaters: [],
  108 + total: 0,
  109 + records: 1,
  110 + roomId: '',
  111 + ownerName: '',
  112 + roomName: '',
  113 + floorNum: '',
  114 + unitNum: '',
  115 + roomNum: '',
  116 + meterType: ""
  117 + }
  118 + },
  119 + _listMeterTypes() {
  120 + const param = {
  121 + page: 1,
  122 + row: 100,
  123 + communityId: this.communityId
  124 + }
  125 +
  126 + listMeterTypes(param).then(response => {
  127 + const data = response.data
  128 + this.simplifyMeterWaterFeeInfo.meterTypes = data.data
  129 + }).catch(error => {
  130 + console.error('请求失败:', error)
  131 + })
  132 + },
  133 + switchData(param) {
  134 + if (param.roomId === '') return
  135 + this.clearSimplifyMeterWaterFeeInfo()
  136 + Object.assign(this.simplifyMeterWaterFeeInfo, param)
  137 + this._listMeterTypes()
  138 + this._listSimplifyMeterWaterFee(1, 10)
  139 + },
  140 + open(params) {
  141 + this.switchData(params)
  142 + }
  143 + }
  144 +}
  145 +</script>
  146 +
  147 +<style scoped>
  148 +.margin-top-lg {
  149 + margin-top: 20px;
  150 +}
  151 +
  152 +.margin-top {
  153 + margin-top: 15px;
  154 +}
  155 +
  156 +.padding-right-xs {
  157 + padding-right: 5px;
  158 +}
  159 +
  160 +.padding-left-xl {
  161 + padding-left: 20px;
  162 +}
  163 +
  164 +.text-right {
  165 + text-align: right;
  166 +}
  167 +</style>
0 \ No newline at end of file 168 \ No newline at end of file
src/components/fee/simplifyMeterWaterLogDemo.vue 0 → 100644
  1 +<template>
  2 + <simplify-meter-water-log ref="simplifyMeterWaterLog"></simplify-meter-water-log>
  3 +</template>
  4 +
  5 +<script>
  6 +import SimplifyMeterWaterLog from './simplifyMeterWaterLog'
  7 +
  8 +export default {
  9 + name: 'SimplifyMeterWaterLogDemo',
  10 + components: {
  11 + SimplifyMeterWaterLog
  12 + },
  13 + mounted() {
  14 + this.$refs.simplifyMeterWaterLog.switchData({
  15 + roomId: '123',
  16 + roomName: 'Test Room',
  17 + ownerName: 'Test Owner',
  18 + floorNum: '1',
  19 + unitNum: '2',
  20 + roomNum: '101'
  21 + })
  22 + }
  23 +}
  24 +</script>
0 \ No newline at end of file 25 \ No newline at end of file
src/components/fee/simplifyOwnerRooms.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top">
  4 + <el-col :span="22" class="text-right"></el-col>
  5 + <el-col :span="2" class="text-right">
  6 + <el-button
  7 + type="primary"
  8 + size="small"
  9 + style="margin-left:10px"
  10 + v-if="hasPrivilege('502020082314267912') && simplifyOwnerRoomsInfo.ownerId"
  11 + @click="_openSimplifyOwnerRoomsBatchPayFeeModal()"
  12 + >
  13 + <i class="el-icon-plus"></i>
  14 + <span>{{ $t('simplifyOwnerRooms.batchPay') }}</span>
  15 + </el-button>
  16 + </el-col>
  17 + </el-row>
  18 + <div>
  19 + <el-table
  20 + :data="simplifyOwnerRoomsInfo.rooms"
  21 + style="margin-top:10px"
  22 + border
  23 + stripe
  24 + >
  25 + <el-table-column :label="$t('simplifyOwnerRooms.roomCode')" align="center">
  26 + <template slot-scope="scope">
  27 + {{scope.row.floorNum}}-{{scope.row.unitNum}}-{{scope.row.roomNum}}
  28 + </template>
  29 + </el-table-column>
  30 + <el-table-column prop="layer" :label="$t('simplifyOwnerRooms.floor')" align="center"></el-table-column>
  31 + <el-table-column prop="roomSubTypeName" :label="$t('simplifyOwnerRooms.type')" align="center"></el-table-column>
  32 + <el-table-column :label="$t('simplifyOwnerRooms.area')" align="center">
  33 + <template slot-scope="scope">
  34 + {{scope.row.builtUpArea}}/{{scope.row.roomArea}}
  35 + </template>
  36 + </el-table-column>
  37 + <el-table-column prop="roomRent" :label="$t('simplifyOwnerRooms.rent')" align="center"></el-table-column>
  38 + <el-table-column :label="$t('simplifyOwnerRooms.validity')" align="center">
  39 + <template slot-scope="scope">
  40 + {{scope.row.startTime}}<br>~{{scope.row.endTime}}
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column prop="stateName" :label="$t('simplifyOwnerRooms.roomStatus')" align="center"></el-table-column>
  44 + <el-table-column :label="$t('simplifyOwnerRooms.roomOweFee')" align="center">
  45 + <template slot-scope="scope">
  46 + {{scope.row.roomOweFee || '0.00'}}({{$t('simplifyOwnerRooms.updateDaily')}})
  47 + </template>
  48 + </el-table-column>
  49 + <el-table-column :label="$t('simplifyOwnerRooms.actions')" align="center">
  50 + <template slot-scope="scope">
  51 + <el-button-group v-if="simplifyOwnerRoomsInfo.roomId != scope.row.roomId">
  52 + <el-button size="mini" @click="_toChooseOwnerRoomModel(scope.row)">
  53 + {{ $t('simplifyOwnerRooms.choose') }}
  54 + </el-button>
  55 + </el-button-group>
  56 + <div v-else>
  57 + {{ $t('simplifyOwnerRooms.currentRoom') }}
  58 + </div>
  59 + </template>
  60 + </el-table-column>
  61 + </el-table>
  62 + <el-row>
  63 + <el-col :span="16"></el-col>
  64 + <el-col :span="8" class="float-right">
  65 + <span>{{ $t('simplifyOwnerRooms.subtotalOweFee') }}:{{simplifyOwnerRoomsInfo.allOweFeeAmount}}</span>
  66 + </el-col>
  67 + </el-row>
  68 + <el-pagination
  69 + @current-change="handleCurrentChange"
  70 + :current-page="currentPage"
  71 + :page-size="pageSize"
  72 + layout="total, prev, pager, next"
  73 + :total="total">
  74 + </el-pagination>
  75 + </div>
  76 + </div>
  77 +</template>
  78 +
  79 +<script>
  80 +import { getCommunityId } from '@/api/community/communityApi'
  81 +import { queryRoomsByOwner } from '@/api/fee/simplifyOwnerRoomsApi'
  82 +
  83 +export default {
  84 + name: 'SimplifyOwnerRooms',
  85 + data() {
  86 + return {
  87 + DEFAULT_PAGE: 1,
  88 + DEFAULT_ROWS: 10,
  89 + simplifyOwnerRoomsInfo: {
  90 + rooms: [],
  91 + ownerId: '',
  92 + roomId: '',
  93 + total: 0,
  94 + records: 1,
  95 + allOweFeeAmount: 0
  96 + },
  97 + currentPage: 1,
  98 + pageSize: 10,
  99 + total: 0
  100 + }
  101 + },
  102 + created() {
  103 + this._initEvent()
  104 + },
  105 + methods: {
  106 + _initEvent() {
  107 + },
  108 + handleSwitch(param) {
  109 + if (!param.ownerId) return
  110 + this.clearSimplifyOwnerRoomsInfo()
  111 + Object.assign(this.simplifyOwnerRoomsInfo, param)
  112 + this._listSimplifyOwnerRooms(this.DEFAULT_PAGE, this.DEFAULT_ROWS)
  113 + },
  114 + handleCurrentChange(val) {
  115 + this._listSimplifyOwnerRooms(val, this.DEFAULT_ROWS)
  116 + },
  117 + async _listSimplifyOwnerRooms() {
  118 + try {
  119 + const res = await queryRoomsByOwner({
  120 + ownerId: this.simplifyOwnerRoomsInfo.ownerId,
  121 + communityId: getCommunityId()
  122 + })
  123 + this.simplifyOwnerRoomsInfo.rooms = res.rooms
  124 + this._computeOwnerRoomOweFeeAmount()
  125 + this.simplifyOwnerRoomsInfo.total = res.total
  126 + this.simplifyOwnerRoomsInfo.records = res.records
  127 + this.total = res.records
  128 + } catch (error) {
  129 + console.error('Request failed:', error)
  130 + }
  131 + },
  132 + _toChooseOwnerRoomModel(room) {
  133 + this.$emit('notifyRoom', room)
  134 + },
  135 + _computeOwnerRoomOweFeeAmount() {
  136 + let total = 0
  137 + this.simplifyOwnerRoomsInfo.allOweFeeAmount = 0
  138 + if (!this.simplifyOwnerRoomsInfo.rooms || this.simplifyOwnerRoomsInfo.rooms.length < 1) return
  139 +
  140 + this.simplifyOwnerRoomsInfo.rooms.forEach(room => {
  141 + if (room.roomOweFee) {
  142 + total += parseFloat(room.roomOweFee)
  143 + }
  144 + })
  145 + this.simplifyOwnerRoomsInfo.allOweFeeAmount = total.toFixed(2)
  146 + },
  147 + clearSimplifyOwnerRoomsInfo() {
  148 + this.simplifyOwnerRoomsInfo = {
  149 + rooms: [],
  150 + ownerId: '',
  151 + roomId: '',
  152 + total: 0,
  153 + records: 1,
  154 + allOweFeeAmount: 0
  155 + }
  156 + },
  157 + _openSimplifyOwnerRoomsBatchPayFeeModal() {
  158 + this.$router.push(`/property/batchPayFeeOrder?ownerId=${this.simplifyOwnerRoomsInfo.ownerId}&payerObjType=3333`)
  159 + },
  160 + hasPrivilege(code) {
  161 + void code; // 占位,消除未使用警告
  162 + return true;
  163 + },
  164 + open(params) {
  165 + this.handleSwitch(params)
  166 + }
  167 + }
  168 +}
  169 +</script>
  170 +
  171 +<style scoped>
  172 +.margin-top {
  173 + margin-top: 15px;
  174 +}
  175 +.float-right {
  176 + float: right;
  177 +}
  178 +.text-right {
  179 + text-align: right;
  180 +}
  181 +</style>
0 \ No newline at end of file 182 \ No newline at end of file
src/components/fee/simplifyOwnerRoomsDemo.vue 0 → 100644
  1 +<template>
  2 + <simplify-owner-rooms ref="simplifyOwnerRooms"></simplify-owner-rooms>
  3 +</template>
  4 +
  5 +<script>
  6 +import SimplifyOwnerRooms from './simplifyOwnerRooms'
  7 +
  8 +export default {
  9 + name: 'SimplifyOwnerRoomsDemo',
  10 + components: {
  11 + SimplifyOwnerRooms
  12 + },
  13 + mounted() {
  14 + this.$refs.simplifyOwnerRooms.$emit('switch', {
  15 + ownerId: '123',
  16 + roomId: '456'
  17 + })
  18 + }
  19 +}
  20 +</script>
0 \ No newline at end of file 21 \ No newline at end of file
src/components/fee/simplifyRefundDeposit.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top">
  4 + <el-col :span="20"></el-col>
  5 + <el-col :span="4" class="text-right"></el-col>
  6 + </el-row>
  7 +
  8 + <el-table :data="simplifyRefundDepositInfo.fees" border style="width: 100%; margin-top:10px">
  9 + <el-table-column prop="payerObjName" :label="$t('simplifyRefundDeposit.chargeObject')"
  10 + align="center"></el-table-column>
  11 + <el-table-column prop="feeName" :label="$t('simplifyRefundDeposit.feeItem')" align="center"></el-table-column>
  12 + <el-table-column :label="$t('simplifyRefundDeposit.timePeriod')" align="center">
  13 + <template slot-scope="scope">
  14 + {{ scope.row.startTime }}~{{ scope.row.endTime }}
  15 + </template>
  16 + </el-table-column>
  17 + <el-table-column prop="receivedAmount" :label="$t('simplifyRefundDeposit.amount')"
  18 + align="center"></el-table-column>
  19 + <el-table-column prop="createTime" :label="$t('simplifyRefundDeposit.paymentTime')"
  20 + align="center"></el-table-column>
  21 + <el-table-column prop="stateName" :label="$t('simplifyRefundDeposit.status')" align="center"></el-table-column>
  22 + <el-table-column :label="$t('simplifyRefundDeposit.operation')" align="center">
  23 + <template slot-scope="scope">
  24 + <el-button-group>
  25 + <el-button v-if="scope.row.state == '1400'" size="mini" @click="_openRefundModel(scope.row)">
  26 + {{ $t('simplifyRefundDeposit.refundDeposit') }}
  27 + </el-button>
  28 + <el-button size="mini" @click="_toSimplifyFeeDepositFeeDetail(scope.row)">
  29 + {{ $t('simplifyRefundDeposit.detail') }}
  30 + </el-button>
  31 + </el-button-group>
  32 + </template>
  33 + </el-table-column>
  34 + </el-table>
  35 +
  36 + <el-row class="margin-top">
  37 + <el-col :span="24" class="text-right">
  38 + <el-pagination @current-change="handleCurrentChange" :current-page="currentPage" :page-size="pageSize"
  39 + layout="total, prev, pager, next" :total="simplifyRefundDepositInfo.total"></el-pagination>
  40 + </el-col>
  41 + </el-row>
  42 + </div>
  43 +</template>
  44 +
  45 +<script>
  46 +import { queryFeeDeposit } from '@/api/fee/simplifyRefundDepositApi'
  47 +import { getCommunityId } from '@/api/community/communityApi'
  48 +
  49 +export default {
  50 + name: 'SimplifyRefundDeposit',
  51 + data() {
  52 + return {
  53 + simplifyRefundDepositInfo: {
  54 + fees: [],
  55 + ownerId: '',
  56 + roomId: '',
  57 + roomName: '',
  58 + total: 0,
  59 + records: 0
  60 + },
  61 + currentPage: 1,
  62 + pageSize: 10,
  63 + communityId: ''
  64 + }
  65 + },
  66 + created() {
  67 + this.communityId = getCommunityId()
  68 + },
  69 + methods: {
  70 + handleCurrentChange(val) {
  71 + this.currentPage = val
  72 + this._listSimplifyFeeDeposit(val, this.pageSize)
  73 + },
  74 + _listSimplifyFeeDeposit(page, rows) {
  75 + const params = {
  76 + page,
  77 + row: rows,
  78 + payerObjId: this.simplifyRefundDepositInfo.roomId,
  79 + ownerId: this.simplifyRefundDepositInfo.ownerId,
  80 + communityId: this.communityId,
  81 + state: '1400'
  82 + }
  83 +
  84 + queryFeeDeposit(params).then(response => {
  85 + if (response.code !== 0) return
  86 + this.simplifyRefundDepositInfo.total = response.total
  87 + this.simplifyRefundDepositInfo.records = response.records
  88 + this.simplifyRefundDepositInfo.fees = response.data
  89 + }).catch(error => {
  90 + console.error('请求失败:', error)
  91 + })
  92 + },
  93 + clearSimplifyFeeDepositInfo() {
  94 + this.simplifyRefundDepositInfo = {
  95 + fees: [],
  96 + ownerId: '',
  97 + roomId: '',
  98 + roomName: '',
  99 + total: 0,
  100 + records: 0
  101 + }
  102 + },
  103 + _openRefundModel() {
  104 + const roomId = this.simplifyRefundDepositInfo.roomId
  105 + this.$router.push(`/pages/fee/refundDepositFee?roomId=${roomId}`)
  106 + },
  107 + _toSimplifyFeeDepositFeeDetail(fee) {
  108 + this.$router.push(`/pages/property/propertyFee?feeId=${fee.feeId}`)
  109 + },
  110 + switchData(param) {
  111 + if (!param.roomId) return
  112 + this.clearSimplifyFeeDepositInfo()
  113 + Object.assign(this.simplifyRefundDepositInfo, param)
  114 + this._listSimplifyFeeDeposit(1, 10)
  115 + },
  116 + open(params) {
  117 + this.switchData(params)
  118 + }
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style scoped>
  124 +.margin-top {
  125 + margin-top: 15px;
  126 +}
  127 +
  128 +.text-right {
  129 + text-align: right;
  130 +}
  131 +</style>
0 \ No newline at end of file 132 \ No newline at end of file
src/components/fee/simplifyRefundDepositDemo.vue 0 → 100644
  1 +<template>
  2 + <simplify-refund-deposit ref="simplifyRefundDeposit"></simplify-refund-deposit>
  3 +</template>
  4 +
  5 +<script>
  6 +import SimplifyRefundDeposit from './simplifyRefundDeposit'
  7 +
  8 +export default {
  9 + name: 'SimplifyRefundDepositDemo',
  10 + components: {
  11 + SimplifyRefundDeposit
  12 + },
  13 + mounted() {
  14 + this.$refs.simplifyRefundDeposit.switchData({
  15 + roomId: '123',
  16 + ownerId: '456',
  17 + roomName: 'Test Room'
  18 + })
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/fee/simplifyRoomFee.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-row class="margin-top-lg">
  4 + <el-col :span="2" >
  5 + <el-select v-model="simplifyRoomFeeInfo.feeTypeCd" @change="changeSimplifyRoomFeeFeeTypeCd" size="small"
  6 + :placeholder="$t('simplifyRoomFee.selectFeeType')">
  7 + <template v-for="item in simplifyRoomFeeInfo.feeTypeCds">
  8 + <el-option :key="item.statusCd" :label="item.name" :value="item.statusCd"
  9 + v-if="item.statusCd != '888800010008'"></el-option>
  10 + </template>
  11 + </el-select>
  12 + </el-col>
  13 + <el-col :span="2" >
  14 + <el-select v-model="simplifyRoomFeeInfo.configId" @change="changeSimplifyRoomConfigId" size="small"
  15 + :placeholder="$t('simplifyRoomFee.selectFeeItem')">
  16 + <el-option v-for="item in simplifyRoomFeeInfo.feeConfigs" :key="item.configId" :label="item.feeName"
  17 + :value="item.configId"></el-option>
  18 + </el-select>
  19 + </el-col>
  20 + <el-col :span="2" >
  21 + <el-select v-model="simplifyRoomFeeInfo.state" @change="changeSimplifyRoomConfigId" size="small"
  22 + :placeholder="$t('simplifyRoomFee.selectStatus')">
  23 + <el-option :label="$t('simplifyRoomFee.valid')" value="2008001"></el-option>
  24 + <el-option :label="$t('simplifyRoomFee.feeEnd')" value="2009001"></el-option>
  25 + </el-select>
  26 + </el-col>
  27 + <el-col :span="2" >
  28 + <el-select v-model="simplifyRoomFeeInfo.ownerFee" @change="changeSimplifyRoomConfigId" size="small">
  29 + <el-option :label="$t('simplifyRoomFee.currentRoom')" value="N"></el-option>
  30 + <el-option :label="$t('simplifyRoomFee.currentOwner')" value="Y"></el-option>
  31 + </el-select>
  32 + </el-col>
  33 + <el-col :span="2" v-if="simplifyRoomFeeInfo.roomId && simplifyRoomFeeInfo.state == '2008001'">
  34 + <el-select v-model="simplifyRoomFeeInfo.showFlag" @change="changeSimplifyRoomShowFlag" size="small">
  35 + <el-option :label="$t('simplifyRoomFee.default')" value="DEFAULT"></el-option>
  36 + <el-option :label="$t('simplifyRoomFee.monthly')" value="MONTH"></el-option>
  37 + </el-select>
  38 + </el-col>
  39 + <el-col :span="2" v-else></el-col>
  40 + <el-col :span="13" class="text-right">
  41 + <el-button type="primary" size="small" v-if="hasPrivilege('502020082314267912')"
  42 + @click="openBatchPayRoomFeeModal">
  43 + <i class="el-icon-plus"></i>
  44 + {{ $t('simplifyRoomFee.batchPayment') }}
  45 + </el-button>
  46 + <el-button type="primary" size="small" v-if="hasPrivilege('502022073007100003')"
  47 + @click="openTempImportRoomFeeModal">
  48 + <i class="el-icon-plus"></i>
  49 + {{ $t('simplifyRoomFee.tempFee') }}
  50 + </el-button>
  51 + <el-button type="primary" size="small" v-if="hasPrivilege('502022073049300004')" @click="openProxyFeeModal">
  52 + <i class="el-icon-plus"></i>
  53 + {{ $t('simplifyRoomFee.quantityPayment') }}
  54 + </el-button>
  55 + <el-button type="primary" size="small" v-if="hasPrivilege('502022073042960005')"
  56 + @click="openAddMeterWaterSimplifyModal">
  57 + <i class="el-icon-plus"></i>
  58 + {{ $t('simplifyRoomFee.waterElectricity') }}
  59 + </el-button>
  60 + <el-button type="primary" size="small" v-if="hasPrivilege('502022073006890006')"
  61 + @click="openRoomCreateFeeComboModal">
  62 + <i class="el-icon-plus"></i>
  63 + {{ $t('simplifyRoomFee.feePackage') }}
  64 + </el-button>
  65 + <el-button type="primary" size="small" v-if="hasPrivilege('502022073096990007')"
  66 + @click="openRoomCreateFeeAddModal">
  67 + <i class="el-icon-plus"></i>
  68 + {{ $t('simplifyRoomFee.createFee') }}
  69 + </el-button>
  70 + <el-button type="primary" size="small" v-if="hasPrivilege('502020080570210194')" @click="toOwnerPayFee">
  71 + <i class="el-icon-plus"></i>
  72 + {{ $t('simplifyRoomFee.arrearsPayment') }}
  73 + </el-button>
  74 + </el-col>
  75 + </el-row>
  76 +
  77 + <div class="margin-top" v-show="simplifyRoomFeeInfo.showFlag == 'DEFAULT'">
  78 + <el-table :data="simplifyRoomFeeInfo.fees" style="width: 100%" border stripe>
  79 + <el-table-column prop="feeName" :label="$t('simplifyRoomFee.feeItem')" align="center">
  80 + <template slot-scope="scope">
  81 + <span class="hand" @click="viewRoomFeeConfig(scope.row)">
  82 + {{ scope.row.feeName }}{{ getSimplifyRoomFeeRoomName(scope.row) }}
  83 + <i class="el-icon-info"></i>
  84 + </span>
  85 + </template>
  86 + </el-table-column>
  87 + <el-table-column prop="feeFlagName" :label="$t('simplifyRoomFee.feeFlag')" align="center"></el-table-column>
  88 + <el-table-column prop="feeTypeCdName" :label="$t('simplifyRoomFee.feeType')" align="center"></el-table-column>
  89 + <el-table-column prop="amountOwed" :label="$t('simplifyRoomFee.receivableAmount')"
  90 + align="center"></el-table-column>
  91 + <el-table-column :label="$t('simplifyRoomFee.accountTime')" align="center">
  92 + <template slot-scope="scope">
  93 + {{ scope.row.startTime }}
  94 + </template>
  95 + </el-table-column>
  96 + <el-table-column :label="$t('simplifyRoomFee.receivablePeriod')" align="center">
  97 + <template slot-scope="scope">
  98 + {{ getEndTime(scope.row) }}~<br />{{ getDeadlineTime(scope.row) }}
  99 + </template>
  100 + </el-table-column>
  101 + <el-table-column :label="$t('simplifyRoomFee.description')" align="center" width="150">
  102 + <template slot-scope="scope">
  103 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  104 + <span>{{ $t('simplifyRoomFee.preDegrees') }}</span>{{ scope.row.preDegrees }}
  105 + </div>
  106 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  107 + <span>{{ $t('simplifyRoomFee.curDegrees') }}</span>{{ scope.row.curDegrees }}
  108 + </div>
  109 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  110 + <span>{{ $t('simplifyRoomFee.unitPrice') }}</span>{{ getOnePrice1(scope.row) }}
  111 + </div>
  112 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  113 + <span>{{ $t('simplifyRoomFee.additionalFee') }}</span>{{ scope.row.additionalAmount }}
  114 + </div>
  115 + <div v-else-if="scope.row.computingFormula == '6006'">
  116 + <span>{{ $t('simplifyRoomFee.usage') }}</span>{{ getAttrValue(scope.row.feeAttrs, '390006') }}
  117 + </div>
  118 + <div v-else-if="scope.row.computingFormula == '6006'">
  119 + <span>{{ $t('simplifyRoomFee.unitPrice') }}</span>{{ scope.row.squarePrice }}
  120 + </div>
  121 + <div v-else-if="scope.row.computingFormula == '6006'">
  122 + <span>{{ $t('simplifyRoomFee.additionalFee') }}</span>{{ scope.row.additionalAmount }}
  123 + </div>
  124 + <div v-else-if="scope.row.feeTypeCd == '888800010017'">
  125 + <span>{{ $t('simplifyRoomFee.algorithm') }}</span>{{ getAttrValue(scope.row.feeAttrs, '390005') }}
  126 + </div>
  127 + <div v-else-if="scope.row.feeTypeCd == '888800010017'">
  128 + <span>{{ $t('simplifyRoomFee.usage') }}</span>{{ getAttrValue(scope.row.feeAttrs, '390003') }}
  129 + </div>
  130 + <div v-else>
  131 + <span>{{ $t('simplifyRoomFee.unitPrice') }}</span>{{ scope.row.squarePrice }}
  132 + </div>
  133 + <div v-if="scope.row.feeFlag == '1003006'">
  134 + <span>{{ $t('simplifyRoomFee.additionalFee') }}</span>{{ scope.row.additionalAmount }}
  135 + </div>
  136 + <div v-else>
  137 + <span>{{ $t('simplifyRoomFee.fixedFee') }}</span>{{ scope.row.additionalAmount }}
  138 + </div>
  139 + </template>
  140 + </el-table-column>
  141 + <el-table-column prop="stateName" :label="$t('simplifyRoomFee.status')" align="center"></el-table-column>
  142 + <el-table-column :label="$t('simplifyRoomFee.operation')" align="center" width="200">
  143 + <template slot-scope="scope">
  144 + <el-button type="text" v-if="scope.row.state != '2009001' && hasPrivilege('502020082314267912')"
  145 + @click="payFee(scope.row)">
  146 + {{ $t('simplifyRoomFee.payment') }}
  147 + </el-button>
  148 + <el-button type="text" @click="payFeeHis(scope.row)">
  149 + {{ $t('simplifyRoomFee.paymentHistory') }}
  150 + </el-button>
  151 + <el-dropdown
  152 + v-if="hasPrivilege('502020090604200029') || hasPrivilege('502021070488970005') || hasPrivilege('502020090427190001')">
  153 + <span class="el-dropdown-link">
  154 + {{ $t('simplifyRoomFee.moreOperations') }}<i class="el-icon-arrow-down el-icon--right"></i>
  155 + </span>
  156 + <el-dropdown-menu slot="dropdown">
  157 + <el-dropdown-item v-if="hasPrivilege('502020090604200029')" @click.native="deleteFee(scope.row)">
  158 + {{ $t('simplifyRoomFee.cancelFee') }}
  159 + </el-dropdown-item>
  160 + <el-dropdown-item v-if="hasPrivilege('502021070488970005')" @click.native="finishFee(scope.row)">
  161 + {{ $t('simplifyRoomFee.manualEnd') }}
  162 + </el-dropdown-item>
  163 + <el-dropdown-item v-if="scope.row.state != '2009001' && hasPrivilege('502020090427190001')"
  164 + @click.native="editFee(scope.row)">
  165 + {{ $t('simplifyRoomFee.feeChange') }}
  166 + </el-dropdown-item>
  167 + <el-dropdown-item>
  168 + <a target="_blank" :href="'/#/pages/fee/feeDetail?feeId=' + scope.row.feeId">
  169 + {{ $t('simplifyRoomFee.details') }}
  170 + </a>
  171 + </el-dropdown-item>
  172 + </el-dropdown-menu>
  173 + </el-dropdown>
  174 + </template>
  175 + </el-table-column>
  176 + </el-table>
  177 + <el-pagination @current-change="handleCurrentChange" :current-page="currentPage" :page-size="pageSize"
  178 + layout="total, prev, pager, next" :total="total" class="pagination text-right"></el-pagination>
  179 + </div>
  180 +
  181 + <div class="margin-top" v-show="simplifyRoomFeeInfo.showFlag == 'MONTH'">
  182 + <el-table :data="simplifyRoomFeeInfo.monthFees" style="width: 100%" border stripe>
  183 + <el-table-column prop="feeName" :label="$t('simplifyRoomFee.feeItem')" align="center">
  184 + <template slot-scope="scope">
  185 + <span class="hand" @click="viewRoomFeeConfig(scope.row)">
  186 + {{ scope.row.feeName }}{{ getSimplifyRoomFeeRoomName(scope.row) }}
  187 + <i class="el-icon-info"></i>
  188 + </span>
  189 + </template>
  190 + </el-table-column>
  191 + <el-table-column prop="feeFlagName" :label="$t('simplifyRoomFee.feeFlag')" align="center"></el-table-column>
  192 + <el-table-column prop="feeTypeCdName" :label="$t('simplifyRoomFee.feeType')" align="center"></el-table-column>
  193 + <el-table-column :label="$t('simplifyRoomFee.chargeYearMonth')" align="center">
  194 + <template slot-scope="scope">
  195 + {{ scope.row.detailYear }}-{{ scope.row.detailMonth }}
  196 + </template>
  197 + </el-table-column>
  198 + <el-table-column prop="receivableAmount" :label="$t('simplifyRoomFee.receivableAmount')"
  199 + align="center"></el-table-column>
  200 + <el-table-column :label="$t('simplifyRoomFee.description')" align="center" width="150">
  201 + <template slot-scope="scope">
  202 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  203 + <span>{{ $t('simplifyRoomFee.preDegrees') }}</span>{{ scope.row.preDegrees }}
  204 + </div>
  205 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  206 + <span>{{ $t('simplifyRoomFee.curDegrees') }}</span>{{ scope.row.curDegrees }}
  207 + </div>
  208 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  209 + <span>{{ $t('simplifyRoomFee.unitPrice') }}</span>{{ getOnePrice1(scope.row) }}
  210 + </div>
  211 + <div v-if="scope.row.computingFormula == '5005' || scope.row.computingFormula == '9009'">
  212 + <span>{{ $t('simplifyRoomFee.additionalFee') }}</span>{{ scope.row.additionalAmount }}
  213 + </div>
  214 + <div v-else-if="scope.row.computingFormula == '6006'">
  215 + <span>{{ $t('simplifyRoomFee.usage') }}</span>{{ getAttrValue(scope.row.feeAttrs, '390006') }}
  216 + </div>
  217 + <div v-else-if="scope.row.computingFormula == '6006'">
  218 + <span>{{ $t('simplifyRoomFee.unitPrice') }}</span>{{ scope.row.squarePrice }}
  219 + </div>
  220 + <div v-else-if="scope.row.computingFormula == '6006'">
  221 + <span>{{ $t('simplifyRoomFee.additionalFee') }}</span>{{ scope.row.additionalAmount }}
  222 + </div>
  223 + <div v-else-if="scope.row.feeTypeCd == '888800010017'">
  224 + <span>{{ $t('simplifyRoomFee.algorithm') }}</span>{{ getAttrValue(scope.row.feeAttrs, '390005') }}
  225 + </div>
  226 + <div v-else-if="scope.row.feeTypeCd == '888800010017'">
  227 + <span>{{ $t('simplifyRoomFee.usage') }}</span>{{ getAttrValue(scope.row.feeAttrs, '390003') }}
  228 + </div>
  229 + <div v-else>
  230 + <span>{{ $t('simplifyRoomFee.unitPrice') }}</span>{{ scope.row.squarePrice }}
  231 + </div>
  232 + <div v-if="scope.row.feeFlag == '1003006'">
  233 + <span>{{ $t('simplifyRoomFee.additionalFee') }}</span>{{ scope.row.additionalAmount }}
  234 + </div>
  235 + <div v-else>
  236 + <span>{{ $t('simplifyRoomFee.fixedFee') }}</span>{{ scope.row.additionalAmount }}
  237 + </div>
  238 + </template>
  239 + </el-table-column>
  240 + <el-table-column :label="$t('simplifyRoomFee.operation')" align="center">
  241 + <template slot-scope="scope">
  242 + <a target="_blank" :href="'/#/pages/fee/feeDetail?feeId=' + scope.row.feeId">
  243 + {{ $t('simplifyRoomFee.details') }}
  244 + </a>
  245 + </template>
  246 + </el-table-column>
  247 + </el-table>
  248 + </div>
  249 +
  250 + <el-row>
  251 + <el-col :span="12" class="text-left">
  252 + <div>{{ $t('simplifyRoomFee.note1') }}</div>
  253 + <div>{{ $t('simplifyRoomFee.note2') }}</div>
  254 + </el-col>
  255 + <el-col :span="6">
  256 + <span>
  257 + <span>{{ $t('simplifyRoomFee.arrearsSubtotal') }}</span>{{ simplifyRoomFeeInfo.totalAmount }}
  258 + </span>
  259 + </el-col>
  260 + </el-row>
  261 + <!-- Modal Components -->
  262 + <delete-fee ref="deleteFee"></delete-fee>
  263 + <edit-fee ref="editFee"></edit-fee>
  264 + <temp-import-room-fee ref="tempImportRoomFee"></temp-import-room-fee>
  265 + </div>
  266 +</template>
  267 +
  268 +<script>
  269 +import { listFee, listFeeConfigs, listMonthFee } from '@/api/fee/simplifyRoomFeeApi'
  270 +import { getDict } from '@/api/community/communityApi'
  271 +import { getCommunityId } from '@/api/community/communityApi'
  272 +//import { listFeeConfigs } from '@/api/fee/feeConfigManageApi'
  273 +import TempImportRoomFee from './tempImportRoomFee'
  274 +import { dateFormat } from '@/utils/dateUtil'
  275 +import DeleteFee from '@/components/fee/deleteFee'
  276 +import EditFee from '@/components/fee/editFee'
  277 +
  278 +export default {
  279 + name: 'SimplifyRoomFee',
  280 + components: {
  281 + TempImportRoomFee,
  282 + DeleteFee,
  283 + EditFee,
  284 + },
  285 + data() {
  286 + return {
  287 + simplifyRoomFeeInfo: {
  288 + total: 0,
  289 + records: 1,
  290 + fees: [],
  291 + monthFees: [],
  292 + roomId: '',
  293 + roomName: '',
  294 + name: '',
  295 + floorNum: '',
  296 + unitNum: '',
  297 + roomNum: '',
  298 + configId: '',
  299 + feeTypeCds: [],
  300 + feeTypeCd: '',
  301 + state: '2008001',
  302 + totalAmount: 0.0,
  303 + roomType: '',
  304 + ownerFee: 'N',
  305 + ownerId: '',
  306 + showFlag: 'DEFAULT',
  307 + feeConfigs: []
  308 + },
  309 + currentPage: 1,
  310 + pageSize: 10,
  311 + total: 0
  312 + }
  313 + },
  314 + computed: {
  315 + filteredFeeTypeCds() {
  316 + return this.simplifyRoomFeeInfo.feeTypeCds.filter(item => item.statusCd !== '888800010008')
  317 + }
  318 + },
  319 + created() {
  320 + this.communityId = getCommunityId()
  321 + //this.loadDictData()
  322 + },
  323 + methods: {
  324 + open(params) {
  325 + this.handleSwitch(params)
  326 + },
  327 + handleSwitch(param) {
  328 + this.clearSimplifyRoomFeeInfo()
  329 + if (param.roomId === '') return
  330 +
  331 + Object.assign(this.simplifyRoomFeeInfo, param)
  332 + this.listSimplifyRoomFee(1, this.pageSize)
  333 +
  334 + getDict('pay_fee_config', 'fee_type_cd').then(data => {
  335 + this.simplifyRoomFeeInfo.feeTypeCds = data
  336 + })
  337 + },
  338 + handleNotify() {
  339 + this.listSimplifyRoomFee(this.currentPage, this.pageSize)
  340 + },
  341 + getOnePrice1(fee) {
  342 + let price = fee.mwPrice
  343 + if (!price) return fee.squarePrice
  344 + if (parseFloat(price) > 0) return price
  345 + return fee.squarePrice
  346 + },
  347 + async listSimplifyRoomFee(page, row) {
  348 + const params = {
  349 + page,
  350 + row,
  351 + communityId: getCommunityId(),
  352 + payerObjId: this.simplifyRoomFeeInfo.roomId,
  353 + payerObjType: '3333',
  354 + configId: this.simplifyRoomFeeInfo.configId,
  355 + state: this.simplifyRoomFeeInfo.state,
  356 + feeTypeCd: this.simplifyRoomFeeInfo.feeTypeCd
  357 + }
  358 +
  359 + if (this.simplifyRoomFeeInfo.ownerFee === 'Y') {
  360 + params.payerObjId = ''
  361 + params.ownerId = this.simplifyRoomFeeInfo.ownerId
  362 + }
  363 +
  364 + try {
  365 + const res = await listFee(params)
  366 + this.simplifyRoomFeeInfo.total = res.total
  367 + this.simplifyRoomFeeInfo.records = res.records
  368 + let totalAmount = 0.0
  369 +
  370 + res.fees.forEach(item => {
  371 + totalAmount += parseFloat(item.amountOwed)
  372 + })
  373 +
  374 + this.simplifyRoomFeeInfo.totalAmount = totalAmount.toFixed(2)
  375 + this.simplifyRoomFeeInfo.fees = res.fees.sort(this.roomFeeCompare)
  376 + this.total = res.records
  377 + } catch (error) {
  378 + console.error('Failed to fetch fee list:', error)
  379 + }
  380 + },
  381 + roomFeeCompare(a, b) {
  382 + if (a.payerObjName < b.payerObjName) return -1
  383 + if (a.payerObjName > b.payerObjName) return 1
  384 + return 0
  385 + },
  386 + toOwnerPayFee() {
  387 + this.$router.push({
  388 + path: '/property/owePayFeeOrder',
  389 + query: {
  390 + payObjId: this.simplifyRoomFeeInfo.roomId,
  391 + payObjType: '3333',
  392 + roomName: this.simplifyRoomFeeInfo.roomName
  393 + }
  394 + })
  395 + },
  396 + openRoomCreateFeeAddModal() {
  397 + this.simplifyRoomFeeInfo.ownerName = this.simplifyRoomFeeInfo.name
  398 + this.$emit('openRoomCreateFeeAddModal', {
  399 + isMore: false,
  400 + room: this.simplifyRoomFeeInfo,
  401 + ownerName: this.simplifyRoomFeeInfo.name
  402 + })
  403 + },
  404 + openAddMeterWaterSimplifyModal() {
  405 + this.$emit('openAddMeterWaterModal', {
  406 + roomId: this.simplifyRoomFeeInfo.roomId,
  407 + roomName: this.simplifyRoomFeeInfo.roomName,
  408 + ownerName: this.simplifyRoomFeeInfo.name
  409 + })
  410 + },
  411 + getAttrValue(attrs, specCd) {
  412 + const attr = attrs.find(item => item.specCd === specCd)
  413 + return attr ? attr.value : ""
  414 + },
  415 + getDeadlineTime(fee) {
  416 + if (fee.amountOwed == 0 && fee.endTime == fee.deadlineTime) return "-"
  417 + if (fee.state == '2009001') return "-"
  418 + return dateFormat(fee.deadlineTime)
  419 + },
  420 + getEndTime(fee) {
  421 + if (fee.state == '2009001') return "-"
  422 + return dateFormat(fee.endTime)
  423 + },
  424 + openProxyFeeModal() {
  425 + this.$emit('openAddProxyFeeModal', {
  426 + roomId: this.simplifyRoomFeeInfo.roomId,
  427 + roomName: this.simplifyRoomFeeInfo.roomName,
  428 + ownerName: this.simplifyRoomFeeInfo.name
  429 + })
  430 + },
  431 + payFee(fee) {
  432 + fee.roomName = this.simplifyRoomFeeInfo.roomName
  433 + fee.builtUpArea = this.simplifyRoomFeeInfo.builtUpArea
  434 + this.$router.push({
  435 + path: '/property/payFeeOrder',
  436 + query: { feeId: fee.feeId }
  437 + })
  438 + },
  439 + editFee(fee) {
  440 + fee.maxEndTime = this.getAttrValue(fee.feeAttrs, '390010')
  441 + this.$refs.editFee.open(fee)
  442 + },
  443 + payFeeHis(fee) {
  444 + fee.builtUpArea = this.simplifyRoomFeeInfo.builtUpArea
  445 + this.$router.push({
  446 + path: '/views/fee/propertyFee',
  447 + query: fee
  448 + })
  449 + },
  450 + deleteFee(fee) {
  451 + this.$emit('openDeleteFeeModal', {
  452 + communityId: getCommunityId(),
  453 + feeId: fee.feeId
  454 + })
  455 + },
  456 + finishFee(fee) {
  457 + this.$emit('openFinishFeeModal', {
  458 + communityId: getCommunityId(),
  459 + feeId: fee.feeId
  460 + })
  461 + },
  462 + openTempImportRoomFeeModal() {
  463 + this.$refs.tempImportRoomFee.open({
  464 + roomId: this.simplifyRoomFeeInfo.roomId,
  465 + roomName: this.simplifyRoomFeeInfo.roomName,
  466 + ownerName: this.simplifyRoomFeeInfo.name
  467 + })
  468 + },
  469 + clearSimplifyRoomFeeInfo() {
  470 + const feeConfigs = this.simplifyRoomFeeInfo.feeConfigs
  471 + this.simplifyRoomFeeInfo = {
  472 + total: 0,
  473 + records: 1,
  474 + fees: [],
  475 + monthFees: [],
  476 + accounts: [],
  477 + roomId: '',
  478 + name: '',
  479 + roomName: '',
  480 + floorNum: '',
  481 + unitNum: '',
  482 + roomNum: '',
  483 + feeConfigs: feeConfigs,
  484 + feeTypeCd: '',
  485 + configId: '',
  486 + state: '2008001',
  487 + totalAmount: 0.0,
  488 + roomType: '',
  489 + ownerFee: 'N',
  490 + ownerId: '',
  491 + showFlag: 'DEFAULT'
  492 + }
  493 + },
  494 + changeSimplifyRoomFeeFeeTypeCd(feeTypeCd) {
  495 + this.simplifyRoomFeeInfo.configId = ''
  496 + this.$emit('notify', {})
  497 +
  498 + const params = {
  499 + page: 1,
  500 + row: 50,
  501 + communityId: getCommunityId(),
  502 + feeTypeCd: feeTypeCd,
  503 + isDefault: '',
  504 + valid: '1'
  505 + }
  506 +
  507 + listFeeConfigs(params).then(res => {
  508 + this.simplifyRoomFeeInfo.feeConfigs = res.feeConfigs
  509 + }).catch(error => {
  510 + console.error('Failed to fetch fee configs:', error)
  511 + })
  512 + },
  513 + changeSimplifyRoomConfigId() {
  514 + this.$emit('notify', {})
  515 + },
  516 + simplifyRoomGetFeeOwnerInfo(attrs) {
  517 + const ownerName = this.getAttrValue(attrs, '390008')
  518 + const ownerLink = this.getAttrValue(attrs, '390009')
  519 + return `业主:${ownerName},电话:${ownerLink}`
  520 + },
  521 + getSimplifyRoomFeeRoomName(fee) {
  522 + if (this.simplifyRoomFeeInfo.ownerFee != 'Y') return ''
  523 +
  524 + const attr = fee.feeAttrs.find(item => item.specCd === '390012')
  525 + return attr ? `(${attr.value})` : ''
  526 + },
  527 + openBatchPayRoomFeeModal() {
  528 + this.$router.push({
  529 + path: '/views/fee/batchPayFeeOrder',
  530 + query: {
  531 + ownerId: this.simplifyRoomFeeInfo.ownerId,
  532 + payerObjType: '3333'
  533 + }
  534 + })
  535 + },
  536 + openMonthPayRoomFeeModal() {
  537 + this.$router.push({
  538 + path: '/property/payFeeMonthOrder',
  539 + query: {
  540 + payerObjId: this.simplifyRoomFeeInfo.roomId,
  541 + payerObjType: '3333'
  542 + }
  543 + })
  544 + },
  545 + openRoomCreateFeeComboModal() {
  546 + this.$router.push({
  547 + path: '/property/createFeeByCombo',
  548 + query: {
  549 + payerObjId: this.simplifyRoomFeeInfo.roomId,
  550 + payerObjName: this.simplifyRoomFeeInfo.roomName,
  551 + payerObjType: '3333'
  552 + }
  553 + })
  554 + },
  555 + viewRoomFeeConfig(fee) {
  556 + const params = {
  557 + page: 1,
  558 + row: 1,
  559 + communityId: getCommunityId(),
  560 + configId: fee.configId
  561 + }
  562 +
  563 + listFeeConfigs(params).then(res => {
  564 + const feeConfig = res.feeConfigs[0]
  565 + this.$emit('openViewDataModal', {
  566 + title: `${fee.feeName} 费用项`,
  567 + data: {
  568 + "费用项ID": feeConfig.configId,
  569 + "费用类型": feeConfig.feeTypeCdName,
  570 + "收费项目": feeConfig.feeName,
  571 + "费用标识": feeConfig.feeFlagName,
  572 + "催缴类型": feeConfig.billTypeName,
  573 + "付费类型": feeConfig.paymentCd == '1200' ? '预付费' : '后付费',
  574 + "缴费周期": feeConfig.paymentCycle,
  575 + "应收开始时间": feeConfig.startTime,
  576 + "应收结束时间": feeConfig.endTime,
  577 + "公式": feeConfig.computingFormulaName,
  578 + "计费单价": feeConfig.computingFormula == '2002' ? '-' : feeConfig.squarePrice,
  579 + "附加/固定费用": feeConfig.additionalAmount
  580 + }
  581 + })
  582 + }).catch(error => {
  583 + console.error('Failed to fetch fee config:', error)
  584 + })
  585 + },
  586 + viewRoomFee(fee) {
  587 + const data = {
  588 + "费用ID": fee.feeId,
  589 + "费用标识": fee.feeFlagName,
  590 + "费用类型": fee.feeTypeCdName,
  591 + "付费对象": fee.payerObjName,
  592 + "费用项": fee.feeName,
  593 + "费用状态": fee.stateName,
  594 + "建账时间": fee.startTime,
  595 + "应收开始时间": this.getEndTime(fee),
  596 + "应收结束时间": this.getDeadlineTime(fee),
  597 + "批次": fee.batchId
  598 + }
  599 +
  600 + fee.feeAttrs.forEach(attr => {
  601 + data[attr.specCdName] = attr.value
  602 + })
  603 +
  604 + this.$emit('openViewDataModal', {
  605 + title: `${fee.feeName} 详情`,
  606 + data: data
  607 + })
  608 + },
  609 + changeSimplifyRoomShowFlag() {
  610 + if (this.simplifyRoomFeeInfo.showFlag == 'MONTH') {
  611 + this.listSimplifyRoomMonthFee(1, this.pageSize)
  612 + } else {
  613 + this.listSimplifyRoomFee(1, this.pageSize)
  614 + }
  615 + },
  616 + async listSimplifyRoomMonthFee(page, row) {
  617 + const params = {
  618 + page,
  619 + row,
  620 + communityId: getCommunityId(),
  621 + objId: this.simplifyRoomFeeInfo.roomId,
  622 + payerObjType: '3333',
  623 + configId: this.simplifyRoomFeeInfo.configId,
  624 + feeTypeCd: this.simplifyRoomFeeInfo.feeTypeCd,
  625 + detailId: '-1',
  626 + feeState: '2008001'
  627 + }
  628 +
  629 + if (this.simplifyRoomFeeInfo.ownerFee == 'Y') {
  630 + params.payerObjId = ''
  631 + params.ownerId = this.simplifyRoomFeeInfo.ownerId
  632 + }
  633 +
  634 + try {
  635 + const res = await listMonthFee(params)
  636 + this.simplifyRoomFeeInfo.total = res.total
  637 + this.simplifyRoomFeeInfo.records = res.records
  638 + let totalAmount = 0.0
  639 +
  640 + res.data.forEach(item => {
  641 + totalAmount += parseFloat(item.receivableAmount)
  642 + })
  643 +
  644 + this.simplifyRoomFeeInfo.totalAmount = totalAmount.toFixed(2)
  645 + this.simplifyRoomFeeInfo.monthFees = res.data
  646 + } catch (error) {
  647 + console.error('Failed to fetch month fee list:', error)
  648 + }
  649 + },
  650 + handleCurrentChange(page) {
  651 + this.currentPage = page
  652 + if (this.simplifyRoomFeeInfo.showFlag == 'MONTH') {
  653 + this.listSimplifyRoomMonthFee(page, this.pageSize)
  654 + } else {
  655 + this.listSimplifyRoomFee(page, this.pageSize)
  656 + }
  657 + },
  658 + // 其他方法类似
  659 + }
  660 +}
  661 +</script>
  662 +
  663 +<style scoped>
  664 +.margin-top-lg {
  665 + margin-top: 20px;
  666 +}
  667 +
  668 +.margin-top {
  669 + margin-top: 15px;
  670 +}
  671 +
  672 +.text-right {
  673 + text-align: right;
  674 +}
  675 +
  676 +.hand {
  677 + cursor: pointer;
  678 +}
  679 +</style>
0 \ No newline at end of file 680 \ No newline at end of file
src/components/fee/simplifyRoomFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <simplify-room-fee ref="simplifyRoomFee"></simplify-room-fee>
  4 + </div>
  5 +</template>
  6 +
  7 +<script>
  8 +import SimplifyRoomFee from './simplifyRoomFee'
  9 +
  10 +export default {
  11 + name: 'SimplifyRoomFeeDemo',
  12 + components: {
  13 + SimplifyRoomFee
  14 + },
  15 + mounted() {
  16 + this.$refs.simplifyRoomFee.$emit('switch', {
  17 + roomId: '123',
  18 + roomName: '测试房间',
  19 + name: '测试业主'
  20 + })
  21 + }
  22 +}
  23 +</script>
0 \ No newline at end of file 24 \ No newline at end of file
src/components/fee/tempImportRoomFee.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('tempImportRoomFee.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="70%"
  6 + @close="clearTempImportRoomFeeInfo"
  7 + >
  8 + <el-form :model="form" label-width="120px">
  9 + <el-form-item :label="$t('tempImportRoomFee.feeType')">
  10 + <el-select
  11 + v-model="form.feeTypeCd"
  12 + @change="changeFeeTypeCd"
  13 + :placeholder="$t('tempImportRoomFee.selectFeeType')"
  14 + >
  15 + <el-option
  16 + v-for="(item,index) in feeTypeCds"
  17 + :key="index"
  18 + :label="item.name"
  19 + :value="item.statusCd"
  20 + ></el-option>
  21 + </el-select>
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('tempImportRoomFee.feeObj')">
  25 + <el-input
  26 + v-model="form.objName"
  27 + disabled
  28 + :placeholder="$t('tempImportRoomFee.inputFeeObj')"
  29 + ></el-input>
  30 + </el-form-item>
  31 +
  32 + <el-form-item :label="$t('tempImportRoomFee.feeName')" v-if="form.feeNameFlag === 'S'">
  33 + <el-select
  34 + v-model="form.configId"
  35 + :placeholder="$t('tempImportRoomFee.selectFeeItem')"
  36 + >
  37 + <el-option
  38 + v-for="(item,index) in feeConfigs"
  39 + :key="index"
  40 + :label="item.feeName"
  41 + :value="item.configId"
  42 + ></el-option>
  43 + </el-select>
  44 + <span>{{$t('tempImportRoomFee.feeItemDesc')}}</span>
  45 + </el-form-item>
  46 +
  47 + <el-form-item :label="$t('tempImportRoomFee.feeName')" v-else>
  48 + <el-col :span="18">
  49 + <el-input
  50 + v-model="form.feeName"
  51 + :placeholder="$t('tempImportRoomFee.inputFeeName')"
  52 + ></el-input>
  53 + </el-col>
  54 + <el-col :span="6">
  55 + <el-button @click="toggleFeeNameFlag">{{$t('tempImportRoomFee.select')}}</el-button>
  56 + </el-col>
  57 + </el-form-item>
  58 +
  59 + <el-form-item :label="$t('tempImportRoomFee.amount')">
  60 + <el-input
  61 + v-model="form.amount"
  62 + :placeholder="$t('tempImportRoomFee.inputAmount')"
  63 + ></el-input>
  64 + </el-form-item>
  65 +
  66 + <el-form-item :label="$t('tempImportRoomFee.startTime')">
  67 + <el-date-picker
  68 + v-model="form.startTime"
  69 + type="datetime"
  70 + :placeholder="$t('tempImportRoomFee.selectStartTime')"
  71 + value-format="yyyy-MM-dd HH:mm:ss"
  72 + ></el-date-picker>
  73 + </el-form-item>
  74 +
  75 + <el-form-item :label="$t('tempImportRoomFee.endTime')">
  76 + <el-date-picker
  77 + v-model="form.endTime"
  78 + type="datetime"
  79 + :placeholder="$t('tempImportRoomFee.selectEndTime')"
  80 + value-format="yyyy-MM-dd HH:mm:ss"
  81 + ></el-date-picker>
  82 + </el-form-item>
  83 + </el-form>
  84 +
  85 + <div slot="footer" class="dialog-footer">
  86 + <el-button @click="dialogVisible = false">{{$t('tempImportRoomFee.cancel')}}</el-button>
  87 + <el-button type="primary" @click="saveTempImportFeeInfo">{{$t('tempImportRoomFee.submit')}}</el-button>
  88 + </div>
  89 + </el-dialog>
  90 +</template>
  91 +
  92 +<script>
  93 +import { importTempData } from '@/api/fee/tempImportRoomFeeApi'
  94 +import { getDict } from '@/api/community/communityApi'
  95 +import { getCommunityId } from '@/api/community/communityApi'
  96 +import { listFeeConfigs } from '@/api/fee/feeConfigManageApi'
  97 +export default {
  98 + name: 'TempImportRoomFee',
  99 + data() {
  100 + return {
  101 + dialogVisible: false,
  102 + form: {
  103 + communityId: '',
  104 + feeTypeCd: '',
  105 + objType: '',
  106 + feeTypeCds: [],
  107 + configId: '',
  108 + objName: '',
  109 + objId: '',
  110 + amount: '',
  111 + startTime: this.formatDate(new Date()),
  112 + endTime: this.addMonth(new Date(), 1),
  113 + feeConfigs: [],
  114 + feeNameFlag: 'S'
  115 + },
  116 + feeTypeCds: [],
  117 + feeConfigs: [],
  118 + communityId: ''
  119 + }
  120 + },
  121 + created() {
  122 + this.communityId = getCommunityId()
  123 + this.loadDictData()
  124 + },
  125 + methods: {
  126 + open(room) {
  127 + this.clearTempImportRoomFeeInfo()
  128 + this.form.objId = room.roomId
  129 + this.form.objName = room.roomName
  130 + this.form.objType = room.objType
  131 + this.dialogVisible = true
  132 + },
  133 + async loadDictData() {
  134 + try {
  135 + const data = await getDict('pay_fee_config', 'fee_type_cd')
  136 + this.feeTypeCds = data
  137 + this.form.feeTypeCds = data
  138 + } catch (error) {
  139 + console.error('获取字典数据失败:', error)
  140 + }
  141 + },
  142 + async changeFeeTypeCd(feeTypeCd) {
  143 + try {
  144 + const res = await listFeeConfigs({
  145 + page: 1,
  146 + row: 500,
  147 + communityId: this.communityId,
  148 + feeTypeCd: feeTypeCd,
  149 + isDefault: 'F',
  150 + computingFormula: '4004',
  151 + valid: '1'
  152 + })
  153 + this.feeConfigs = res.feeConfigs
  154 + } catch (error) {
  155 + console.error('获取费用配置失败:', error)
  156 + }
  157 + },
  158 + toggleFeeNameFlag() {
  159 + this.form.feeNameFlag = this.form.feeNameFlag === 'S' ? 'I' : 'S'
  160 + },
  161 + validateForm() {
  162 + if (!this.form.feeTypeCd) {
  163 + this.$message.warning(this.$t('tempImportRoomFee.feeTypeRequired'))
  164 + return false
  165 + }
  166 + if (!this.form.configId && this.form.feeNameFlag === 'S') {
  167 + this.$message.warning(this.$t('tempImportRoomFee.feeNameRequired'))
  168 + return false
  169 + }
  170 + if (!this.form.objId) {
  171 + this.$message.warning(this.$t('tempImportRoomFee.feeObjRequired'))
  172 + return false
  173 + }
  174 + if (!this.form.startTime) {
  175 + this.$message.warning(this.$t('tempImportRoomFee.startTimeRequired'))
  176 + return false
  177 + }
  178 + if (!this.form.endTime) {
  179 + this.$message.warning(this.$t('tempImportRoomFee.endTimeRequired'))
  180 + return false
  181 + }
  182 + if (new Date(this.form.startTime) >= new Date(this.form.endTime)) {
  183 + this.$message.warning(this.$t('tempImportRoomFee.endTimeMustAfterStart'))
  184 + return false
  185 + }
  186 + if (!this.form.amount) {
  187 + this.$message.warning(this.$t('tempImportRoomFee.amountRequired'))
  188 + return false
  189 + }
  190 + return true
  191 + },
  192 + async saveTempImportFeeInfo() {
  193 + if (!this.validateForm()) return
  194 +
  195 + try {
  196 + const res = await importTempData({
  197 + ...this.form,
  198 + communityId: this.communityId
  199 + })
  200 + if (res.code === 0) {
  201 + this.dialogVisible = false
  202 + this.$emit('notify')
  203 + this.$message.success(this.$t('tempImportRoomFee.createSuccess'))
  204 + } else {
  205 + this.$message.error(res.msg)
  206 + }
  207 + } catch (error) {
  208 + console.error('请求失败:', error)
  209 + this.$message.error(this.$t('tempImportRoomFee.createFailed'))
  210 + }
  211 + },
  212 + clearTempImportRoomFeeInfo() {
  213 + this.form = {
  214 + communityId: this.communityId,
  215 + feeTypeCd: '',
  216 + feeTypeCds: this.feeTypeCds,
  217 + configId: '',
  218 + objName: '',
  219 + objId: '',
  220 + amount: '',
  221 + startTime: this.formatDate(new Date()),
  222 + endTime: this.addMonth(new Date(), 1),
  223 + feeNameFlag: 'S',
  224 + feeConfigs: []
  225 + }
  226 + },
  227 + formatDate(date) {
  228 + const year = date.getFullYear()
  229 + const month = String(date.getMonth() + 1).padStart(2, '0')
  230 + const day = String(date.getDate()).padStart(2, '0')
  231 + const hours = String(date.getHours()).padStart(2, '0')
  232 + const minutes = String(date.getMinutes()).padStart(2, '0')
  233 + const seconds = String(date.getSeconds()).padStart(2, '0')
  234 + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
  235 + },
  236 + addMonth(date, months) {
  237 + const newDate = new Date(date)
  238 + newDate.setMonth(newDate.getMonth() + months)
  239 + return this.formatDate(newDate)
  240 + }
  241 + }
  242 +}
  243 +</script>
0 \ No newline at end of file 244 \ No newline at end of file
src/components/fee/tempImportRoomFeeDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openModal">{{$t('tempImportRoomFeeDemo.openModal')}}</el-button>
  4 + <temp-import-room-fee ref="tempImportRoomFee"></temp-import-room-fee>
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import TempImportRoomFee from './tempImportRoomFee'
  10 +
  11 +export default {
  12 + name: 'TempImportRoomFeeDemo',
  13 + components: {
  14 + TempImportRoomFee
  15 + },
  16 + methods: {
  17 + openModal() {
  18 + this.$refs.tempImportRoomFee.open({
  19 + roomId: '123',
  20 + roomName: '测试房间',
  21 + ownerName: '测试业主'
  22 + })
  23 + }
  24 + }
  25 +}
  26 +</script>
0 \ No newline at end of file 27 \ No newline at end of file
src/components/fee/viewFeeConfigData.vue 0 → 100644
  1 +<template>
  2 + <el-tooltip effect="dark" content="查看详情" placement="top">
  3 + <i class="el-icon-info hand" @click="open"></i>
  4 + </el-tooltip>
  5 +</template>
  6 +
  7 +<script>
  8 +import { getCommunityId } from '@/api/community/communityApi'
  9 +import { listFeeConfigs } from '@/api/fee/propertyFeeApi'
  10 +
  11 +export default {
  12 + name: 'ViewFeeConfigData',
  13 + data() {
  14 + return {
  15 + configId: '',
  16 + communityId: ''
  17 + }
  18 + },
  19 + created() {
  20 + this.communityId = getCommunityId()
  21 + },
  22 + methods: {
  23 + open(params) {
  24 + this.configId = params.configId
  25 + this._loadFeeConfigData()
  26 + },
  27 + async _loadFeeConfigData() {
  28 + try {
  29 + const res = await listFeeConfigs({
  30 + page: 1,
  31 + row: 1,
  32 + communityId: this.communityId,
  33 + configId: this.configId
  34 + })
  35 +
  36 + if (res.data && res.data.length > 0) {
  37 + const feeConfig = res.data[0]
  38 + const configData = {
  39 + "费用项ID": feeConfig.configId,
  40 + "费用类型": feeConfig.feeTypeCdName,
  41 + "收费项目": feeConfig.feeName,
  42 + "费用标识": feeConfig.feeFlagName,
  43 + "催缴类型": feeConfig.billTypeName,
  44 + "付费类型": feeConfig.paymentCd === '1200' ? this.$t('viewFeeConfigData.prepaid') : this.$t('viewFeeConfigData.postpaid'),
  45 + "缴费周期": feeConfig.paymentCycle,
  46 + "计费起始时间": feeConfig.startTime,
  47 + "计费终止时间": feeConfig.endTime,
  48 + "公式": feeConfig.computingFormulaName,
  49 + "计费单价": feeConfig.computingFormula === '2002' ? '-' : feeConfig.squarePrice,
  50 + "附加/固定费用": feeConfig.additionalAmount
  51 + }
  52 +
  53 + this.$emit('openViewDataModal', {
  54 + title: `${feeConfig.feeName} ${this.$t('viewFeeConfigData.feeItem')}`,
  55 + data: configData
  56 + })
  57 + }
  58 + } catch (error) {
  59 + console.error('加载费用配置数据失败:', error)
  60 + }
  61 + }
  62 + }
  63 +}
  64 +</script>
  65 +
  66 +<style scoped>
  67 +.hand {
  68 + cursor: pointer;
  69 + color: #409EFF;
  70 + margin-left: 5px;
  71 +}
  72 +</style>
0 \ No newline at end of file 73 \ No newline at end of file
src/components/fee/viewFeeDetailDiscount.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('viewFeeDetailDiscount.discount')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + center
  7 + >
  8 + <el-table
  9 + :data="viewFeeDetailDiscountInfo.feeDetailDiscounts"
  10 + border
  11 + stripe
  12 + style="width: 100%"
  13 + >
  14 + <el-table-column
  15 + prop="discountName"
  16 + :label="$t('viewFeeDetailDiscount.discountName')"
  17 + align="center"
  18 + />
  19 + <el-table-column
  20 + :label="$t('viewFeeDetailDiscount.discountType')"
  21 + align="center"
  22 + >
  23 + <template slot-scope="scope">
  24 + {{ scope.row.discountType === '1001' ? $t('viewFeeDetailDiscount.discount') : $t('viewFeeDetailDiscount.breach') }}
  25 + </template>
  26 + </el-table-column>
  27 + <el-table-column
  28 + prop="ruleName"
  29 + :label="$t('viewFeeDetailDiscount.ruleName')"
  30 + align="center"
  31 + />
  32 + <el-table-column
  33 + :label="$t('viewFeeDetailDiscount.discountRule')"
  34 + align="center"
  35 + >
  36 + <template slot-scope="scope">
  37 + <div v-for="(item,index) in scope.row.feeDiscountSpecs" :key="index">
  38 + {{item.specName}}:{{item.specValue}}
  39 + </div>
  40 + </template>
  41 + </el-table-column>
  42 + <el-table-column
  43 + prop="discountPrice"
  44 + :label="$t('viewFeeDetailDiscount.discountAmount')"
  45 + align="center"
  46 + />
  47 + </el-table>
  48 + </el-dialog>
  49 +</template>
  50 +
  51 +<script>
  52 +import { getCommunityId } from '@/api/community/communityApi'
  53 +import { queryFeeDetailDiscount } from '@/api/fee/propertyFeeApi'
  54 +
  55 +export default {
  56 + name: 'ViewFeeDetailDiscount',
  57 + data() {
  58 + return {
  59 + visible: false,
  60 + viewFeeDetailDiscountInfo: {
  61 + feeDetailDiscounts: []
  62 + },
  63 + communityId: ''
  64 + }
  65 + },
  66 + created() {
  67 + this.communityId = getCommunityId()
  68 + },
  69 + methods: {
  70 + open(params) {
  71 + this.visible = true
  72 + this._loadAllFeeDetailDiscountInfo(params)
  73 + },
  74 + async _loadAllFeeDetailDiscountInfo(params) {
  75 + try {
  76 + const res = await queryFeeDetailDiscount({
  77 + page: 1,
  78 + row: 30,
  79 + communityId: this.communityId,
  80 + detailId: params.detailId
  81 + })
  82 +
  83 + this.viewFeeDetailDiscountInfo.feeDetailDiscounts = res.data || []
  84 + } catch (error) {
  85 + console.error('加载折扣信息失败:', error)
  86 + }
  87 + }
  88 + }
  89 +}
  90 +</script>
  91 +
  92 +<style scoped>
  93 +.el-table {
  94 + margin-top: 15px;
  95 +}
  96 +</style>
0 \ No newline at end of file 97 \ No newline at end of file
src/components/fee/viewMainFee.vue 0 → 100644
  1 +<template>
  2 + <el-card class="box-card">
  3 + <div slot="header" class="clearfix">
  4 + <span>{{ $t('viewMainFee.feeInfo') }}</span>
  5 + <el-button
  6 + type="primary"
  7 + size="small"
  8 + style="float: right; margin-left: 10px;"
  9 + @click="_openCallBackOwner"
  10 + >
  11 + {{ $t('common.back') }}
  12 + </el-button>
  13 + </div>
  14 +
  15 + <el-row :gutter="20">
  16 + <el-col :span="6">
  17 + <div class="form-item">
  18 + <label>{{ $t('viewMainFee.feeId') }}</label>
  19 + <div>{{ mainFeeInfo.feeId }}</div>
  20 + </div>
  21 + </el-col>
  22 + <el-col :span="6">
  23 + <div class="form-item">
  24 + <label>{{ $t('viewMainFee.feeFlag') }}</label>
  25 + <div>{{ mainFeeInfo.feeFlagName }}</div>
  26 + </div>
  27 + </el-col>
  28 + <el-col :span="6">
  29 + <div class="form-item">
  30 + <label>{{ $t('viewMainFee.feeType') }}</label>
  31 + <div>{{ mainFeeInfo.feeTypeCdName }}</div>
  32 + </div>
  33 + </el-col>
  34 + <el-col :span="6">
  35 + <div class="form-item">
  36 + <label>{{ $t('viewMainFee.payerObj') }}</label>
  37 + <div>
  38 + {{ mainFeeInfo.payerObjName }}
  39 + <view-room-data
  40 + v-if="mainFeeInfo.payerObjType == '3333'"
  41 + ref="viewRoomData"
  42 + />
  43 + </div>
  44 + </div>
  45 + </el-col>
  46 +
  47 + <el-col :span="6">
  48 + <div class="form-item">
  49 + <label>{{ $t('viewMainFee.feeItem') }}</label>
  50 + <div class="hand" @click="_viewFeeConfig">
  51 + {{ mainFeeInfo.feeName }}
  52 + <view-fee-config-data ref="viewFeeConfigData" />
  53 + </div>
  54 + </div>
  55 + </el-col>
  56 + <el-col :span="6">
  57 + <div class="form-item">
  58 + <label>{{ $t('viewMainFee.feeStatus') }}</label>
  59 + <div>{{ mainFeeInfo.stateName }}</div>
  60 + </div>
  61 + </el-col>
  62 + <el-col :span="6">
  63 + <div class="form-item">
  64 + <label>{{ $t('viewMainFee.startTime') }}</label>
  65 + <div>{{ mainFeeInfo.startTime }}</div>
  66 + </div>
  67 + </el-col>
  68 + <el-col :span="6">
  69 + <div class="form-item">
  70 + <label>{{ $t('viewMainFee.billingStartTime') }}</label>
  71 + <div>{{ _getEndTime(mainFeeInfo) }}</div>
  72 + </div>
  73 + </el-col>
  74 +
  75 + <el-col :span="6">
  76 + <div class="form-item">
  77 + <label>{{ $t('viewMainFee.billingEndTime') }}</label>
  78 + <div>{{ _getDeadlineTime(mainFeeInfo) }}</div>
  79 + </div>
  80 + </el-col>
  81 + <el-col :span="6" v-if="mainFeeInfo.amount != '-1.00'">
  82 + <div class="form-item">
  83 + <label>{{ $t('viewMainFee.feeAmount') }}</label>
  84 + <div>{{ mainFeeInfo.amount }}</div>
  85 + </div>
  86 + </el-col>
  87 + <el-col :span="6">
  88 + <div class="form-item">
  89 + <label>{{ $t('viewMainFee.batch') }}</label>
  90 + <div>{{ mainFeeInfo.batchId }}</div>
  91 + </div>
  92 + </el-col>
  93 +
  94 + <template v-for="(item,index) in mainFeeInfo.feeAttrs">
  95 + <el-col :span="6" :key="index">
  96 + <div class="form-item">
  97 + <label>{{ item.specCdName }}:</label>
  98 + <div>{{ item.value }}</div>
  99 + </div>
  100 + </el-col>
  101 + </template>
  102 + </el-row>
  103 +
  104 + <el-row :gutter="20" v-if="mainFeeInfo.payerObjType == '3333'">
  105 + <el-col :span="6">
  106 + <div class="form-item">
  107 + <label>{{ $t('viewMainFee.area') }}</label>
  108 + <div>{{ mainFeeInfo.builtUpArea }}</div>
  109 + </div>
  110 + </el-col>
  111 + <el-col :span="6">
  112 + <div class="form-item">
  113 + <label>{{ $t('viewMainFee.unitPrice') }}</label>
  114 + <div>{{ mainFeeInfo.squarePrice }}</div>
  115 + </div>
  116 + </el-col>
  117 + <el-col :span="6">
  118 + <div class="form-item">
  119 + <label>{{ $t('viewMainFee.additionalFee') }}</label>
  120 + <div>{{ mainFeeInfo.additionalAmount }}</div>
  121 + </div>
  122 + </el-col>
  123 + </el-row>
  124 +
  125 + <el-row :gutter="20" v-else>
  126 + <el-col :span="6">
  127 + <div class="form-item">
  128 + <label>{{ $t('viewMainFee.fixedFee') }}</label>
  129 + <div>{{ mainFeeInfo.additionalAmount }}</div>
  130 + </div>
  131 + </el-col>
  132 + </el-row>
  133 + </el-card>
  134 +</template>
  135 +
  136 +<script>
  137 +import { getCommunityId } from '@/api/community/communityApi'
  138 +import { listFee } from '@/api/fee/propertyFeeApi'
  139 +import ViewRoomData from './viewRoomData'
  140 +import ViewFeeConfigData from './viewFeeConfigData'
  141 +
  142 +export default {
  143 + name: 'ViewMainFee',
  144 + components: {
  145 + ViewRoomData,
  146 + ViewFeeConfigData
  147 + },
  148 + props: {
  149 + feeName: {
  150 + type: String,
  151 + required: true
  152 + },
  153 + feeTypeCd: {
  154 + type: String,
  155 + required: true
  156 + },
  157 + payName: {
  158 + type: String,
  159 + required: true
  160 + }
  161 + },
  162 + data() {
  163 + return {
  164 + mainFeeInfo: {
  165 + feeName: this.feeName,
  166 + feeId: "",
  167 + feeTypeCd: '',
  168 + builtUpArea: "",
  169 + startTime: "",
  170 + endTime: "",
  171 + amount: "-1.00",
  172 + feeFlagName: '',
  173 + feeTypeCdName: '',
  174 + configId: '',
  175 + stateName: '',
  176 + additionalAmount: 0.0,
  177 + squarePrice: 0,
  178 + deadlineTime: '',
  179 + payerObjType: '',
  180 + payerObjId: '',
  181 + payerObjName: '',
  182 + feeAttrs: [],
  183 + batchId: ''
  184 + },
  185 + communityId: ''
  186 + }
  187 + },
  188 + created() {
  189 + this.communityId = getCommunityId()
  190 + const feeId = this.$route.query.feeId
  191 + if (feeId) {
  192 + this.loadMainFeeInfo({ feeId })
  193 + }
  194 + },
  195 + methods: {
  196 + async loadMainFeeInfo(params) {
  197 + try {
  198 + const res = await listFee({
  199 + ...params,
  200 + communityId: this.communityId,
  201 + page: 1,
  202 + row: 1
  203 + })
  204 +
  205 + if (res.data && res.data.length > 0) {
  206 + Object.assign(this.mainFeeInfo, res.data[0])
  207 + this.mainFeeInfo.feeAttrs = res.data[0].feeAttrs || []
  208 +
  209 + if (this.mainFeeInfo.payerObjType === '3333') {
  210 + this._loadRoomAndOwnerByRoomId()
  211 + } else if (this.mainFeeInfo.payerObjType === '6666') {
  212 + this._loadRoomAndOwnerByCarId()
  213 + } else {
  214 + this._loadContractAndOwnerByContractId()
  215 + }
  216 +
  217 + this.$emit('listFeeDetail', { feeId: this.mainFeeInfo.feeId })
  218 + }
  219 + } catch (error) {
  220 + console.error('加载主费用信息失败:', error)
  221 + }
  222 + },
  223 + _openCallBackOwner() {
  224 + this.$router.go(-1)
  225 + },
  226 + _getDeadlineTime(fee) {
  227 + if (fee.endTime === fee.deadlineTime || fee.state === '2009001') {
  228 + return "-"
  229 + }
  230 + return fee.deadlineTime
  231 + },
  232 + _getEndTime(fee) {
  233 + if (fee.state === '2009001') {
  234 + return "-"
  235 + }
  236 + return fee.endTime
  237 + },
  238 + _viewFeeConfig() {
  239 + this.$refs.viewFeeConfigData.open({ configId: this.mainFeeInfo.configId })
  240 + },
  241 + _viewRoomData() {
  242 + this.$refs.viewRoomData.open({ roomId: this.mainFeeInfo.payerObjId })
  243 + },
  244 + async _loadRoomAndOwnerByRoomId() {
  245 + // 实现获取房间和业主信息的逻辑
  246 + },
  247 + async _loadRoomAndOwnerByCarId() {
  248 + // 实现获取车位和业主信息的逻辑
  249 + },
  250 + async _loadContractAndOwnerByContractId() {
  251 + // 实现获取合同和业主信息的逻辑
  252 + }
  253 + }
  254 +}
  255 +</script>
  256 +
  257 +<style scoped>
  258 +.form-item {
  259 + margin-bottom: 20px;
  260 +
  261 + label {
  262 + display: block;
  263 + margin-bottom: 5px;
  264 + font-weight: bold;
  265 + }
  266 +
  267 + div {
  268 + padding: 8px 0;
  269 + }
  270 +}
  271 +
  272 +.hand {
  273 + cursor: pointer;
  274 + color: #409EFF;
  275 +
  276 + &:hover {
  277 + text-decoration: underline;
  278 + }
  279 +}
  280 +</style>
0 \ No newline at end of file 281 \ No newline at end of file
src/components/fee/viewRoomData.vue 0 → 100644
  1 +<template>
  2 + <el-tooltip effect="dark" content="查看详情" placement="top">
  3 + <i class="el-icon-info hand" @click="open"></i>
  4 + </el-tooltip>
  5 +</template>
  6 +
  7 +<script>
  8 +import { getCommunityId } from '@/api/community/communityApi'
  9 +import { queryRooms } from '@/api/fee/propertyFeeApi'
  10 +
  11 +export default {
  12 + name: 'ViewRoomData',
  13 + data() {
  14 + return {
  15 + roomId: '',
  16 + communityId: ''
  17 + }
  18 + },
  19 + created() {
  20 + this.communityId = getCommunityId()
  21 + },
  22 + methods: {
  23 + open(params) {
  24 + this.roomId = params.roomId
  25 + this._loadViewRoomData()
  26 + },
  27 + async _loadViewRoomData() {
  28 + try {
  29 + const res = await queryRooms({
  30 + page: 1,
  31 + row: 1,
  32 + communityId: this.communityId,
  33 + roomId: this.roomId
  34 + })
  35 +
  36 + if (res.data && res.data.length > 0) {
  37 + const room = res.data[0]
  38 + const roomData = {
  39 + "房屋": `${room.floorNum}-${room.unitNum}-${room.roomNum}`,
  40 + "楼层": room.layer,
  41 + "业主": room.ownerName || '-',
  42 + "电话": room.link || '-',
  43 + "类型": room.roomSubTypeName,
  44 + "建筑面积": room.builtUpArea,
  45 + "室内面积": room.roomArea,
  46 + "租金": room.roomRent,
  47 + "房屋状态": room.stateName,
  48 + "入住时间": room.startTime
  49 + }
  50 +
  51 + if (room.roomAttrDto) {
  52 + room.roomAttrDto.forEach(attr => {
  53 + roomData[attr.specName] = attr.valueName
  54 + })
  55 + }
  56 +
  57 + this.$emit('openViewDataModal', {
  58 + title: `${room.floorNum}-${room.unitNum}-${room.roomNum} 详情`,
  59 + data: roomData
  60 + })
  61 + }
  62 + } catch (error) {
  63 + console.error('加载房间数据失败:', error)
  64 + }
  65 + }
  66 + }
  67 +}
  68 +</script>
  69 +
  70 +<style scoped>
  71 +.hand {
  72 + cursor: pointer;
  73 + color: #409EFF;
  74 + margin-left: 5px;
  75 +}
  76 +</style>
0 \ No newline at end of file 77 \ No newline at end of file
src/components/fee/writeOweFeeCallable.vue
1 <template> 1 <template>
2 - <el-dialog :title="$t('oweFeeCallable.write.title')" :visible.sync="dialogVisible" width="50%" @close="handleClose">  
3 - <el-form :model="form" label-width="120px" ref="form">  
4 - <el-form-item :label="$t('oweFeeCallable.write.roomName')" prop="roomName">  
5 - <el-input v-model="form.roomName" disabled></el-input>  
6 - </el-form-item>  
7 - <el-form-item :label="$t('oweFeeCallable.write.feeName')" prop="feeIds">  
8 - <el-checkbox-group v-model="form.feeIds">  
9 - <el-checkbox v-for="fee in form.fees" :key="fee.feeId" :label="fee.feeId">  
10 - {{ fee.feeName }}  
11 - </el-checkbox>  
12 - </el-checkbox-group>  
13 - </el-form-item>  
14 - <el-form-item :label="$t('oweFeeCallable.write.remark')" prop="remark">  
15 - <el-input type="textarea" :rows="5" v-model="form.remark"  
16 - :placeholder="$t('oweFeeCallable.write.remarkPlaceholder')">  
17 - </el-input>  
18 - </el-form-item>  
19 - </el-form> 2 + <el-dialog
  3 + :title="$t('writeOweFeeCallable.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="70%"
  6 + :before-close="handleClose"
  7 + >
  8 + <div class="ibox-content">
  9 + <el-form label-width="120px">
  10 + <el-form-item :label="$t('writeOweFeeCallable.room')">
  11 + <el-input
  12 + v-model="writeOweFeeCallableInfo.roomName"
  13 + readonly
  14 + :placeholder="$t('writeOweFeeCallable.roomPlaceholder')"
  15 + ></el-input>
  16 + </el-form-item>
  17 + <el-form-item :label="$t('writeOweFeeCallable.fees')">
  18 + <el-checkbox-group v-model="writeOweFeeCallableInfo.feeIds">
  19 + <el-checkbox
  20 + v-for="(item,index) in writeOweFeeCallableInfo.fees"
  21 + :key="index"
  22 + :label="item.feeId"
  23 + >
  24 + {{item.feeName}}
  25 + </el-checkbox>
  26 + </el-checkbox-group>
  27 + </el-form-item>
  28 + <el-form-item :label="$t('writeOweFeeCallable.remark')">
  29 + <el-input
  30 + type="textarea"
  31 + :rows="5"
  32 + v-model="writeOweFeeCallableInfo.remark"
  33 + :placeholder="$t('writeOweFeeCallable.remarkPlaceholder')"
  34 + ></el-input>
  35 + </el-form-item>
  36 + </el-form>
  37 + </div>
20 <span slot="footer" class="dialog-footer"> 38 <span slot="footer" class="dialog-footer">
21 - <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>  
22 - <el-button type="primary" @click="handleSubmit">{{ $t('common.submit') }}</el-button> 39 + <el-button @click="dialogVisible = false">{{ $t('writeOweFeeCallable.cancel') }}</el-button>
  40 + <el-button type="primary" @click="_wirteCallable">{{ $t('writeOweFeeCallable.submit') }}</el-button>
23 </span> 41 </span>
24 </el-dialog> 42 </el-dialog>
25 </template> 43 </template>
26 44
27 <script> 45 <script>
28 -import { listFee } from '@/api/fee/feeApi'  
29 -import { writeOweFeeCallable } from '@/api/fee/oweFeeCallableApi'  
30 import { getCommunityId } from '@/api/community/communityApi' 46 import { getCommunityId } from '@/api/community/communityApi'
  47 +import { writeOweFeeCallable, listFee } from '@/api/fee/writeOweFeeCallableApi'
31 48
32 export default { 49 export default {
33 name: 'WriteOweFeeCallable', 50 name: 'WriteOweFeeCallable',
34 data() { 51 data() {
35 return { 52 return {
36 dialogVisible: false, 53 dialogVisible: false,
37 - form: { 54 + writeOweFeeCallableInfo: {
38 roomId: '', 55 roomId: '',
39 roomName: '', 56 roomName: '',
40 fees: [], 57 fees: [],
41 feeIds: [], 58 feeIds: [],
42 - remark: '',  
43 - communityId: '' 59 + remark: ''
44 } 60 }
45 } 61 }
46 }, 62 },
  63 + created() {
  64 + this._initEvent()
  65 + },
47 methods: { 66 methods: {
48 - open(data) {  
49 - this.form = {  
50 - roomId: data.roomId,  
51 - roomName: data.roomName,  
52 - fees: [],  
53 - feeIds: [],  
54 - remark: '',  
55 - communityId: getCommunityId()  
56 - }  
57 - this.loadFees() 67 + _initEvent() {
  68 + this.$on('openWriteOweFeeCallableModal', this.open)
  69 + },
  70 + open(param) {
  71 + Object.assign(this.writeOweFeeCallableInfo, param)
  72 + this._loadWriteOweRoomFees()
58 this.dialogVisible = true 73 this.dialogVisible = true
59 }, 74 },
60 - async loadFees() { 75 + handleClose(done) {
  76 + this.clearWriteOweFeeCallable()
  77 + done()
  78 + },
  79 + async _wirteCallable() {
61 try { 80 try {
62 const params = { 81 const params = {
63 - communityId: this.form.communityId,  
64 - payerObjId: this.form.roomId,  
65 - state: '2008001',  
66 - page: 1,  
67 - row: 100 82 + ...this.writeOweFeeCallableInfo,
  83 + communityId: getCommunityId()
  84 + }
  85 + const res = await writeOweFeeCallable(params)
  86 + if (res.code === 0) {
  87 + this.dialogVisible = false
  88 + this.clearWriteOweFeeCallable()
  89 + this.$emit('listOweFeeCallable', {})
  90 + this.$emit('listOwnerData', {})
  91 + this.$message.success(this.$t('writeOweFeeCallable.success'))
  92 + } else {
  93 + this.$message.error(res.msg)
68 } 94 }
69 - const response = await listFee(params)  
70 - this.form.fees = response.data.fees || []  
71 } catch (error) { 95 } catch (error) {
72 - console.error('加载费用数据失败:', error) 96 + console.error('Request failed:', error)
  97 + this.$message.error(error.message)
  98 + }
  99 + },
  100 + clearWriteOweFeeCallable() {
  101 + this.writeOweFeeCallableInfo = {
  102 + roomId: '',
  103 + roomName: '',
  104 + fees: [],
  105 + feeIds: [],
  106 + remark: ''
73 } 107 }
74 }, 108 },
75 - async handleSubmit() { 109 + async _loadWriteOweRoomFees() {
76 try { 110 try {
77 - await writeOweFeeCallable(this.form)  
78 - this.$message.success(this.$t('oweFeeCallable.write.success'))  
79 - this.dialogVisible = false  
80 - this.$emit('success') 111 + const res = await listFee({
  112 + page: 1,
  113 + row: 100,
  114 + communityId: getCommunityId(),
  115 + payerObjId: this.writeOweFeeCallableInfo.roomId,
  116 + state: '2008001'
  117 + })
  118 + this.writeOweFeeCallableInfo.fees = res.fees
81 } catch (error) { 119 } catch (error) {
82 - console.error('提交失败:', error)  
83 - this.$message.error(error.message || this.$t('oweFeeCallable.write.error')) 120 + console.error('Request failed:', error)
84 } 121 }
85 - },  
86 - handleClose() {  
87 - this.$refs.form.resetFields()  
88 } 122 }
89 } 123 }
90 } 124 }
91 -</script>  
92 -  
93 -<style lang="scss" scoped>  
94 -.el-checkbox {  
95 - margin-right: 15px;  
96 -}  
97 -</style>  
98 \ No newline at end of file 125 \ No newline at end of file
  126 +</script>
99 \ No newline at end of file 127 \ No newline at end of file
src/components/fee/writeOweFeeCallableDemo.vue 0 → 100644
  1 +<template>
  2 + <el-button @click="openModal">{{$t('writeOweFeeCallableDemo.openModal')}}</el-button>
  3 + <write-owe-fee-callable ref="writeOweFeeCallable"></write-owe-fee-callable>
  4 +</template>
  5 +
  6 +<script>
  7 +import WriteOweFeeCallable from './writeOweFeeCallable'
  8 +
  9 +export default {
  10 + name: 'WriteOweFeeCallableDemo',
  11 + components: {
  12 + WriteOweFeeCallable
  13 + },
  14 + methods: {
  15 + openModal() {
  16 + this.$refs.writeOweFeeCallable.open({
  17 + roomId: '123',
  18 + roomName: 'Test Room'
  19 + })
  20 + }
  21 + }
  22 +}
  23 +</script>
0 \ No newline at end of file 24 \ No newline at end of file
src/components/owner/ownerDetailAccount.vue
@@ -109,10 +109,6 @@ export default { @@ -109,10 +109,6 @@ export default {
109 }, 109 },
110 }, 110 },
111 created() { 111 created() {
112 - this.$on('switch', (data) => {  
113 - this.ownerDetailAccountInfo.ownerId = data.ownerId  
114 - this._loadOwnerDetailAccountData(1, this.pagination.pageSize)  
115 - })  
116 } 112 }
117 } 113 }
118 </script> 114 </script>