手机端
This commit is contained in:
parent
fcf97c48bd
commit
de9df89004
294
src/App.vue
294
src/App.vue
|
|
@ -1,12 +1,30 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<el-container>
|
||||
<el-header height="60px" style="background-color: #333; color: white; display: flex; align-items: center; justify-content: space-between;">
|
||||
<h1 style="margin: 0; font-size: 18px;">租房管理系统</h1>
|
||||
<el-button type="primary" plain @click="logout">退出</el-button>
|
||||
<!-- 顶部导航栏 -->
|
||||
<el-header height="60px" class="app-header">
|
||||
<div class="header-left">
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<el-button
|
||||
v-if="isMobile"
|
||||
type="text"
|
||||
class="menu-toggle-btn"
|
||||
@click="drawerVisible = true"
|
||||
>
|
||||
<i class="el-icon-s-fold" style="font-size: 24px; color: white;"></i>
|
||||
</el-button>
|
||||
<h1 class="app-title">租房管理系统</h1>
|
||||
</div>
|
||||
<el-button type="primary" plain size="small" @click="logout">退出</el-button>
|
||||
</el-header>
|
||||
|
||||
<el-container>
|
||||
<el-aside width="200px" style="background-color: #f0f2f5; min-height: calc(100vh - 60px);">
|
||||
<!-- PC端侧边栏 -->
|
||||
<el-aside
|
||||
v-if="!isMobile"
|
||||
width="200px"
|
||||
class="app-aside"
|
||||
>
|
||||
<el-menu
|
||||
:default-active="activeIndex"
|
||||
class="el-menu-vertical-demo"
|
||||
|
|
@ -53,11 +71,74 @@
|
|||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
<el-main style="padding: 20px;">
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<el-main class="app-main">
|
||||
<router-view />
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
|
||||
<!-- 移动端侧边栏抽屉 -->
|
||||
<el-drawer
|
||||
:visible.sync="drawerVisible"
|
||||
:with-header="false"
|
||||
:size="drawerWidth"
|
||||
direction="ltr"
|
||||
class="mobile-drawer"
|
||||
>
|
||||
<div class="drawer-header">
|
||||
<h3>菜单</h3>
|
||||
<el-button type="text" @click="drawerVisible = false">
|
||||
<i class="el-icon-close" style="font-size: 20px;"></i>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-menu
|
||||
:default-active="activeIndex"
|
||||
class="el-menu-vertical-demo"
|
||||
@select="handleMobileSelect"
|
||||
background-color="#fff"
|
||||
text-color="#333"
|
||||
active-text-color="#409EFF"
|
||||
>
|
||||
<el-menu-item index="dashboard">
|
||||
<i class="el-icon-s-home"></i>
|
||||
<span>首页</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="region-list">
|
||||
<i class="el-icon-location"></i>
|
||||
<span>区域管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="apartment-list">
|
||||
<i class="el-icon-office-building"></i>
|
||||
<span>公寓管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="room-list">
|
||||
<i class="el-icon-menu"></i>
|
||||
<span>房间管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="rental-list">
|
||||
<i class="el-icon-key"></i>
|
||||
<span>租房管理</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="rental-archive">
|
||||
<i class="el-icon-document"></i>
|
||||
<span>租赁档案</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="water-archive">
|
||||
<i class="el-icon-document"></i>
|
||||
<span>水费档案</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="rent-statistics">
|
||||
<i class="el-icon-data-analysis"></i>
|
||||
<span>租金统计</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="room-statistics">
|
||||
<i class="el-icon-data-analysis"></i>
|
||||
<span>房间状态统计</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -66,13 +147,40 @@ export default {
|
|||
name: 'App',
|
||||
data() {
|
||||
return {
|
||||
activeIndex: 'dashboard'
|
||||
activeIndex: 'dashboard',
|
||||
isMobile: false,
|
||||
drawerVisible: false,
|
||||
drawerWidth: '70%'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.checkDevice()
|
||||
window.addEventListener('resize', this.checkDevice)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.checkDevice)
|
||||
},
|
||||
methods: {
|
||||
checkDevice() {
|
||||
const width = window.innerWidth
|
||||
this.isMobile = width <= 768
|
||||
// 根据屏幕宽度调整抽屉大小
|
||||
if (width <= 375) {
|
||||
this.drawerWidth = '80%'
|
||||
} else if (width <= 768) {
|
||||
this.drawerWidth = '70%'
|
||||
}
|
||||
},
|
||||
handleSelect(key, keyPath) {
|
||||
this.activeIndex = key
|
||||
// 根据选择的菜单项导航到对应的路由
|
||||
this.navigateToRoute(key)
|
||||
},
|
||||
handleMobileSelect(key, keyPath) {
|
||||
this.activeIndex = key
|
||||
this.drawerVisible = false
|
||||
this.navigateToRoute(key)
|
||||
},
|
||||
navigateToRoute(key) {
|
||||
const routeMap = {
|
||||
'dashboard': '/',
|
||||
'region-list': '/region/list',
|
||||
|
|
@ -93,7 +201,6 @@ export default {
|
|||
}
|
||||
},
|
||||
logout() {
|
||||
// 退出登录逻辑
|
||||
this.$message.success('退出成功')
|
||||
}
|
||||
}
|
||||
|
|
@ -114,8 +221,179 @@ export default {
|
|||
color: #2c3e50;
|
||||
}
|
||||
|
||||
/* 顶部导航栏样式 */
|
||||
.app-header {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.menu-toggle-btn {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.app-aside {
|
||||
background-color: #f0f2f5;
|
||||
min-height: calc(100vh - 60px);
|
||||
}
|
||||
|
||||
.el-menu-vertical-demo:not(.el-menu--collapse) {
|
||||
width: 200px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
/* 主内容区样式 */
|
||||
.app-main {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
min-height: calc(100vh - 60px);
|
||||
}
|
||||
|
||||
/* 移动端抽屉样式 */
|
||||
.mobile-drawer .el-drawer__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.drawer-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.app-header {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.app-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* 表格横向滚动 */
|
||||
.el-table {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
/* 表单元素适配 */
|
||||
.el-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
padding: 0 0 8px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
/* 搜索表单适配 */
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-input,
|
||||
.search-form .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 卡片适配 */
|
||||
.el-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.el-card__header {
|
||||
padding: 12px 15px;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
/* 分页适配 */
|
||||
.el-pagination {
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.el-pagination .el-pagination__total,
|
||||
.el-pagination .el-pagination__sizes,
|
||||
.el-pagination .el-pagination__jump {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 按钮组适配 */
|
||||
.el-button + .el-button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* 对话框适配 */
|
||||
.el-dialog {
|
||||
width: 90% !important;
|
||||
margin-top: 10vh !important;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏幕手机适配 */
|
||||
@media screen and (max-width: 375px) {
|
||||
.app-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.app-main {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -3,6 +3,7 @@ import App from './App.vue'
|
|||
import router from './router'
|
||||
import ElementUI from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import './styles/responsive.css'
|
||||
|
||||
Vue.use(ElementUI)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
/* 全局响应式样式 */
|
||||
|
||||
/* 移动端隐藏类 */
|
||||
.hidden-xs-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hidden-sm-and-up {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.hidden-xs-only {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.hidden-sm-and-up {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* 表单适配 */
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-input,
|
||||
.search-form .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 表格横向滚动 */
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
/* 分页适配 */
|
||||
.pagination-wrapper,
|
||||
.pagination {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 卡片头部适配 */
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 移动端卡片列表样式 */
|
||||
.mobile-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mobile-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.mobile-card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.mobile-card-id {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.mobile-card-body {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mobile-card-label {
|
||||
color: #909399;
|
||||
min-width: 70px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mobile-card-value {
|
||||
color: #606266;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.mobile-card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
/* 对话框适配 */
|
||||
.el-dialog {
|
||||
width: 90% !important;
|
||||
margin-top: 10vh !important;
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.hidden-sm-and-up {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏幕手机适配 */
|
||||
@media screen and (max-width: 375px) {
|
||||
.mobile-card {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.mobile-card-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,10 +6,10 @@
|
|||
</el-card>
|
||||
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-location"></el-icon>
|
||||
<i class="el-icon-location stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ regionCount }}</div>
|
||||
<div class="stat-label">区域数量</div>
|
||||
|
|
@ -17,10 +17,10 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-building"></el-icon>
|
||||
<i class="el-icon-office-building stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ apartmentCount }}</div>
|
||||
<div class="stat-label">公寓数量</div>
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-home"></el-icon>
|
||||
<i class="el-icon-menu stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ roomCount }}</div>
|
||||
<div class="stat-label">房间数量</div>
|
||||
|
|
@ -40,10 +40,10 @@
|
|||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-s-finance"></el-icon>
|
||||
<i class="el-icon-house stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ emptyRoomCount }}</div>
|
||||
<div class="stat-label">空房数量</div>
|
||||
|
|
@ -51,10 +51,10 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-s-finance"></el-icon>
|
||||
<i class="el-icon-key stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ rentedRoomCount }}</div>
|
||||
<div class="stat-label">在租数量</div>
|
||||
|
|
@ -62,10 +62,10 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-s-finance"></el-icon>
|
||||
<i class="el-icon-time stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ soonExpireRoomCount }}</div>
|
||||
<div class="stat-label">即将到期</div>
|
||||
|
|
@ -73,10 +73,10 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-s-finance"></el-icon>
|
||||
<i class="el-icon-warning stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">{{ expiredRoomCount }}</div>
|
||||
<div class="stat-label">已到期</div>
|
||||
|
|
@ -84,23 +84,23 @@
|
|||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-s-finance"></el-icon>
|
||||
<i class="el-icon-money stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">¥{{ collectedRentAmount }}</div>
|
||||
<div class="stat-value">{{ formatMoney(collectedRentAmount) }}</div>
|
||||
<div class="stat-label">已收租金</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8">
|
||||
<el-col :xs="12" :sm="12" :md="8">
|
||||
<el-card class="stat-card">
|
||||
<div class="stat-item">
|
||||
<el-icon class="el-icon-s-finance"></el-icon>
|
||||
<i class="el-icon-water-cup stat-icon"></i>
|
||||
<div class="stat-info">
|
||||
<div class="stat-value">¥{{ collectedWaterAmount }}</div>
|
||||
<div class="stat-value">{{ formatMoney(collectedWaterAmount) }}</div>
|
||||
<div class="stat-label">已收水费</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -108,23 +108,31 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card style="margin-top: 20px;">
|
||||
<el-card class="stats-table-card">
|
||||
<template slot="header">
|
||||
<div class="card-header">
|
||||
<span>区域公寓房间状态分布</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="regionApartmentHouseStats" style="width: 100%" show-summary :summary-method="getSummary">
|
||||
<el-table-column prop="region" label="区域" width="180"></el-table-column>
|
||||
<el-table-column prop="apartment" label="公寓" width="180"></el-table-column>
|
||||
<el-table-column prop="empty" label="空房" width="80"></el-table-column>
|
||||
<el-table-column prop="rented" label="在租" width="80"></el-table-column>
|
||||
<el-table-column prop="soon_expire" label="即将到期" width="100"></el-table-column>
|
||||
<el-table-column prop="expired" label="已到期" width="80"></el-table-column>
|
||||
<el-table-column prop="cleaning" label="打扫中" width="80"></el-table-column>
|
||||
<el-table-column prop="maintenance" label="维修中" width="80"></el-table-column>
|
||||
<el-table-column prop="total" label="总数" width="80"></el-table-column>
|
||||
</el-table>
|
||||
<div class="table-wrapper">
|
||||
<el-table
|
||||
:data="regionApartmentHouseStats"
|
||||
style="width: 100%"
|
||||
show-summary
|
||||
:summary-method="getSummary"
|
||||
class="stats-table"
|
||||
>
|
||||
<el-table-column prop="region" label="区域" min-width="100"></el-table-column>
|
||||
<el-table-column prop="apartment" label="公寓" min-width="100"></el-table-column>
|
||||
<el-table-column prop="empty" label="空房" width="70"></el-table-column>
|
||||
<el-table-column prop="rented" label="在租" width="70"></el-table-column>
|
||||
<el-table-column prop="soon_expire" label="即将到期" width="90"></el-table-column>
|
||||
<el-table-column prop="expired" label="已到期" width="70"></el-table-column>
|
||||
<el-table-column prop="cleaning" label="打扫中" width="70"></el-table-column>
|
||||
<el-table-column prop="maintenance" label="维修中" width="70"></el-table-column>
|
||||
<el-table-column prop="total" label="总数" width="70"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -178,6 +186,12 @@ export default {
|
|||
this.$message.error('加载数据失败')
|
||||
}
|
||||
},
|
||||
formatMoney(value) {
|
||||
if (value >= 10000) {
|
||||
return '¥' + (value / 10000).toFixed(1) + '万'
|
||||
}
|
||||
return '¥' + value
|
||||
},
|
||||
getSummary(param) {
|
||||
const { columns, data } = param;
|
||||
const sums = [];
|
||||
|
|
@ -208,32 +222,39 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.dashboard {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.welcome-card {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
padding: 30px 0;
|
||||
}
|
||||
|
||||
.welcome-card h2 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 24px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.welcome-card p {
|
||||
margin: 0;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
height: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.stat-item .el-icon {
|
||||
.stat-icon {
|
||||
font-size: 36px;
|
||||
color: #409EFF;
|
||||
margin-right: 20px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
|
|
@ -241,14 +262,14 @@ export default {
|
|||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
|
|
@ -257,4 +278,77 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stats-table-card {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.stats-table {
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.welcome-card {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.welcome-card h2 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.welcome-card p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
padding: 5px;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 24px;
|
||||
margin-right: 0;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.stats-table-card {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 375px) {
|
||||
.welcome-card h2 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
<span>添加公寓</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="apartmentForm" :rules="rules" ref="apartmentForm" label-width="100px">
|
||||
<el-form :model="apartmentForm" :rules="rules" ref="apartmentForm" label-width="100px" class="form-content">
|
||||
<el-form-item label="区域" prop="regionId">
|
||||
<el-select v-model="apartmentForm.regionId" placeholder="请选择区域">
|
||||
<el-select v-model="apartmentForm.regionId" placeholder="请选择区域" style="width: 100%">
|
||||
<el-option v-for="region in regions" :key="region.id" :label="region.name" :value="region.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<el-form-item label="地址" prop="address">
|
||||
<el-input v-model="apartmentForm.address" placeholder="请输入地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -90,7 +90,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.apartment-add {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -98,4 +98,38 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
<span>编辑公寓</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="apartmentForm" :rules="rules" ref="apartmentForm" label-width="100px">
|
||||
<el-form :model="apartmentForm" :rules="rules" ref="apartmentForm" label-width="100px" class="form-content">
|
||||
<el-form-item label="区域" prop="regionId">
|
||||
<el-select v-model="apartmentForm.regionId" placeholder="请选择区域">
|
||||
<el-select v-model="apartmentForm.regionId" placeholder="请选择区域" style="width: 100%">
|
||||
<el-option v-for="region in regions" :key="region.id" :label="region.name" :value="region.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<el-form-item label="地址" prop="address">
|
||||
<el-input v-model="apartmentForm.address" placeholder="请输入地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -103,7 +103,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.apartment-edit {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -111,4 +111,38 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,12 +4,14 @@
|
|||
<template slot="header">
|
||||
<div class="card-header">
|
||||
<span>公寓管理</span>
|
||||
<el-button type="primary" @click="handleAdd">添加公寓</el-button>
|
||||
<el-button type="primary" size="small" @click="handleAdd">添加公寓</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<el-form-item label="区域">
|
||||
<el-select v-model="searchForm.regionId" placeholder="请选择区域">
|
||||
<el-select v-model="searchForm.regionId" placeholder="请选择区域" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="region in regions" :key="region.id" :label="region.name" :value="region.id"></el-option>
|
||||
</el-select>
|
||||
|
|
@ -22,22 +24,55 @@
|
|||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="apartments" style="width: 100%">
|
||||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||
<el-table-column prop="regionName" label="区域"></el-table-column>
|
||||
<el-table-column prop="name" label="公寓名称"></el-table-column>
|
||||
<el-table-column prop="address" label="地址"></el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="primary" @click="handleEdit(scope.row.id)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination" style="margin-top: 20px;">
|
||||
|
||||
<!-- PC端表格 -->
|
||||
<div class="table-wrapper hidden-xs-only">
|
||||
<el-table :data="apartments" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||
<el-table-column prop="regionName" label="区域" min-width="100"></el-table-column>
|
||||
<el-table-column prop="name" label="公寓名称" min-width="120"></el-table-column>
|
||||
<el-table-column prop="address" label="地址" min-width="200" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="primary" @click="handleEdit(scope.row.id)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="mobile-list hidden-sm-and-up">
|
||||
<div v-for="item in apartments" :key="item.id" class="mobile-card">
|
||||
<div class="mobile-card-header">
|
||||
<span class="mobile-card-title">{{ item.name }}</span>
|
||||
<span class="mobile-card-id">ID: {{ item.id }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-body">
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">区域:</span>
|
||||
<span class="mobile-card-value">{{ item.regionName || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">地址:</span>
|
||||
<span class="mobile-card-value">{{ item.address || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">创建时间:</span>
|
||||
<span class="mobile-card-value">{{ item.createTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-footer">
|
||||
<el-button size="mini" type="primary" @click="handleEdit(item.id)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(item.id)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="paginationLayout"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
|
|
@ -65,14 +100,30 @@ export default {
|
|||
name: ''
|
||||
},
|
||||
currentPage: 1,
|
||||
pageSize: 10
|
||||
pageSize: 10,
|
||||
isLoading: false,
|
||||
isMobile: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
paginationLayout() {
|
||||
return this.isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.checkDevice()
|
||||
window.addEventListener('resize', this.checkDevice)
|
||||
this.loadData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.checkDevice)
|
||||
},
|
||||
methods: {
|
||||
checkDevice() {
|
||||
this.isMobile = window.innerWidth <= 768
|
||||
},
|
||||
async loadData() {
|
||||
this.isLoading = true
|
||||
try {
|
||||
// 加载区域数据
|
||||
const regionsResponse = await regionApi.getAll()
|
||||
|
|
@ -98,6 +149,8 @@ export default {
|
|||
this.total = apartmentsResponse.total
|
||||
} catch (error) {
|
||||
this.$message.error('加载数据失败')
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
}
|
||||
},
|
||||
handleAdd() {
|
||||
|
|
@ -137,12 +190,12 @@ export default {
|
|||
},
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val
|
||||
this.loadApartments()
|
||||
this.loadData()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.pageSize = val
|
||||
this.currentPage = 1
|
||||
this.loadApartments()
|
||||
this.loadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +203,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.apartment-list {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -163,8 +216,125 @@ export default {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 移动端卡片列表样式 */
|
||||
.mobile-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.mobile-card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.mobile-card-id {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.mobile-card-body {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mobile-card-label {
|
||||
color: #909399;
|
||||
min-width: 70px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mobile-card-value {
|
||||
color: #606266;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.mobile-card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
/* 响应式显示控制 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.hidden-xs-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-input,
|
||||
.search-form .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.hidden-sm-and-up {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
<span>添加区域</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="regionForm" :rules="rules" ref="regionForm" label-width="100px">
|
||||
<el-form :model="regionForm" :rules="rules" ref="regionForm" label-width="100px" class="form-content">
|
||||
<el-form-item label="区域名称" prop="name">
|
||||
<el-input v-model="regionForm.name" placeholder="请输入区域名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="区域描述" prop="description">
|
||||
<el-input type="textarea" v-model="regionForm.description" placeholder="请输入区域描述"></el-input>
|
||||
<el-input type="textarea" v-model="regionForm.description" placeholder="请输入区域描述" rows="4"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -69,7 +69,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.region-add {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -77,4 +77,38 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,14 +6,14 @@
|
|||
<span>编辑区域</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="regionForm" :rules="rules" ref="regionForm" label-width="100px">
|
||||
<el-form :model="regionForm" :rules="rules" ref="regionForm" label-width="100px" class="form-content">
|
||||
<el-form-item label="区域名称" prop="name">
|
||||
<el-input v-model="regionForm.name" placeholder="请输入区域名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="区域描述" prop="description">
|
||||
<el-input type="textarea" v-model="regionForm.description" placeholder="请输入区域描述"></el-input>
|
||||
<el-input type="textarea" v-model="regionForm.description" placeholder="请输入区域描述" rows="4"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -84,7 +84,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.region-edit {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -92,4 +92,38 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,24 +4,53 @@
|
|||
<template slot="header">
|
||||
<div class="card-header">
|
||||
<span>区域列表</span>
|
||||
<el-button type="primary" @click="handleAdd">添加区域</el-button>
|
||||
<el-button type="primary" size="small" @click="handleAdd">添加区域</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="regions" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||
<el-table-column prop="name" label="区域名称"></el-table-column>
|
||||
<el-table-column prop="description" label="区域描述"></el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="primary" @click="handleEdit(scope.row.id)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination" style="margin-top: 20px;">
|
||||
|
||||
<!-- PC端表格 -->
|
||||
<div class="table-wrapper hidden-xs-only">
|
||||
<el-table :data="regions" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||
<el-table-column prop="name" label="区域名称" min-width="120"></el-table-column>
|
||||
<el-table-column prop="description" label="区域描述" min-width="200" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="primary" @click="handleEdit(scope.row.id)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="mobile-list hidden-sm-and-up">
|
||||
<div v-for="item in regions" :key="item.id" class="mobile-card">
|
||||
<div class="mobile-card-header">
|
||||
<span class="mobile-card-title">{{ item.name }}</span>
|
||||
<span class="mobile-card-id">ID: {{ item.id }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-body">
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">描述:</span>
|
||||
<span class="mobile-card-value">{{ item.description || '-' }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">创建时间:</span>
|
||||
<span class="mobile-card-value">{{ item.createTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-footer">
|
||||
<el-button size="mini" type="primary" @click="handleEdit(item.id)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(item.id)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="paginationLayout"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
|
|
@ -45,13 +74,27 @@ export default {
|
|||
total: 0,
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
isLoading: false
|
||||
isLoading: false,
|
||||
isMobile: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
paginationLayout() {
|
||||
return this.isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.checkDevice()
|
||||
window.addEventListener('resize', this.checkDevice)
|
||||
this.loadRegions()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.checkDevice)
|
||||
},
|
||||
methods: {
|
||||
checkDevice() {
|
||||
this.isMobile = window.innerWidth <= 768
|
||||
},
|
||||
async loadRegions() {
|
||||
this.isLoading = true
|
||||
try {
|
||||
|
|
@ -106,7 +149,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.region-list {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -115,8 +158,106 @@ export default {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 移动端卡片列表样式 */
|
||||
.mobile-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.mobile-card-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.mobile-card-id {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.mobile-card-body {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mobile-card-label {
|
||||
color: #909399;
|
||||
min-width: 70px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mobile-card-value {
|
||||
color: #606266;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.mobile-card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
/* 响应式显示控制 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.hidden-xs-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.hidden-sm-and-up {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
<span>添加租房</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="rentalForm" :rules="rules" ref="rentalForm" label-width="120px">
|
||||
<el-form :model="rentalForm" :rules="rules" ref="rentalForm" label-width="120px" class="form-content">
|
||||
<el-form-item label="房间" prop="roomId">
|
||||
<el-select v-model="rentalForm.roomId" placeholder="请选择房间" style="width: 100%">
|
||||
<el-option
|
||||
|
|
@ -64,7 +64,7 @@
|
|||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="rentalForm.remark" type="textarea" rows="3" placeholder="请输入备注信息"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -91,7 +91,6 @@ export default {
|
|||
status: 'active',
|
||||
remark: ''
|
||||
},
|
||||
// 保存返回时的查询参数
|
||||
returnQuery: {},
|
||||
rules: {
|
||||
roomId: [{ required: true, message: '请选择房间', trigger: 'blur' }],
|
||||
|
|
@ -121,18 +120,14 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
// 获取返回时的查询参数
|
||||
this.returnQuery = this.$route.query
|
||||
// 初始化开始日期为今天
|
||||
this.rentalForm.startDate = new Date()
|
||||
// 初始化结束日期
|
||||
this.updateEndDate()
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
async loadData() {
|
||||
try {
|
||||
// 并行加载房间和公寓数据(使用list接口)
|
||||
const [roomsResponse, apartmentsResponse] = await Promise.all([
|
||||
roomApi.list(),
|
||||
apartmentApi.list()
|
||||
|
|
@ -141,16 +136,11 @@ export default {
|
|||
this.rooms = roomsResponse
|
||||
this.apartments = apartmentsResponse
|
||||
|
||||
// 检查URL参数中是否有roomId
|
||||
const roomId = this.$route.query.roomId ? Number(this.$route.query.roomId) : null
|
||||
if (roomId) {
|
||||
// 确保roomId是字符串类型,与option的value类型一致
|
||||
this.rentalForm.roomId = roomId
|
||||
|
||||
// 查找对应的房间信息
|
||||
const room = this.rooms.find(r => r.id == roomId)
|
||||
if (room) {
|
||||
// 自动填充租金
|
||||
this.rentalForm.rent = room.monthlyPrice
|
||||
}
|
||||
}
|
||||
|
|
@ -171,14 +161,12 @@ export default {
|
|||
try {
|
||||
await rentalApi.create(this.rentalForm)
|
||||
this.$message.success('添加成功')
|
||||
// 跳转到租房详情页面
|
||||
if (this.rentalForm.roomId) {
|
||||
this.$router.push({
|
||||
path: `/rental/detail/${this.rentalForm.roomId}`,
|
||||
query: this.returnQuery
|
||||
})
|
||||
} else {
|
||||
// 如果没有房间ID,跳转到列表页面
|
||||
this.$router.push({
|
||||
path: '/rental/list',
|
||||
query: this.returnQuery
|
||||
|
|
@ -216,7 +204,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.rental-add {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -224,4 +212,42 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.el-divider__text {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
<div class="card-header">
|
||||
<span>房屋详情</span>
|
||||
<div class="action-buttons">
|
||||
<el-button v-if="room.status === 'empty'" type="primary" @click="handleRent">租房</el-button>
|
||||
<el-button v-if="room.status === 'rented'" type="warning" @click="handleCheckout">退房</el-button>
|
||||
<el-button v-if="!room.otherStatus || room.otherStatus === ''" type="info" @click="handleCleaning">打扫</el-button>
|
||||
<el-button v-if="!room.otherStatus || room.otherStatus === ''" type="danger" @click="handleMaintenance">维修</el-button>
|
||||
<el-button v-if="room.otherStatus === 'cleaning'" type="success" @click="handleComplete">打扫完成</el-button>
|
||||
<el-button v-if="room.otherStatus === 'maintenance'" type="success" @click="handleComplete">维修完成</el-button>
|
||||
<el-button type="primary" @click="goBack">返回</el-button>
|
||||
<el-button v-if="room.status === 'empty'" type="primary" size="small" @click="handleRent">租房</el-button>
|
||||
<el-button v-if="room.status === 'rented'" type="warning" size="small" @click="handleCheckout">退房</el-button>
|
||||
<el-button v-if="!room.otherStatus || room.otherStatus === ''" type="info" size="small" @click="handleCleaning">打扫</el-button>
|
||||
<el-button v-if="!room.otherStatus || room.otherStatus === ''" type="danger" size="small" @click="handleMaintenance">维修</el-button>
|
||||
<el-button v-if="room.otherStatus === 'cleaning'" type="success" size="small" @click="handleComplete">打扫完成</el-button>
|
||||
<el-button v-if="room.otherStatus === 'maintenance'" type="success" size="small" @click="handleComplete">维修完成</el-button>
|
||||
<el-button type="primary" size="small" @click="goBack">返回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -26,15 +26,15 @@
|
|||
<span class="label">租金:</span>
|
||||
<span class="value">
|
||||
¥{{ room.monthlyPrice }}/月
|
||||
<span v-if="room.yearlyPrice" style="margin-left: 10px;">¥{{ room.yearlyPrice }}/年</span>
|
||||
<span v-if="room.yearlyPrice" class="yearly-price">¥{{ room.yearlyPrice }}/年</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-item status-item">
|
||||
<span class="label">状态:</span>
|
||||
<span class="value" style="display: flex; gap: 8px;">
|
||||
<el-tag :type="getStatusType(room.status)">{{ getStatusText(room.status) }}</el-tag>
|
||||
<el-tag v-if="room.status === 'rented' && room.subStatus" :type="getSubStatusType(room.subStatus)">{{ getSubStatusText(room.subStatus) }}</el-tag>
|
||||
<el-tag v-if="room.otherStatus && room.otherStatus !== ''" :type="getOtherStatusType(room.otherStatus)">{{ getOtherStatusText(room.otherStatus) }}</el-tag>
|
||||
<span class="value">
|
||||
<el-tag :type="getStatusType(room.status)" size="small">{{ getStatusText(room.status) }}</el-tag>
|
||||
<el-tag v-if="room.status === 'rented' && room.subStatus" :type="getSubStatusType(room.subStatus)" size="small">{{ getSubStatusText(room.subStatus) }}</el-tag>
|
||||
<el-tag v-if="room.otherStatus && room.otherStatus !== ''" :type="getOtherStatusType(room.otherStatus)" size="small">{{ getOtherStatusText(room.otherStatus) }}</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
|
|
@ -46,37 +46,39 @@
|
|||
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="租赁档案" name="rental">
|
||||
<el-table :data="rentalHistory" style="width: 100%">
|
||||
<el-table-column prop="tenantName" label="租客" width="120"></el-table-column>
|
||||
<el-table-column prop="startDate" label="开始日期" width="150"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" width="150"></el-table-column>
|
||||
<el-table-column prop="rent" label="租金(元/月)" width="120"></el-table-column>
|
||||
<el-table-column prop="deposit" label="押金(元)" width="120"></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="150"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'">
|
||||
{{ scope.row.status === 'active' ? '在租' : '已到期' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="220">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="small" @click="handleEditRental(scope.row)">编辑</el-button>
|
||||
<el-button type="success" size="small" @click="handleRenewRental(scope.row)">续租</el-button>
|
||||
<el-button type="danger" size="small" @click="handleDeleteRental(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="margin-top: 20px; display: flex; justify-content: flex-end;">
|
||||
<div class="table-wrapper">
|
||||
<el-table :data="rentalHistory" style="width: 100%" class="detail-table">
|
||||
<el-table-column prop="tenantName" label="租客" min-width="100"></el-table-column>
|
||||
<el-table-column prop="startDate" label="开始日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="rent" label="租金(元/月)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="deposit" label="押金(元)" min-width="90"></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="120"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.status === 'active' ? '在租' : '已到期' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="140"></el-table-column>
|
||||
<el-table-column label="操作" min-width="180" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleEditRental(scope.row)">编辑</el-button>
|
||||
<el-button type="success" size="mini" @click="handleRenewRental(scope.row)">续租</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDeleteRental(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
|
@ -85,46 +87,51 @@
|
|||
<div class="section-header">
|
||||
<el-button type="primary" size="small" @click="handleAddWaterBill">添加水费</el-button>
|
||||
</div>
|
||||
<el-table :data="waterBills" style="width: 100%">
|
||||
<el-table-column prop="startDate" label="开始日期" width="150"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" width="150"></el-table-column>
|
||||
<el-table-column prop="startReading" label="起始度数" width="120"></el-table-column>
|
||||
<el-table-column prop="endReading" label="结束度数" width="120"></el-table-column>
|
||||
<el-table-column prop="usage" label="用水量(吨)" width="120"></el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价(元/吨)" width="120"></el-table-column>
|
||||
<el-table-column prop="amount" label="费用(元)" width="100"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'paid' ? 'success' : 'warning'">
|
||||
{{ scope.row.status === 'paid' ? '已支付' : '未支付' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="small" @click="handleEditWaterBill(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="small" @click="handleDeleteWaterBill(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="margin-top: 20px; display: flex; justify-content: flex-end;">
|
||||
<div class="table-wrapper">
|
||||
<el-table :data="waterBills" style="width: 100%" class="detail-table">
|
||||
<el-table-column prop="startDate" label="开始日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="startReading" label="起始度数" min-width="90"></el-table-column>
|
||||
<el-table-column prop="endReading" label="结束度数" min-width="90"></el-table-column>
|
||||
<el-table-column prop="usage" label="用水量(吨)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价(元/吨)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="amount" label="费用(元)" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<span class="amount-value">¥{{ scope.row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'paid' ? 'success' : 'warning'" size="small">
|
||||
{{ scope.row.status === 'paid' ? '已支付' : '未支付' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="140" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleEditWaterBill(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDeleteWaterBill(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
@size-change="handleWaterSizeChange"
|
||||
@current-change="handleWaterCurrentChange"
|
||||
:current-page="waterCurrentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="waterPageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
|
||||
:total="waterTotal">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
|
||||
<!-- 水费编辑对话框 -->
|
||||
<el-dialog title="编辑水费" :visible.sync="waterBillDialogVisible" width="500px">
|
||||
<el-form :model="waterBillForm" :rules="waterBillRules" ref="waterBillForm">
|
||||
<el-form :model="waterBillForm" :rules="waterBillRules" ref="waterBillForm" label-width="90px">
|
||||
<el-form-item label="开始日期" prop="startDate">
|
||||
<el-date-picker v-model="waterBillForm.startDate" type="date" placeholder="选择开始日期" style="width: 100%"></el-date-picker>
|
||||
</el-form-item>
|
||||
|
|
@ -141,7 +148,7 @@
|
|||
<el-input v-model.number="waterBillForm.unitPrice" placeholder="请输入单价"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="waterBillForm.status" placeholder="请选择状态">
|
||||
<el-select v-model="waterBillForm.status" placeholder="请选择状态" style="width: 100%">
|
||||
<el-option label="未支付" value="unpaid"></el-option>
|
||||
<el-option label="已支付" value="paid"></el-option>
|
||||
</el-select>
|
||||
|
|
@ -153,11 +160,9 @@
|
|||
</span>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
|
||||
<!-- 租赁编辑对话框 -->
|
||||
<el-dialog :title="rentalForm.id ? '编辑租赁记录' : '新增租赁记录'" :visible.sync="rentalDialogVisible" width="500px">
|
||||
<el-form :model="rentalForm" :rules="rentalRules" ref="rentalForm">
|
||||
<el-form :model="rentalForm" :rules="rentalRules" ref="rentalForm" label-width="80px">
|
||||
<el-form-item label="租客姓名" prop="tenantName">
|
||||
<el-input v-model="rentalForm.tenantName" placeholder="请输入租客姓名"></el-input>
|
||||
</el-form-item>
|
||||
|
|
@ -205,13 +210,10 @@ export default {
|
|||
waterBills: [],
|
||||
isLoading: false,
|
||||
activeTab: 'rental',
|
||||
// 保存返回时的查询参数
|
||||
returnQuery: {},
|
||||
// 分页相关 - 租赁档案
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
// 分页相关 - 水费记录
|
||||
waterCurrentPage: 1,
|
||||
waterPageSize: 10,
|
||||
waterTotal: 0,
|
||||
|
|
@ -255,14 +257,21 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isMobile() {
|
||||
return window.innerWidth <= 768
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 获取返回时的查询参数
|
||||
this.returnQuery = this.$route.query
|
||||
this.loadData()
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
},
|
||||
watch: {
|
||||
activeTab: function() {
|
||||
// 当tab切换时,刷新对应的数据
|
||||
if (this.activeTab === 'rental') {
|
||||
this.loadRentalHistory()
|
||||
} else if (this.activeTab === 'water') {
|
||||
|
|
@ -271,19 +280,16 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
handleResize() {
|
||||
this.$forceUpdate()
|
||||
},
|
||||
async loadData() {
|
||||
this.isLoading = true
|
||||
try {
|
||||
const roomId = this.$route.params.id
|
||||
|
||||
// 加载房间数据
|
||||
const roomResponse = await roomApi.getById(roomId)
|
||||
this.room = roomResponse
|
||||
|
||||
// 加载租赁历史
|
||||
await this.loadRentalHistory()
|
||||
|
||||
// 如果当前激活的是水费tab,加载水费数据
|
||||
if (this.activeTab === 'water') {
|
||||
await this.loadWaterBills()
|
||||
}
|
||||
|
|
@ -297,17 +303,12 @@ export default {
|
|||
this.isLoading = true
|
||||
try {
|
||||
const roomId = this.$route.params.id
|
||||
// 调用API获取水费记录,支持分页
|
||||
const response = await waterBillApi.getAll({
|
||||
roomId,
|
||||
page: this.waterCurrentPage,
|
||||
pageSize: this.waterPageSize
|
||||
})
|
||||
|
||||
// 处理返回数据
|
||||
this.waterBills = response.data || response
|
||||
|
||||
// 设置总数
|
||||
this.waterTotal = response.total || 0
|
||||
} catch (error) {
|
||||
this.$message.error('加载水费记录失败')
|
||||
|
|
@ -319,22 +320,13 @@ export default {
|
|||
this.isLoading = true
|
||||
try {
|
||||
const roomId = this.$route.params.id
|
||||
// 调用API获取当前房间的租赁记录,支持分页
|
||||
const response = await rentalApi.getAll({
|
||||
roomId,
|
||||
page: this.currentPage,
|
||||
pageSize: this.pageSize
|
||||
})
|
||||
|
||||
// 处理返回数据
|
||||
const data = response.data || response
|
||||
this.rentalHistory = data.map(rental => {
|
||||
return {
|
||||
...rental
|
||||
}
|
||||
})
|
||||
|
||||
// 设置总数
|
||||
this.rentalHistory = data.map(rental => ({ ...rental }))
|
||||
this.total = response.total || 0
|
||||
} catch (error) {
|
||||
this.$message.error('加载租赁历史失败')
|
||||
|
|
@ -433,17 +425,12 @@ export default {
|
|||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
// 找到当前房间的租房记录
|
||||
const roomId = this.$route.params.id
|
||||
const rental = this.rentalHistory.find(r => r.roomId == roomId && r.status === 'active')
|
||||
|
||||
if (rental) {
|
||||
// 更新租房记录状态
|
||||
await rentalApi.update(rental.id, { status: 'expired' })
|
||||
|
||||
// 更新房间状态
|
||||
await roomApi.update(roomId, { status: 'empty' })
|
||||
|
||||
this.$message.success('退房成功')
|
||||
this.loadData()
|
||||
} else {
|
||||
|
|
@ -453,9 +440,7 @@ export default {
|
|||
console.error('退房失败:', error)
|
||||
this.$message.error('退房失败:' + (error.message || '未知错误'))
|
||||
}
|
||||
}).catch(() => {
|
||||
// 取消退房
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
async handleCleaning() {
|
||||
this.$confirm('确定要标记为打扫中吗?', '提示', {
|
||||
|
|
@ -471,9 +456,7 @@ export default {
|
|||
} catch (error) {
|
||||
this.$message.error('操作失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
// 取消操作
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
async handleMaintenance() {
|
||||
this.$confirm('确定要标记为维修中吗?', '提示', {
|
||||
|
|
@ -489,9 +472,7 @@ export default {
|
|||
} catch (error) {
|
||||
this.$message.error('操作失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
// 取消操作
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
async handleComplete() {
|
||||
this.$confirm('确定要完成打扫/维修吗?', '提示', {
|
||||
|
|
@ -507,9 +488,7 @@ export default {
|
|||
} catch (error) {
|
||||
this.$message.error('操作失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
// 取消操作
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
handleAddWaterBill() {
|
||||
this.waterBillForm = {
|
||||
|
|
@ -536,15 +515,10 @@ export default {
|
|||
try {
|
||||
const roomId = this.$route.params.id
|
||||
if (this.waterBillForm.id) {
|
||||
// 更新水费记录
|
||||
await waterBillApi.update(this.waterBillForm.id, this.waterBillForm)
|
||||
this.$message.success('水费记录更新成功')
|
||||
} else {
|
||||
// 创建水费记录
|
||||
await waterBillApi.create({
|
||||
...this.waterBillForm,
|
||||
roomId
|
||||
})
|
||||
await waterBillApi.create({ ...this.waterBillForm, roomId })
|
||||
this.$message.success('水费记录添加成功')
|
||||
}
|
||||
this.waterBillDialogVisible = false
|
||||
|
|
@ -566,11 +540,8 @@ export default {
|
|||
} catch (error) {
|
||||
this.$message.error('删除失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
// 取消删除
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
handleEditRental(rental) {
|
||||
this.rentalForm = {
|
||||
...rental,
|
||||
|
|
@ -580,19 +551,13 @@ export default {
|
|||
this.rentalDialogVisible = true
|
||||
},
|
||||
handleRenewRental(rental) {
|
||||
// 计算新的开始日期和结束日期
|
||||
const oldEndDate = new Date(rental.endDate)
|
||||
const newStartDate = new Date(oldEndDate)
|
||||
|
||||
// 计算租赁时长(月)
|
||||
const oldStartDate = new Date(rental.startDate)
|
||||
const monthsDiff = (oldEndDate.getFullYear() - oldStartDate.getFullYear()) * 12 + (oldEndDate.getMonth() - oldStartDate.getMonth())
|
||||
|
||||
// 计算新的结束日期
|
||||
const newEndDate = new Date(newStartDate)
|
||||
newEndDate.setMonth(newEndDate.getMonth() + monthsDiff)
|
||||
|
||||
// 预填表单,保持租客信息不变,清空ID
|
||||
this.rentalForm = {
|
||||
id: '',
|
||||
roomId: rental.roomId,
|
||||
|
|
@ -611,11 +576,9 @@ export default {
|
|||
async handleSaveRental() {
|
||||
try {
|
||||
if (this.rentalForm.id) {
|
||||
// 更新租赁记录
|
||||
await rentalApi.update(this.rentalForm.id, this.rentalForm)
|
||||
this.$message.success('租赁记录更新成功')
|
||||
} else {
|
||||
// 创建租赁记录
|
||||
await rentalApi.create(this.rentalForm)
|
||||
this.$message.success('租赁记录添加成功')
|
||||
}
|
||||
|
|
@ -632,36 +595,22 @@ export default {
|
|||
type: 'danger'
|
||||
}).then(async () => {
|
||||
try {
|
||||
// 先获取租赁记录的详细信息
|
||||
const rental = this.rentalHistory.find(r => r.id == id)
|
||||
|
||||
// 删除租赁记录
|
||||
await rentalApi.delete(id)
|
||||
this.$message.success('租赁记录删除成功')
|
||||
|
||||
// 如果是在租状态,更新房间状态为空房
|
||||
if (rental && rental.status === 'active' && rental.roomId) {
|
||||
await roomApi.update(rental.roomId, {
|
||||
status: 'empty',
|
||||
subStatus: 'normal'
|
||||
})
|
||||
await roomApi.update(rental.roomId, { status: 'empty', subStatus: 'normal' })
|
||||
this.$message.success('房间状态已更新为空房')
|
||||
}
|
||||
|
||||
this.loadData()
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
this.$message.error('删除失败:' + (error.message || '未知错误'))
|
||||
}
|
||||
}).catch(() => {
|
||||
// 取消删除
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
goBack() {
|
||||
this.$router.push({
|
||||
path: '/rental/list',
|
||||
query: this.returnQuery
|
||||
})
|
||||
this.$router.push({ path: '/rental/list', query: this.returnQuery })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -669,13 +618,15 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.rental-detail {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.room-info-section {
|
||||
|
|
@ -704,34 +655,36 @@ export default {
|
|||
.info-item .label {
|
||||
width: 80px;
|
||||
color: #606266;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-item .value {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.rental-history-section {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
.yearly-price {
|
||||
margin-left: 10px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.rental-history-section h3 {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
.status-item .value {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.water-bill-section {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.electricity-bill-section {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
.detail-table {
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
|
|
@ -741,14 +694,67 @@ export default {
|
|||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.section-header h3 {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
color: #f56c6c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.card-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.room-info-section h2 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.room-basic-info {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.info-item .label {
|
||||
width: auto;
|
||||
margin-bottom: 3px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.info-item .value {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,22 +6,24 @@
|
|||
<span>租房管理</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<el-form-item label="公寓">
|
||||
<el-select v-model="searchForm.apartmentId" placeholder="请选择公寓">
|
||||
<el-select v-model="searchForm.apartmentId" placeholder="请选择公寓" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="apartment in apartments" :key="apartment.id" :label="apartment.name" :value="apartment.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="主状态">
|
||||
<el-select v-model="searchForm.status" placeholder="请选择主状态">
|
||||
<el-select v-model="searchForm.status" placeholder="请选择主状态" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="空房" value="empty"></el-option>
|
||||
<el-option label="在租" value="rented"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="附属状态">
|
||||
<el-select v-model="searchForm.subStatus" placeholder="请选择附属状态">
|
||||
<el-select v-model="searchForm.subStatus" placeholder="请选择附属状态" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="正常" value="normal"></el-option>
|
||||
<el-option label="即将到期" value="soon_expire"></el-option>
|
||||
|
|
@ -29,7 +31,7 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他状态">
|
||||
<el-select v-model="searchForm.otherStatus" placeholder="请选择其他状态">
|
||||
<el-select v-model="searchForm.otherStatus" placeholder="请选择其他状态" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="打扫中" value="cleaning"></el-option>
|
||||
<el-option label="维修中" value="maintenance"></el-option>
|
||||
|
|
@ -43,47 +45,50 @@
|
|||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="room-cards">
|
||||
|
||||
<!-- 房间卡片列表 -->
|
||||
<div class="room-cards" v-loading="isLoading">
|
||||
<div
|
||||
v-for="room in rooms"
|
||||
:key="room.id"
|
||||
@click="handleRoomClick(room.id)"
|
||||
style="cursor: pointer;"
|
||||
class="room-card-wrapper"
|
||||
>
|
||||
<el-card
|
||||
:class="['room-card', `status-${room.status === 'rented' ? room.subStatus : room.status}`]"
|
||||
>
|
||||
<div class="room-card-header">
|
||||
<h3>{{ getApartmentName(room.apartmentId) }}</h3>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<el-tag v-if="room.status === 'rented'" :type="getSubStatusType(room.subStatus)">{{ getSubStatusText(room.subStatus) }}</el-tag>
|
||||
<el-tag v-else>空房</el-tag>
|
||||
<el-tag v-if="room.otherStatus" :type="getOtherStatusType(room.otherStatus)">{{ getOtherStatusText(room.otherStatus) }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="room-card-body">
|
||||
<div class="room-info">
|
||||
<span class="room-number">{{ room.roomNumber }}</span>
|
||||
<span class="room-area">{{ room.area }}㎡</span>
|
||||
<div class="price-info">
|
||||
<span class="room-price">¥{{ room.monthlyPrice }}/月</span>
|
||||
<span v-if="room.yearlyPrice" class="room-price yearly">¥{{ room.yearlyPrice }}/年</span>
|
||||
<div class="room-card-header">
|
||||
<h3>{{ getApartmentName(room.apartmentId) }}</h3>
|
||||
<div class="room-card-tags">
|
||||
<el-tag v-if="room.status === 'rented'" :type="getSubStatusType(room.subStatus)" size="small">{{ getSubStatusText(room.subStatus) }}</el-tag>
|
||||
<el-tag v-else size="small">空房</el-tag>
|
||||
<el-tag v-if="room.otherStatus" :type="getOtherStatusType(room.otherStatus)" size="small">{{ getOtherStatusText(room.otherStatus) }}</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rental-info" v-if="room.Rentals && room.Rentals.length > 0">
|
||||
<p>租客: {{ room.Rentals[0].tenantName }}</p>
|
||||
<p>租期: {{ room.Rentals[0].startDate }} 至 {{ room.Rentals[0].endDate }}</p>
|
||||
<div class="room-card-body">
|
||||
<div class="room-info">
|
||||
<span class="room-number">{{ room.roomNumber }}</span>
|
||||
<span class="room-area">{{ room.area }}㎡</span>
|
||||
<div class="price-info">
|
||||
<span class="room-price">¥{{ room.monthlyPrice }}/月</span>
|
||||
<span v-if="room.yearlyPrice" class="room-price yearly">¥{{ room.yearlyPrice }}/年</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rental-info" v-if="room.Rentals && room.Rentals.length > 0">
|
||||
<p><i class="el-icon-user"></i> {{ room.Rentals[0].tenantName }}</p>
|
||||
<p><i class="el-icon-date"></i> {{ room.Rentals[0].startDate }} 至 {{ room.Rentals[0].endDate }}</p>
|
||||
</div>
|
||||
<div class="rental-info" v-else>
|
||||
<p class="no-rental">暂无租客信息</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rental-info" v-else>
|
||||
<p>暂无租客信息</p>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination" style="margin-top: 20px;">
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="paginationLayout"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:current-page="currentPage"
|
||||
|
|
@ -115,26 +120,36 @@ export default {
|
|||
},
|
||||
currentPage: 1,
|
||||
pageSize: 50,
|
||||
isLoading: false
|
||||
isLoading: false,
|
||||
isMobile: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
paginationLayout() {
|
||||
return this.isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 从路由参数中获取查询参数和页码
|
||||
this.checkDevice()
|
||||
window.addEventListener('resize', this.checkDevice)
|
||||
this.initFromQuery()
|
||||
this.loadData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.checkDevice)
|
||||
},
|
||||
methods: {
|
||||
// 从路由参数初始化搜索参数和页码
|
||||
checkDevice() {
|
||||
this.isMobile = window.innerWidth <= 768
|
||||
},
|
||||
initFromQuery() {
|
||||
const query = this.$route.query
|
||||
if (query) {
|
||||
// 初始化搜索参数
|
||||
if (query.apartmentId) this.searchForm.apartmentId = parseInt(query.apartmentId)
|
||||
if (query.status) this.searchForm.status = query.status
|
||||
if (query.subStatus) this.searchForm.subStatus = query.subStatus
|
||||
if (query.otherStatus) this.searchForm.otherStatus = query.otherStatus
|
||||
if (query.roomNumber) this.searchForm.roomNumber = query.roomNumber
|
||||
// 初始化页码
|
||||
if (query.page) this.currentPage = parseInt(query.page)
|
||||
if (query.pageSize) this.pageSize = parseInt(query.pageSize)
|
||||
}
|
||||
|
|
@ -144,11 +159,9 @@ export default {
|
|||
|
||||
this.isLoading = true
|
||||
try {
|
||||
// 加载公寓数据
|
||||
const apartmentsResponse = await apartmentApi.getAll()
|
||||
this.apartments = apartmentsResponse.data || apartmentsResponse
|
||||
|
||||
// 构建查询参数
|
||||
const params = {
|
||||
apartmentId: this.searchForm.apartmentId,
|
||||
status: this.searchForm.status,
|
||||
|
|
@ -159,13 +172,11 @@ export default {
|
|||
pageSize: this.pageSize
|
||||
}
|
||||
|
||||
// 加载房间数据(包含租房信息)
|
||||
const roomsResponse = await roomApi.getAll(params)
|
||||
if (roomsResponse.data) {
|
||||
this.rooms = roomsResponse.data
|
||||
this.total = roomsResponse.total
|
||||
} else {
|
||||
// 兼容旧的返回格式
|
||||
this.rooms = roomsResponse
|
||||
this.total = roomsResponse.length
|
||||
}
|
||||
|
|
@ -197,7 +208,7 @@ export default {
|
|||
},
|
||||
getOtherStatusType(status) {
|
||||
switch (status) {
|
||||
case 'cleaning': return 'info'
|
||||
case 'cleaning': return 'warning'
|
||||
case 'maintenance': return 'danger'
|
||||
default: return ''
|
||||
}
|
||||
|
|
@ -209,13 +220,8 @@ export default {
|
|||
default: return status
|
||||
}
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
this.$router.push('/rental/add')
|
||||
},
|
||||
handleRoomClick(roomId) {
|
||||
try {
|
||||
// 保存当前的查询参数和页码到路由参数
|
||||
this.$router.push({
|
||||
path: `/rental/detail/${roomId}`,
|
||||
query: {
|
||||
|
|
@ -245,7 +251,6 @@ export default {
|
|||
},
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val
|
||||
// 更新路由参数,保存查询状态
|
||||
this.$router.push({
|
||||
path: this.$route.path,
|
||||
query: {
|
||||
|
|
@ -259,7 +264,6 @@ export default {
|
|||
handleSizeChange(val) {
|
||||
this.pageSize = val
|
||||
this.currentPage = 1
|
||||
// 更新路由参数,保存查询状态
|
||||
this.$router.push({
|
||||
path: this.$route.path,
|
||||
query: {
|
||||
|
|
@ -276,7 +280,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.rental-list {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -296,19 +300,14 @@ export default {
|
|||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.room-card {
|
||||
.room-card-wrapper {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid #e4e7ed;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 220px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.room-card * {
|
||||
pointer-events: none;
|
||||
.room-card {
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid #e4e7ed;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.room-card:hover {
|
||||
|
|
@ -319,20 +318,25 @@ export default {
|
|||
.room-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 15px;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.room-card-header {
|
||||
.room-card-header h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.room-card-tags {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
flex-shrink: 0;
|
||||
gap: 5px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.room-card-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
|
@ -344,16 +348,19 @@ export default {
|
|||
margin-bottom: 15px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.room-number {
|
||||
font-size: 24px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.room-area {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
|
|
@ -363,8 +370,9 @@ export default {
|
|||
}
|
||||
|
||||
.room-price {
|
||||
color: #409EFF;
|
||||
color: #f56c6c;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.room-price.yearly {
|
||||
|
|
@ -375,21 +383,32 @@ export default {
|
|||
|
||||
.rental-info {
|
||||
margin-top: 10px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.rental-info p {
|
||||
margin: 5px 0;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.rental-info p.no-rental {
|
||||
color: #909399;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 状态样式 */
|
||||
.status-empty {
|
||||
border-color: #ffffff;
|
||||
background-color: #f9f9f9;
|
||||
border-color: #dcdfe6;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.status-normal {
|
||||
|
|
@ -406,4 +425,79 @@ export default {
|
|||
border-color: #f56c6c;
|
||||
background-color: #fef0f0;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.search-form {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-input,
|
||||
.search-form .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.room-cards {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.room-card {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.room-card:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.room-card-header h3 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.room-number {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.room-info {
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 375px) {
|
||||
.room-cards {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.room-card {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.room-number {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.room-price {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -51,55 +51,117 @@
|
|||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="rentalList" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column prop="tenantName" label="租客" width="120"></el-table-column>
|
||||
<el-table-column label="房间" width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ getApartmentName(scope.row.roomId) }} - {{ getRoomNumber(scope.row.roomId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startDate" label="开始日期" width="120"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" width="120"></el-table-column>
|
||||
<el-table-column prop="rent" label="租金(元/月)" width="120"></el-table-column>
|
||||
<el-table-column prop="deposit" label="押金(元)" width="120"></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="150"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'">
|
||||
{{ scope.row.status === 'active' ? '在租' : '已到期' }}
|
||||
|
||||
<!-- PC端表格 -->
|
||||
<div class="table-wrapper hidden-xs-only">
|
||||
<el-table :data="rentalList" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column prop="tenantName" label="租客" min-width="100"></el-table-column>
|
||||
<el-table-column label="区域" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.Room.Apartment.Region.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="公寓" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.Room.Apartment.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="房间" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.Room.roomNumber}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startDate" label="开始日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="rent" label="租金(元/月)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="deposit" label="押金(元)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="120"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'" size="small">
|
||||
{{ scope.row.status === 'active' ? '在租' : '已到期' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="150"></el-table-column>
|
||||
<el-table-column label="操作" min-width="200" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="success" size="mini" @click="handleRenew(scope.row)">续租</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="mobile-list hidden-sm-and-up">
|
||||
<div v-for="item in rentalList" :key="item.id" class="mobile-card">
|
||||
<div class="mobile-card-header">
|
||||
<span class="mobile-card-title">{{ item.tenantName }}</span>
|
||||
<el-tag :type="item.status === 'active' ? 'success' : 'danger'" size="mini">
|
||||
{{ item.status === 'active' ? '在租' : '已到期' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="220">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="success" size="small" @click="handleRenew(scope.row)">续租</el-button>
|
||||
<el-button type="danger" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
</div>
|
||||
<div class="mobile-card-body">
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">区域:</span>
|
||||
<span class="mobile-card-value">{{ item.Room.Apartment.Region.name }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">公寓:</span>
|
||||
<span class="mobile-card-value">{{ item.Room.Apartment.name }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">房间:</span>
|
||||
<span class="mobile-card-value">{{ item.Room.roomNumber }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">租期:</span>
|
||||
<span class="mobile-card-value">{{ item.startDate }} 至 {{ item.endDate }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">租金:</span>
|
||||
<span class="mobile-card-value">¥{{ item.rent }}/月</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">押金:</span>
|
||||
<span class="mobile-card-value">¥{{ item.deposit }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item" v-if="item.remark">
|
||||
<span class="mobile-card-label">备注:</span>
|
||||
<span class="mobile-card-value">{{ item.remark }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-footer">
|
||||
<el-button type="primary" size="mini" @click="handleEdit(item)">编辑</el-button>
|
||||
<el-button type="success" size="mini" @click="handleRenew(item)">续租</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(item.id)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="rentalForm.id ? '编辑租赁记录' : '新增租赁记录'" :visible.sync="rentalDialogVisible" width="500px">
|
||||
<el-form :model="rentalForm" :rules="rentalRules" ref="rentalForm">
|
||||
<el-form :model="rentalForm" :rules="rentalRules" ref="rentalForm" label-width="80px">
|
||||
<el-form-item label="租客姓名" prop="tenantName">
|
||||
<el-input v-model="rentalForm.tenantName" placeholder="请输入租客姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="房间" prop="roomId">
|
||||
<el-select v-model="rentalForm.roomId" placeholder="请选择房间" style="width: 100%">
|
||||
<el-option v-for="room in allRooms" :key="room.id" :label="`${getApartmentName(room.id)} - ${room.roomNumber}`" :value="room.id"></el-option>
|
||||
<el-option v-for="room in allRooms" :key="room.id" :label="`${room.Apartment.name} - ${room.roomNumber}`" :value="room.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始日期" prop="startDate">
|
||||
|
|
@ -176,15 +238,27 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isMobile() {
|
||||
return window.innerWidth <= 768
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadApartments()
|
||||
this.loadAllRooms()
|
||||
this.loadData()
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
},
|
||||
methods: {
|
||||
handleResize() {
|
||||
this.$forceUpdate()
|
||||
},
|
||||
async loadApartments() {
|
||||
try {
|
||||
const response = await apartmentApi.getAll()
|
||||
const response = await apartmentApi.list()
|
||||
this.apartments = response.data || response
|
||||
} catch (error) {
|
||||
this.$message.error('加载公寓数据失败')
|
||||
|
|
@ -192,7 +266,7 @@ export default {
|
|||
},
|
||||
async loadAllRooms() {
|
||||
try {
|
||||
const response = await roomApi.getAll()
|
||||
const response = await roomApi.list()
|
||||
this.allRooms = response.data || response
|
||||
} catch (error) {
|
||||
this.$message.error('加载房间数据失败')
|
||||
|
|
@ -204,7 +278,7 @@ export default {
|
|||
return
|
||||
}
|
||||
try {
|
||||
const response = await roomApi.getAll({ apartmentId: this.searchForm.apartmentId })
|
||||
const response = await roomApi.list({ apartmentId: this.searchForm.apartmentId })
|
||||
this.rooms = response.data || response
|
||||
} catch (error) {
|
||||
this.$message.error('加载房间数据失败')
|
||||
|
|
@ -353,7 +427,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.rental-archive {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -366,9 +440,31 @@ export default {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-select,
|
||||
.search-form .el-date-picker {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -42,49 +42,96 @@
|
|||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="waterBillList" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column label="房间" width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ getApartmentName(scope.row.roomId) }} - {{ getRoomNumber(scope.row.roomId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startDate" label="开始日期" width="120"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" width="120"></el-table-column>
|
||||
<el-table-column prop="startReading" label="起始度数" width="120"></el-table-column>
|
||||
<el-table-column prop="endReading" label="结束度数" width="120"></el-table-column>
|
||||
<el-table-column prop="usage" label="用水量(吨)" width="120"></el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价(元/吨)" width="120"></el-table-column>
|
||||
<el-table-column prop="amount" label="费用(元)" width="100"></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'paid' ? 'success' : 'warning'">
|
||||
{{ scope.row.status === 'paid' ? '已支付' : '未支付' }}
|
||||
|
||||
<!-- PC端表格 -->
|
||||
<div class="table-wrapper hidden-xs-only">
|
||||
<el-table :data="waterBillList" style="width: 100%" v-loading="isLoading">
|
||||
<el-table-column label="房间" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ getApartmentName(scope.row.roomId) }} - {{ getRoomNumber(scope.row.roomId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startDate" label="开始日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="endDate" label="结束日期" min-width="100"></el-table-column>
|
||||
<el-table-column prop="startReading" label="起始度数" min-width="90"></el-table-column>
|
||||
<el-table-column prop="endReading" label="结束度数" min-width="90"></el-table-column>
|
||||
<el-table-column prop="usage" label="用水量(吨)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="unitPrice" label="单价(元/吨)" min-width="100"></el-table-column>
|
||||
<el-table-column prop="amount" label="费用(元)" min-width="90">
|
||||
<template slot-scope="scope">
|
||||
<span class="amount-value">¥{{ scope.row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 'paid' ? 'success' : 'warning'" size="small">
|
||||
{{ scope.row.status === 'paid' ? '已支付' : '未支付' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="150"></el-table-column>
|
||||
<el-table-column label="操作" min-width="150" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="mobile-list hidden-sm-and-up">
|
||||
<div v-for="item in waterBillList" :key="item.id" class="mobile-card">
|
||||
<div class="mobile-card-header">
|
||||
<span class="mobile-card-title">{{ getApartmentName(item.roomId) }} - {{ getRoomNumber(item.roomId) }}</span>
|
||||
<el-tag :type="item.status === 'paid' ? 'success' : 'warning'" size="mini">
|
||||
{{ item.status === 'paid' ? '已支付' : '未支付' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="small" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
</div>
|
||||
<div class="mobile-card-body">
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">计费周期:</span>
|
||||
<span class="mobile-card-value">{{ item.startDate }} 至 {{ item.endDate }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">用水量:</span>
|
||||
<span class="mobile-card-value">{{ item.usage }} 吨</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">费用:</span>
|
||||
<span class="mobile-card-value amount-value">¥{{ item.amount }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">读数:</span>
|
||||
<span class="mobile-card-value">{{ item.startReading }} → {{ item.endReading }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">单价:</span>
|
||||
<span class="mobile-card-value">¥{{ item.unitPrice }}/吨</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-footer">
|
||||
<el-button type="primary" size="mini" @click="handleEdit(item)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(item.id)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="waterBillForm.id ? '编辑水费' : '添加水费'" :visible.sync="waterBillDialogVisible" width="500px">
|
||||
<el-form :model="waterBillForm" :rules="waterBillRules" ref="waterBillForm">
|
||||
<el-form :model="waterBillForm" :rules="waterBillRules" ref="waterBillForm" label-width="90px">
|
||||
<el-form-item label="房间" prop="roomId">
|
||||
<el-select v-model="waterBillForm.roomId" placeholder="请选择房间" style="width: 100%">
|
||||
<el-option v-for="room in allRooms" :key="room.id" :label="`${getApartmentName(room.id)} - ${room.roomNumber}`" :value="room.id"></el-option>
|
||||
|
|
@ -163,15 +210,27 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isMobile() {
|
||||
return window.innerWidth <= 768
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadApartments()
|
||||
this.loadAllRooms()
|
||||
this.loadData()
|
||||
window.addEventListener('resize', this.handleResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize)
|
||||
},
|
||||
methods: {
|
||||
handleResize() {
|
||||
this.$forceUpdate()
|
||||
},
|
||||
async loadApartments() {
|
||||
try {
|
||||
const response = await apartmentApi.getAll()
|
||||
const response = await apartmentApi.list()
|
||||
this.apartments = response.data || response
|
||||
} catch (error) {
|
||||
this.$message.error('加载公寓数据失败')
|
||||
|
|
@ -179,7 +238,7 @@ export default {
|
|||
},
|
||||
async loadAllRooms() {
|
||||
try {
|
||||
const response = await roomApi.getAll()
|
||||
const response = await roomApi.list()
|
||||
this.allRooms = response.data || response
|
||||
} catch (error) {
|
||||
this.$message.error('加载房间数据失败')
|
||||
|
|
@ -191,7 +250,7 @@ export default {
|
|||
return
|
||||
}
|
||||
try {
|
||||
const response = await roomApi.getAll({ apartmentId: this.searchForm.apartmentId })
|
||||
const response = await roomApi.list({ apartmentId: this.searchForm.apartmentId })
|
||||
this.rooms = response.data || response
|
||||
} catch (error) {
|
||||
this.$message.error('加载房间数据失败')
|
||||
|
|
@ -325,7 +384,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.water-archive {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -338,9 +397,36 @@ export default {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
color: #f56c6c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-select,
|
||||
.search-form .el-date-picker {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
<span>添加房间</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="roomForm" :rules="rules" ref="roomForm" label-width="100px">
|
||||
<el-form :model="roomForm" :rules="rules" ref="roomForm" label-width="100px" class="form-content">
|
||||
<el-form-item label="公寓" prop="apartmentId">
|
||||
<el-select v-model="roomForm.apartmentId" placeholder="请选择公寓">
|
||||
<el-select v-model="roomForm.apartmentId" placeholder="请选择公寓" style="width: 100%">
|
||||
<el-option v-for="apartment in apartments" :key="apartment.id" :label="apartment.name" :value="apartment.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
|
@ -25,14 +25,14 @@
|
|||
<el-input type="number" v-model="roomForm.yearlyPrice" placeholder="请输入年租金"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="主状态" prop="status">
|
||||
<el-select v-model="roomForm.status" placeholder="请选择主状态">
|
||||
<el-select v-model="roomForm.status" placeholder="请选择主状态" style="width: 100%">
|
||||
<el-option label="空房" value="empty"></el-option>
|
||||
<el-option label="在租" value="rented"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="附属状态" prop="subStatus" v-if="roomForm.status === 'rented'">
|
||||
<el-select v-model="roomForm.subStatus" placeholder="请选择附属状态">
|
||||
<el-select v-model="roomForm.subStatus" placeholder="请选择附属状态" style="width: 100%">
|
||||
<el-option label="正常" value="normal"></el-option>
|
||||
<el-option label="即将到期" value="soon_expire"></el-option>
|
||||
<el-option label="已到期" value="expired"></el-option>
|
||||
|
|
@ -40,13 +40,13 @@
|
|||
</el-form-item>
|
||||
|
||||
<el-form-item label="其他状态" prop="otherStatus">
|
||||
<el-select v-model="roomForm.otherStatus" placeholder="请选择其他状态">
|
||||
<el-select v-model="roomForm.otherStatus" placeholder="请选择其他状态" style="width: 100%">
|
||||
<el-option label="无" value=""></el-option>
|
||||
<el-option label="打扫中" value="cleaning"></el-option>
|
||||
<el-option label="维修中" value="maintenance"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -160,7 +160,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.room-add {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -168,4 +168,38 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -6,9 +6,9 @@
|
|||
<span>编辑房间</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :model="roomForm" :rules="rules" ref="roomForm" label-width="100px">
|
||||
<el-form :model="roomForm" :rules="rules" ref="roomForm" label-width="100px" class="form-content">
|
||||
<el-form-item label="公寓" prop="apartmentId">
|
||||
<el-select v-model="roomForm.apartmentId" placeholder="请选择公寓">
|
||||
<el-select v-model="roomForm.apartmentId" placeholder="请选择公寓" style="width: 100%">
|
||||
<el-option v-for="apartment in apartments" :key="apartment.id" :label="apartment.name" :value="apartment.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
|
@ -25,14 +25,14 @@
|
|||
<el-input type="number" v-model="roomForm.yearlyPrice" placeholder="请输入年租金"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="主状态" prop="status">
|
||||
<el-select v-model="roomForm.status" placeholder="请选择主状态">
|
||||
<el-select v-model="roomForm.status" placeholder="请选择主状态" style="width: 100%">
|
||||
<el-option label="空房" value="empty"></el-option>
|
||||
<el-option label="在租" value="rented"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="附属状态" prop="subStatus" v-if="roomForm.status === 'rented'">
|
||||
<el-select v-model="roomForm.subStatus" placeholder="请选择附属状态">
|
||||
<el-select v-model="roomForm.subStatus" placeholder="请选择附属状态" style="width: 100%">
|
||||
<el-option label="正常" value="normal"></el-option>
|
||||
<el-option label="即将到期" value="soon_expire"></el-option>
|
||||
<el-option label="已到期" value="expired"></el-option>
|
||||
|
|
@ -40,13 +40,13 @@
|
|||
</el-form-item>
|
||||
|
||||
<el-form-item label="其他状态" prop="otherStatus">
|
||||
<el-select v-model="roomForm.otherStatus" placeholder="请选择其他状态">
|
||||
<el-select v-model="roomForm.otherStatus" placeholder="请选择其他状态" style="width: 100%">
|
||||
<el-option label="无" value=""></el-option>
|
||||
<el-option label="打扫中" value="cleaning"></el-option>
|
||||
<el-option label="维修中" value="maintenance"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item class="form-actions">
|
||||
<el-button type="primary" @click="submitForm">提交</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
|
|
@ -74,7 +74,6 @@ export default {
|
|||
otherStatus: '',
|
||||
subStatus: 'normal'
|
||||
},
|
||||
// 保存返回时的查询参数
|
||||
returnQuery: {},
|
||||
apartments: [],
|
||||
rules: {
|
||||
|
|
@ -125,7 +124,6 @@ export default {
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
// 获取返回时的查询参数
|
||||
this.returnQuery = this.$route.query
|
||||
this.loadApartments()
|
||||
this.loadRoomData()
|
||||
|
|
@ -183,7 +181,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.room-edit {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -191,4 +189,38 @@ export default {
|
|||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-content {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.form-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__label {
|
||||
float: none;
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-content .el-form-item__content {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions .el-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,25 +4,27 @@
|
|||
<template slot="header">
|
||||
<div class="card-header">
|
||||
<span>房间管理</span>
|
||||
<el-button type="primary" @click="handleAdd">添加房间</el-button>
|
||||
<el-button type="primary" size="small" @click="handleAdd">添加房间</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 搜索表单 -->
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<el-form-item label="公寓">
|
||||
<el-select v-model="searchForm.apartmentId" placeholder="请选择公寓">
|
||||
<el-select v-model="searchForm.apartmentId" placeholder="请选择公寓" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option v-for="apartment in apartments" :key="apartment.id" :label="apartment.name" :value="apartment.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="主状态">
|
||||
<el-select v-model="searchForm.status" placeholder="请选择主状态">
|
||||
<el-select v-model="searchForm.status" placeholder="请选择主状态" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="空房" value="empty"></el-option>
|
||||
<el-option label="在租" value="rented"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="附属状态">
|
||||
<el-select v-model="searchForm.subStatus" placeholder="请选择附属状态">
|
||||
<el-select v-model="searchForm.subStatus" placeholder="请选择附属状态" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="正常" value="normal"></el-option>
|
||||
<el-option label="即将到期" value="soon_expire"></el-option>
|
||||
|
|
@ -30,7 +32,7 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="其他状态">
|
||||
<el-select v-model="searchForm.otherStatus" placeholder="请选择其他状态">
|
||||
<el-select v-model="searchForm.otherStatus" placeholder="请选择其他状态" style="width: 100%">
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option label="打扫中" value="cleaning"></el-option>
|
||||
<el-option label="维修中" value="maintenance"></el-option>
|
||||
|
|
@ -44,45 +46,94 @@
|
|||
<el-button @click="resetSearch">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table
|
||||
:data="rooms"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="apartmentName" label="公寓" width="150"></el-table-column>
|
||||
<el-table-column prop="roomNumber" label="房间号" width="100"></el-table-column>
|
||||
<el-table-column prop="area" label="面积(㎡)" width="100"></el-table-column>
|
||||
<el-table-column prop="monthlyPrice" label="月租金(元)" width="120"></el-table-column>
|
||||
<el-table-column prop="yearlyPrice" label="年租金(元)" width="120"></el-table-column>
|
||||
<el-table-column prop="status" label="主状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getStatusType(scope.row.status)">{{ getStatusText(scope.row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="subStatus" label="附属状态" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status === 'rented'" :type="getSubStatusType(scope.row.subStatus)">{{ getSubStatusText(scope.row.subStatus) }}</el-tag>
|
||||
<span v-else>无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column prop="otherStatus" label="其他状态" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.otherStatus" :type="getOtherStatusType(scope.row.otherStatus)">{{ getOtherStatusText(scope.row.otherStatus) }}</el-tag>
|
||||
<span v-else>无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- PC端表格 -->
|
||||
<div class="table-wrapper hidden-xs-only">
|
||||
<el-table
|
||||
:data="rooms"
|
||||
style="width: 100%"
|
||||
v-loading="isLoading"
|
||||
>
|
||||
<el-table-column prop="apartmentName" label="公寓" min-width="120"></el-table-column>
|
||||
<el-table-column prop="roomNumber" label="房间号" width="100"></el-table-column>
|
||||
<el-table-column prop="area" label="面积(㎡)" width="100"></el-table-column>
|
||||
<el-table-column prop="monthlyPrice" label="月租金(元)" width="120"></el-table-column>
|
||||
<el-table-column prop="yearlyPrice" label="年租金(元)" width="120"></el-table-column>
|
||||
<el-table-column prop="status" label="主状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getStatusType(scope.row.status)" size="small">{{ getStatusText(scope.row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="subStatus" label="附属状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status === 'rented'" :type="getSubStatusType(scope.row.subStatus)" size="small">{{ getSubStatusText(scope.row.subStatus) }}</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="otherStatus" label="其他状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.otherStatus" :type="getOtherStatusType(scope.row.otherStatus)" size="small">{{ getOtherStatusText(scope.row.otherStatus) }}</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="primary" @click="handleEdit(scope.row.id)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<el-table-column label="操作" width="200">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="small" type="primary" @click="handleEdit(scope.row.id)">编辑</el-button>
|
||||
<el-button size="small" type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination" style="margin-top: 20px;">
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="mobile-list hidden-sm-and-up">
|
||||
<div v-for="item in rooms" :key="item.id" class="mobile-card">
|
||||
<div class="mobile-card-header">
|
||||
<div class="mobile-card-title">
|
||||
<span>{{ item.apartmentName }}</span>
|
||||
<span class="room-number">{{ item.roomNumber }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-tags">
|
||||
<el-tag :type="getStatusType(item.status)" size="mini">{{ getStatusText(item.status) }}</el-tag>
|
||||
<el-tag v-if="item.status === 'rented' && item.subStatus" :type="getSubStatusType(item.subStatus)" size="mini">
|
||||
{{ getSubStatusText(item.subStatus) }}
|
||||
</el-tag>
|
||||
<el-tag v-if="item.otherStatus" :type="getOtherStatusType(item.otherStatus)" size="mini">
|
||||
{{ getOtherStatusText(item.otherStatus) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-body">
|
||||
<div class="mobile-card-row">
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">面积:</span>
|
||||
<span class="mobile-card-value">{{ item.area }}㎡</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">月租:</span>
|
||||
<span class="mobile-card-value price">¥{{ item.monthlyPrice }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-item" v-if="item.yearlyPrice">
|
||||
<span class="mobile-card-label">年租:</span>
|
||||
<span class="mobile-card-value price">¥{{ item.yearlyPrice }}</span>
|
||||
</div>
|
||||
<div class="mobile-card-item">
|
||||
<span class="mobile-card-label">创建时间:</span>
|
||||
<span class="mobile-card-value">{{ item.createTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mobile-card-footer">
|
||||
<el-button size="mini" type="primary" @click="handleEdit(item.id)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="handleDelete(item.id)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrapper">
|
||||
<el-pagination
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:layout="paginationLayout"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
|
|
@ -114,26 +165,36 @@ export default {
|
|||
},
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
isLoading: false
|
||||
isLoading: false,
|
||||
isMobile: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
paginationLayout() {
|
||||
return this.isMobile ? 'prev, pager, next' : 'total, sizes, prev, pager, next, jumper'
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 从路由参数中获取查询参数和页码
|
||||
this.checkDevice()
|
||||
window.addEventListener('resize', this.checkDevice)
|
||||
this.initFromQuery()
|
||||
this.loadData()
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.checkDevice)
|
||||
},
|
||||
methods: {
|
||||
// 从路由参数初始化搜索参数和页码
|
||||
checkDevice() {
|
||||
this.isMobile = window.innerWidth <= 768
|
||||
},
|
||||
initFromQuery() {
|
||||
const query = this.$route.query
|
||||
if (query) {
|
||||
// 初始化搜索参数
|
||||
if (query.apartmentId) this.searchForm.apartmentId = parseInt(query.apartmentId)
|
||||
if (query.status) this.searchForm.status = query.status
|
||||
if (query.subStatus) this.searchForm.subStatus = query.subStatus
|
||||
if (query.otherStatus) this.searchForm.otherStatus = query.otherStatus
|
||||
if (query.roomNumber) this.searchForm.roomNumber = query.roomNumber
|
||||
// 初始化页码
|
||||
if (query.page) this.currentPage = parseInt(query.page)
|
||||
if (query.pageSize) this.pageSize = parseInt(query.pageSize)
|
||||
}
|
||||
|
|
@ -143,11 +204,9 @@ export default {
|
|||
|
||||
this.isLoading = true
|
||||
try {
|
||||
// 加载公寓数据
|
||||
const apartmentsResponse = await apartmentApi.getAll()
|
||||
this.apartments = apartmentsResponse.data || apartmentsResponse
|
||||
|
||||
// 构建查询参数
|
||||
const params = {
|
||||
apartmentId: this.searchForm.apartmentId,
|
||||
status: this.searchForm.status,
|
||||
|
|
@ -158,11 +217,9 @@ export default {
|
|||
pageSize: this.pageSize
|
||||
}
|
||||
|
||||
// 加载房间数据
|
||||
const roomsResponse = await roomApi.getAll(params)
|
||||
if (roomsResponse.data) {
|
||||
this.rooms = roomsResponse.data.map(room => {
|
||||
// 为房间添加公寓名称
|
||||
const apartment = this.apartments.find(a => a.id == room.apartmentId)
|
||||
return {
|
||||
...room,
|
||||
|
|
@ -171,7 +228,6 @@ export default {
|
|||
})
|
||||
this.total = roomsResponse.total
|
||||
} else {
|
||||
// 兼容旧的返回格式
|
||||
this.rooms = roomsResponse.map(room => {
|
||||
const apartment = this.apartments.find(a => a.id == room.apartmentId)
|
||||
return {
|
||||
|
|
@ -189,7 +245,7 @@ export default {
|
|||
},
|
||||
getStatusType(status) {
|
||||
switch (status) {
|
||||
case 'empty': return ''
|
||||
case 'empty': return 'info'
|
||||
case 'rented': return 'success'
|
||||
default: return ''
|
||||
}
|
||||
|
|
@ -203,7 +259,7 @@ export default {
|
|||
},
|
||||
getOtherStatusType(status) {
|
||||
switch (status) {
|
||||
case 'cleaning': return 'info'
|
||||
case 'cleaning': return 'warning'
|
||||
case 'maintenance': return 'danger'
|
||||
default: return ''
|
||||
}
|
||||
|
|
@ -235,7 +291,6 @@ export default {
|
|||
this.$router.push('/room/add')
|
||||
},
|
||||
handleEdit(id) {
|
||||
// 保存当前的查询参数和页码到路由参数
|
||||
this.$router.push({
|
||||
path: `/room/edit/${id}`,
|
||||
query: {
|
||||
|
|
@ -292,7 +347,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.room-list {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -305,8 +360,148 @@ export default {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* 移动端卡片列表样式 */
|
||||
.mobile-list {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mobile-card-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.mobile-card-title span:first-child {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.room-number {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.mobile-card-tags {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mobile-card-body {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-card-row {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.mobile-card-item {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mobile-card-label {
|
||||
color: #909399;
|
||||
min-width: 50px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.mobile-card-value {
|
||||
color: #606266;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mobile-card-value.price {
|
||||
color: #f56c6c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mobile-card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
/* 响应式显示控制 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.hidden-xs-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item {
|
||||
display: block;
|
||||
margin-right: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.search-form .el-form-item__content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-form .el-input,
|
||||
.search-form .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.hidden-sm-and-up {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -9,13 +9,23 @@
|
|||
<div class="chart-container">
|
||||
<el-empty description="图表功能暂未实现" style="margin: 40px 0;"></el-empty>
|
||||
</div>
|
||||
<el-table :data="roomStatusData" style="width: 100%; margin-top: 20px;">
|
||||
<el-table-column prop="status" label="状态" width="120"></el-table-column>
|
||||
<el-table-column prop="count" label="数量"></el-table-column>
|
||||
<el-table-column prop="percentage" label="占比"></el-table-column>
|
||||
</el-table>
|
||||
<div class="total-count" style="margin-top: 20px; text-align: right;">
|
||||
<el-tag size="large" type="primary">房间总数:{{ totalCount }} 间</el-tag>
|
||||
<div class="table-wrapper">
|
||||
<el-table :data="roomStatusData" style="width: 100%; margin-top: 20px;" class="stats-table">
|
||||
<el-table-column prop="status" label="状态" min-width="100"></el-table-column>
|
||||
<el-table-column prop="count" label="数量" min-width="80">
|
||||
<template slot-scope="scope">
|
||||
<span class="count-value">{{ scope.row.count }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="percentage" label="占比" min-width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-progress :percentage="parseFloat(scope.row.percentage)" :show-text="true"></el-progress>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="total-count">
|
||||
<el-tag size="medium" type="primary">房间总数:{{ totalCount }} 间</el-tag>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
|
@ -33,7 +43,6 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
totalCount() {
|
||||
// 只计算在租和空房的数量
|
||||
return this.roomStatusData
|
||||
.filter(item => item.status === '在租' || item.status === '空房')
|
||||
.reduce((sum, item) => sum + item.count, 0)
|
||||
|
|
@ -47,13 +56,12 @@ export default {
|
|||
try {
|
||||
const response = await statisticsApi.getRoomStatus()
|
||||
const data = response
|
||||
// 只计算在租和空房的数量作为总数
|
||||
const total = data
|
||||
.filter(item => item.status === '在租' || item.status === '空房')
|
||||
.reduce((sum, item) => sum + item.count, 0)
|
||||
this.roomStatusData = data.map(item => ({
|
||||
...item,
|
||||
percentage: total > 0 ? `${((item.count / total) * 100).toFixed(2)}%` : '0.00%'
|
||||
percentage: total > 0 ? parseFloat(((item.count / total) * 100).toFixed(2)) : 0
|
||||
}))
|
||||
} catch (error) {
|
||||
this.$message.error('加载房间状态统计数据失败')
|
||||
|
|
@ -65,7 +73,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.room-statistics {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -79,4 +87,38 @@ export default {
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.stats-table {
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.count-value {
|
||||
font-weight: bold;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.total-count {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.chart-container {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.total-count {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -9,12 +9,18 @@
|
|||
<div class="chart-container">
|
||||
<el-empty description="图表功能暂未实现" style="margin: 40px 0;"></el-empty>
|
||||
</div>
|
||||
<el-table :data="rentData" style="width: 100%; margin-top: 20px;">
|
||||
<el-table-column prop="month" label="月份" width="120"></el-table-column>
|
||||
<el-table-column prop="amount" label="租金收入(元)"></el-table-column>
|
||||
</el-table>
|
||||
<div class="total-amount" style="margin-top: 20px; text-align: right;">
|
||||
<el-tag size="large" type="primary">总租金收入:{{ totalAmount }} 元</el-tag>
|
||||
<div class="table-wrapper">
|
||||
<el-table :data="rentData" style="width: 100%; margin-top: 20px;" class="stats-table">
|
||||
<el-table-column prop="month" label="月份" min-width="100"></el-table-column>
|
||||
<el-table-column prop="amount" label="租金收入(元)" min-width="150">
|
||||
<template slot-scope="scope">
|
||||
<span class="amount-value">¥{{ scope.row.amount }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="total-amount">
|
||||
<el-tag size="medium" type="primary">总租金收入:{{ totalAmount }} 元</el-tag>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
|
@ -53,7 +59,7 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
.rent-statistics {
|
||||
padding: 20px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
|
@ -65,4 +71,38 @@ export default {
|
|||
.chart-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.stats-table {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.amount-value {
|
||||
color: #f56c6c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.chart-container {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue