|
|
@@ -1,5 +1,5 @@
|
|
|
<script setup lang="ts">
|
|
|
-import { nextTick, onMounted, reactive, ref } from 'vue'
|
|
|
+import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
|
|
|
import type { UploadProps, UploadUserFile } from 'element-plus'
|
|
|
import {
|
|
|
ElButton,
|
|
|
@@ -64,6 +64,8 @@ interface CanBeReceiptDataReponse extends BaseResponse {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+type paymentReasonType = '房屋租赁费用' | '押金' | '物业费' | '水费'
|
|
|
+
|
|
|
interface ReceiptDto {
|
|
|
paymentUnit: string // 交款单位
|
|
|
paymentMethod: string // 付款方式
|
|
|
@@ -72,9 +74,11 @@ interface ReceiptDto {
|
|
|
zj: number // 租金
|
|
|
wyf: number // 物业费
|
|
|
sf: number // 水费
|
|
|
- paymentReason: string // 付款事由
|
|
|
+ paymentReason: paymentReasonType[] // 付款事由
|
|
|
rzrq: string //入账日期
|
|
|
operator: string
|
|
|
+ startDate: string // 开始日期
|
|
|
+ endDate: string // 结束日期
|
|
|
}
|
|
|
|
|
|
interface CanBeReturnReceiptDataReponse extends BaseResponse {
|
|
|
@@ -135,6 +139,8 @@ const previewContainer = ref<HTMLElement>()
|
|
|
const previewFileType = ref<FileType>(FileType.DOCX)
|
|
|
const previewFileUrl = ref('')
|
|
|
const previewRelativeUrl = ref('') // 新增:存储相对路径用于下载
|
|
|
+const receiptFormRef = ref<InstanceType<typeof ElForm>>()
|
|
|
+const returnReceiptFormRef = ref<InstanceType<typeof ElForm>>()
|
|
|
|
|
|
// PDF预览相关
|
|
|
const pdfSource = ref('')
|
|
|
@@ -165,9 +171,38 @@ const receiptForm = reactive<ReceiptDto>({
|
|
|
zj: 0,
|
|
|
wyf: 0,
|
|
|
sf: 0,
|
|
|
- paymentReason: '房屋租赁费用',
|
|
|
+ paymentReason: ['房屋租赁费用', '押金'],
|
|
|
rzrq: '',
|
|
|
operator: userInfo.value?.personName,
|
|
|
+ startDate: '',
|
|
|
+ endDate: '',
|
|
|
+})
|
|
|
+
|
|
|
+const receiptFormRules = computed(() => {
|
|
|
+ const rules: any = {
|
|
|
+ paymentUnit: [{ required: true, message: '请填写交款单位', trigger: 'blur' }],
|
|
|
+ paymentMethod: [{ required: true, message: '请选择付款方式', trigger: 'change' }],
|
|
|
+ paymentReason: [{ required: true, message: '请选择付款事由', trigger: 'change' }],
|
|
|
+ rzrq: [{ required: true, message: '请选择入账日期', trigger: 'change' }],
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据选中的付款事由动态添加验证规则
|
|
|
+ if (receiptForm.paymentReason.includes('押金')) {
|
|
|
+ rules.yj = [{ required: true, message: '请填写押金金额', trigger: 'blur' }]
|
|
|
+ }
|
|
|
+ if (receiptForm.paymentReason.includes('房屋租赁费用')) {
|
|
|
+ rules.zj = [{ required: true, message: '请填写租金金额', trigger: 'blur' }]
|
|
|
+ rules.startDate = [{ required: true, message: '请选择开始日期', trigger: 'change' }]
|
|
|
+ rules.endDate = [{ required: true, message: '请选择结束日期', trigger: 'change' }]
|
|
|
+ }
|
|
|
+ if (receiptForm.paymentReason.includes('物业费')) {
|
|
|
+ rules.wyf = [{ required: true, message: '请填写物业费金额', trigger: 'blur' }]
|
|
|
+ }
|
|
|
+ if (receiptForm.paymentReason.includes('水费')) {
|
|
|
+ rules.sf = [{ required: true, message: '请填写水费金额', trigger: 'blur' }]
|
|
|
+ }
|
|
|
+
|
|
|
+ return rules
|
|
|
})
|
|
|
|
|
|
// 退据相关
|
|
|
@@ -187,6 +222,16 @@ const returnReceiptForm = reactive<ReturnReceiptDto>({
|
|
|
zh: '',
|
|
|
})
|
|
|
|
|
|
+const returnReceiptFormRules = computed(() => {
|
|
|
+ const rules: any = {
|
|
|
+ dw: [{ required: true, message: '请填写单位名称', trigger: 'blur' }],
|
|
|
+ zh: [{ required: true, message: '请填写租户名称', trigger: 'blur' }],
|
|
|
+ yj: [{ required: true, message: '请填写押金金额', trigger: 'blur' }],
|
|
|
+ }
|
|
|
+
|
|
|
+ return rules
|
|
|
+})
|
|
|
+
|
|
|
// 付款方式选项
|
|
|
const paymentMethods = [
|
|
|
{ label: '转账', value: '转账' },
|
|
|
@@ -199,8 +244,7 @@ const paymentReasons = [
|
|
|
{ label: '房屋租赁费用', value: '房屋租赁费用' },
|
|
|
{ label: '押金', value: '押金' },
|
|
|
{ label: '物业费', value: '物业费' },
|
|
|
- { label: '水电费', value: '水电费' },
|
|
|
- { label: '其他费用', value: '其他费用' },
|
|
|
+ { label: '水费', value: '水费' },
|
|
|
]
|
|
|
|
|
|
// 获取文件类型
|
|
|
@@ -222,7 +266,7 @@ const getFileType = (url: string): FileType => {
|
|
|
|
|
|
// 获取合同状态标签类型
|
|
|
const getStatusType = (status: string) => {
|
|
|
- const statusMap: Record<string, string> = {
|
|
|
+ const statusMap: Record<string, 'success' | 'warning' | 'info' | 'primary' | 'danger'> = {
|
|
|
有效: 'success',
|
|
|
已退租: 'warning',
|
|
|
}
|
|
|
@@ -574,22 +618,28 @@ const getCanBeReceiptData = async (contractId: string) => {
|
|
|
contractId,
|
|
|
},
|
|
|
})
|
|
|
- console.log(res) // res的类型就是CanBeReceiptDataReponse
|
|
|
+ // console.log(res) // res的类型就是CanBeReceiptDataReponse
|
|
|
return res
|
|
|
}
|
|
|
|
|
|
// 获取收据
|
|
|
const gainReceipt = async (contractId: string, dto: ReceiptDto) => {
|
|
|
+ const convertReceiptDtoForBackend = (dto: ReceiptDto): any => {
|
|
|
+ return {
|
|
|
+ ...dto,
|
|
|
+ paymentReason: dto.paymentReason.join(','),
|
|
|
+ }
|
|
|
+ }
|
|
|
const res = await clientPost<ReceiptDto, BaseResponse & { data: string }>(
|
|
|
'/acontractInfo/getReceipt',
|
|
|
- dto,
|
|
|
+ convertReceiptDtoForBackend(dto),
|
|
|
{
|
|
|
params: {
|
|
|
contractId: contractId,
|
|
|
},
|
|
|
},
|
|
|
)
|
|
|
- console.log(res) // res.data就是收据的url地址 前面还是要添加MINIO_URL
|
|
|
+ // console.log(res) // res.data就是收据的url地址 前面还是要添加MINIO_URL
|
|
|
return res
|
|
|
}
|
|
|
|
|
|
@@ -609,7 +659,11 @@ const openReceiptDialog = async (contractId: string, contractNumber: string) =>
|
|
|
zj: 0,
|
|
|
wyf: 0,
|
|
|
sf: 0,
|
|
|
- paymentReason: '房屋租赁费用',
|
|
|
+ paymentReason: ['房屋租赁费用', '押金'],
|
|
|
+ rzrq: '',
|
|
|
+ operator: '',
|
|
|
+ startDate: '',
|
|
|
+ endDate: '',
|
|
|
})
|
|
|
|
|
|
try {
|
|
|
@@ -635,7 +689,23 @@ const openReceiptDialog = async (contractId: string, contractNumber: string) =>
|
|
|
|
|
|
// 计算总金额
|
|
|
const calculateTotalAmount = () => {
|
|
|
- receiptForm.rmb = receiptForm.yj + receiptForm.zj + receiptForm.wyf + receiptForm.sf
|
|
|
+ let total = 0
|
|
|
+
|
|
|
+ // 只计算选中的付款事由对应的金额
|
|
|
+ if (receiptForm.paymentReason.includes('押金')) {
|
|
|
+ total += receiptForm.yj
|
|
|
+ }
|
|
|
+ if (receiptForm.paymentReason.includes('房屋租赁费用')) {
|
|
|
+ total += receiptForm.zj
|
|
|
+ }
|
|
|
+ if (receiptForm.paymentReason.includes('物业费')) {
|
|
|
+ total += receiptForm.wyf
|
|
|
+ }
|
|
|
+ if (receiptForm.paymentReason.includes('水费')) {
|
|
|
+ total += receiptForm.sf
|
|
|
+ }
|
|
|
+
|
|
|
+ receiptForm.rmb = total
|
|
|
}
|
|
|
|
|
|
// 监听金额变化,自动计算总额
|
|
|
@@ -643,19 +713,45 @@ const handleAmountChange = () => {
|
|
|
calculateTotalAmount()
|
|
|
}
|
|
|
|
|
|
+// 监听付款事由变化,当取消选择时重置对应金额
|
|
|
+watch(
|
|
|
+ () => receiptForm.paymentReason,
|
|
|
+ (newReasons, oldReasons) => {
|
|
|
+ // 找出被取消选择的付款事由
|
|
|
+ if (oldReasons) {
|
|
|
+ const removedReasons = oldReasons.filter((reason) => !newReasons.includes(reason))
|
|
|
+
|
|
|
+ // 重置被取消选择的付款事由对应的金额
|
|
|
+ removedReasons.forEach((reason) => {
|
|
|
+ if (reason === '押金') {
|
|
|
+ receiptForm.yj = 0
|
|
|
+ } else if (reason === '房屋租赁费用') {
|
|
|
+ receiptForm.zj = 0
|
|
|
+ receiptForm.startDate = ''
|
|
|
+ receiptForm.endDate = ''
|
|
|
+ } else if (reason === '物业费') {
|
|
|
+ receiptForm.wyf = 0
|
|
|
+ } else if (reason === '水费') {
|
|
|
+ receiptForm.sf = 0
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重新计算总金额
|
|
|
+ calculateTotalAmount()
|
|
|
+ },
|
|
|
+)
|
|
|
+
|
|
|
// 生成收据
|
|
|
const generateReceipt = async () => {
|
|
|
- // 表单验证
|
|
|
- if (!receiptForm.paymentUnit.trim()) {
|
|
|
- ElMessage.warning('请填写交款单位')
|
|
|
- return
|
|
|
- }
|
|
|
- if (receiptForm.rmb <= 0) {
|
|
|
- ElMessage.warning('总金额必须大于0')
|
|
|
- return
|
|
|
- }
|
|
|
- if (!receiptForm.rzrq) {
|
|
|
- ElMessage.warning('请填写入账日期')
|
|
|
+ // 使用 Element Plus 表单验证
|
|
|
+ if (!receiptFormRef.value) return
|
|
|
+
|
|
|
+ try {
|
|
|
+ await receiptFormRef.value.validate()
|
|
|
+ } catch (error) {
|
|
|
+ console.error('表单验证失败:', error)
|
|
|
+ ElMessage.warning('请填写完整的表单信息')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -719,6 +815,10 @@ const closeReceiptDialog = () => {
|
|
|
receiptVisible.value = false
|
|
|
currentReceiptContractId.value = ''
|
|
|
currentReceiptContractNumber.value = ''
|
|
|
+ // 重置表单验证
|
|
|
+ if (receiptFormRef.value) {
|
|
|
+ receiptFormRef.value.resetFields()
|
|
|
+ }
|
|
|
// 重置表单
|
|
|
Object.assign(receiptForm, {
|
|
|
paymentUnit: '',
|
|
|
@@ -728,7 +828,11 @@ const closeReceiptDialog = () => {
|
|
|
zj: 0,
|
|
|
wyf: 0,
|
|
|
sf: 0,
|
|
|
- paymentReason: '房屋租赁费用',
|
|
|
+ paymentReason: ['房屋租赁费用', '押金'],
|
|
|
+ rzrq: '',
|
|
|
+ operator: userInfo.value?.personName,
|
|
|
+ startDate: '',
|
|
|
+ endDate: '',
|
|
|
})
|
|
|
}
|
|
|
|
|
|
@@ -778,6 +882,11 @@ const openReturnReceiptDialog = async (contractId: string, contractNumber: strin
|
|
|
zj: 0,
|
|
|
wyf: 0,
|
|
|
zh: '',
|
|
|
+ paymentReason: ['房屋租赁费用', '押金'],
|
|
|
+ rzrq: '',
|
|
|
+ operator: userInfo.value?.personName,
|
|
|
+ startDate: '',
|
|
|
+ endDate: '',
|
|
|
})
|
|
|
|
|
|
try {
|
|
|
@@ -812,17 +921,13 @@ const handleReturnAmountChange = () => {
|
|
|
|
|
|
// 生成退据
|
|
|
const generateReturnReceipt = async () => {
|
|
|
- // 表单验证
|
|
|
- if (!returnReceiptForm.dw.trim()) {
|
|
|
- ElMessage.warning('请填写单位名称')
|
|
|
- return
|
|
|
- }
|
|
|
- if (!returnReceiptForm.zh.trim()) {
|
|
|
- ElMessage.warning('请填写租户名称')
|
|
|
- return
|
|
|
- }
|
|
|
- if (returnReceiptForm.rmb <= 0) {
|
|
|
- ElMessage.warning('总金额必须大于0')
|
|
|
+ // 使用 Element Plus 表单验证
|
|
|
+ if (!returnReceiptFormRef.value) return
|
|
|
+
|
|
|
+ try {
|
|
|
+ await returnReceiptFormRef.value.validate()
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.warning('请填写完整的表单信息')
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -889,6 +994,10 @@ const closeReturnReceiptDialog = () => {
|
|
|
returnReceiptVisible.value = false
|
|
|
currentReturnReceiptContractId.value = ''
|
|
|
currentReturnReceiptContractNumber.value = ''
|
|
|
+ // 重置表单验证
|
|
|
+ if (returnReceiptFormRef.value) {
|
|
|
+ returnReceiptFormRef.value.resetFields()
|
|
|
+ }
|
|
|
// 重置表单
|
|
|
Object.assign(returnReceiptForm, {
|
|
|
dw: '',
|
|
|
@@ -897,6 +1006,11 @@ const closeReturnReceiptDialog = () => {
|
|
|
zj: 0,
|
|
|
wyf: 0,
|
|
|
zh: '',
|
|
|
+ paymentReason: ['房屋租赁费用', '押金'],
|
|
|
+ rzrq: '',
|
|
|
+ operator: userInfo.value?.personName,
|
|
|
+ startDate: '',
|
|
|
+ endDate: '',
|
|
|
})
|
|
|
}
|
|
|
|
|
|
@@ -1238,7 +1352,13 @@ onMounted(() => {
|
|
|
destroy-on-close
|
|
|
>
|
|
|
<div v-loading="receiptLoading" element-loading-text="正在获取收据数据...">
|
|
|
- <ElForm :model="receiptForm" label-width="100px" class="py-4">
|
|
|
+ <ElForm
|
|
|
+ ref="receiptFormRef"
|
|
|
+ :model="receiptForm"
|
|
|
+ :rules="receiptFormRules"
|
|
|
+ label-width="100px"
|
|
|
+ class="py-4"
|
|
|
+ >
|
|
|
<div class="mb-4 p-3 bg-blue-50 border border-blue-200 rounded-lg">
|
|
|
<div class="flex items-start gap-2">
|
|
|
<AlertCircle class="w-4 h-4 text-blue-500 mt-0.5 flex-shrink-0" />
|
|
|
@@ -1254,11 +1374,11 @@ onMounted(() => {
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <ElFormItem label="交款单位" required>
|
|
|
+ <ElFormItem label="交款单位" prop="paymentUnit">
|
|
|
<ElInput v-model="receiptForm.paymentUnit" placeholder="请输入交款单位名称" clearable />
|
|
|
</ElFormItem>
|
|
|
|
|
|
- <ElFormItem label="付款方式">
|
|
|
+ <ElFormItem label="付款方式" prop="paymentMethod">
|
|
|
<ElSelect
|
|
|
v-model="receiptForm.paymentMethod"
|
|
|
placeholder="请选择付款方式"
|
|
|
@@ -1273,10 +1393,11 @@ onMounted(() => {
|
|
|
</ElSelect>
|
|
|
</ElFormItem>
|
|
|
|
|
|
- <ElFormItem label="付款事由">
|
|
|
+ <ElFormItem label="付款事由" prop="paymentReason">
|
|
|
<ElSelect
|
|
|
v-model="receiptForm.paymentReason"
|
|
|
placeholder="请选择付款事由"
|
|
|
+ multiple
|
|
|
style="width: 100%"
|
|
|
>
|
|
|
<ElOption
|
|
|
@@ -1289,7 +1410,11 @@ onMounted(() => {
|
|
|
</ElFormItem>
|
|
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
|
- <ElFormItem label="押金(元)">
|
|
|
+ <ElFormItem
|
|
|
+ label="押金(元)"
|
|
|
+ v-if="receiptForm.paymentReason.includes('押金')"
|
|
|
+ prop="yj"
|
|
|
+ >
|
|
|
<ElInputNumber
|
|
|
v-model="receiptForm.yj"
|
|
|
:min="0"
|
|
|
@@ -1298,7 +1423,11 @@ onMounted(() => {
|
|
|
@change="handleAmountChange"
|
|
|
/>
|
|
|
</ElFormItem>
|
|
|
- <ElFormItem label="租金(元)">
|
|
|
+ <ElFormItem
|
|
|
+ label="租金(元)"
|
|
|
+ v-if="receiptForm.paymentReason.includes('房屋租赁费用')"
|
|
|
+ prop="zj"
|
|
|
+ >
|
|
|
<ElInputNumber
|
|
|
v-model="receiptForm.zj"
|
|
|
:min="0"
|
|
|
@@ -1307,7 +1436,37 @@ onMounted(() => {
|
|
|
@change="handleAmountChange"
|
|
|
/>
|
|
|
</ElFormItem>
|
|
|
- <ElFormItem label="物业费(元)">
|
|
|
+ <ElFormItem
|
|
|
+ label="开始日期"
|
|
|
+ v-if="receiptForm.paymentReason.includes('房屋租赁费用')"
|
|
|
+ prop="startDate"
|
|
|
+ >
|
|
|
+ <ElDatePicker
|
|
|
+ v-model="receiptForm.startDate"
|
|
|
+ type="date"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ placeholder="请选择开始日期"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+ </ElFormItem>
|
|
|
+ <ElFormItem
|
|
|
+ label="结束日期"
|
|
|
+ v-if="receiptForm.paymentReason.includes('房屋租赁费用')"
|
|
|
+ prop="endDate"
|
|
|
+ >
|
|
|
+ <ElDatePicker
|
|
|
+ v-model="receiptForm.endDate"
|
|
|
+ type="date"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ placeholder="请选择结束日期"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+ </ElFormItem>
|
|
|
+ <ElFormItem
|
|
|
+ label="物业费(元)"
|
|
|
+ v-if="receiptForm.paymentReason.includes('物业费')"
|
|
|
+ prop="wyf"
|
|
|
+ >
|
|
|
<ElInputNumber
|
|
|
v-model="receiptForm.wyf"
|
|
|
:min="0"
|
|
|
@@ -1316,7 +1475,11 @@ onMounted(() => {
|
|
|
@change="handleAmountChange"
|
|
|
/>
|
|
|
</ElFormItem>
|
|
|
- <ElFormItem label="水费(元)">
|
|
|
+ <ElFormItem
|
|
|
+ label="水费(元)"
|
|
|
+ v-if="receiptForm.paymentReason.includes('水费')"
|
|
|
+ prop="sf"
|
|
|
+ >
|
|
|
<ElInputNumber
|
|
|
v-model="receiptForm.sf"
|
|
|
:min="0"
|
|
|
@@ -1325,7 +1488,7 @@ onMounted(() => {
|
|
|
@change="handleAmountChange"
|
|
|
/>
|
|
|
</ElFormItem>
|
|
|
- <ElFormItem label="入账日期" required>
|
|
|
+ <ElFormItem label="入账日期" prop="rzrq">
|
|
|
<ElDatePicker
|
|
|
v-model="receiptForm.rzrq"
|
|
|
type="date"
|
|
|
@@ -1374,7 +1537,13 @@ onMounted(() => {
|
|
|
destroy-on-close
|
|
|
>
|
|
|
<div v-loading="returnReceiptLoading" element-loading-text="正在获取退据数据...">
|
|
|
- <ElForm :model="returnReceiptForm" label-width="100px" class="py-4">
|
|
|
+ <ElForm
|
|
|
+ ref="returnReceiptFormRef"
|
|
|
+ :model="returnReceiptForm"
|
|
|
+ :rules="returnReceiptFormRules"
|
|
|
+ label-width="100px"
|
|
|
+ class="py-4"
|
|
|
+ >
|
|
|
<div class="mb-4 p-3 bg-orange-50 border border-orange-200 rounded-lg">
|
|
|
<div class="flex items-start gap-2">
|
|
|
<AlertCircle class="w-4 h-4 text-orange-500 mt-0.5 flex-shrink-0" />
|
|
|
@@ -1390,16 +1559,16 @@ onMounted(() => {
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <ElFormItem label="单位名称" required>
|
|
|
+ <ElFormItem label="单位名称" prop="dw">
|
|
|
<ElInput v-model="returnReceiptForm.dw" placeholder="请输入单位名称" clearable />
|
|
|
</ElFormItem>
|
|
|
|
|
|
- <ElFormItem label="租户名称" required>
|
|
|
+ <ElFormItem label="租户名称" prop="zh">
|
|
|
<ElInput v-model="returnReceiptForm.zh" placeholder="请输入租户名称" clearable />
|
|
|
</ElFormItem>
|
|
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
|
- <ElFormItem label="押金(元)">
|
|
|
+ <ElFormItem label="押金(元)" prop="yj">
|
|
|
<ElInputNumber
|
|
|
v-model="returnReceiptForm.yj"
|
|
|
:min="0"
|
|
|
@@ -1448,12 +1617,7 @@ onMounted(() => {
|
|
|
<ElButton
|
|
|
type="primary"
|
|
|
:loading="returnReceiptGenerating"
|
|
|
- :disabled="
|
|
|
- returnReceiptLoading ||
|
|
|
- !returnReceiptForm.dw.trim() ||
|
|
|
- !returnReceiptForm.zh.trim() ||
|
|
|
- returnReceiptForm.rmb <= 0
|
|
|
- "
|
|
|
+ :disabled="returnReceiptLoading"
|
|
|
@click="generateReturnReceipt"
|
|
|
>
|
|
|
{{ returnReceiptGenerating ? '生成中...' : '生成退据' }}
|