Browse Source

feat(cxcy): 新增公租房收入信息管理功能

- 添加了公租房收入信息的查询、新增、编辑和删除功能
- 实现了批量删除和数据导出功能
- 集成了数据导入功能,并优化了导入流程
- 优化了表格展示效果,增加了分页功能
-调整了搜索和筛选功能,提高了用户体验
nahida 11 tháng trước cách đây
mục cha
commit
019268283c
2 tập tin đã thay đổi với 361 bổ sung54 xóa
  1. 347 28
      src/views/cxcy/srqk.vue
  2. 14 26
      src/views/zcgl/xxgl.vue

+ 347 - 28
src/views/cxcy/srqk.vue

@@ -1,12 +1,22 @@
 <script setup lang="ts">
-
-import { onMounted } from 'vue'
+import { onMounted, ref, reactive } from 'vue'
 import { clientDownloadExcel, clientGet, clientPost } from '@/utils/request.ts'
-import { ElLoading, ElMessage } from 'element-plus'
+import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
+import type { UploadProps, FormInstance } from 'element-plus'
+import { Plus, Delete, Edit, Search, Refresh, Download, Upload } from '@element-plus/icons-vue'
+
+
+interface PageType<T> {
+  records: T[];
+  total: number;
+  size: number;
+  current: number;
+  pages: number;
+}
 
 interface Property {
   id: string; // 主键
-  receiptNumber: string; // 收据号(必填)
+  receiptNumber?: string; // 收据号
   building?: string; // 楼栋
   roomNumber?: string; // 房号
   collectionTime?: Date; // 收取时间
@@ -33,7 +43,7 @@ interface PropertyListResponse extends BaseResponse{
 }
 
 interface AddProperty {
-  receiptNumber: string; // 收据号(必填)
+  receiptNumber?: string; // 收据号
   building?: string; // 楼栋
   roomNumber?: string; // 房号
   collectionTime?: Date; // 收取时间
@@ -63,8 +73,24 @@ interface UpdateProperty {
   remarks?: string; // 备注
 }
 
+// Reactive state variables
+const tableData = ref<Property[]>([]);
+const total = ref(0);
+const pageSize = ref(10);
+const pageNum = ref(1);
 
+const searchForm = reactive({
+  receiptNumber: '',
+  roomNumber: '',
+  building: ''
+});
 
+const dialogVisible = ref(false);
+const dialogTitle = ref('');
+const isEdit = ref(false);
+const formData = reactive<Property>({});
+const formRef = ref<FormInstance>();
+const selectedIds = ref<string[]>([]);
 
 //新增
 const add = async (data:AddProperty) =>{
@@ -74,10 +100,11 @@ const add = async (data:AddProperty) =>{
 
   if(res.code !== 200){
     ElMessage.error(res.msg);
-    return;
+    return false;
   }
 
   ElMessage.success(res.msg);
+  return true;
 }
 
 //根据id获取数据
@@ -85,9 +112,9 @@ const getById = async (id:string) =>{
   const res = await clientGet<null,PropertyOneResponse>('/ainnovation/getById/'+id);
   if(res.code !== 200){
     ElMessage.error(res.msg);
-    return;
+    return null;
   }
-  console.log(res.data);
+  return res.data;
 }
 
 //分页获取数据
@@ -100,11 +127,11 @@ const getList = async () =>{
     building?: string;
   },PropertyListResponse>('/ainnovation/findByPage',{
     params:{
-      pageNum: 1,
-      pageSize: 10,
-      building:'',//这是模糊搜索的值(如果没有值就不要传个空的过去)
-      roomNumber:'',//这是模糊搜索的值(如果没有值就不要传个空的过去)
-      receiptNumber:''//这是模糊搜索的值(如果没有值就不要传个空的过去)
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      building: searchForm.building || undefined,
+      roomNumber: searchForm.roomNumber || undefined,
+      receiptNumber: searchForm.receiptNumber || undefined
     }
   });
 
@@ -112,30 +139,33 @@ const getList = async () =>{
     ElMessage.error(res.msg);
     return;
   }
-  console.log(res.data);
+  tableData.value = res.data.records;
+  total.value = res.data.total;
 }
 
 //批量删除
 const delBatch = async (ids: string[]) => {
-  const res = await clientPost<string, BaseResponse>('/ainnovation/deleteBatch', JSON.stringify(ids));
+  // Note: clientPost expects the data directly, not JSON.stringify
+  const res = await clientPost<string[], BaseResponse>('/ainnovation/deleteBatch', ids);
   if (res.code !== 200) {
     ElMessage.error(res.msg)
-    return
+    return false;
   }
   ElMessage.success(res.msg)
+  return true;
 }
 
 //修改
-const update = async (updateId:string,data:UpdateProperty) =>{
+const update = async (data:UpdateProperty) =>{
   const res = await clientPost<UpdateProperty,BaseResponse>('/ainnovation/update',{
-    ...data,
-    id:updateId
+    ...data
   })
   if(res.code !== 200){
     ElMessage.error(res.msg);
-    return;
+    return false;
   }
   ElMessage.success(res.msg);
+  return true;
 }
 
 //导出为excel
@@ -150,11 +180,12 @@ const exportExcel = async () => {
   try {
     await clientDownloadExcel('/ainnovation/exportData', {
       params: {
-        roomNumber: '',//这是模糊搜索的值(如果没有值就不要传个空的过去)
-        building: '',//这是模糊搜索的值(如果没有值就不要传个空的过去)
-        receiptNumber: '',//这是模糊搜索的值(如果没有值就不要传个空的过去)
+        roomNumber: searchForm.roomNumber || undefined,
+        building: searchForm.building || undefined,
+        receiptNumber: searchForm.receiptNumber || undefined,
       },
     })
+    ElMessage.success('导出成功');
   } catch (error) {
     console.error('导出失败:', error)
     ElMessage.error('导出失败')
@@ -165,29 +196,317 @@ const exportExcel = async () => {
 
 //excel导入
 const importExcel = async (file: File) => {
-  const res = await clientPost<{file: File},BaseResponse>('/ainnovation/importData',{
-    file
+  const formData = new FormData();
+  formData.append('file', file);
+  const res = await clientPost<FormData,BaseResponse>('/ainnovation/importData', formData, {
+    headers: {
+      'Content-Type': 'multipart/form-data'
+    }
   })
   if(res.code !== 200){
     ElMessage.error(res.msg);
-    return;
+    return false;
   }
   ElMessage.success(res.msg);
+  return true;
 }
 
+// --- CRUD Operations and Handlers ---
+
+const handleAdd = () => {
+  isEdit.value = false;
+  dialogTitle.value = '新增公租房收入信息';
+  // Reset form data
+  Object.keys(formData).forEach(key => delete formData[key as keyof Property]);
+  dialogVisible.value = true;
+};
+
+const handleEdit = async (row: Property) => {
+  isEdit.value = true;
+  dialogTitle.value = '编辑公租房收入信息';
+  const data = await getById(row.id);
+  if (data) {
+    Object.assign(formData, data);
+    dialogVisible.value = true;
+  }
+};
+
+const handleDelete = async (id: string) => {
+  ElMessageBox.confirm('确定删除此条记录吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+  }).then(async () => {
+    const success = await delBatch([id]);
+    if (success) {
+      getList();
+    }
+  }).catch(() => {
+    ElMessage.info('已取消删除');
+  });
+};
+
+const handleBatchDelete = () => {
+  if (selectedIds.value.length === 0) {
+    ElMessage.warning('请选择要删除的记录');
+    return;
+  }
+  ElMessageBox.confirm(`确定删除选中的 ${selectedIds.value.length} 条记录吗?`, '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+  }).then(async () => {
+    const success = await delBatch(selectedIds.value);
+    if (success) {
+      getList();
+    }
+  }).catch(() => {
+    ElMessage.info('已取消批量删除');
+  });
+};
+
+const handleSearch = () => {
+  pageNum.value = 1; // Reset to first page on search
+  getList();
+};
+
+const handleResetSearch = () => {
+  searchForm.receiptNumber = '';
+  searchForm.roomNumber = '';
+  searchForm.building = '';
+  pageNum.value = 1;
+  getList();
+};
+
+const handleConfirm = async () => {
+  if (!formRef.value) return;
+  await formRef.value.validate(async (valid) => {
+    if (valid) {
+      let success = false;
+      if (isEdit.value) {
+        success = await update(formData);
+      } else {
+        success = await add(formData);
+      }
+      if (success) {
+        dialogVisible.value = false;
+        getList();
+      }
+    } else {
+      ElMessage.error('请检查表单填写');
+    }
+  });
+};
+
+const handleCurrentChange = (val: number) => {
+  pageNum.value = val;
+  getList();
+};
+
+const handleSizeChange = (val: number) => {
+  pageSize.value = val;
+  pageNum.value = 1; // Reset to first page when page size changes
+  getList();
+};
 
+const handleSelectionChange = (selection: Property[]) => {
+  selectedIds.value = selection.map(item => item.id);
+};
 
+// Modified handleUploadSuccess as per user's request
+const handleUploadSuccess: UploadProps['onSuccess'] = async (response, uploadFile) => {
+  if (response) { // Check if response exists
+    ElMessage.success('文件导入成功');
+    getList();
+  } else {
+    // Assuming response might be null/undefined or not have a msg property if it's an error
+    ElMessage.error(`文件导入失败: ${response?.msg || '未知错误'}`);
+  }
+};
+
+const handleUploadError: UploadProps['onError'] = (error) => {
+  ElMessage.error(`文件导入失败: ${error.message}`);
+};
 
+const handleBeforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
+  const isExcel = rawFile.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || rawFile.type === 'application/vnd.ms-excel';
+  if (!isExcel) {
+    ElMessage.error('导入文件只能是 Excel 格式!');
+    return false;
+  }
+  return true;
+};
 
 const init = () => {
+  getList();
 }
 
 onMounted(()=>{
   init();
 })
-
 </script>
 
 <template>
-  <div>创新创业收入情况信息</div>
+  <div class="p-4">
+    <h1 class="text-2xl font-bold mb-6">创新创业收入情况信息</h1>
+
+    <!-- Search and Action Bar -->
+    <div class="mb-6 p-4 bg-white rounded-lg shadow-sm flex flex-wrap items-center gap-4">
+      <el-form :inline="true" :model="searchForm" class="flex-grow flex flex-wrap gap-x-4">
+        <el-form-item label="收据号">
+          <el-input v-model="searchForm.receiptNumber" placeholder="请输入收据号" clearable />
+        </el-form-item>
+        <el-form-item label="楼栋">
+          <el-input v-model="searchForm.building" placeholder="请输入楼栋" clearable />
+        </el-form-item>
+        <el-form-item label="房号">
+          <el-input v-model="searchForm.roomNumber" placeholder="请输入房号" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
+          <el-button :icon="Refresh" @click="handleResetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <div class="flex gap-2">
+        <el-button type="primary" :icon="Plus" @click="handleAdd">新增</el-button>
+        <el-button type="danger" :icon="Delete" @click="handleBatchDelete" :disabled="selectedIds.length === 0">批量删除</el-button>
+        <el-button type="success" :icon="Download" @click="exportExcel">导出</el-button>
+        <el-upload
+          class="inline-block ml-2"
+          action="/api/ainnovation/importData"
+          :show-file-list="false"
+          :on-success="handleUploadSuccess"
+          :on-error="handleUploadError"
+          :before-upload="handleBeforeUpload"
+          :http-request="(options) => importExcel(options.file)"
+        >
+          <el-button type="info" :icon="Upload">导入</el-button>
+        </el-upload>
+      </div>
+    </div>
+
+    <!-- Table -->
+    <div class="bg-white rounded-lg shadow-sm p-4">
+      <el-table :data="tableData" style="width: 100%" max-height="65vh" border @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="receiptNumber" label="收据号" width="100" />
+        <el-table-column prop="building" label="楼栋" width="80" />
+        <el-table-column prop="roomNumber" label="房号" width="80" />
+        <el-table-column prop="collectionTime" label="收取时间" width="180">
+          <template #default="{ row }">
+            {{
+              row.collectionTime
+                ? new Date(row.collectionTime).toLocaleString('zh-CN', {
+                  year: 'numeric',
+                  month: '2-digit',
+                  day: '2-digit',
+                  hour: '2-digit',
+                  minute: '2-digit',
+                  second: '2-digit',
+                  hour12: false,
+                }).replace(/\//g, '-')
+                : '-'
+            }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="rent" label="房租(元)" width="100" />
+        <el-table-column prop="deposit" label="押金(元)" width="100" />
+        <el-table-column prop="waterFee" label="水费(元)" width="100" />
+        <el-table-column prop="electricityFee" label="电费(元)" width="100" />
+        <el-table-column prop="propertyManagementFee" label="物业管理费(元)" width="120" />
+        <el-table-column prop="rentPeriod" label="租金收取时段" />
+        <el-table-column prop="handler" label="经手人" width="100" />
+        <el-table-column prop="remarks" label="备注" />
+        <el-table-column prop="createTime" label="创建时间" width="180">
+          <template #default="{ row }">
+            {{ row.createTime ? new Date(row.createTime).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="150" fixed="right">
+          <template #default="{ row }">
+            <el-button :icon="Edit" size="small" @click="handleEdit(row)">编辑</el-button>
+            <el-button type="danger" :icon="Delete" size="small" @click="handleDelete(row.id)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <!-- Pagination -->
+      <div class="mt-4 flex justify-end">
+        <el-pagination
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+          :current-page="pageNum"
+          :page-sizes="[10, 20, 50, 100]"
+          :page-size="pageSize"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="total"
+        />
+      </div>
+    </div>
+
+    <!-- Add/Edit Dialog -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="600px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <el-form :model="formData" ref="formRef" label-width="120px">
+        <el-form-item label="收据号" prop="receiptNumber" :rules="[{ required: true, message: '请输入收据号', trigger: 'blur' }]">
+          <el-input v-model="formData.receiptNumber" placeholder="请输入收据号" />
+        </el-form-item>
+        <el-form-item label="楼栋" prop="building" :rules="[{ required: true, message: '请输入楼栋', trigger: 'blur' }]">
+          <el-input v-model="formData.building" placeholder="请输入楼栋" />
+        </el-form-item>
+        <el-form-item label="房号" prop="roomNumber" :rules="[{ required: true, message: '请输入房号', trigger: 'blur' }]">
+          <el-input v-model="formData.roomNumber" placeholder="请输入房号" />
+        </el-form-item>
+        <!-- 找到以下这段 -->
+        <el-form-item label="收取时间" prop="collectionTime">
+          <el-date-picker
+            v-model="formData.collectionTime"
+            type="datetime"
+            placeholder="选择日期和时间"
+            value-format="YYYY-MM-DD HH:mm:ss"    style="width: 100%;"
+          />
+        </el-form-item>
+        <el-form-item label="房租(元)" prop="rent">
+          <el-input-number v-model="formData.rent" :min="0" :precision="2" :step="100" style="width: 100%;" />
+        </el-form-item>
+        <el-form-item label="押金(元)" prop="deposit">
+          <el-input-number v-model="formData.deposit" :min="0" :precision="2" :step="100" style="width: 100%;" />
+        </el-form-item>
+        <el-form-item label="水费(元)" prop="waterFee">
+          <el-input-number v-model="formData.waterFee" :min="0" :precision="2" :step="10" style="width: 100%;" />
+        </el-form-item>
+        <el-form-item label="电费(元)" prop="electricityFee">
+          <el-input-number v-model="formData.electricityFee" :min="0" :precision="2" :step="10" style="width: 100%;" />
+        </el-form-item>
+        <el-form-item label="物业管理费(元)" prop="propertyManagementFee">
+          <el-input-number v-model="formData.propertyManagementFee" :min="0" :precision="2" :step="10" style="width: 100%;" />
+        </el-form-item>
+        <el-form-item label="租金收取时段" prop="rentPeriod">
+          <el-input v-model="formData.rentPeriod" placeholder="请输入租金收取时段" />
+        </el-form-item>
+        <el-form-item label="经手人" prop="handler">
+          <el-input v-model="formData.handler" placeholder="请输入经手人" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="formData.remarks" type="textarea" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="handleConfirm">确定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
 </template>
+
+<style scoped>
+/* Add any specific styles here if needed, otherwise UnoCSS handles most */
+</style>

+ 14 - 26
src/views/zcgl/xxgl.vue

@@ -2,23 +2,9 @@
 import { onMounted, ref, reactive } from 'vue'
 import { clientDownloadExcel, clientGet, clientPost } from '@/utils/request.ts'
 import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
-import type { UploadProps, UploadRawFile, FormInstance } from 'element-plus'
+import type { UploadProps, FormInstance } from 'element-plus'
 import { Plus, Delete, Edit, Search, Refresh, Download, Upload } from '@element-plus/icons-vue'
 
-// Assuming BaseResponse and PageType are globally defined and available
-interface BaseResponse {
-  code: number;
-  msg: string;
-}
-
-interface PageType<T> {
-  records: T[];
-  total: number;
-  size: number;
-  current: number;
-  pages: number;
-}
-
 interface Property {
   id: string; // 主键
   assetCode?: string; // 资产编号
@@ -35,11 +21,11 @@ interface Property {
   updateBy?: string; // 修改人
 }
 
-interface PropertyOneResponse {
+interface PropertyOneResponse extends BaseResponse{
   data: Property;
 }
 
-interface PropertyListResponse {
+interface PropertyListResponse extends BaseResponse{
   data: PageType<Property>;
 }
 
@@ -87,23 +73,25 @@ const selectedIds = ref<string[]>([]);
 
 // Options for assetType and assetStatus selects
 const assetTypeOptions = [
-  { label: '公租房', value: 1 },
-  { label: '厂房', value: 2 }
+  { label: '公租房', value: '公租房' },
+  { label: '厂房', value: '厂房' }
 ];
 
 const assetStatusOptions = [
-  { label: '空置', value: 0 },
-  { label: '已租赁', value: 1 },
-  { label: '维修中', value: 2 },
-  { label: '其他', value: 3 } // Example for other statuses
+  { label: '空置', value: '空置' },
+  { label: '已租赁', value: '已租赁' },
+  { label: '维修中', value: '维修中' },
+  { label: '其他', value: '其他' } // Example for other statuses
 ];
 
 // Helper to get label from value
 const getAssetTypeLabel = (value: number | undefined) => {
+  console.log(value)
   return assetTypeOptions.find(option => option.value === value)?.label || '未知';
 };
 
 const getAssetStatusLabel = (value: number | undefined) => {
+  console.log(value)
   return assetStatusOptions.find(option => option.value === value)?.label || '未知';
 };
 
@@ -372,7 +360,7 @@ onMounted(()=>{
     <div class="mb-6 p-4 bg-white rounded-lg shadow-sm flex flex-wrap items-center gap-4">
       <el-form :inline="true" :model="searchForm" class="flex-grow flex flex-wrap gap-x-4">
         <el-form-item label="资产类型">
-          <el-select v-model="searchForm.assetType" placeholder="请选择资产类型" clearable>
+          <el-select style="width: 150px" v-model="searchForm.assetType" placeholder="请选择资产类型" clearable >
             <el-option
               v-for="item in assetTypeOptions"
               :key="item.value"
@@ -433,12 +421,12 @@ onMounted(()=>{
         <el-table-column prop="roomNumber" label="房间号/厂房编号" width="150" />
         <el-table-column prop="createTime" label="创建时间" width="180">
           <template #default="{ row }">
-            {{ row.createTime ? new Date(row.createTime).toLocaleString('sv-SE') : '-' }}
+            {{ row.createTime ? new Date(row.createTime).toLocaleString() : '-' }}
           </template>
         </el-table-column>
         <el-table-column prop="updateTime" label="修改时间" width="180">
           <template #default="{ row }">
-            {{ row.updateTime ? new Date(row.updateTime).toLocaleString('sv-SE') : '-' }}
+            {{ row.updateTime ? new Date(row.updateTime).toLocaleString() : '-' }}
           </template>
         </el-table-column>
         <el-table-column label="操作" width="150" fixed="right">