Commit af1bcbd68a4ce5ee1285c14426759a06767033e3

Authored by wuxw
1 parent f0032091

房屋页面开发中

Showing 82 changed files with 4994 additions and 76 deletions
src/api/room/addFloorApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function addFloor(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/floor/saveFloor',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + resolve(response)
  11 + }).catch(error => {
  12 + reject(error)
  13 + })
  14 + })
  15 +}
0 \ No newline at end of file 16 \ No newline at end of file
src/api/room/addUnitApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function saveUnit(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/unit.saveUnit',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '添加单元失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/deleteFloorApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function deleteFloor(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/floor/deleteFloor',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + resolve(response)
  11 + }).catch(error => {
  12 + reject(error)
  13 + })
  14 + })
  15 +}
0 \ No newline at end of file 16 \ No newline at end of file
src/api/room/deleteRoomApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function deleteRoom(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/room.deleteRoom',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res.data)
  13 + } else {
  14 + reject(new Error(res.msg || '删除房屋失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/deleteUnitApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function deleteUnit(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/unit.deleteUnit',
  7 + method: 'post',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '删除单元失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/editFloorApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function editFloor(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/floor/editFloor',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + resolve(response)
  11 + }).catch(error => {
  12 + reject(error)
  13 + })
  14 + })
  15 +}
0 \ No newline at end of file 16 \ No newline at end of file
src/api/room/editRoomApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function updateRoom(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/room.updateRoom',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res.data)
  13 + } else {
  14 + reject(new Error(res.msg || '更新房屋失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
  21 +
  22 +export function getUnits(params) {
  23 + return new Promise((resolve, reject) => {
  24 + request({
  25 + url: '/unit.queryUnits',
  26 + method: 'get',
  27 + params
  28 + }).then(response => {
  29 + const res = response.data
  30 + if (res.code === 0) {
  31 + resolve(res.data)
  32 + } else {
  33 + reject(new Error(res.msg || '获取单元列表失败'))
  34 + }
  35 + }).catch(error => {
  36 + reject(error)
  37 + })
  38 + })
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
src/api/room/editUnitApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function updateUnit(data) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/unit.updateUnit',
  7 + method: 'post',
  8 + data
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '更新单元失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/floorUnitTreeApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function getFloorAndUnits(communityId) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/floor.queryFloorAndUnits',
  7 + method: 'get',
  8 + params: { communityId }
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res.data)
  13 + } else {
  14 + reject(new Error(res.msg || '获取楼栋单元失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/importOwnerRoomApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function importOwnerRoom(formData) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/assetImport/importData',
  7 + method: 'post',
  8 + data: formData,
  9 + headers: {
  10 + 'Content-Type': 'multipart/form-data'
  11 + }
  12 + }).then(response => {
  13 + resolve(response)
  14 + }).catch(error => {
  15 + reject(error)
  16 + })
  17 + })
  18 +}
0 \ No newline at end of file 19 \ No newline at end of file
src/api/room/ownerCarsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryOwnerCars(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/owner.queryOwnerCars',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '获取业主车辆失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/ownerComplaintsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listComplaints(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/complaint.listComplaints',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '获取业主投诉失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/ownerMembersApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryOwnerMembers(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/owner.queryOwnerMembers',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '获取业主成员失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/ownerOweFeesApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询业主欠费信息
  4 +export function getOwnerOweFees(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/reportOweFee/queryReportOweFee',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '获取业主欠费信息失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
0 \ No newline at end of file 22 \ No newline at end of file
src/api/room/ownerRepairsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function listOwnerRepairs(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/ownerRepair.listOwnerRepairs',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res)
  13 + } else {
  14 + reject(new Error(res.msg || '获取业主报修失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/ownerRoomsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function queryRoomsByOwner(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/room.queryRoomsByOwner',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res.data)
  13 + } else {
  14 + reject(new Error(res.msg || '获取业主房屋失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/api/room/roomApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询房屋列表
  4 +export function queryRooms(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/room.queryRooms',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '获取房屋列表失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
  22 +
  23 +// 查询楼栋列表
  24 +export function getFloors(params) {
  25 + return new Promise((resolve, reject) => {
  26 + request({
  27 + url: '/floor.queryFloors',
  28 + method: 'get',
  29 + params
  30 + }).then(response => {
  31 + const res = response.data
  32 + if (res.code === 0) {
  33 + resolve(res)
  34 + } else {
  35 + reject(new Error(res.msg || '获取楼栋列表失败'))
  36 + }
  37 + }).catch(error => {
  38 + reject(error)
  39 + })
  40 + })
  41 +}
  42 +
  43 +// 查询单元列表
  44 +export function getUnits(params) {
  45 + return new Promise((resolve, reject) => {
  46 + request({
  47 + url: '/unit.queryUnits',
  48 + method: 'get',
  49 + params
  50 + }).then(response => {
  51 + const res = response.data
  52 + if (res.code === 0) {
  53 + resolve(res)
  54 + } else {
  55 + reject(new Error(res.msg || '获取单元列表失败'))
  56 + }
  57 + }).catch(error => {
  58 + reject(error)
  59 + })
  60 + })
  61 +}
0 \ No newline at end of file 62 \ No newline at end of file
src/api/room/roomContractsApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询房屋合同信息
  4 +export function getRoomContracts(params, roomId) {
  5 + return new Promise((resolve, reject) => {
  6 + const url = roomId ? '/contract.queryContractByRoomId' : '/contract/queryContract'
  7 +
  8 + request({
  9 + url,
  10 + method: 'get',
  11 + params
  12 + }).then(response => {
  13 + const res = response.data
  14 + if (res.code === 0) {
  15 + resolve(res)
  16 + } else {
  17 + reject(new Error(res.msg || '获取房屋合同信息失败'))
  18 + }
  19 + }).catch(error => {
  20 + reject(error)
  21 + })
  22 + })
  23 +}
0 \ No newline at end of file 24 \ No newline at end of file
src/api/room/roomOweFeesApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 查询房屋欠费信息
  4 +export function getRoomOweFees(params) {
  5 + return new Promise((resolve, reject) => {
  6 + request({
  7 + url: '/reportOweFee/queryReportOweFee',
  8 + method: 'get',
  9 + params
  10 + }).then(response => {
  11 + const res = response.data
  12 + if (res.code === 0) {
  13 + resolve(res)
  14 + } else {
  15 + reject(new Error(res.msg || '获取房屋欠费信息失败'))
  16 + }
  17 + }).catch(error => {
  18 + reject(error)
  19 + })
  20 + })
  21 +}
0 \ No newline at end of file 22 \ No newline at end of file
src/api/room/searchFloorApi.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +export function searchFloors(params) {
  4 + return new Promise((resolve, reject) => {
  5 + request({
  6 + url: '/floor.queryFloors',
  7 + method: 'get',
  8 + params
  9 + }).then(response => {
  10 + const res = response.data
  11 + if (res.code === 0) {
  12 + resolve(res.data)
  13 + } else {
  14 + reject(new Error(res.msg || '查询楼栋失败'))
  15 + }
  16 + }).catch(error => {
  17 + reject(error)
  18 + })
  19 + })
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/components/owner/ownerCars.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="dialogVisible"
  4 + :title="$t('ownerCars.title')"
  5 + width="80%"
  6 + top="5vh"
  7 + @close="handleClose"
  8 + >
  9 + <el-row>
  10 + <el-col :span="24">
  11 + <div class="table-container">
  12 + <el-table :data="ownerCarsInfo.cars" border stripe>
  13 + <el-table-column prop="carNum" :label="$t('ownerCars.licensePlate')" align="center" />
  14 + <el-table-column :label="$t('ownerCars.licenseType')" align="center">
  15 + <template #default="{ row }">
  16 + <span v-if="row.leaseType === 'T'">{{ $t('ownerCars.temporary') }}</span>
  17 + <span v-else>{{ row.leaseTypeName }}</span>
  18 + </template>
  19 + </el-table-column>
  20 + <el-table-column prop="carTypeName" :label="$t('ownerCars.carType')" align="center" />
  21 + <el-table-column prop="carColor" :label="$t('ownerCars.color')" align="center" />
  22 + <el-table-column :label="$t('ownerCars.owner')" align="center">
  23 + <template #default="{ row }">
  24 + {{ row.ownerName }}<br>({{ row.link }})
  25 + </template>
  26 + </el-table-column>
  27 + <el-table-column :label="$t('ownerCars.parkingSpace')" align="center">
  28 + <template #default="{ row }">
  29 + <div v-if="row.areaNum && row.state === '1001'">
  30 + {{ row.areaNum }}{{ $t('ownerCars.park') }}{{ row.num }}{{ $t('ownerCars.space') }}
  31 + </div>
  32 + <div v-else>{{ $t('ownerCars.released') }}</div>
  33 + </template>
  34 + </el-table-column>
  35 + <el-table-column :label="$t('ownerCars.validity')" align="center">
  36 + <template #default="{ row }">
  37 + <div v-if="row.leaseType === 'H'">
  38 + {{ row.startTime }}<br>~{{ row.endTime }}
  39 + </div>
  40 + <div v-else>-</div>
  41 + </template>
  42 + </el-table-column>
  43 + </el-table>
  44 + </div>
  45 + <el-pagination
  46 + background
  47 + layout="prev, pager, next, sizes, total"
  48 + :total="totalCount"
  49 + :page-size="pageSize"
  50 + :current-page="currentPage"
  51 + @size-change="handleSizeChange"
  52 + @current-change="handleCurrentChange"
  53 + />
  54 + </el-col>
  55 + </el-row>
  56 + </el-dialog>
  57 +</template>
  58 +
  59 +<script>
  60 +import { queryOwnerCars } from '@/api/room/ownerCarsApi'
  61 +
  62 +export default {
  63 + name: 'OwnerCars',
  64 + data() {
  65 + return {
  66 + dialogVisible: false,
  67 + ownerCarsInfo: {
  68 + cars: [],
  69 + ownerId: ''
  70 + },
  71 + totalCount: 0,
  72 + pageSize: 10,
  73 + currentPage: 1
  74 + }
  75 + },
  76 + methods: {
  77 + open(ownerId) {
  78 + this.ownerCarsInfo.ownerId = ownerId
  79 + this.dialogVisible = true
  80 + this._loadOwnerCarInfo(1, this.pageSize)
  81 + },
  82 + handleClose() {
  83 + this.dialogVisible = false
  84 + },
  85 + handleSizeChange(size) {
  86 + this.pageSize = size
  87 + this._loadOwnerCarInfo(this.currentPage, size)
  88 + },
  89 + handleCurrentChange(page) {
  90 + this.currentPage = page
  91 + this._loadOwnerCarInfo(page, this.pageSize)
  92 + },
  93 + async _loadOwnerCarInfo(page, size) {
  94 + try {
  95 + const params = {
  96 + page: page,
  97 + row: size,
  98 + communityId: this.$store.getters.communityId,
  99 + ownerId: this.ownerCarsInfo.ownerId
  100 + }
  101 +
  102 + const response = await queryOwnerCars(params)
  103 + this.ownerCarsInfo.cars = response.data
  104 + this.totalCount = response.total
  105 + this.currentPage = page
  106 + } catch (error) {
  107 + console.error('加载业主车辆信息失败:', error)
  108 + }
  109 + }
  110 + }
  111 +}
  112 +</script>
  113 +
  114 +<style scoped>
  115 +.table-container {
  116 + margin-top: 15px;
  117 +}
  118 +</style>
0 \ No newline at end of file 119 \ No newline at end of file
src/components/owner/ownerCarsDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openOwnerCars">查看业主车辆</el-button>
  4 + <owner-cars ref="ownerCarsRef" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import OwnerCars from './ownerCars'
  10 +
  11 +export default {
  12 + components: {
  13 + OwnerCars
  14 + },
  15 + methods: {
  16 + openOwnerCars() {
  17 + this.$refs.ownerCarsRef.open('456') // 传递业主ID
  18 + }
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/owner/ownerComplaints.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="dialogVisible"
  4 + :title="$t('ownerComplaints.title')"
  5 + width="80%"
  6 + top="5vh"
  7 + @close="handleClose"
  8 + >
  9 + <el-row>
  10 + <el-col :span="24">
  11 + <div class="table-container">
  12 + <el-table :data="ownerComplaintsInfo.complaints" border stripe>
  13 + <el-table-column prop="typeCdName" :label="$t('ownerComplaints.type')" align="center" />
  14 + <el-table-column :label="$t('ownerComplaints.room')" align="center">
  15 + <template #default="{ row }">
  16 + {{ row.floorNum }}-{{ row.unitNum }}-{{ row.roomNum }}
  17 + </template>
  18 + </el-table-column>
  19 + <el-table-column prop="complaintName" :label="$t('ownerComplaints.contact')" align="center" />
  20 + <el-table-column prop="tel" :label="$t('ownerComplaints.phone')" align="center" />
  21 + <el-table-column prop="stateName" :label="$t('ownerComplaints.status')" align="center" />
  22 + <el-table-column :label="$t('ownerComplaints.handler')" align="center">
  23 + <template #default="{ row }">
  24 + {{ row.currentUserName || $t('ownerComplaints.none') }}
  25 + </template>
  26 + </el-table-column>
  27 + <el-table-column :label="$t('ownerComplaints.handlerPhone')" align="center">
  28 + <template #default="{ row }">
  29 + {{ row.currentUserTel || $t('ownerComplaints.none') }}
  30 + </template>
  31 + </el-table-column>
  32 + <el-table-column prop="createTime" :label="$t('ownerComplaints.createTime')" align="center" />
  33 + </el-table>
  34 + </div>
  35 + <el-pagination
  36 + background
  37 + layout="prev, pager, next, sizes, total"
  38 + :total="totalCount"
  39 + :page-size="pageSize"
  40 + :current-page="currentPage"
  41 + @size-change="handleSizeChange"
  42 + @current-change="handleCurrentChange"
  43 + />
  44 + </el-col>
  45 + </el-row>
  46 + </el-dialog>
  47 +</template>
  48 +
  49 +<script>
  50 +import { listComplaints } from '@/api/room/ownerComplaintsApi'
  51 +
  52 +export default {
  53 + name: 'OwnerComplaints',
  54 + data() {
  55 + return {
  56 + dialogVisible: false,
  57 + ownerComplaintsInfo: {
  58 + complaints: [],
  59 + ownerId: ''
  60 + },
  61 + totalCount: 0,
  62 + pageSize: 10,
  63 + currentPage: 1
  64 + }
  65 + },
  66 + methods: {
  67 + open(ownerId) {
  68 + this.ownerComplaintsInfo.ownerId = ownerId
  69 + this.dialogVisible = true
  70 + this._loadOwnerComplaintInfo(1, this.pageSize)
  71 + },
  72 + handleClose() {
  73 + this.dialogVisible = false
  74 + },
  75 + handleSizeChange(size) {
  76 + this.pageSize = size
  77 + this._loadOwnerComplaintInfo(this.currentPage, size)
  78 + },
  79 + handleCurrentChange(page) {
  80 + this.currentPage = page
  81 + this._loadOwnerComplaintInfo(page, this.pageSize)
  82 + },
  83 + async _loadOwnerComplaintInfo(page, size) {
  84 + try {
  85 + const params = {
  86 + page: page,
  87 + row: size,
  88 + communityId: this.$store.getters.communityId,
  89 + ownerId: this.ownerComplaintsInfo.ownerId
  90 + }
  91 +
  92 + const response = await listComplaints(params)
  93 + this.ownerComplaintsInfo.complaints = response.data
  94 + this.totalCount = response.total
  95 + this.currentPage = page
  96 + } catch (error) {
  97 + console.error('加载业主投诉信息失败:', error)
  98 + }
  99 + }
  100 + }
  101 +}
  102 +</script>
  103 +
  104 +<style scoped>
  105 +.table-container {
  106 + margin-top: 15px;
  107 +}
  108 +</style>
0 \ No newline at end of file 109 \ No newline at end of file
src/components/owner/ownerComplaintsDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openOwnerComplaints">查看业主投诉</el-button>
  4 + <owner-complaints ref="ownerComplaintsRef" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import OwnerComplaints from './ownerComplaints'
  10 +
  11 +export default {
  12 + components: {
  13 + OwnerComplaints
  14 + },
  15 + methods: {
  16 + openOwnerComplaints() {
  17 + this.$refs.ownerComplaintsRef.open('789') // 传递业主ID
  18 + }
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/owner/ownerMembers.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="dialogVisible"
  4 + :title="$t('ownerMembers.title')"
  5 + width="80%"
  6 + top="5vh"
  7 + @close="handleClose"
  8 + >
  9 + <el-row>
  10 + <el-col :span="24">
  11 + <div class="table-container">
  12 + <el-table :data="ownerMembersInfo.members" border stripe>
  13 + <el-table-column prop="name" :label="$t('ownerMembers.name')" align="center" />
  14 + <el-table-column prop="sex" :label="$t('ownerMembers.sex')" align="center">
  15 + <template #default="{ row }">
  16 + {{ row.sex == 0 ? $t('ownerMembers.male') : $t('ownerMembers.female') }}
  17 + </template>
  18 + </el-table-column>
  19 + <el-table-column prop="age" :label="$t('ownerMembers.age')" align="center" />
  20 + <el-table-column prop="ownerTypeName" :label="$t('ownerMembers.type')" align="center" />
  21 + <el-table-column prop="idCard" :label="$t('ownerMembers.idCard')" align="center" />
  22 + <el-table-column prop="link" :label="$t('ownerMembers.contact')" align="center" />
  23 + <el-table-column prop="address" :label="$t('ownerMembers.address')" align="center" />
  24 + </el-table>
  25 + </div>
  26 + <el-pagination
  27 + background
  28 + layout="prev, pager, next, sizes, total"
  29 + :total="totalCount"
  30 + :page-size="pageSize"
  31 + :current-page="currentPage"
  32 + @size-change="handleSizeChange"
  33 + @current-change="handleCurrentChange"
  34 + />
  35 + </el-col>
  36 + </el-row>
  37 + </el-dialog>
  38 +</template>
  39 +
  40 +<script>
  41 +import { queryOwnerMembers } from '@/api/room/ownerMembersApi'
  42 +
  43 +export default {
  44 + name: 'OwnerMembers',
  45 + data() {
  46 + return {
  47 + dialogVisible: false,
  48 + ownerMembersInfo: {
  49 + members: [],
  50 + ownerId: ''
  51 + },
  52 + totalCount: 0,
  53 + pageSize: 10,
  54 + currentPage: 1
  55 + }
  56 + },
  57 + methods: {
  58 + open(ownerId) {
  59 + this.ownerMembersInfo.ownerId = ownerId
  60 + this.dialogVisible = true
  61 + this._loadOwnerMemberInfo(1, this.pageSize)
  62 + },
  63 + handleClose() {
  64 + this.dialogVisible = false
  65 + },
  66 + handleSizeChange(size) {
  67 + this.pageSize = size
  68 + this._loadOwnerMemberInfo(this.currentPage, size)
  69 + },
  70 + handleCurrentChange(page) {
  71 + this.currentPage = page
  72 + this._loadOwnerMemberInfo(page, this.pageSize)
  73 + },
  74 + async _loadOwnerMemberInfo(page, size) {
  75 + try {
  76 + const params = {
  77 + page: page,
  78 + row: size,
  79 + communityId: this.$store.getters.communityId,
  80 + ownerId: this.ownerMembersInfo.ownerId
  81 + }
  82 +
  83 + const response = await queryOwnerMembers(params)
  84 + this.ownerMembersInfo.members = response.data
  85 + this.totalCount = response.total
  86 + this.currentPage = page
  87 + } catch (error) {
  88 + console.error('加载业主成员信息失败:', error)
  89 + }
  90 + }
  91 + }
  92 +}
  93 +</script>
  94 +
  95 +<style scoped>
  96 +.table-container {
  97 + margin-top: 15px;
  98 +}
  99 +</style>
0 \ No newline at end of file 100 \ No newline at end of file
src/components/owner/ownerMembersDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openOwnerMembers">查看业主成员</el-button>
  4 + <owner-members ref="ownerMembersRef" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import OwnerMembers from './ownerMembers'
  10 +
  11 +export default {
  12 + components: {
  13 + OwnerMembers
  14 + },
  15 + methods: {
  16 + openOwnerMembers() {
  17 + this.$refs.ownerMembersRef.open('123') // 传递业主ID
  18 + }
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/owner/ownerOweFees.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="visible"
  4 + :title="$t('ownerOweFees.title')"
  5 + width="80%"
  6 + top="5vh"
  7 + custom-class="custom-modal"
  8 + @close="handleClose"
  9 + >
  10 + <el-table
  11 + :data="ownerOweFeesInfo.fees"
  12 + stripe
  13 + border
  14 + style="width: 100%; margin-top: 15px"
  15 + >
  16 + <el-table-column
  17 + prop="payerObjName"
  18 + :label="$t('ownerOweFees.payerObj')"
  19 + align="center"
  20 + />
  21 + <el-table-column
  22 + prop="ownerName"
  23 + :label="$t('ownerOweFees.ownerName')"
  24 + align="center"
  25 + />
  26 + <el-table-column
  27 + prop="ownerTel"
  28 + :label="$t('ownerOweFees.phone')"
  29 + align="center"
  30 + />
  31 + <el-table-column
  32 + prop="endTime"
  33 + :label="$t('ownerOweFees.startTime')"
  34 + align="center"
  35 + />
  36 + <el-table-column
  37 + prop="deadlineTime"
  38 + :label="$t('ownerOweFees.endTime')"
  39 + align="center"
  40 + />
  41 + <el-table-column
  42 + prop="amountOwed"
  43 + :label="`${$t('ownerOweFees.total')} (${$t('ownerOweFees.unit')})`"
  44 + align="center"
  45 + />
  46 + <el-table-column
  47 + prop="updateTime"
  48 + :label="$t('ownerOweFees.updateTime')"
  49 + align="center"
  50 + />
  51 + </el-table>
  52 +
  53 + <el-pagination
  54 + v-if="pagination.total > 0"
  55 + background
  56 + layout="prev, pager, next"
  57 + :total="pagination.total"
  58 + :page-size="pagination.pageSize"
  59 + :current-page="pagination.currentPage"
  60 + @current-change="handlePageChange"
  61 + style="margin-top: 20px; text-align: right"
  62 + />
  63 + </el-dialog>
  64 +</template>
  65 +
  66 +<script>
  67 +import { getOwnerOweFees } from '@/api/room/ownerOweFeesApi'
  68 +
  69 +export default {
  70 + name: 'OwnerOweFees',
  71 + data() {
  72 + return {
  73 + visible: false,
  74 + ownerOweFeesInfo: {
  75 + fees: [],
  76 + ownerId: ''
  77 + },
  78 + pagination: {
  79 + total: 0,
  80 + pageSize: 10,
  81 + currentPage: 1
  82 + }
  83 + }
  84 + },
  85 + methods: {
  86 + open(ownerId) {
  87 + this.ownerOweFeesInfo.ownerId = ownerId
  88 + this.pagination.currentPage = 1
  89 + this.visible = true
  90 + this.loadData()
  91 + },
  92 + handleClose() {
  93 + this.visible = false
  94 + },
  95 + handlePageChange(currentPage) {
  96 + this.pagination.currentPage = currentPage
  97 + this.loadData()
  98 + },
  99 + async loadData() {
  100 + try {
  101 + const params = {
  102 + page: this.pagination.currentPage,
  103 + row: this.pagination.pageSize,
  104 + communityId: this.getCommunityId(),
  105 + ownerId: this.ownerOweFeesInfo.ownerId
  106 + }
  107 +
  108 + const response = await getOwnerOweFees(params)
  109 + this.ownerOweFeesInfo.fees = response.data
  110 + this.pagination.total = response.records
  111 + } catch (error) {
  112 + console.error('加载欠费信息失败:', error)
  113 + this.$message.error(this.$t('common.loadFailed'))
  114 + }
  115 + },
  116 + getCommunityId() {
  117 + return this.$store.state.user.currentCommunity.communityId
  118 + }
  119 + }
  120 +}
  121 +</script>
  122 +
  123 +<style scoped>
  124 +.custom-modal >>> .el-dialog__body {
  125 + padding: 15px 20px;
  126 +}
  127 +</style>
0 \ No newline at end of file 128 \ No newline at end of file
src/components/owner/ownerOweFeesDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="primary" @click="openModal">
  4 + {{ $t('ownerOweFeesDemo.openBtn') }}
  5 + </el-button>
  6 + <owner-owe-fees ref="oweFeesRef" />
  7 + </div>
  8 +</template>
  9 +
  10 +<script>
  11 +import OwnerOweFees from './ownerOweFees'
  12 +
  13 +export default {
  14 + components: {
  15 + OwnerOweFees
  16 + },
  17 + methods: {
  18 + openModal() {
  19 + // 模拟业主ID
  20 + const ownerId = '12345'
  21 + this.$refs.oweFeesRef.open(ownerId)
  22 + }
  23 + }
  24 +}
  25 +</script>
0 \ No newline at end of file 26 \ No newline at end of file
src/components/owner/ownerRepairs.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="dialogVisible"
  4 + :title="$t('ownerRepairs.title')"
  5 + width="80%"
  6 + top="5vh"
  7 + @close="handleClose"
  8 + >
  9 + <el-row>
  10 + <el-col :span="24">
  11 + <div class="table-container">
  12 + <el-table :data="ownerRepairsInfo.repairs" border stripe>
  13 + <el-table-column prop="repairId" :label="$t('ownerRepairs.workOrder')" align="center" />
  14 + <el-table-column prop="repairObjName" :label="$t('ownerRepairs.location')" align="center" />
  15 + <el-table-column prop="repairTypeName" :label="$t('ownerRepairs.repairType')" align="center" />
  16 + <el-table-column prop="repairName" :label="$t('ownerRepairs.reporter')" align="center" />
  17 + <el-table-column prop="tel" :label="$t('ownerRepairs.contact')" align="center" />
  18 + <el-table-column prop="appointmentTime" :label="$t('ownerRepairs.appointmentTime')" align="center" />
  19 + <el-table-column :label="$t('ownerRepairs.status')" align="center">
  20 + <template #default="{ row }">
  21 + <span v-if="row.state === '1800' && (row.returnVisitFlag === '001' || row.returnVisitFlag === '002')">
  22 + {{ row.stateName }}{{ $t('ownerRepairs.taskProcessed') }}
  23 + </span>
  24 + <span v-else>
  25 + {{ row.stateName }}
  26 + </span>
  27 + </template>
  28 + </el-table-column>
  29 + </el-table>
  30 + </div>
  31 + <el-pagination
  32 + background
  33 + layout="prev, pager, next, sizes, total"
  34 + :total="totalCount"
  35 + :page-size="pageSize"
  36 + :current-page="currentPage"
  37 + @size-change="handleSizeChange"
  38 + @current-change="handleCurrentChange"
  39 + />
  40 + </el-col>
  41 + </el-row>
  42 + </el-dialog>
  43 +</template>
  44 +
  45 +<script>
  46 +import { listOwnerRepairs } from '@/api/room/ownerRepairsApi'
  47 +
  48 +export default {
  49 + name: 'OwnerRepairs',
  50 + data() {
  51 + return {
  52 + dialogVisible: false,
  53 + ownerRepairsInfo: {
  54 + repairs: [],
  55 + ownerId: ''
  56 + },
  57 + totalCount: 0,
  58 + pageSize: 10,
  59 + currentPage: 1
  60 + }
  61 + },
  62 + methods: {
  63 + open(ownerId) {
  64 + this.ownerRepairsInfo.ownerId = ownerId
  65 + this.dialogVisible = true
  66 + this._loadOwnerRepairInfo(1, this.pageSize)
  67 + },
  68 + handleClose() {
  69 + this.dialogVisible = false
  70 + },
  71 + handleSizeChange(size) {
  72 + this.pageSize = size
  73 + this._loadOwnerRepairInfo(this.currentPage, size)
  74 + },
  75 + handleCurrentChange(page) {
  76 + this.currentPage = page
  77 + this._loadOwnerRepairInfo(page, this.pageSize)
  78 + },
  79 + async _loadOwnerRepairInfo(page, size) {
  80 + try {
  81 + const params = {
  82 + page: page,
  83 + row: size,
  84 + communityId: this.$store.getters.communityId,
  85 + ownerId: this.ownerRepairsInfo.ownerId
  86 + }
  87 +
  88 + const response = await listOwnerRepairs(params)
  89 + this.ownerRepairsInfo.repairs = response.data
  90 + this.totalCount = response.total
  91 + this.currentPage = page
  92 + } catch (error) {
  93 + console.error('加载业主报修信息失败:', error)
  94 + }
  95 + }
  96 + }
  97 +}
  98 +</script>
  99 +
  100 +<style scoped>
  101 +.table-container {
  102 + margin-top: 15px;
  103 +}
  104 +</style>
0 \ No newline at end of file 105 \ No newline at end of file
src/components/owner/ownerRepairsDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openOwnerRepairs">查看业主报修</el-button>
  4 + <owner-repairs ref="ownerRepairsRef" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import OwnerRepairs from './ownerRepairs'
  10 +
  11 +export default {
  12 + components: {
  13 + OwnerRepairs
  14 + },
  15 + methods: {
  16 + openOwnerRepairs() {
  17 + this.$refs.ownerRepairsRef.open('101') // 传递业主ID
  18 + }
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/owner/ownerRooms.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('ownerRooms.title')"
  4 + :visible.sync="visible"
  5 + width="70%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-table :data="ownerRoomsInfo.rooms" style="width: 100%">
  9 + <el-table-column prop="roomId" :label="$t('ownerRooms.roomId')" align="center" />
  10 + <el-table-column prop="layer" :label="$t('ownerRooms.layer')" align="center" />
  11 + <el-table-column prop="roomSubTypeName" :label="$t('ownerRooms.type')" align="center" />
  12 + <el-table-column :label="$t('ownerRooms.area')" align="center">
  13 + <template slot-scope="scope">
  14 + {{ scope.row.builtUpArea }}/{{ scope.row.roomArea }}
  15 + </template>
  16 + </el-table-column>
  17 + <el-table-column prop="roomRent" :label="$t('ownerRooms.rent')" align="center" />
  18 + <el-table-column prop="stateName" :label="$t('ownerRooms.status')" align="center" />
  19 + <el-table-column :label="$t('ownerRooms.oweFee')" align="center">
  20 + <template slot-scope="scope">
  21 + {{ scope.row.roomOweFee || '0.00' }} ({{ $t('ownerRooms.updateDaily') }})
  22 + </template>
  23 + </el-table-column>
  24 + </el-table>
  25 +
  26 + <el-row class="mt-3">
  27 + <el-col :span="8">
  28 + <span>{{ $t('ownerRooms.subtotal') }}: {{ ownerRoomsInfo.allOweFeeAmount }}</span>
  29 + </el-col>
  30 + <el-col :span="16" class="text-right">
  31 + <el-pagination
  32 + :current-page="pagination.currentPage"
  33 + :page-size="pagination.pageSize"
  34 + :total="pagination.total"
  35 + layout="prev, pager, next"
  36 + @current-change="handlePageChange"
  37 + />
  38 + </el-col>
  39 + </el-row>
  40 + </el-dialog>
  41 +</template>
  42 +
  43 +<script>
  44 +import { queryRoomsByOwner } from '@/api/room/ownerRoomsApi'
  45 +
  46 +export default {
  47 + name: 'OwnerRooms',
  48 + data() {
  49 + return {
  50 + visible: false,
  51 + ownerRoomsInfo: {
  52 + rooms: [],
  53 + ownerId: '',
  54 + allOweFeeAmount: 0
  55 + },
  56 + pagination: {
  57 + currentPage: 1,
  58 + pageSize: 10,
  59 + total: 0
  60 + }
  61 + }
  62 + },
  63 + methods: {
  64 + open(params) {
  65 + this.ownerRoomsInfo.ownerId = params.ownerId
  66 + this.visible = true
  67 + this.loadOwnerRoomInfo()
  68 + },
  69 + handleClose() {
  70 + this.visible = false
  71 + },
  72 + handlePageChange(page) {
  73 + this.pagination.currentPage = page
  74 + this.loadOwnerRoomInfo()
  75 + },
  76 + async loadOwnerRoomInfo() {
  77 + try {
  78 + const params = {
  79 + page: this.pagination.currentPage,
  80 + row: this.pagination.pageSize,
  81 + communityId: this.getCommunityId(),
  82 + ownerId: this.ownerRoomsInfo.ownerId
  83 + }
  84 +
  85 + const response = await queryRoomsByOwner(params)
  86 + this.ownerRoomsInfo.rooms = response.rooms
  87 + this.pagination.total = response.total || 0
  88 + this.computeOwnerRoomOweFeeAmount()
  89 + } catch (error) {
  90 + console.error('加载业主房屋信息失败:', error)
  91 + }
  92 + },
  93 + computeOwnerRoomOweFeeAmount() {
  94 + let totalOweFeeAmount = 0
  95 + this.ownerRoomsInfo.rooms.forEach(room => {
  96 + if (room.roomOweFee) {
  97 + totalOweFeeAmount += parseFloat(room.roomOweFee)
  98 + }
  99 + })
  100 + this.ownerRoomsInfo.allOweFeeAmount = totalOweFeeAmount.toFixed(2)
  101 + }
  102 + }
  103 +}
  104 +</script>
0 \ No newline at end of file 105 \ No newline at end of file
src/components/room/addFloor.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.addFloor.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  9 + <el-form-item :label="$t('room.addFloor.floorNum')" prop="floorNum">
  10 + <el-input v-model="form.floorNum" :placeholder="$t('room.addFloor.floorNumPlaceholder')" />
  11 + </el-form-item>
  12 +
  13 + <el-form-item :label="$t('room.addFloor.name')" prop="name">
  14 + <el-input v-model="form.name" :placeholder="$t('room.addFloor.namePlaceholder')" />
  15 + </el-form-item>
  16 +
  17 + <el-form-item :label="$t('room.addFloor.floorArea')" prop="floorArea">
  18 + <el-input v-model="form.floorArea" :placeholder="$t('room.addFloor.floorAreaPlaceholder')">
  19 + <template slot="append">m²</template>
  20 + </el-input>
  21 + </el-form-item>
  22 +
  23 + <el-form-item :label="$t('room.addFloor.seq')" prop="seq">
  24 + <el-input-number v-model="form.seq" :min="1" />
  25 + </el-form-item>
  26 +
  27 + <el-form-item :label="$t('room.addFloor.remark')" prop="remark">
  28 + <el-input v-model="form.remark" type="textarea" :placeholder="$t('room.addFloor.remarkPlaceholder')" />
  29 + </el-form-item>
  30 +
  31 + <el-alert v-if="errorInfo" :title="errorInfo" type="error" show-icon />
  32 + </el-form>
  33 +
  34 + <span slot="footer" class="dialog-footer">
  35 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  36 + <el-button type="primary" @click="handleSave">{{ $t('common.save') }}</el-button>
  37 + </span>
  38 + </el-dialog>
  39 +</template>
  40 +
  41 +<script>
  42 +import { addFloor } from '@/api/room/addFloorApi'
  43 +
  44 +export default {
  45 + name: 'AddFloor',
  46 + props: {
  47 + callBackListener: String,
  48 + callBackFunction: String
  49 + },
  50 + data() {
  51 + return {
  52 + visible: false,
  53 + form: {
  54 + communityId: this.getCommunityId(),
  55 + floorNum: '',
  56 + name: '',
  57 + floorArea: '',
  58 + seq: 1,
  59 + remark: ''
  60 + },
  61 + errorInfo: '',
  62 + rules: {
  63 + floorNum: [
  64 + { required: true, message: this.$t('room.addFloor.floorNumRequired'), trigger: 'blur' },
  65 + { min: 1, max: 64, message: this.$t('room.addFloor.floorNumLength'), trigger: 'blur' }
  66 + ],
  67 + name: [
  68 + { required: true, message: this.$t('room.addFloor.nameRequired'), trigger: 'blur' },
  69 + { min: 2, max: 64, message: this.$t('room.addFloor.nameLength'), trigger: 'blur' }
  70 + ],
  71 + floorArea: [
  72 + { required: true, message: this.$t('room.addFloor.floorAreaRequired'), trigger: 'blur' },
  73 + { pattern: /^\d+(\.\d{1,2})?$/, message: this.$t('room.addFloor.floorAreaFormat'), trigger: 'blur' }
  74 + ],
  75 + seq: [
  76 + { required: true, message: this.$t('room.addFloor.seqRequired'), trigger: 'blur' },
  77 + { type: 'number', message: this.$t('room.addFloor.seqNumber'), trigger: 'blur' }
  78 + ],
  79 + remark: [
  80 + { max: 200, message: this.$t('room.addFloor.remarkMaxLength'), trigger: 'blur' }
  81 + ]
  82 + }
  83 + }
  84 + },
  85 + watch: {
  86 + 'form.floorNum': function(newVal) {
  87 + if (newVal) {
  88 + this.form.name = `${newVal}${this.$t('room.addFloor.buildingSuffix')}`
  89 + } else {
  90 + this.form.name = ''
  91 + }
  92 + }
  93 + },
  94 + methods: {
  95 + open() {
  96 + this.visible = true
  97 + this.resetForm()
  98 + },
  99 + handleClose() {
  100 + this.visible = false
  101 + this.resetForm()
  102 + },
  103 + resetForm() {
  104 + this.form = {
  105 + communityId: this.getCommunityId(),
  106 + floorNum: '',
  107 + name: '',
  108 + floorArea: '',
  109 + seq: 1,
  110 + remark: ''
  111 + }
  112 + this.errorInfo = ''
  113 + this.$refs.form.resetFields()
  114 + },
  115 + async handleSave() {
  116 + this.$refs.form.validate(async (valid) => {
  117 + if (!valid) return
  118 +
  119 + try {
  120 + if (this.callBackListener && this.callBackFunction) {
  121 + const floorInfo = { ...this.form }
  122 + floorInfo.floorName = this.form.name
  123 + this.$emit(this.callBackFunction, floorInfo)
  124 + this.handleClose()
  125 + return
  126 + }
  127 +
  128 + const response = await addFloor(this.form)
  129 +
  130 + if (response.code === 0) {
  131 + this.$message.success(this.$t('room.addFloor.saveSuccess'))
  132 + this.handleClose()
  133 + this.$emit('refresh-data')
  134 + this.$emit('refresh-tree')
  135 + } else {
  136 + this.errorInfo = response.msg || this.$t('room.addFloor.saveFailed')
  137 + }
  138 + } catch (error) {
  139 + this.errorInfo = this.$t('room.addFloor.saveError')
  140 + }
  141 + })
  142 + },
  143 + getCommunityId() {
  144 + // 实际项目中替换为获取社区ID的逻辑
  145 + return 'your-community-id'
  146 + }
  147 + }
  148 +}
  149 +</script>
0 \ No newline at end of file 150 \ No newline at end of file
src/components/room/addFloorDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openAddFloorModal">Add Building</el-button>
  4 + <add-floor ref="addFloorModal" @refresh-data="refreshData" @refresh-tree="refreshTree" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import AddFloor from '../addFloor'
  10 +
  11 +export default {
  12 + components: {
  13 + AddFloor
  14 + },
  15 + methods: {
  16 + openAddFloorModal() {
  17 + this.$refs.addFloorModal.open()
  18 + },
  19 + refreshData() {
  20 + console.log('Refresh building list')
  21 + },
  22 + refreshTree() {
  23 + console.log('Refresh building tree')
  24 + }
  25 + }
  26 +}
  27 +</script>
0 \ No newline at end of file 28 \ No newline at end of file
src/components/room/addUnit.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('addUnit.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="addUnitInfo" label-width="120px">
  9 + <el-form-item :label="$t('addUnit.unitNum')" prop="unitNum" required>
  10 + <el-input
  11 + v-model="addUnitInfo.unitNum"
  12 + :placeholder="$t('addUnit.unitNumPlaceholder')"
  13 + ></el-input>
  14 + </el-form-item>
  15 +
  16 + <el-form-item :label="$t('addUnit.layerCount')" prop="layerCount" required>
  17 + <el-input
  18 + v-model.number="addUnitInfo.layerCount"
  19 + type="number"
  20 + :placeholder="$t('addUnit.layerCountPlaceholder')"
  21 + ></el-input>
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('addUnit.unitArea')" prop="unitArea" required>
  25 + <el-input
  26 + v-model="addUnitInfo.unitArea"
  27 + :placeholder="$t('addUnit.unitAreaPlaceholder')"
  28 + ></el-input>
  29 + </el-form-item>
  30 +
  31 + <el-form-item :label="$t('addUnit.lift')" prop="lift" required>
  32 + <el-select
  33 + v-model="addUnitInfo.lift"
  34 + :placeholder="$t('addUnit.liftPlaceholder')"
  35 + style="width: 100%"
  36 + >
  37 + <el-option
  38 + :label="$t('addUnit.liftOption1')"
  39 + value="1010"
  40 + ></el-option>
  41 + <el-option
  42 + :label="$t('addUnit.liftOption2')"
  43 + value="2020"
  44 + ></el-option>
  45 + </el-select>
  46 + </el-form-item>
  47 +
  48 + <el-form-item :label="$t('addUnit.remark')">
  49 + <el-input
  50 + v-model="addUnitInfo.remark"
  51 + type="textarea"
  52 + :rows="3"
  53 + :placeholder="$t('addUnit.remarkPlaceholder')"
  54 + ></el-input>
  55 + </el-form-item>
  56 + </el-form>
  57 +
  58 + <span slot="footer" class="dialog-footer">
  59 + <el-button @click="handleClose">{{ $t('addUnit.cancel') }}</el-button>
  60 + <el-button type="primary" @click="addUnit">{{ $t('addUnit.save') }}</el-button>
  61 + </span>
  62 + </el-dialog>
  63 +</template>
  64 +
  65 +<script>
  66 +import { saveUnit } from '@/api/room/addUnitApi'
  67 +
  68 +export default {
  69 + name: 'AddUnit',
  70 + data() {
  71 + return {
  72 + visible: false,
  73 + addUnitInfo: {
  74 + floorId: '',
  75 + unitNum: '',
  76 + layerCount: '',
  77 + lift: '',
  78 + remark: '',
  79 + communityId: '',
  80 + unitArea: ''
  81 + }
  82 + }
  83 + },
  84 + methods: {
  85 + open(params) {
  86 + this.refreshAddUnitInfo()
  87 + if (params && params.floorId) {
  88 + this.addUnitInfo.floorId = params.floorId
  89 + }
  90 + this.addUnitInfo.communityId = this.getCommunityId()
  91 + this.visible = true
  92 + },
  93 + handleClose() {
  94 + this.visible = false
  95 + },
  96 + refreshAddUnitInfo() {
  97 + this.addUnitInfo = {
  98 + floorId: '',
  99 + unitNum: '',
  100 + layerCount: '',
  101 + lift: '',
  102 + remark: '',
  103 + communityId: '',
  104 + unitArea: ''
  105 + }
  106 + this.$nextTick(() => {
  107 + if (this.$refs.form) {
  108 + this.$refs.form.clearValidate()
  109 + }
  110 + })
  111 + },
  112 + validateForm() {
  113 + return new Promise((resolve) => {
  114 + this.$refs.form.validate((valid) => {
  115 + resolve(valid)
  116 + })
  117 + })
  118 + },
  119 + async addUnit() {
  120 + const isValid = await this.validateForm()
  121 + if (!isValid) return
  122 +
  123 + if (this.addUnitInfo.unitNum === '0') {
  124 + this.$message.warning(this.$t('addUnit.zeroUnitWarning'))
  125 + return
  126 + }
  127 +
  128 + try {
  129 + await saveUnit(this.addUnitInfo)
  130 + this.$message.success(this.$t('addUnit.successMessage'))
  131 + this.$emit('refresh-tree', { floorId: this.addUnitInfo.floorId })
  132 + this.$emit('refresh-data', { floorId: this.addUnitInfo.floorId })
  133 + this.handleClose()
  134 + } catch (error) {
  135 + console.error('添加单元失败:', error)
  136 + this.$message.error(error.message || this.$t('addUnit.errorMessage'))
  137 + }
  138 + }
  139 + }
  140 +}
  141 +</script>
0 \ No newline at end of file 142 \ No newline at end of file
src/components/room/addUnitDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="primary" @click="openAddUnit">添加单元</el-button>
  4 + <add-unit ref="addUnit" @refresh-tree="refreshTree" @refresh-data="refreshData" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import AddUnit from './addUnit'
  10 +
  11 +export default {
  12 + components: {
  13 + AddUnit
  14 + },
  15 + methods: {
  16 + openAddUnit() {
  17 + this.$refs.addUnit.open({ floorId: '123' })
  18 + },
  19 + refreshTree(data) {
  20 + console.log('刷新树结构', data)
  21 + },
  22 + refreshData(data) {
  23 + console.log('刷新数据', data)
  24 + }
  25 + }
  26 +}
  27 +</script>
0 \ No newline at end of file 28 \ No newline at end of file
src/components/room/deleteFloor.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.deleteFloor.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + :before-close="handleClose"
  7 + >
  8 + <p>{{ $t('room.deleteFloor.confirmMessage') }}</p>
  9 + <span slot="footer" class="dialog-footer">
  10 + <el-button @click="handleClose">{{ $t('room.deleteFloor.cancelText') }}</el-button>
  11 + <el-button type="danger" @click="handleDelete">{{ $t('room.deleteFloor.confirmDelete') }}</el-button>
  12 + </span>
  13 + </el-dialog>
  14 +</template>
  15 +
  16 +<script>
  17 +import { deleteFloor } from '@/api/room/deleteFloorApi'
  18 +
  19 +export default {
  20 + name: 'DeleteFloor',
  21 + data() {
  22 + return {
  23 + visible: false,
  24 + floorInfo: {
  25 + floorId: '',
  26 + communityId: this.getCommunityId()
  27 + }
  28 + }
  29 + },
  30 + methods: {
  31 + open(floorInfo) {
  32 + this.floorInfo = {
  33 + ...floorInfo,
  34 + communityId: this.getCommunityId()
  35 + }
  36 + this.visible = true
  37 + },
  38 + handleClose() {
  39 + this.visible = false
  40 + },
  41 + async handleDelete() {
  42 + try {
  43 + const response = await deleteFloor(this.floorInfo)
  44 +
  45 + if (response.code === 0) {
  46 + this.$message.success(this.$t('room.deleteFloor.deleteSuccess'))
  47 + this.handleClose()
  48 + this.$emit('refresh-data')
  49 + this.$emit('refresh-tree')
  50 + } else {
  51 + this.$message.error(response.msg || this.$t('room.deleteFloor.deleteFailed'))
  52 + }
  53 + } catch (error) {
  54 + this.$message.error(this.$t('room.deleteFloor.deleteError'))
  55 + }
  56 + },
  57 + getCommunityId() {
  58 + // 实际项目中替换为获取社区ID的逻辑
  59 + return 'your-community-id'
  60 + }
  61 + }
  62 +}
  63 +</script>
0 \ No newline at end of file 64 \ No newline at end of file
src/components/room/deleteFloorDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openDeleteModal">Delete Building</el-button>
  4 + <delete-floor ref="deleteModal" @refresh-data="refreshData" @refresh-tree="refreshTree" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import DeleteFloor from '../deleteFloor'
  10 +
  11 +export default {
  12 + components: {
  13 + DeleteFloor
  14 + },
  15 + methods: {
  16 + openDeleteModal() {
  17 + // 模拟楼栋数据
  18 + const buildingData = {
  19 + floorId: '123',
  20 + floorNum: 'A1'
  21 + }
  22 + this.$refs.deleteModal.open(buildingData)
  23 + },
  24 + refreshData() {
  25 + console.log('Refresh building list')
  26 + },
  27 + refreshTree() {
  28 + console.log('Refresh building tree')
  29 + }
  30 + }
  31 +}
  32 +</script>
0 \ No newline at end of file 33 \ No newline at end of file
src/components/room/deleteRoom.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.deleteRoom.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="30%"
  6 + >
  7 + <div style="text-align: center">
  8 + <p>{{ $t('room.deleteRoom.confirmMessage') }}</p>
  9 + </div>
  10 + <div slot="footer">
  11 + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
  12 + <el-button type="danger" @click="deleteRoom">{{ $t('common.confirmDelete') }}</el-button>
  13 + </div>
  14 + </el-dialog>
  15 +</template>
  16 +
  17 +<script>
  18 +import { deleteRoom } from '@/api/room/deleteRoomApi'
  19 +
  20 +export default {
  21 + name: 'DeleteRoom',
  22 + data() {
  23 + return {
  24 + dialogVisible: false,
  25 + roomInfo: {}
  26 + }
  27 + },
  28 + created() {
  29 + this.$eventBus.$on('deleteRoom', this.open)
  30 + },
  31 + beforeDestroy() {
  32 + this.$eventBus.$off('deleteRoom', this.open)
  33 + },
  34 + methods: {
  35 + open(roomInfo) {
  36 + this.roomInfo = roomInfo
  37 + this.dialogVisible = true
  38 + },
  39 + async deleteRoom() {
  40 + try {
  41 + this.roomInfo.communityId = this.getCommunityId()
  42 +
  43 + await deleteRoom(this.roomInfo)
  44 +
  45 + this.dialogVisible = false
  46 + this.$emit('room-deleted')
  47 + this.$eventBus.$emit('room', 'loadData', { floorId: this.roomInfo.floorId })
  48 + this.$message.success(this.$t('common.deleteSuccess'))
  49 + } catch (error) {
  50 + console.error('删除房屋失败', error)
  51 + this.$message.error(error.message || this.$t('common.deleteFailed'))
  52 + }
  53 + },
  54 + getCommunityId() {
  55 + return this.$store.state.community.currentCommunity.communityId
  56 + }
  57 + }
  58 +}
  59 +</script>
0 \ No newline at end of file 60 \ No newline at end of file
src/components/room/deleteRoomDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openDeleteRoom">删除房屋</el-button>
  4 + <delete-room ref="deleteRoom" @room-deleted="handleRoomDeleted" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import DeleteRoom from '@/components/room/deleteRoom'
  10 +
  11 +export default {
  12 + components: {
  13 + DeleteRoom
  14 + },
  15 + methods: {
  16 + openDeleteRoom() {
  17 + // 模拟房屋数据
  18 + const roomData = {
  19 + roomId: '123',
  20 + floorId: '456'
  21 + }
  22 + this.$refs.deleteRoom.open(roomData)
  23 + },
  24 + handleRoomDeleted() {
  25 + console.log('房屋删除成功')
  26 + }
  27 + }
  28 +}
  29 +</script>
0 \ No newline at end of file 30 \ No newline at end of file
src/components/room/deleteUnit.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('deleteUnit.title')"
  4 + :visible.sync="visible"
  5 + width="30%"
  6 + :before-close="handleClose"
  7 + >
  8 + <div class="text-center">
  9 + <p>{{ $t('deleteUnit.confirmMessage') }}</p>
  10 + </div>
  11 + <span slot="footer" class="dialog-footer">
  12 + <el-button @click="handleClose">{{ $t('deleteUnit.cancel') }}</el-button>
  13 + <el-button type="danger" @click="deleteUnit">{{ $t('deleteUnit.confirm') }}</el-button>
  14 + </span>
  15 + </el-dialog>
  16 +</template>
  17 +
  18 +<script>
  19 +import { deleteUnit } from '@/api/room/deleteUnitApi'
  20 +
  21 +export default {
  22 + name: 'DeleteUnit',
  23 + data() {
  24 + return {
  25 + visible: false,
  26 + deleteUnitInfo: {
  27 + _currentFloorId: '',
  28 + _currentUnitId: ''
  29 + }
  30 + }
  31 + },
  32 + methods: {
  33 + open(params) {
  34 + this.deleteUnitInfo._currentFloorId = params.floorId
  35 + this.deleteUnitInfo._currentUnitId = params.unitId
  36 + this.visible = true
  37 + },
  38 + handleClose() {
  39 + this.visible = false
  40 + },
  41 + async deleteUnit() {
  42 + const param = {
  43 + floorId: this.deleteUnitInfo._currentFloorId,
  44 + unitId: this.deleteUnitInfo._currentUnitId,
  45 + communityId: this.getCommunityId()
  46 + }
  47 +
  48 + try {
  49 + await deleteUnit(param)
  50 + this.$message.success(this.$t('deleteUnit.successMessage'))
  51 + this.$emit('refresh-tree', { floorId: this.deleteUnitInfo._currentFloorId })
  52 + this.$emit('refresh-data', { floorId: this.deleteUnitInfo._currentFloorId })
  53 + this.handleClose()
  54 + } catch (error) {
  55 + console.error('删除单元失败:', error)
  56 + this.$message.error(error.message || this.$t('deleteUnit.errorMessage'))
  57 + }
  58 + }
  59 + }
  60 +}
  61 +</script>
0 \ No newline at end of file 62 \ No newline at end of file
src/components/room/deleteUnitDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="danger" @click="openDeleteUnit">删除单元</el-button>
  4 + <delete-unit ref="deleteUnit" @refresh-tree="refreshTree" @refresh-data="refreshData" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import DeleteUnit from './deleteUnit'
  10 +
  11 +export default {
  12 + components: {
  13 + DeleteUnit
  14 + },
  15 + methods: {
  16 + openDeleteUnit() {
  17 + const unitData = {
  18 + floorId: '123',
  19 + unitId: '456'
  20 + }
  21 + this.$refs.deleteUnit.open(unitData)
  22 + },
  23 + refreshTree(data) {
  24 + console.log('刷新树结构', data)
  25 + },
  26 + refreshData(data) {
  27 + console.log('刷新数据', data)
  28 + }
  29 + }
  30 +}
  31 +</script>
0 \ No newline at end of file 32 \ No newline at end of file
src/components/room/editFloor.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.editFloor.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="form" :rules="rules" label-width="120px">
  9 + <el-form-item :label="$t('room.editFloor.floorNum')" prop="floorNum">
  10 + <el-input v-model="form.floorNum" :placeholder="$t('room.editFloor.floorNumPlaceholder')" />
  11 + </el-form-item>
  12 +
  13 + <el-form-item :label="$t('room.editFloor.floorName')" prop="floorName">
  14 + <el-input v-model="form.floorName" :placeholder="$t('room.editFloor.floorNamePlaceholder')" />
  15 + </el-form-item>
  16 +
  17 + <el-form-item :label="$t('room.editFloor.floorArea')" prop="floorArea">
  18 + <el-input v-model="form.floorArea" :placeholder="$t('room.editFloor.floorAreaPlaceholder')">
  19 + <template slot="append">m²</template>
  20 + </el-input>
  21 + </el-form-item>
  22 +
  23 + <el-form-item :label="$t('room.editFloor.seq')" prop="seq">
  24 + <el-input-number v-model="form.seq" :min="1" />
  25 + </el-form-item>
  26 +
  27 + <el-form-item :label="$t('room.editFloor.remark')" prop="remark">
  28 + <el-input v-model="form.remark" type="textarea" :placeholder="$t('room.editFloor.remarkPlaceholder')" />
  29 + </el-form-item>
  30 +
  31 + <el-alert v-if="errorInfo" :title="errorInfo" type="error" show-icon />
  32 + </el-form>
  33 +
  34 + <span slot="footer" class="dialog-footer">
  35 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  36 + <el-button type="primary" @click="handleUpdate">{{ $t('common.update') }}</el-button>
  37 + </span>
  38 + </el-dialog>
  39 +</template>
  40 +
  41 +<script>
  42 +import { editFloor } from '@/api/room/editFloorApi'
  43 +
  44 +export default {
  45 + name: 'EditFloor',
  46 + data() {
  47 + return {
  48 + visible: false,
  49 + form: {
  50 + floorId: '',
  51 + floorNum: '',
  52 + floorName: '',
  53 + floorArea: '',
  54 + seq: 1,
  55 + remark: '',
  56 + communityId: this.getCommunityId()
  57 + },
  58 + errorInfo: '',
  59 + rules: {
  60 + floorNum: [
  61 + { required: true, message: this.$t('room.editFloor.floorNumRequired'), trigger: 'blur' },
  62 + { min: 1, max: 64, message: this.$t('room.editFloor.floorNumLength'), trigger: 'blur' }
  63 + ],
  64 + floorName: [
  65 + { required: true, message: this.$t('room.editFloor.floorNameRequired'), trigger: 'blur' },
  66 + { min: 2, max: 64, message: this.$t('room.editFloor.floorNameLength'), trigger: 'blur' }
  67 + ],
  68 + floorArea: [
  69 + { required: true, message: this.$t('room.editFloor.floorAreaRequired'), trigger: 'blur' },
  70 + { pattern: /^\d+(\.\d{1,2})?$/, message: this.$t('room.editFloor.floorAreaFormat'), trigger: 'blur' }
  71 + ],
  72 + seq: [
  73 + { required: true, message: this.$t('room.editFloor.seqRequired'), trigger: 'blur' },
  74 + { type: 'number', message: this.$t('room.editFloor.seqNumber'), trigger: 'blur' }
  75 + ],
  76 + remark: [
  77 + { max: 200, message: this.$t('room.editFloor.remarkMaxLength'), trigger: 'blur' }
  78 + ]
  79 + }
  80 + }
  81 + },
  82 + methods: {
  83 + open(floorInfo) {
  84 + this.form = {
  85 + ...floorInfo,
  86 + communityId: this.getCommunityId()
  87 + }
  88 + this.visible = true
  89 + this.errorInfo = ''
  90 + },
  91 + handleClose() {
  92 + this.visible = false
  93 + this.resetForm()
  94 + },
  95 + resetForm() {
  96 + this.form = {
  97 + floorId: '',
  98 + floorNum: '',
  99 + floorName: '',
  100 + floorArea: '',
  101 + seq: 1,
  102 + remark: '',
  103 + communityId: this.getCommunityId()
  104 + }
  105 + this.errorInfo = ''
  106 + },
  107 + async handleUpdate() {
  108 + this.$refs.form.validate(async (valid) => {
  109 + if (!valid) return
  110 +
  111 + try {
  112 + const payload = {
  113 + ...this.form,
  114 + name: this.form.floorName
  115 + }
  116 +
  117 + const response = await editFloor(payload)
  118 +
  119 + if (response.code === 0) {
  120 + this.$message.success(this.$t('room.editFloor.updateSuccess'))
  121 + this.handleClose()
  122 + this.$emit('refresh-data')
  123 + this.$emit('refresh-tree', { floorId: this.form.floorId })
  124 + } else {
  125 + this.errorInfo = response.msg || this.$t('room.editFloor.updateFailed')
  126 + }
  127 + } catch (error) {
  128 + this.errorInfo = this.$t('room.editFloor.updateError')
  129 + }
  130 + })
  131 + },
  132 + getCommunityId() {
  133 + // 实际项目中替换为获取社区ID的逻辑
  134 + return 'your-community-id'
  135 + }
  136 + }
  137 +}
  138 +</script>
0 \ No newline at end of file 139 \ No newline at end of file
src/components/room/editFloorDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openEditModal">Edit Building</el-button>
  4 + <edit-floor ref="editModal" @refresh-data="refreshData" @refresh-tree="refreshTree" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import EditFloor from '../editFloor'
  10 +
  11 +export default {
  12 + components: {
  13 + EditFloor
  14 + },
  15 + methods: {
  16 + openEditModal() {
  17 + // 模拟楼栋数据
  18 + const buildingData = {
  19 + floorId: '123',
  20 + floorNum: 'A1',
  21 + floorName: 'A1 Building',
  22 + floorArea: '3000',
  23 + seq: 1,
  24 + remark: 'Main building'
  25 + }
  26 + this.$refs.editModal.open(buildingData)
  27 + },
  28 + refreshData() {
  29 + console.log('Refresh building list')
  30 + },
  31 + refreshTree(data) {
  32 + console.log('Refresh building tree with floorId:', data.floorId)
  33 + }
  34 + }
  35 +}
  36 +</script>
0 \ No newline at end of file 37 \ No newline at end of file
src/components/room/editRoom.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.editRoom.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="50%"
  6 + >
  7 + <el-form :model="form" label-width="120px" label-position="right">
  8 + <el-row>
  9 + <el-col :span="12">
  10 + <el-form-item :label="$t('room.editRoom.roomNum')" required>
  11 + <el-input v-model="form.roomNum" :placeholder="$t('room.editRoom.placeholder.roomNum')" />
  12 + </el-form-item>
  13 + </el-col>
  14 + <el-col :span="12">
  15 + <el-form-item :label="$t('room.editRoom.layer')" required>
  16 + <el-input v-model="form.layer" :placeholder="$t('room.editRoom.placeholder.layer')" />
  17 + </el-form-item>
  18 + </el-col>
  19 + </el-row>
  20 +
  21 + <el-row>
  22 + <el-col :span="12">
  23 + <el-form-item :label="$t('room.editRoom.unit')" required>
  24 + <el-select v-model="form.unitId" :placeholder="$t('room.editRoom.placeholder.unit')">
  25 + <el-option
  26 + v-for="unit in units"
  27 + :key="unit.unitId"
  28 + :label="`${unit.unitNum}${$t('room.editRoom.unit')}`"
  29 + :value="unit.unitId"
  30 + />
  31 + </el-select>
  32 + </el-form-item>
  33 + </el-col>
  34 + <el-col :span="12">
  35 + <el-form-item :label="$t('room.editRoom.roomType')" required>
  36 + <el-select v-model="form.roomSubType" :placeholder="$t('room.editRoom.placeholder.roomType')">
  37 + <el-option
  38 + v-for="item in roomSubTypes"
  39 + :key="item.statusCd"
  40 + :label="item.name"
  41 + :value="item.statusCd"
  42 + />
  43 + </el-select>
  44 + </el-form-item>
  45 + </el-col>
  46 + </el-row>
  47 +
  48 + <el-row>
  49 + <el-col :span="12">
  50 + <el-form-item :label="$t('room.editRoom.apartment1')" required>
  51 + <el-select v-model="form.apartment1" :placeholder="$t('room.editRoom.placeholder.apartment')">
  52 + <el-option
  53 + v-for="item in apartment1Options"
  54 + :key="item.value"
  55 + :label="item.label"
  56 + :value="item.value"
  57 + />
  58 + </el-select>
  59 + </el-form-item>
  60 + </el-col>
  61 + <el-col :span="12">
  62 + <el-form-item :label="$t('room.editRoom.apartment2')" required>
  63 + <el-select v-model="form.apartment2" :placeholder="$t('room.editRoom.placeholder.apartment')">
  64 + <el-option
  65 + v-for="item in apartment2Options"
  66 + :key="item.value"
  67 + :label="item.label"
  68 + :value="item.value"
  69 + />
  70 + </el-select>
  71 + </el-form-item>
  72 + </el-col>
  73 + </el-row>
  74 +
  75 + <el-row>
  76 + <el-col :span="12">
  77 + <el-form-item :label="$t('room.editRoom.builtUpArea')" required>
  78 + <el-input v-model="form.builtUpArea" type="number" :placeholder="$t('room.editRoom.placeholder.builtUpArea')" />
  79 + </el-form-item>
  80 + </el-col>
  81 + <el-col :span="12">
  82 + <el-form-item :label="$t('room.editRoom.roomArea')" required>
  83 + <el-input v-model="form.roomArea" :placeholder="$t('room.editRoom.placeholder.roomArea')" />
  84 + </el-form-item>
  85 + </el-col>
  86 + </el-row>
  87 +
  88 + <el-row>
  89 + <el-col :span="12">
  90 + <el-form-item :label="$t('room.editRoom.feeCoefficient')">
  91 + <el-input v-model="form.feeCoefficient" :placeholder="$t('room.editRoom.placeholder.feeCoefficient')" />
  92 + </el-form-item>
  93 + </el-col>
  94 + <el-col :span="12">
  95 + <el-form-item :label="$t('room.editRoom.roomRent')" required>
  96 + <el-input v-model="form.roomRent" :placeholder="$t('room.editRoom.placeholder.roomRent')" />
  97 + </el-form-item>
  98 + </el-col>
  99 + </el-row>
  100 +
  101 + <el-row v-if="form.state !== '2002'">
  102 + <el-col :span="12">
  103 + <el-form-item :label="$t('room.editRoom.roomState')" required>
  104 + <el-select v-model="form.state" :placeholder="$t('room.editRoom.placeholder.roomState')">
  105 + <el-option
  106 + v-for="item in roomStateOptions"
  107 + :key="item.value"
  108 + :label="item.label"
  109 + :value="item.value"
  110 + />
  111 + </el-select>
  112 + </el-form-item>
  113 + </el-col>
  114 + <el-col :span="12">
  115 + <el-form-item :label="$t('room.editRoom.endTime')" required>
  116 + <el-date-picker
  117 + v-model="form.endTime"
  118 + type="date"
  119 + :placeholder="$t('room.editRoom.placeholder.endTime')"
  120 + value-format="yyyy-MM-dd"
  121 + />
  122 + </el-form-item>
  123 + </el-col>
  124 + </el-row>
  125 +
  126 + <div v-for="(item, index) in form.attrs" :key="index">
  127 + <el-form-item :label="item.specName">
  128 + <el-input
  129 + v-if="item.specType === '2233'"
  130 + v-model="item.value"
  131 + :placeholder="item.specHoldplace"
  132 + />
  133 + <el-select
  134 + v-else-if="item.specType === '3344'"
  135 + v-model="item.value"
  136 + :placeholder="item.specHoldplace"
  137 + >
  138 + <el-option
  139 + v-for="value in item.values"
  140 + :key="value.value"
  141 + :label="value.valueName"
  142 + :value="value.value"
  143 + />
  144 + </el-select>
  145 + </el-form-item>
  146 + </div>
  147 +
  148 + <el-form-item :label="$t('room.editRoom.remark')">
  149 + <el-input
  150 + v-model="form.remark"
  151 + type="textarea"
  152 + :placeholder="$t('room.editRoom.placeholder.remark')"
  153 + :rows="3"
  154 + />
  155 + </el-form-item>
  156 + </el-form>
  157 +
  158 + <div slot="footer">
  159 + <el-button @click="dialogVisible = false">{{ $t('common.cancel') }}</el-button>
  160 + <el-button type="primary" @click="editRoom">{{ $t('common.save') }}</el-button>
  161 + </div>
  162 + </el-dialog>
  163 +</template>
  164 +
  165 +<script>
  166 +import { updateRoom, getUnits } from '@/api/room/editRoomApi'
  167 +import { getDict } from '@/api/community/communityApi'
  168 +
  169 +export default {
  170 + name: 'EditRoom',
  171 + data() {
  172 + return {
  173 + dialogVisible: false,
  174 + form: {
  175 + roomId: '',
  176 + unitId: '',
  177 + roomNum: '',
  178 + layer: '',
  179 + apartment: '',
  180 + apartment1: '',
  181 + apartment2: '',
  182 + builtUpArea: '',
  183 + feeCoefficient: '1.00',
  184 + state: '',
  185 + remark: '',
  186 + communityId: '',
  187 + attrs: [],
  188 + roomSubType: '110',
  189 + roomArea: '',
  190 + roomRent: '0',
  191 + endTime: ''
  192 + },
  193 + units: [],
  194 + roomSubTypes: [],
  195 + apartment1Options: [
  196 + { value: '10', label: this.$t('room.editRoom.apartment1Options.oneRoom') },
  197 + { value: '20', label: this.$t('room.editRoom.apartment1Options.twoRooms') },
  198 + { value: '30', label: this.$t('room.editRoom.apartment1Options.threeRooms') },
  199 + { value: '40', label: this.$t('room.editRoom.apartment1Options.fourRooms') },
  200 + { value: '50', label: this.$t('room.editRoom.apartment1Options.fiveRooms') },
  201 + { value: '60', label: this.$t('room.editRoom.apartment1Options.sixRooms') },
  202 + { value: '70', label: this.$t('room.editRoom.apartment1Options.sevenRooms') },
  203 + { value: '80', label: this.$t('room.editRoom.apartment1Options.eightRooms') }
  204 + ],
  205 + apartment2Options: [
  206 + { value: '101', label: this.$t('room.editRoom.apartment2Options.oneHall') },
  207 + { value: '102', label: this.$t('room.editRoom.apartment2Options.twoHalls') },
  208 + { value: '103', label: this.$t('room.editRoom.apartment2Options.threeHalls') },
  209 + { value: '104', label: this.$t('room.editRoom.apartment2Options.fourHalls') },
  210 + { value: '105', label: this.$t('room.editRoom.apartment2Options.fiveHalls') },
  211 + { value: '106', label: this.$t('room.editRoom.apartment2Options.sixHalls') },
  212 + { value: '107', label: this.$t('room.editRoom.apartment2Options.sevenHalls') },
  213 + { value: '108', label: this.$t('room.editRoom.apartment2Options.eightHalls') }
  214 + ],
  215 + roomStateOptions: [
  216 + { value: '2001', label: this.$t('room.editRoom.roomStateOptions.occupied') },
  217 + { value: '2003', label: this.$t('room.editRoom.roomStateOptions.delivered') },
  218 + { value: '2005', label: this.$t('room.editRoom.roomStateOptions.decorated') },
  219 + { value: '2004', label: this.$t('room.editRoom.roomStateOptions.vacant') },
  220 + { value: '2009', label: this.$t('room.editRoom.roomStateOptions.decorating') }
  221 + ]
  222 + }
  223 + },
  224 + created() {
  225 + this.loadRoomAttrSpec()
  226 + this.$eventBus.$on('editRoom', this.open)
  227 + },
  228 + beforeDestroy() {
  229 + this.$eventBus.$off('editRoom', this.open)
  230 + },
  231 + methods: {
  232 + async open(room) {
  233 + this.resetForm()
  234 + this.form = { ...this.form, ...room }
  235 +
  236 + try {
  237 + // 加载房屋类型字典
  238 + const data = await getDict('building_room', 'room_sub_type')
  239 + this.roomSubTypes = data
  240 +
  241 + // 加载单元列表
  242 + await this.loadUnits(room.floorId)
  243 +
  244 + this.dialogVisible = true
  245 + } catch (error) {
  246 + console.error('打开编辑房屋失败', error)
  247 + }
  248 + },
  249 + async loadUnits(floorId) {
  250 + try {
  251 + const response = await getUnits({
  252 + floorId: floorId,
  253 + communityId: this.getCommunityId()
  254 + })
  255 + this.units = response
  256 + } catch (error) {
  257 + console.error('加载单元列表失败', error)
  258 + }
  259 + },
  260 + async loadRoomAttrSpec() {
  261 + try {
  262 + // 这里需要实现获取属性规格的逻辑
  263 + // 简化处理,实际项目中需要调用API
  264 + this.form.attrs = []
  265 + } catch (error) {
  266 + console.error('加载房屋属性失败', error)
  267 + }
  268 + },
  269 + async editRoom() {
  270 + try {
  271 + this.form.apartment = this.form.apartment1 + this.form.apartment2
  272 + this.form.communityId = this.getCommunityId()
  273 +
  274 + await updateRoom(this.form)
  275 +
  276 + this.dialogVisible = false
  277 + this.$emit('room-updated')
  278 + this.$eventBus.$emit('room', 'loadData', { floorId: this.form.floorId })
  279 + this.$message.success(this.$t('common.updateSuccess'))
  280 + } catch (error) {
  281 + console.error('更新房屋失败', error)
  282 + this.$message.error(error.message || this.$t('common.updateFailed'))
  283 + }
  284 + },
  285 + resetForm() {
  286 + this.form = {
  287 + roomId: '',
  288 + unitId: '',
  289 + roomNum: '',
  290 + layer: '',
  291 + apartment: '',
  292 + apartment1: '',
  293 + apartment2: '',
  294 + builtUpArea: '',
  295 + feeCoefficient: '1.00',
  296 + state: '',
  297 + remark: '',
  298 + communityId: '',
  299 + attrs: [],
  300 + roomSubType: '110',
  301 + roomArea: '',
  302 + roomRent: '0',
  303 + endTime: ''
  304 + }
  305 + },
  306 + getCommunityId() {
  307 + return this.$store.state.community.currentCommunity.communityId
  308 + }
  309 + }
  310 +}
  311 +</script>
0 \ No newline at end of file 312 \ No newline at end of file
src/components/room/editRoomDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openEditRoom">编辑房屋</el-button>
  4 + <edit-room ref="editRoom" @room-updated="handleRoomUpdated" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import EditRoom from '@/components/room/editRoom'
  10 +
  11 +export default {
  12 + components: {
  13 + EditRoom
  14 + },
  15 + methods: {
  16 + openEditRoom() {
  17 + // 模拟房屋数据
  18 + const roomData = {
  19 + roomId: '123',
  20 + floorId: '456',
  21 + roomNum: '101',
  22 + unitId: '789',
  23 + layer: '1',
  24 + apartment: '1020',
  25 + builtUpArea: '100',
  26 + feeCoefficient: '1.0',
  27 + state: '2001',
  28 + remark: '备注信息',
  29 + roomArea: '80',
  30 + roomRent: '3000',
  31 + endTime: '2023-12-31'
  32 + }
  33 + this.$refs.editRoom.open(roomData)
  34 + },
  35 + handleRoomUpdated() {
  36 + console.log('房屋更新成功')
  37 + }
  38 + }
  39 +}
  40 +</script>
0 \ No newline at end of file 41 \ No newline at end of file
src/components/room/editUnit.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('editUnit.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="editUnitInfo" label-width="120px">
  9 + <el-form-item :label="$t('editUnit.unitNum')" prop="unitNum" required>
  10 + <el-input
  11 + v-model="editUnitInfo.unitNum"
  12 + :placeholder="$t('editUnit.unitNumPlaceholder')"
  13 + ></el-input>
  14 + </el-form-item>
  15 +
  16 + <el-form-item :label="$t('editUnit.layerCount')" prop="layerCount" required>
  17 + <el-input
  18 + v-model.number="editUnitInfo.layerCount"
  19 + type="number"
  20 + :placeholder="$t('editUnit.layerCountPlaceholder')"
  21 + ></el-input>
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('editUnit.unitArea')" prop="unitArea" required>
  25 + <el-input
  26 + v-model="editUnitInfo.unitArea"
  27 + :placeholder="$t('editUnit.unitAreaPlaceholder')"
  28 + ></el-input>
  29 + </el-form-item>
  30 +
  31 + <el-form-item :label="$t('editUnit.lift')" prop="lift" required>
  32 + <el-select
  33 + v-model="editUnitInfo.lift"
  34 + :placeholder="$t('editUnit.liftPlaceholder')"
  35 + style="width: 100%"
  36 + >
  37 + <el-option
  38 + :label="$t('editUnit.liftOption1')"
  39 + value="1010"
  40 + ></el-option>
  41 + <el-option
  42 + :label="$t('editUnit.liftOption2')"
  43 + value="2020"
  44 + ></el-option>
  45 + </el-select>
  46 + </el-form-item>
  47 +
  48 + <el-form-item :label="$t('editUnit.remark')">
  49 + <el-input
  50 + v-model="editUnitInfo.remark"
  51 + type="textarea"
  52 + :rows="3"
  53 + :placeholder="$t('editUnit.remarkPlaceholder')"
  54 + ></el-input>
  55 + </el-form-item>
  56 + </el-form>
  57 +
  58 + <span slot="footer" class="dialog-footer">
  59 + <el-button @click="handleClose">{{ $t('editUnit.cancel') }}</el-button>
  60 + <el-button type="primary" @click="editUnit">{{ $t('editUnit.save') }}</el-button>
  61 + </span>
  62 + </el-dialog>
  63 +</template>
  64 +
  65 +<script>
  66 +import { updateUnit } from '@/api/room/editUnitApi'
  67 +
  68 +export default {
  69 + name: 'EditUnit',
  70 + data() {
  71 + return {
  72 + visible: false,
  73 + editUnitInfo: {
  74 + floorId: '',
  75 + unitId: '',
  76 + unitNum: '',
  77 + layerCount: '',
  78 + lift: '',
  79 + remark: '',
  80 + communityId: '',
  81 + unitArea: ''
  82 + }
  83 + }
  84 + },
  85 + methods: {
  86 + open(params) {
  87 + Object.assign(this.editUnitInfo, params)
  88 + this.editUnitInfo.communityId = this.getCommunityId()
  89 + this.visible = true
  90 + },
  91 + handleClose() {
  92 + this.visible = false
  93 + },
  94 + validateForm() {
  95 + return new Promise((resolve) => {
  96 + this.$refs.form.validate((valid) => {
  97 + resolve(valid)
  98 + })
  99 + })
  100 + },
  101 + async editUnit() {
  102 + const isValid = await this.validateForm()
  103 + if (!isValid) return
  104 +
  105 + if (this.editUnitInfo.unitNum === '0') {
  106 + this.$message.warning(this.$t('editUnit.zeroUnitWarning'))
  107 + return
  108 + }
  109 +
  110 + try {
  111 + await updateUnit(this.editUnitInfo)
  112 + this.$message.success(this.$t('editUnit.successMessage'))
  113 + this.$emit('refresh-tree', { floorId: this.editUnitInfo.floorId })
  114 + this.$emit('refresh-data', { floorId: this.editUnitInfo.floorId })
  115 + this.handleClose()
  116 + } catch (error) {
  117 + console.error('修改单元失败:', error)
  118 + this.$message.error(error.message || this.$t('editUnit.errorMessage'))
  119 + }
  120 + }
  121 + }
  122 +}
  123 +</script>
0 \ No newline at end of file 124 \ No newline at end of file
src/components/room/editUnitDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="primary" @click="openEditUnit">编辑单元</el-button>
  4 + <edit-unit ref="editUnit" @refresh-tree="refreshTree" @refresh-data="refreshData" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import EditUnit from './editUnit'
  10 +
  11 +export default {
  12 + components: {
  13 + EditUnit
  14 + },
  15 + methods: {
  16 + openEditUnit() {
  17 + const unitData = {
  18 + floorId: '123',
  19 + unitId: '456',
  20 + unitNum: 'A1',
  21 + layerCount: 20,
  22 + lift: '1010',
  23 + unitArea: '3000',
  24 + remark: '备注信息'
  25 + }
  26 + this.$refs.editUnit.open(unitData)
  27 + },
  28 + refreshTree(data) {
  29 + console.log('刷新树结构', data)
  30 + },
  31 + refreshData(data) {
  32 + console.log('刷新数据', data)
  33 + }
  34 + }
  35 +}
  36 +</script>
0 \ No newline at end of file 37 \ No newline at end of file
src/components/room/floorUnitTree.vue 0 → 100644
  1 +<template>
  2 + <div class="bg-white margin-top-xs padding border-radius tree-div">
  3 + <el-tree
  4 + v-if="treeData.length > 0"
  5 + :data="treeData"
  6 + :props="defaultProps"
  7 + node-key="id"
  8 + default-expand-all
  9 + :expand-on-click-node="false"
  10 + @node-click="handleNodeClick"
  11 + >
  12 + <template #default="{ node, data }">
  13 + <span class="custom-tree-node">
  14 + <i :class="data.icon" style="margin-right:5px"></i>
  15 + <span>{{ node.label }}</span>
  16 + </span>
  17 + </template>
  18 + </el-tree>
  19 + <div v-else class="no-data">
  20 + {{ $t('room.floorUnitTree.noData') }}
  21 + </div>
  22 + </div>
  23 +</template>
  24 +
  25 +<script>
  26 +import { getFloorAndUnits } from '@/api/room/floorUnitTreeApi'
  27 +
  28 +export default {
  29 + name: 'FloorUnitTree',
  30 + props: {
  31 + callBackListener: String
  32 + },
  33 + data() {
  34 + return {
  35 + treeData: [],
  36 + defaultProps: {
  37 + children: 'children',
  38 + label: 'text'
  39 + },
  40 + currentFloorId: ''
  41 + }
  42 + },
  43 + mounted() {
  44 + this.loadData()
  45 + this.$eventBus.$on('floorUnitTree', this.handleRefreshTree)
  46 + },
  47 + beforeDestroy() {
  48 + this.$eventBus.$off('floorUnitTree', this.handleRefreshTree)
  49 + },
  50 + methods: {
  51 + handleRefreshTree(param) {
  52 + if (param) {
  53 + this.currentFloorId = param.floorId
  54 + }
  55 + this.loadData()
  56 + },
  57 + async loadData() {
  58 + try {
  59 + const communityId = this.getCommunityId()
  60 + const response = await getFloorAndUnits(communityId)
  61 + this.treeData = this.transformData(response)
  62 + } catch (error) {
  63 + console.error('加载楼栋单元树失败', error)
  64 + }
  65 + },
  66 + transformData(units) {
  67 + const treeData = []
  68 + const floorMap = {}
  69 +
  70 + units.forEach(item => {
  71 + if (!floorMap[item.floorId]) {
  72 + floorMap[item.floorId] = {
  73 + id: `f_${item.floorId}`,
  74 + floorId: item.floorId,
  75 + floorNum: item.floorNum,
  76 + icon: 'el-icon-office-building',
  77 + text: `${item.floorNum}${this.$t('room.floorUnitTree.building')}(${item.floorName})`,
  78 + children: []
  79 + }
  80 + treeData.push(floorMap[item.floorId])
  81 + }
  82 +
  83 + if (item.unitId && item.unitNum !== '0') {
  84 + floorMap[item.floorId].children.push({
  85 + id: `u_${item.unitId}`,
  86 + unitId: item.unitId,
  87 + text: `${item.unitNum}${this.$t('room.floorUnitTree.unit')}`,
  88 + icon: 'el-icon-house'
  89 + })
  90 + }
  91 + })
  92 +
  93 + return treeData
  94 + },
  95 + handleNodeClick(data) {
  96 + if (data.id.startsWith('f_')) {
  97 + this.$emit('switchFloor', { floorId: data.floorId })
  98 + this.$eventBus.$emit(this.callBackListener, 'switchFloor', { floorId: data.floorId })
  99 + } else {
  100 + this.$emit('switchUnit', { unitId: data.unitId })
  101 + this.$eventBus.$emit(this.callBackListener, 'switchUnit', { unitId: data.unitId })
  102 + }
  103 + },
  104 + }
  105 +}
  106 +</script>
  107 +
  108 +<style scoped>
  109 +.tree-div {
  110 + min-height: 300px;
  111 +}
  112 +.custom-tree-node {
  113 + display: flex;
  114 + align-items: center;
  115 +}
  116 +.no-data {
  117 + text-align: center;
  118 + padding: 20px;
  119 + color: #909399;
  120 +}
  121 +</style>
0 \ No newline at end of file 122 \ No newline at end of file
src/components/room/floorUnitTreeDemo.vue 0 → 100644
  1 +<template>
  2 + <floor-unit-tree
  3 + :call-back-listener="callbackListener"
  4 + @switchFloor="handleSwitchFloor"
  5 + @switchUnit="handleSwitchUnit"
  6 + />
  7 +</template>
  8 +
  9 +<script>
  10 +import FloorUnitTree from '@/components/room/floorUnitTree'
  11 +
  12 +export default {
  13 + components: {
  14 + FloorUnitTree
  15 + },
  16 + data() {
  17 + return {
  18 + callbackListener: 'demoFloorUnitTree'
  19 + }
  20 + },
  21 + methods: {
  22 + handleSwitchFloor(data) {
  23 + console.log('切换楼栋', data.floorId)
  24 + },
  25 + handleSwitchUnit(data) {
  26 + console.log('切换单元', data.unitId)
  27 + }
  28 + }
  29 +}
  30 +</script>
0 \ No newline at end of file 31 \ No newline at end of file
src/components/room/importOwnerRoom.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.importOwnerRoom.title')"
  4 + :visible.sync="visible"
  5 + width="50%"
  6 + :before-close="handleClose"
  7 + >
  8 + <el-form ref="form" :model="form" label-width="120px">
  9 + <el-form-item :label="$t('room.importOwnerRoom.selectFile')">
  10 + <el-upload
  11 + ref="upload"
  12 + action=""
  13 + :auto-upload="false"
  14 + :on-change="handleFileChange"
  15 + accept=".xls,.xlsx"
  16 + >
  17 + <el-button size="small" type="primary">{{ $t('room.importOwnerRoom.clickUpload') }}</el-button>
  18 + <div slot="tip" class="el-upload__tip">
  19 + {{ fileName || $t('room.importOwnerRoom.requiredFile') }}
  20 + </div>
  21 + </el-upload>
  22 + </el-form-item>
  23 +
  24 + <el-form-item :label="$t('room.importOwnerRoom.downloadTemplate')">
  25 + <span>{{ $t('room.importOwnerRoom.downloadFirst') }}</span>
  26 + <el-link type="primary" :href="templateUrl" target="_blank">
  27 + {{ $t('room.importOwnerRoom.propertyTemplate') }}
  28 + </el-link>
  29 + <span>{{ $t('room.importOwnerRoom.prepareData') }}</span>
  30 + </el-form-item>
  31 + </el-form>
  32 +
  33 + <span slot="footer" class="dialog-footer">
  34 + <el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
  35 + <el-button type="primary" @click="handleImport">{{ $t('common.import') }}</el-button>
  36 + </span>
  37 + </el-dialog>
  38 +</template>
  39 +
  40 +<script>
  41 +import { importOwnerRoom } from '@/api/room/importOwnerRoomApi'
  42 +
  43 +export default {
  44 + name: 'ImportOwnerRoom',
  45 + data() {
  46 + return {
  47 + visible: false,
  48 + form: {
  49 + communityId: this.getCommunityId(),
  50 + file: null
  51 + },
  52 + fileName: '',
  53 + templateUrl: '/import/importRoom.xlsx'
  54 + }
  55 + },
  56 + methods: {
  57 + open() {
  58 + this.visible = true
  59 + this.resetForm()
  60 + },
  61 + handleClose() {
  62 + this.visible = false
  63 + this.resetForm()
  64 + },
  65 + resetForm() {
  66 + this.form.file = null
  67 + this.fileName = ''
  68 + if (this.$refs.upload) {
  69 + this.$refs.upload.clearFiles()
  70 + }
  71 + },
  72 + handleFileChange(file) {
  73 + this.form.file = file.raw
  74 + this.fileName = file.name
  75 + },
  76 + validate() {
  77 + if (!this.form.file) {
  78 + this.$message.error(this.$t('room.importOwnerRoom.fileRequired'))
  79 + return false
  80 + }
  81 +
  82 + const fileType = this.fileName.split('.').pop().toLowerCase()
  83 + if (!['xls', 'xlsx'].includes(fileType)) {
  84 + this.$message.error(this.$t('room.importOwnerRoom.invalidFormat'))
  85 + return false
  86 + }
  87 +
  88 + if (this.form.file.size > 2 * 1024 * 1024) {
  89 + this.$message.error(this.$t('room.importOwnerRoom.fileSizeExceeded'))
  90 + return false
  91 + }
  92 +
  93 + return true
  94 + },
  95 + async handleImport() {
  96 + if (!this.validate()) return
  97 +
  98 + try {
  99 + const formData = new FormData()
  100 + formData.append('uploadFile', this.form.file)
  101 + formData.append('communityId', this.form.communityId)
  102 + formData.append('importAdapt', 'importRoomOwner')
  103 +
  104 + const response = await importOwnerRoom(formData)
  105 +
  106 + if (response.code === 0) {
  107 + this.$message.success(this.$t('room.importOwnerRoom.importSuccess'))
  108 + this.handleClose()
  109 + this.$router.push({
  110 + path: '/property/assetImportLogDetail',
  111 + query: {
  112 + logId: response.data.logId,
  113 + logType: 'importRoomOwner'
  114 + }
  115 + })
  116 + } else {
  117 + this.$message.error(response.msg || this.$t('room.importOwnerRoom.importFailed'))
  118 + }
  119 + } catch (error) {
  120 + this.$message.error(this.$t('room.importOwnerRoom.importError'))
  121 + }
  122 + },
  123 + getCommunityId() {
  124 + // 实际项目中替换为获取社区ID的逻辑
  125 + return 'your-community-id'
  126 + }
  127 + }
  128 +}
  129 +</script>
0 \ No newline at end of file 130 \ No newline at end of file
src/components/room/importOwnerRoomDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openImportModal">Open Import</el-button>
  4 + <import-owner-room ref="importModal" @import-success="handleImportSuccess" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import ImportOwnerRoom from '../importOwnerRoom'
  10 +
  11 +export default {
  12 + components: {
  13 + ImportOwnerRoom
  14 + },
  15 + methods: {
  16 + openImportModal() {
  17 + this.$refs.importModal.open()
  18 + },
  19 + handleImportSuccess() {
  20 + console.log('Import successful, handle refresh logic here')
  21 + }
  22 + }
  23 +}
  24 +</script>
0 \ No newline at end of file 25 \ No newline at end of file
src/components/room/ownerRoomsDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="primary" @click="openOwnerRooms">查看业主房屋</el-button>
  4 + <owner-rooms ref="ownerRooms" />
  5 + </div>
  6 +</template>
  7 +
  8 +<script>
  9 +import OwnerRooms from './ownerRooms'
  10 +
  11 +export default {
  12 + components: {
  13 + OwnerRooms
  14 + },
  15 + methods: {
  16 + openOwnerRooms() {
  17 + this.$refs.ownerRooms.open({ ownerId: '123' })
  18 + }
  19 + }
  20 +}
  21 +</script>
0 \ No newline at end of file 22 \ No newline at end of file
src/components/room/roomContracts.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="visible"
  4 + :title="$t('roomContracts.title')"
  5 + width="90%"
  6 + top="5vh"
  7 + custom-class="custom-modal"
  8 + @close="handleClose"
  9 + >
  10 + <el-table
  11 + :data="roomContractsInfo.contracts"
  12 + stripe
  13 + border
  14 + style="width: 100%; margin-top: 15px"
  15 + >
  16 + <el-table-column
  17 + prop="contractName"
  18 + :label="$t('roomContracts.contractName')"
  19 + align="center"
  20 + />
  21 + <el-table-column
  22 + prop="contractCode"
  23 + :label="$t('roomContracts.contractCode')"
  24 + align="center"
  25 + />
  26 + <el-table-column
  27 + prop="parentContractCode"
  28 + :label="$t('roomContracts.parentContractCode')"
  29 + align="center"
  30 + >
  31 + <template slot-scope="scope">
  32 + {{ scope.row.parentContractCode || '-' }}
  33 + </template>
  34 + </el-table-column>
  35 + <el-table-column
  36 + prop="contractTypeName"
  37 + :label="$t('roomContracts.contractType')"
  38 + align="center"
  39 + />
  40 + <el-table-column
  41 + prop="operator"
  42 + :label="$t('roomContracts.operator')"
  43 + align="center"
  44 + />
  45 + <el-table-column
  46 + prop="amount"
  47 + :label="$t('roomContracts.amount')"
  48 + align="center"
  49 + />
  50 + <el-table-column
  51 + prop="startTime"
  52 + :label="$t('roomContracts.startTime')"
  53 + align="center"
  54 + />
  55 + <el-table-column
  56 + prop="endTime"
  57 + :label="$t('roomContracts.endTime')"
  58 + align="center"
  59 + />
  60 + <el-table-column
  61 + prop="createTime"
  62 + :label="$t('roomContracts.createTime')"
  63 + align="center"
  64 + />
  65 + <el-table-column
  66 + prop="stateName"
  67 + :label="$t('roomContracts.state')"
  68 + align="center"
  69 + />
  70 + </el-table>
  71 +
  72 + <el-pagination
  73 + v-if="pagination.total > 0"
  74 + background
  75 + layout="prev, pager, next"
  76 + :total="pagination.total"
  77 + :page-size="pagination.pageSize"
  78 + :current-page="pagination.currentPage"
  79 + @current-change="handlePageChange"
  80 + style="margin-top: 20px; text-align: right"
  81 + />
  82 + </el-dialog>
  83 +</template>
  84 +
  85 +<script>
  86 +import { getRoomContracts } from '@/api/room/roomContractsApi'
  87 +
  88 +export default {
  89 + name: 'RoomContracts',
  90 + data() {
  91 + return {
  92 + visible: false,
  93 + roomContractsInfo: {
  94 + contracts: [],
  95 + ownerId: '',
  96 + roomId: ''
  97 + },
  98 + pagination: {
  99 + total: 0,
  100 + pageSize: 10,
  101 + currentPage: 1
  102 + }
  103 + }
  104 + },
  105 + methods: {
  106 + open(params) {
  107 + this.roomContractsInfo.ownerId = params.ownerId || ''
  108 + this.roomContractsInfo.roomId = params.roomId || ''
  109 + this.pagination.currentPage = 1
  110 + this.visible = true
  111 + this.loadData()
  112 + },
  113 + handleClose() {
  114 + this.visible = false
  115 + },
  116 + handlePageChange(currentPage) {
  117 + this.pagination.currentPage = currentPage
  118 + this.loadData()
  119 + },
  120 + async loadData() {
  121 + try {
  122 + const params = {
  123 + page: this.pagination.currentPage,
  124 + row: this.pagination.pageSize,
  125 + communityId: this.getCommunityId(),
  126 + objId: this.roomContractsInfo.ownerId
  127 + }
  128 +
  129 + if (this.roomContractsInfo.roomId) {
  130 + params.roomId = this.roomContractsInfo.roomId
  131 + }
  132 +
  133 + const response = await getRoomContracts(params, this.roomContractsInfo.roomId)
  134 + this.roomContractsInfo.contracts = response.data
  135 + this.pagination.total = response.records
  136 + } catch (error) {
  137 + console.error('加载合同信息失败:', error)
  138 + this.$message.error(this.$t('common.loadFailed'))
  139 + }
  140 + },
  141 + getCommunityId() {
  142 + return this.$store.state.user.currentCommunity.communityId
  143 + }
  144 + }
  145 +}
  146 +</script>
  147 +
  148 +<style scoped>
  149 +.custom-modal >>> .el-dialog__body {
  150 + padding: 15px 20px;
  151 +}
  152 +</style>
0 \ No newline at end of file 153 \ No newline at end of file
src/components/room/roomContractsDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="primary" @click="openByOwner">
  4 + {{ $t('roomContractsDemo.openByOwner') }}
  5 + </el-button>
  6 + <el-button type="primary" @click="openByRoom">
  7 + {{ $t('roomContractsDemo.openByRoom') }}
  8 + </el-button>
  9 + <room-contracts ref="contractsRef" />
  10 + </div>
  11 +</template>
  12 +
  13 +<script>
  14 +import RoomContracts from './roomContracts'
  15 +
  16 +export default {
  17 + components: {
  18 + RoomContracts
  19 + },
  20 + methods: {
  21 + openByOwner() {
  22 + // 模拟业主ID
  23 + this.$refs.contractsRef.open({ ownerId: '12345' })
  24 + },
  25 + openByRoom() {
  26 + // 模拟房屋ID
  27 + this.$refs.contractsRef.open({ roomId: '67890' })
  28 + }
  29 + }
  30 +}
  31 +</script>
0 \ No newline at end of file 32 \ No newline at end of file
src/components/room/roomOweFees.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :visible.sync="visible"
  4 + :title="$t('roomOweFees.title')"
  5 + width="80%"
  6 + top="5vh"
  7 + custom-class="custom-modal"
  8 + @close="handleClose"
  9 + >
  10 + <el-table
  11 + :data="roomOweFeesInfo.fees"
  12 + stripe
  13 + border
  14 + style="width: 100%; margin-top: 15px"
  15 + >
  16 + <el-table-column
  17 + prop="payerObjName"
  18 + :label="$t('roomOweFees.payerObj')"
  19 + align="center"
  20 + />
  21 + <el-table-column
  22 + prop="ownerName"
  23 + :label="$t('roomOweFees.ownerName')"
  24 + align="center"
  25 + />
  26 + <el-table-column
  27 + prop="ownerTel"
  28 + :label="$t('roomOweFees.phone')"
  29 + align="center"
  30 + />
  31 + <el-table-column
  32 + prop="endTime"
  33 + :label="$t('roomOweFees.startTime')"
  34 + align="center"
  35 + />
  36 + <el-table-column
  37 + prop="deadlineTime"
  38 + :label="$t('roomOweFees.endTime')"
  39 + align="center"
  40 + />
  41 + <el-table-column
  42 + prop="amountOwed"
  43 + :label="`${$t('roomOweFees.total')} (${$t('roomOweFees.unit')})`"
  44 + align="center"
  45 + />
  46 + <el-table-column
  47 + prop="updateTime"
  48 + :label="$t('roomOweFees.updateTime')"
  49 + align="center"
  50 + />
  51 + </el-table>
  52 +
  53 + <el-pagination
  54 + v-if="pagination.total > 0"
  55 + background
  56 + layout="prev, pager, next"
  57 + :total="pagination.total"
  58 + :page-size="pagination.pageSize"
  59 + :current-page="pagination.currentPage"
  60 + @current-change="handlePageChange"
  61 + style="margin-top: 20px; text-align: right"
  62 + />
  63 + </el-dialog>
  64 +</template>
  65 +
  66 +<script>
  67 +import { getRoomOweFees } from '@/api/room/roomOweFeesApi'
  68 +
  69 +export default {
  70 + name: 'RoomOweFees',
  71 + data() {
  72 + return {
  73 + visible: false,
  74 + roomOweFeesInfo: {
  75 + fees: [],
  76 + roomId: ''
  77 + },
  78 + pagination: {
  79 + total: 0,
  80 + pageSize: 10,
  81 + currentPage: 1
  82 + }
  83 + }
  84 + },
  85 + methods: {
  86 + open(roomId) {
  87 + this.roomOweFeesInfo.roomId = roomId
  88 + this.pagination.currentPage = 1
  89 + this.visible = true
  90 + this.loadData()
  91 + },
  92 + handleClose() {
  93 + this.visible = false
  94 + },
  95 + handlePageChange(currentPage) {
  96 + this.pagination.currentPage = currentPage
  97 + this.loadData()
  98 + },
  99 + async loadData() {
  100 + try {
  101 + const params = {
  102 + page: this.pagination.currentPage,
  103 + row: this.pagination.pageSize,
  104 + communityId: this.getCommunityId(),
  105 + payerObjId: this.roomOweFeesInfo.roomId,
  106 + payerObjType: '3333'
  107 + }
  108 +
  109 + const response = await getRoomOweFees(params)
  110 + this.roomOweFeesInfo.fees = response.data
  111 + this.pagination.total = response.records
  112 + } catch (error) {
  113 + console.error('加载房屋欠费信息失败:', error)
  114 + this.$message.error(this.$t('common.loadFailed'))
  115 + }
  116 + },
  117 + getCommunityId() {
  118 + return this.$store.state.user.currentCommunity.communityId
  119 + }
  120 + }
  121 +}
  122 +</script>
  123 +
  124 +<style scoped>
  125 +.custom-modal >>> .el-dialog__body {
  126 + padding: 15px 20px;
  127 +}
  128 +</style>
0 \ No newline at end of file 129 \ No newline at end of file
src/components/room/roomOweFeesDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button type="primary" @click="openModal">
  4 + {{ $t('roomOweFeesDemo.openBtn') }}
  5 + </el-button>
  6 + <room-owe-fees ref="roomOweFeesRef" />
  7 + </div>
  8 +</template>
  9 +
  10 +<script>
  11 +import RoomOweFees from './roomOweFees'
  12 +
  13 +export default {
  14 + components: {
  15 + RoomOweFees
  16 + },
  17 + methods: {
  18 + openModal() {
  19 + // 模拟房屋ID
  20 + const roomId = '67890'
  21 + this.$refs.roomOweFeesRef.open(roomId)
  22 + }
  23 + }
  24 +}
  25 +</script>
0 \ No newline at end of file 26 \ No newline at end of file
src/components/room/searchFloor.vue 0 → 100644
  1 +<template>
  2 + <el-dialog
  3 + :title="$t('room.searchFloor.title')"
  4 + :visible.sync="dialogVisible"
  5 + width="80%"
  6 + >
  7 + <el-row>
  8 + <el-col :span="24">
  9 + <el-row :gutter="10">
  10 + <el-col :sm="8" :md="6">
  11 + <el-input
  12 + v-model="searchParams.floorId"
  13 + :placeholder="$t('room.searchFloor.placeholder.floorId')"
  14 + />
  15 + </el-col>
  16 + <el-col :sm="8" :md="6">
  17 + <el-input
  18 + v-model="searchParams.floorName"
  19 + :placeholder="$t('room.searchFloor.placeholder.floorName')"
  20 + />
  21 + </el-col>
  22 + <el-col :sm="8" :md="6">
  23 + <el-input
  24 + v-model="searchParams.floorNum"
  25 + :placeholder="$t('room.searchFloor.placeholder.floorNum')"
  26 + />
  27 + </el-col>
  28 + <el-col :sm="24" :md="6">
  29 + <el-button type="primary" @click="searchFloors">
  30 + <i class="el-icon-search"></i>
  31 + {{ $t('common.search') }}
  32 + </el-button>
  33 + <el-button @click="resetFloors">
  34 + <i class="el-icon-refresh"></i>
  35 + {{ $t('common.reset') }}
  36 + </el-button>
  37 + </el-col>
  38 + </el-row>
  39 +
  40 + <el-table :data="floorList" style="width: 100%; margin-top: 15px">
  41 + <el-table-column prop="floorId" :label="$t('room.searchFloor.table.floorId')" align="center" />
  42 + <el-table-column prop="floorName" :label="$t('room.searchFloor.table.floorName')" align="center" />
  43 + <el-table-column prop="floorNum" :label="$t('room.searchFloor.table.floorNum')" align="center" />
  44 + <el-table-column prop="userName" :label="$t('room.searchFloor.table.creator')" align="center" />
  45 + <el-table-column :label="$t('room.searchFloor.table.actions')" align="center">
  46 + <template #default="{ row }">
  47 + <el-button size="mini" type="primary" @click="chooseFloor(row)">
  48 + {{ $t('common.select') }}
  49 + </el-button>
  50 + </template>
  51 + </el-table-column>
  52 + </el-table>
  53 +
  54 + <el-pagination
  55 + background
  56 + layout="prev, pager, next"
  57 + :total="total"
  58 + :page-size="pageSize"
  59 + :current-page="currentPage"
  60 + @current-change="handlePageChange"
  61 + />
  62 + </el-col>
  63 + </el-row>
  64 + </el-dialog>
  65 +</template>
  66 +
  67 +<script>
  68 +import { searchFloors } from '@/api/room/searchFloorApi'
  69 +
  70 +export default {
  71 + name: 'SearchFloor',
  72 + props: {
  73 + emitChooseFloor: String,
  74 + emitLoadData: String
  75 + },
  76 + data() {
  77 + return {
  78 + dialogVisible: false,
  79 + searchParams: {
  80 + floorId: '',
  81 + floorName: '',
  82 + floorNum: ''
  83 + },
  84 + floorList: [],
  85 + currentPage: 1,
  86 + pageSize: 10,
  87 + total: 0
  88 + }
  89 + },
  90 + methods: {
  91 + open() {
  92 + this.dialogVisible = true
  93 + this.resetFloors()
  94 + this.loadFloors()
  95 + },
  96 + async loadFloors() {
  97 + try {
  98 + const params = {
  99 + ...this.searchParams,
  100 + page: this.currentPage,
  101 + row: this.pageSize,
  102 + communityId: this.getCommunityId()
  103 + }
  104 +
  105 + const response = await searchFloors(params)
  106 + this.floorList = response.apiFloorDataVoList
  107 + this.total = response.records
  108 + } catch (error) {
  109 + console.error('加载楼栋列表失败', error)
  110 + }
  111 + },
  112 + searchFloors() {
  113 + this.currentPage = 1
  114 + this.loadFloors()
  115 + },
  116 + resetFloors() {
  117 + this.searchParams = {
  118 + floorId: '',
  119 + floorName: '',
  120 + floorNum: ''
  121 + }
  122 + this.currentPage = 1
  123 + this.loadFloors()
  124 + },
  125 + handlePageChange(page) {
  126 + this.currentPage = page
  127 + this.loadFloors()
  128 + },
  129 + chooseFloor(floor) {
  130 + this.$emit('chooseFloor', floor)
  131 + this.$eventBus.$emit(this.emitChooseFloor, 'chooseFloor', floor)
  132 + this.$eventBus.$emit(this.emitLoadData, 'loadData', { floorId: floor.floorId })
  133 + this.dialogVisible = false
  134 + },
  135 + getCommunityId() {
  136 + return this.$store.state.community.currentCommunity.communityId
  137 + }
  138 + }
  139 +}
  140 +</script>
0 \ No newline at end of file 141 \ No newline at end of file
src/components/room/searchFloorDemo.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <el-button @click="openSearchFloor">打开搜索楼栋</el-button>
  4 + <search-floor
  5 + ref="searchFloor"
  6 + emit-choose-floor="handleChooseFloor"
  7 + emit-load-data="handleLoadData"
  8 + @choose-floor="handleChooseFloor"
  9 + />
  10 + </div>
  11 +</template>
  12 +
  13 +<script>
  14 +import SearchFloor from '@/components/room/searchFloor'
  15 +
  16 +export default {
  17 + components: {
  18 + SearchFloor
  19 + },
  20 + methods: {
  21 + openSearchFloor() {
  22 + this.$refs.searchFloor.open()
  23 + },
  24 + handleChooseFloor(floor) {
  25 + console.log('选择了楼栋', floor)
  26 + },
  27 + handleLoadData(data) {
  28 + console.log('加载数据', data)
  29 + }
  30 + }
  31 +}
  32 +</script>
0 \ No newline at end of file 33 \ No newline at end of file
src/i18n/index.js
@@ -122,6 +122,7 @@ import { messages as enterCommunityMessages } from &#39;../views/community/enterComm @@ -122,6 +122,7 @@ import { messages as enterCommunityMessages } from &#39;../views/community/enterComm
122 import { messages as roomRenovationManageMessages } from '../views/community/roomRenovationManageLang' 122 import { messages as roomRenovationManageMessages } from '../views/community/roomRenovationManageLang'
123 import { messages as feeConfigManageMessages } from '../views/fee/feeConfigManageLang' 123 import { messages as feeConfigManageMessages } from '../views/fee/feeConfigManageLang'
124 import { messages as payFeeConfigDiscountManageMessages } from '../views/fee/payFeeConfigDiscountManageLang' 124 import { messages as payFeeConfigDiscountManageMessages } from '../views/fee/payFeeConfigDiscountManageLang'
  125 +import { messages as roomMessages } from '../views/room/roomLang.js'
125 126
126 127
127 Vue.use(VueI18n) 128 Vue.use(VueI18n)
@@ -249,6 +250,7 @@ const messages = { @@ -249,6 +250,7 @@ const messages = {
249 ...roomRenovationManageMessages.en, 250 ...roomRenovationManageMessages.en,
250 ...feeConfigManageMessages.en, 251 ...feeConfigManageMessages.en,
251 ...payFeeConfigDiscountManageMessages.en, 252 ...payFeeConfigDiscountManageMessages.en,
  253 + ...roomMessages.en,
252 }, 254 },
253 zh: { 255 zh: {
254 ...loginMessages.zh, 256 ...loginMessages.zh,
@@ -371,6 +373,7 @@ const messages = { @@ -371,6 +373,7 @@ const messages = {
371 ...roomRenovationManageMessages.zh, 373 ...roomRenovationManageMessages.zh,
372 ...feeConfigManageMessages.zh, 374 ...feeConfigManageMessages.zh,
373 ...payFeeConfigDiscountManageMessages.zh, 375 ...payFeeConfigDiscountManageMessages.zh,
  376 + ...roomMessages.en,
374 } 377 }
375 } 378 }
376 379
src/router/index.js
@@ -587,15 +587,20 @@ const routes = [ @@ -587,15 +587,20 @@ const routes = [
587 component: () => import('@/views/community/roomRenovationManageList.vue') 587 component: () => import('@/views/community/roomRenovationManageList.vue')
588 }, 588 },
589 { 589 {
590 - path:'/pages/property/feeConfigManage',  
591 - name:'/pages/property/feeConfigManage', 590 + path: '/pages/property/feeConfigManage',
  591 + name: '/pages/property/feeConfigManage',
592 component: () => import('@/views/fee/feeConfigManageList.vue') 592 component: () => import('@/views/fee/feeConfigManageList.vue')
593 - },  
594 - {  
595 - path:'/views/fee/payFeeConfigDiscountManage',  
596 - name:'/views/fee/payFeeConfigDiscountManage',  
597 - component: () => import('@/views/fee/payFeeConfigDiscountManageList.vue')  
598 - }, 593 + },
  594 + {
  595 + path: '/views/fee/payFeeConfigDiscountManage',
  596 + name: '/views/fee/payFeeConfigDiscountManage',
  597 + component: () => import('@/views/fee/payFeeConfigDiscountManageList.vue')
  598 + },
  599 + {
  600 + path: '/pages/property/room',
  601 + name: '/pages/property/room',
  602 + component: () => import('@/views/room/roomList.vue')
  603 + },
599 // 其他子路由可以在这里添加 604 // 其他子路由可以在这里添加
600 ] 605 ]
601 }, 606 },
src/src/locale/lang/community/enterCommunityLang.js deleted
1 -export default {  
2 - en: {  
3 - enterCommunity: {  
4 - myCommunity: 'My Community',  
5 - commercialProcess: 'Commercial Process',  
6 - province: 'Province',  
7 - city: 'City',  
8 - district: 'District',  
9 - communityName: 'Community Name',  
10 - communityCode: 'Community Code',  
11 - servicePhone: 'Service Phone',  
12 - area: 'Area',  
13 - startTime: 'Start Time',  
14 - endTime: 'End Time',  
15 - status: 'Status',  
16 - operation: 'Operation',  
17 - modify: 'Modify',  
18 - back: 'Back',  
19 - communityAddress: 'Community Address',  
20 - communityLandmark: 'Community Landmark',  
21 - cityCode: 'City Code',  
22 - xCoordinate: 'X Coordinate',  
23 - yCoordinate: 'Y Coordinate',  
24 - serviceQR: 'Service QR Code',  
25 - communityArea: 'Community Area',  
26 - save: 'Save',  
27 - cancel: 'Cancel',  
28 - statusOptions: {  
29 - '1000': 'Under Review',  
30 - '1100': 'Approved',  
31 - '1200': 'Rejected'  
32 - }  
33 - }  
34 - },  
35 - zh: {  
36 - enterCommunity: {  
37 - myCommunity: '我的小区',  
38 - commercialProcess: '商用流程',  
39 - province: '省份',  
40 - city: '市/州',  
41 - district: '区/县',  
42 - communityName: '小区名称',  
43 - communityCode: '小区编码',  
44 - servicePhone: '客服电话',  
45 - area: '面积',  
46 - startTime: '开始时间',  
47 - endTime: '结束时间',  
48 - status: '状态',  
49 - operation: '操作',  
50 - modify: '修改',  
51 - back: '返回',  
52 - communityAddress: '小区地址',  
53 - communityLandmark: '小区地标',  
54 - cityCode: '城市编码',  
55 - xCoordinate: 'X坐标',  
56 - yCoordinate: 'Y坐标',  
57 - serviceQR: '客服二维码',  
58 - communityArea: '小区面积',  
59 - save: '保存',  
60 - cancel: '取消',  
61 - statusOptions: {  
62 - '1000': '入驻审核',  
63 - '1100': '入驻成功',  
64 - '1200': '入驻失败'  
65 - }  
66 - }  
67 - }  
68 -}  
69 \ No newline at end of file 0 \ No newline at end of file
src/views/room/addFloorLang.js 0 → 100644
  1 +export default {
  2 + en: {
  3 + room: {
  4 + addFloor: {
  5 + title: 'Add Building',
  6 + floorNum: 'Building Number',
  7 + name: 'Building Name',
  8 + floorArea: 'Floor Area',
  9 + seq: 'Sequence',
  10 + remark: 'Remark',
  11 + buildingSuffix: ' Building',
  12 + floorNumPlaceholder: 'Required, please enter number',
  13 + namePlaceholder: 'Required, please enter name',
  14 + floorAreaPlaceholder: 'Required, please enter floor area',
  15 + remarkPlaceholder: 'Optional, please enter remark',
  16 + floorNumRequired: 'Building number is required',
  17 + floorNumLength: 'Building number must be 1-64 characters',
  18 + nameRequired: 'Building name is required',
  19 + nameLength: 'Building name must be 2-64 characters',
  20 + floorAreaRequired: 'Floor area is required',
  21 + floorAreaFormat: 'Invalid floor area format, e.g. 300.00',
  22 + seqRequired: 'Sequence is required',
  23 + seqNumber: 'Sequence must be a number',
  24 + remarkMaxLength: 'Remark cannot exceed 200 characters',
  25 + saveSuccess: 'Add successful',
  26 + saveFailed: 'Add failed',
  27 + saveError: 'Error adding building'
  28 + }
  29 + }
  30 + },
  31 + zh: {
  32 + room: {
  33 + addFloor: {
  34 + title: '添加楼栋',
  35 + floorNum: '楼栋编号',
  36 + name: '楼栋名称',
  37 + floorArea: '建筑面积',
  38 + seq: '排序',
  39 + remark: '备注',
  40 + buildingSuffix: '号楼',
  41 + floorNumPlaceholder: '必填,请填写编号',
  42 + namePlaceholder: '必填,请填写名称',
  43 + floorAreaPlaceholder: '必填,请填写建筑面积',
  44 + remarkPlaceholder: '可填,请填写备注',
  45 + floorNumRequired: '楼栋编号不能为空',
  46 + floorNumLength: '楼栋编号长度必须在1位至64位',
  47 + nameRequired: '楼栋名称不能为空',
  48 + nameLength: '楼栋名称长度必须在2位至64位',
  49 + floorAreaRequired: '建筑面积不能为空',
  50 + floorAreaFormat: '建筑面积错误,如300.00',
  51 + seqRequired: '排序不能为空',
  52 + seqNumber: '排序必须是数字',
  53 + remarkMaxLength: '备注长度不能超过200位',
  54 + saveSuccess: '添加成功',
  55 + saveFailed: '添加失败',
  56 + saveError: '添加楼栋出错'
  57 + }
  58 + }
  59 + }
  60 +}
0 \ No newline at end of file 61 \ No newline at end of file
src/views/room/addUnitLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + addUnit: {
  4 + title: 'Add Unit',
  5 + unitNum: 'Unit Number',
  6 + unitNumPlaceholder: 'Required, please enter unit number',
  7 + layerCount: 'Total Floors',
  8 + layerCountPlaceholder: 'Required, please enter total floors',
  9 + unitArea: 'Building Area',
  10 + unitAreaPlaceholder: 'Required, please enter building area',
  11 + lift: 'Elevator',
  12 + liftPlaceholder: 'Required, please select elevator availability',
  13 + liftOption1: 'Yes',
  14 + liftOption2: 'No',
  15 + remark: 'Remark',
  16 + remarkPlaceholder: 'Please enter remarks',
  17 + save: 'Save',
  18 + cancel: 'Cancel',
  19 + zeroUnitWarning: 'Unit 0 is specific to shops and cannot be added',
  20 + successMessage: 'Unit added successfully',
  21 + errorMessage: 'Failed to add unit'
  22 + }
  23 + },
  24 + zh: {
  25 + addUnit: {
  26 + title: '添加单元',
  27 + unitNum: '单元编号',
  28 + unitNumPlaceholder: '必填,请填写单元编号',
  29 + layerCount: '总层数',
  30 + layerCountPlaceholder: '必填,请填写单元总层数',
  31 + unitArea: '建筑面积',
  32 + unitAreaPlaceholder: '必填,请填写建筑面积',
  33 + lift: '电梯',
  34 + liftPlaceholder: '必填,请选择是否有电梯',
  35 + liftOption1: '有',
  36 + liftOption2: '无',
  37 + remark: '备注',
  38 + remarkPlaceholder: '请填写备注信息',
  39 + save: '保存',
  40 + cancel: '取消',
  41 + zeroUnitWarning: '0单元为商铺特有,不允许添加',
  42 + successMessage: '单元添加成功',
  43 + errorMessage: '添加单元失败'
  44 + }
  45 + }
  46 +}
0 \ No newline at end of file 47 \ No newline at end of file
src/views/room/deleteFloorLang.js 0 → 100644
  1 +export default {
  2 + en: {
  3 + room: {
  4 + deleteFloor: {
  5 + title: 'Confirm Operation',
  6 + confirmMessage: 'Are you sure you want to delete?',
  7 + cancelText: 'Cancel',
  8 + confirmDelete: 'Confirm Delete',
  9 + deleteSuccess: 'Delete successful',
  10 + deleteFailed: 'Delete failed',
  11 + deleteError: 'Error deleting building'
  12 + }
  13 + }
  14 + },
  15 + zh: {
  16 + room: {
  17 + deleteFloor: {
  18 + title: '请确认您的操作',
  19 + confirmMessage: '确认是否删除?',
  20 + cancelText: '点错了',
  21 + confirmDelete: '确认删除',
  22 + deleteSuccess: '删除成功',
  23 + deleteFailed: '删除失败',
  24 + deleteError: '删除楼栋出错'
  25 + }
  26 + }
  27 + }
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
src/views/room/deleteRoomLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + room: {
  4 + deleteRoom: {
  5 + title: 'Confirm Operation',
  6 + confirmMessage: 'Confirm deletion! Deleting a room will delete associated fees and payment records, and automatically unbind owners!'
  7 + }
  8 + }
  9 + },
  10 + zh: {
  11 + room: {
  12 + deleteRoom: {
  13 + title: '请确认您的操作',
  14 + confirmMessage: '确认是否删除! 删除房屋会关联删除房屋下的费用以及缴费记录,并且自动解绑业主!'
  15 + }
  16 + }
  17 + }
  18 +}
0 \ No newline at end of file 19 \ No newline at end of file
src/views/room/deleteUnitLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + deleteUnit: {
  4 + title: 'Confirm Operation',
  5 + confirmMessage: 'Are you sure you want to delete this unit?',
  6 + cancel: 'Cancel',
  7 + confirm: 'Confirm Delete',
  8 + successMessage: 'Unit deleted successfully',
  9 + errorMessage: 'Failed to delete unit'
  10 + }
  11 + },
  12 + zh: {
  13 + deleteUnit: {
  14 + title: '请确认您的操作',
  15 + confirmMessage: '确定删除小区单元?',
  16 + cancel: '点错了',
  17 + confirm: '确认删除',
  18 + successMessage: '单元删除成功',
  19 + errorMessage: '删除单元失败'
  20 + }
  21 + }
  22 +}
0 \ No newline at end of file 23 \ No newline at end of file
src/views/room/editFloorLang.js 0 → 100644
  1 +export default {
  2 + en: {
  3 + room: {
  4 + editFloor: {
  5 + title: 'Edit Building',
  6 + floorNum: 'Building Number',
  7 + floorName: 'Building Name',
  8 + floorArea: 'Floor Area',
  9 + seq: 'Sequence',
  10 + remark: 'Remark',
  11 + floorNumPlaceholder: 'Required, please enter number',
  12 + floorNamePlaceholder: 'Required, please enter name',
  13 + floorAreaPlaceholder: 'Required, please enter floor area',
  14 + remarkPlaceholder: 'Optional, please enter remark',
  15 + floorNumRequired: 'Building number is required',
  16 + floorNumLength: 'Building number must be 1-64 characters',
  17 + floorNameRequired: 'Building name is required',
  18 + floorNameLength: 'Building name must be 2-64 characters',
  19 + floorAreaRequired: 'Floor area is required',
  20 + floorAreaFormat: 'Invalid floor area format, e.g. 300.00',
  21 + seqRequired: 'Sequence is required',
  22 + seqNumber: 'Sequence must be a number',
  23 + remarkMaxLength: 'Remark cannot exceed 200 characters',
  24 + updateSuccess: 'Update successful',
  25 + updateFailed: 'Update failed',
  26 + updateError: 'Error updating building'
  27 + }
  28 + }
  29 + },
  30 + zh: {
  31 + room: {
  32 + editFloor: {
  33 + title: '修改楼栋',
  34 + floorNum: '楼栋编号',
  35 + floorName: '楼栋名称',
  36 + floorArea: '建筑面积',
  37 + seq: '排序',
  38 + remark: '备注',
  39 + floorNumPlaceholder: '必填,请填写编号',
  40 + floorNamePlaceholder: '必填,请填写名称',
  41 + floorAreaPlaceholder: '必填,请填写建筑面积',
  42 + remarkPlaceholder: '可填,请填写备注',
  43 + floorNumRequired: '楼栋编号不能为空',
  44 + floorNumLength: '楼栋编号长度必须在1位至64位',
  45 + floorNameRequired: '楼栋名称不能为空',
  46 + floorNameLength: '楼栋名称长度必须在2位至64位',
  47 + floorAreaRequired: '建筑面积不能为空',
  48 + floorAreaFormat: '建筑面积错误,如300.00',
  49 + seqRequired: '排序不能为空',
  50 + seqNumber: '排序必须是数字',
  51 + remarkMaxLength: '备注长度不能超过200位',
  52 + updateSuccess: '修改成功',
  53 + updateFailed: '修改失败',
  54 + updateError: '修改楼栋出错'
  55 + }
  56 + }
  57 + }
  58 +}
0 \ No newline at end of file 59 \ No newline at end of file
src/views/room/editRoomLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + room: {
  4 + editRoom: {
  5 + title: 'Edit Room',
  6 + roomNum: 'Room Number',
  7 + layer: 'Floor',
  8 + unit: 'Unit',
  9 + roomType: 'Room Type',
  10 + apartment1: 'Bedrooms',
  11 + apartment2: 'Living Rooms',
  12 + builtUpArea: 'Built-up Area (m²)',
  13 + roomArea: 'Indoor Area (m²)',
  14 + feeCoefficient: 'Fee Coefficient',
  15 + roomRent: 'Rent',
  16 + roomState: 'Room State',
  17 + endTime: 'End Time',
  18 + remark: 'Remark',
  19 + placeholder: {
  20 + roomNum: 'Required, please enter room number',
  21 + layer: 'Required, please enter floor',
  22 + unit: 'Required, please select unit',
  23 + roomType: 'Required, please select room type',
  24 + apartment: 'Required, please select apartment layout',
  25 + builtUpArea: 'Required, please enter built-up area! m²',
  26 + roomArea: 'Required, please enter indoor area! m²',
  27 + feeCoefficient: 'Please enter fee coefficient',
  28 + roomRent: 'Required, please enter rent',
  29 + roomState: 'Required, please select room state',
  30 + endTime: 'Required, please select end time',
  31 + remark: 'Please enter remark information'
  32 + },
  33 + apartment1Options: {
  34 + oneRoom: 'One Bedroom',
  35 + twoRooms: 'Two Bedrooms',
  36 + threeRooms: 'Three Bedrooms',
  37 + fourRooms: 'Four Bedrooms',
  38 + fiveRooms: 'Five Bedrooms',
  39 + sixRooms: 'Six Bedrooms',
  40 + sevenRooms: 'Seven Bedrooms',
  41 + eightRooms: 'Eight Bedrooms'
  42 + },
  43 + apartment2Options: {
  44 + oneHall: 'One Living Room',
  45 + twoHalls: 'Two Living Rooms',
  46 + threeHalls: 'Three Living Rooms',
  47 + fourHalls: 'Four Living Rooms',
  48 + fiveHalls: 'Five Living Rooms',
  49 + sixHalls: 'Six Living Rooms',
  50 + sevenHalls: 'Seven Living Rooms',
  51 + eightHalls: 'Eight Living Rooms'
  52 + },
  53 + roomStateOptions: {
  54 + occupied: 'Occupied',
  55 + delivered: 'Delivered',
  56 + decorated: 'Decorated',
  57 + vacant: 'Vacant',
  58 + decorating: 'Decorating'
  59 + }
  60 + }
  61 + }
  62 + },
  63 + zh: {
  64 + room: {
  65 + editRoom: {
  66 + title: '修改房屋',
  67 + roomNum: '房屋编号',
  68 + layer: '房屋楼层',
  69 + unit: '房屋单元',
  70 + roomType: '房屋类型',
  71 + apartment1: '户型室',
  72 + apartment2: '户型厅',
  73 + builtUpArea: '建筑面积(平方)',
  74 + roomArea: '室内面积(平方)',
  75 + feeCoefficient: '算费系数',
  76 + roomRent: '租金',
  77 + roomState: '房屋状态',
  78 + endTime: '结束时间',
  79 + remark: '备注',
  80 + placeholder: {
  81 + roomNum: '必填,请填写房屋编号',
  82 + layer: '必填,请填写房屋楼层',
  83 + unit: '必填,请选择单元',
  84 + roomType: '必填,请选择房屋类型',
  85 + apartment: '必填,请选择房屋户型',
  86 + builtUpArea: '必填,请填写房屋建筑面积! 平方',
  87 + roomArea: '必填,请填写室内面积! 平方',
  88 + feeCoefficient: '请填写算费系数',
  89 + roomRent: '必填,请填写租金',
  90 + roomState: '必填,请选择房屋状态',
  91 + endTime: '必填,请选择结束时间',
  92 + remark: '请填写备注信息'
  93 + },
  94 + apartment1Options: {
  95 + oneRoom: '一室',
  96 + twoRooms: '两室',
  97 + threeRooms: '三室',
  98 + fourRooms: '四室',
  99 + fiveRooms: '五室',
  100 + sixRooms: '六室',
  101 + sevenRooms: '七室',
  102 + eightRooms: '八室'
  103 + },
  104 + apartment2Options: {
  105 + oneHall: '一厅',
  106 + twoHalls: '两厅',
  107 + threeHalls: '三厅',
  108 + fourHalls: '四厅',
  109 + fiveHalls: '五厅',
  110 + sixHalls: '六厅',
  111 + sevenHalls: '七厅',
  112 + eightHalls: '八厅'
  113 + },
  114 + roomStateOptions: {
  115 + occupied: '已入住',
  116 + delivered: '已交房',
  117 + decorated: '已装修',
  118 + vacant: '未入住',
  119 + decorating: '装修中'
  120 + }
  121 + }
  122 + }
  123 + }
  124 +}
0 \ No newline at end of file 125 \ No newline at end of file
src/views/room/editUnitLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + editUnit: {
  4 + title: 'Edit Unit',
  5 + unitNum: 'Unit Number',
  6 + unitNumPlaceholder: 'Required, please enter unit number',
  7 + layerCount: 'Total Floors',
  8 + layerCountPlaceholder: 'Required, please enter total floors',
  9 + unitArea: 'Building Area',
  10 + unitAreaPlaceholder: 'Required, please enter building area',
  11 + lift: 'Elevator',
  12 + liftPlaceholder: 'Required, please select elevator availability',
  13 + liftOption1: 'Yes',
  14 + liftOption2: 'No',
  15 + remark: 'Remark',
  16 + remarkPlaceholder: 'Please enter remarks',
  17 + save: 'Save',
  18 + cancel: 'Cancel',
  19 + zeroUnitWarning: 'Unit 0 is specific to shops and cannot be edited',
  20 + successMessage: 'Unit updated successfully',
  21 + errorMessage: 'Failed to update unit'
  22 + }
  23 + },
  24 + zh: {
  25 + editUnit: {
  26 + title: '修改单元',
  27 + unitNum: '单元编号',
  28 + unitNumPlaceholder: '必填,请填写单元编号',
  29 + layerCount: '总层数',
  30 + layerCountPlaceholder: '必填,请填写单元总层数',
  31 + unitArea: '建筑面积',
  32 + unitAreaPlaceholder: '必填,请填写建筑面积',
  33 + lift: '电梯',
  34 + liftPlaceholder: '必填,请选择是否有电梯',
  35 + liftOption1: '有',
  36 + liftOption2: '无',
  37 + remark: '备注',
  38 + remarkPlaceholder: '请填写备注信息',
  39 + save: '保存',
  40 + cancel: '取消',
  41 + zeroUnitWarning: '0单元为商铺特有,不允许修改',
  42 + successMessage: '单元修改成功',
  43 + errorMessage: '修改单元失败'
  44 + }
  45 + }
  46 +}
0 \ No newline at end of file 47 \ No newline at end of file
src/views/room/floorUnitTreeLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + room: {
  4 + floorUnitTree: {
  5 + building: 'Building',
  6 + unit: 'Unit',
  7 + noData: 'No buildings currently'
  8 + }
  9 + }
  10 + },
  11 + zh: {
  12 + room: {
  13 + floorUnitTree: {
  14 + building: '栋',
  15 + unit: '单元',
  16 + noData: '当前没有楼栋'
  17 + }
  18 + }
  19 + }
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
src/views/room/importOwnerRoomLang.js 0 → 100644
  1 +export default {
  2 + en: {
  3 + room: {
  4 + importOwnerRoom: {
  5 + title: 'Property Import',
  6 + selectFile: 'Select File',
  7 + clickUpload: 'Click to upload',
  8 + requiredFile: 'Required, please select data file',
  9 + downloadTemplate: 'Download Template',
  10 + downloadFirst: 'Please download first',
  11 + propertyTemplate: 'Property Template',
  12 + prepareData: 'to prepare data, then upload for import',
  13 + fileRequired: 'File cannot be empty',
  14 + invalidFormat: 'Invalid Excel format',
  15 + fileSizeExceeded: 'Excel file size cannot exceed 2MB',
  16 + importSuccess: 'Import successful',
  17 + importFailed: 'Import failed',
  18 + importError: 'Import error occurred'
  19 + }
  20 + }
  21 + },
  22 + zh: {
  23 + room: {
  24 + importOwnerRoom: {
  25 + title: '房产导入',
  26 + selectFile: '选择文件',
  27 + clickUpload: '点击上传',
  28 + requiredFile: '必填,请选择数据文件',
  29 + downloadTemplate: '下载模板',
  30 + downloadFirst: '请先下载',
  31 + propertyTemplate: '房产模板',
  32 + prepareData: '准备数据后,上传导入',
  33 + fileRequired: '文件不能为空',
  34 + invalidFormat: '不是有效的Excel格式',
  35 + fileSizeExceeded: 'Excel文件大小不能超过2M',
  36 + importSuccess: '导入成功',
  37 + importFailed: '导入失败',
  38 + importError: '导入出错'
  39 + }
  40 + }
  41 + }
  42 +}
0 \ No newline at end of file 43 \ No newline at end of file
src/views/room/ownerCarsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerCars: {
  4 + title: 'Owner Cars',
  5 + licensePlate: 'License Plate',
  6 + licenseType: 'License Type',
  7 + temporary: 'Temporary Car',
  8 + carType: 'Car Type',
  9 + color: 'Color',
  10 + owner: 'Owner',
  11 + parkingSpace: 'Parking Space',
  12 + park: ' Park',
  13 + space: ' Space',
  14 + released: 'Space Released',
  15 + validity: 'Validity Period'
  16 + }
  17 + },
  18 + zh: {
  19 + ownerCars: {
  20 + title: '业主车辆',
  21 + licensePlate: '车牌号',
  22 + licenseType: '车牌类型',
  23 + temporary: '临时车',
  24 + carType: '车辆类型',
  25 + color: '颜色',
  26 + owner: '业主',
  27 + parkingSpace: '车位',
  28 + park: '车场',
  29 + space: '车位',
  30 + released: '车位已释放',
  31 + validity: '有效期'
  32 + }
  33 + }
  34 +}
0 \ No newline at end of file 35 \ No newline at end of file
src/views/room/ownerComplaintsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerComplaints: {
  4 + title: 'Owner Complaints',
  5 + type: 'Type',
  6 + room: 'Room',
  7 + contact: 'Contact',
  8 + phone: 'Phone',
  9 + status: 'Status',
  10 + handler: 'Handler',
  11 + handlerPhone: 'Handler Phone',
  12 + createTime: 'Create Time',
  13 + none: 'None'
  14 + }
  15 + },
  16 + zh: {
  17 + ownerComplaints: {
  18 + title: '业主投诉',
  19 + type: '类型',
  20 + room: '房屋',
  21 + contact: '联系人',
  22 + phone: '联系电话',
  23 + status: '状态',
  24 + handler: '处理人',
  25 + handlerPhone: '处理人电话',
  26 + createTime: '创建时间',
  27 + none: '无'
  28 + }
  29 + }
  30 +}
0 \ No newline at end of file 31 \ No newline at end of file
src/views/room/ownerMembersLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerMembers: {
  4 + title: 'Owner Members',
  5 + name: 'Name',
  6 + sex: 'Gender',
  7 + male: 'Male',
  8 + female: 'Female',
  9 + age: 'Age',
  10 + type: 'Type',
  11 + idCard: 'ID Card',
  12 + contact: 'Contact',
  13 + address: 'Address'
  14 + }
  15 + },
  16 + zh: {
  17 + ownerMembers: {
  18 + title: '业主成员',
  19 + name: '名称',
  20 + sex: '性别',
  21 + male: '男',
  22 + female: '女',
  23 + age: '年龄',
  24 + type: '类型',
  25 + idCard: '身份证',
  26 + contact: '联系方式',
  27 + address: '家庭住址'
  28 + }
  29 + }
  30 +}
0 \ No newline at end of file 31 \ No newline at end of file
src/views/room/ownerOweFeesLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerOweFees: {
  4 + title: 'Owner Arrears',
  5 + payerObj: 'Charge Object',
  6 + ownerName: 'Owner Name',
  7 + phone: 'Phone',
  8 + startTime: 'Start Time',
  9 + endTime: 'End Time',
  10 + total: 'Total',
  11 + unit: 'Unit: Yuan',
  12 + updateTime: 'Update Time'
  13 + },
  14 + ownerOweFeesDemo: {
  15 + openBtn: 'View Owner Arrears'
  16 + }
  17 + },
  18 + zh: {
  19 + ownerOweFees: {
  20 + title: '业主欠费',
  21 + payerObj: '收费对象',
  22 + ownerName: '业主名称',
  23 + phone: '手机号',
  24 + startTime: '开始时间',
  25 + endTime: '结束时间',
  26 + total: '合计',
  27 + unit: '单位:元',
  28 + updateTime: '更新时间'
  29 + },
  30 + ownerOweFeesDemo: {
  31 + openBtn: '查看业主欠费'
  32 + }
  33 + }
  34 +}
0 \ No newline at end of file 35 \ No newline at end of file
src/views/room/ownerRepairsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerRepairs: {
  4 + title: 'Owner Repairs',
  5 + workOrder: 'Work Order ID',
  6 + location: 'Location',
  7 + repairType: 'Repair Type',
  8 + reporter: 'Reporter',
  9 + contact: 'Contact',
  10 + appointmentTime: 'Appointment Time',
  11 + status: 'Status',
  12 + taskProcessed: '(Task Processed)'
  13 + }
  14 + },
  15 + zh: {
  16 + ownerRepairs: {
  17 + title: '业主报修',
  18 + workOrder: '工单编码',
  19 + location: '位置',
  20 + repairType: '报修类型',
  21 + reporter: '报修人',
  22 + contact: '联系方式',
  23 + appointmentTime: '预约时间',
  24 + status: '状态',
  25 + taskProcessed: '(定时任务处理)'
  26 + }
  27 + }
  28 +}
0 \ No newline at end of file 29 \ No newline at end of file
src/views/room/ownerRoomsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + ownerRooms: {
  4 + title: 'Owner Rooms',
  5 + roomId: 'Room ID',
  6 + layer: 'Floor',
  7 + type: 'Type',
  8 + area: 'Built/Indoor Area',
  9 + rent: 'Rent',
  10 + status: 'Room Status',
  11 + oweFee: 'Owed Fee',
  12 + updateDaily: 'Updated daily',
  13 + subtotal: 'Subtotal of owed fees',
  14 + successMessage: 'Data loaded successfully',
  15 + errorMessage: 'Failed to load data'
  16 + }
  17 + },
  18 + zh: {
  19 + ownerRooms: {
  20 + title: '业主房屋',
  21 + roomId: '房屋ID',
  22 + layer: '楼层',
  23 + type: '类型',
  24 + area: '建筑/室内面积',
  25 + rent: '租金',
  26 + status: '房屋状态',
  27 + oweFee: '房屋欠费',
  28 + updateDaily: '按天更新',
  29 + subtotal: '欠费小计',
  30 + successMessage: '数据加载成功',
  31 + errorMessage: '加载数据失败'
  32 + }
  33 + }
  34 +}
0 \ No newline at end of file 35 \ No newline at end of file
src/views/room/roomContractsLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + roomContracts: {
  4 + title: 'Room Contracts',
  5 + contractName: 'Contract Name',
  6 + contractCode: 'Contract Code',
  7 + parentContractCode: 'Parent Contract Code',
  8 + contractType: 'Contract Type',
  9 + operator: 'Operator',
  10 + amount: 'Contract Amount',
  11 + startTime: 'Start Time',
  12 + endTime: 'End Time',
  13 + createTime: 'Draft Time',
  14 + state: 'Status'
  15 + },
  16 + roomContractsDemo: {
  17 + openByOwner: 'Open by Owner',
  18 + openByRoom: 'Open by Room'
  19 + }
  20 + },
  21 + zh: {
  22 + roomContracts: {
  23 + title: '房屋合同',
  24 + contractName: '合同名称',
  25 + contractCode: '合同编号',
  26 + parentContractCode: '父合同编号',
  27 + contractType: '合同类型',
  28 + operator: '经办人',
  29 + amount: '合同金额',
  30 + startTime: '开始时间',
  31 + endTime: '结束时间',
  32 + createTime: '起草时间',
  33 + state: '状态'
  34 + },
  35 + roomContractsDemo: {
  36 + openByOwner: '按业主打开',
  37 + openByRoom: '按房屋打开'
  38 + }
  39 + }
  40 +}
0 \ No newline at end of file 41 \ No newline at end of file
src/views/room/roomLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + roomList: {
  4 + addBuilding: 'Add Building',
  5 + editBuilding: 'Edit Building',
  6 + deleteBuilding: 'Delete Building',
  7 + addUnit: 'Add Unit',
  8 + editUnit: 'Edit Unit',
  9 + deleteUnit: 'Delete Unit',
  10 + addRoom: 'Add Room',
  11 + importRoom: 'Import Property',
  12 + document: 'Document',
  13 + queryCondition: 'Query Condition',
  14 + roomIdPlaceholder: 'Please fill in room number format: Building-Unit-Room',
  15 + selectState: 'Select Status',
  16 + selectRoomType: 'Required, select room type',
  17 + query: 'Query',
  18 + reset: 'Reset',
  19 + room: 'Room',
  20 + floor: 'Floor',
  21 + owner: 'Owner',
  22 + type: 'Type',
  23 + area: 'Building/Indoor Area',
  24 + rent: 'Rent',
  25 + roomStatus: 'Room Status',
  26 + validity: 'Validity Period',
  27 + ownerMembers: 'Owner Members',
  28 + ownerCars: 'Owner Vehicles',
  29 + ownerRooms: 'Owner Rooms',
  30 + complaints: 'Complaints',
  31 + repairs: 'Repairs',
  32 + roomOweFee: 'Room Arrears',
  33 + ownerOweFee: 'Owner Arrears',
  34 + roomContracts: 'Room Contracts',
  35 + operation: 'Operation',
  36 + edit: 'Edit',
  37 + delete: 'Delete',
  38 + handOver: 'Hand Over',
  39 + checkOut: 'Check Out',
  40 + businessAcceptance: 'Business Acceptance',
  41 + layer: 'Layer',
  42 + squareMeter: 'm²',
  43 + roomStatusDesc1: 'Room status is divided into: unsold, unoccupied, handed over, decorated, occupied, etc.',
  44 + roomStatusDesc2: '1. Unsold means there is no relationship between the room and the owner, so the status cannot be manually modified. It needs to be changed to occupied by the owner moving in.',
  45 + roomStatusDesc3: '2. Unoccupied, handed over, decorated, and occupied status indicate that there is a relationship between the owner and the room. They can be modified mutually, mainly used to create different fees based on different status when creating room fees.',
  46 + rentDesc: 'Rent: Mainly used for park-type properties or properties with many rented rooms, residential properties can ignore this.'
  47 + }
  48 + },
  49 + zh: {
  50 + roomList: {
  51 + addBuilding: '添加楼栋',
  52 + editBuilding: '修改楼栋',
  53 + deleteBuilding: '删除楼栋',
  54 + addUnit: '添加单元',
  55 + editUnit: '修改单元',
  56 + deleteUnit: '删除单元',
  57 + addRoom: '添加房屋',
  58 + importRoom: '房产导入',
  59 + document: '文档',
  60 + queryCondition: '查询条件',
  61 + roomIdPlaceholder: '请填写房屋编号 格式 楼栋-单元-房屋',
  62 + selectState: '请选择状态',
  63 + selectRoomType: '必填,请选择房屋类型',
  64 + query: '查询',
  65 + reset: '重置',
  66 + room: '房屋',
  67 + floor: '楼层',
  68 + owner: '业主',
  69 + type: '类型',
  70 + area: '建筑/室内面积',
  71 + rent: '租金',
  72 + roomStatus: '房屋状态',
  73 + validity: '有效期',
  74 + ownerMembers: '业主成员',
  75 + ownerCars: '业主车辆',
  76 + ownerRooms: '业主房屋',
  77 + complaints: '投诉',
  78 + repairs: '报修',
  79 + roomOweFee: '房屋欠费',
  80 + ownerOweFee: '业主欠费',
  81 + roomContracts: '房屋合同',
  82 + operation: '操作',
  83 + edit: '修改',
  84 + delete: '删除',
  85 + handOver: '交房',
  86 + checkOut: '退房',
  87 + businessAcceptance: '业务受理',
  88 + layer: '层',
  89 + squareMeter: '平方米',
  90 + roomStatusDesc1: '房屋状态 分为:未销售,未入住,已交房,已装修,已入住 等状态',
  91 + roomStatusDesc2: '1、未销售表示 房屋和业主之间还没有任何关系,所以修改时状态不能手工修改 需要业主入住房屋的方式 将未销售改为已入住',
  92 + roomStatusDesc3: '2、未入住 已交房 已装修 已入住 状态表示业主和房屋之间已经有关系 可以相互修改,主要作用为在房屋创建费用时根据不同的状态去创建不同的费用',
  93 + rentDesc: '租金:主要用于园区类或者房屋出租比较多的物业使用,小区物业忽略'
  94 + }
  95 + }
  96 +}
0 \ No newline at end of file 97 \ No newline at end of file
src/views/room/roomList.vue 0 → 100644
  1 +<template>
  2 + <div class="room-container">
  3 + <div class="bg-white padding-sm text-left">
  4 + <el-button type="primary" size="small" @click="openAddRoomFloorModal">
  5 + <i class="el-icon-plus"></i>{{ $t('roomList.addBuilding') }}
  6 + </el-button>
  7 + <el-button type="primary" size="small" @click="openUpdateRoomFloorModal">
  8 + <i class="el-icon-edit"></i>{{ $t('roomList.editBuilding') }}
  9 + </el-button>
  10 + <el-button type="primary" size="small" @click="openDeleteRoomFloorModal">
  11 + <i class="el-icon-close"></i>{{ $t('roomList.deleteBuilding') }}
  12 + </el-button>
  13 + <el-button type="primary" size="small" class="margin-left-sm" @click="openAddRoomUnitModal">
  14 + <i class="el-icon-plus"></i>{{ $t('roomList.addUnit') }}
  15 + </el-button>
  16 + <el-button type="primary" size="small" class="margin-left-sm" @click="openUpdateRoomUnitModal">
  17 + <i class="el-icon-edit"></i>{{ $t('roomList.editUnit') }}
  18 + </el-button>
  19 + <el-button type="primary" size="small" class="margin-left-sm" @click="openDeleteRoomUnitModal">
  20 + <i class="el-icon-close"></i>{{ $t('roomList.deleteUnit') }}
  21 + </el-button>
  22 + <el-button type="primary" size="small" class="margin-left-sm" @click="openAddRoom"
  23 + v-if="hasPrivilege('502020082453087940')">
  24 + <i class="el-icon-plus"></i>
  25 + <span>{{ $t('roomList.addRoom') }}</span>
  26 + </el-button>
  27 + <el-button type="primary" size="small" class="margin-left-sm" @click="openImportRoomInfo">
  28 + <i class="el-icon-plus"></i>
  29 + <span>{{ $t('roomList.importRoom') }}</span>
  30 + </el-button>
  31 + <el-button type="primary" size="small" @click="showMarkdown">
  32 + <i class="el-icon-document"></i>
  33 + <span>{{ $t('roomList.document') }}</span>
  34 + </el-button>
  35 + </div>
  36 +
  37 + <el-row class="flex justify-start">
  38 + <el-col :span="4" class="room-floor-unit-tree">
  39 + <floor-unit-tree :call-back-listener="callbackListener" @switchFloor="handleSwitchFloor"
  40 + @switchUnit="handleSwitchUnit" />
  41 + </el-col>
  42 + <el-col :span="20" class="margin-top-xs margin-left-sm">
  43 + <el-card class="ibox">
  44 + <div slot="header" class="clearfix flex justify-between">
  45 + <span>{{ $t('roomList.queryCondition') }}</span>
  46 + </div>
  47 + <el-form :inline="true" class="text-left">
  48 + <el-form-item>
  49 + <el-input :placeholder="$t('roomList.roomIdPlaceholder')" size="small" v-model="roomInfo.conditions.roomId"
  50 + class="form-control form-control-sm"></el-input>
  51 + </el-form-item>
  52 + <el-form-item>
  53 + <el-select v-model="roomInfo.conditions.state" size="small" :placeholder="$t('roomList.selectState')">
  54 + <el-option v-for="(item, index) in roomInfo.states" :key="index" :label="item.name"
  55 + :value="item.statusCd"></el-option>
  56 + </el-select>
  57 + </el-form-item>
  58 + <el-form-item>
  59 + <el-select v-model="roomInfo.conditions.roomSubType" size="small"
  60 + :placeholder="$t('roomList.selectRoomType')">
  61 + <el-option v-for="(item, index) in roomInfo.roomSubTypes" :key="index" :label="item.name"
  62 + :value="item.statusCd"></el-option>
  63 + </el-select>
  64 + </el-form-item>
  65 + <el-form-item>
  66 + <el-select v-model="roomInfo.isAll" size="small" @change="changeIsAll">
  67 + <el-option label="当前楼栋单元" value="N"></el-option>
  68 + <el-option label="全部楼栋单元" value="Y"></el-option>
  69 + </el-select>
  70 + </el-form-item>
  71 + <el-form-item>
  72 + <el-button type="primary" size="small" @click="queryRoomMethod">
  73 + <i class="el-icon-search"></i>{{ $t('roomList.query') }}
  74 + </el-button>
  75 + <el-button type="info" size="small" @click="resetRoomInfo">
  76 + <i class="el-icon-refresh"></i>{{ $t('roomList.reset') }}
  77 + </el-button>
  78 + </el-form-item>
  79 + </el-form>
  80 + </el-card>
  81 +
  82 + <el-card class="">
  83 + <div class=" border-radius">
  84 + <div>
  85 + <el-table :data="roomInfo.rooms" style="width: 100%" border stripe>
  86 + <el-table-column prop="roomId" :label="$t('roomList.room')" width="120" fixed="left"
  87 + class-name="text-center hc-table-fix-left-td">
  88 + <template slot-scope="scope">
  89 + <div class="hc-td">
  90 + {{ scope.row.floorNum }}-{{ scope.row.unitNum }}-{{ scope.row.roomNum }}
  91 + </div>
  92 + </template>
  93 + </el-table-column>
  94 + <el-table-column prop="layer" :label="$t('roomList.floor')" width="100" align="center">
  95 + <template slot-scope="scope">
  96 + <div class="hc-td">
  97 + {{ scope.row.layer }}{{ $t('roomList.layer') }}
  98 + </div>
  99 + </template>
  100 + </el-table-column>
  101 + <el-table-column prop="ownerName" :label="$t('roomList.owner')" width="150" align="center">
  102 + <template slot-scope="scope">
  103 + <div v-if="scope.row.ownerName" class="hc-td hand">
  104 + <a target="_blank" :href="'/#/pages/owner/ownerDetail?ownerId=' + scope.row.ownerId">
  105 + {{ scope.row.ownerName }}({{ scope.row.link }})
  106 + </a>
  107 + </div>
  108 + <div v-else class="hc-td textAuto">-</div>
  109 + </template>
  110 + </el-table-column>
  111 + <el-table-column prop="roomSubTypeName" :label="$t('roomList.type')" width="120" align="center">
  112 + <template slot-scope="scope">
  113 + <div class="hc-td">{{ scope.row.roomSubTypeName }}</div>
  114 + </template>
  115 + </el-table-column>
  116 + <el-table-column :label="$t('roomList.area')" width="150" align="center">
  117 + <template slot-scope="scope">
  118 + <div class="hc-td">
  119 + {{ scope.row.builtUpArea }}/{{ scope.row.roomArea }}
  120 + {{ $t('roomList.squareMeter') }}
  121 + </div>
  122 + </template>
  123 + </el-table-column>
  124 + <el-table-column prop="roomRent" :label="$t('roomList.rent')" width="100" align="center">
  125 + <template slot-scope="scope">
  126 + <div class="hc-td">{{ scope.row.roomRent }}</div>
  127 + </template>
  128 + </el-table-column>
  129 + <el-table-column prop="stateName" :label="$t('roomList.roomStatus')" width="120" align="center">
  130 + <template slot-scope="scope">
  131 + <div class="hc-td">{{ scope.row.stateName }}</div>
  132 + </template>
  133 + </el-table-column>
  134 + <el-table-column :label="$t('roomList.validity')" width="150" align="center">
  135 + <template slot-scope="scope">
  136 + <div class="hc-td">
  137 + {{ scope.row.startTime }}<br>
  138 + ~{{ scope.row.endTime }}
  139 + </div>
  140 + </template>
  141 + </el-table-column>
  142 + <el-table-column :label="$t('roomList.ownerMembers')" width="120" align="center">
  143 + <template slot-scope="scope">
  144 + <div class="hc-td">
  145 + <a href="javascript:void(0)" @click="viewOwnerMembers(scope.row)">
  146 + {{ scope.row.memberCount || 0 }}
  147 + </a>
  148 + </div>
  149 + </template>
  150 + </el-table-column>
  151 + <el-table-column :label="$t('roomList.ownerCars')" width="120" align="center">
  152 + <template slot-scope="scope">
  153 + <div class="hc-td">
  154 + <a href="javascript:void(0)" @click="viewOwnerCars(scope.row)">
  155 + {{ scope.row.carCount || 0 }}
  156 + </a>
  157 + </div>
  158 + </template>
  159 + </el-table-column>
  160 + <el-table-column :label="$t('roomList.ownerRooms')" width="120" align="center">
  161 + <template slot-scope="scope">
  162 + <div class="hc-td">
  163 + <a href="javascript:void(0)" @click="viewOwnerRooms(scope.row)">
  164 + {{ scope.row.roomCount || 0 }}
  165 + </a>
  166 + </div>
  167 + </template>
  168 + </el-table-column>
  169 + <el-table-column :label="$t('roomList.complaints')" width="100" align="center">
  170 + <template slot-scope="scope">
  171 + <div class="hc-td">
  172 + <a href="javascript:void(0)" @click="viewComplaints(scope.row)">
  173 + {{ scope.row.complaintCount || 0 }}
  174 + </a>
  175 + </div>
  176 + </template>
  177 + </el-table-column>
  178 + <el-table-column :label="$t('roomList.repairs')" width="100" align="center">
  179 + <template slot-scope="scope">
  180 + <div class="hc-td">
  181 + <a href="javascript:void(0)" @click="viewRepairs(scope.row)">
  182 + {{ scope.row.repairCount || 0 }}
  183 + </a>
  184 + </div>
  185 + </template>
  186 + </el-table-column>
  187 + <el-table-column :label="$t('roomList.roomOweFee')" width="120" align="center">
  188 + <template slot-scope="scope">
  189 + <div class="hc-td">
  190 + <a href="javascript:void(0)" @click="viewRoomOweFees(scope.row)">
  191 + {{ scope.row.roomOweFee || '0.00' }}
  192 + </a>
  193 + </div>
  194 + </template>
  195 + </el-table-column>
  196 + <el-table-column :label="$t('roomList.ownerOweFee')" width="120" align="center">
  197 + <template slot-scope="scope">
  198 + <div class="hc-td">
  199 + <a href="javascript:void(0)" @click="viewOweFees(scope.row)">
  200 + {{ scope.row.oweFee || '0.00' }}
  201 + </a>
  202 + </div>
  203 + </template>
  204 + </el-table-column>
  205 + <el-table-column :label="$t('roomList.roomContracts')" width="120" align="center">
  206 + <template slot-scope="scope">
  207 + <div class="hc-td">
  208 + <a href="javascript:void(0)" @click="viewRoomContracts(scope.row)">
  209 + {{ scope.row.contractCount || 0 }}
  210 + </a>
  211 + </div>
  212 + </template>
  213 + </el-table-column>
  214 + <el-table-column v-for="(item, index) in roomInfo.listColumns" :key="index" :label="item" width="120"
  215 + align="center">
  216 + <template slot-scope="scope">
  217 + <div class="hc-td">{{ scope.row.listValues[index] || '' }}</div>
  218 + </template>
  219 + </el-table-column>
  220 + <el-table-column :label="$t('roomList.operation')" fixed="right" width="300" align="center"
  221 + class-name="text-center hc-table-fix-right-td">
  222 + <template slot-scope="scope">
  223 + <el-button-group>
  224 + <el-button v-if="hasPrivilege('502020082493857941')" size="mini"
  225 + @click="openEditRoomModel(scope.row)">
  226 + {{ $t('roomList.edit') }}
  227 + </el-button>
  228 + <el-button v-if="hasPrivilege('502020082417457942')" size="mini"
  229 + @click="openDelRoomModel(scope.row)">
  230 + {{ $t('roomList.delete') }}
  231 + </el-button>
  232 + <el-button v-if="scope.row.state == '2002' && hasPrivilege('502023021978930012')" size="mini"
  233 + @click="toRoomBindOwner(scope.row)">
  234 + {{ $t('roomList.handOver') }}
  235 + </el-button>
  236 + <el-button
  237 + v-if="scope.row.state != '2002' && scope.row.ownerId && hasPrivilege('502023021973760015')"
  238 + size="mini" @click="toRoomUnBindOwner(scope.row)">
  239 + {{ $t('roomList.checkOut') }}
  240 + </el-button>
  241 + <el-button v-if="scope.row.state != '2002'" size="mini" @click="toSimplifyAcceptance(scope.row)">
  242 + {{ $t('roomList.businessAcceptance') }}
  243 + </el-button>
  244 + </el-button-group>
  245 + </template>
  246 + </el-table-column>
  247 + </el-table>
  248 + </div>
  249 +
  250 + <el-row class="margin-top">
  251 + <el-col :span="14" class="text-left">
  252 + <div>{{ $t('roomList.roomStatusDesc1') }}</div>
  253 + <div>{{ $t('roomList.roomStatusDesc2') }}</div>
  254 + <div>{{ $t('roomList.roomStatusDesc3') }}</div>
  255 + <div>{{ $t('roomList.rentDesc') }}</div>
  256 + </el-col>
  257 + <el-col :span="10" class="float-right">
  258 + <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
  259 + :current-page="roomInfo.currentPage" :page-sizes="[10, 20, 30, 40]" :page-size="DEFAULT_ROW"
  260 + layout="total, sizes, prev, pager, next, jumper" :total="roomInfo.total"></el-pagination>
  261 + </el-col>
  262 + </el-row>
  263 + </div>
  264 + </el-card>
  265 + </el-col>
  266 + </el-row>
  267 +
  268 + <!-- 子组件 -->
  269 + <search-floor ref="searchFloor" emit-choose-floor="room" emit-load-data="room" />
  270 + <edit-room ref="editRoom" />
  271 + <delete-room ref="deleteRoom" />
  272 + <import-owner-room ref="importOwnerRoom" />
  273 + <add-floor ref="addFloor" />
  274 + <edit-floor ref="editFloor" />
  275 + <delete-floor ref="deleteFloor" />
  276 + <add-unit ref="addUnit" />
  277 + <edit-unit ref="editUnit" />
  278 + <delete-unit ref="deleteUnit" />
  279 + <owner-rooms ref="ownerRooms" />
  280 + <owner-members ref="ownerMembers" />
  281 + <owner-cars ref="ownerCars" />
  282 + <owner-complaints ref="ownerComplaints" />
  283 + <owner-repairs ref="ownerRepairs" />
  284 + <owner-owe-fees ref="ownerOweFees" />
  285 + <room-owe-fees ref="roomOweFees" />
  286 + <room-contracts ref="roomContracts" />
  287 + </div>
  288 +</template>
  289 +
  290 +<script>
  291 +import { getDict } from '@/api/community/communityApi'
  292 +import { queryRooms,getFloors,getUnits } from '@/api/room/roomApi'
  293 +import FloorUnitTree from '@/components/room/floorUnitTree'
  294 +import SearchFloor from '@/components/room/searchFloor'
  295 +import EditRoom from '@/components/room/editRoom'
  296 +import DeleteRoom from '@/components/room/deleteRoom'
  297 +import ImportOwnerRoom from '@/components/room/importOwnerRoom'
  298 +import AddFloor from '@/components/room/addFloor'
  299 +import EditFloor from '@/components/room/editFloor'
  300 +import DeleteFloor from '@/components/room/deleteFloor'
  301 +import AddUnit from '@/components/room/addUnit'
  302 +import EditUnit from '@/components/room/editUnit'
  303 +import DeleteUnit from '@/components/room/deleteUnit'
  304 +import OwnerRooms from '@/components/owner/ownerRooms'
  305 +import OwnerMembers from '@/components/owner/ownerMembers'
  306 +import OwnerCars from '@/components/owner/ownerCars'
  307 +import OwnerComplaints from '@/components/owner/ownerComplaints'
  308 +import OwnerRepairs from '@/components/owner/ownerRepairs'
  309 +import OwnerOweFees from '@/components/owner/ownerOweFees'
  310 +import RoomOweFees from '@/components/room/roomOweFees'
  311 +import RoomContracts from '@/components/room/roomContracts'
  312 +
  313 +const DEFAULT_PAGE = 1
  314 +const DEFAULT_ROW = 10
  315 +
  316 +export default {
  317 + name: 'RoomList',
  318 + components: {
  319 + FloorUnitTree,
  320 + SearchFloor,
  321 + EditRoom,
  322 + DeleteRoom,
  323 + ImportOwnerRoom,
  324 + AddFloor,
  325 + EditFloor,
  326 + DeleteFloor,
  327 + AddUnit,
  328 + EditUnit,
  329 + DeleteUnit,
  330 + OwnerRooms,
  331 + OwnerMembers,
  332 + OwnerCars,
  333 + OwnerComplaints,
  334 + OwnerRepairs,
  335 + OwnerOweFees,
  336 + RoomOweFees,
  337 + RoomContracts
  338 + },
  339 + data() {
  340 + return {
  341 + DEFAULT_PAGE,
  342 + DEFAULT_ROW,
  343 + callbackListener: 'room',
  344 + roomInfo: {
  345 + rooms: [],
  346 + total: 0,
  347 + records: 1,
  348 + floorId: '',
  349 + unitId: '',
  350 + states: [],
  351 + roomNum: '',
  352 + isAll: 'N',
  353 + moreCondition: false,
  354 + conditions: {
  355 + floorId: '',
  356 + floorName: '',
  357 + unitId: '',
  358 + roomNum: '',
  359 + roomId: '',
  360 + state: '',
  361 + section: '',
  362 + roomType: '1010301',
  363 + roomSubType: '',
  364 + flag: ''
  365 + },
  366 + currentPage: DEFAULT_PAGE,
  367 + listColumns: [],
  368 + roomSubTypes: []
  369 + }
  370 + }
  371 + },
  372 + mounted() {
  373 + this.initData()
  374 + // window.addEventListener('resize', this.handleResize)
  375 + },
  376 + beforeDestroy() {
  377 + // window.removeEventListener('resize', this.handleResize)
  378 + },
  379 + methods: {
  380 + async initData() {
  381 + this.roomInfo.conditions.floorId = this.$route.query.floorId || ''
  382 + this.roomInfo.conditions.floorName = this.$route.query.floorName || ''
  383 +
  384 + try {
  385 + // 获取房屋状态字典
  386 + const stateData = await getDict('building_room', 'state')
  387 + this.roomInfo.states = stateData
  388 +
  389 + // 获取房屋类型字典
  390 + const roomTypeData = await getDict('building_room', 'room_sub_type')
  391 + this.roomInfo.roomSubTypes = roomTypeData
  392 +
  393 + this.listRoom(DEFAULT_PAGE, DEFAULT_ROW)
  394 + } catch (error) {
  395 + console.error('初始化数据失败:', error)
  396 + }
  397 + },
  398 +
  399 + async listRoom(page, row) {
  400 + this.roomInfo.conditions.page = page
  401 + this.roomInfo.conditions.row = row
  402 + this.roomInfo.conditions.communityId = this.getCommunityId()
  403 +
  404 + const params = { ...this.roomInfo.conditions }
  405 +
  406 + // 处理房间号格式
  407 + const allNum = params.roomId || ''
  408 + const allNums = allNum.split('-')
  409 + if (allNums.length >= 3) {
  410 + params.floorNum = allNums[0].trim()
  411 + params.unitNum = allNums[1].trim()
  412 + params.roomNum = allNums.slice(2).join('-').trim()
  413 + params.roomId = ''
  414 + params.unitId = ''
  415 + params.floorId = ''
  416 + }
  417 +
  418 + try {
  419 + const res = await queryRooms(params)
  420 + this.roomInfo.total = res.total
  421 + this.roomInfo.records = res.records
  422 + this.roomInfo.rooms = res.rooms
  423 + this.dealRoomAttr(res.rooms)
  424 + } catch (error) {
  425 + console.error('获取房间列表失败:', error)
  426 + this.$message.error('获取房间列表失败')
  427 + }
  428 + },
  429 +
  430 + dealRoomAttr(rooms) {
  431 + if (!rooms || !rooms.length) return
  432 +
  433 + // 获取表格列配置
  434 + this.getColumns(rooms, () => {
  435 + rooms.forEach(item => {
  436 + this.getColumnsValue(item)
  437 + })
  438 + })
  439 + },
  440 +
  441 + getColumnsValue(room) {
  442 + room.listValues = []
  443 + if (!room.roomAttrDto || !room.roomAttrDto.length) {
  444 + this.roomInfo.listColumns.forEach(() => {
  445 + room.listValues.push('')
  446 + })
  447 + return
  448 + }
  449 +
  450 + this.roomInfo.listColumns.forEach(column => {
  451 + const attr = room.roomAttrDto.find(dto => dto.specName === column)
  452 + room.listValues.push(attr ? attr.valueName : '')
  453 + })
  454 + },
  455 +
  456 + async getColumns(rooms, callback) {
  457 + try {
  458 + const attrSpecs = await getDict('building_room_attr')
  459 + this.roomInfo.listColumns = attrSpecs
  460 + .filter(item => item.listShow === 'Y')
  461 + .map(item => item.specName)
  462 + callback()
  463 + } catch (error) {
  464 + console.error('获取房屋属性失败:', error)
  465 + }
  466 + },
  467 +
  468 + handleSwitchFloor(data) {
  469 + this.roomInfo.conditions.floorId = data.floorId
  470 + this.roomInfo.conditions.unitId = ''
  471 + this.roomInfo.conditions.flag = 1
  472 + this.roomInfo.isAll = 'N'
  473 + this.listRoom(DEFAULT_PAGE, DEFAULT_ROW)
  474 + },
  475 +
  476 + handleSwitchUnit(data) {
  477 + this.roomInfo.conditions.floorId = ''
  478 + this.roomInfo.conditions.unitId = data.unitId
  479 + this.roomInfo.conditions.flag = 1
  480 + this.roomInfo.isAll = 'N'
  481 + this.listRoom(DEFAULT_PAGE, DEFAULT_ROW)
  482 + },
  483 +
  484 + handleSizeChange(val) {
  485 + this.listRoom(this.roomInfo.currentPage, val)
  486 + },
  487 +
  488 + handleCurrentChange(val) {
  489 + this.roomInfo.currentPage = val
  490 + this.listRoom(val, DEFAULT_ROW)
  491 + },
  492 +
  493 + computeTableDivWidth() {
  494 + // const bodyWidth = document.body.clientWidth
  495 + // const menuWidth = document.getElementById('menu-nav').offsetWidth || 0
  496 + // const treeWidth = document.querySelector('.room-floor-unit-tree').offsetWidth || 0
  497 + // return `${bodyWidth - menuWidth - treeWidth - 80}px`
  498 + return '100%'
  499 + },
  500 +
  501 + handleResize() {
  502 + this.$forceUpdate()
  503 + },
  504 +
  505 + // 按钮操作相关方法
  506 + openAddRoom() {
  507 + this.$router.push('/pages/property/addRoomView')
  508 + },
  509 +
  510 + openEditRoomModel(room) {
  511 + this.$refs.editRoom.open(room)
  512 + },
  513 +
  514 + openDelRoomModel(room) {
  515 + this.$refs.deleteRoom.open(room)
  516 + },
  517 +
  518 + queryRoomMethod() {
  519 + this.roomInfo.conditions.flag = 0
  520 + this.listRoom(DEFAULT_PAGE, DEFAULT_ROW)
  521 + },
  522 +
  523 + resetRoomInfo() {
  524 + this.roomInfo.conditions = {
  525 + floorId: '',
  526 + floorName: '',
  527 + unitId: '',
  528 + roomNum: '',
  529 + roomId: '',
  530 + state: '',
  531 + section: '',
  532 + roomType: '1010301',
  533 + roomSubType: '',
  534 + flag: ''
  535 + }
  536 + this.listRoom(DEFAULT_PAGE, DEFAULT_ROW)
  537 + },
  538 +
  539 + openImportRoomInfo() {
  540 + this.$refs.importOwnerRoom.open()
  541 + },
  542 +
  543 + openAddRoomFloorModal() {
  544 + this.$refs.addFloor.open()
  545 + },
  546 +
  547 + async openUpdateRoomFloorModal() {
  548 + if (!this.roomInfo.conditions.floorId) {
  549 + this.$message.warning('请先选择楼栋')
  550 + return
  551 + }
  552 +
  553 + try {
  554 + const floorData = await this.loadFloor(this.roomInfo.conditions.floorId)
  555 + this.$refs.editFloor.open(floorData)
  556 + } catch (error) {
  557 + console.error('加载楼栋信息失败:', error)
  558 + }
  559 + },
  560 +
  561 + async openDeleteRoomFloorModal() {
  562 + if (!this.roomInfo.conditions.floorId) {
  563 + this.$message.warning('请先选择楼栋')
  564 + return
  565 + }
  566 +
  567 + try {
  568 + const floorData = await this.loadFloor(this.roomInfo.conditions.floorId)
  569 + this.$refs.deleteFloor.open(floorData)
  570 + } catch (error) {
  571 + console.error('加载楼栋信息失败:', error)
  572 + }
  573 + },
  574 +
  575 + openAddRoomUnitModal() {
  576 + if (!this.roomInfo.conditions.floorId) {
  577 + this.$message.warning('请先选择楼栋')
  578 + return
  579 + }
  580 + this.$refs.addUnit.open({ floorId: this.roomInfo.conditions.floorId })
  581 + },
  582 +
  583 + async openUpdateRoomUnitModal() {
  584 + if (!this.roomInfo.conditions.unitId) {
  585 + this.$message.warning('请先选择单元')
  586 + return
  587 + }
  588 +
  589 + try {
  590 + const unitData = await this.loadUnits(this.roomInfo.conditions.unitId)
  591 + this.$refs.editUnit.open(unitData)
  592 + } catch (error) {
  593 + console.error('加载单元信息失败:', error)
  594 + }
  595 + },
  596 +
  597 + async openDeleteRoomUnitModal() {
  598 + if (!this.roomInfo.conditions.unitId) {
  599 + this.$message.warning('请先选择单元')
  600 + return
  601 + }
  602 +
  603 + try {
  604 + const unitData = await this.loadUnits(this.roomInfo.conditions.unitId)
  605 + this.$refs.deleteUnit.open(unitData)
  606 + } catch (error) {
  607 + console.error('加载单元信息失败:', error)
  608 + }
  609 + },
  610 +
  611 + changeIsAll() {
  612 + if (this.roomInfo.isAll === 'Y') {
  613 + this.roomInfo.conditions.floorId = ''
  614 + this.roomInfo.conditions.unitId = ''
  615 + }
  616 + this.listRoom(this.roomInfo.currentPage, DEFAULT_ROW)
  617 + },
  618 +
  619 + toSimplifyAcceptance(room) {
  620 + const date = new Date()
  621 + localStorage.setItem('JAVA110_IS_BACK', date.getTime())
  622 + localStorage.setItem('simplifyAcceptanceSearch', JSON.stringify({
  623 + searchType: '1',
  624 + searchValue: `${room.floorNum}-${room.unitNum}-${room.roomNum}`,
  625 + searchPlaceholder: '请输入房屋编号 楼栋-单元-房屋 如1-1-1',
  626 + }))
  627 + this.$router.push('/pages/property/simplifyAcceptance?tab=业务受理')
  628 + },
  629 +
  630 + viewOwnerRooms(room) {
  631 + this.$refs.ownerRooms.open(room)
  632 + },
  633 +
  634 + viewOwnerMembers(room) {
  635 + this.$refs.ownerMembers.open(room.ownerId)
  636 + },
  637 +
  638 + viewOwnerCars(room) {
  639 + this.$refs.ownerCars.open(room.ownerId)
  640 + },
  641 +
  642 + viewComplaints(room) {
  643 + this.$refs.ownerComplaints.open(room.ownerId)
  644 + },
  645 +
  646 + viewRepairs(room) {
  647 + this.$refs.ownerRepairs.open(room.ownerId)
  648 + },
  649 +
  650 + viewOweFees(room) {
  651 + this.$refs.ownerOweFees.open(room.ownerId)
  652 + },
  653 +
  654 + viewRoomOweFees(room) {
  655 + this.$refs.roomOweFees.open(room.roomId)
  656 + },
  657 +
  658 + viewRoomContracts(room) {
  659 + this.$refs.roomContracts.open({ roomId: room.roomId })
  660 + },
  661 +
  662 + toRoomBindOwner(room) {
  663 + this.$router.push(`/pages/owner/roomBindOwner?roomId=${room.roomId}`)
  664 + },
  665 +
  666 + toRoomUnBindOwner(room) {
  667 + this.$router.push(`/pages/property/deleteOwnerRoom?ownerId=${room.ownerId}`)
  668 + },
  669 +
  670 + showMarkdown() {
  671 + this.$router.push('/pages/property/room')
  672 + },
  673 +
  674 + async loadFloor(floorId) {
  675 + const params = {
  676 + page: 1,
  677 + row: 1,
  678 + communityId: this.getCommunityId(),
  679 + floorId: floorId
  680 + }
  681 + const res = await getFloors(params)
  682 + return res.apiFloorDataVoList[0]
  683 + },
  684 +
  685 + async loadUnits(unitId) {
  686 + const params = {
  687 + unitId: unitId,
  688 + communityId: this.getCommunityId(),
  689 + }
  690 + const res = await getUnits(params)
  691 + return res[0]
  692 + }
  693 + }
  694 +}
  695 +</script>
  696 +
  697 +<style scoped>
  698 +.room-container {
  699 + padding: 15px;
  700 +}
  701 +
  702 +.bg-white {
  703 + background-color: #fff;
  704 +}
  705 +
  706 +.padding-sm {
  707 + padding: 10px;
  708 +}
  709 +
  710 +.margin-left-sm {
  711 + margin-left: 10px;
  712 +}
  713 +
  714 +.margin-top-xs {
  715 + margin-top: 5px;
  716 +}
  717 +
  718 +.ibox {
  719 + margin-bottom: 15px;
  720 +}
  721 +
  722 +.ibox-title {
  723 + border-color: #e7eaec;
  724 + background-color: #f9f9f9;
  725 + border-bottom: 1px solid #e7eaec;
  726 + padding: 10px 15px;
  727 +}
  728 +
  729 +.ibox-content {
  730 + padding: 15px;
  731 +}
  732 +
  733 +.hc-table-div {
  734 + overflow-x: auto;
  735 +}
  736 +
  737 +.hc-td {
  738 + padding: 5px;
  739 + text-align: center;
  740 +}
  741 +
  742 +.text-center {
  743 + text-align: center;
  744 +}
  745 +
  746 +.hand {
  747 + cursor: pointer;
  748 +}
  749 +
  750 +.textAuto {
  751 + text-align: center;
  752 +}
  753 +
  754 +.float-right {
  755 + float: right;
  756 +}
  757 +
  758 +.border-radius {
  759 + border-radius: 4px;
  760 +}
  761 +</style>
0 \ No newline at end of file 762 \ No newline at end of file
src/views/room/roomOweFeesLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + roomOweFees: {
  4 + title: 'Room Arrears',
  5 + payerObj: 'Charge Object',
  6 + ownerName: 'Owner Name',
  7 + phone: 'Phone',
  8 + startTime: 'Start Time',
  9 + endTime: 'End Time',
  10 + total: 'Total',
  11 + unit: 'Unit: Yuan',
  12 + updateTime: 'Update Time'
  13 + },
  14 + roomOweFeesDemo: {
  15 + openBtn: 'View Room Arrears'
  16 + }
  17 + },
  18 + zh: {
  19 + roomOweFees: {
  20 + title: '房屋欠费',
  21 + payerObj: '收费对象',
  22 + ownerName: '业主名称',
  23 + phone: '手机号',
  24 + startTime: '开始时间',
  25 + endTime: '结束时间',
  26 + total: '合计',
  27 + unit: '单位:元',
  28 + updateTime: '更新时间'
  29 + },
  30 + roomOweFeesDemo: {
  31 + openBtn: '查看房屋欠费'
  32 + }
  33 + }
  34 +}
0 \ No newline at end of file 35 \ No newline at end of file
src/views/room/searchFloorLang.js 0 → 100644
  1 +export const messages = {
  2 + en: {
  3 + room: {
  4 + searchFloor: {
  5 + title: 'Building Search',
  6 + placeholder: {
  7 + floorId: 'Please enter building ID',
  8 + floorName: 'Please enter building name',
  9 + floorNum: 'Please enter building number'
  10 + },
  11 + table: {
  12 + floorId: 'Building ID',
  13 + floorName: 'Name',
  14 + floorNum: 'Number',
  15 + creator: 'Creator',
  16 + actions: 'Actions'
  17 + }
  18 + }
  19 + }
  20 + },
  21 + zh: {
  22 + room: {
  23 + searchFloor: {
  24 + title: '小区楼',
  25 + placeholder: {
  26 + floorId: '请输入楼栋ID',
  27 + floorName: '请输入楼栋名称',
  28 + floorNum: '请输入楼栋编号'
  29 + },
  30 + table: {
  31 + floorId: '楼ID',
  32 + floorName: '名称',
  33 + floorNum: '编号',
  34 + creator: '创建人',
  35 + actions: '操作'
  36 + }
  37 + }
  38 + }
  39 + }
  40 +}
0 \ No newline at end of file 41 \ No newline at end of file