|
@@ -0,0 +1,357 @@
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
|
+import { onMounted, reactive, ref } from 'vue'
|
|
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
|
+import { Download, RefreshCw, Search, Trash2 } from 'lucide-vue-next'
|
|
|
|
|
+import { clientGet, clientPost } from '@/utils/request.ts'
|
|
|
|
|
+
|
|
|
|
|
+// 退据信息接口定义
|
|
|
|
|
+interface ARefund {
|
|
|
|
|
+ id: string // 主键
|
|
|
|
|
+ contractId?: string // 合同id
|
|
|
|
|
+ unit?: string // 单位
|
|
|
|
|
+ tenant?: string // 租户
|
|
|
|
|
+ deposit?: number // 押金
|
|
|
|
|
+ rent?: number // 租金
|
|
|
|
|
+ propertyFee?: number // 物业费
|
|
|
|
|
+ totalAmount?: number // 合计
|
|
|
|
|
+ generationDate?: string // 生成日期
|
|
|
|
|
+ attachmentUrl?: string // 附件url
|
|
|
|
|
+ createTime?: string // 创建时间
|
|
|
|
|
+ updateTime?: string // 更新时间
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 退据响应数据接口
|
|
|
|
|
+interface ARefundResponse extends BaseResponse {
|
|
|
|
|
+ data: PageType<ARefund>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 响应式数据
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
+const tableData = ref<ARefund[]>([])
|
|
|
|
|
+const selectedRows = ref<ARefund[]>([])
|
|
|
|
|
+const total = ref(0)
|
|
|
|
|
+
|
|
|
|
|
+// MinIO文件服务基础地址
|
|
|
|
|
+const MINIO_URL = import.meta.env.VITE_MINIO_BASE_URL
|
|
|
|
|
+
|
|
|
|
|
+// 搜索表单数据
|
|
|
|
|
+const searchForm = reactive({
|
|
|
|
|
+ tenant: '',
|
|
|
|
|
+ unit: '',
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 获取退据列表数据
|
|
|
|
|
+const getList = async () => {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await clientGet<
|
|
|
|
|
+ {
|
|
|
|
|
+ tenant: string
|
|
|
|
|
+ unit: string
|
|
|
|
|
+ },
|
|
|
|
|
+ ARefundResponse
|
|
|
|
|
+ >('/arefund/findByPage', {
|
|
|
|
|
+ params: {
|
|
|
|
|
+ pageNum: searchForm.pageNum,
|
|
|
|
|
+ pageSize: searchForm.pageSize,
|
|
|
|
|
+ tenant: searchForm.tenant,
|
|
|
|
|
+ unit: searchForm.unit,
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ if (res.code !== 200) {
|
|
|
|
|
+ ElMessage.error(res.msg)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tableData.value = res.data.records
|
|
|
|
|
+ total.value = res.data.total
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取退据列表失败:', error)
|
|
|
|
|
+ ElMessage.error('获取数据失败,请稍后重试')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 搜索处理
|
|
|
|
|
+const handleSearch = () => {
|
|
|
|
|
+ searchForm.pageNum = 1
|
|
|
|
|
+ getList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 重置搜索条件
|
|
|
|
|
+const handleReset = () => {
|
|
|
|
|
+ searchForm.tenant = ''
|
|
|
|
|
+ searchForm.unit = ''
|
|
|
|
|
+ searchForm.pageNum = 1
|
|
|
|
|
+ getList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 批量删除退据
|
|
|
|
|
+const handleBatchDelete = async () => {
|
|
|
|
|
+ if (selectedRows.value.length === 0) {
|
|
|
|
|
+ ElMessage.warning('请选择要删除的退据记录')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm(
|
|
|
|
|
+ `确定要删除选中的 ${selectedRows.value.length} 条退据记录吗?`,
|
|
|
|
|
+ '确认删除',
|
|
|
|
|
+ {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning',
|
|
|
|
|
+ },
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ const ids = selectedRows.value.map((row) => row.id).filter(Boolean)
|
|
|
|
|
+ const res = await clientPost<string[], BaseResponse>('/arefund/deleteBatch', ids)
|
|
|
|
|
+
|
|
|
|
|
+ if (res.code !== 200) {
|
|
|
|
|
+ ElMessage.error(res.msg)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ElMessage.success(res.msg)
|
|
|
|
|
+ selectedRows.value = []
|
|
|
|
|
+ getList()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('删除退据失败:', error)
|
|
|
|
|
+ // 用户取消删除时不做处理
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 表格选择项变化
|
|
|
|
|
+const handleSelectionChange = (selection: ARefund[]) => {
|
|
|
|
|
+ selectedRows.value = selection
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 分页页码变化
|
|
|
|
|
+const handlePageChange = (page: number) => {
|
|
|
|
|
+ searchForm.pageNum = page
|
|
|
|
|
+ getList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 每页条数变化
|
|
|
|
|
+const handleSizeChange = (size: number) => {
|
|
|
|
|
+ searchForm.pageSize = size
|
|
|
|
|
+ searchForm.pageNum = 1
|
|
|
|
|
+ getList()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 格式化金额显示
|
|
|
|
|
+const formatAmount = (amount: number | undefined) => {
|
|
|
|
|
+ return amount ? `¥${amount.toLocaleString()}` : '-'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 格式化日期显示
|
|
|
|
|
+const formatDate = (date: string | undefined) => {
|
|
|
|
|
+ return date ? new Date(date).toLocaleDateString() : '-'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 下载附件
|
|
|
|
|
+const handleDownloadAttachment = async (row: ARefund) => {
|
|
|
|
|
+ if (!row.attachmentUrl) {
|
|
|
|
|
+ ElMessage.warning('该退据记录没有附件')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 处理完整URL和相对路径两种情况
|
|
|
|
|
+ const url = row.attachmentUrl.startsWith('http')
|
|
|
|
|
+ ? row.attachmentUrl
|
|
|
|
|
+ : `${MINIO_URL}${row.attachmentUrl}`
|
|
|
|
|
+
|
|
|
|
|
+ // 创建临时下载链接
|
|
|
|
|
+ const link = document.createElement('a')
|
|
|
|
|
+ link.href = url
|
|
|
|
|
+ link.download = `退据附件_${row.id}.${getFileExtension(url)}`
|
|
|
|
|
+ link.target = '_blank'
|
|
|
|
|
+ document.body.appendChild(link)
|
|
|
|
|
+ link.click()
|
|
|
|
|
+ document.body.removeChild(link)
|
|
|
|
|
+ ElMessage.success('附件下载已开始')
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('附件下载失败:', error)
|
|
|
|
|
+ ElMessage.error('附件下载失败,请稍后重试')
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取文件扩展名
|
|
|
|
|
+const getFileExtension = (url: string): string => {
|
|
|
|
|
+ const parts = url.split('.')
|
|
|
|
|
+ return parts.length > 1 ? parts[parts.length - 1] : 'pdf'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 页面挂载时加载数据
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ getList()
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="p-6 bg-gray-50 min-h-screen">
|
|
|
|
|
+ <div class="bg-white rounded-lg shadow-sm">
|
|
|
|
|
+ <!-- 页面标题 -->
|
|
|
|
|
+ <div class="px-6 py-4 border-b border-gray-200">
|
|
|
|
|
+ <h1 class="text-xl font-semibold text-gray-900">租房退据管理</h1>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 搜索表单区域 -->
|
|
|
|
|
+ <div class="p-6 border-b border-gray-200">
|
|
|
|
|
+ <el-form :model="searchForm" inline class="search-form">
|
|
|
|
|
+ <el-form-item label="租户名称">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="searchForm.tenant"
|
|
|
|
|
+ placeholder="请输入租户名称"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ class="w-48"
|
|
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item label="所属单位">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="searchForm.unit"
|
|
|
|
|
+ placeholder="请输入所属单位"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ class="w-48"
|
|
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
|
|
+ />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-button type="primary" @click="handleSearch" :loading="loading">
|
|
|
|
|
+ <Search class="w-4 h-4 mr-1" v-if="!loading" />
|
|
|
|
|
+ 搜索
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button @click="handleReset">
|
|
|
|
|
+ <RefreshCw class="w-4 h-4 mr-1" />
|
|
|
|
|
+ 重置
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 操作按钮区域 -->
|
|
|
|
|
+ <div class="px-6 py-4 border-b border-gray-200">
|
|
|
|
|
+ <div class="flex justify-between items-center">
|
|
|
|
|
+ <div class="flex gap-2">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="danger"
|
|
|
|
|
+ :disabled="selectedRows.length === 0"
|
|
|
|
|
+ @click="handleBatchDelete"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Trash2 class="w-4 h-4 mr-1" />
|
|
|
|
|
+ 批量删除 ({{ selectedRows.length }})
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="text-sm text-gray-500">共 {{ total }} 条记录</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 数据表格区域 -->
|
|
|
|
|
+ <div class="px-6">
|
|
|
|
|
+ <el-table
|
|
|
|
|
+ :data="tableData"
|
|
|
|
|
+ v-loading="loading"
|
|
|
|
|
+ @selection-change="handleSelectionChange"
|
|
|
|
|
+ stripe
|
|
|
|
|
+ class="w-full"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-table-column type="selection" width="55" />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- <el-table-column prop="id" label="退据ID" width="240" />-->
|
|
|
|
|
+
|
|
|
|
|
+ <!-- <el-table-column prop="contractId" label="合同ID" width="280" />-->
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="unit" label="所属单位" />
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="tenant" label="租户名称" />
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="deposit" label="押金" align="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ {{ formatAmount(row.deposit) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="rent" label="租金" align="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ {{ formatAmount(row.rent) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="propertyFee" label="物业费" align="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ {{ formatAmount(row.propertyFee) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="totalAmount" label="合计金额" align="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <span class="font-medium text-green-600">
|
|
|
|
|
+ {{ formatAmount(row.totalAmount) }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column prop="generationDate" label="生成日期">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ {{ formatDate(row.generationDate) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column label="操作" width="120" fixed="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ link
|
|
|
|
|
+ v-if="row.attachmentUrl"
|
|
|
|
|
+ @click="handleDownloadAttachment(row)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Download class="w-3 h-3 mr-1" />
|
|
|
|
|
+ 下载附件
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <span v-else class="text-gray-400 text-xs">无附件</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 分页控件区域 -->
|
|
|
|
|
+ <div class="px-6 py-4 border-t border-gray-200">
|
|
|
|
|
+ <el-pagination
|
|
|
|
|
+ v-model:current-page="searchForm.pageNum"
|
|
|
|
|
+ v-model:page-size="searchForm.pageSize"
|
|
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
|
|
+ :total="total"
|
|
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
|
+ @size-change="handleSizeChange"
|
|
|
|
|
+ @current-change="handlePageChange"
|
|
|
|
|
+ class="justify-end"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+:deep(.el-table) {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-pagination) {
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.search-form .el-form-item) {
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|