Merge branch 'zqy-mst' of http://1.14.121.39:8430/gitadmin/eden-web into zqy-mst
This commit is contained in:
commit
f2b1115bd9
@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"mammoth": "^1.9.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
|
@ -50,7 +50,10 @@
|
||||
"vue-router": "3.4.9",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "3.6.0",
|
||||
"xlsx": "^0.18.5"
|
||||
"xlsx": "^0.18.5",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"mammoth": "^1.9.0",
|
||||
"qrcode.vue": "^3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "4.4.6",
|
||||
|
@ -416,7 +416,7 @@ export function uploadBillAttachment(billId, file) {
|
||||
formData.append('billId', billId)
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: '/bill/attachment/upload',
|
||||
url: '/bill/upload-attachment',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
@ -425,10 +425,11 @@ export function uploadBillAttachment(billId, file) {
|
||||
})
|
||||
}
|
||||
|
||||
// 账单附件删除
|
||||
export function deleteBillAttachment(attachmentId) {
|
||||
return request({
|
||||
url: `/bill/attachment/${attachmentId}`,
|
||||
method: 'delete'
|
||||
url: `/bill/attachment/delete/${attachmentId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@ -446,4 +447,267 @@ export function exportBillList(data) {
|
||||
data,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 收支流水相关接口
|
||||
export function getTransactionList(params) {
|
||||
return request({
|
||||
url: '/finance/transaction/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getTransactionDetail(id) {
|
||||
return request({
|
||||
url: `/finance/transaction/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addTransaction(data) {
|
||||
return request({
|
||||
url: '/finance/transaction',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateTransaction(data) {
|
||||
return request({
|
||||
url: '/finance/transaction',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function exportTransactionList(params) {
|
||||
return request({
|
||||
url: '/finance/transaction/export',
|
||||
method: 'get',
|
||||
params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function getTransactionAttachments(transactionId) {
|
||||
return request({
|
||||
url: `/finance/transaction/${transactionId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function uploadTransactionAttachment(transactionId, file) {
|
||||
const formData = new FormData()
|
||||
formData.append('transactionId', transactionId)
|
||||
formData.append('userId', localStorage.getItem('userId') || '')
|
||||
formData.append('userName', localStorage.getItem('userName') || '')
|
||||
formData.append('file', file)
|
||||
|
||||
return request({
|
||||
url: '/finance/transaction/attachment',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteTransactionAttachment(attachmentId) {
|
||||
return request({
|
||||
url: `/finance/transaction/attachment/file/${attachmentId}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function previewAttachment(attachmentId) {
|
||||
return request({
|
||||
url: `/finance/transaction/attachment/preview/file/${attachmentId}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function previewAttachmentByFileId(fileId) {
|
||||
return request({
|
||||
url: `/finance/transaction/attachment/preview/file/${fileId}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function downloadAttachment(fileId, fileName) {
|
||||
return request({
|
||||
url: `/finance/transaction/attachment/download/${fileId}`,
|
||||
method: 'get',
|
||||
params: { fileName },
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteAttachmentByFileId(fileId) {
|
||||
return request({
|
||||
url: `/finance/transaction/attachment/file/${fileId}`,
|
||||
method: 'delete',
|
||||
params: {
|
||||
userId: localStorage.getItem('userId') || ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function addTransactionOperation(data) {
|
||||
return request({
|
||||
url: '/finance/transaction/operation',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getTransactionOperationLogs(transactionId, query) {
|
||||
return request({
|
||||
url: `/finance/transaction/${transactionId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取所有收支账户
|
||||
export function getAllFinanceAccounts() {
|
||||
return request({
|
||||
url: '/finance/account/list',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 账单调整相关接口
|
||||
|
||||
// 添加账单调整(按金额或按比例)
|
||||
export function addBillAdjustment(data) {
|
||||
return request({
|
||||
url: '/v1/bill-adjustments',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 作废账单调整
|
||||
export function voidBillAdjustment(data) {
|
||||
return request({
|
||||
url: '/v1/bill-adjustments/void',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 分页查询账单调整记录
|
||||
export function getBillAdjustmentList(params) {
|
||||
return request({
|
||||
url: '/v1/bill-adjustments',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取账单调整详情
|
||||
export function getBillAdjustmentDetail(id) {
|
||||
return request({
|
||||
url: `/v1/bill-adjustments/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 上传账单调整附件
|
||||
export function uploadBillAdjustmentAttachment(id, file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: `/v1/bill-adjustments/${id}/attachments`,
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除账单调整附件
|
||||
export function deleteBillAdjustmentAttachment(attachmentId) {
|
||||
return request({
|
||||
url: `/v1/bill-adjustments/attachments/${attachmentId}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取账单明细
|
||||
export function getBillDetailById(detailId) {
|
||||
return request({
|
||||
url: `/v1/bill-details/${detailId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取账单调整附件列表
|
||||
export function getBillAdjustmentAttachmentList(adjustmentId) {
|
||||
return request({
|
||||
url: `/v1/bill-adjustments/attachments/view/${adjustmentId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取账单操作记录
|
||||
export function getBillOperationRecords(billId, params) {
|
||||
return request({
|
||||
url: `/v1/operation-records/list/${billId}`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 账单支付相关接口
|
||||
// 提交账单支付
|
||||
export function submitBillPayment(data) {
|
||||
return request({
|
||||
url: '/v1/bill-payments',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 分页查询支付记录
|
||||
export function getBillPaymentRecords(params) {
|
||||
return request({
|
||||
url: '/v1/bill-payments',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取支付详情
|
||||
export function getBillPaymentDetail(id) {
|
||||
return request({
|
||||
url: `/v1/bill-payments/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 上传支付附件
|
||||
export function uploadBillPaymentAttachment(id, file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: `/v1/bill-payments/${id}/attachments`,
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 删除支付附件
|
||||
export function deleteBillPaymentAttachment(attachmentId) {
|
||||
return request({
|
||||
url: `/v1/bill-payments/attachments/${attachmentId}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
136
pc/src/components/RegionSelector.vue
Normal file
136
pc/src/components/RegionSelector.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<el-cascader
|
||||
v-model="selectedRegion"
|
||||
:options="regionOptions"
|
||||
:props="{ expandTrigger: 'hover', value: 'value', label: 'label' }"
|
||||
:placeholder="placeholder"
|
||||
filterable
|
||||
clearable
|
||||
@change="handleChange"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { regionData, pcaTextArr } from 'element-china-area-data'
|
||||
|
||||
export default {
|
||||
name: 'RegionSelector',
|
||||
props: {
|
||||
value: {
|
||||
type: [Array, String],
|
||||
default: () => []
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择省/市/区'
|
||||
},
|
||||
// 是否使用纯文本数据
|
||||
useTextData: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
regionOptions: this.useTextData ? pcaTextArr : regionData,
|
||||
selectedRegion: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
// 处理传入的值,适配组件
|
||||
if (typeof val === 'string') {
|
||||
// 如果是字符串,按空格分割为数组
|
||||
const parts = val.split(' ').filter(item => item);
|
||||
|
||||
if (parts.length > 0) {
|
||||
if (this.useTextData) {
|
||||
// 如果使用纯文本数据,直接设置
|
||||
this.selectedRegion = parts;
|
||||
} else {
|
||||
// 如果使用编码数据,需要转换成编码
|
||||
this.convertTextToCode(parts);
|
||||
}
|
||||
} else {
|
||||
this.selectedRegion = [];
|
||||
}
|
||||
} else if (Array.isArray(val)) {
|
||||
// 已经是数组,直接使用
|
||||
this.selectedRegion = val;
|
||||
} else {
|
||||
this.selectedRegion = [];
|
||||
}
|
||||
} else {
|
||||
this.selectedRegion = [];
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 将文本转换为区域代码
|
||||
convertTextToCode(textArray) {
|
||||
// 由于没有TextToCode对象,我们需要手动查找
|
||||
const findValueByLabel = (options, label, level = 0) => {
|
||||
for (const option of options) {
|
||||
if (option.label === label) {
|
||||
return level === textArray.length - 1 ? option.value :
|
||||
findValueByLabel(option.children || [], textArray[level + 1], level + 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const value = findValueByLabel(this.regionOptions, textArray[0], 0);
|
||||
if (value) {
|
||||
this.selectedRegion = value.split(',');
|
||||
} else {
|
||||
this.selectedRegion = [];
|
||||
}
|
||||
},
|
||||
|
||||
handleChange(value) {
|
||||
|
||||
// 选择值改变时,转换为可读字符串并发送事件
|
||||
if (value && value.length > 0) {
|
||||
const labels = this.getSelectedLabels(value);
|
||||
const regionText = labels.join(' ');
|
||||
this.$emit('input', regionText);
|
||||
this.$emit('change', regionText, value, labels);
|
||||
|
||||
} else {
|
||||
this.$emit('input', '');
|
||||
this.$emit('change', '', [], []);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getSelectedLabels(codes) {
|
||||
// 根据选中的代码值获取对应的文本标签
|
||||
const labels = [];
|
||||
let options = this.regionOptions;
|
||||
|
||||
for (let i = 0; i < codes.length; i++) {
|
||||
const code = codes[i];
|
||||
const option = options.find(item => item.value === code);
|
||||
|
||||
if (option) {
|
||||
labels.push(option.label);
|
||||
options = option.children || [];
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -30,6 +30,12 @@ export default {
|
||||
component: () => import('@/views/finance/billList/index.vue'),
|
||||
name: 'BillList',
|
||||
meta: { title: '所有账单', icon: 'el-icon-notebook-2' }
|
||||
},
|
||||
{
|
||||
path: 'transaction',
|
||||
component: () => import('@/views/finance/transaction/index.vue'),
|
||||
name: 'Transaction',
|
||||
meta: { title: '收支流水', icon: 'el-icon-money' }
|
||||
}
|
||||
]
|
||||
}
|
@ -5,8 +5,8 @@
|
||||
<el-form ref="chargeModeForm" :model="billForm" :rules="chargeModeRules" label-width="120px">
|
||||
<el-form-item label="含税规则" prop="taxInclusiveRule" required>
|
||||
<el-radio-group v-model="billForm.taxInclusiveRule">
|
||||
<el-radio label="含税">含税</el-radio>
|
||||
<el-radio label="不含税">不含税</el-radio>
|
||||
<el-radio label="1" value="1">含税</el-radio>
|
||||
<el-radio label="2" value="2">不含税</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="税率(%)" prop="taxRate" required>
|
||||
@ -14,18 +14,18 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="特殊账单类型" prop="specialBillType" required>
|
||||
<el-radio-group v-model="billForm.specialBillType">
|
||||
<el-radio label="正常">正常</el-radio>
|
||||
<el-radio label="罚金">罚金</el-radio>
|
||||
<el-radio label="1" value="1">正常</el-radio>
|
||||
<el-radio label="2" value="2">罚金</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="滞纳金起算天数" prop="lateFeeStartDays">
|
||||
<el-input-number v-model="billForm.lateFeeStartDays" :min="0" :precision="0" style="width: 200px"></el-input-number>
|
||||
<el-form-item label="滞纳金起算天数" prop="ovdueStartDays">
|
||||
<el-input-number v-model="billForm.ovdueStartDays" :min="0" :precision="0" style="width: 200px"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="滞纳金比例(%/天)" prop="lateFeeRate">
|
||||
<el-input-number v-model="billForm.lateFeeRate" :min="0" :max="100" :precision="10" style="width: 200px"></el-input-number>
|
||||
<el-form-item label="滞纳金比例(%/天)" prop="ovdueIntRate">
|
||||
<el-input-number v-model="billForm.ovdueIntRate" :min="0" :max="100" :precision="10" style="width: 200px"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="滞纳金上限(%)" prop="lateFeeLimit">
|
||||
<el-input-number v-model="billForm.lateFeeLimit" :min="0" :max="100" :precision="10" style="width: 200px"></el-input-number>
|
||||
<el-form-item label="滞纳金上限(%)" prop="ovdueLimitRate">
|
||||
<el-input-number v-model="billForm.ovdueLimitRate" :min="0" :max="100" :precision="10" style="width: 200px"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
@ -64,8 +64,8 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="付款方" prop="payeeId" required>
|
||||
<el-select v-model="billForm.payeeId" placeholder="请选择付款方" filterable remote clearable
|
||||
<el-form-item label="付款方" prop="paysdId" required>
|
||||
<el-select v-model="billForm.paysdId" placeholder="请选择付款方" filterable remote clearable
|
||||
:remote-method="searchPayees" @change="handlePayeeChange" style="width: 400px">
|
||||
<el-option v-for="item in payeeOptions" :key="item.id"
|
||||
:label="item.name" :value="item.id">
|
||||
@ -75,12 +75,12 @@
|
||||
<el-form-item label="币种" prop="currCode" required>
|
||||
<el-input v-model="billForm.currCode" disabled style="width: 400px"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="应收金额" prop="receivableAmount" required>
|
||||
<el-input-number v-model="billForm.receivableAmount" :min="0" :precision="2" style="width: 400px"></el-input-number>
|
||||
<el-form-item label="应收金额" prop="accigRcvAmt" required>
|
||||
<el-input-number v-model="billForm.accigRcvAmt" :min="0" :precision="2" style="width: 400px"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="应收日期" prop="receivableDate" required>
|
||||
<el-form-item label="应收日期" prop="pybDt" required>
|
||||
<el-date-picker
|
||||
v-model="billForm.receivableDate"
|
||||
v-model="billForm.pybDt"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
@ -139,18 +139,39 @@
|
||||
<el-table-column label="操作" width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="previewFile(scope.row)">预览</el-button>
|
||||
<el-button size="mini" type="text" @click="downloadFile(scope.row)">下载</el-button>
|
||||
<el-button size="mini" type="text" class="delete-btn" @click="deleteFile(scope.$index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 文件预览对话框 -->
|
||||
<el-dialog title="附件预览" :visible.sync="previewDialogVisible" width="800px" append-to-body>
|
||||
<div class="preview-container" v-loading="previewLoading">
|
||||
<div v-if="previewUrl && isPdf" class="preview-iframe">
|
||||
<iframe :src="previewUrl" width="100%" height="500px" frameborder="0"></iframe>
|
||||
</div>
|
||||
<div v-else-if="previewUrl && isImage" class="preview-image">
|
||||
<img :src="previewUrl" style="max-width: 100%;" />
|
||||
</div>
|
||||
<div v-else-if="!previewLoading" class="preview-error">
|
||||
<i class="el-icon-warning"></i>
|
||||
<p>预览加载失败,请尝试下载后查看</p>
|
||||
<div class="preview-actions">
|
||||
<el-button type="primary" @click="downloadCurrentPreview">下载文件</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="previewDialogVisible = false">关 闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFeeTypeTree } from '@/api/finance'
|
||||
import { getFeeTypeTree, uploadBillAttachment, addBill } from '@/api/finance'
|
||||
|
||||
export default {
|
||||
name: 'AddBill',
|
||||
@ -167,30 +188,28 @@ export default {
|
||||
billForm: {
|
||||
contractId: '',
|
||||
contractNumber: '',
|
||||
payeeId: '',
|
||||
payeeName: '',
|
||||
paysdId: '',
|
||||
paysdName: '',
|
||||
payeeContact: '',
|
||||
feeCategoryId: '',
|
||||
feeTypeId: '',
|
||||
feeTypeName: '',
|
||||
feTpName: '',
|
||||
currCode: '156', // 默认人民币
|
||||
billingStartDate: '',
|
||||
billingEndDate: '',
|
||||
receivableAmount: 0,
|
||||
price: 0,
|
||||
priceU: '元/月',
|
||||
taxInclusiveRule: '含税',
|
||||
chggBgnDt: '',
|
||||
chggEndDt: '',
|
||||
accigRcvAmt: 0,
|
||||
taxInclusiveRule: '1',
|
||||
taxRate: 0,
|
||||
receivableDate: '',
|
||||
specialBillType: '正常',
|
||||
lateFeeStartDays: 0,
|
||||
lateFeeRate: 0,
|
||||
lateFeeLimit: 0,
|
||||
pybDt: '',
|
||||
specialBillType: '1',
|
||||
ovdueStartDays: 0,
|
||||
ovdueIntRate: 0,
|
||||
ovdueLimitRate: 0,
|
||||
companyId: '',
|
||||
companyName: '',
|
||||
corNm: '',
|
||||
accountId: '',
|
||||
billRemark: '',
|
||||
roomInfoList: []
|
||||
roomIds: []
|
||||
},
|
||||
// 表单验证规则
|
||||
chargeModeRules: {
|
||||
@ -205,7 +224,7 @@ export default {
|
||||
]
|
||||
},
|
||||
billInfoRules: {
|
||||
payeeId: [
|
||||
paysdId: [
|
||||
{ required: true, message: '请选择付款方', trigger: 'change' }
|
||||
],
|
||||
companyId: [
|
||||
@ -214,10 +233,10 @@ export default {
|
||||
accountId: [
|
||||
{ required: true, message: '请选择收支账户', trigger: 'change' }
|
||||
],
|
||||
receivableAmount: [
|
||||
accigRcvAmt: [
|
||||
{ required: true, message: '请输入应收金额', trigger: 'blur' }
|
||||
],
|
||||
receivableDate: [
|
||||
pybDt: [
|
||||
{ required: true, message: '请选择应收日期', trigger: 'change' }
|
||||
]
|
||||
},
|
||||
@ -244,7 +263,16 @@ export default {
|
||||
selectedRoomIds: [],
|
||||
// 附件上传相关
|
||||
fileList: [],
|
||||
attachmentLoading: false
|
||||
attachmentLoading: false,
|
||||
|
||||
// 预览相关
|
||||
previewDialogVisible: false,
|
||||
previewLoading: false,
|
||||
previewUrl: '',
|
||||
previewBlob: null,
|
||||
currentPreviewName: '',
|
||||
isPdf: false,
|
||||
isImage: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -280,10 +308,10 @@ export default {
|
||||
children = category.financeFeeTypes.map(feeType => {
|
||||
return {
|
||||
id: feeType.id || Math.random().toString(36).substr(2, 9),
|
||||
label: feeType.feeTypeName || '未命名费用',
|
||||
label: feeType.feTpName || '未命名费用',
|
||||
categoryId: categoryId,
|
||||
// 存储原始数据以便后续使用
|
||||
feeTypeName: feeType.feeTypeName || '未命名费用',
|
||||
feTpName: feeType.feTpName || '未命名费用',
|
||||
// 确保没有更多的子节点
|
||||
children: null
|
||||
}
|
||||
@ -302,7 +330,7 @@ export default {
|
||||
getCompanyOptions() {
|
||||
// 模拟数据,实际应调用API
|
||||
this.companyOptions = [
|
||||
{ id: 'C001', name: '智慧园区物业管理有限公司' }
|
||||
{ id: 123, name: '智慧园区物业管理有限公司' }
|
||||
]
|
||||
},
|
||||
// 获取收支账户选项
|
||||
@ -318,8 +346,8 @@ export default {
|
||||
if (query) {
|
||||
// 实际应调用API
|
||||
this.contractOptions = [
|
||||
{ contractId: 'CT001', contractNumber: 'HT2023001', customerName: '张三' },
|
||||
{ contractId: 'CT002', contractNumber: 'HT2023002', customerName: '李四' }
|
||||
{ contractId: 11, contractNumber: 'HT2023001', customerName: '张三' },
|
||||
{ contractId: 22, contractNumber: 'HT2023002', customerName: '李四' }
|
||||
]
|
||||
} else {
|
||||
this.contractOptions = []
|
||||
@ -338,19 +366,21 @@ export default {
|
||||
}
|
||||
},
|
||||
// 处理付款方变更
|
||||
handlePayeeChange(payeeId) {
|
||||
const payee = this.payeeOptions.find(item => item.id === payeeId)
|
||||
handlePayeeChange(paysdId) {
|
||||
const payee = this.payeeOptions.find(item => item.id === paysdId)
|
||||
if (payee) {
|
||||
this.billForm.payeeName = payee.name
|
||||
this.billForm.paysdName = payee.name
|
||||
this.billForm.payeeContact = payee.contact
|
||||
// 触发表单验证更新
|
||||
this.$nextTick(() => {
|
||||
this.$refs.billInfoForm.validateField('payeeId')
|
||||
this.$refs.billInfoForm.validateField('paysdId')
|
||||
})
|
||||
}
|
||||
},
|
||||
// 处理费用类型变更
|
||||
handleFeeTypeChange(value) {
|
||||
console.log(value);
|
||||
|
||||
if (value) {
|
||||
// 查找匹配的费用类型
|
||||
let selectedFeeType = null;
|
||||
@ -370,7 +400,7 @@ export default {
|
||||
}
|
||||
// 检查子节点
|
||||
if (category.children && category.children.length > 0) {
|
||||
const found = category.children.find(item => item.id === value);
|
||||
const found = category.children.find(item => item.id === value[1]);
|
||||
if (found) {
|
||||
selectedCategory = category;
|
||||
selectedFeeType = {
|
||||
@ -389,25 +419,25 @@ export default {
|
||||
if (selectedFeeType.type === '分类') {
|
||||
this.billForm.feeCategoryId = selectedFeeType.id;
|
||||
this.billForm.feeTypeId = '';
|
||||
this.billForm.feeTypeName = selectedFeeType.name;
|
||||
this.billForm.feTpName = selectedFeeType.name;
|
||||
} else {
|
||||
this.billForm.feeCategoryId = selectedCategory.id;
|
||||
this.billForm.feeTypeId = selectedFeeType.id;
|
||||
this.billForm.feeTypeName = selectedFeeType.name;
|
||||
this.billForm.feTpName = selectedFeeType.name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 清空选择
|
||||
this.billForm.feeCategoryId = '';
|
||||
this.billForm.feeTypeId = '';
|
||||
this.billForm.feeTypeName = '';
|
||||
this.billForm.feTpName = '';
|
||||
}
|
||||
},
|
||||
// 处理公司变更
|
||||
handleCompanyChange(companyId) {
|
||||
const company = this.companyOptions.find(item => item.id === companyId)
|
||||
if (company) {
|
||||
this.billForm.companyName = company.name
|
||||
this.billForm.corNm = company.name
|
||||
// 触发表单验证更新
|
||||
this.$nextTick(() => {
|
||||
this.$refs.billInfoForm.validateField('companyId')
|
||||
@ -420,11 +450,11 @@ export default {
|
||||
// 处理计费周期变更
|
||||
handleBillingPeriodChange(val) {
|
||||
if (val && val.length === 2) {
|
||||
this.billForm.billingStartDate = val[0]
|
||||
this.billForm.billingEndDate = val[1]
|
||||
this.billForm.chggBgnDt = val[0]
|
||||
this.billForm.chggEndDt = val[1]
|
||||
} else {
|
||||
this.billForm.billingStartDate = ''
|
||||
this.billForm.billingEndDate = ''
|
||||
this.billForm.chggBgnDt = ''
|
||||
this.billForm.chggEndDt = ''
|
||||
}
|
||||
},
|
||||
|
||||
@ -525,9 +555,6 @@ export default {
|
||||
// 更新选中的房间ID列表
|
||||
this.selectedRoomIds = roomNodes.map(node => node.id)
|
||||
|
||||
// 重置房源信息列表
|
||||
this.billForm.roomInfoList = []
|
||||
|
||||
// 创建一个Map用于收集项目信息
|
||||
const projectMap = new Map()
|
||||
|
||||
@ -553,20 +580,63 @@ export default {
|
||||
|
||||
// 只有完整路径的房间才处理
|
||||
if (roomInfo && floorNode && buildingNode && projectNode) {
|
||||
// 更新房源信息列表
|
||||
this.billForm.roomInfoList.push({
|
||||
roomId: roomNode.id,
|
||||
// 确认项目是否已在Map中
|
||||
if (!projectMap.has(projectNode.id)) {
|
||||
projectMap.set(projectNode.id, {
|
||||
id: projectNode.id,
|
||||
projectName: projectNode.label,
|
||||
projectType: '产业园区', // 如果有projectType属性,应该使用projectNode中的值
|
||||
buildings: []
|
||||
})
|
||||
}
|
||||
|
||||
// 获取当前项目
|
||||
const project = projectMap.get(projectNode.id)
|
||||
|
||||
// 查找楼宇
|
||||
let building = project.buildings.find(b => b.id === buildingNode.id)
|
||||
if (!building) {
|
||||
building = {
|
||||
id: buildingNode.id,
|
||||
buildingName: buildingNode.label,
|
||||
buildingCode: '', // 如果有buildingCode属性,应该使用buildingNode中的值
|
||||
floors: []
|
||||
}
|
||||
project.buildings.push(building)
|
||||
}
|
||||
|
||||
// 查找楼层
|
||||
let floor = building.floors.find(f => f.id === floorNode.id)
|
||||
if (!floor) {
|
||||
floor = {
|
||||
id: floorNode.id,
|
||||
floorName: floorNode.label,
|
||||
floorNumber: 0, // 如果有floorNumber属性,应该使用floorNode中的值
|
||||
rooms: []
|
||||
}
|
||||
building.floors.push(floor)
|
||||
}
|
||||
|
||||
// 添加房间
|
||||
const room = {
|
||||
id: roomInfo.id,
|
||||
roomNumber: roomInfo.roomNumber || roomNode.label.split('(')[0],
|
||||
buildingId: buildingNode.id,
|
||||
buildingName: buildingNode.label,
|
||||
floorId: floorNode.id,
|
||||
floorName: floorNode.label,
|
||||
projectId: projectNode.id,
|
||||
projectName: projectNode.label,
|
||||
rentArea: roomInfo.rentalArea || 0
|
||||
})
|
||||
roomType: roomInfo.roomType || '',
|
||||
roomStatus: roomInfo.roomStatus || '1',
|
||||
buildingArea: roomInfo.buildingArea || 0,
|
||||
rentalArea: roomInfo.rentalArea || 0
|
||||
}
|
||||
|
||||
// 检查该房间是否已经存在
|
||||
const roomExists = floor.rooms.some(r => r.id === room.id)
|
||||
if (!roomExists) {
|
||||
floor.rooms.push(room)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 将Map转换为数组
|
||||
this.billForm.roomIds = Array.from(projectMap.values())
|
||||
},
|
||||
// 上传文件前检查
|
||||
beforeUpload(file) {
|
||||
@ -586,32 +656,87 @@ export default {
|
||||
// 自定义上传文件
|
||||
uploadFile(options) {
|
||||
this.attachmentLoading = true
|
||||
const file = options.file
|
||||
|
||||
// 此处模拟上传,实际应调用API
|
||||
setTimeout(() => {
|
||||
this.fileList.push({
|
||||
name: options.file.name,
|
||||
url: URL.createObjectURL(options.file),
|
||||
operatorName: '当前用户',
|
||||
operateTime: new Date().toLocaleString()
|
||||
})
|
||||
|
||||
this.attachmentLoading = false
|
||||
this.$message.success('上传成功')
|
||||
}, 1000)
|
||||
// 创建临时URL供预览
|
||||
const tempUrl = URL.createObjectURL(file)
|
||||
const fileName = file.name
|
||||
|
||||
// 向上传列表中添加文件
|
||||
const currentUser = this.$store.getters.name || '当前用户'
|
||||
|
||||
this.fileList.push({
|
||||
name: fileName,
|
||||
file: file,
|
||||
url: tempUrl,
|
||||
operatorName: currentUser,
|
||||
operateTime: new Date().toLocaleString()
|
||||
})
|
||||
|
||||
this.attachmentLoading = false
|
||||
this.$message.success('上传成功')
|
||||
|
||||
console.log(this.fileList);
|
||||
|
||||
},
|
||||
|
||||
// 预览文件
|
||||
previewFile(file) {
|
||||
window.open(file.url)
|
||||
this.previewLoading = true
|
||||
this.previewDialogVisible = true
|
||||
this.currentPreviewName = file.name || '附件'
|
||||
this.previewUrl = ''
|
||||
this.isPdf = false
|
||||
this.isImage = false
|
||||
|
||||
// 根据文件名后缀判断文件类型
|
||||
const fileExt = file.name ? file.name.split('.').pop().toLowerCase() : ''
|
||||
|
||||
try {
|
||||
// 获取文件内容进行预览
|
||||
const blob = file.file ? file.file : new Blob()
|
||||
this.previewBlob = blob
|
||||
|
||||
// 设置文件类型标志
|
||||
if (fileExt === 'pdf') {
|
||||
this.isPdf = true
|
||||
} else if (['jpg', 'jpeg', 'png', 'gif'].includes(fileExt)) {
|
||||
this.isImage = true
|
||||
}
|
||||
|
||||
// 创建URL用于预览
|
||||
this.previewUrl = file.url || URL.createObjectURL(blob)
|
||||
this.previewLoading = false
|
||||
} catch (error) {
|
||||
console.error('预览失败', error)
|
||||
this.$message.error('获取预览数据失败')
|
||||
this.previewLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 下载当前预览的文件
|
||||
downloadCurrentPreview() {
|
||||
if (!this.previewUrl) {
|
||||
this.$message.error('没有可下载的文件')
|
||||
return
|
||||
}
|
||||
|
||||
const link = document.createElement('a')
|
||||
link.href = this.previewUrl
|
||||
link.setAttribute('download', this.currentPreviewName)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
},
|
||||
|
||||
// 下载文件
|
||||
downloadFile(file) {
|
||||
// 实际应调用API下载
|
||||
const link = document.createElement('a')
|
||||
link.href = file.url
|
||||
link.download = file.name
|
||||
link.click()
|
||||
},
|
||||
|
||||
// 删除文件
|
||||
deleteFile(index) {
|
||||
this.$confirm('确认删除该附件?', '提示', {
|
||||
@ -631,8 +756,8 @@ export default {
|
||||
}
|
||||
|
||||
if (this.formExtension.billingPeriod && this.formExtension.billingPeriod.length === 2) {
|
||||
this.billForm.billingStartDate = this.formExtension.billingPeriod[0]
|
||||
this.billForm.billingEndDate = this.formExtension.billingPeriod[1]
|
||||
this.billForm.chggBgnDt = this.formExtension.billingPeriod[0]
|
||||
this.billForm.chggEndDt = this.formExtension.billingPeriod[1]
|
||||
}
|
||||
|
||||
return this.billForm
|
||||
@ -665,7 +790,7 @@ export default {
|
||||
}
|
||||
|
||||
// 验证是否选择了房源
|
||||
if (this.billForm.roomInfoList.length === 0) {
|
||||
if (this.billForm.roomIds.length === 0) {
|
||||
this.$message.warning('请至少选择一个房源')
|
||||
this.activeTab = 'roomInfo'
|
||||
resolve(false)
|
||||
@ -698,30 +823,28 @@ export default {
|
||||
this.billForm = {
|
||||
contractId: '',
|
||||
contractNumber: '',
|
||||
payeeId: '',
|
||||
payeeName: '',
|
||||
paysdId: '',
|
||||
paysdName: '',
|
||||
payeeContact: '',
|
||||
feeCategoryId: '',
|
||||
feeTypeId: '',
|
||||
feeTypeName: '',
|
||||
feTpName: '',
|
||||
currCode: '156', // 默认人民币
|
||||
billingStartDate: '',
|
||||
billingEndDate: '',
|
||||
receivableAmount: 0,
|
||||
price: 0,
|
||||
priceU: '元/月',
|
||||
taxInclusiveRule: '含税',
|
||||
chggBgnDt: '',
|
||||
chggEndDt: '',
|
||||
accigRcvAmt: 0,
|
||||
taxInclusiveRule: '1',
|
||||
taxRate: 0,
|
||||
receivableDate: '',
|
||||
specialBillType: '正常',
|
||||
lateFeeStartDays: 0,
|
||||
lateFeeRate: 0,
|
||||
lateFeeLimit: 0,
|
||||
pybDt: '',
|
||||
specialBillType: '1',
|
||||
ovdueStartDays: 0,
|
||||
ovdueIntRate: 0,
|
||||
ovdueLimitRate: 0,
|
||||
companyId: '',
|
||||
companyName: '',
|
||||
corNm: '',
|
||||
accountId: '',
|
||||
billRemark: '',
|
||||
roomInfoList: []
|
||||
roomIds: []
|
||||
}
|
||||
|
||||
// 重置扩展表单数据
|
||||
@ -738,7 +861,62 @@ export default {
|
||||
|
||||
// 重置文件上传列表
|
||||
this.fileList = []
|
||||
}
|
||||
},
|
||||
// 表单提交
|
||||
submitForm() {
|
||||
this.validateForm().then(valid => {
|
||||
if (valid) {
|
||||
const formData = this.getFormData()
|
||||
|
||||
this.loading = true
|
||||
addBill(formData)
|
||||
.then(response => {
|
||||
if (response.code === '0000000000000000') {
|
||||
this.$message.success('添加账单成功')
|
||||
|
||||
// 如果有附件,上传附件
|
||||
if (this.fileList.length > 0) {
|
||||
|
||||
this.uploadAttachments(response.data)
|
||||
} else {
|
||||
this.$emit('success')
|
||||
this.resetForm()
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response.message || '添加账单失败')
|
||||
this.loading = false
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('添加账单失败', error)
|
||||
this.$message.error('添加账单失败,请检查表单数据')
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 上传附件
|
||||
uploadAttachments(billId) {
|
||||
const uploadPromises = this.fileList.map(fileItem => {
|
||||
return uploadBillAttachment(billId, fileItem.file)
|
||||
})
|
||||
|
||||
Promise.all(uploadPromises)
|
||||
.then(() => {
|
||||
this.$message.success('附件上传成功')
|
||||
this.$emit('success')
|
||||
this.resetForm()
|
||||
this.loading = false
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('附件上传失败', error)
|
||||
this.$message.warning('账单创建成功,但部分附件上传失败')
|
||||
this.$emit('success')
|
||||
this.resetForm()
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -755,4 +933,45 @@ export default {
|
||||
color: #F56C6C;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
min-height: 500px;
|
||||
max-height: 700px;
|
||||
overflow: auto;
|
||||
|
||||
.preview-iframe {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.preview-error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 300px;
|
||||
color: #909399;
|
||||
|
||||
i {
|
||||
font-size: 48px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,17 @@
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" class="search-form">
|
||||
<el-form-item label="合同编号" prop="contractNumber">
|
||||
<el-input v-model="queryParams.contractNumber" placeholder="请输入合同编号" clearable style="width: 220px" />
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input v-model="queryParams.contractNo" placeholder="请输入合同编号" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="房号" prop="roomNumber">
|
||||
<el-input v-model="queryParams.roomNumber" placeholder="请输入房号" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="对方名称" prop="payeeName">
|
||||
<el-input v-model="queryParams.payeeName" placeholder="请输入对方名称" clearable style="width: 220px" />
|
||||
<el-form-item label="对方名称" prop="paysdName">
|
||||
<el-input v-model="queryParams.paysdName" placeholder="请输入对方名称" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="账单编号" prop="billNumber">
|
||||
<el-input v-model="queryParams.billNumber" placeholder="请输入账单编号" clearable style="width: 220px" />
|
||||
<el-form-item label="账单编号" prop="totBillNo">
|
||||
<el-input v-model="queryParams.totBillNo" placeholder="请输入账单编号" clearable style="width: 220px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="账单状态" prop="billStatus">
|
||||
<el-select v-model="queryParams.billStatus" placeholder="请选择账单状态" clearable multiple style="width: 220px">
|
||||
@ -20,7 +20,7 @@
|
||||
<el-option label="关闭" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="应收时间" prop="receivableDate">
|
||||
<el-form-item label="应收时间" prop="pybDt">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
@ -77,11 +77,11 @@
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<el-table v-loading="loading" :data="billList" border>
|
||||
<el-table-column label="对方名称" prop="payeeName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="对方名称" prop="paysdName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="项目楼宇名称" prop="projectName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="房号" prop="roomNumber" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="账单编号" prop="billNumber" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="合同编号" prop="contractNumber" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="账单编号" prop="totBillNo" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="合同编号" prop="contractNo" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="结清状态" min-width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getClearStatusType(scope.row.clearStatus)">
|
||||
@ -89,25 +89,25 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="费用类型" prop="feeTypeName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="账单金额" prop="billAmount" min-width="100" align="right">
|
||||
<el-table-column label="费用类型" prop="feTpName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="账单金额" prop="accblAmt" min-width="100" align="right">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.billAmount ? scope.row.billAmount.toFixed(2) : '0.00' }}
|
||||
{{ scope.row.accblAmt ? scope.row.accblAmt.toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应收金额" prop="receivableAmount" min-width="100" align="right">
|
||||
<el-table-column label="应收金额" prop="accigRcvAmt" min-width="100" align="right">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.receivableAmount ? scope.row.receivableAmount.toFixed(2) : '0.00' }}
|
||||
{{ scope.row.accigRcvAmt ? scope.row.accigRcvAmt.toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="实收金额" prop="receivedAmount" min-width="100" align="right">
|
||||
<el-table-column label="实收金额" prop="atmRecvAmt" min-width="100" align="right">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.receivedAmount ? scope.row.receivedAmount.toFixed(2) : '0.00' }}
|
||||
{{ scope.row.atmRecvAmt ? scope.row.atmRecvAmt.toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="开始日期" prop="billingStartDate" min-width="120" align="center" />
|
||||
<el-table-column label="结束日期" prop="billingEndDate" min-width="120" align="center" />
|
||||
<el-table-column label="应收日期" prop="receivableDate" min-width="120" align="center" />
|
||||
<el-table-column label="开始日期" prop="chggBgnDt" min-width="120" align="center" />
|
||||
<el-table-column label="结束日期" prop="chggEndDt" min-width="120" align="center" />
|
||||
<el-table-column label="应收日期" prop="pybDt" min-width="120" align="center" />
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleViewDetail(scope.row)">查看</el-button>
|
||||
@ -171,10 +171,10 @@ export default {
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
contractNumber: '',
|
||||
contractNo: '',
|
||||
roomNumber: '',
|
||||
payeeName: '',
|
||||
billNumber: '',
|
||||
paysdName: '',
|
||||
totBillNo: '',
|
||||
billStatus: [],
|
||||
receivableDateStart: '',
|
||||
receivableDateEnd: '',
|
||||
@ -217,7 +217,7 @@ export default {
|
||||
}
|
||||
|
||||
getBillList(queryParams).then(response => {
|
||||
this.billList = response.data.data || []
|
||||
this.billList = response.data.list || []
|
||||
this.total = response.data.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
@ -250,10 +250,10 @@ export default {
|
||||
children = category.financeFeeTypes.map(feeType => {
|
||||
return {
|
||||
id: feeType.id || Math.random().toString(36).substr(2, 9),
|
||||
label: feeType.feeTypeName || '未命名费用',
|
||||
label: feeType.feTpName || '未命名费用',
|
||||
categoryId: categoryId,
|
||||
// 存储原始数据以便后续使用
|
||||
feeTypeName: feeType.feeTypeName || '未命名费用',
|
||||
feTpName: feeType.feTpName || '未命名费用',
|
||||
// 确保没有更多的子节点
|
||||
children: null
|
||||
}
|
||||
@ -353,12 +353,28 @@ export default {
|
||||
this.$refs.addBillForm.validateForm().then(valid => {
|
||||
if (valid) {
|
||||
const billData = this.$refs.addBillForm.getFormData()
|
||||
billData.billType = 1
|
||||
billData.billSource = 3
|
||||
|
||||
addBill(billData).then(response => {
|
||||
this.$message.success('添加账单成功')
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
if (response.code === '0000000000000000') {
|
||||
this.$message.success('添加账单成功')
|
||||
|
||||
// 如果有附件,上传附件
|
||||
const fileList = this.$refs.addBillForm.fileList
|
||||
if (fileList && fileList.length > 0) {
|
||||
this.$refs.addBillForm.uploadAttachments(response.data)
|
||||
// 上传附件由组件内部处理后续流程,不需要在这里关闭弹窗
|
||||
} else {
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
}
|
||||
} else {
|
||||
this.$message.error(response.message || '添加账单失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
// 错误处理
|
||||
this.$message.error('添加账单失败')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -0,0 +1,520 @@
|
||||
<template>
|
||||
<div class="transaction-detail-container" v-loading="loading">
|
||||
<!-- 详情主体 -->
|
||||
<el-tabs v-model="activeTab">
|
||||
<!-- 总体信息 -->
|
||||
<el-tab-pane label="总体信息" name="overall">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>总体信息</span>
|
||||
</div>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="对方单位名称">{{ detailData.totalInfo && detailData.totalInfo.unitName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="总金额">
|
||||
<span class="amount">{{ formatAmount(detailData.totalInfo && detailData.totalInfo.totalAmount) }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="已匹配金额">
|
||||
<span class="amount matched">{{ formatAmount(detailData.totalInfo && detailData.totalInfo.matchedAmount) }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="未匹配金额">
|
||||
<span class="amount unmatched">{{ formatAmount(detailData.totalInfo && detailData.totalInfo.unmatchedAmount) }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 流水信息 -->
|
||||
<el-tab-pane label="流水信息" name="transaction">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>流水信息</span>
|
||||
</div>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="借贷标">
|
||||
<el-tag :type="(detailData.transaction && detailData.transaction.dcFlagCode === '0') ? 'danger' : 'success'">
|
||||
{{ (detailData.transaction && detailData.transaction.dcFlagCode === '0') ? '借(支出)' : '贷(收入)' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="发生额">
|
||||
<span class="amount">{{ formatAmount(detailData.transaction && detailData.transaction.occuAmt) }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="入账日期">{{ detailData.transaction && detailData.transaction.inaccDate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="对方单位名称">{{ detailData.transaction && detailData.transaction.unitName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="支付方式">{{ getPaymentModeName(detailData.transaction && detailData.transaction.payModeName) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="对方账号">{{ detailData.transaction && detailData.transaction.opsAccname || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="凭证号">{{ detailData.transaction && detailData.transaction.txVchrNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="收据编号">{{ detailData.transaction && detailData.transaction.receiptNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人">{{ detailData.transaction && detailData.transaction.conterName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="流水账户">{{ detailData.transaction && detailData.transaction.openaccBankName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="摘要">{{ detailData.transaction && detailData.transaction.summ || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">{{ detailData.transaction && detailData.transaction.remark || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 匹配账单(新增的独立标签页) -->
|
||||
<el-tab-pane label="匹配账单" name="matchBills">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>匹配账单</span>
|
||||
</div>
|
||||
<el-table :data="detailData.relatedBills || []" border style="width: 100%">
|
||||
<el-table-column prop="unitName" label="对方名称" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="feeTypeName" label="费用类型" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="费用周期" min-width="200">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.billingStartDate || '-' }} 至 {{ scope.row.billingEndDate || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="receivableAmount" label="应收金额" min-width="120" align="right">
|
||||
<template slot-scope="scope">
|
||||
{{ formatAmount(scope.row.receivableAmount) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="!detailData.relatedBills || detailData.relatedBills.length === 0" class="empty-data">
|
||||
暂无匹配账单
|
||||
</div>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 附件信息 -->
|
||||
<el-tab-pane label="附件信息" name="attachment">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>附件信息</span>
|
||||
<el-button style="float: right;" type="primary" size="small" @click="handleAddAttachment">
|
||||
<i class="el-icon-plus"></i> 添加附件
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="detailData.attachments || []" border style="width: 100%">
|
||||
<el-table-column prop="fileName" label="文件名" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="createUserName" label="操作人" width="150" />
|
||||
<el-table-column prop="createTime" label="操作时间" width="180" />
|
||||
<el-table-column label="操作" width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="previewFile(scope.row)">预览</el-button>
|
||||
<el-button size="mini" type="text" @click="downloadFile(scope.row)">下载</el-button>
|
||||
<el-button size="mini" type="text" class="delete-btn" @click="deleteFile(scope.$index, scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="!detailData.attachments || detailData.attachments.length === 0" class="empty-data">
|
||||
暂无附件
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 文件上传对话框 -->
|
||||
<el-dialog title="上传附件" :visible.sync="uploadDialogVisible" width="500px" append-to-body>
|
||||
<el-upload
|
||||
class="upload-area"
|
||||
action="#"
|
||||
:http-request="uploadFile"
|
||||
:file-list="uploadFileList"
|
||||
:before-upload="beforeUpload"
|
||||
multiple
|
||||
:limit="10">
|
||||
<el-button type="primary">点击上传</el-button>
|
||||
<div slot="tip" class="el-upload__tip">只能上传jpg/png/pdf文件,且不超过5MB</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="uploadDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="confirmUpload">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 操作记录 -->
|
||||
<el-tab-pane label="操作记录" name="logs">
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>操作记录</span>
|
||||
</div>
|
||||
<el-table :data="detailData.operationRecords || []" border style="width: 100%" v-loading="logsLoading">
|
||||
<el-table-column prop="oprPersonNm" label="操作人" width="150" />
|
||||
<el-table-column prop="oprContent" label="操作内容" min-width="250" show-overflow-tooltip />
|
||||
<el-table-column prop="createTime" label="操作时间" width="180" />
|
||||
</el-table>
|
||||
<div v-if="!detailData.operationRecords || detailData.operationRecords.length === 0" class="empty-data">
|
||||
暂无操作记录
|
||||
</div>
|
||||
|
||||
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 文件预览对话框 -->
|
||||
<el-dialog title="附件预览" :visible.sync="previewDialogVisible" width="800px" append-to-body>
|
||||
<div class="preview-container" v-loading="previewLoading">
|
||||
<div v-if="previewUrl && isPdf" class="preview-iframe">
|
||||
<iframe :src="previewUrl" width="100%" height="500px" frameborder="0"></iframe>
|
||||
</div>
|
||||
<div v-else-if="previewUrl && isImage" class="preview-image">
|
||||
<img :src="previewUrl" style="max-width: 100%;" />
|
||||
</div>
|
||||
<div v-else-if="!previewLoading" class="preview-error">
|
||||
<i class="el-icon-warning"></i>
|
||||
<p>预览加载失败,请尝试下载后查看</p>
|
||||
<div class="preview-actions">
|
||||
<el-button type="primary" @click="downloadCurrentPreview">下载文件</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="previewDialogVisible = false">关 闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getTransactionDetail,
|
||||
uploadTransactionAttachment,
|
||||
deleteTransactionAttachment,
|
||||
getTransactionOperationLogs,
|
||||
previewAttachment,
|
||||
downloadAttachment,
|
||||
addTransactionOperation
|
||||
} from '@/api/finance'
|
||||
|
||||
export default {
|
||||
name: 'TransactionDetail',
|
||||
props: {
|
||||
transactionId: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
activeTab: 'overall',
|
||||
detailData: {},
|
||||
|
||||
// 附件相关
|
||||
uploadDialogVisible: false,
|
||||
uploadFileList: [],
|
||||
|
||||
// 预览相关
|
||||
previewDialogVisible: false,
|
||||
previewLoading: false,
|
||||
previewUrl: '',
|
||||
previewBlob: null,
|
||||
currentPreviewName: '',
|
||||
isPdf: false,
|
||||
isImage: false,
|
||||
|
||||
// 操作记录相关
|
||||
logsLoading: false,
|
||||
logsTotal: 0,
|
||||
logsQuery: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
transactionId: undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
// 获取流水详情
|
||||
getDetail() {
|
||||
this.loading = true
|
||||
getTransactionDetail(this.transactionId).then(response => {
|
||||
this.detailData = response.data || {}
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 获取操作记录
|
||||
getOperationLogs() {
|
||||
this.logsLoading = true
|
||||
this.logsQuery.transactionId = this.transactionId
|
||||
getTransactionOperationLogs(this.logsQuery).then(response => {
|
||||
if (this.detailData.operationRecords) {
|
||||
this.detailData.operationRecords = response.data.data || []
|
||||
}
|
||||
this.logsTotal = response.data.total
|
||||
this.logsLoading = false
|
||||
}).catch(() => {
|
||||
this.logsLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 操作记录分页大小改变
|
||||
handleLogsSizeChange(val) {
|
||||
this.logsQuery.pageSize = val
|
||||
this.getOperationLogs()
|
||||
},
|
||||
|
||||
// 操作记录分页页码改变
|
||||
handleLogsCurrentChange(val) {
|
||||
this.logsQuery.pageNum = val
|
||||
this.getOperationLogs()
|
||||
},
|
||||
|
||||
// 格式化金额
|
||||
formatAmount(amount) {
|
||||
if (amount === undefined || amount === null) {
|
||||
return '0.00'
|
||||
}
|
||||
return parseFloat(amount).toFixed(2)
|
||||
},
|
||||
|
||||
// 处理添加附件
|
||||
handleAddAttachment() {
|
||||
this.uploadDialogVisible = true
|
||||
this.uploadFileList = []
|
||||
},
|
||||
|
||||
// 上传前检查
|
||||
beforeUpload(file) {
|
||||
const isValidType = ['image/jpeg', 'image/png', 'application/pdf'].includes(file.type)
|
||||
const isLt5M = file.size / 1024 / 1024 < 5
|
||||
|
||||
if (!isValidType) {
|
||||
this.$message.error('只能上传JPG/PNG/PDF格式的文件!')
|
||||
}
|
||||
|
||||
if (!isLt5M) {
|
||||
this.$message.error('文件大小不能超过5MB!')
|
||||
}
|
||||
|
||||
return isValidType && isLt5M
|
||||
},
|
||||
|
||||
// 文件上传
|
||||
uploadFile(options) {
|
||||
// 先将文件加入上传列表,等确认后再统一上传
|
||||
const file = options.file
|
||||
|
||||
// 创建临时URL供预览
|
||||
const tempUrl = URL.createObjectURL(file)
|
||||
|
||||
// 向上传列表中添加文件
|
||||
this.uploadFileList.push({
|
||||
name: file.name,
|
||||
file: file,
|
||||
url: tempUrl
|
||||
})
|
||||
},
|
||||
|
||||
// 确认上传
|
||||
confirmUpload() {
|
||||
if (this.uploadFileList.length === 0) {
|
||||
this.$message.warning('请选择要上传的文件')
|
||||
return
|
||||
}
|
||||
|
||||
const userId = this.$store.getters.userId || ''
|
||||
const userName = this.$store.getters.name || ''
|
||||
|
||||
const uploadPromises = this.uploadFileList.map(fileItem => {
|
||||
return uploadTransactionAttachment(this.transactionId, fileItem.file, userId, userName)
|
||||
})
|
||||
|
||||
this.loading = true
|
||||
Promise.all(uploadPromises)
|
||||
.then(() => {
|
||||
this.$message.success('附件上传成功')
|
||||
this.uploadDialogVisible = false
|
||||
|
||||
|
||||
// 重新获取详情以更新附件列表
|
||||
this.getDetail()
|
||||
this.loading = false
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.error('部分附件上传失败,请重试')
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 预览文件
|
||||
previewFile(file) {
|
||||
this.previewLoading = true
|
||||
this.previewDialogVisible = true
|
||||
this.currentPreviewName = file.fileName || '附件'
|
||||
this.previewUrl = ''
|
||||
this.isPdf = false
|
||||
this.isImage = false
|
||||
|
||||
previewAttachment(file.fileId).then(response => {
|
||||
// 判断文件类型
|
||||
const contentType = response.headers['content-type']
|
||||
|
||||
// 创建blob对象
|
||||
const blob = new Blob([response.data], { type: contentType })
|
||||
this.previewBlob = blob
|
||||
|
||||
// 判断文件类型并设置标志
|
||||
this.isPdf = contentType === 'application/pdf'
|
||||
this.isImage = contentType.startsWith('image/')
|
||||
|
||||
// 创建URL用于预览
|
||||
this.previewUrl = URL.createObjectURL(blob)
|
||||
this.previewLoading = false
|
||||
}).catch(error => {
|
||||
console.error('预览失败', error)
|
||||
this.$message.error('获取预览数据失败')
|
||||
this.previewLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 下载当前预览的文件
|
||||
downloadCurrentPreview() {
|
||||
if (!this.previewBlob) {
|
||||
this.$message.error('没有可下载的文件')
|
||||
return
|
||||
}
|
||||
|
||||
const url = URL.createObjectURL(this.previewBlob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.setAttribute('download', this.currentPreviewName)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
},
|
||||
|
||||
// 下载文件
|
||||
downloadFile(file) {
|
||||
downloadAttachment(file.fileId, file.fileName).then(response => {
|
||||
// 创建下载链接
|
||||
const blob = new Blob([response.data])
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = file.fileName
|
||||
link.style.display = 'none'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}).catch(() => {
|
||||
this.$message.warning('无法下载该文件')
|
||||
})
|
||||
},
|
||||
|
||||
// 删除文件
|
||||
deleteFile(index, file) {
|
||||
this.$confirm('确认删除该附件?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const userId = this.$store.getters.userId || ''
|
||||
deleteTransactionAttachment(file.fileId, userId).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
if (this.detailData.attachments) {
|
||||
this.detailData.attachments.splice(index, 1)
|
||||
}
|
||||
// 重新获取详情以更新附件列表
|
||||
this.getDetail()
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
|
||||
|
||||
// 添加支付方式显示方法
|
||||
getPaymentModeName(code) {
|
||||
const paymentModeMap = {
|
||||
'1': '现金',
|
||||
'2': '网银转账',
|
||||
'3': 'POS机',
|
||||
'4': '支付宝',
|
||||
'5': '微信',
|
||||
'6': '转账支票',
|
||||
'7': '其他方式',
|
||||
'8': '线上支付'
|
||||
}
|
||||
return paymentModeMap[code] || code || '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.transaction-detail-container {
|
||||
padding: 0 20px;
|
||||
|
||||
.amount {
|
||||
font-weight: bold;
|
||||
color: #409EFF;
|
||||
|
||||
&.matched {
|
||||
color: #67C23A;
|
||||
}
|
||||
|
||||
&.unmatched {
|
||||
color: #E6A23C;
|
||||
}
|
||||
}
|
||||
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.empty-data {
|
||||
color: #909399;
|
||||
text-align: center;
|
||||
padding: 30px 0;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
color: #F56C6C;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
min-height: 500px;
|
||||
max-height: 700px;
|
||||
overflow: auto;
|
||||
|
||||
.preview-iframe {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.preview-error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 300px;
|
||||
color: #909399;
|
||||
|
||||
i {
|
||||
font-size: 48px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
352
pc/src/views/finance/transaction/index.vue
Normal file
352
pc/src/views/finance/transaction/index.vue
Normal file
@ -0,0 +1,352 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" class="search-form">
|
||||
<el-form-item label="借贷标" prop="dcFlagCode">
|
||||
<el-select v-model="queryParams.dcFlagCode" placeholder="请选择借贷标" clearable style="width: 200px">
|
||||
<el-option label="借(支出)" value="0" />
|
||||
<el-option label="贷(收入)" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="支付方式" prop="payModeName">
|
||||
<el-select v-model="queryParams.payModeCode" placeholder="请选择支付方式" clearable style="width: 200px">
|
||||
<el-option label="现金" value="1" />
|
||||
<el-option label="网银转账" value="2" />
|
||||
<el-option label="POS机" value="3" />
|
||||
<el-option label="支付宝" value="4" />
|
||||
<el-option label="微信" value="5" />
|
||||
<el-option label="转账支票" value="6" />
|
||||
<el-option label="其他方式" value="7" />
|
||||
<el-option label="线上支付" value="8" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="流水账户" prop="accountId">
|
||||
<el-select v-model="queryParams.accountId" placeholder="请选择流水账户" clearable filterable style="width: 200px">
|
||||
<el-option v-for="item in accountOptions" :key="item.id" :label="item.accountName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建人员" prop="createUserName">
|
||||
<el-input v-model="queryParams.createUserName" placeholder="请输入创建人员" clearable style="width: 200px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入账时间" prop="inaccDate">
|
||||
<el-date-picker
|
||||
v-model="accountDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
style="width: 240px">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="createDate">
|
||||
<el-date-picker
|
||||
v-model="createDateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="yyyy-MM-dd"
|
||||
style="width: 240px">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="发生额" prop="occuAmt">
|
||||
<el-input-number v-model="queryParams.occuAmtMin" placeholder="最小值" :min="0" :precision="2" style="width: 110px" controls-position="right" />
|
||||
<span style="margin: 0 5px;">-</span>
|
||||
<el-input-number v-model="queryParams.occuAmtMax" placeholder="最大值" :min="0" :precision="2" style="width: 110px" controls-position="right" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
<el-button type="warning" icon="el-icon-download" style="float: right;" @click="handleExport">导出</el-button>
|
||||
</el-form>
|
||||
|
||||
<!-- 表格区域 -->
|
||||
<el-table v-loading="loading" :data="transactionList" border>
|
||||
<el-table-column label="项目楼宇名称" prop="projectName" min-width="120" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.projectName }} - {{ scope.row.buildingName }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="房号" prop="roomNo" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="对方账号" prop="opsAccname" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="入账日期" prop="inaccDate" min-width="120" align="center" />
|
||||
<el-table-column label="对方名称" prop="unitName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="借贷标" min-width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.dcFlagCode === '0' ? 'danger' : 'success'">
|
||||
{{ scope.row.dcFlagCode === '0' ? '借(支出)' : '贷(收入)' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发生额" prop="occuAmt" min-width="100" align="right">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.occuAmt ? parseFloat(scope.row.occuAmt).toFixed(2) : '0.00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="币种(单位)" prop="currCode" min-width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ getCurrencyName(scope.row.currCode) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="支付方式" prop="payModeName" min-width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
{{ getPaymentModeName(scope.row.payModeName) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建人" prop="createUserId" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="状态" prop="transactionStatus" min-width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getStatusType(scope.row.transactionStatus)">
|
||||
{{ getStatusName(scope.row.transactionStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建日期" prop="createTime" min-width="120" align="center" />
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleViewDetail(scope.row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<!-- 分页区域 -->
|
||||
<el-pagination
|
||||
background
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="queryParams.pageNum"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
:page-size="queryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<!-- 流水详情对话框 -->
|
||||
<el-dialog title="收支流水详情" :visible.sync="detailVisible" width="80%" append-to-body>
|
||||
<transaction-detail v-if="detailVisible" :transactionId="currentTransaction.id" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTransactionList, exportTransactionList, getAllFinanceAccounts } from '@/api/finance'
|
||||
import TransactionDetail from './components/TransactionDetail'
|
||||
|
||||
export default {
|
||||
name: 'Transaction',
|
||||
components: {
|
||||
TransactionDetail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 加载标志
|
||||
loading: false,
|
||||
// 收支流水列表数据
|
||||
transactionList: [],
|
||||
// 总记录数
|
||||
total: 0,
|
||||
// 入账时间范围
|
||||
accountDateRange: [],
|
||||
// 创建时间范围
|
||||
createDateRange: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
dcFlagCode: undefined,
|
||||
payModeCode: undefined,
|
||||
accountId: undefined,
|
||||
createUserName: undefined,
|
||||
inaccDateStart: undefined,
|
||||
inaccDateEnd: undefined,
|
||||
createDateStart: undefined,
|
||||
createDateEnd: undefined,
|
||||
occuAmtMin: undefined,
|
||||
occuAmtMax: undefined
|
||||
},
|
||||
// 收支账户选项
|
||||
accountOptions: [],
|
||||
// 详情对话框显示标志
|
||||
detailVisible: false,
|
||||
// 当前查看的流水详情
|
||||
currentTransaction: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
// this.getAccountOptions()
|
||||
},
|
||||
methods: {
|
||||
// 获取收支流水列表
|
||||
getList() {
|
||||
this.loading = true
|
||||
// 处理查询参数
|
||||
const queryParams = { ...this.queryParams }
|
||||
|
||||
// 处理入账时间范围
|
||||
if (this.accountDateRange && this.accountDateRange.length > 0) {
|
||||
queryParams.inaccDateStart = this.accountDateRange[0]
|
||||
queryParams.inaccDateEnd = this.accountDateRange[1]
|
||||
}
|
||||
|
||||
// 处理创建时间范围
|
||||
if (this.createDateRange && this.createDateRange.length > 0) {
|
||||
queryParams.createDateStart = this.createDateRange[0]
|
||||
queryParams.createDateEnd = this.createDateRange[1]
|
||||
}
|
||||
|
||||
// 转换支付方式编码为后端参数
|
||||
if (queryParams.payModeCode) {
|
||||
queryParams.payModeName = queryParams.payModeCode
|
||||
delete queryParams.payModeCode
|
||||
}
|
||||
|
||||
getTransactionList(queryParams).then(response => {
|
||||
this.transactionList = response.data.data || []
|
||||
this.total = response.data.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 获取收支账户选项
|
||||
getAccountOptions() {
|
||||
getAllFinanceAccounts().then(response => {
|
||||
this.accountOptions = response.data || []
|
||||
})
|
||||
},
|
||||
// 搜索按钮操作
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
// 重置按钮操作
|
||||
resetQuery() {
|
||||
this.accountDateRange = []
|
||||
this.createDateRange = []
|
||||
this.$refs.queryForm.resetFields()
|
||||
this.handleQuery()
|
||||
},
|
||||
// 分页大小改变
|
||||
handleSizeChange(val) {
|
||||
this.queryParams.pageSize = val
|
||||
this.getList()
|
||||
},
|
||||
// 分页页码改变
|
||||
handleCurrentChange(val) {
|
||||
this.queryParams.pageNum = val
|
||||
this.getList()
|
||||
},
|
||||
// 查看流水详情
|
||||
handleViewDetail(row) {
|
||||
this.currentTransaction = row
|
||||
this.detailVisible = true
|
||||
},
|
||||
// 导出收支流水
|
||||
handleExport() {
|
||||
// 处理导出参数
|
||||
const exportParams = { ...this.queryParams }
|
||||
delete exportParams.pageNum
|
||||
delete exportParams.pageSize
|
||||
|
||||
// 处理入账时间范围
|
||||
if (this.accountDateRange && this.accountDateRange.length > 0) {
|
||||
exportParams.inaccDateStart = this.accountDateRange[0]
|
||||
exportParams.inaccDateEnd = this.accountDateRange[1]
|
||||
}
|
||||
|
||||
// 处理创建时间范围
|
||||
if (this.createDateRange && this.createDateRange.length > 0) {
|
||||
exportParams.createDateStart = this.createDateRange[0]
|
||||
exportParams.createDateEnd = this.createDateRange[1]
|
||||
}
|
||||
|
||||
this.$confirm('是否确认导出所有数据项?', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
exportTransactionList(exportParams).then(response => {
|
||||
// 创建下载链接
|
||||
const blob = new Blob([response.data])
|
||||
const fileName = `收支流水列表_${new Date().getTime()}.xlsx`
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
// IE浏览器下载
|
||||
navigator.msSaveBlob(blob, fileName)
|
||||
} else {
|
||||
// 非IE浏览器下载
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = fileName
|
||||
link.style.display = 'none'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
// 获取币种名称
|
||||
getCurrencyName(currency) {
|
||||
const currencyMap = {
|
||||
'156': '人民币',
|
||||
'840': '美元',
|
||||
'978': '欧元',
|
||||
'826': '英镑',
|
||||
'392': '日元'
|
||||
}
|
||||
return currencyMap[currency] || currency || '人民币'
|
||||
},
|
||||
// 获取状态类型
|
||||
getStatusType(status) {
|
||||
const statusMap = {
|
||||
'0': 'info',
|
||||
'1': 'success'
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
},
|
||||
// 获取状态名称
|
||||
getStatusName(status) {
|
||||
const statusMap = {
|
||||
'0': '处理中',
|
||||
'1': '已完成'
|
||||
}
|
||||
return statusMap[status] || '未知状态'
|
||||
},
|
||||
// 获取支付方式名称
|
||||
getPaymentModeName(code) {
|
||||
const paymentModeMap = {
|
||||
'1': '现金',
|
||||
'2': '网银转账',
|
||||
'3': 'POS机',
|
||||
'4': '支付宝',
|
||||
'5': '微信',
|
||||
'6': '转账支票',
|
||||
'7': '其他方式',
|
||||
'8': '线上支付'
|
||||
}
|
||||
return paymentModeMap[code] || code || '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -63,7 +63,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属地区">
|
||||
<el-input v-model="queryParams.region" placeholder="请输入所属地区" clearable size="small" />
|
||||
<region-selector v-model="queryParams.region" :value="queryParams.region" placeholder="请选择所属地区" size="small" @change="handleRegionChange" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
@ -133,7 +133,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所属地区" prop="region">
|
||||
<el-input v-model="form.region" placeholder="请输入所属地区" />
|
||||
<region-selector v-model="form.region" placeholder="请选择所属地区" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -223,9 +223,13 @@
|
||||
|
||||
<script>
|
||||
import { getProjectList, getProjectDetail, addProject, updateProject, deleteProject, getAllProjectStatistics, getTagByType } from '@/api/project'
|
||||
import RegionSelector from '@/components/RegionSelector'
|
||||
|
||||
export default {
|
||||
name: 'ProjectList',
|
||||
components: {
|
||||
RegionSelector
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
@ -338,7 +342,9 @@ export default {
|
||||
handleAdd() {
|
||||
this.dialogTitle = '新增项目'
|
||||
// 完全重置表单数据
|
||||
this.form = {}
|
||||
this.form = {
|
||||
region: '' // 初始化region为空字符串以确保组件正确绑定
|
||||
}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
@ -474,6 +480,10 @@ export default {
|
||||
// 重置表单和校验状态
|
||||
this.form = {}
|
||||
this.$refs['form'].clearValidate()
|
||||
},
|
||||
handleRegionChange(regionText) {
|
||||
|
||||
this.queryParams.region = regionText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ module.exports = {
|
||||
},
|
||||
// proxy: {
|
||||
// '/': {
|
||||
// target: 'http://192.168.137.214:8082',
|
||||
// target: 'http://192.168.137.214:8080',
|
||||
// changeOrigin: true,
|
||||
// pathRewrite: {
|
||||
// '^/api': '/api'
|
||||
|
Loading…
x
Reference in New Issue
Block a user