Ver código fonte

feat(zfgl): 完善收据与退据表单功能

- 引入 computed 和 watch 以支持动态表单验证
- 付款事由字段改为多选并定义类型约束- 增加开始日期和结束日期字段用于租赁费用- 实现基于所选付款事由的动态表单校验规则
-优化金额计算逻辑,仅累加已选项目的金额
- 添加表单引用以便进行统一验证和重置操作
- 当取消选择付款项目时自动清空对应金额输入
- 替换原有手动校验为 Element Plus 的表单验证机制
- 更新 UI 组件属性绑定及条件渲染配置
- 调整接口请求参数结构适配后端接收格式
nahida 7 meses atrás
pai
commit
5a462cbbf0
1 arquivos alterados com 217 adições e 53 exclusões
  1. 217 53
      src/views/zfgl/zfhtgl.vue

+ 217 - 53
src/views/zfgl/zfhtgl.vue

@@ -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 ? '生成中...' : '生成退据' }}