no message
This commit is contained in:
@@ -1,418 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ page import="java.util.List, com.hrs.model.entity.Collection, com.hrs.model.entity.House, com.hrs.model.entity.User" %>
|
||||
<%
|
||||
User loginUser = (User) session.getAttribute("loginUser");
|
||||
if (loginUser == null || !"0".equals(loginUser.getRoleType())) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/login");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Collection> collectionList = (List<Collection>) request.getAttribute("collectionList");
|
||||
Integer totalCount = (Integer) request.getAttribute("totalCount");
|
||||
String msg = request.getParameter("msg");
|
||||
String error = request.getParameter("error");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>我的收藏 - 租房系统</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, "微软雅黑", sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 20px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.nav a:hover, .nav a.active {
|
||||
background-color: #45a049;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background-color: white;
|
||||
padding: 12px 0;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.stats {
|
||||
background-color: white;
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.message {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
animation: fadeOut 3s ease forwards;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
animation: fadeOut 3s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
0% { opacity: 1; }
|
||||
70% { opacity: 1; }
|
||||
100% { opacity: 0; display: none; }
|
||||
}
|
||||
|
||||
.collection-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.collection-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
transition: transform 0.3s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.collection-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.house-image {
|
||||
height: 200px;
|
||||
background-color: #e0e0e0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.house-image .no-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.house-info {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.house-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.house-title a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.house-title a:hover {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.house-detail {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.house-price {
|
||||
color: #f44336;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.house-price span {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.collect-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: rgba(0,0,0,0.6);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
transition: background-color 0.3s;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 80px;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
margin-top: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.empty-state a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
right: 20px;
|
||||
padding: 12px 24px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
z-index: 1000;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.toast-success {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
.toast-error {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="container clearfix">
|
||||
<div class="logo">🏠 租房系统</div>
|
||||
<div class="user-info">
|
||||
欢迎,<%= loginUser.getRealName() %> |
|
||||
<a href="${pageContext.request.contextPath}/user/logout" style="color:white;">退出</a>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a>
|
||||
<a href="${pageContext.request.contextPath}/user/collection/list" class="active">我的收藏</a>
|
||||
<a href="${pageContext.request.contextPath}/user/reservation/list">我的预约</a>
|
||||
<a href="${pageContext.request.contextPath}/user/order/list">我的订单</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="breadcrumb">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a> >
|
||||
<span>我的收藏</span>
|
||||
</div>
|
||||
|
||||
<% if (msg != null) { %>
|
||||
<div class="message"><%= msg %></div>
|
||||
<% } %>
|
||||
<% if (error != null) { %>
|
||||
<div class="error-message"><%= error %></div>
|
||||
<% } %>
|
||||
|
||||
<div class="stats">
|
||||
📚 共收藏 <strong id="totalCount"><%= totalCount %></strong> 套房源
|
||||
</div>
|
||||
|
||||
<div class="collection-list" id="collectionList">
|
||||
<%
|
||||
if (collectionList != null && !collectionList.isEmpty()) {
|
||||
for (Collection collection : collectionList) {
|
||||
House house = collection.getHouse();
|
||||
if (house != null) {
|
||||
%>
|
||||
<div class="collection-card" data-id="<%= collection.getId() %>">
|
||||
<div class="house-image" style="background-image: url('<%= house.getFirstImage() != null ? house.getFirstImage() : "" %>');">
|
||||
<% if (house.getFirstImage() == null) { %>
|
||||
<div class="no-image">🏠 暂无图片</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<button class="delete-btn" onclick="deleteCollection(<%= collection.getId() %>)" title="取消收藏">×</button>
|
||||
<div class="house-info">
|
||||
<div class="house-title">
|
||||
<a href="${pageContext.request.contextPath}/user/house/detail?id=<%= house.getId() %>">
|
||||
<%= house.getTitle() %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="house-detail">
|
||||
📍 <%= house.getArea() %> | <%= house.getHouseType() %> | <%= house.getRentTypeText() %>
|
||||
</div>
|
||||
<div class="house-price">
|
||||
¥<%= house.getRentPrice() %><span>/月</span>
|
||||
</div>
|
||||
<div class="collect-time">
|
||||
收藏时间:<%= collection.getCollectTime() %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
}
|
||||
} else {
|
||||
%>
|
||||
<div class="empty-state">
|
||||
<div style="font-size: 64px;">❤️</div>
|
||||
<p>还没有收藏任何房源</p>
|
||||
<p><a href="${pageContext.request.contextPath}/user/house/list">去浏览房源 >></a></p>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2026 租房系统 | 让租房更简单</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// AJAX删除收藏
|
||||
function deleteCollection(id) {
|
||||
if (confirm('确定要取消收藏这套房源吗?')) {
|
||||
// 发送AJAX请求
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '${pageContext.request.contextPath}/user/collection/delete?id=' + id + '&ajax=true&from=list', true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||
var result = JSON.parse(xhr.responseText);
|
||||
if (result.success) {
|
||||
// 移除DOM元素
|
||||
var card = document.querySelector('.collection-card[data-id="' + id + '"]');
|
||||
if (card) {
|
||||
card.remove();
|
||||
}
|
||||
// 更新计数
|
||||
var totalSpan = document.getElementById('totalCount');
|
||||
var currentCount = parseInt(totalSpan.innerText);
|
||||
totalSpan.innerText = currentCount - 1;
|
||||
// 显示成功提示
|
||||
showToast('取消收藏成功', 'success');
|
||||
// 检查是否还有收藏
|
||||
var remainingCards = document.querySelectorAll('.collection-card');
|
||||
if (remainingCards.length == 0) {
|
||||
location.reload(); // 刷新页面显示空状态
|
||||
}
|
||||
} else {
|
||||
showToast(result.msg || '取消收藏失败', 'error');
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
}
|
||||
|
||||
// 显示提示消息
|
||||
function showToast(msg, type) {
|
||||
var toast = document.createElement('div');
|
||||
toast.className = 'toast toast-' + type;
|
||||
toast.innerHTML = msg;
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(function() {
|
||||
toast.remove();
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,597 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ page import="com.hrs.model.entity.House, com.hrs.model.entity.User" %>
|
||||
<%
|
||||
User loginUser = (User) session.getAttribute("loginUser");
|
||||
if (loginUser == null || !"0".equals(loginUser.getRoleType())) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/login");
|
||||
return;
|
||||
}
|
||||
|
||||
House house = (House) request.getAttribute("house");
|
||||
if (house == null) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/house/list");
|
||||
return;
|
||||
}
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><%= house.getTitle() %> - 租房系统</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, "微软雅黑", sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 头部导航 */
|
||||
.header {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 20px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
background-color: #45a049;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 面包屑导航 */
|
||||
.breadcrumb {
|
||||
background-color: white;
|
||||
padding: 12px 0;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.breadcrumb a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 主要内容区 */
|
||||
.main-content {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 图片区域 */
|
||||
.house-images {
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.main-image {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-color: #f0f0f0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.thumb-images {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
width: 80px;
|
||||
height: 60px;
|
||||
background-color: #e0e0e0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.thumb:hover {
|
||||
border-color: #4CAF50;
|
||||
}
|
||||
|
||||
.thumb.active {
|
||||
border-color: #4CAF50;
|
||||
}
|
||||
|
||||
.no-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #999;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
/* 房源信息 */
|
||||
.house-info {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.house-title {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.price-box {
|
||||
background-color: #fff3e0;
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 32px;
|
||||
color: #f44336;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.price span {
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 15px;
|
||||
border-bottom: 2px solid #4CAF50;
|
||||
}
|
||||
|
||||
.facility-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.facility-item {
|
||||
background-color: #f5f5f5;
|
||||
padding: 5px 15px;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.description {
|
||||
line-height: 1.8;
|
||||
color: #666;
|
||||
background-color: #f9f9f9;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* 房东信息 */
|
||||
.landlord-card {
|
||||
background-color: #f9f9f9;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.landlord-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.landlord-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.landlord-avatar {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-color: #4CAF50;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.landlord-details p {
|
||||
margin: 5px 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 30px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #ff9800;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #fb8c00;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
border: 1px solid #4CAF50;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 页脚 */
|
||||
.footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
/* 消息提示 */
|
||||
.message {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
padding: 12px 20px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
z-index: 1000;
|
||||
animation: slideIn 0.3s ease;
|
||||
}
|
||||
|
||||
.message-success {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
.message-error {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 头部导航 -->
|
||||
<div class="header">
|
||||
<div class="container clearfix">
|
||||
<div class="logo">🏠 租房系统</div>
|
||||
<div class="user-info">
|
||||
欢迎,<%= loginUser.getRealName() %> |
|
||||
<a href="${pageContext.request.contextPath}/user/logout" style="color:white;">退出</a>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a>
|
||||
<a href="${pageContext.request.contextPath}/user/collection/list">我的收藏</a>
|
||||
<a href="${pageContext.request.contextPath}/user/reservation/list">我的预约</a>
|
||||
<a href="${pageContext.request.contextPath}/user/order/list">我的订单</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- 面包屑导航 -->
|
||||
<div class="breadcrumb">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a> >
|
||||
<span><%= house.getTitle() %></span>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<!-- 图片区域 -->
|
||||
<div class="house-images">
|
||||
<div class="main-image" id="mainImage" style="background-image: url('<%= house.getFirstImage() != null ? house.getFirstImage() : "" %>');">
|
||||
<% if (house.getFirstImage() == null) { %>
|
||||
<div class="no-image">🏠 暂无图片</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="thumb-images" id="thumbImages">
|
||||
<%
|
||||
String[] images = null;
|
||||
if (house.getImgUrl() != null && !house.getImgUrl().isEmpty()) {
|
||||
images = house.getImgUrl().split(",");
|
||||
for (int i = 0; i < images.length; i++) {
|
||||
%>
|
||||
<div class="thumb" style="background-image: url('<%= images[i] %>');" onclick="changeImage('<%= images[i] %>', this)"></div>
|
||||
<%
|
||||
}
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 房源信息 -->
|
||||
<div class="house-info">
|
||||
<div class="house-title"><%= house.getTitle() %></div>
|
||||
|
||||
<div class="price-box">
|
||||
<span class="price">¥<%= house.getRentPrice() %><span>/月</span></span>
|
||||
</div>
|
||||
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<div class="info-label">户型</div>
|
||||
<div class="info-value"><%= house.getHouseType() != null ? house.getHouseType() : "待定" %></div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">面积</div>
|
||||
<div class="info-value"><%= house.getArea() != null ? house.getArea() : "待定" %></div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">租赁类型</div>
|
||||
<div class="info-value"><%= house.getRentTypeText() %></div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">房源编号</div>
|
||||
<div class="info-value"><%= house.getHouseNo() %></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">📍 房源地址</div>
|
||||
<p style="color: #666;"><%= house.getAddress() != null ? house.getAddress() : "暂无地址信息" %></p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">🛋️ 配套设施</div>
|
||||
<div class="facility-list">
|
||||
<%
|
||||
String facility = house.getFacility();
|
||||
if (facility != null && !facility.isEmpty()) {
|
||||
String[] facilities = facility.split(",");
|
||||
for (String f : facilities) {
|
||||
%>
|
||||
<span class="facility-item"><%= f.trim() %></span>
|
||||
<%
|
||||
}
|
||||
} else {
|
||||
%>
|
||||
<span class="facility-item">暂无设施信息</span>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">📝 房源描述</div>
|
||||
<div class="description">
|
||||
<%= house.getDescription() != null ? house.getDescription() : "暂无描述信息" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 房东信息 -->
|
||||
<div class="landlord-card">
|
||||
<div class="landlord-title">👤 房东信息</div>
|
||||
<div class="landlord-info">
|
||||
<div class="landlord-avatar">👨</div>
|
||||
<div class="landlord-details">
|
||||
<p><strong><%= house.getLandlordName() != null ? house.getLandlordName() : "房东" %></strong></p>
|
||||
<p>📞 <%= house.getLandlordPhone() != null ? house.getLandlordPhone() : "暂无联系方式" %></p>
|
||||
<p>⭐ 认证房东 · 已发布房源</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-primary" onclick="makeReservation()">📅 预约看房</button>
|
||||
<%
|
||||
// 检查是否已收藏
|
||||
com.hrs.model.dao.CollectionDAO collectionDAO = new com.hrs.model.dao.CollectionDAO();
|
||||
boolean isCollected = collectionDAO.isCollected(loginUser.getId(), house.getId());
|
||||
if (isCollected) {
|
||||
%>
|
||||
<button class="btn btn-outline" onclick="cancelCollection(<%= house.getId() %>)">❤️ 已收藏</button>
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
<button class="btn btn-secondary" onclick="addToCollection()">❤️ 收藏房源</button>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
<a href="${pageContext.request.contextPath}/user/house/list" class="btn btn-outline">🔙 返回列表</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<div class="footer">
|
||||
<p>© 2026 租房系统 | 让租房更简单</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 切换主图
|
||||
function changeImage(url, element) {
|
||||
document.getElementById('mainImage').style.backgroundImage = 'url(' + url + ')';
|
||||
|
||||
// 移除所有active类
|
||||
var thumbs = document.querySelectorAll('.thumb');
|
||||
thumbs.forEach(function(thumb) {
|
||||
thumb.classList.remove('active');
|
||||
});
|
||||
// 添加active类到当前
|
||||
element.classList.add('active');
|
||||
}
|
||||
|
||||
// 预约看房
|
||||
function makeReservation() {
|
||||
var houseId = <%= house.getId() %>;
|
||||
// 跳转到预约页面
|
||||
window.location.href = '${pageContext.request.contextPath}/user/reservation/add?houseId=' + houseId;
|
||||
}
|
||||
|
||||
// 收藏房源(暂时用alert,后面实现真正的收藏功能)
|
||||
function addToCollection() {
|
||||
var houseId = <%= house.getId() %>;
|
||||
// 发送AJAX请求收藏
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '${pageContext.request.contextPath}/user/collection/add', true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||
var result = xhr.responseText;
|
||||
if (result == 'success') {
|
||||
showMessage('收藏成功!', 'success');
|
||||
// 刷新页面更新按钮状态
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
} else if (result == 'exists') {
|
||||
showMessage('您已经收藏过这套房源了', 'error');
|
||||
} else {
|
||||
showMessage('收藏失败,请稍后重试', 'error');
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send('houseId=' + houseId);
|
||||
}
|
||||
|
||||
// 取消收藏
|
||||
function cancelCollection(houseId) {
|
||||
if (confirm('确定要取消收藏这套房源吗?')) {
|
||||
window.location.href = '${pageContext.request.contextPath}/user/collection/deleteByHouse?houseId=' + houseId;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示提示消息
|
||||
function showMessage(msg, type) {
|
||||
var messageDiv = document.createElement('div');
|
||||
messageDiv.className = 'message message-' + type;
|
||||
messageDiv.innerHTML = msg;
|
||||
document.body.appendChild(messageDiv);
|
||||
|
||||
setTimeout(function() {
|
||||
messageDiv.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 如果有缩略图,默认第一个高亮
|
||||
var firstThumb = document.querySelector('.thumb');
|
||||
if (firstThumb) {
|
||||
firstThumb.classList.add('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,412 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ page import="java.util.List, com.hrs.model.entity.House, com.hrs.model.entity.User" %>
|
||||
<%
|
||||
User loginUser = (User) session.getAttribute("loginUser");
|
||||
if (loginUser == null || !"0".equals(loginUser.getRoleType())) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/login");
|
||||
return;
|
||||
}
|
||||
|
||||
List<House> houseList = (List<House>) request.getAttribute("houseList");
|
||||
Integer totalCount = (Integer) request.getAttribute("totalCount");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>房源列表 - 租房系统</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, "微软雅黑", sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 头部导航 */
|
||||
.header {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 20px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
background-color: #45a049;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 搜索栏 */
|
||||
.search-bar {
|
||||
background-color: white;
|
||||
padding: 20px 0;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: flex-end;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.search-group label {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.search-group input, .search-group select {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.search-btn:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.reset-btn {
|
||||
background-color: #999;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* 房源列表 */
|
||||
.house-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.house-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
transition: transform 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.house-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.house-image {
|
||||
height: 200px;
|
||||
background-color: #e0e0e0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.house-image .no-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.house-info {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.house-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.house-title a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.house-title a:hover {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.house-detail {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.house-price {
|
||||
color: #f44336;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.house-price span {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.house-tags {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
background-color: #f0f0f0;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
margin-right: 5px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.house-footer {
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 10px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.landlord-info {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 5px 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background-color: transparent;
|
||||
border: 1px solid #4CAF50;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 统计信息 */
|
||||
.stats {
|
||||
background-color: white;
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 页脚 */
|
||||
.footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 头部导航 -->
|
||||
<div class="header">
|
||||
<div class="container clearfix">
|
||||
<div class="logo">🏠 租房系统</div>
|
||||
<div class="user-info">
|
||||
欢迎,<%= loginUser.getRealName() %> |
|
||||
<a href="${pageContext.request.contextPath}/user/logout" style="color:white;">退出</a>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a>
|
||||
<a href="${pageContext.request.contextPath}/user/collection/list">我的收藏</a>
|
||||
<a href="#">我的预约</a>
|
||||
<a href="#">我的订单</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<div class="container">
|
||||
<form class="search-form" action="${pageContext.request.contextPath}/user/house/list" method="get">
|
||||
<div class="search-group">
|
||||
<label>区域</label>
|
||||
<select name="area">
|
||||
<option value="">全部区域</option>
|
||||
<option value="朝阳区" <%= "朝阳区".equals(request.getAttribute("searchArea")) ? "selected" : "" %>>朝阳区</option>
|
||||
<option value="海淀区" <%= "海淀区".equals(request.getAttribute("searchArea")) ? "selected" : "" %>>海淀区</option>
|
||||
<option value="东城区" <%= "东城区".equals(request.getAttribute("searchArea")) ? "selected" : "" %>>东城区</option>
|
||||
<option value="西城区" <%= "西城区".equals(request.getAttribute("searchArea")) ? "selected" : "" %>>西城区</option>
|
||||
<option value="丰台区" <%= "丰台区".equals(request.getAttribute("searchArea")) ? "selected" : "" %>>丰台区</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="search-group">
|
||||
<label>最低租金(元)</label>
|
||||
<input type="number" name="minPrice" placeholder="不限" value="<%= request.getAttribute("minPrice") != null ? request.getAttribute("minPrice") : "" %>">
|
||||
</div>
|
||||
<div class="search-group">
|
||||
<label>最高租金(元)</label>
|
||||
<input type="number" name="maxPrice" placeholder="不限" value="<%= request.getAttribute("maxPrice") != null ? request.getAttribute("maxPrice") : "" %>">
|
||||
</div>
|
||||
<button type="submit" class="search-btn">搜索</button>
|
||||
<a href="${pageContext.request.contextPath}/user/house/list" class="reset-btn">重置</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<!-- 统计信息 -->
|
||||
<div class="stats">
|
||||
📊 共找到 <strong><%= totalCount %></strong> 套房源
|
||||
</div>
|
||||
|
||||
<!-- 房源列表 -->
|
||||
<div class="house-list">
|
||||
<%
|
||||
if (houseList != null && !houseList.isEmpty()) {
|
||||
for (House house : houseList) {
|
||||
%>
|
||||
<div class="house-card">
|
||||
<div class="house-image" style="background-image: url('<%= house.getFirstImage() != null ? house.getFirstImage() : "" %>');">
|
||||
<% if (house.getFirstImage() == null) { %>
|
||||
<div class="no-image">🏠 暂无图片</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="house-info">
|
||||
<div class="house-title">
|
||||
<a href="${pageContext.request.contextPath}/user/house/detail?id=<%= house.getId() %>">
|
||||
<%= house.getTitle() %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="house-detail">
|
||||
📍 <%= house.getArea() %> | <%= house.getHouseType() %> | <%= house.getRentTypeText() %>
|
||||
</div>
|
||||
<div class="house-price">
|
||||
¥<%= house.getRentPrice() %><span>/月</span>
|
||||
</div>
|
||||
<div class="house-tags">
|
||||
<span class="tag">#<%= house.getHouseType() %></span>
|
||||
<span class="tag">#<%= house.getArea() %></span>
|
||||
</div>
|
||||
<div class="house-footer">
|
||||
<div class="landlord-info">
|
||||
👤 <%= house.getLandlordName() != null ? house.getLandlordName() : "房东" %>
|
||||
</div>
|
||||
<a href="${pageContext.request.contextPath}/user/house/detail?id=<%= house.getId() %>" class="btn btn-primary">
|
||||
查看详情
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
} else {
|
||||
%>
|
||||
<div class="empty-state">
|
||||
<div style="font-size: 48px;">🏠</div>
|
||||
<p>暂无房源,请稍后再来</p>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<div class="footer">
|
||||
<p>© 2026 租房系统 | 让租房更简单</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%
|
||||
// 重定向到房源列表页
|
||||
response.sendRedirect(request.getContextPath() + "/user/house/list");
|
||||
%>
|
||||
@@ -1,151 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>租房系统登录</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
.login-container {
|
||||
background-color: white;
|
||||
padding: 40px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
width: 360px;
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
.role-group {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.role-group label {
|
||||
display: inline;
|
||||
font-weight: normal;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.error {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.register-link {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
color: #666;
|
||||
}
|
||||
.register-link a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
.register-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<h2>租房系统登录</h2>
|
||||
|
||||
<%-- 显示错误信息 --%>
|
||||
<%
|
||||
String error = (String)request.getAttribute("error");
|
||||
if(error != null) {
|
||||
%>
|
||||
<div class="error"><%= error %></div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
<%-- 显示成功信息(如注册成功) --%>
|
||||
<%
|
||||
String message = (String)request.getAttribute("message");
|
||||
if(message != null) {
|
||||
%>
|
||||
<div class="message" style="background-color:#e8f5e9; color:#2e7d32; padding:10px; border-radius:4px; margin-bottom:20px; text-align:center;">
|
||||
<%= message %>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
<form action="${pageContext.request.contextPath}/user/login" method="post">
|
||||
<div class="form-group">
|
||||
<label>用户名:</label>
|
||||
<input type="text" name="username" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>密码:</label>
|
||||
<input type="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>登录角色:</label>
|
||||
<div class="role-group">
|
||||
<label>
|
||||
<input type="radio" name="roleType" value="0" checked> 租客
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="roleType" value="1"> 房东
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="roleType" value="2"> 管理员
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit">登录</button>
|
||||
</form>
|
||||
|
||||
<div class="register-link">
|
||||
还没有账号? <a href="${pageContext.request.contextPath}/user/register">立即注册</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,218 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>租房系统注册</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.register-container {
|
||||
background-color: white;
|
||||
padding: 40px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
width: 450px;
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
.role-group {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.role-group label {
|
||||
display: inline;
|
||||
font-weight: normal;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
.error {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.message {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.login-link {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
color: #666;
|
||||
}
|
||||
.login-link a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
.login-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.hint {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.required {
|
||||
color: #f44336;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="register-container">
|
||||
<h2>租房系统注册</h2>
|
||||
|
||||
<%-- 显示错误信息 --%>
|
||||
<%
|
||||
String error = (String)request.getAttribute("error");
|
||||
if(error != null) {
|
||||
%>
|
||||
<div class="error"><%= error %></div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
<%-- 显示成功信息 --%>
|
||||
<%
|
||||
String message = (String)request.getAttribute("message");
|
||||
if(message != null) {
|
||||
%>
|
||||
<div class="message"><%= message %></div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
<form action="${pageContext.request.contextPath}/user/register" method="post">
|
||||
<div class="form-group">
|
||||
<label>用户名 <span class="required">*</span></label>
|
||||
<input type="text" name="username" placeholder="请输入用户名" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>密码 <span class="required">*</span></label>
|
||||
<input type="password" name="password" placeholder="请输入密码" required>
|
||||
<div class="hint">密码长度6-20位,建议使用字母+数字组合</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>确认密码 <span class="required">*</span></label>
|
||||
<input type="password" name="confirmPassword" placeholder="请再次输入密码" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>真实姓名</label>
|
||||
<input type="text" name="realName" placeholder="请输入真实姓名">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>手机号 <span class="required">*</span></label>
|
||||
<input type="text" name="phone" placeholder="请输入11位手机号" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>身份证号</label>
|
||||
<input type="text" name="idCard" placeholder="请输入身份证号(可选)">
|
||||
<div class="hint">房东认证需要提供身份证号</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>注册角色 <span class="required">*</span></label>
|
||||
<div class="role-group">
|
||||
<label>
|
||||
<input type="radio" name="roleType" value="0" checked> 租客
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" name="roleType" value="1"> 房东
|
||||
</label>
|
||||
</div>
|
||||
<div class="hint">房东需要管理员审核认证后才能发布房源</div>
|
||||
</div>
|
||||
|
||||
<button type="submit">立即注册</button>
|
||||
</form>
|
||||
|
||||
<div class="login-link">
|
||||
已有账号? <a href="${pageContext.request.contextPath}/user/login">返回登录</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 简单的前端验证
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
var password = document.querySelector('input[name="password"]').value;
|
||||
var confirm = document.querySelector('input[name="confirmPassword"]').value;
|
||||
var phone = document.querySelector('input[name="phone"]').value;
|
||||
|
||||
// 验证密码长度
|
||||
if(password.length < 6 || password.length > 20) {
|
||||
alert('密码长度应为6-20位');
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证两次密码
|
||||
if(password !== confirm) {
|
||||
alert('两次输入的密码不一致');
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证手机号
|
||||
var phoneReg = /^1[3-9]\d{9}$/;
|
||||
if(!phoneReg.test(phone)) {
|
||||
alert('请输入正确的11位手机号');
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,313 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ page import="com.hrs.model.entity.House, com.hrs.model.entity.User" %>
|
||||
<%
|
||||
User loginUser = (User) session.getAttribute("loginUser");
|
||||
if (loginUser == null || !"0".equals(loginUser.getRoleType())) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/login");
|
||||
return;
|
||||
}
|
||||
|
||||
House house = (House) request.getAttribute("house");
|
||||
if (house == null) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/house/list");
|
||||
return;
|
||||
}
|
||||
|
||||
String error = (String) request.getAttribute("error");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>预约看房 - 租房系统</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, "微软雅黑", sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 20px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.nav a:hover {
|
||||
background-color: #45a049;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background-color: white;
|
||||
padding: 12px 0;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.main-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.house-summary {
|
||||
background-color: #f9f9f9;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 25px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.house-img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: #e0e0e0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.house-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.house-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.house-detail {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.house-price {
|
||||
color: #f44336;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 30px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #999;
|
||||
color: white;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="container clearfix">
|
||||
<div class="logo">🏠 租房系统</div>
|
||||
<div class="user-info">
|
||||
欢迎,<%= loginUser.getRealName() %> |
|
||||
<a href="${pageContext.request.contextPath}/user/logout" style="color:white;">退出</a>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a>
|
||||
<a href="${pageContext.request.contextPath}/user/collection/list">我的收藏</a>
|
||||
<a href="${pageContext.request.contextPath}/user/reservation/list">我的预约</a>
|
||||
<a href="${pageContext.request.contextPath}/user/order/list">我的订单</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="breadcrumb">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a> >
|
||||
<a href="${pageContext.request.contextPath}/user/house/detail?id=<%= house.getId() %>">房源详情</a> >
|
||||
<span>预约看房</span>
|
||||
</div>
|
||||
|
||||
<div class="main-card">
|
||||
<h2 style="margin-bottom: 20px;">📅 预约看房</h2>
|
||||
|
||||
<% if (error != null) { %>
|
||||
<div class="error"><%= error %></div>
|
||||
<% } %>
|
||||
|
||||
<!-- 房源信息摘要 -->
|
||||
<div class="house-summary">
|
||||
<div class="house-img" style="background-image: url('<%= house.getFirstImage() != null ? house.getFirstImage() : "" %>');">
|
||||
<% if (house.getFirstImage() == null) { %>
|
||||
<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#999;">🏠</div>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="house-info">
|
||||
<div class="house-title"><%= house.getTitle() %></div>
|
||||
<div class="house-detail">📍 <%= house.getArea() %> | <%= house.getHouseType() %> | <%= house.getRentTypeText() %></div>
|
||||
<div class="house-price">¥<%= house.getRentPrice() %>/月</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="${pageContext.request.contextPath}/user/reservation/add" method="post">
|
||||
<input type="hidden" name="houseId" value="<%= house.getId() %>">
|
||||
|
||||
<div class="form-group">
|
||||
<label>选择看房日期 *</label>
|
||||
<input type="date" name="reserveDate" required min="<%= new java.text.SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()) %>">
|
||||
<div class="hint">请选择您方便的看房日期</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>选择看房时间 *</label>
|
||||
<input type="time" name="reserveTime" required>
|
||||
<div class="hint">建议选择 9:00-18:00 之间的时间</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>备注信息(可选)</label>
|
||||
<textarea name="remark" placeholder="请输入您的特殊需求或问题..."></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">提交预约</button>
|
||||
<a href="${pageContext.request.contextPath}/user/house/detail?id=<%= house.getId() %>" class="btn btn-secondary">返回</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2026 租房系统 | 让租房更简单</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 设置日期最小值
|
||||
var dateInput = document.querySelector('input[type="date"]');
|
||||
var today = new Date();
|
||||
var yyyy = today.getFullYear();
|
||||
var mm = String(today.getMonth() + 1).padStart(2, '0');
|
||||
var dd = String(today.getDate()).padStart(2, '0');
|
||||
dateInput.min = yyyy + '-' + mm + '-' + dd;
|
||||
|
||||
// 设置时间默认值
|
||||
var timeInput = document.querySelector('input[type="time"]');
|
||||
timeInput.value = "10:00";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,347 +0,0 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%@ page import="java.util.List, java.text.SimpleDateFormat, com.hrs.model.entity.Reservation, com.hrs.model.entity.House, com.hrs.model.entity.User" %>
|
||||
<%
|
||||
User loginUser = (User) session.getAttribute("loginUser");
|
||||
if (loginUser == null || !"0".equals(loginUser.getRoleType())) {
|
||||
response.sendRedirect(request.getContextPath() + "/user/login");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Reservation> reservationList = (List<Reservation>) request.getAttribute("reservationList");
|
||||
Integer totalCount = (Integer) request.getAttribute("totalCount");
|
||||
String msg = request.getParameter("msg");
|
||||
String error = request.getParameter("error");
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
%>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>我的预约 - 租房系统</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, "微软雅黑", sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logo {
|
||||
float: left;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-left: 20px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.nav a:hover, .nav a.active {
|
||||
background-color: #45a049;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background-color: white;
|
||||
padding: 12px 0;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.stats {
|
||||
background-color: white;
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.message {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
animation: fadeOut 3s ease forwards;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
animation: fadeOut 3s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
0% { opacity: 1; }
|
||||
70% { opacity: 1; }
|
||||
100% { opacity: 0; display: none; }
|
||||
}
|
||||
|
||||
.reservation-table {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3e0;
|
||||
color: #f39c12;
|
||||
}
|
||||
|
||||
.status-confirmed {
|
||||
background-color: #e8f5e9;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #ffebee;
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #e3f2fd;
|
||||
color: #2196F3;
|
||||
}
|
||||
|
||||
.house-link {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.house-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 4px 12px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
|
||||
.btn-disabled {
|
||||
background-color: #ccc;
|
||||
color: #666;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.empty-state a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.clearfix::after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="container clearfix">
|
||||
<div class="logo">🏠 租房系统</div>
|
||||
<div class="user-info">
|
||||
欢迎,<%= loginUser.getRealName() %> |
|
||||
<a href="${pageContext.request.contextPath}/user/logout" style="color:white;">退出</a>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a>
|
||||
<a href="${pageContext.request.contextPath}/user/collection/list">我的收藏</a>
|
||||
<a href="${pageContext.request.contextPath}/user/reservation/list" class="active">我的预约</a>
|
||||
<a href="${pageContext.request.contextPath}/user/order/list">我的订单</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="breadcrumb">
|
||||
<a href="${pageContext.request.contextPath}/user/house/list">首页</a> >
|
||||
<span>我的预约</span>
|
||||
</div>
|
||||
|
||||
<% if (msg != null) { %>
|
||||
<div class="message"><%= msg %></div>
|
||||
<% } %>
|
||||
<% if (error != null) { %>
|
||||
<div class="error-message"><%= error %></div>
|
||||
<% } %>
|
||||
|
||||
<div class="stats">
|
||||
📋 共有 <strong><%= totalCount %></strong> 条预约记录
|
||||
</div>
|
||||
|
||||
<div class="reservation-table">
|
||||
<%
|
||||
if (reservationList != null && !reservationList.isEmpty()) {
|
||||
%>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>房源信息</th>
|
||||
<th>预约时间</th>
|
||||
<th>状态</th>
|
||||
<th>备注</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
for (Reservation reservation : reservationList) {
|
||||
House house = reservation.getHouse();
|
||||
%>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="${pageContext.request.contextPath}/user/house/detail?id=<%= house.getId() %>" class="house-link">
|
||||
<strong><%= house.getTitle() %></strong>
|
||||
</a><br>
|
||||
<span style="font-size:12px;color:#999;"><%= house.getArea() %> | ¥<%= house.getRentPrice() %>/月</span>
|
||||
</td>
|
||||
<td><%= sdf.format(reservation.getReserveTime()) %></td>
|
||||
<td>
|
||||
<span class="status-badge status-<%= reservation.getStatus().equals("0") ? "pending" : reservation.getStatus().equals("1") ? "confirmed" : reservation.getStatus().equals("2") ? "cancelled" : "completed" %>">
|
||||
<%= reservation.getStatusText() %>
|
||||
</span>
|
||||
</td>
|
||||
<td style="max-width:200px; overflow:hidden; text-overflow:ellipsis;">
|
||||
<%= reservation.getRemark() != null ? reservation.getRemark() : "-" %>
|
||||
</td>
|
||||
<td>
|
||||
<% if ("0".equals(reservation.getStatus())) { %>
|
||||
<a href="${pageContext.request.contextPath}/user/reservation/cancel?id=<%= reservation.getId() %>"
|
||||
class="btn btn-danger"
|
||||
onclick="return confirm('确定要取消这个预约吗?')">取消</a>
|
||||
<% } else { %>
|
||||
<span class="btn btn-disabled">已处理</span>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</tbody>
|
||||
</table>
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
<div class="empty-state">
|
||||
<div style="font-size: 64px;">📅</div>
|
||||
<p>还没有任何预约记录</p>
|
||||
<p><a href="${pageContext.request.contextPath}/user/house/list">去浏览房源 >></a></p>
|
||||
</div>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2026 租房系统 | 让租房更简单</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user