Ver código fonte

feat(zcgl): 添加资产附属设施管理功能

- 新增资产附属设施管理页面,实现设备信息的增删改查
- 添加设备类型和状态的下拉选项
- 实现文件导入导出功能
- 优化表格展示,增加分页和搜索功能
nahida 10 meses atrás
pai
commit
bbd2d4ec83
2 arquivos alterados com 1329 adições e 0 exclusões
  1. 584 0
      src/views/gzfxx/gain.vue
  2. 745 0
      src/views/zcgl/fsss.vue

+ 584 - 0
src/views/gzfxx/gain.vue

@@ -0,0 +1,584 @@
+<script setup lang="ts">
+import { onMounted, reactive, ref } from 'vue'
+import { clientDownloadExcel, clientGet, clientPost } from '@/utils/request.ts'
+import type { FormInstance, UploadProps } from 'element-plus'
+import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
+import { Delete, Download, Edit, Plus, Refresh, Search, 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 // 收据号
+  building?: string // 楼栋
+  roomNumber?: string // 房号
+  collectionTime?: Date // 收取时间
+  rent?: number // 房租
+  deposit?: number // 押金
+  waterFee?: number // 水费
+  electricityFee?: number // 电费
+  propertyManagementFee?: number // 物业管理费
+  rentPeriod?: string // 租金收取时段
+  handler?: string // 经手人
+  remarks?: string // 备注
+  createTime?: Date // 创建时间
+  createBy?: string // 创建人
+  updateTime?: Date // 修改时间
+  updateBy?: string // 修改人
+}
+
+interface PropertyOneResponse extends BaseResponse {
+  data: Property
+}
+
+interface PropertyListResponse extends BaseResponse {
+  data: PageType<Property>
+}
+
+interface AddProperty {
+  receiptNumber?: string // 收据号
+  building?: string // 楼栋
+  roomNumber?: string // 房号
+  collectionTime?: Date // 收取时间
+  rent?: number // 房租
+  deposit?: number // 押金
+  waterFee?: number // 水费
+  electricityFee?: number // 电费
+  propertyManagementFee?: number // 物业管理费
+  rentPeriod?: string // 租金收取时段
+  handler?: string // 经手人
+  remarks?: string // 备注
+}
+
+interface UpdateProperty {
+  id?: string
+  receiptNumber?: string // 收据号
+  building?: string // 楼栋
+  roomNumber?: string // 房号
+  collectionTime?: Date // 收取时间
+  rent?: number // 房租
+  deposit?: number // 押金
+  waterFee?: number // 水费
+  electricityFee?: number // 电费
+  propertyManagementFee?: number // 物业管理费
+  rentPeriod?: string // 租金收取时段
+  handler?: string // 经手人
+  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) => {
+  const res = await clientPost<AddProperty, BaseResponse>('/apublicRentalHousing/save', {
+    ...data,
+  })
+
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+
+  ElMessage.success(res.msg)
+  return true
+}
+
+//根据id获取数据
+const getById = async (id: string) => {
+  const res = await clientGet<null, PropertyOneResponse>('/apublicRentalHousing/getById/' + id)
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return null
+  }
+  return res.data
+}
+
+//分页获取数据
+const getList = async () => {
+  const res = await clientGet<
+    {
+      pageNum: number
+      pageSize: number
+      receiptNumber?: string
+      roomNumber?: string
+      building?: string
+    },
+    PropertyListResponse
+  >('/apublicRentalHousing/findByPage', {
+    params: {
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      building: searchForm.building || undefined,
+      roomNumber: searchForm.roomNumber || undefined,
+      receiptNumber: searchForm.receiptNumber || undefined,
+    },
+  })
+
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return
+  }
+  tableData.value = res.data.records
+  total.value = res.data.total
+}
+
+//批量删除
+const delBatch = async (ids: string[]) => {
+  // Note: clientPost expects the data directly, not JSON.stringify
+  const res = await clientPost<string[], BaseResponse>('/apublicRentalHousing/deleteBatch', ids)
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+  ElMessage.success(res.msg)
+  return true
+}
+
+//修改
+const update = async (data: UpdateProperty) => {
+  const res = await clientPost<UpdateProperty, BaseResponse>('/apublicRentalHousing/update', {
+    ...data,
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+  ElMessage.success(res.msg)
+  return true
+}
+
+//导出为excel
+const exportExcel = async () => {
+  const loading = ElLoading.service({
+    lock: true,
+    text: '导出中,请稍候...',
+    background: 'rgba(0, 0, 0, 0.1)',
+    fullscreen: true,
+  })
+
+  try {
+    await clientDownloadExcel('/apublicRentalHousing/exportData', {
+      params: {
+        roomNumber: searchForm.roomNumber || undefined,
+        building: searchForm.building || undefined,
+        receiptNumber: searchForm.receiptNumber || undefined,
+      },
+    })
+    ElMessage.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    ElMessage.error('导出失败')
+  } finally {
+    loading.close()
+  }
+}
+
+//excel导入
+const importExcel = async (file: File) => {
+  const formData = new FormData()
+  formData.append('file', file)
+  const res = await clientPost<FormData, BaseResponse>(
+    '/apublicRentalHousing/importData',
+    formData,
+    {
+      headers: {
+        'Content-Type': 'multipart/form-data',
+      },
+    },
+  )
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    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 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/apublicRentalHousing/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 max-h-200px">
+      <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>

+ 745 - 0
src/views/zcgl/fsss.vue

@@ -0,0 +1,745 @@
+<script setup lang="ts">
+import { onMounted, reactive, ref } from 'vue'
+import { clientDownloadExcel, clientGet, clientPost } from '@/utils/request.ts'
+import type { FormInstance, UploadProps } from 'element-plus'
+import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
+import { Delete, Download, Edit, Plus, Refresh, Search, Upload } from '@element-plus/icons-vue'
+
+interface Property {
+  id: string // 主键
+  assetCode?: string // 主资产编号
+  assetName?: string // 主资产名称
+  roomNumber?: string // 主房间号/厂房编号
+  equipmentName?: string // 设备名称
+  equipmentType?: string // 设备类型编码
+  modelNumber?: string // 设备型号
+  serialNumber?: string // 设备序列号
+  purchaseDate?: string // 采购日期 (改为string)
+  purchasePrice?: number // 采购价格
+  installationDate?: string // 安装启用日期 (改为string)
+  installationLocation?: string // 安装位置
+  manufacturer?: string // 生产厂家
+  warrantyPeriod?: number // 质保期限(月)
+  warrantyEndDate?: string // 质保到期日 (改为string)
+  maintenanceCycle?: number // 维护周期(月)
+  currentStatus?: string // 设备状态
+  lastMaintenanceDate?: string // 上次维护日期 (改为string)
+  nextMaintenanceDate?: string // 下次维护提醒日期 (改为string)
+  maintenanceCost?: number // 累计维护费用
+  repairRecord?: string // 维修记录摘要
+  operator?: string // 当前操作人员
+  remark?: string // 其他备注信息
+  createTime?: Date // 记录创建时间 (保持Date,仅用于显示)
+  createBy?: string // 创建人
+  updateTime?: Date // 最后更新时间 (保持Date,仅用于显示)
+  updateBy?: string // 修改人
+}
+
+interface PropertyOneResponse extends BaseResponse {
+  data: Property
+}
+
+interface PropertyListResponse extends BaseResponse {
+  data: PageType<Property>
+}
+
+interface AddProperty {
+  assetCode?: string // 主资产编号
+  assetName?: string // 主资产名称
+  roomNumber?: string // 主房间号/厂房编号
+  equipmentName?: string // 设备名称
+  equipmentType?: string // 设备类型编码
+  modelNumber?: string // 设备型号
+  serialNumber?: string // 设备序列号
+  purchaseDate?: string // 采购日期 (改为string)
+  purchasePrice?: number // 采购价格
+  installationDate?: string // 安装启用日期 (改为string)
+  installationLocation?: string // 安装位置
+  manufacturer?: string // 生产厂家
+  warrantyPeriod?: number // 质保期限(月)
+  warrantyEndDate?: string // 质保到期日 (改为string)
+  maintenanceCycle?: number // 维护周期(月)
+  currentStatus?: string // 设备状态
+  lastMaintenanceDate?: string // 上次维护日期 (改为string)
+  nextMaintenanceDate?: string // 下次维护提醒日期 (改为string)
+  maintenanceCost?: number // 累计维护费用
+  repairRecord?: string // 维修记录摘要
+  operator?: string // 当前操作人员
+  remark?: string // 其他备注信息
+}
+
+interface UpdateProperty {
+  id?: string
+  assetCode?: string // 主资产编号
+  assetName?: string // 主资产名称
+  roomNumber?: string // 主房间号/厂房编号
+  equipmentName?: string // 设备名称
+  equipmentType?: string // 设备类型编码
+  modelNumber?: string // 设备型号
+  serialNumber?: string // 设备序列号
+  purchaseDate?: string // 采购日期 (改为string)
+  purchasePrice?: number // 采购价格
+  installationDate?: string // 安装启用日期 (改为string)
+  installationLocation?: string // 安装位置
+  manufacturer?: string // 生产厂家
+  warrantyPeriod?: number // 质保期限(月)
+  warrantyEndDate?: string // 质保到期日 (改为string)
+  maintenanceCycle?: number // 维护周期(月)
+  currentStatus?: string // 设备状态
+  lastMaintenanceDate?: string // 上次维护日期 (改为string)
+  nextMaintenanceDate?: string // 下次维护提醒日期 (改为string)
+  maintenanceCost?: number // 累计维护费用
+  repairRecord?: string // 维修记录摘要
+  operator?: string // 当前操作人员
+  remark?: string // 其他备注信息
+}
+
+// Reactive state variables
+const tableData = ref<Property[]>([])
+const total = ref(0)
+const pageSize = ref(10)
+const pageNum = ref(1)
+
+const searchForm = reactive({
+  modelNumber: '',
+  equipmentType: '',
+  equipmentName: '',
+  assetCode: '',
+})
+
+const dialogVisible = ref(false)
+const dialogTitle = ref('')
+const isEdit = ref(false)
+const formData = reactive<Property>({})
+const formRef = ref<FormInstance>()
+const selectedIds = ref<string[]>([])
+
+// Options for select dropdowns
+const equipmentTypeOptions = [
+  { label: '空调', value: '空调' },
+  { label: '电梯', value: '电梯' },
+  { label: '消防设备', value: '消防设备' },
+  { label: '监控系统', value: '监控系统' },
+  { label: '照明设备', value: '照明设备' },
+  { label: '其他', value: '其他' },
+]
+
+const currentStatusOptions = [
+  { label: '正常运行', value: '正常运行' },
+  { label: '故障', value: '故障' },
+  { label: '维修中', value: '维修中' },
+  { label: '停用', value: '停用' },
+]
+
+// Helper to get label from value
+const getEquipmentTypeLabel = (value: string | undefined) => {
+  return equipmentTypeOptions.find((option) => option.value === value)?.label || '未知'
+}
+
+const getCurrentStatusLabel = (value: string | undefined) => {
+  return currentStatusOptions.find((option) => option.value === value)?.label || '未知'
+}
+
+//新增
+const add = async (data: AddProperty) => {
+  const res = await clientPost<AddProperty, BaseResponse>('/aequipmentManagement/save', {
+    ...data,
+  })
+
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+
+  ElMessage.success(res.msg)
+  return true
+}
+
+//根据id获取数据
+const getById = async (id: string) => {
+  const res = await clientGet<null, PropertyOneResponse>('/aequipmentManagement/getById/' + id)
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return null
+  }
+  return res.data
+}
+
+//分页获取数据
+const getList = async () => {
+  const res = await clientGet<
+    {
+      pageNum: number
+      pageSize: number
+      modelNumber?: string
+      equipmentType?: string
+      equipmentName?: string
+      assetCode?: string
+    },
+    PropertyListResponse
+  >('/aequipmentManagement/findByPage', {
+    params: {
+      pageNum: pageNum.value,
+      pageSize: pageSize.value,
+      modelNumber: searchForm.modelNumber || undefined,
+      equipmentType: searchForm.equipmentType || undefined,
+      equipmentName: searchForm.equipmentName || undefined,
+      assetCode: searchForm.assetCode || undefined,
+    },
+  })
+
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return
+  }
+  tableData.value = res.data.records
+  total.value = res.data.total
+}
+
+//批量删除
+const delBatch = async (ids: string[]) => {
+  const res = await clientPost<string[], BaseResponse>('/aequipmentManagement/deleteBatch', ids)
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+  ElMessage.success(res.msg)
+  return true
+}
+
+//修改
+const update = async (data: UpdateProperty) => {
+  const res = await clientPost<UpdateProperty, BaseResponse>('/aequipmentManagement/update', {
+    ...data,
+  })
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    return false
+  }
+  ElMessage.success(res.msg)
+  return true
+}
+
+//导出为excel
+const exportExcel = async () => {
+  const loading = ElLoading.service({
+    lock: true,
+    text: '导出中,请稍候...',
+    background: 'rgba(0, 0, 0, 0.1)',
+    fullscreen: true,
+  })
+
+  try {
+    await clientDownloadExcel('/aequipmentManagement/exportData', {
+      params: {
+        equipmentName: searchForm.equipmentName || undefined,
+        assetCode: searchForm.assetCode || undefined,
+        equipmentType: searchForm.equipmentType || undefined,
+        modelNumber: searchForm.modelNumber || undefined,
+      },
+    })
+    ElMessage.success('导出成功')
+  } catch (error) {
+    console.error('导出失败:', error)
+    ElMessage.error('导出失败')
+  } finally {
+    loading.close()
+  }
+}
+
+//excel导入
+const importExcel = async (file: File) => {
+  const formData = new FormData()
+  formData.append('file', file)
+  const res = await clientPost<FormData, BaseResponse>(
+    '/aequipmentManagement/importData',
+    formData,
+    {
+      headers: {
+        'Content-Type': 'multipart/form-data',
+      },
+    },
+  )
+  if (res.code !== 200) {
+    ElMessage.error(res.msg)
+    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.modelNumber = ''
+  searchForm.equipmentType = ''
+  searchForm.equipmentName = ''
+  searchForm.assetCode = ''
+  pageNum.value = 1
+  getList()
+}
+
+const handleConfirm = async () => {
+  if (!formRef.value) return
+  await formRef.value.validate(async (valid) => {
+    if (valid) {
+      let success = false
+      const dataToSend = { ...formData }
+
+      // Date fields are already strings from el-date-picker due to value-format
+      // No further formatting needed here.
+
+      if (isEdit.value) {
+        success = await update(dataToSend)
+      } else {
+        success = await add(dataToSend)
+      }
+      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)
+}
+
+const handleUploadSuccess: UploadProps['onSuccess'] = async (response, uploadFile) => {
+  if (response) {
+    ElMessage.success('文件导入成功')
+    getList()
+  } else {
+    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 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.assetCode" placeholder="请输入资产编号" clearable />
+        </el-form-item>
+        <el-form-item label="设备名称">
+          <el-input v-model="searchForm.equipmentName" placeholder="请输入设备名称" clearable />
+        </el-form-item>
+        <el-form-item label="设备类型">
+          <el-select
+            style="width: 150px"
+            v-model="searchForm.equipmentType"
+            placeholder="请选择设备类型"
+            clearable
+          >
+            <el-option
+              v-for="item in equipmentTypeOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="设备型号">
+          <el-input v-model="searchForm.modelNumber" 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/aequipmentManagement/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 overflow-x-auto">
+      <el-table
+        :data="tableData"
+        style="width: 100%"
+        border
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55" fixed="left" />
+        <el-table-column prop="assetCode" label="主资产编号" width="120" />
+        <el-table-column prop="assetName" label="主资产名称" width="150" />
+        <el-table-column prop="roomNumber" label="主房间号/厂房编号" width="180" />
+        <el-table-column prop="equipmentName" label="设备名称" width="150" />
+        <el-table-column prop="equipmentType" label="设备类型" width="100">
+          <template #default="{ row }">
+            {{ getEquipmentTypeLabel(row.equipmentType) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="modelNumber" label="设备型号" width="120" />
+        <el-table-column prop="serialNumber" label="设备序列号" width="150" />
+        <el-table-column prop="purchaseDate" label="采购日期" width="180">
+          <template #default="{ row }">
+            {{ row.purchaseDate ? new Date(row.purchaseDate).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="purchasePrice" label="采购价格(元)" width="120" />
+        <el-table-column prop="installationDate" label="安装启用日期" width="180">
+          <template #default="{ row }">
+            {{ row.installationDate ? new Date(row.installationDate).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="installationLocation" label="安装位置" width="150" />
+        <el-table-column prop="manufacturer" label="生产厂家" width="150" />
+        <el-table-column prop="warrantyPeriod" label="质保期限(月)" width="120" />
+        <el-table-column prop="warrantyEndDate" label="质保到期日" width="180">
+          <template #default="{ row }">
+            {{ row.warrantyEndDate ? new Date(row.warrantyEndDate).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="maintenanceCycle" label="维护周期(月)" width="120" />
+        <el-table-column prop="currentStatus" label="设备状态" width="100">
+          <template #default="{ row }">
+            {{ getCurrentStatusLabel(row.currentStatus) }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="lastMaintenanceDate" label="上次维护日期" width="180">
+          <template #default="{ row }">
+            {{ row.lastMaintenanceDate ? new Date(row.lastMaintenanceDate).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="nextMaintenanceDate" label="下次维护提醒日期" width="180">
+          <template #default="{ row }">
+            {{ row.nextMaintenanceDate ? new Date(row.nextMaintenanceDate).toLocaleString() : '-' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="maintenanceCost" label="累计维护费用(元)" width="150" />
+        <el-table-column prop="repairRecord" label="维修记录摘要" width="200" />
+        <el-table-column prop="operator" label="当前操作人员" width="120" />
+        <el-table-column prop="remark" label="其他备注信息" width="200" />
+        <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 prop="updateTime" label="最后更新时间" width="180">
+          <template #default="{ row }">
+            {{ row.updateTime ? new Date(row.updateTime).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="1200px"
+      :close-on-click-modal="false"
+      :close-on-press-escape="false"
+    >
+      <el-form
+        :model="formData"
+        ref="formRef"
+        label-width="150px"
+        class="grid grid-cols-2 md:grid-cols-3 gap-4"
+      >
+        <el-form-item label="主资产编号" prop="assetCode">
+          <el-input v-model="formData.assetCode" placeholder="请输入主资产编号" />
+        </el-form-item>
+        <el-form-item label="主资产名称" prop="assetName">
+          <el-input v-model="formData.assetName" placeholder="请输入主资产名称" />
+        </el-form-item>
+        <el-form-item label="主房间号/厂房编号" prop="roomNumber">
+          <el-input v-model="formData.roomNumber" placeholder="请输入主房间号或厂房编号" />
+        </el-form-item>
+        <el-form-item
+          label="设备名称"
+          prop="equipmentName"
+          :rules="[{ required: true, message: '请输入设备名称', trigger: 'blur' }]"
+        >
+          <el-input v-model="formData.equipmentName" placeholder="请输入设备名称" />
+        </el-form-item>
+        <el-form-item label="设备类型" prop="equipmentType">
+          <el-select
+            v-model="formData.equipmentType"
+            placeholder="请选择设备类型"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in equipmentTypeOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="设备型号" prop="modelNumber">
+          <el-input v-model="formData.modelNumber" placeholder="请输入设备型号" />
+        </el-form-item>
+        <el-form-item label="设备序列号" prop="serialNumber">
+          <el-input v-model="formData.serialNumber" placeholder="请输入设备序列号" />
+        </el-form-item>
+        <el-form-item label="采购日期" prop="purchaseDate">
+          <el-date-picker
+            v-model="formData.purchaseDate"
+            type="datetime"
+            placeholder="选择采购日期时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="采购价格(元)" prop="purchasePrice">
+          <el-input-number
+            v-model="formData.purchasePrice"
+            :min="0"
+            :precision="2"
+            :step="100"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="安装启用日期" prop="installationDate">
+          <el-date-picker
+            v-model="formData.installationDate"
+            type="datetime"
+            placeholder="选择安装启用日期时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="安装位置" prop="installationLocation">
+          <el-input v-model="formData.installationLocation" placeholder="请输入安装位置" />
+        </el-form-item>
+        <el-form-item label="生产厂家" prop="manufacturer">
+          <el-input v-model="formData.manufacturer" placeholder="请输入生产厂家" />
+        </el-form-item>
+        <el-form-item label="质保期限(月)" prop="warrantyPeriod">
+          <el-input-number
+            v-model="formData.warrantyPeriod"
+            :min="0"
+            :step="1"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="质保到期日" prop="warrantyEndDate">
+          <el-date-picker
+            v-model="formData.warrantyEndDate"
+            type="datetime"
+            placeholder="选择质保到期日期时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="维护周期(月)" prop="maintenanceCycle">
+          <el-input-number
+            v-model="formData.maintenanceCycle"
+            :min="0"
+            :step="1"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="设备状态" prop="currentStatus">
+          <el-select
+            v-model="formData.currentStatus"
+            placeholder="请选择设备状态"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in currentStatusOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="上次维护日期" prop="lastMaintenanceDate">
+          <el-date-picker
+            v-model="formData.lastMaintenanceDate"
+            type="datetime"
+            placeholder="选择上次维护日期时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="下次维护提醒日期" prop="nextMaintenanceDate">
+          <el-date-picker
+            v-model="formData.nextMaintenanceDate"
+            type="datetime"
+            placeholder="选择下次维护提醒日期时间"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="累计维护费用(元)" prop="maintenanceCost">
+          <el-input-number
+            v-model="formData.maintenanceCost"
+            :min="0"
+            :precision="2"
+            :step="10"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="维修记录摘要" prop="repairRecord" class="md:col-span-2">
+          <el-input
+            v-model="formData.repairRecord"
+            type="textarea"
+            placeholder="请输入维修记录摘要"
+          />
+        </el-form-item>
+        <el-form-item label="当前操作人员" prop="operator">
+          <el-input v-model="formData.operator" placeholder="请输入当前操作人员" />
+        </el-form-item>
+        <el-form-item label="其他备注信息" prop="remark" class="md:col-span-2">
+          <el-input v-model="formData.remark" 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>