Commit 9b01bbd3b49b65c684120ac159c6f3b1381fd66b
1 parent
20e526fa
开发完成发票相关功能
Showing
25 changed files
with
2925 additions
and
2 deletions
src/api/fee/addOwnerInvoiceApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | + | |
| 3 | +// 保存业主发票信息 | |
| 4 | +export function saveOwnerInvoice(data) { | |
| 5 | + return new Promise((resolve, reject) => { | |
| 6 | + request({ | |
| 7 | + url: '/invoice.saveOwnerInvoice', | |
| 8 | + method: 'post', | |
| 9 | + data | |
| 10 | + }).then(response => { | |
| 11 | + const res = response.data | |
| 12 | + if (res.code === 0) { | |
| 13 | + resolve(res) | |
| 14 | + } else { | |
| 15 | + reject(new Error(res.msg || '保存发票信息失败')) | |
| 16 | + } | |
| 17 | + }).catch(error => { | |
| 18 | + reject(error) | |
| 19 | + }) | |
| 20 | + }) | |
| 21 | +} | |
| 22 | + | |
| 23 | +// 查询业主列表 | |
| 24 | +export function queryOwners(params) { | |
| 25 | + return new Promise((resolve, reject) => { | |
| 26 | + request({ | |
| 27 | + url: '/owner.queryOwners', | |
| 28 | + method: 'get', | |
| 29 | + params | |
| 30 | + }).then(response => { | |
| 31 | + const res = response.data | |
| 32 | + if (res.code === 0) { | |
| 33 | + resolve({ | |
| 34 | + data: res.data, | |
| 35 | + total: res.records | |
| 36 | + }) | |
| 37 | + } else { | |
| 38 | + reject(new Error(res.msg || '查询业主失败')) | |
| 39 | + } | |
| 40 | + }).catch(error => { | |
| 41 | + reject(error) | |
| 42 | + }) | |
| 43 | + }) | |
| 44 | +} | |
| 0 | 45 | \ No newline at end of file | ... | ... |
src/api/fee/invoiceApplyApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 获取发票申请列表 | |
| 5 | +export function listInvoiceApply(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + const communityId = getCommunityId() | |
| 8 | + request({ | |
| 9 | + url: '/invoice.listInvoiceApply', | |
| 10 | + method: 'get', | |
| 11 | + params: { | |
| 12 | + ...params, | |
| 13 | + communityId | |
| 14 | + } | |
| 15 | + }).then(response => { | |
| 16 | + const res = response.data | |
| 17 | + if (res.code === 0) { | |
| 18 | + resolve(res) | |
| 19 | + } else { | |
| 20 | + reject(new Error(res.msg || '获取发票申请列表失败')) | |
| 21 | + } | |
| 22 | + }).catch(error => { | |
| 23 | + reject(error) | |
| 24 | + }) | |
| 25 | + }) | |
| 26 | +} | |
| 27 | + | |
| 28 | +// 审核发票申请 | |
| 29 | +export function auditInvoiceApply(data) { | |
| 30 | + return new Promise((resolve, reject) => { | |
| 31 | + const communityId = getCommunityId() | |
| 32 | + request({ | |
| 33 | + url: '/invoice.auditInvoiceApply', | |
| 34 | + method: 'post', | |
| 35 | + data: { | |
| 36 | + ...data, | |
| 37 | + communityId | |
| 38 | + } | |
| 39 | + }).then(response => { | |
| 40 | + const res = response.data | |
| 41 | + if (res.code === 0) { | |
| 42 | + resolve(res) | |
| 43 | + } else { | |
| 44 | + reject(new Error(res.msg || '审核发票申请失败')) | |
| 45 | + } | |
| 46 | + }).catch(error => { | |
| 47 | + reject(error) | |
| 48 | + }) | |
| 49 | + }) | |
| 50 | +} | |
| 51 | + | |
| 52 | +// 删除发票申请 | |
| 53 | +export function deleteInvoiceApply(data) { | |
| 54 | + return new Promise((resolve, reject) => { | |
| 55 | + const communityId = getCommunityId() | |
| 56 | + request({ | |
| 57 | + url: '/invoice.deleteInvoiceApply', | |
| 58 | + method: 'post', | |
| 59 | + data: { | |
| 60 | + ...data, | |
| 61 | + communityId | |
| 62 | + } | |
| 63 | + }).then(response => { | |
| 64 | + const res = response.data | |
| 65 | + if (res.code === 0) { | |
| 66 | + resolve(res) | |
| 67 | + } else { | |
| 68 | + reject(new Error(res.msg || '删除发票申请失败')) | |
| 69 | + } | |
| 70 | + }).catch(error => { | |
| 71 | + reject(error) | |
| 72 | + }) | |
| 73 | + }) | |
| 74 | +} | |
| 75 | + | |
| 76 | +// 上传发票照片 | |
| 77 | +export function uploadInvoicePhoto(data) { | |
| 78 | + return new Promise((resolve, reject) => { | |
| 79 | + const communityId = getCommunityId() | |
| 80 | + request({ | |
| 81 | + url: '/invoice.uploadInvoicePhoto', | |
| 82 | + method: 'post', | |
| 83 | + data: { | |
| 84 | + ...data, | |
| 85 | + communityId | |
| 86 | + } | |
| 87 | + }).then(response => { | |
| 88 | + const res = response.data | |
| 89 | + if (res.code === 0) { | |
| 90 | + resolve(res) | |
| 91 | + } else { | |
| 92 | + reject(new Error(res.msg || '上传发票照片失败')) | |
| 93 | + } | |
| 94 | + }).catch(error => { | |
| 95 | + reject(error) | |
| 96 | + }) | |
| 97 | + }) | |
| 98 | +} | |
| 99 | + | |
| 100 | +// 写入发票事件 | |
| 101 | +export function writeInvoiceEvent(data) { | |
| 102 | + return new Promise((resolve, reject) => { | |
| 103 | + const communityId = getCommunityId() | |
| 104 | + request({ | |
| 105 | + url: '/invoice.writeInvoiceApply', | |
| 106 | + method: 'post', | |
| 107 | + data: { | |
| 108 | + ...data, | |
| 109 | + communityId | |
| 110 | + } | |
| 111 | + }).then(response => { | |
| 112 | + const res = response.data | |
| 113 | + if (res.code === 0) { | |
| 114 | + resolve(res) | |
| 115 | + } else { | |
| 116 | + reject(new Error(res.msg || '写入发票事件失败')) | |
| 117 | + } | |
| 118 | + }).catch(error => { | |
| 119 | + reject(error) | |
| 120 | + }) | |
| 121 | + }) | |
| 122 | +} | |
| 123 | + | |
| 124 | +// 上传图片 | |
| 125 | +export function uploadImage(formData) { | |
| 126 | + return new Promise((resolve, reject) => { | |
| 127 | + const communityId = getCommunityId() | |
| 128 | + formData.append('communityId', communityId) | |
| 129 | + | |
| 130 | + request({ | |
| 131 | + url: 'uploadFile/uploadImage', | |
| 132 | + method: 'post', | |
| 133 | + data: formData, | |
| 134 | + headers: { | |
| 135 | + 'Content-Type': 'multipart/form-data' | |
| 136 | + } | |
| 137 | + }).then(response => { | |
| 138 | + const res = response.data | |
| 139 | + if (res.code === 0) { | |
| 140 | + resolve(res.data) | |
| 141 | + } else { | |
| 142 | + reject(new Error(res.msg || '上传图片失败')) | |
| 143 | + } | |
| 144 | + }).catch(error => { | |
| 145 | + reject(error) | |
| 146 | + }) | |
| 147 | + }) | |
| 148 | +} | |
| 0 | 149 | \ No newline at end of file | ... | ... |
src/api/fee/invoiceApplyDetailApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * 获取发票申请详情 | |
| 6 | + * @param {Object} params | |
| 7 | + * @returns | |
| 8 | + */ | |
| 9 | +export function getInvoiceApplyDetail(params) { | |
| 10 | + return new Promise((resolve, reject) => { | |
| 11 | + params.communityId = getCommunityId() | |
| 12 | + request({ | |
| 13 | + url: '/invoice.listInvoiceApply', | |
| 14 | + method: 'get', | |
| 15 | + params | |
| 16 | + }).then(response => { | |
| 17 | + const res = response.data | |
| 18 | + if (res.code === 0) { | |
| 19 | + resolve(res) | |
| 20 | + } else { | |
| 21 | + reject(new Error(res.msg || '获取发票申请详情失败')) | |
| 22 | + } | |
| 23 | + }).catch(error => { | |
| 24 | + reject(error) | |
| 25 | + }) | |
| 26 | + }) | |
| 27 | +} | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * 获取发票申请费用明细 | |
| 31 | + * @param {Object} params | |
| 32 | + * @returns | |
| 33 | + */ | |
| 34 | +export function getInvoiceApplyItemList(params) { | |
| 35 | + return new Promise((resolve, reject) => { | |
| 36 | + params.communityId = getCommunityId() | |
| 37 | + request({ | |
| 38 | + url: '/invoice.listInvoiceApplyItem', | |
| 39 | + method: 'get', | |
| 40 | + params | |
| 41 | + }).then(response => { | |
| 42 | + const res = response.data | |
| 43 | + if (res.code === 0) { | |
| 44 | + resolve(res) | |
| 45 | + } else { | |
| 46 | + reject(new Error(res.msg || '获取发票申请费用明细失败')) | |
| 47 | + } | |
| 48 | + }).catch(error => { | |
| 49 | + reject(error) | |
| 50 | + }) | |
| 51 | + }) | |
| 52 | +} | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * 获取发票申请审核记录 | |
| 56 | + * @param {Object} params | |
| 57 | + * @returns | |
| 58 | + */ | |
| 59 | +export function getInvoiceEventList(params) { | |
| 60 | + return new Promise((resolve, reject) => { | |
| 61 | + params.communityId = getCommunityId() | |
| 62 | + request({ | |
| 63 | + url: '/invoice.listInvoiceEvent', | |
| 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 || '获取发票申请审核记录失败')) | |
| 72 | + } | |
| 73 | + }).catch(error => { | |
| 74 | + reject(error) | |
| 75 | + }) | |
| 76 | + }) | |
| 77 | +} | |
| 0 | 78 | \ No newline at end of file | ... | ... |
src/api/fee/ownerApplyInvoiceApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 获取业主发票信息列表 | |
| 5 | +export function listOwnerInvoice(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + const communityId = getCommunityId() | |
| 8 | + request({ | |
| 9 | + url: '/invoice.listOwnerInvoice', | |
| 10 | + method: 'get', | |
| 11 | + params: { | |
| 12 | + ...params, | |
| 13 | + communityId | |
| 14 | + } | |
| 15 | + }).then(response => { | |
| 16 | + const res = response.data | |
| 17 | + | |
| 18 | + resolve(res) | |
| 19 | + }).catch(error => { | |
| 20 | + reject(error) | |
| 21 | + }) | |
| 22 | + }) | |
| 23 | +} | |
| 24 | + | |
| 25 | +// 查询费用明细 | |
| 26 | +export function queryFeeDetail(params) { | |
| 27 | + return new Promise((resolve, reject) => { | |
| 28 | + const communityId = getCommunityId() | |
| 29 | + request({ | |
| 30 | + url: '/fee.queryFeeDetail', | |
| 31 | + method: 'get', | |
| 32 | + params: { | |
| 33 | + ...params, | |
| 34 | + communityId | |
| 35 | + } | |
| 36 | + }).then(response => { | |
| 37 | + const res = response.data | |
| 38 | + | |
| 39 | + resolve(res) | |
| 40 | + }).catch(error => { | |
| 41 | + reject(error) | |
| 42 | + }) | |
| 43 | + }) | |
| 44 | +} | |
| 45 | + | |
| 46 | +// 查询账户预存明细 | |
| 47 | +export function listAccountReceipt(params) { | |
| 48 | + return new Promise((resolve, reject) => { | |
| 49 | + const communityId = getCommunityId() | |
| 50 | + request({ | |
| 51 | + url: '/receipt.listAccountReceipt', | |
| 52 | + method: 'get', | |
| 53 | + params: { | |
| 54 | + ...params, | |
| 55 | + communityId | |
| 56 | + } | |
| 57 | + }).then(response => { | |
| 58 | + const res = response.data | |
| 59 | + | |
| 60 | + resolve(res) | |
| 61 | + }).catch(error => { | |
| 62 | + reject(error) | |
| 63 | + }) | |
| 64 | + }) | |
| 65 | +} | |
| 66 | + | |
| 67 | +// 保存发票申请 | |
| 68 | +export function saveInvoiceApply(data) { | |
| 69 | + return new Promise((resolve, reject) => { | |
| 70 | + const communityId = getCommunityId() | |
| 71 | + request({ | |
| 72 | + url: '/invoice.saveInvoiceApply', | |
| 73 | + method: 'post', | |
| 74 | + data: { | |
| 75 | + ...data, | |
| 76 | + communityId | |
| 77 | + } | |
| 78 | + }).then(response => { | |
| 79 | + const res = response.data | |
| 80 | + if (res.code === 0) { | |
| 81 | + resolve(res) | |
| 82 | + } else { | |
| 83 | + reject(new Error(res.msg || '保存发票申请失败')) | |
| 84 | + } | |
| 85 | + }).catch(error => { | |
| 86 | + reject(error) | |
| 87 | + }) | |
| 88 | + }) | |
| 89 | +} | |
| 0 | 90 | \ No newline at end of file | ... | ... |
src/api/fee/ownerInvoiceApi.js
0 → 100644
| 1 | +import request from '@/utils/request' | |
| 2 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 3 | + | |
| 4 | +// 查询业主发票列表 | |
| 5 | +export function listOwnerInvoice(params) { | |
| 6 | + return new Promise((resolve, reject) => { | |
| 7 | + params.communityId = getCommunityId() | |
| 8 | + request({ | |
| 9 | + url: '/invoice.listOwnerInvoice', | |
| 10 | + method: 'get', | |
| 11 | + params | |
| 12 | + }).then(response => { | |
| 13 | + const res = response.data | |
| 14 | + if (res.code === 0) { | |
| 15 | + resolve(res) | |
| 16 | + } else { | |
| 17 | + reject(new Error(res.msg || '获取发票列表失败')) | |
| 18 | + } | |
| 19 | + }).catch(error => { | |
| 20 | + reject(error) | |
| 21 | + }) | |
| 22 | + }) | |
| 23 | +} | |
| 24 | + | |
| 25 | +// 更新业主发票 | |
| 26 | +export function updateOwnerInvoice(data) { | |
| 27 | + return new Promise((resolve, reject) => { | |
| 28 | + data.communityId = getCommunityId() | |
| 29 | + request({ | |
| 30 | + url: '/invoice.updateOwnerInvoice', | |
| 31 | + method: 'post', | |
| 32 | + data | |
| 33 | + }).then(response => { | |
| 34 | + const res = response.data | |
| 35 | + if (res.code === 0) { | |
| 36 | + resolve(res) | |
| 37 | + } else { | |
| 38 | + reject(new Error(res.msg || '更新发票失败')) | |
| 39 | + } | |
| 40 | + }).catch(error => { | |
| 41 | + reject(error) | |
| 42 | + }) | |
| 43 | + }) | |
| 44 | +} | |
| 45 | + | |
| 46 | +// 删除业主发票 | |
| 47 | +export function deleteOwnerInvoice(data) { | |
| 48 | + return new Promise((resolve, reject) => { | |
| 49 | + data.communityId = getCommunityId() | |
| 50 | + request({ | |
| 51 | + url: '/invoice.deleteOwnerInvoice', | |
| 52 | + method: 'post', | |
| 53 | + data | |
| 54 | + }).then(response => { | |
| 55 | + const res = response.data | |
| 56 | + if (res.code === 0) { | |
| 57 | + resolve(res) | |
| 58 | + } else { | |
| 59 | + reject(new Error(res.msg || '删除发票失败')) | |
| 60 | + } | |
| 61 | + }).catch(error => { | |
| 62 | + reject(error) | |
| 63 | + }) | |
| 64 | + }) | |
| 65 | +} | |
| 0 | 66 | \ No newline at end of file | ... | ... |
src/components/fee/audit.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('audit.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="closeDialog" | |
| 7 | + > | |
| 8 | + <el-form label-width="120px"> | |
| 9 | + <el-form-item :label="$t('audit.status')"> | |
| 10 | + <el-select | |
| 11 | + v-model="form.state" | |
| 12 | + :placeholder="$t('audit.statusRequired')" | |
| 13 | + style="width: 100%" | |
| 14 | + > | |
| 15 | + <el-option | |
| 16 | + :label="$t('audit.approve')" | |
| 17 | + value="1100" | |
| 18 | + /> | |
| 19 | + <el-option | |
| 20 | + :label="$t('audit.reject')" | |
| 21 | + value="1200" | |
| 22 | + /> | |
| 23 | + </el-select> | |
| 24 | + </el-form-item> | |
| 25 | + <el-form-item :label="$t('audit.reason')"> | |
| 26 | + <el-input | |
| 27 | + v-model="form.remark" | |
| 28 | + type="textarea" | |
| 29 | + :rows="3" | |
| 30 | + :placeholder="$t('audit.reasonRequired')" | |
| 31 | + /> | |
| 32 | + </el-form-item> | |
| 33 | + </el-form> | |
| 34 | + <div slot="footer"> | |
| 35 | + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button> | |
| 36 | + <el-button | |
| 37 | + type="primary" | |
| 38 | + @click="submitAudit" | |
| 39 | + >{{ $t('common.submit') }}</el-button> | |
| 40 | + </div> | |
| 41 | + </el-dialog> | |
| 42 | +</template> | |
| 43 | + | |
| 44 | +<script> | |
| 45 | +export default { | |
| 46 | + name: 'AuditDialog', | |
| 47 | + data() { | |
| 48 | + return { | |
| 49 | + visible: false, | |
| 50 | + form: { | |
| 51 | + state: '', | |
| 52 | + remark: '' | |
| 53 | + } | |
| 54 | + } | |
| 55 | + }, | |
| 56 | + watch: { | |
| 57 | + 'form.state'(val) { | |
| 58 | + if (val === '1100') { | |
| 59 | + this.form.remark = this.$t('audit.approve') | |
| 60 | + } else if (val === '1200') { | |
| 61 | + this.form.remark = this.$t('audit.reject') + ': ' | |
| 62 | + } | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + methods: { | |
| 66 | + open() { | |
| 67 | + this.form = { | |
| 68 | + state: '', | |
| 69 | + remark: '' | |
| 70 | + } | |
| 71 | + this.visible = true | |
| 72 | + }, | |
| 73 | + closeDialog() { | |
| 74 | + this.visible = false | |
| 75 | + }, | |
| 76 | + submitAudit() { | |
| 77 | + if (!this.form.state) { | |
| 78 | + this.$message.warning(this.$t('audit.statusRequired')) | |
| 79 | + return | |
| 80 | + } | |
| 81 | + if (!this.form.remark) { | |
| 82 | + this.$message.warning(this.$t('audit.reasonRequired')) | |
| 83 | + return | |
| 84 | + } | |
| 85 | + this.$emit('success', this.form) | |
| 86 | + this.closeDialog() | |
| 87 | + } | |
| 88 | + } | |
| 89 | +} | |
| 90 | +</script> | |
| 0 | 91 | \ No newline at end of file | ... | ... |
src/components/fee/deleteInvoiceApply.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('deleteInvoiceApply.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="30%" | |
| 6 | + @close="closeDialog" | |
| 7 | + > | |
| 8 | + <div align="center"> | |
| 9 | + <p>{{ $t('deleteInvoiceApply.confirmMessage') }}</p> | |
| 10 | + </div> | |
| 11 | + <div slot="footer"> | |
| 12 | + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button> | |
| 13 | + <el-button | |
| 14 | + type="primary" | |
| 15 | + @click="deleteInvoiceApply" | |
| 16 | + >{{ $t('common.confirmDelete') }}</el-button> | |
| 17 | + </div> | |
| 18 | + </el-dialog> | |
| 19 | +</template> | |
| 20 | + | |
| 21 | +<script> | |
| 22 | +import { deleteInvoiceApply as deleteApi } from '@/api/fee/invoiceApplyApi' | |
| 23 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 24 | + | |
| 25 | +export default { | |
| 26 | + name: 'DeleteInvoiceApply', | |
| 27 | + data() { | |
| 28 | + return { | |
| 29 | + visible: false, | |
| 30 | + applyData: {} | |
| 31 | + } | |
| 32 | + }, | |
| 33 | + methods: { | |
| 34 | + open(row) { | |
| 35 | + this.applyData = { ...row } | |
| 36 | + this.visible = true | |
| 37 | + }, | |
| 38 | + closeDialog() { | |
| 39 | + this.visible = false | |
| 40 | + }, | |
| 41 | + async deleteInvoiceApply() { | |
| 42 | + try { | |
| 43 | + const params = { | |
| 44 | + ...this.applyData, | |
| 45 | + communityId: getCommunityId() | |
| 46 | + } | |
| 47 | + await deleteApi(params) | |
| 48 | + this.$emit('success') | |
| 49 | + this.$message.success(this.$t('common.deleteSuccess')) | |
| 50 | + this.closeDialog() | |
| 51 | + } catch (error) { | |
| 52 | + this.$message.error(error.message) | |
| 53 | + } | |
| 54 | + } | |
| 55 | + } | |
| 56 | +} | |
| 57 | +</script> | |
| 0 | 58 | \ No newline at end of file | ... | ... |
src/components/fee/deleteOwnerInvoice.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('confirmDeleteTitle')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="30%" | |
| 6 | + > | |
| 7 | + <p>{{ $t('confirmDeleteContent') }}</p> | |
| 8 | + <div slot="footer"> | |
| 9 | + <el-button @click="visible = false">{{ $t('cancel') }}</el-button> | |
| 10 | + <el-button type="danger" @click="handleDelete">{{ $t('confirmDelete') }}</el-button> | |
| 11 | + </div> | |
| 12 | + </el-dialog> | |
| 13 | +</template> | |
| 14 | + | |
| 15 | +<script> | |
| 16 | +import { deleteOwnerInvoice } from '@/api/fee/ownerInvoiceApi' | |
| 17 | + | |
| 18 | +export default { | |
| 19 | + name: 'DeleteOwnerInvoice', | |
| 20 | + data() { | |
| 21 | + return { | |
| 22 | + visible: false, | |
| 23 | + currentData: null | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + methods: { | |
| 27 | + open(data) { | |
| 28 | + this.currentData = data | |
| 29 | + this.visible = true | |
| 30 | + }, | |
| 31 | + async handleDelete() { | |
| 32 | + try { | |
| 33 | + await deleteOwnerInvoice({ oiId: this.currentData.oiId }) | |
| 34 | + this.$message.success(this.$t('common.deleteSuccess')) | |
| 35 | + this.visible = false | |
| 36 | + this.$emit('success') | |
| 37 | + } catch (error) { | |
| 38 | + this.$message.error(error.message || this.$t('common.deleteFailed')) | |
| 39 | + } | |
| 40 | + } | |
| 41 | + } | |
| 42 | +} | |
| 43 | +</script> | |
| 0 | 44 | \ No newline at end of file | ... | ... |
src/components/fee/editOwnerInvoice.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('editTitle')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="resetForm" | |
| 7 | + > | |
| 8 | + <el-form ref="form" :model="formData" label-width="150px"> | |
| 9 | + <el-form-item :label="$t('invoiceType')" prop="invoiceType" required> | |
| 10 | + <el-select | |
| 11 | + v-model="formData.invoiceType" | |
| 12 | + :placeholder="$t('requiredInvoiceType')" | |
| 13 | + style="width: 100%" | |
| 14 | + > | |
| 15 | + <el-option value="1001" :label="$t('personal')" /> | |
| 16 | + <el-option value="2002" :label="$t('enterprise')" /> | |
| 17 | + </el-select> | |
| 18 | + </el-form-item> | |
| 19 | + | |
| 20 | + <el-form-item :label="$t('invoiceHeader')" prop="invoiceName" required> | |
| 21 | + <el-input | |
| 22 | + v-model="formData.invoiceName" | |
| 23 | + :placeholder="$t('requiredInvoiceHeader')" | |
| 24 | + /> | |
| 25 | + </el-form-item> | |
| 26 | + | |
| 27 | + <el-form-item :label="$t('taxpayerId')" prop="invoiceNum" required> | |
| 28 | + <el-input | |
| 29 | + v-model="formData.invoiceNum" | |
| 30 | + :placeholder="$t('requiredTaxpayerId')" | |
| 31 | + /> | |
| 32 | + </el-form-item> | |
| 33 | + | |
| 34 | + <el-form-item :label="$t('address')" prop="invoiceAddress" required> | |
| 35 | + <el-input | |
| 36 | + v-model="formData.invoiceAddress" | |
| 37 | + :placeholder="$t('requiredAddress')" | |
| 38 | + /> | |
| 39 | + </el-form-item> | |
| 40 | + | |
| 41 | + <el-form-item :label="$t('phone')" prop="invoiceLink" required> | |
| 42 | + <el-input | |
| 43 | + v-model="formData.invoiceLink" | |
| 44 | + :placeholder="$t('requiredPhone')" | |
| 45 | + /> | |
| 46 | + </el-form-item> | |
| 47 | + | |
| 48 | + <el-form-item :label="$t('bankAccount')" prop="invoiceAccount" required> | |
| 49 | + <el-input | |
| 50 | + v-model="formData.invoiceAccount" | |
| 51 | + :placeholder="$t('requiredBankAccount')" | |
| 52 | + /> | |
| 53 | + </el-form-item> | |
| 54 | + | |
| 55 | + <el-form-item :label="$t('remark')" prop="remark"> | |
| 56 | + <el-input | |
| 57 | + v-model="formData.remark" | |
| 58 | + type="textarea" | |
| 59 | + :placeholder="$t('optionalRemark')" | |
| 60 | + /> | |
| 61 | + </el-form-item> | |
| 62 | + </el-form> | |
| 63 | + | |
| 64 | + <div slot="footer"> | |
| 65 | + <el-button @click="visible = false">{{ $t('cancel') }}</el-button> | |
| 66 | + <el-button type="primary" @click="handleSave">{{ $t('save') }}</el-button> | |
| 67 | + </div> | |
| 68 | + </el-dialog> | |
| 69 | +</template> | |
| 70 | + | |
| 71 | +<script> | |
| 72 | +import { updateOwnerInvoice } from '@/api/fee/ownerInvoiceApi' | |
| 73 | + | |
| 74 | +export default { | |
| 75 | + name: 'EditOwnerInvoice', | |
| 76 | + data() { | |
| 77 | + return { | |
| 78 | + visible: false, | |
| 79 | + formData: { | |
| 80 | + oiId: '', | |
| 81 | + ownerId: '', | |
| 82 | + ownerName: '', | |
| 83 | + invoiceType: '', | |
| 84 | + invoiceName: '', | |
| 85 | + invoiceNum: '', | |
| 86 | + invoiceAddress: '', | |
| 87 | + invoiceLink: '', | |
| 88 | + invoiceAccount: '', | |
| 89 | + remark: '' | |
| 90 | + } | |
| 91 | + } | |
| 92 | + }, | |
| 93 | + methods: { | |
| 94 | + open(data) { | |
| 95 | + Object.assign(this.formData, data) | |
| 96 | + this.visible = true | |
| 97 | + }, | |
| 98 | + resetForm() { | |
| 99 | + this.$refs.form.resetFields() | |
| 100 | + Object.keys(this.formData).forEach(key => { | |
| 101 | + this.formData[key] = '' | |
| 102 | + }) | |
| 103 | + }, | |
| 104 | + async handleSave() { | |
| 105 | + try { | |
| 106 | + await updateOwnerInvoice(this.formData) | |
| 107 | + this.$message.success(this.$t('common.saveSuccess')) | |
| 108 | + this.visible = false | |
| 109 | + this.$emit('success') | |
| 110 | + } catch (error) { | |
| 111 | + this.$message.error(error.message || this.$t('common.saveFailed')) | |
| 112 | + } | |
| 113 | + } | |
| 114 | + } | |
| 115 | +} | |
| 116 | +</script> | |
| 0 | 117 | \ No newline at end of file | ... | ... |
src/components/fee/invoiceApplyDetailEvent.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="invoice-apply-detail-event"> | |
| 3 | + <el-table :data="events" border style="width: 100%"> | |
| 4 | + <el-table-column prop="eventTypeName" :label="$t('invoiceApplyDetailEvent.type')" align="center"></el-table-column> | |
| 5 | + <el-table-column prop="createUserName" :label="$t('invoiceApplyDetailEvent.operator')" align="center"></el-table-column> | |
| 6 | + <el-table-column prop="remark" :label="$t('invoiceApplyDetailEvent.remark')" align="center"></el-table-column> | |
| 7 | + <el-table-column prop="createTime" :label="$t('invoiceApplyDetailEvent.time')" align="center"></el-table-column> | |
| 8 | + </el-table> | |
| 9 | + | |
| 10 | + <el-pagination | |
| 11 | + @size-change="handleSizeChange" | |
| 12 | + @current-change="handleCurrentChange" | |
| 13 | + :current-page="page.current" | |
| 14 | + :page-sizes="[10, 20, 30, 50]" | |
| 15 | + :page-size="page.size" | |
| 16 | + layout="total, sizes, prev, pager, next, jumper" | |
| 17 | + :total="page.total"> | |
| 18 | + </el-pagination> | |
| 19 | + </div> | |
| 20 | +</template> | |
| 21 | + | |
| 22 | +<script> | |
| 23 | +import { getInvoiceEventList } from '@/api/fee/invoiceApplyDetailApi' | |
| 24 | + | |
| 25 | +export default { | |
| 26 | + name: 'InvoiceApplyDetailEvent', | |
| 27 | + props: { | |
| 28 | + applyId: { | |
| 29 | + type: String, | |
| 30 | + required: true | |
| 31 | + } | |
| 32 | + }, | |
| 33 | + data() { | |
| 34 | + return { | |
| 35 | + events: [], | |
| 36 | + page: { | |
| 37 | + current: 1, | |
| 38 | + size: 10, | |
| 39 | + total: 0 | |
| 40 | + } | |
| 41 | + } | |
| 42 | + }, | |
| 43 | + watch: { | |
| 44 | + applyId: { | |
| 45 | + immediate: true, | |
| 46 | + handler() { | |
| 47 | + if (this.applyId) { | |
| 48 | + this.loadData() | |
| 49 | + } | |
| 50 | + } | |
| 51 | + } | |
| 52 | + }, | |
| 53 | + methods: { | |
| 54 | + async loadData() { | |
| 55 | + try { | |
| 56 | + const params = { | |
| 57 | + page: this.page.current, | |
| 58 | + row: this.page.size, | |
| 59 | + applyId: this.applyId | |
| 60 | + } | |
| 61 | + const res = await getInvoiceEventList(params) | |
| 62 | + if (res.code === 0) { | |
| 63 | + this.events = res.data | |
| 64 | + this.page.total = res.total | |
| 65 | + } | |
| 66 | + } catch (error) { | |
| 67 | + this.$message.error(this.$t('invoiceApplyDetailEvent.fetchError')) | |
| 68 | + } | |
| 69 | + }, | |
| 70 | + handleSizeChange(val) { | |
| 71 | + this.page.size = val | |
| 72 | + this.loadData() | |
| 73 | + }, | |
| 74 | + handleCurrentChange(val) { | |
| 75 | + this.page.current = val | |
| 76 | + this.loadData() | |
| 77 | + } | |
| 78 | + } | |
| 79 | +} | |
| 80 | +</script> | |
| 81 | + | |
| 82 | +<style scoped> | |
| 83 | +.invoice-apply-detail-event { | |
| 84 | + margin-top: 20px; | |
| 85 | +} | |
| 86 | +</style> | |
| 0 | 87 | \ No newline at end of file | ... | ... |
src/components/fee/invoiceApplyDetailFee.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="invoice-apply-detail-fee"> | |
| 3 | + <el-table :data="fees" border style="width: 100%"> | |
| 4 | + <el-table-column prop="itemTypeName" :label="$t('invoiceApplyDetailFee.type')" align="center"></el-table-column> | |
| 5 | + <el-table-column prop="itemName" :label="$t('invoiceApplyDetailFee.name')" align="center"></el-table-column> | |
| 6 | + <el-table-column prop="itemAmount" :label="$t('invoiceApplyDetailFee.amount')" align="center"></el-table-column> | |
| 7 | + <el-table-column prop="payTime" :label="$t('invoiceApplyDetailFee.payTime')" align="center"></el-table-column> | |
| 8 | + <el-table-column prop="remark" :label="$t('invoiceApplyDetailFee.remark')" align="center"></el-table-column> | |
| 9 | + <el-table-column :label="$t('invoiceApplyDetailFee.paymentId')" align="center"> | |
| 10 | + <template slot-scope="scope"> | |
| 11 | + {{ scope.row.itemObjId }} | |
| 12 | + (<a href="javascript:void(0)" v-if="scope.row.itemType === '2002'" @click="viewFeeDetail(scope.row)">{{ $t('common.view') }}</a> | |
| 13 | + <a href="javascript:void(0)" v-else @click="viewAcctDetail(scope.row)">{{ $t('common.view') }}</a>) | |
| 14 | + </template> | |
| 15 | + </el-table-column> | |
| 16 | + </el-table> | |
| 17 | + | |
| 18 | + <el-pagination | |
| 19 | + @size-change="handleSizeChange" | |
| 20 | + @current-change="handleCurrentChange" | |
| 21 | + :current-page="page.current" | |
| 22 | + :page-sizes="[10, 20, 30, 50]" | |
| 23 | + :page-size="page.size" | |
| 24 | + layout="total, sizes, prev, pager, next, jumper" | |
| 25 | + :total="page.total"> | |
| 26 | + </el-pagination> | |
| 27 | + </div> | |
| 28 | +</template> | |
| 29 | + | |
| 30 | +<script> | |
| 31 | +import { getInvoiceApplyItemList } from '@/api/fee/invoiceApplyDetailApi' | |
| 32 | + | |
| 33 | +export default { | |
| 34 | + name: 'InvoiceApplyDetailFee', | |
| 35 | + props: { | |
| 36 | + applyId: { | |
| 37 | + type: String, | |
| 38 | + required: true | |
| 39 | + }, | |
| 40 | + ownerId: { | |
| 41 | + type: String, | |
| 42 | + default: '' | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + data() { | |
| 46 | + return { | |
| 47 | + fees: [], | |
| 48 | + page: { | |
| 49 | + current: 1, | |
| 50 | + size: 10, | |
| 51 | + total: 0 | |
| 52 | + } | |
| 53 | + } | |
| 54 | + }, | |
| 55 | + watch: { | |
| 56 | + applyId: { | |
| 57 | + immediate: true, | |
| 58 | + handler() { | |
| 59 | + if (this.applyId) { | |
| 60 | + this.loadData() | |
| 61 | + } | |
| 62 | + } | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + methods: { | |
| 66 | + async loadData() { | |
| 67 | + try { | |
| 68 | + const params = { | |
| 69 | + page: this.page.current, | |
| 70 | + row: this.page.size, | |
| 71 | + applyId: this.applyId | |
| 72 | + } | |
| 73 | + const res = await getInvoiceApplyItemList(params) | |
| 74 | + if (res.code === 0) { | |
| 75 | + this.fees = res.data.map(item => ({ | |
| 76 | + ...item, | |
| 77 | + itemTypeName: item.itemType === '2002' ? this.$t('invoiceApplyDetailFee.feeType') : this.$t('invoiceApplyDetailFee.accountType') | |
| 78 | + })) | |
| 79 | + this.page.total = res.total | |
| 80 | + } | |
| 81 | + } catch (error) { | |
| 82 | + this.$message.error(this.$t('invoiceApplyDetailFee.fetchError')) | |
| 83 | + } | |
| 84 | + }, | |
| 85 | + handleSizeChange(val) { | |
| 86 | + this.page.size = val | |
| 87 | + this.loadData() | |
| 88 | + }, | |
| 89 | + handleCurrentChange(val) { | |
| 90 | + this.page.current = val | |
| 91 | + this.loadData() | |
| 92 | + }, | |
| 93 | + viewFeeDetail(fee) { | |
| 94 | + this.$router.push({ path: '/fee/feeDetail', query: { detailId: fee.itemObjId }}) | |
| 95 | + }, | |
| 96 | + viewAcctDetail(fee) { | |
| 97 | + this.$router.push({ path: '/owner/ownerDetail', query: { ownerId: fee.ownerId, currentTab: 'ownerDetailAccountReceipt' }}) | |
| 98 | + } | |
| 99 | + } | |
| 100 | +} | |
| 101 | +</script> | |
| 102 | + | |
| 103 | +<style scoped> | |
| 104 | +.invoice-apply-detail-fee { | |
| 105 | + margin-top: 20px; | |
| 106 | +} | |
| 107 | +</style> | |
| 0 | 108 | \ No newline at end of file | ... | ... |
src/components/fee/searchOwnerInvoice.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog :title="$t('searchOwnerInvoice.title')" :visible.sync="visible" width="80%" @close="handleClose"> | |
| 3 | + <div> | |
| 4 | + <el-row :gutter="20"> | |
| 5 | + <el-col :span="9"> | |
| 6 | + <el-input v-model="searchForm.roomName" :placeholder="$t('searchOwnerInvoice.placeholderRoom')" clearable | |
| 7 | + @keyup.enter.native="handleSearch" /> | |
| 8 | + </el-col> | |
| 9 | + <el-col :span="9"> | |
| 10 | + <el-input v-model="searchForm.ownerNameLike" :placeholder="$t('searchOwnerInvoice.placeholderOwner')" clearable | |
| 11 | + @keyup.enter.native="handleSearch" /> | |
| 12 | + </el-col> | |
| 13 | + <el-col :span="6"> | |
| 14 | + <el-button type="primary" @click="handleSearch"> | |
| 15 | + {{ $t('searchOwnerInvoice.search') }} | |
| 16 | + </el-button> | |
| 17 | + </el-col> | |
| 18 | + </el-row> | |
| 19 | + | |
| 20 | + <el-table v-loading="loading" :data="ownerInvoices" border style="width: 100%; margin-top: 20px"> | |
| 21 | + <el-table-column prop="ownerName" :label="$t('searchOwnerInvoice.ownerName')" align="center" /> | |
| 22 | + <el-table-column prop="invoiceType" :label="$t('searchOwnerInvoice.invoiceType')" align="center"> | |
| 23 | + <template slot-scope="scope"> | |
| 24 | + {{ scope.row.invoiceType === '1001' ? $t('searchOwnerInvoice.personal') : $t('searchOwnerInvoice.company') }} | |
| 25 | + </template> | |
| 26 | + </el-table-column> | |
| 27 | + <el-table-column prop="invoiceName" :label="$t('searchOwnerInvoice.invoiceTitle')" align="center" /> | |
| 28 | + <el-table-column prop="invoiceNum" :label="$t('searchOwnerInvoice.taxpayerId')" align="center" /> | |
| 29 | + <el-table-column prop="invoiceAddress" :label="$t('searchOwnerInvoice.addressPhone')" align="center" /> | |
| 30 | + <el-table-column :label="$t('searchOwnerInvoice.operation')" align="center"> | |
| 31 | + <template slot-scope="scope"> | |
| 32 | + <el-button type="primary" size="small" @click="handleSelect(scope.row)"> | |
| 33 | + {{ $t('searchOwnerInvoice.select') }} | |
| 34 | + </el-button> | |
| 35 | + </template> | |
| 36 | + </el-table-column> | |
| 37 | + </el-table> | |
| 38 | + | |
| 39 | + <el-pagination :current-page="pagination.current" :page-sizes="[10, 20, 30, 50]" :page-size="pagination.size" | |
| 40 | + layout="total, sizes, prev, pager, next" :total="pagination.total" @size-change="handleSizeChange" | |
| 41 | + @current-change="handlePageChange" /> | |
| 42 | + </div> | |
| 43 | + </el-dialog> | |
| 44 | +</template> | |
| 45 | + | |
| 46 | +<script> | |
| 47 | +import { listOwnerInvoice } from '@/api/fee/ownerApplyInvoiceApi' | |
| 48 | + | |
| 49 | +export default { | |
| 50 | + name: 'SearchOwnerInvoice', | |
| 51 | + props: { | |
| 52 | + visible: { | |
| 53 | + type: Boolean, | |
| 54 | + default: false | |
| 55 | + } | |
| 56 | + }, | |
| 57 | + data() { | |
| 58 | + return { | |
| 59 | + loading: false, | |
| 60 | + searchForm: { | |
| 61 | + roomName: '', | |
| 62 | + ownerNameLike: '' | |
| 63 | + }, | |
| 64 | + ownerInvoices: [], | |
| 65 | + pagination: { | |
| 66 | + current: 1, | |
| 67 | + size: 10, | |
| 68 | + total: 0 | |
| 69 | + } | |
| 70 | + } | |
| 71 | + }, | |
| 72 | + methods: { | |
| 73 | + open() { | |
| 74 | + this.visible = true | |
| 75 | + this.loadData() | |
| 76 | + }, | |
| 77 | + handleClose() { | |
| 78 | + this.$emit('update:visible', false) | |
| 79 | + }, | |
| 80 | + async loadData() { | |
| 81 | + this.loading = true | |
| 82 | + try { | |
| 83 | + const params = { | |
| 84 | + page: this.pagination.current, | |
| 85 | + row: this.pagination.size, | |
| 86 | + ownerNameLike: this.searchForm.ownerNameLike, | |
| 87 | + roomName: this.searchForm.roomName | |
| 88 | + } | |
| 89 | + | |
| 90 | + const res = await listOwnerInvoice(params) | |
| 91 | + this.ownerInvoices = res.data | |
| 92 | + this.pagination.total = res.records | |
| 93 | + } catch (error) { | |
| 94 | + console.error('Failed to load owner invoices:', error) | |
| 95 | + this.$message.error(this.$t('common.loadFailed')) | |
| 96 | + } finally { | |
| 97 | + this.loading = false | |
| 98 | + } | |
| 99 | + }, | |
| 100 | + handleSearch() { | |
| 101 | + this.pagination.current = 1 | |
| 102 | + this.loadData() | |
| 103 | + }, | |
| 104 | + handleSizeChange(size) { | |
| 105 | + this.pagination.size = size | |
| 106 | + this.loadData() | |
| 107 | + }, | |
| 108 | + handlePageChange(page) { | |
| 109 | + this.pagination.current = page | |
| 110 | + this.loadData() | |
| 111 | + }, | |
| 112 | + handleSelect(owner) { | |
| 113 | + this.$emit('select', owner) | |
| 114 | + this.handleClose() | |
| 115 | + } | |
| 116 | + } | |
| 117 | +} | |
| 118 | +</script> | |
| 119 | + | |
| 120 | +<style scoped> | |
| 121 | +.el-row { | |
| 122 | + margin-bottom: 20px; | |
| 123 | +} | |
| 124 | +</style> | |
| 0 | 125 | \ No newline at end of file | ... | ... |
src/components/fee/uploadInvoicePhoto.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('uploadInvoicePhoto.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="closeDialog" | |
| 7 | + > | |
| 8 | + <el-form label-width="120px"> | |
| 9 | + <el-form-item :label="$t('uploadInvoicePhoto.invoiceCode')"> | |
| 10 | + <el-input | |
| 11 | + v-model="form.invoiceCode" | |
| 12 | + :placeholder="$t('uploadInvoicePhoto.codeRequired')" | |
| 13 | + /> | |
| 14 | + </el-form-item> | |
| 15 | + <el-form-item :label="$t('uploadInvoicePhoto.invoice')"> | |
| 16 | + <upload-image-url | |
| 17 | + ref="uploadImage" | |
| 18 | + @notifyUploadCoverImage="handleImageUpload" | |
| 19 | + /> | |
| 20 | + </el-form-item> | |
| 21 | + </el-form> | |
| 22 | + <div slot="footer"> | |
| 23 | + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button> | |
| 24 | + <el-button | |
| 25 | + type="primary" | |
| 26 | + @click="saveUploadInvoicePhoto" | |
| 27 | + >{{ $t('common.save') }}</el-button> | |
| 28 | + </div> | |
| 29 | + </el-dialog> | |
| 30 | +</template> | |
| 31 | + | |
| 32 | +<script> | |
| 33 | +import { uploadInvoicePhoto } from '@/api/fee/invoiceApplyApi' | |
| 34 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 35 | +import UploadImageUrl from '@/components/upload/UploadImageUrl' | |
| 36 | + | |
| 37 | +export default { | |
| 38 | + name: 'UploadInvoicePhoto', | |
| 39 | + components: { | |
| 40 | + UploadImageUrl | |
| 41 | + }, | |
| 42 | + data() { | |
| 43 | + return { | |
| 44 | + visible: false, | |
| 45 | + form: { | |
| 46 | + applyId: '', | |
| 47 | + invoiceCode: '', | |
| 48 | + photos: [] | |
| 49 | + } | |
| 50 | + } | |
| 51 | + }, | |
| 52 | + methods: { | |
| 53 | + open(row) { | |
| 54 | + this.form = { | |
| 55 | + applyId: row.applyId, | |
| 56 | + invoiceCode: '', | |
| 57 | + photos: [] | |
| 58 | + } | |
| 59 | + this.$refs.uploadImage.clearImages() | |
| 60 | + this.visible = true | |
| 61 | + }, | |
| 62 | + closeDialog() { | |
| 63 | + this.visible = false | |
| 64 | + }, | |
| 65 | + handleImageUpload(photos) { | |
| 66 | + this.form.photos = photos | |
| 67 | + }, | |
| 68 | + async saveUploadInvoicePhoto() { | |
| 69 | + if (!this.form.invoiceCode) { | |
| 70 | + this.$message.warning(this.$t('uploadInvoicePhoto.codeRequired')) | |
| 71 | + return | |
| 72 | + } | |
| 73 | + if (this.form.photos.length === 0) { | |
| 74 | + this.$message.warning(this.$t('uploadInvoicePhoto.photoRequired')) | |
| 75 | + return | |
| 76 | + } | |
| 77 | + | |
| 78 | + try { | |
| 79 | + const params = { | |
| 80 | + ...this.form, | |
| 81 | + communityId: getCommunityId() | |
| 82 | + } | |
| 83 | + await uploadInvoicePhoto(params) | |
| 84 | + this.$emit('success') | |
| 85 | + this.$message.success(this.$t('common.saveSuccess')) | |
| 86 | + this.closeDialog() | |
| 87 | + } catch (error) { | |
| 88 | + this.$message.error(error.message) | |
| 89 | + } | |
| 90 | + } | |
| 91 | + } | |
| 92 | +} | |
| 93 | +</script> | |
| 0 | 94 | \ No newline at end of file | ... | ... |
src/components/fee/wirteInvoiceEvent.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <el-dialog | |
| 3 | + :title="$t('wirteInvoiceEvent.title')" | |
| 4 | + :visible.sync="visible" | |
| 5 | + width="50%" | |
| 6 | + @close="closeDialog" | |
| 7 | + > | |
| 8 | + <el-form label-width="120px"> | |
| 9 | + <el-form-item :label="$t('wirteInvoiceEvent.type')"> | |
| 10 | + <el-select | |
| 11 | + v-model="form.eventType" | |
| 12 | + :placeholder="$t('wirteInvoiceEvent.typeRequired')" | |
| 13 | + style="width: 100%" | |
| 14 | + > | |
| 15 | + <el-option | |
| 16 | + :label="$t('wirteInvoiceEvent.receive')" | |
| 17 | + value="4004" | |
| 18 | + /> | |
| 19 | + <el-option | |
| 20 | + :label="$t('wirteInvoiceEvent.register')" | |
| 21 | + value="5005" | |
| 22 | + /> | |
| 23 | + </el-select> | |
| 24 | + </el-form-item> | |
| 25 | + <el-form-item :label="$t('wirteInvoiceEvent.remark')"> | |
| 26 | + <el-input | |
| 27 | + v-model="form.remark" | |
| 28 | + type="textarea" | |
| 29 | + :rows="3" | |
| 30 | + :placeholder="$t('wirteInvoiceEvent.remarkRequired')" | |
| 31 | + /> | |
| 32 | + </el-form-item> | |
| 33 | + </el-form> | |
| 34 | + <div slot="footer"> | |
| 35 | + <el-button @click="closeDialog">{{ $t('common.cancel') }}</el-button> | |
| 36 | + <el-button | |
| 37 | + type="primary" | |
| 38 | + @click="saveEvent" | |
| 39 | + >{{ $t('common.save') }}</el-button> | |
| 40 | + </div> | |
| 41 | + </el-dialog> | |
| 42 | +</template> | |
| 43 | + | |
| 44 | +<script> | |
| 45 | +import { writeInvoiceEvent } from '@/api/fee/invoiceApplyApi' | |
| 46 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 47 | + | |
| 48 | +export default { | |
| 49 | + name: 'WirteInvoiceEvent', | |
| 50 | + data() { | |
| 51 | + return { | |
| 52 | + visible: false, | |
| 53 | + form: { | |
| 54 | + applyId: '', | |
| 55 | + eventType: '', | |
| 56 | + remark: '' | |
| 57 | + } | |
| 58 | + } | |
| 59 | + }, | |
| 60 | + methods: { | |
| 61 | + open(row) { | |
| 62 | + this.form = { | |
| 63 | + applyId: row.applyId, | |
| 64 | + eventType: '', | |
| 65 | + remark: '' | |
| 66 | + } | |
| 67 | + this.visible = true | |
| 68 | + }, | |
| 69 | + closeDialog() { | |
| 70 | + this.visible = false | |
| 71 | + }, | |
| 72 | + async saveEvent() { | |
| 73 | + if (!this.form.eventType) { | |
| 74 | + this.$message.warning(this.$t('wirteInvoiceEvent.typeRequired')) | |
| 75 | + return | |
| 76 | + } | |
| 77 | + if (!this.form.remark) { | |
| 78 | + this.$message.warning(this.$t('wirteInvoiceEvent.remarkRequired')) | |
| 79 | + return | |
| 80 | + } | |
| 81 | + | |
| 82 | + try { | |
| 83 | + const params = { | |
| 84 | + ...this.form, | |
| 85 | + communityId: getCommunityId() | |
| 86 | + } | |
| 87 | + await writeInvoiceEvent(params) | |
| 88 | + this.$emit('success') | |
| 89 | + this.$message.success(this.$t('common.saveSuccess')) | |
| 90 | + this.closeDialog() | |
| 91 | + } catch (error) { | |
| 92 | + this.$message.error(error.message) | |
| 93 | + } | |
| 94 | + } | |
| 95 | + } | |
| 96 | +} | |
| 97 | +</script> | |
| 0 | 98 | \ No newline at end of file | ... | ... |
src/i18n/index.js
| ... | ... | @@ -139,6 +139,10 @@ import { messages as ownerCommitteeManageMessages } from '../views/owner/ownerCo |
| 139 | 139 | import { messages as addOwnerCommitteeMessages } from '../views/owner/addOwnerCommitteeLang' |
| 140 | 140 | import { messages as editOwnerCommitteeMessages } from '../views/owner/editOwnerCommitteeLang' |
| 141 | 141 | import { messages as ownerCommitteeDetailMessages } from '../views/owner/ownerCommitteeDetailLang' |
| 142 | +import { messages as ownerInvoiceMessages } from '../views/fee/ownerInvoiceLang' | |
| 143 | +import { messages as invoiceApplyMessages } from '../views/fee/invoiceApplyLang' | |
| 144 | +import { messages as ownerApplyInvoiceMessages } from '../views/fee/ownerApplyInvoiceLang' | |
| 145 | +import { messages as invoiceApplyDetailMessages } from '../views/fee/invoiceApplyDetailLang' | |
| 142 | 146 | |
| 143 | 147 | Vue.use(VueI18n) |
| 144 | 148 | |
| ... | ... | @@ -282,6 +286,10 @@ const messages = { |
| 282 | 286 | ...addOwnerCommitteeMessages.en, |
| 283 | 287 | ...editOwnerCommitteeMessages.en, |
| 284 | 288 | ...ownerCommitteeDetailMessages.en, |
| 289 | + ...ownerInvoiceMessages.en, | |
| 290 | + ...invoiceApplyMessages.en, | |
| 291 | + ...ownerApplyInvoiceMessages.en, | |
| 292 | + ...invoiceApplyDetailMessages.en, | |
| 285 | 293 | }, |
| 286 | 294 | zh: { |
| 287 | 295 | ...loginMessages.zh, |
| ... | ... | @@ -421,6 +429,10 @@ const messages = { |
| 421 | 429 | ...addOwnerCommitteeMessages.zh, |
| 422 | 430 | ...editOwnerCommitteeMessages.zh, |
| 423 | 431 | ...ownerCommitteeDetailMessages.zh, |
| 432 | + ...ownerInvoiceMessages.zh, | |
| 433 | + ...invoiceApplyMessages.zh, | |
| 434 | + ...ownerApplyInvoiceMessages.zh, | |
| 435 | + ...invoiceApplyDetailMessages.zh, | |
| 424 | 436 | } |
| 425 | 437 | } |
| 426 | 438 | ... | ... |
src/router/index.js
| ... | ... | @@ -682,10 +682,35 @@ const routes = [ |
| 682 | 682 | component: () => import('@/views/owner/editOwnerCommitteeList.vue') |
| 683 | 683 | }, |
| 684 | 684 | { |
| 685 | - path:'/views/owner/ownerCommitteeDetail', | |
| 686 | - name:'/views/owner/ownerCommitteeDetail', | |
| 685 | + path: '/views/owner/ownerCommitteeDetail', | |
| 686 | + name: '/views/owner/ownerCommitteeDetail', | |
| 687 | 687 | component: () => import('@/views/owner/ownerCommitteeDetailList.vue') |
| 688 | + }, | |
| 689 | + { | |
| 690 | + path: '/pages/fee/ownerInvoice', | |
| 691 | + name: '/pages/fee/ownerInvoice', | |
| 692 | + component: () => import('@/views/fee/ownerInvoiceList.vue') | |
| 693 | + }, | |
| 694 | + { | |
| 695 | + path: '/views/fee/addOwnerInvoice', | |
| 696 | + name: '/views/fee/addOwnerInvoice', | |
| 697 | + component: () => import('@/views/fee/addOwnerInvoiceList.vue') | |
| 698 | + }, | |
| 699 | + { | |
| 700 | + path:'/pages/fee/invoiceApply', | |
| 701 | + name:'/pages/fee/invoiceApply', | |
| 702 | + component: () => import('@/views/fee/invoiceApplyList.vue') | |
| 688 | 703 | }, |
| 704 | + { | |
| 705 | + path:'/views/fee/ownerApplyInvoice', | |
| 706 | + name:'/views/fee/ownerApplyInvoice', | |
| 707 | + component: () => import('@/views/fee/ownerApplyInvoiceList.vue') | |
| 708 | + }, | |
| 709 | + { | |
| 710 | + path:'/views/fee/invoiceApplyDetail', | |
| 711 | + name:'/views/fee/invoiceApplyDetail', | |
| 712 | + component: () => import('@/views/fee/invoiceApplyDetailList.vue') | |
| 713 | + }, | |
| 689 | 714 | // 其他子路由可以在这里添加 |
| 690 | 715 | ] |
| 691 | 716 | }, | ... | ... |
src/views/fee/addOwnerInvoiceList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="app-container"> | |
| 3 | + <el-card shadow="never"> | |
| 4 | + <div slot="header" class="clearfix"> | |
| 5 | + <span>{{ $t('addOwnerInvoice.title') }}</span> | |
| 6 | + <el-button class="float-right" type="text" @click="$router.go(-1)"> | |
| 7 | + {{ $t('addOwnerInvoice.back') }} | |
| 8 | + </el-button> | |
| 9 | + </div> | |
| 10 | + | |
| 11 | + <el-form ref="form" :model="formData" :rules="rules" label-width="150px" label-position="right"> | |
| 12 | + <el-form-item :label="$t('addOwnerInvoice.owner')" prop="ownerName"> | |
| 13 | + <el-input v-model="formData.ownerName" :placeholder="$t('addOwnerInvoice.placeholder.owner')" disabled | |
| 14 | + style="width: 70%" /> | |
| 15 | + <el-button type="primary" style="margin-left: 10px" @click="openOwnerDialog"> | |
| 16 | + {{ $t('addOwnerInvoice.selectOwner') }} | |
| 17 | + </el-button> | |
| 18 | + </el-form-item> | |
| 19 | + | |
| 20 | + <el-form-item :label="$t('addOwnerInvoice.invoiceType')" prop="invoiceType"> | |
| 21 | + <el-select v-model="formData.invoiceType" :placeholder="$t('addOwnerInvoice.placeholder.invoiceType')" | |
| 22 | + style="width: 100%"> | |
| 23 | + <el-option v-for="item in invoiceTypes" :key="item.value" :label="item.label" :value="item.value" /> | |
| 24 | + </el-select> | |
| 25 | + </el-form-item> | |
| 26 | + | |
| 27 | + <el-form-item :label="$t('addOwnerInvoice.invoiceTitle')" prop="invoiceName"> | |
| 28 | + <el-input v-model="formData.invoiceName" :placeholder="$t('addOwnerInvoice.placeholder.invoiceTitle')" | |
| 29 | + style="width: 100%" /> | |
| 30 | + </el-form-item> | |
| 31 | + | |
| 32 | + <el-form-item :label="$t('addOwnerInvoice.taxNumber')" prop="invoiceNum"> | |
| 33 | + <el-input v-model="formData.invoiceNum" :placeholder="$t('addOwnerInvoice.placeholder.taxNumber')" | |
| 34 | + style="width: 100%" /> | |
| 35 | + </el-form-item> | |
| 36 | + | |
| 37 | + <el-form-item :label="$t('addOwnerInvoice.address')" prop="invoiceAddress"> | |
| 38 | + <el-input v-model="formData.invoiceAddress" :placeholder="$t('addOwnerInvoice.placeholder.address')" | |
| 39 | + style="width: 100%" /> | |
| 40 | + </el-form-item> | |
| 41 | + | |
| 42 | + <el-form-item :label="$t('addOwnerInvoice.phone')" prop="invoiceLink"> | |
| 43 | + <el-input v-model="formData.invoiceLink" :placeholder="$t('addOwnerInvoice.placeholder.phone')" | |
| 44 | + style="width: 100%" /> | |
| 45 | + </el-form-item> | |
| 46 | + | |
| 47 | + <el-form-item :label="$t('addOwnerInvoice.bankAccount')" prop="invoiceAccount"> | |
| 48 | + <el-input v-model="formData.invoiceAccount" :placeholder="$t('addOwnerInvoice.placeholder.bankAccount')" | |
| 49 | + style="width: 100%" /> | |
| 50 | + </el-form-item> | |
| 51 | + | |
| 52 | + <el-form-item :label="$t('addOwnerInvoice.remarks')"> | |
| 53 | + <el-input v-model="formData.remark" type="textarea" :rows="3" | |
| 54 | + :placeholder="$t('addOwnerInvoice.placeholder.remarks')" style="width: 100%" /> | |
| 55 | + </el-form-item> | |
| 56 | + | |
| 57 | + <el-form-item> | |
| 58 | + <el-button type="primary" @click="submitForm"> | |
| 59 | + {{ $t('addOwnerInvoice.save') }} | |
| 60 | + </el-button> | |
| 61 | + </el-form-item> | |
| 62 | + </el-form> | |
| 63 | + </el-card> | |
| 64 | + | |
| 65 | + <search-owner ref="searchOwner" :visible.sync="showOwnerDialog" @chooseOwner="handleOwnerSelect" /> | |
| 66 | + </div> | |
| 67 | +</template> | |
| 68 | + | |
| 69 | +<script> | |
| 70 | +import { saveOwnerInvoice } from '@/api/fee/addOwnerInvoiceApi' | |
| 71 | +import SearchOwner from '@/components/owner/SearchOwner' | |
| 72 | + | |
| 73 | +export default { | |
| 74 | + name: 'AddOwnerInvoice', | |
| 75 | + components: { SearchOwner }, | |
| 76 | + data() { | |
| 77 | + return { | |
| 78 | + showOwnerDialog: false, | |
| 79 | + formData: { | |
| 80 | + oiId: '', | |
| 81 | + ownerId: '', | |
| 82 | + ownerName: '', | |
| 83 | + invoiceType: '', | |
| 84 | + invoiceName: '', | |
| 85 | + invoiceNum: '', | |
| 86 | + invoiceAddress: '', | |
| 87 | + invoiceLink: '', | |
| 88 | + invoiceAccount: '', | |
| 89 | + remark: '' | |
| 90 | + }, | |
| 91 | + invoiceTypes: [ | |
| 92 | + { value: '1001', label: this.$t('addOwnerInvoice.personal') }, | |
| 93 | + { value: '2002', label: this.$t('addOwnerInvoice.enterprise') } | |
| 94 | + ], | |
| 95 | + rules: { | |
| 96 | + ownerName: [ | |
| 97 | + { required: true, message: this.$t('addOwnerInvoice.validation.ownerRequired'), trigger: 'blur' } | |
| 98 | + ], | |
| 99 | + invoiceType: [ | |
| 100 | + { required: true, message: this.$t('addOwnerInvoice.validation.typeRequired'), trigger: 'change' } | |
| 101 | + ], | |
| 102 | + invoiceName: [ | |
| 103 | + { required: true, message: this.$t('addOwnerInvoice.validation.titleRequired'), trigger: 'blur' } | |
| 104 | + ], | |
| 105 | + invoiceNum: [ | |
| 106 | + { required: true, message: this.$t('addOwnerInvoice.validation.taxNumberRequired'), trigger: 'blur' } | |
| 107 | + ], | |
| 108 | + invoiceAddress: [ | |
| 109 | + { required: true, message: this.$t('addOwnerInvoice.validation.addressRequired'), trigger: 'blur' } | |
| 110 | + ], | |
| 111 | + invoiceLink: [ | |
| 112 | + { required: true, message: this.$t('addOwnerInvoice.validation.phoneRequired'), trigger: 'blur' } | |
| 113 | + ], | |
| 114 | + invoiceAccount: [ | |
| 115 | + { required: true, message: this.$t('addOwnerInvoice.validation.bankAccountRequired'), trigger: 'blur' } | |
| 116 | + ] | |
| 117 | + } | |
| 118 | + } | |
| 119 | + }, | |
| 120 | + methods: { | |
| 121 | + openOwnerDialog() { | |
| 122 | + this.$refs.searchOwner.open() | |
| 123 | + }, | |
| 124 | + handleOwnerSelect(owner) { | |
| 125 | + this.formData.ownerId = owner.ownerId | |
| 126 | + this.formData.ownerName = owner.name | |
| 127 | + }, | |
| 128 | + submitForm() { | |
| 129 | + this.$refs.form.validate(async valid => { | |
| 130 | + if (valid) { | |
| 131 | + try { | |
| 132 | + const payload = { | |
| 133 | + ...this.formData, | |
| 134 | + communityId: this.getCommunityId() | |
| 135 | + } | |
| 136 | + | |
| 137 | + await saveOwnerInvoice(payload) | |
| 138 | + this.$message.success(this.$t('common.saveSuccess')) | |
| 139 | + this.$router.go(-1) | |
| 140 | + } catch (error) { | |
| 141 | + console.error('保存失败:', error) | |
| 142 | + this.$message.error(error.message || this.$t('common.saveFailed')) | |
| 143 | + } | |
| 144 | + } | |
| 145 | + }) | |
| 146 | + } | |
| 147 | + } | |
| 148 | +} | |
| 149 | +</script> | |
| 150 | + | |
| 151 | +<style lang="scss" scoped> | |
| 152 | +.app-container { | |
| 153 | + padding: 20px; | |
| 154 | +} | |
| 155 | + | |
| 156 | +.float-right { | |
| 157 | + float: right; | |
| 158 | +} | |
| 159 | + | |
| 160 | +.el-form { | |
| 161 | + max-width: 800px; | |
| 162 | + margin: 0 auto; | |
| 163 | +} | |
| 164 | + | |
| 165 | +.el-select, | |
| 166 | +.el-input { | |
| 167 | + width: 100%; | |
| 168 | +} | |
| 169 | +</style> | |
| 0 | 170 | \ No newline at end of file | ... | ... |
src/views/fee/invoiceApplyDetailLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + invoiceApplyDetail: { | |
| 4 | + title: 'Invoice Details', | |
| 5 | + back: 'Back', | |
| 6 | + applyId: 'Apply ID:', | |
| 7 | + invoiceType: 'Invoice Type:', | |
| 8 | + personal: 'Personal', | |
| 9 | + company: 'Company', | |
| 10 | + ownerName: 'Owner Name:', | |
| 11 | + createUserName: 'Applicant:', | |
| 12 | + invoiceName: 'Invoice Title:', | |
| 13 | + invoiceNum: 'Taxpayer ID:', | |
| 14 | + invoiceAddress: 'Address/Phone:', | |
| 15 | + invoiceAmount: 'Apply Amount:', | |
| 16 | + stateName: 'Status:', | |
| 17 | + createTime: 'Apply Time:', | |
| 18 | + invoiceCode: 'Invoice Code:', | |
| 19 | + feeTab: 'Fee Details', | |
| 20 | + eventTab: 'Audit Records', | |
| 21 | + imageTab: 'View Invoice', | |
| 22 | + notUploaded: 'Not uploaded', | |
| 23 | + noInvoice: 'No Invoice', | |
| 24 | + downloadInvoice: 'Download Invoice', | |
| 25 | + fetchError: 'Failed to fetch invoice details' | |
| 26 | + }, | |
| 27 | + invoiceApplyDetailFee: { | |
| 28 | + type: 'Type', | |
| 29 | + name: 'Name', | |
| 30 | + amount: 'Amount', | |
| 31 | + payTime: 'Pay Time', | |
| 32 | + remark: 'Remark', | |
| 33 | + paymentId: 'Payment ID', | |
| 34 | + feeType: 'Fee', | |
| 35 | + accountType: 'Account', | |
| 36 | + fetchError: 'Failed to fetch fee details' | |
| 37 | + }, | |
| 38 | + invoiceApplyDetailEvent: { | |
| 39 | + type: 'Type', | |
| 40 | + operator: 'Operator', | |
| 41 | + remark: 'Remark', | |
| 42 | + time: 'Time', | |
| 43 | + fetchError: 'Failed to fetch audit records' | |
| 44 | + }, | |
| 45 | + }, | |
| 46 | + zh: { | |
| 47 | + invoiceApplyDetail: { | |
| 48 | + title: '发票详情', | |
| 49 | + back: '返回', | |
| 50 | + applyId: '编号:', | |
| 51 | + invoiceType: '发票类型:', | |
| 52 | + personal: '个人', | |
| 53 | + company: '企业', | |
| 54 | + ownerName: '业主名称:', | |
| 55 | + createUserName: '申请人:', | |
| 56 | + invoiceName: '发票名头:', | |
| 57 | + invoiceNum: '纳税人识别号:', | |
| 58 | + invoiceAddress: '地址、电话:', | |
| 59 | + invoiceAmount: '申请金额:', | |
| 60 | + stateName: '审核状态:', | |
| 61 | + createTime: '申请时间:', | |
| 62 | + invoiceCode: '发票编号:', | |
| 63 | + feeTab: '开票明细', | |
| 64 | + eventTab: '审核记录', | |
| 65 | + imageTab: '查看发票', | |
| 66 | + notUploaded: '未上传', | |
| 67 | + noInvoice: '没有发票', | |
| 68 | + downloadInvoice: '下载发票', | |
| 69 | + fetchError: '获取发票详情失败' | |
| 70 | + }, | |
| 71 | + invoiceApplyDetailFee: { | |
| 72 | + type: '类型', | |
| 73 | + name: '名称', | |
| 74 | + amount: '金额', | |
| 75 | + payTime: '缴费时间', | |
| 76 | + remark: '备注', | |
| 77 | + paymentId: '缴费ID', | |
| 78 | + feeType: '费用', | |
| 79 | + accountType: '账户', | |
| 80 | + fetchError: '获取费用明细失败' | |
| 81 | + }, | |
| 82 | + invoiceApplyDetailEvent: { | |
| 83 | + type: '类型', | |
| 84 | + operator: '操作人', | |
| 85 | + remark: '说明', | |
| 86 | + time: '时间', | |
| 87 | + fetchError: '获取审核记录失败' | |
| 88 | + }, | |
| 89 | + } | |
| 90 | +} | |
| 0 | 91 | \ No newline at end of file | ... | ... |
src/views/fee/invoiceApplyDetailList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="invoice-apply-detail"> | |
| 3 | + <el-card class="box-card"> | |
| 4 | + <div class="card-header"> | |
| 5 | + <div class="text-title">{{ $t('invoiceApplyDetail.title') }}</div> | |
| 6 | + <div> | |
| 7 | + <el-button type="primary" size="small" style="margin-left:10px" @click="goBack"> | |
| 8 | + {{ $t('invoiceApplyDetail.back') }} | |
| 9 | + </el-button> | |
| 10 | + </div> | |
| 11 | + </div> | |
| 12 | + | |
| 13 | + <!-- 业主信息 --> | |
| 14 | + <div class="margin-top"> | |
| 15 | + <el-row :gutter="20"> | |
| 16 | + <el-col :span="24"> | |
| 17 | + <el-row :gutter="20"> | |
| 18 | + <el-col :span="6"> | |
| 19 | + <div class="form-group"> | |
| 20 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.applyId') }}</label> | |
| 21 | + <label>{{ invoiceApplyDetailInfo.applyId }}</label> | |
| 22 | + </div> | |
| 23 | + </el-col> | |
| 24 | + <el-col :span="6"> | |
| 25 | + <div class="form-group"> | |
| 26 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.invoiceType') }}</label> | |
| 27 | + <label>{{ invoiceApplyDetailInfo.invoiceType === '1001' ? $t('invoiceApplyDetail.personal') : | |
| 28 | + $t('invoiceApplyDetail.company') }}</label> | |
| 29 | + </div> | |
| 30 | + </el-col> | |
| 31 | + <el-col :span="6"> | |
| 32 | + <div class="form-group"> | |
| 33 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.ownerName') }}</label> | |
| 34 | + <label>{{ invoiceApplyDetailInfo.ownerName }}</label> | |
| 35 | + </div> | |
| 36 | + </el-col> | |
| 37 | + <el-col :span="6"> | |
| 38 | + <div class="form-group"> | |
| 39 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.createUserName') }}</label> | |
| 40 | + <label>{{ invoiceApplyDetailInfo.createUserName }}({{ invoiceApplyDetailInfo.applyTel }})</label> | |
| 41 | + </div> | |
| 42 | + </el-col> | |
| 43 | + </el-row> | |
| 44 | + <el-row :gutter="20"> | |
| 45 | + <el-col :span="6"> | |
| 46 | + <div class="form-group"> | |
| 47 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.invoiceName') }}</label> | |
| 48 | + <label>{{ invoiceApplyDetailInfo.invoiceName }}</label> | |
| 49 | + </div> | |
| 50 | + </el-col> | |
| 51 | + <el-col :span="6"> | |
| 52 | + <div class="form-group"> | |
| 53 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.invoiceNum') }}</label> | |
| 54 | + <label>{{ invoiceApplyDetailInfo.invoiceNum }}</label> | |
| 55 | + </div> | |
| 56 | + </el-col> | |
| 57 | + <el-col :span="6"> | |
| 58 | + <div class="form-group"> | |
| 59 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.invoiceAddress') }}</label> | |
| 60 | + <label>{{ invoiceApplyDetailInfo.invoiceAddress }}</label> | |
| 61 | + </div> | |
| 62 | + </el-col> | |
| 63 | + <el-col :span="6"> | |
| 64 | + <div class="form-group"> | |
| 65 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.invoiceAmount') }}</label> | |
| 66 | + <label>{{ invoiceApplyDetailInfo.invoiceAmount }}</label> | |
| 67 | + </div> | |
| 68 | + </el-col> | |
| 69 | + </el-row> | |
| 70 | + <el-row :gutter="20"> | |
| 71 | + <el-col :span="6"> | |
| 72 | + <div class="form-group"> | |
| 73 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.stateName') }}</label> | |
| 74 | + <label>{{ invoiceApplyDetailInfo.stateName }}</label> | |
| 75 | + </div> | |
| 76 | + </el-col> | |
| 77 | + <el-col :span="6"> | |
| 78 | + <div class="form-group"> | |
| 79 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.createTime') }}</label> | |
| 80 | + <label>{{ invoiceApplyDetailInfo.createTime }}</label> | |
| 81 | + </div> | |
| 82 | + </el-col> | |
| 83 | + <el-col :span="6"> | |
| 84 | + <div class="form-group"> | |
| 85 | + <label class="col-form-label">{{ $t('invoiceApplyDetail.invoiceCode') }}</label> | |
| 86 | + <label>{{ invoiceApplyDetailInfo.invoiceCode || $t('invoiceApplyDetail.notUploaded') }}</label> | |
| 87 | + </div> | |
| 88 | + </el-col> | |
| 89 | + </el-row> | |
| 90 | + </el-col> | |
| 91 | + </el-row> | |
| 92 | + </div> | |
| 93 | + <el-divider></el-divider> | |
| 94 | + | |
| 95 | + <el-tabs v-model="invoiceApplyDetailInfo._currentTab" @tab-click="handleTabClick"> | |
| 96 | + <el-tab-pane :label="$t('invoiceApplyDetail.feeTab')" name="invoiceApplyDetailFee"> | |
| 97 | + <invoice-apply-detail-fee v-if="invoiceApplyDetailInfo._currentTab === 'invoiceApplyDetailFee'" | |
| 98 | + :apply-id="invoiceApplyDetailInfo.applyId" | |
| 99 | + :owner-id="invoiceApplyDetailInfo.ownerId"></invoice-apply-detail-fee> | |
| 100 | + </el-tab-pane> | |
| 101 | + <el-tab-pane :label="$t('invoiceApplyDetail.eventTab')" name="invoiceApplyDetailEvent"> | |
| 102 | + <invoice-apply-detail-event v-if="invoiceApplyDetailInfo._currentTab === 'invoiceApplyDetailEvent'" | |
| 103 | + :apply-id="invoiceApplyDetailInfo.applyId"></invoice-apply-detail-event> | |
| 104 | + </el-tab-pane> | |
| 105 | + <el-tab-pane :label="$t('invoiceApplyDetail.imageTab')" name="invoiceApplyDetailJpg"> | |
| 106 | + <div v-if="invoiceApplyDetailInfo.urls && invoiceApplyDetailInfo.urls.length > 0"> | |
| 107 | + <div v-for="(item, index) in invoiceApplyDetailInfo.urls" :key="index"> | |
| 108 | + <a target="_blank" :href="item">{{ $t('invoiceApplyDetail.downloadInvoice') }}</a> | |
| 109 | + </div> | |
| 110 | + </div> | |
| 111 | + <div class="padding" v-else> | |
| 112 | + {{ $t('invoiceApplyDetail.noInvoice') }} | |
| 113 | + </div> | |
| 114 | + </el-tab-pane> | |
| 115 | + </el-tabs> | |
| 116 | + </el-card> | |
| 117 | + </div> | |
| 118 | +</template> | |
| 119 | + | |
| 120 | +<script> | |
| 121 | +import { getInvoiceApplyDetail } from '@/api/fee/invoiceApplyDetailApi' | |
| 122 | +import InvoiceApplyDetailFee from '@/components/fee/invoiceApplyDetailFee' | |
| 123 | +import InvoiceApplyDetailEvent from '@/components/fee/invoiceApplyDetailEvent' | |
| 124 | + | |
| 125 | +export default { | |
| 126 | + name: 'InvoiceApplyDetailList', | |
| 127 | + components: { | |
| 128 | + InvoiceApplyDetailFee, | |
| 129 | + InvoiceApplyDetailEvent | |
| 130 | + }, | |
| 131 | + data() { | |
| 132 | + return { | |
| 133 | + invoiceApplyDetailInfo: { | |
| 134 | + applyId: '', | |
| 135 | + invoiceType: '', | |
| 136 | + ownerName: '', | |
| 137 | + createUserName: '', | |
| 138 | + invoiceName: '', | |
| 139 | + invoiceNum: '', | |
| 140 | + invoiceAddress: '', | |
| 141 | + invoiceAmount: '', | |
| 142 | + stateName: '', | |
| 143 | + createTime: '', | |
| 144 | + invoiceCode: '', | |
| 145 | + urls: [], | |
| 146 | + _currentTab: 'invoiceApplyDetailFee' | |
| 147 | + } | |
| 148 | + } | |
| 149 | + }, | |
| 150 | + created() { | |
| 151 | + this.invoiceApplyDetailInfo.applyId = this.$route.query.applyId | |
| 152 | + if (this.invoiceApplyDetailInfo.applyId) { | |
| 153 | + this.loadInvoiceApplyInfo() | |
| 154 | + } | |
| 155 | + }, | |
| 156 | + methods: { | |
| 157 | + async loadInvoiceApplyInfo() { | |
| 158 | + try { | |
| 159 | + const params = { | |
| 160 | + page: 1, | |
| 161 | + row: 1, | |
| 162 | + applyId: this.invoiceApplyDetailInfo.applyId | |
| 163 | + } | |
| 164 | + const res = await getInvoiceApplyDetail(params) | |
| 165 | + if (res.code === 0 && res.data && res.data.length > 0) { | |
| 166 | + Object.assign(this.invoiceApplyDetailInfo, res.data[0]) | |
| 167 | + } | |
| 168 | + } catch (error) { | |
| 169 | + this.$message.error(this.$t('invoiceApplyDetail.fetchError')) | |
| 170 | + } | |
| 171 | + }, | |
| 172 | + handleTabClick(tab) { | |
| 173 | + this.invoiceApplyDetailInfo._currentTab = tab.name | |
| 174 | + }, | |
| 175 | + goBack() { | |
| 176 | + this.$router.go(-1) | |
| 177 | + } | |
| 178 | + } | |
| 179 | +} | |
| 180 | +</script> | |
| 181 | + | |
| 182 | +<style scoped> | |
| 183 | +.invoice-apply-detail { | |
| 184 | + padding: 20px; | |
| 185 | +} | |
| 186 | + | |
| 187 | +.card-header { | |
| 188 | + display: flex; | |
| 189 | + justify-content: space-between; | |
| 190 | + align-items: center; | |
| 191 | +} | |
| 192 | + | |
| 193 | +.text-title { | |
| 194 | + font-size: 18px; | |
| 195 | + font-weight: bold; | |
| 196 | +} | |
| 197 | + | |
| 198 | +.margin-top { | |
| 199 | + margin-top: 20px; | |
| 200 | +} | |
| 201 | + | |
| 202 | +.padding { | |
| 203 | + padding: 20px; | |
| 204 | +} | |
| 205 | + | |
| 206 | +.form-group { | |
| 207 | + margin-bottom: 15px; | |
| 208 | +} | |
| 209 | + | |
| 210 | +.col-form-label { | |
| 211 | + margin-right: 10px; | |
| 212 | +}</style> | |
| 0 | 213 | \ No newline at end of file | ... | ... |
src/views/fee/invoiceApplyLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + invoiceApply: { | |
| 4 | + searchTitle: 'Search Conditions', | |
| 5 | + title: 'Invoice Application', | |
| 6 | + apply: 'Apply', | |
| 7 | + table: { | |
| 8 | + id: 'ID', | |
| 9 | + invoiceType: 'Invoice Type', | |
| 10 | + ownerName: 'Owner Name', | |
| 11 | + applicant: 'Applicant', | |
| 12 | + invoiceName: 'Invoice Title', | |
| 13 | + taxNumber: 'Taxpayer ID', | |
| 14 | + addressPhone: 'Address & Phone', | |
| 15 | + amount: 'Amount', | |
| 16 | + invoiceCode: 'Invoice Code', | |
| 17 | + status: 'Status', | |
| 18 | + applyTime: 'Apply Time' | |
| 19 | + }, | |
| 20 | + states: { | |
| 21 | + all: 'All', | |
| 22 | + pendingReview: 'Pending Review', | |
| 23 | + pendingUpload: 'Pending Upload', | |
| 24 | + reviewFailed: 'Review Failed', | |
| 25 | + pendingReceive: 'Pending Receive', | |
| 26 | + received: 'Received' | |
| 27 | + }, | |
| 28 | + personal: 'Personal', | |
| 29 | + company: 'Company', | |
| 30 | + notUploaded: 'Not Uploaded', | |
| 31 | + openInvoice: 'Open Invoice', | |
| 32 | + uploadInvoice: 'Upload Invoice', | |
| 33 | + reUpload: 'Re-upload', | |
| 34 | + verify: 'Verify', | |
| 35 | + register: 'Register', | |
| 36 | + auditSuccess: 'Audit successful', | |
| 37 | + invoiceCodePlaceholder: 'Please enter invoice number', | |
| 38 | + invoiceTypePlaceholder: 'Please select invoice type', | |
| 39 | + ownerNamePlaceholder: 'Please enter owner name', | |
| 40 | + applicantPlaceholder: 'Please enter applicant', | |
| 41 | + phonePlaceholder: 'Please enter applicant phone' | |
| 42 | + }, | |
| 43 | + deleteInvoiceApply: { | |
| 44 | + title: 'Confirm Operation', | |
| 45 | + confirmMessage: 'Confirm to delete this invoice application?' | |
| 46 | + }, | |
| 47 | + uploadInvoicePhoto: { | |
| 48 | + title: 'Upload Invoice', | |
| 49 | + invoiceCode: 'Invoice Code', | |
| 50 | + invoice: 'Invoice', | |
| 51 | + codeRequired: 'Required, please enter invoice code', | |
| 52 | + photoRequired: 'Please select invoice photo' | |
| 53 | + }, | |
| 54 | + wirteInvoiceEvent: { | |
| 55 | + title: 'Register/Verify', | |
| 56 | + type: 'Type', | |
| 57 | + remark: 'Remark', | |
| 58 | + typeRequired: 'Required, please select type', | |
| 59 | + remarkRequired: 'Required, please enter remark', | |
| 60 | + receive: 'Receive', | |
| 61 | + register: 'Register' | |
| 62 | + }, | |
| 63 | + audit: { | |
| 64 | + title: 'Audit Information', | |
| 65 | + status: 'Audit Status', | |
| 66 | + reason: 'Reason', | |
| 67 | + statusRequired: 'Please select audit status', | |
| 68 | + reasonRequired: 'Required, please enter reason', | |
| 69 | + approve: 'Approve', | |
| 70 | + reject: 'Reject' | |
| 71 | + }, | |
| 72 | + uploadImage: { | |
| 73 | + sizeLimit: 'Image size cannot exceed 2MB' | |
| 74 | + } | |
| 75 | + }, | |
| 76 | + zh: { | |
| 77 | + invoiceApply: { | |
| 78 | + searchTitle: '查询条件', | |
| 79 | + title: '申请发票', | |
| 80 | + apply: '申请', | |
| 81 | + table: { | |
| 82 | + id: '编号', | |
| 83 | + invoiceType: '发票类型', | |
| 84 | + ownerName: '业主名称', | |
| 85 | + applicant: '申请人', | |
| 86 | + invoiceName: '发票名头', | |
| 87 | + taxNumber: '纳税人识别号', | |
| 88 | + addressPhone: '地址、电话', | |
| 89 | + amount: '申请金额', | |
| 90 | + invoiceCode: '发票号', | |
| 91 | + status: '审核状态', | |
| 92 | + applyTime: '申请时间' | |
| 93 | + }, | |
| 94 | + states: { | |
| 95 | + all: '全部', | |
| 96 | + pendingReview: '待审核', | |
| 97 | + pendingUpload: '待上传', | |
| 98 | + reviewFailed: '审核失败', | |
| 99 | + pendingReceive: '带领用', | |
| 100 | + received: '已领用' | |
| 101 | + }, | |
| 102 | + personal: '个人', | |
| 103 | + company: '企业', | |
| 104 | + notUploaded: '未上传', | |
| 105 | + openInvoice: '开票', | |
| 106 | + uploadInvoice: '上传发票', | |
| 107 | + reUpload: '重新上传', | |
| 108 | + verify: '核销', | |
| 109 | + register: '登记', | |
| 110 | + auditSuccess: '审核成功', | |
| 111 | + invoiceCodePlaceholder: '请填写发票号', | |
| 112 | + invoiceTypePlaceholder: '请选择发票类型', | |
| 113 | + ownerNamePlaceholder: '请填写业主名称', | |
| 114 | + applicantPlaceholder: '请填写申请人', | |
| 115 | + phonePlaceholder: '请填写申请人电话' | |
| 116 | + }, | |
| 117 | + deleteInvoiceApply: { | |
| 118 | + title: '请确认您的操作', | |
| 119 | + confirmMessage: '确定删除申请发票' | |
| 120 | + }, | |
| 121 | + uploadInvoicePhoto: { | |
| 122 | + title: '上传发票', | |
| 123 | + invoiceCode: '发票编号', | |
| 124 | + invoice: '发票', | |
| 125 | + codeRequired: '必填,请填写发票编号', | |
| 126 | + photoRequired: '请选择发票' | |
| 127 | + }, | |
| 128 | + wirteInvoiceEvent: { | |
| 129 | + title: '登记核销', | |
| 130 | + type: '类型', | |
| 131 | + remark: '说明', | |
| 132 | + typeRequired: '必填,请选择类型', | |
| 133 | + remarkRequired: '必填,请填写说明', | |
| 134 | + receive: '领用', | |
| 135 | + register: '登记' | |
| 136 | + }, | |
| 137 | + audit: { | |
| 138 | + title: '审核信息', | |
| 139 | + status: '审核状态', | |
| 140 | + reason: '原因', | |
| 141 | + statusRequired: '请审核', | |
| 142 | + reasonRequired: '必填,请填写原因', | |
| 143 | + approve: '同意', | |
| 144 | + reject: '拒绝' | |
| 145 | + }, | |
| 146 | + uploadImage: { | |
| 147 | + sizeLimit: '图片大小不能超过 2MB' | |
| 148 | + } | |
| 149 | + } | |
| 150 | +} | |
| 0 | 151 | \ No newline at end of file | ... | ... |
src/views/fee/invoiceApplyList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div> | |
| 3 | + <el-row :gutter="20"> | |
| 4 | + <el-col :span="4"> | |
| 5 | + <el-card class="border-radius"> | |
| 6 | + <div class="treeview attendance-staff"> | |
| 7 | + <ul class="list-group text-center border-radius"> | |
| 8 | + <li v-for="(item, index) in states" :key="index" @click="swatchState(item)" :class="{ | |
| 9 | + 'vc-node-selected': conditions.state === item.state | |
| 10 | + }" class="list-group-item node-orgTree"> | |
| 11 | + {{ $t(`invoiceApply.states.${item.stateName}`) }} | |
| 12 | + </li> | |
| 13 | + </ul> | |
| 14 | + </div> | |
| 15 | + </el-card> | |
| 16 | + </el-col> | |
| 17 | + <el-col :span="20"> | |
| 18 | + <el-row> | |
| 19 | + <el-col :span="24"> | |
| 20 | + <el-card> | |
| 21 | + <div slot="header" class="text-left"> | |
| 22 | + <span>{{ $t('invoiceApply.searchTitle') }}</span> | |
| 23 | + </div> | |
| 24 | + <el-row :gutter="20"> | |
| 25 | + <el-col :span="4"> | |
| 26 | + <el-input v-model="conditions.invoiceCode" :placeholder="$t('invoiceApply.invoiceCodePlaceholder')" /> | |
| 27 | + </el-col> | |
| 28 | + <el-col :span="4"> | |
| 29 | + <el-select v-model="conditions.invoiceType" :placeholder="$t('invoiceApply.invoiceTypePlaceholder')"> | |
| 30 | + <el-option label="请选择发票类型" value="" /> | |
| 31 | + <el-option label="个人" value="1001" /> | |
| 32 | + <el-option label="企业" value="2002" /> | |
| 33 | + </el-select> | |
| 34 | + </el-col> | |
| 35 | + <el-col :span="4"> | |
| 36 | + <el-input v-model="conditions.ownerName" :placeholder="$t('invoiceApply.ownerNamePlaceholder')" /> | |
| 37 | + </el-col> | |
| 38 | + <el-col :span="4"> | |
| 39 | + <el-input v-model="conditions.createUserName" :placeholder="$t('invoiceApply.applicantPlaceholder')" /> | |
| 40 | + </el-col> | |
| 41 | + <el-col :span="4"> | |
| 42 | + <el-input v-model="conditions.applyTel" :placeholder="$t('invoiceApply.phonePlaceholder')" /> | |
| 43 | + </el-col> | |
| 44 | + <el-col :span="4"> | |
| 45 | + <el-button type="primary" @click="_queryInvoiceApplyMethod"> | |
| 46 | + <i class="el-icon-search" /> | |
| 47 | + <span>{{ $t('common.search') }}</span> | |
| 48 | + </el-button> | |
| 49 | + </el-col> | |
| 50 | + </el-row> | |
| 51 | + </el-card> | |
| 52 | + </el-col> | |
| 53 | + </el-row> | |
| 54 | + <el-row> | |
| 55 | + <el-col :span="24"> | |
| 56 | + <el-card> | |
| 57 | + <div slot="header" class="flex justify-between"> | |
| 58 | + <span>{{ $t('invoiceApply.title') }}</span> | |
| 59 | + <el-button type="primary" size="small" class="float-right" @click="_invoiceApply"> | |
| 60 | + {{ $t('invoiceApply.apply') }} | |
| 61 | + </el-button> | |
| 62 | + </div> | |
| 63 | + <el-table :data="invoiceApplys" border style="width: 100%"> | |
| 64 | + <el-table-column prop="applyId" :label="$t('invoiceApply.table.id')" align="center" /> | |
| 65 | + <el-table-column prop="invoiceType" :label="$t('invoiceApply.table.invoiceType')" align="center"> | |
| 66 | + <template slot-scope="scope"> | |
| 67 | + {{ scope.row.invoiceType === '1001' ? $t('invoiceApply.personal') : $t('invoiceApply.company') }} | |
| 68 | + </template> | |
| 69 | + </el-table-column> | |
| 70 | + <el-table-column prop="ownerName" :label="$t('invoiceApply.table.ownerName')" align="center" /> | |
| 71 | + <el-table-column :label="$t('invoiceApply.table.applicant')" align="center"> | |
| 72 | + <template slot-scope="scope"> | |
| 73 | + {{ scope.row.createUserName }}({{ scope.row.applyTel }}) | |
| 74 | + </template> | |
| 75 | + </el-table-column> | |
| 76 | + <el-table-column prop="invoiceName" :label="$t('invoiceApply.table.invoiceName')" align="center" /> | |
| 77 | + <el-table-column prop="invoiceNum" :label="$t('invoiceApply.table.taxNumber')" align="center" /> | |
| 78 | + <el-table-column prop="invoiceAddress" :label="$t('invoiceApply.table.addressPhone')" align="center" /> | |
| 79 | + <el-table-column prop="invoiceAmount" :label="$t('invoiceApply.table.amount')" align="center" /> | |
| 80 | + <el-table-column prop="invoiceCode" :label="$t('invoiceApply.table.invoiceCode')" align="center"> | |
| 81 | + <template slot-scope="scope"> | |
| 82 | + {{ scope.row.invoiceCode || $t('invoiceApply.notUploaded') }} | |
| 83 | + </template> | |
| 84 | + </el-table-column> | |
| 85 | + <el-table-column prop="stateName" :label="$t('invoiceApply.table.status')" align="center" /> | |
| 86 | + <el-table-column prop="createTime" :label="$t('invoiceApply.table.applyTime')" align="center" /> | |
| 87 | + <el-table-column :label="$t('common.operation')" align="center" width="220"> | |
| 88 | + <template slot-scope="scope"> | |
| 89 | + <el-button v-if="scope.row.state === 'W'" size="mini" @click="_openInvoiceAuditModel(scope.row)"> | |
| 90 | + {{ $t('common.audit') }} | |
| 91 | + </el-button> | |
| 92 | + <template v-else> | |
| 93 | + <el-button v-if="hasPlugin('invoice') && scope.row.state !== 'W'" size="mini" | |
| 94 | + @click="_toOpenInvoicePlugin(scope.row)"> | |
| 95 | + {{ $t('invoiceApply.openInvoice') }} | |
| 96 | + </el-button> | |
| 97 | + <div v-else> | |
| 98 | + <el-button v-if="['U', 'G', 'C'].includes(scope.row.state)" size="mini" | |
| 99 | + @click="_openUploadInvoicePhoto(scope.row)"> | |
| 100 | + {{ scope.row.state === 'U' ? $t('invoiceApply.uploadInvoice') : $t('invoiceApply.reUpload') }} | |
| 101 | + </el-button> | |
| 102 | + <el-button v-if="['U', 'G', 'C'].includes(scope.row.state)" size="mini" | |
| 103 | + @click="_openUserGetInvoice(scope.row)"> | |
| 104 | + {{ scope.row.state === 'G' ? $t('invoiceApply.verify') : $t('invoiceApply.register') }} | |
| 105 | + </el-button> | |
| 106 | + </div> | |
| 107 | + </template> | |
| 108 | + <el-button size="mini" type="danger" @click="_openDeleteInvoiceApplyModel(scope.row)"> | |
| 109 | + {{ $t('common.delete') }} | |
| 110 | + </el-button> | |
| 111 | + <el-button size="mini" @click="_openInvoiceApplyDetail(scope.row)"> | |
| 112 | + {{ $t('common.detail') }} | |
| 113 | + </el-button> | |
| 114 | + </template> | |
| 115 | + </el-table-column> | |
| 116 | + </el-table> | |
| 117 | + <el-pagination :current-page="page.current" :page-sizes="[10, 20, 30, 50]" :page-size="page.size" | |
| 118 | + :total="page.total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange" | |
| 119 | + @current-change="handleCurrentChange" /> | |
| 120 | + </el-card> | |
| 121 | + </el-col> | |
| 122 | + </el-row> | |
| 123 | + </el-col> | |
| 124 | + </el-row> | |
| 125 | + | |
| 126 | + <delete-invoice-apply ref="deleteDialog" @success="listInvoiceApplys" /> | |
| 127 | + <upload-invoice-photo ref="uploadPhotoDialog" @success="listInvoiceApplys" /> | |
| 128 | + <wirte-invoice-event ref="writeEventDialog" @success="listInvoiceApplys" /> | |
| 129 | + <audit-dialog ref="auditDialog" @success="notifyAuditInfo" /> | |
| 130 | + </div> | |
| 131 | +</template> | |
| 132 | + | |
| 133 | +<script> | |
| 134 | +import { listInvoiceApply, auditInvoiceApply } from '@/api/fee/invoiceApplyApi' | |
| 135 | +import { getCommunityId } from '@/api/community/communityApi' | |
| 136 | +import DeleteInvoiceApply from '@/components/fee/deleteInvoiceApply' | |
| 137 | +import UploadInvoicePhoto from '@/components/fee/uploadInvoicePhoto' | |
| 138 | +import WirteInvoiceEvent from '@/components/fee/wirteInvoiceEvent' | |
| 139 | +import AuditDialog from '@/components/fee/audit' | |
| 140 | + | |
| 141 | +export default { | |
| 142 | + name: 'InvoiceApplyList', | |
| 143 | + components: { | |
| 144 | + DeleteInvoiceApply, | |
| 145 | + UploadInvoicePhoto, | |
| 146 | + WirteInvoiceEvent, | |
| 147 | + AuditDialog | |
| 148 | + }, | |
| 149 | + data() { | |
| 150 | + return { | |
| 151 | + states: [ | |
| 152 | + { stateName: 'all', state: '' }, | |
| 153 | + { stateName: 'pendingReview', state: 'W' }, | |
| 154 | + { stateName: 'pendingUpload', state: 'U' }, | |
| 155 | + { stateName: 'reviewFailed', state: 'F' }, | |
| 156 | + { stateName: 'pendingReceive', state: 'G' }, | |
| 157 | + { stateName: 'received', state: 'C' } | |
| 158 | + ], | |
| 159 | + conditions: { | |
| 160 | + invoiceCode: '', | |
| 161 | + invoiceType: '', | |
| 162 | + ownerName: '', | |
| 163 | + applyTel: '', | |
| 164 | + createUserName: '', | |
| 165 | + state: '' | |
| 166 | + }, | |
| 167 | + invoiceApplys: [], | |
| 168 | + page: { | |
| 169 | + current: 1, | |
| 170 | + size: 10, | |
| 171 | + total: 0 | |
| 172 | + }, | |
| 173 | + auditData: {} | |
| 174 | + } | |
| 175 | + }, | |
| 176 | + created() { | |
| 177 | + this.communityId = getCommunityId() | |
| 178 | + this.listInvoiceApplys() | |
| 179 | + }, | |
| 180 | + methods: { | |
| 181 | + async listInvoiceApplys() { | |
| 182 | + try { | |
| 183 | + const params = { | |
| 184 | + ...this.conditions, | |
| 185 | + page: this.page.current, | |
| 186 | + row: this.page.size, | |
| 187 | + communityId: this.communityId | |
| 188 | + } | |
| 189 | + const res = await listInvoiceApply(params) | |
| 190 | + this.invoiceApplys = res.data | |
| 191 | + this.page.total = res.total | |
| 192 | + } catch (error) { | |
| 193 | + this.$message.error(this.$t('common.fetchError')) | |
| 194 | + } | |
| 195 | + }, | |
| 196 | + handleSizeChange(size) { | |
| 197 | + this.page.size = size | |
| 198 | + this.listInvoiceApplys() | |
| 199 | + }, | |
| 200 | + handleCurrentChange(current) { | |
| 201 | + this.page.current = current | |
| 202 | + this.listInvoiceApplys() | |
| 203 | + }, | |
| 204 | + swatchState(item) { | |
| 205 | + this.conditions.state = item.state | |
| 206 | + this.listInvoiceApplys() | |
| 207 | + }, | |
| 208 | + _queryInvoiceApplyMethod() { | |
| 209 | + this.page.current = 1 | |
| 210 | + this.listInvoiceApplys() | |
| 211 | + }, | |
| 212 | + _invoiceApply() { | |
| 213 | + this.$router.push('/views/fee/ownerApplyInvoice') | |
| 214 | + }, | |
| 215 | + _openInvoiceApplyDetail(row) { | |
| 216 | + this.$router.push(`/views/fee/invoiceApplyDetail?applyId=${row.applyId}`) | |
| 217 | + }, | |
| 218 | + _openInvoiceAuditModel(row) { | |
| 219 | + this.auditData = { ...row } | |
| 220 | + this.$refs.auditDialog.open() | |
| 221 | + }, | |
| 222 | + async notifyAuditInfo(auditInfo) { | |
| 223 | + try { | |
| 224 | + const params = { | |
| 225 | + ...this.auditData, | |
| 226 | + state: auditInfo.state, | |
| 227 | + remark: auditInfo.remark, | |
| 228 | + communityId: this.communityId | |
| 229 | + } | |
| 230 | + await auditInvoiceApply(params) | |
| 231 | + this.$message.success(this.$t('invoiceApply.auditSuccess')) | |
| 232 | + this.listInvoiceApplys() | |
| 233 | + } catch (error) { | |
| 234 | + this.$message.error(error.message) | |
| 235 | + } | |
| 236 | + }, | |
| 237 | + _openUploadInvoicePhoto(row) { | |
| 238 | + this.$refs.uploadPhotoDialog.open(row) | |
| 239 | + }, | |
| 240 | + _openUserGetInvoice(row) { | |
| 241 | + this.$refs.writeEventDialog.open(row) | |
| 242 | + }, | |
| 243 | + _toOpenInvoicePlugin(row) { | |
| 244 | + const userInfo = this.$store.getters.userInfo | |
| 245 | + this.$router.push({ | |
| 246 | + path: '/plugin', | |
| 247 | + query: { | |
| 248 | + pluginType: 'invoice', | |
| 249 | + orderNo: row.applyId, | |
| 250 | + staffName: userInfo.name, | |
| 251 | + communityId: this.communityId | |
| 252 | + } | |
| 253 | + }) | |
| 254 | + }, | |
| 255 | + _openDeleteInvoiceApplyModel(row) { | |
| 256 | + this.$refs.deleteDialog.open(row) | |
| 257 | + }, | |
| 258 | + hasPlugin(pluginName) { | |
| 259 | + // 实际项目中需要根据业务逻辑实现 | |
| 260 | + console.log(pluginName) | |
| 261 | + return true | |
| 262 | + } | |
| 263 | + } | |
| 264 | +} | |
| 265 | +</script> | |
| 266 | + | |
| 267 | +<style scoped> | |
| 268 | +.border-radius { | |
| 269 | + border-radius: 4px; | |
| 270 | +} | |
| 271 | + | |
| 272 | +.list-group { | |
| 273 | + padding: 0; | |
| 274 | + margin: 0; | |
| 275 | + list-style: none; | |
| 276 | +} | |
| 277 | + | |
| 278 | +.list-group-item { | |
| 279 | + padding: 10px 15px; | |
| 280 | + margin-bottom: -1px; | |
| 281 | + background-color: #fff; | |
| 282 | + border: 1px solid #ddd; | |
| 283 | + cursor: pointer; | |
| 284 | +} | |
| 285 | + | |
| 286 | +.list-group-item:hover, | |
| 287 | +.vc-node-selected { | |
| 288 | + background-color: #f5f7fa; | |
| 289 | + color: #409EFF; | |
| 290 | +} | |
| 291 | + | |
| 292 | +.float-right { | |
| 293 | + float: right; | |
| 294 | +} | |
| 295 | +</style> | |
| 0 | 296 | \ No newline at end of file | ... | ... |
src/views/fee/ownerApplyInvoiceLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + ownerApplyInvoice: { | |
| 4 | + title: 'Invoice Application', | |
| 5 | + invoiceTitle: 'Invoice Title', | |
| 6 | + taxpayerId: 'Taxpayer ID', | |
| 7 | + invoiceType: 'Invoice Type', | |
| 8 | + addressPhone: 'Address & Phone', | |
| 9 | + owner: 'Owner', | |
| 10 | + content: 'Content', | |
| 11 | + personal: 'Personal', | |
| 12 | + enterprise: 'Enterprise', | |
| 13 | + paidFees: 'Paid Fees', | |
| 14 | + accountDeposit: 'Account Deposit', | |
| 15 | + feeName: 'Fee Item', | |
| 16 | + payer: 'Payer', | |
| 17 | + receivablePaid: 'Receivable/Paid', | |
| 18 | + paymentMethod: 'Payment Method', | |
| 19 | + paymentPeriod: 'Payment Period', | |
| 20 | + paymentTime: 'Payment Time', | |
| 21 | + cashier: 'Cashier', | |
| 22 | + status: 'Status', | |
| 23 | + remark: 'Remark', | |
| 24 | + accountName: 'Account Name', | |
| 25 | + accountType: 'Account Type', | |
| 26 | + depositAmount: 'Deposit Amount', | |
| 27 | + depositMethod: 'Deposit Method', | |
| 28 | + totalAmount: 'Total Amount', | |
| 29 | + depositTime: 'Deposit Time', | |
| 30 | + back: 'Back', | |
| 31 | + select: 'Select', | |
| 32 | + submit: 'Submit', | |
| 33 | + required: 'Required', | |
| 34 | + chooseInvoiceTitle: 'Please select invoice title', | |
| 35 | + chooseTaxId: 'Please select taxpayer ID', | |
| 36 | + chooseInvoiceType: 'Please select invoice type', | |
| 37 | + chooseAddressPhone: 'Please enter address and phone', | |
| 38 | + chooseContent: 'Please select content', | |
| 39 | + noFeeSelected: 'No paid fees selected', | |
| 40 | + noDepositSelected: 'No account deposit selected' | |
| 41 | + }, | |
| 42 | + searchOwnerInvoice: { | |
| 43 | + title: 'Select Owner', | |
| 44 | + ownerName: 'Owner Name', | |
| 45 | + invoiceType: 'Invoice Type', | |
| 46 | + invoiceTitle: 'Invoice Title', | |
| 47 | + taxpayerId: 'Taxpayer ID', | |
| 48 | + addressPhone: 'Address & Phone', | |
| 49 | + operation: 'Operation', | |
| 50 | + search: 'Search', | |
| 51 | + placeholderRoom: 'Enter room number (building-unit-room)', | |
| 52 | + placeholderOwner: 'Enter owner name', | |
| 53 | + select: 'Select', | |
| 54 | + personal: 'Personal', | |
| 55 | + company: 'Company' | |
| 56 | + } | |
| 57 | + }, | |
| 58 | + zh: { | |
| 59 | + ownerApplyInvoice: { | |
| 60 | + title: '发票申请', | |
| 61 | + invoiceTitle: '发票抬头', | |
| 62 | + taxpayerId: '纳税人识别号', | |
| 63 | + invoiceType: '发票类型', | |
| 64 | + addressPhone: '地址、电话', | |
| 65 | + owner: '业主', | |
| 66 | + content: '开票内容', | |
| 67 | + personal: '个人', | |
| 68 | + enterprise: '企业', | |
| 69 | + paidFees: '已缴费费用', | |
| 70 | + accountDeposit: '账户预存', | |
| 71 | + feeName: '费用项', | |
| 72 | + payer: '收费对象', | |
| 73 | + receivablePaid: '应收/实收', | |
| 74 | + paymentMethod: '缴费方式', | |
| 75 | + paymentPeriod: '缴费起始段', | |
| 76 | + paymentTime: '缴费时间', | |
| 77 | + cashier: '收银员', | |
| 78 | + status: '状态', | |
| 79 | + remark: '备注', | |
| 80 | + accountName: '账户名称', | |
| 81 | + accountType: '账户类型', | |
| 82 | + depositAmount: '预存金额', | |
| 83 | + depositMethod: '预存方式', | |
| 84 | + totalAmount: '总金额', | |
| 85 | + depositTime: '预存时间', | |
| 86 | + back: '返回', | |
| 87 | + select: '选择', | |
| 88 | + submit: '提交', | |
| 89 | + required: '必填', | |
| 90 | + chooseInvoiceTitle: '请选择发票抬头', | |
| 91 | + chooseTaxId: '请选择纳税人识别号', | |
| 92 | + chooseInvoiceType: '请选择发票类型', | |
| 93 | + chooseAddressPhone: '请输入地址、电话', | |
| 94 | + chooseContent: '请选择开票内容', | |
| 95 | + noFeeSelected: '未选择已缴费费用', | |
| 96 | + noDepositSelected: '未选择账户预存' | |
| 97 | + }, | |
| 98 | + searchOwnerInvoice: { | |
| 99 | + title: '选择业主', | |
| 100 | + ownerName: '业主名称', | |
| 101 | + invoiceType: '发票类型', | |
| 102 | + invoiceTitle: '发票名头', | |
| 103 | + taxpayerId: '纳税人识别号', | |
| 104 | + addressPhone: '地址、电话', | |
| 105 | + operation: '操作', | |
| 106 | + search: '查询', | |
| 107 | + placeholderRoom: '输入房屋编号楼栋-单元-房屋', | |
| 108 | + placeholderOwner: '输入业主名称', | |
| 109 | + select: '选择', | |
| 110 | + personal: '个人', | |
| 111 | + company: '公司' | |
| 112 | + } | |
| 113 | + } | |
| 114 | +} | |
| 0 | 115 | \ No newline at end of file | ... | ... |
src/views/fee/ownerApplyInvoiceList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="owner-apply-invoice-container"> | |
| 3 | + <el-card> | |
| 4 | + <div slot="header" class="clearfix flex justify-between"> | |
| 5 | + <h3>{{ $t('ownerApplyInvoice.title') }}</h3> | |
| 6 | + <div class="header-actions"> | |
| 7 | + <el-button type="primary" size="small" @click="goBack"> | |
| 8 | + {{ $t('ownerApplyInvoice.back') }} | |
| 9 | + </el-button> | |
| 10 | + </div> | |
| 11 | + </div> | |
| 12 | + | |
| 13 | + <el-form ref="form" :model="formData" label-width="150px"> | |
| 14 | + <el-row :gutter="20"> | |
| 15 | + <el-col :span="8"> | |
| 16 | + <el-form-item :label="$t('ownerApplyInvoice.invoiceTitle')" required> | |
| 17 | + <el-input v-model="formData.invoiceName" :placeholder="$t('ownerApplyInvoice.chooseInvoiceTitle')" | |
| 18 | + disabled /> | |
| 19 | + </el-form-item> | |
| 20 | + </el-col> | |
| 21 | + <el-col :span="4" class="text-left"> | |
| 22 | + <el-button type="primary" size="small" style="margin-left: 150px; margin-bottom: 20px" | |
| 23 | + @click="openSelectOwner"> | |
| 24 | + {{ $t('ownerApplyInvoice.select') }} | |
| 25 | + </el-button></el-col> | |
| 26 | + <el-col :span="12"> | |
| 27 | + <el-form-item :label="$t('ownerApplyInvoice.taxpayerId')" required> | |
| 28 | + <el-input v-model="formData.invoiceNum" :placeholder="$t('ownerApplyInvoice.chooseTaxId')" disabled /> | |
| 29 | + </el-form-item> | |
| 30 | + </el-col> | |
| 31 | + </el-row> | |
| 32 | + | |
| 33 | + <el-row :gutter="20"> | |
| 34 | + <el-col :span="12"> | |
| 35 | + <el-form-item :label="$t('ownerApplyInvoice.invoiceType')" required> | |
| 36 | + <el-select v-model="formData.invoiceType" :placeholder="$t('ownerApplyInvoice.chooseInvoiceType')" | |
| 37 | + style="width:100%"> | |
| 38 | + <el-option :label="$t('ownerApplyInvoice.personal')" value="1001" /> | |
| 39 | + <el-option :label="$t('ownerApplyInvoice.enterprise')" value="2002" /> | |
| 40 | + </el-select> | |
| 41 | + </el-form-item> | |
| 42 | + </el-col> | |
| 43 | + <el-col :span="12"> | |
| 44 | + <el-form-item :label="$t('ownerApplyInvoice.addressPhone')" required> | |
| 45 | + <el-input v-model="formData.invoiceAddress" :placeholder="$t('ownerApplyInvoice.chooseAddressPhone')" /> | |
| 46 | + </el-form-item> | |
| 47 | + </el-col> | |
| 48 | + </el-row> | |
| 49 | + | |
| 50 | + <el-row :gutter="20"> | |
| 51 | + <el-col :span="12"> | |
| 52 | + <el-form-item :label="$t('ownerApplyInvoice.owner')" required> | |
| 53 | + <el-input v-model="formData.ownerName" :placeholder="$t('ownerApplyInvoice.chooseContent')" disabled /> | |
| 54 | + </el-form-item> | |
| 55 | + </el-col> | |
| 56 | + <el-col :span="12"> | |
| 57 | + <el-form-item :label="$t('ownerApplyInvoice.content')" required> | |
| 58 | + <el-select v-model="formData.invoiceFlag" :placeholder="$t('ownerApplyInvoice.chooseContent')" | |
| 59 | + style="width:100%" @change="handleContentChange"> | |
| 60 | + <el-option :label="$t('ownerApplyInvoice.paidFees')" value="FEE" /> | |
| 61 | + <el-option :label="$t('ownerApplyInvoice.accountDeposit')" value="ACCT" /> | |
| 62 | + </el-select> | |
| 63 | + </el-form-item> | |
| 64 | + </el-col> | |
| 65 | + </el-row> | |
| 66 | + </el-form> | |
| 67 | + | |
| 68 | + | |
| 69 | + </el-card> | |
| 70 | + | |
| 71 | + <!-- 已缴费费用 --> | |
| 72 | + <el-card v-if="formData.invoiceFlag === 'FEE'" class="mt-20"> | |
| 73 | + <div slot="header" class="flex justify-between"> | |
| 74 | + <h3>{{ $t('ownerApplyInvoice.paidFees') }}</h3> | |
| 75 | + </div> | |
| 76 | + | |
| 77 | + <el-table :data="feeDetails" border style="width: 100%"> | |
| 78 | + <el-table-column type="selection" width="55" align="center" @select-all="handleFeeSelectAll" /> | |
| 79 | + <el-table-column prop="feeName" :label="$t('ownerApplyInvoice.feeName')" align="center" /> | |
| 80 | + <el-table-column prop="payerObjName" :label="$t('ownerApplyInvoice.payer')" align="center" /> | |
| 81 | + <el-table-column :label="$t('ownerApplyInvoice.receivablePaid')" align="center"> | |
| 82 | + <template slot-scope="scope"> | |
| 83 | + {{ scope.row.receivableAmount }}/{{ scope.row.receivedAmount }} | |
| 84 | + </template> | |
| 85 | + </el-table-column> | |
| 86 | + <el-table-column prop="primeRateName" :label="$t('ownerApplyInvoice.paymentMethod')" align="center" /> | |
| 87 | + <el-table-column :label="$t('ownerApplyInvoice.paymentPeriod')" align="center"> | |
| 88 | + <template slot-scope="scope"> | |
| 89 | + {{ formatDate(scope.row.startTime) }}~<br> | |
| 90 | + {{ formatDate(scope.row.endTime) }} | |
| 91 | + </template> | |
| 92 | + </el-table-column> | |
| 93 | + <el-table-column prop="createTime" :label="$t('ownerApplyInvoice.paymentTime')" align="center" /> | |
| 94 | + <el-table-column prop="cashierName" :label="$t('ownerApplyInvoice.cashier')" align="center"> | |
| 95 | + <template slot-scope="scope"> | |
| 96 | + {{ scope.row.cashierName || '-' }} | |
| 97 | + </template> | |
| 98 | + </el-table-column> | |
| 99 | + <el-table-column prop="stateName" :label="$t('ownerApplyInvoice.status')" align="center" /> | |
| 100 | + <el-table-column prop="remark" :label="$t('ownerApplyInvoice.remark')" align="center" /> | |
| 101 | + </el-table> | |
| 102 | + </el-card> | |
| 103 | + | |
| 104 | + <!-- 账户预存 --> | |
| 105 | + <el-card v-if="formData.invoiceFlag === 'ACCT'" class="mt-20"> | |
| 106 | + <div slot="" class="flex justify-between"> | |
| 107 | + <h3>{{ $t('ownerApplyInvoice.accountDeposit') }}</h3> | |
| 108 | + </div> | |
| 109 | + | |
| 110 | + <el-table :data="acctDetails" border style="width: 100%"> | |
| 111 | + <el-table-column type="selection" width="55" align="center" @select-all="handleAcctSelectAll" /> | |
| 112 | + <el-table-column prop="acctName" :label="$t('ownerApplyInvoice.accountName')" align="center" /> | |
| 113 | + <el-table-column prop="acctTypeName" :label="$t('ownerApplyInvoice.accountType')" align="center" /> | |
| 114 | + <el-table-column prop="ownerName" :label="$t('ownerApplyInvoice.owner')" align="center" /> | |
| 115 | + <el-table-column prop="receivedAmount" :label="$t('ownerApplyInvoice.depositAmount')" align="center" /> | |
| 116 | + <el-table-column prop="primeRateName" :label="$t('ownerApplyInvoice.depositMethod')" align="center" /> | |
| 117 | + <el-table-column prop="amount" :label="$t('ownerApplyInvoice.totalAmount')" align="center" /> | |
| 118 | + <el-table-column prop="createTime" :label="$t('ownerApplyInvoice.depositTime')" align="center" /> | |
| 119 | + </el-table> | |
| 120 | + </el-card> | |
| 121 | + | |
| 122 | + <div class="mt-20 text-right"> | |
| 123 | + <el-button type="primary" @click="handleSubmit"> | |
| 124 | + {{ $t('ownerApplyInvoice.submit') }} | |
| 125 | + </el-button> | |
| 126 | + </div> | |
| 127 | + | |
| 128 | + <search-owner-invoice ref="searchOwnerInvoice" :visible.sync="showSearchDialog" @select="handleOwnerSelect" /> | |
| 129 | + </div> | |
| 130 | +</template> | |
| 131 | + | |
| 132 | +<script> | |
| 133 | +import { queryFeeDetail, listAccountReceipt, saveInvoiceApply } from '@/api/fee/ownerApplyInvoiceApi' | |
| 134 | +import SearchOwnerInvoice from '@/components/fee/searchOwnerInvoice' | |
| 135 | +import { formatDate } from '@/utils/dateUtil' | |
| 136 | + | |
| 137 | +export default { | |
| 138 | + name: 'OwnerApplyInvoiceList', | |
| 139 | + components: { | |
| 140 | + SearchOwnerInvoice | |
| 141 | + }, | |
| 142 | + data() { | |
| 143 | + return { | |
| 144 | + showSearchDialog: false, | |
| 145 | + formData: { | |
| 146 | + oiId: '', | |
| 147 | + ownerId: '', | |
| 148 | + ownerName: '', | |
| 149 | + invoiceType: '', | |
| 150 | + invoiceName: '', | |
| 151 | + invoiceAddress: '', | |
| 152 | + invoiceNum: '', | |
| 153 | + detailIds: [], | |
| 154 | + feeDetails: [], | |
| 155 | + invoiceFlag: 'FEE', | |
| 156 | + arIds: [], | |
| 157 | + acctDetails: [] | |
| 158 | + }, | |
| 159 | + feeDetails: [], | |
| 160 | + acctDetails: [] | |
| 161 | + } | |
| 162 | + }, | |
| 163 | + methods: { | |
| 164 | + formatDate, | |
| 165 | + goBack() { | |
| 166 | + this.$router.go(-1) | |
| 167 | + }, | |
| 168 | + openSelectOwner() { | |
| 169 | + this.showSearchDialog = true | |
| 170 | + this.$nextTick(() => { | |
| 171 | + this.$refs.searchOwnerInvoice.open() | |
| 172 | + }) | |
| 173 | + }, | |
| 174 | + handleOwnerSelect(owner) { | |
| 175 | + Object.assign(this.formData, owner) | |
| 176 | + this.formData.detailIds = [] | |
| 177 | + this.formData.arIds = [] | |
| 178 | + | |
| 179 | + if (this.formData.invoiceFlag === 'FEE') { | |
| 180 | + this.loadFeeDetails() | |
| 181 | + } else { | |
| 182 | + this.loadAcctDetails() | |
| 183 | + } | |
| 184 | + }, | |
| 185 | + async loadFeeDetails() { | |
| 186 | + try { | |
| 187 | + const params = { | |
| 188 | + page: 1, | |
| 189 | + row: 50, | |
| 190 | + ownerId: this.formData.ownerId, | |
| 191 | + openInvoice: 'N' | |
| 192 | + } | |
| 193 | + | |
| 194 | + const res = await queryFeeDetail(params) | |
| 195 | + this.feeDetails = res.feeDetails || [] | |
| 196 | + | |
| 197 | + // 默认全选 | |
| 198 | + this.formData.detailIds = this.feeDetails.map(item => item.detailId) | |
| 199 | + } catch (error) { | |
| 200 | + console.error('Failed to load fee details:', error) | |
| 201 | + this.$message.error(this.$t('common.loadFailed')) | |
| 202 | + } | |
| 203 | + }, | |
| 204 | + async loadAcctDetails() { | |
| 205 | + try { | |
| 206 | + const params = { | |
| 207 | + page: 1, | |
| 208 | + row: 50, | |
| 209 | + ownerId: this.formData.ownerId | |
| 210 | + } | |
| 211 | + | |
| 212 | + const res = await listAccountReceipt(params) | |
| 213 | + this.acctDetails = res.data || [] | |
| 214 | + | |
| 215 | + // 默认全选 | |
| 216 | + this.formData.arIds = this.acctDetails.map(item => item.arId) | |
| 217 | + } catch (error) { | |
| 218 | + console.error('Failed to load account details:', error) | |
| 219 | + this.$message.error(this.$t('common.loadFailed')) | |
| 220 | + } | |
| 221 | + }, | |
| 222 | + handleContentChange() { | |
| 223 | + if (!this.formData.ownerId) return | |
| 224 | + | |
| 225 | + this.formData.detailIds = [] | |
| 226 | + this.formData.arIds = [] | |
| 227 | + | |
| 228 | + if (this.formData.invoiceFlag === 'FEE') { | |
| 229 | + this.loadFeeDetails() | |
| 230 | + } else { | |
| 231 | + this.loadAcctDetails() | |
| 232 | + } | |
| 233 | + }, | |
| 234 | + handleFeeSelectAll(selection) { | |
| 235 | + this.formData.detailIds = selection.length | |
| 236 | + ? this.feeDetails.map(item => item.detailId) | |
| 237 | + : [] | |
| 238 | + }, | |
| 239 | + handleAcctSelectAll(selection) { | |
| 240 | + this.formData.arIds = selection.length | |
| 241 | + ? this.acctDetails.map(item => item.arId) | |
| 242 | + : [] | |
| 243 | + }, | |
| 244 | + async handleSubmit() { | |
| 245 | + try { | |
| 246 | + // 验证表单 | |
| 247 | + if (!this.formData.ownerId) { | |
| 248 | + this.$message.warning(this.$t('ownerApplyInvoice.chooseContent')) | |
| 249 | + return | |
| 250 | + } | |
| 251 | + | |
| 252 | + if (this.formData.invoiceFlag === 'FEE' && !this.formData.detailIds.length) { | |
| 253 | + this.$message.warning(this.$t('ownerApplyInvoice.noFeeSelected')) | |
| 254 | + return | |
| 255 | + } | |
| 256 | + | |
| 257 | + if (this.formData.invoiceFlag === 'ACCT' && !this.formData.arIds.length) { | |
| 258 | + this.$message.warning(this.$t('ownerApplyInvoice.noDepositSelected')) | |
| 259 | + return | |
| 260 | + } | |
| 261 | + | |
| 262 | + // 准备提交数据 | |
| 263 | + const submitData = { | |
| 264 | + ...this.formData, | |
| 265 | + detailIds: this.formData.invoiceFlag === 'FEE' ? this.formData.detailIds : [], | |
| 266 | + arIds: this.formData.invoiceFlag === 'ACCT' ? this.formData.arIds : [] | |
| 267 | + } | |
| 268 | + | |
| 269 | + // 调用API | |
| 270 | + await saveInvoiceApply(submitData) | |
| 271 | + this.$message.success(this.$t('common.submitSuccess')) | |
| 272 | + this.goBack() | |
| 273 | + } catch (error) { | |
| 274 | + console.error('Failed to submit invoice application:', error) | |
| 275 | + this.$message.error(error.message || this.$t('common.submitFailed')) | |
| 276 | + } | |
| 277 | + } | |
| 278 | + } | |
| 279 | +} | |
| 280 | +</script> | |
| 281 | + | |
| 282 | +<style scoped> | |
| 283 | +.owner-apply-invoice-container { | |
| 284 | + padding: 20px; | |
| 285 | +} | |
| 286 | + | |
| 287 | +.mt-20 { | |
| 288 | + margin-top: 20px; | |
| 289 | +} | |
| 290 | + | |
| 291 | +.text-right { | |
| 292 | + text-align: right; | |
| 293 | +} | |
| 294 | + | |
| 295 | +.header-actions {} | |
| 296 | +</style> | |
| 0 | 297 | \ No newline at end of file | ... | ... |
src/views/fee/ownerInvoiceLang.js
0 → 100644
| 1 | +export const messages = { | |
| 2 | + en: { | |
| 3 | + searchCondition: 'Search Conditions', | |
| 4 | + ownerNamePlaceholder: 'Enter owner name', | |
| 5 | + invoiceTypePlaceholder: 'Select invoice type', | |
| 6 | + personal: 'Personal', | |
| 7 | + enterprise: 'Enterprise', | |
| 8 | + invoiceHeaderPlaceholder: 'Enter invoice header', | |
| 9 | + search: 'Search', | |
| 10 | + invoiceHeader: 'Invoice Header', | |
| 11 | + add: 'Add', | |
| 12 | + serialNumber: 'Serial Number', | |
| 13 | + ownerName: 'Owner Name', | |
| 14 | + invoiceType: 'Invoice Type', | |
| 15 | + taxpayerId: 'Taxpayer ID', | |
| 16 | + address: 'Address', | |
| 17 | + phone: 'Phone', | |
| 18 | + bankAccount: 'Bank Account', | |
| 19 | + remark: 'Remark', | |
| 20 | + operation: 'Operation', | |
| 21 | + modify: 'Modify', | |
| 22 | + delete: 'Delete', | |
| 23 | + confirmDeleteTitle: 'Confirm Deletion', | |
| 24 | + confirmDeleteContent: 'Are you sure to delete this invoice header?', | |
| 25 | + cancel: 'Cancel', | |
| 26 | + confirmDelete: 'Confirm Delete', | |
| 27 | + editTitle: 'Edit', | |
| 28 | + requiredInvoiceType: 'Invoice type is required', | |
| 29 | + requiredInvoiceHeader: 'Invoice header is required', | |
| 30 | + requiredTaxpayerId: 'Taxpayer ID is required', | |
| 31 | + requiredAddress: 'Address is required', | |
| 32 | + requiredPhone: 'Phone is required', | |
| 33 | + requiredBankAccount: 'Bank account is required', | |
| 34 | + optionalRemark: 'Remark (optional)', | |
| 35 | + save: 'Save', | |
| 36 | + addOwnerInvoice: { | |
| 37 | + title: 'Add Invoice', | |
| 38 | + back: 'Back', | |
| 39 | + owner: 'Owner', | |
| 40 | + selectOwner: 'Select Owner', | |
| 41 | + invoiceType: 'Invoice Type', | |
| 42 | + invoiceTitle: 'Invoice Title', | |
| 43 | + taxNumber: 'Taxpayer ID', | |
| 44 | + address: 'Address', | |
| 45 | + phone: 'Phone', | |
| 46 | + bankAccount: 'Bank Account', | |
| 47 | + remarks: 'Remarks', | |
| 48 | + save: 'Save', | |
| 49 | + required: 'Required', | |
| 50 | + personal: 'Personal', | |
| 51 | + enterprise: 'Enterprise', | |
| 52 | + placeholder: { | |
| 53 | + owner: 'Please select owner', | |
| 54 | + invoiceType: 'Please select invoice type', | |
| 55 | + invoiceTitle: 'Please enter invoice title', | |
| 56 | + taxNumber: 'Please enter taxpayer ID', | |
| 57 | + address: 'Please enter address', | |
| 58 | + phone: 'Please enter phone number', | |
| 59 | + bankAccount: 'Please enter bank account', | |
| 60 | + remarks: 'Optional remarks' | |
| 61 | + }, | |
| 62 | + validation: { | |
| 63 | + ownerRequired: 'Owner is required', | |
| 64 | + typeRequired: 'Invoice type is required', | |
| 65 | + titleRequired: 'Invoice title is required', | |
| 66 | + taxNumberRequired: 'Taxpayer ID is required', | |
| 67 | + addressRequired: 'Address is required', | |
| 68 | + phoneRequired: 'Phone is required', | |
| 69 | + bankAccountRequired: 'Bank account is required' | |
| 70 | + } | |
| 71 | + }, | |
| 72 | + }, | |
| 73 | + zh: { | |
| 74 | + searchCondition: '查询条件', | |
| 75 | + ownerNamePlaceholder: '请输入业主名称', | |
| 76 | + invoiceTypePlaceholder: '请选择发票类型', | |
| 77 | + personal: '个人', | |
| 78 | + enterprise: '企业', | |
| 79 | + invoiceHeaderPlaceholder: '请输入发票名头', | |
| 80 | + search: '查询', | |
| 81 | + invoiceHeader: '发票抬头', | |
| 82 | + add: '添加', | |
| 83 | + serialNumber: '编号', | |
| 84 | + ownerName: '业主名称', | |
| 85 | + invoiceType: '发票类型', | |
| 86 | + taxpayerId: '纳税人识别号', | |
| 87 | + address: '地址', | |
| 88 | + phone: '电话', | |
| 89 | + bankAccount: '开户行及账号', | |
| 90 | + remark: '备注', | |
| 91 | + operation: '操作', | |
| 92 | + modify: '修改', | |
| 93 | + delete: '删除', | |
| 94 | + confirmDeleteTitle: '请确认您的操作', | |
| 95 | + confirmDeleteContent: '确定删除发票抬头', | |
| 96 | + cancel: '点错了', | |
| 97 | + confirmDelete: '确认删除', | |
| 98 | + editTitle: '修改', | |
| 99 | + requiredInvoiceType: '必填,请选择发票类型', | |
| 100 | + requiredInvoiceHeader: '必填,请填写发票名头', | |
| 101 | + requiredTaxpayerId: '必填,请填写纳税人识别号', | |
| 102 | + requiredAddress: '必填,请填写地址', | |
| 103 | + requiredPhone: '必填,请填写电话', | |
| 104 | + requiredBankAccount: '必填,请填写开户行及账号', | |
| 105 | + optionalRemark: '选填,请填写备注', | |
| 106 | + save: '保存', | |
| 107 | + addOwnerInvoice: { | |
| 108 | + title: '添加发票抬头', | |
| 109 | + back: '返回', | |
| 110 | + owner: '业主', | |
| 111 | + selectOwner: '选择业主', | |
| 112 | + invoiceType: '发票类型', | |
| 113 | + invoiceTitle: '发票名头', | |
| 114 | + taxNumber: '纳税人识别号', | |
| 115 | + address: '地址', | |
| 116 | + phone: '电话', | |
| 117 | + bankAccount: '开户行及账号', | |
| 118 | + remarks: '备注', | |
| 119 | + save: '保存', | |
| 120 | + required: '必填', | |
| 121 | + personal: '个人', | |
| 122 | + enterprise: '企业', | |
| 123 | + placeholder: { | |
| 124 | + owner: '请选择业主', | |
| 125 | + invoiceType: '请选择发票类型', | |
| 126 | + invoiceTitle: '请填写发票名头', | |
| 127 | + taxNumber: '请填写纳税人识别号', | |
| 128 | + address: '请填写地址', | |
| 129 | + phone: '请填写电话', | |
| 130 | + bankAccount: '请填写开户行及账号', | |
| 131 | + remarks: '选填备注' | |
| 132 | + }, | |
| 133 | + validation: { | |
| 134 | + ownerRequired: '业主不能为空', | |
| 135 | + typeRequired: '发票类型不能为空', | |
| 136 | + titleRequired: '发票名头不能为空', | |
| 137 | + taxNumberRequired: '纳税人识别号不能为空', | |
| 138 | + addressRequired: '地址不能为空', | |
| 139 | + phoneRequired: '电话不能为空', | |
| 140 | + bankAccountRequired: '开户行及账号不能为空' | |
| 141 | + } | |
| 142 | + }, | |
| 143 | + } | |
| 144 | +} | |
| 0 | 145 | \ No newline at end of file | ... | ... |
src/views/fee/ownerInvoiceList.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div class="owner-invoice-container"> | |
| 3 | + <!-- 查询条件 --> | |
| 4 | + <el-card class="search-card"> | |
| 5 | + <div slot="header" class="clearfix"> | |
| 6 | + <span>{{ $t('searchCondition') }}</span> | |
| 7 | + </div> | |
| 8 | + | |
| 9 | + <el-row :gutter="20"> | |
| 10 | + <el-col :span="6"> | |
| 11 | + <el-input v-model="searchForm.ownerName" :placeholder="$t('ownerNamePlaceholder')" /> | |
| 12 | + </el-col> | |
| 13 | + | |
| 14 | + <el-col :span="6"> | |
| 15 | + <el-select v-model="searchForm.invoiceType" :placeholder="$t('invoiceTypePlaceholder')" style="width: 100%"> | |
| 16 | + <el-option value="" :label="$t('invoiceTypePlaceholder')" /> | |
| 17 | + <el-option value="1001" :label="$t('personal')" /> | |
| 18 | + <el-option value="2002" :label="$t('enterprise')" /> | |
| 19 | + </el-select> | |
| 20 | + </el-col> | |
| 21 | + | |
| 22 | + <el-col :span="6"> | |
| 23 | + <el-input v-model="searchForm.invoiceName" :placeholder="$t('invoiceHeaderPlaceholder')" /> | |
| 24 | + </el-col> | |
| 25 | + | |
| 26 | + <el-col :span="6"> | |
| 27 | + <el-button type="primary" @click="fetchData">{{ $t('search') }}</el-button> | |
| 28 | + </el-col> | |
| 29 | + </el-row> | |
| 30 | + </el-card> | |
| 31 | + | |
| 32 | + <!-- 发票抬头列表 --> | |
| 33 | + <el-card class="list-card"> | |
| 34 | + <div slot="header" class="clearfix"> | |
| 35 | + <span>{{ $t('invoiceHeader') }}</span> | |
| 36 | + <el-button type="primary" size="small" style="float: right" @click="handleAdd"> | |
| 37 | + {{ $t('add') }} | |
| 38 | + </el-button> | |
| 39 | + </div> | |
| 40 | + | |
| 41 | + <el-table :data="tableData" border style="width: 100%" v-loading="loading"> | |
| 42 | + <el-table-column prop="oiId" :label="$t('serialNumber')" align="center" min-width="80" /> | |
| 43 | + | |
| 44 | + <el-table-column prop="ownerName" :label="$t('ownerName')" align="center" min-width="120" /> | |
| 45 | + | |
| 46 | + <el-table-column prop="invoiceType" :label="$t('invoiceType')" align="center" min-width="100"> | |
| 47 | + <template slot-scope="scope"> | |
| 48 | + {{ scope.row.invoiceType === '1001' ? $t('personal') : $t('enterprise') }} | |
| 49 | + </template> | |
| 50 | + </el-table-column> | |
| 51 | + | |
| 52 | + <el-table-column prop="invoiceName" :label="$t('invoiceHeader')" align="center" min-width="150" /> | |
| 53 | + | |
| 54 | + <el-table-column prop="invoiceNum" :label="$t('taxpayerId')" align="center" min-width="150" /> | |
| 55 | + | |
| 56 | + <el-table-column prop="invoiceAddress" :label="$t('address')" align="center" min-width="150" /> | |
| 57 | + | |
| 58 | + <el-table-column prop="invoiceLink" :label="$t('phone')" align="center" min-width="120" /> | |
| 59 | + | |
| 60 | + <el-table-column prop="invoiceAccount" :label="$t('bankAccount')" align="center" min-width="200" /> | |
| 61 | + | |
| 62 | + <el-table-column prop="remark" :label="$t('remark')" align="center" min-width="150" /> | |
| 63 | + | |
| 64 | + <el-table-column :label="$t('operation')" align="center" fixed="right" width="180"> | |
| 65 | + <template slot-scope="scope"> | |
| 66 | + <el-button size="mini" type="primary" @click="handleEdit(scope.row)"> | |
| 67 | + {{ $t('modify') }} | |
| 68 | + </el-button> | |
| 69 | + <el-button size="mini" type="danger" @click="handleDelete(scope.row)"> | |
| 70 | + {{ $t('delete') }} | |
| 71 | + </el-button> | |
| 72 | + </template> | |
| 73 | + </el-table-column> | |
| 74 | + </el-table> | |
| 75 | + | |
| 76 | + <!-- 分页 --> | |
| 77 | + <el-pagination background layout="total, sizes, prev, pager, next" :current-page="pagination.current" | |
| 78 | + :page-size="pagination.size" :total="pagination.total" @size-change="handleSizeChange" | |
| 79 | + @current-change="handlePageChange" style="margin-top: 20px; text-align: right;" /> | |
| 80 | + </el-card> | |
| 81 | + | |
| 82 | + <!-- 编辑组件 --> | |
| 83 | + <edit-owner-invoice ref="editDialog" @success="fetchData" /> | |
| 84 | + | |
| 85 | + <!-- 删除组件 --> | |
| 86 | + <delete-owner-invoice ref="deleteDialog" @success="fetchData" /> | |
| 87 | + </div> | |
| 88 | +</template> | |
| 89 | + | |
| 90 | +<script> | |
| 91 | +import { listOwnerInvoice } from '@/api/fee/ownerInvoiceApi' | |
| 92 | +import EditOwnerInvoice from '@/components/fee/editOwnerInvoice' | |
| 93 | +import DeleteOwnerInvoice from '@/components/fee/deleteOwnerInvoice' | |
| 94 | + | |
| 95 | +export default { | |
| 96 | + name: 'OwnerInvoiceList', | |
| 97 | + components: { | |
| 98 | + EditOwnerInvoice, | |
| 99 | + DeleteOwnerInvoice | |
| 100 | + }, | |
| 101 | + data() { | |
| 102 | + return { | |
| 103 | + loading: false, | |
| 104 | + searchForm: { | |
| 105 | + ownerName: '', | |
| 106 | + invoiceType: '', | |
| 107 | + invoiceName: '' | |
| 108 | + }, | |
| 109 | + tableData: [], | |
| 110 | + pagination: { | |
| 111 | + current: 1, | |
| 112 | + size: 10, | |
| 113 | + total: 0 | |
| 114 | + } | |
| 115 | + } | |
| 116 | + }, | |
| 117 | + created() { | |
| 118 | + this.fetchData() | |
| 119 | + }, | |
| 120 | + methods: { | |
| 121 | + async fetchData() { | |
| 122 | + this.loading = true | |
| 123 | + try { | |
| 124 | + const params = { | |
| 125 | + ...this.searchForm, | |
| 126 | + page: this.pagination.current, | |
| 127 | + row: this.pagination.size | |
| 128 | + } | |
| 129 | + | |
| 130 | + const response = await listOwnerInvoice(params) | |
| 131 | + this.tableData = response.data | |
| 132 | + this.pagination.total = response.total | |
| 133 | + } catch (error) { | |
| 134 | + this.$message.error(error.message || this.$t('common.fetchError')) | |
| 135 | + } finally { | |
| 136 | + this.loading = false | |
| 137 | + } | |
| 138 | + }, | |
| 139 | + | |
| 140 | + handleAdd() { | |
| 141 | + this.$router.push('/views/fee/addOwnerInvoice') | |
| 142 | + }, | |
| 143 | + | |
| 144 | + handleEdit(row) { | |
| 145 | + this.$refs.editDialog.open({ ...row }) | |
| 146 | + }, | |
| 147 | + | |
| 148 | + handleDelete(row) { | |
| 149 | + this.$refs.deleteDialog.open(row) | |
| 150 | + }, | |
| 151 | + | |
| 152 | + handlePageChange(page) { | |
| 153 | + this.pagination.current = page | |
| 154 | + this.fetchData() | |
| 155 | + }, | |
| 156 | + | |
| 157 | + handleSizeChange(size) { | |
| 158 | + this.pagination.size = size | |
| 159 | + this.fetchData() | |
| 160 | + } | |
| 161 | + } | |
| 162 | +} | |
| 163 | +</script> | |
| 164 | + | |
| 165 | +<style lang="scss" scoped> | |
| 166 | +.owner-invoice-container { | |
| 167 | + padding: 20px; | |
| 168 | + | |
| 169 | + .search-card, | |
| 170 | + .list-card { | |
| 171 | + margin-bottom: 20px; | |
| 172 | + } | |
| 173 | + | |
| 174 | + .clearfix { | |
| 175 | + display: flex; | |
| 176 | + justify-content: space-between; | |
| 177 | + align-items: center; | |
| 178 | + } | |
| 179 | +} | |
| 180 | +</style> | |
| 0 | 181 | \ No newline at end of file | ... | ... |