feat(ui): 更新页面标题和样式,增强移动端体验

refactor: 优化套餐管理页面布局和交互效果
This commit is contained in:
2025-12-06 02:45:16 +08:00
parent bb3ebffb37
commit ae3ed1e58f
5 changed files with 540 additions and 240 deletions
+1 -1
View File
@@ -274,7 +274,7 @@ try {
<body>
<div class="container">
<header class="header">
<h1>🚗 洗车店管理系统</h1>
<h1>🚗 洗车预约系统 - 今日待办</h1>
<nav class="nav">
<a href="index.php" class="nav-link">预约洗车</a>
<a href="bookings.php" class="nav-link">预约管理</a>
+2 -2
View File
@@ -199,7 +199,7 @@ $packages_json = json_encode(array_map(function($package) {
<meta name="description" content="洗车预约系统 - 在线预约洗车服务">
<meta name="keywords" content="洗车,预约,在线预约,汽车美容">
<link rel="apple-touch-icon" href="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyIiBoZWlnaHQ9IjE5MiIgdmlld0JveD0iMCAwIDE5MiAxOTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxOTIiIGhlaWdodD0iMTkyIiByeD0iMjQiIGZpbGw9IiMzMDk1RjQiLz4KPHN2ZyB4PSI0OCIgeT0iNDgiIHdpZHRoPSI5NiIgaGVpZ2h0PSI5NiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+CjxwYXRoIGQ9Ik0yMS4yIDQuNEMyMS42IDMuNiAyMi4xIDMuMSAyMi41IDIuN0MyMy40IDIuMSAyNC41IDIuMSAyNS4yIDIuN0MyNS44IDMuMSAyNi4zIDMuNiAyNi43IDQuNEMyNy4xIDUuMSAyNy4xIDYuMiAyNi43IDcuMUMyNi4zIDcuOCAyNS44IDguMyAyNS4yIDguN0MyNC43IDkuMSAyMy42IDkuMSAyMi45IDguN0MyMi4zIDguMyAyMS44IDcuOCAyMS40IDcuMUMyMS4wIDYuMiAyMS4wIDUuMSAyMS4yIDQuNFoiLz4KPHN2ZyB4PSIyMCIgeT0iMTIiIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJ3aGl0ZSI+CjxwYXRoIGQ9Ik0yMSAyMy41QzIwLjUgMjMuNSAyMCAyMyAyMCAyMi41VjEyQzIwIDExLjUgMjAuNSAxMSAyMSAxMUg5QzguNSAxMSAxMi41IDEwLjUgMTIgMTBIMjBWMTBCMjAgMTAuNSAyMC41IDExIDIxIDExVjIzLjVaIi8+CjxwYXRoIGQ9Ik0xOCAyMFYxN0gxNFY4SDVWMTNIMTlWMTVIMTlWMjBaIi8+CjxwYXRoIGQ9Ik04IDEwSDVWN0g4VjEwWiIvPgo8L3N2Zz4KPC9zdmc+">
<title>洗车预约系统</title>
<title>张老师撸车(私家车库)工作室</title>
<link rel="stylesheet" href="style.css">
<style>
@@ -311,7 +311,7 @@ $packages_json = json_encode(array_map(function($package) {
<body>
<div class="container">
<header class="header">
<h1>🚗 洗车预约系统</h1>
<h1>🚗 张老师撸车(私家车库)工作室预约系统</h1>
<nav class="nav">
<a href="index.php" class="nav-link active">预约洗车</a>
<a href="bookings.php" class="nav-link">预约管理</a>
+71 -74
View File
@@ -55,43 +55,19 @@ $packages = $stmt->fetchAll();
<title>套餐管理 - 洗车预约系统</title>
<link rel="stylesheet" href="style.css">
<style>
/* 套餐管理页面特定样式 - 与pending_bookings.php保持一致 */
/* 套餐管理页面特定样式 */
.pending-bookings-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.package-form-container {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 20px;
padding: 20px;
}
/* 加载动画 */
.loading { display: none; }
.packages-list {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 20px;
padding: 20px;
}
.packages-list h2 {
margin-top: 0;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
color: #2c3e50;
}
.package-form-container h2 {
margin-top: 0;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
color: #2c3e50;
/* 页面淡入效果 */
body {
animation: fadeIn 0.5s ease;
}
</style>
</head>
@@ -117,55 +93,61 @@ $packages = $stmt->fetchAll();
<?php endif; ?>
<div class="package-form-container">
<h2>添加新套餐</h2>
<form method="POST">
<h2>📋 添加新套餐</h2>
<form method="POST" class="package-form">
<input type="hidden" name="action" value="add">
<div class="form-group">
<label for="package_name">套餐名称</label>
<input type="text" id="package_name" name="package_name" required placeholder="请输入套餐名称">
<label for="package_name" class="required">套餐名称</label>
<input type="text" id="package_name" name="package_name" required placeholder="请输入套餐名称(如:标准洗车套餐)" class="form-control">
</div>
<div class="form-group">
<label for="description">套餐描述</label>
<textarea id="description" name="description" rows="3" placeholder="请输入套餐描述"></textarea>
<label for="description">套餐描述</label>
<textarea id="description" name="description" rows="3" placeholder="请详细描述套餐内容和特点" class="form-control"></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label for="base_duration">基础时长(分钟):</label>
<input type="number" id="base_duration" name="base_duration" min="15" step="15" value="60" required>
<label for="base_duration" class="required">基础时长</label>
<div class="input-group">
<input type="number" id="base_duration" name="base_duration" min="15" step="15" value="60" required class="form-control">
<span class="input-group-addon">分钟</span>
</div>
</div>
<div class="form-group">
<label for="price">价格(元):</label>
<input type="number" id="price" name="price" min="0" step="0.01" required placeholder="请输入套餐价格">
<label for="price" class="required">价格</label>
<div class="input-group">
<span class="input-group-addon">¥</span>
<input type="number" id="price" name="price" min="0" step="0.01" required placeholder="0.00" class="form-control">
</div>
</div>
</div>
<div class="form-group">
<label>服务项目</label>
<label>服务项目</label>
<div class="services-container">
<div class="service-item">
<input type="text" name="services[]" placeholder="服务项目1" value="外观清洗">
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)">删除</button>
<input type="text" name="services[]" placeholder="请输入服务项目(如:外观清洗)" value="外观清洗" class="form-control">
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)"><span>删除</span></button>
</div>
<div class="service-item">
<input type="text" name="services[]" placeholder="服务项目2" value="内饰清洁">
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)">删除</button>
<input type="text" name="services[]" placeholder="请输入服务项目(如:内饰清洁)" value="内饰清洁" class="form-control">
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)"><span>删除</span></button>
</div>
</div>
<button type="button" class="btn-outline btn-sm" onclick="addService()">+ 添加服务项目</button>
<button type="button" class="btn-outline btn-sm" onclick="addService()"><span>+ 添加服务项目</span></button>
</div>
<div class="form-actions">
<button type="submit" class="btn-primary btn-lg">添加套餐</button>
<button type="submit" class="btn-primary btn-lg"><span>✨ 添加套餐</span></button>
</div>
</form>
</div>
<div class="packages-list">
<h2>套餐列表</h2>
<h2>📊 套餐列表</h2>
<?php if (empty($packages)): ?>
<div class="empty-state">
<div class="empty-icon">📦</div>
@@ -175,8 +157,8 @@ $packages = $stmt->fetchAll();
<?php else: ?>
<div class="packages-grid">
<?php foreach ($packages as $package): ?>
<div class="package-card pending-card <?= $package['is_active'] ? '' : 'inactive' ?>">
<div class="package-header pending-header">
<div class="package-card <?= $package['is_active'] ? '' : 'inactive' ?>" data-package-id="<?= $package['id'] ?>">
<div class="package-header">
<h3 class="package-title"><?= htmlspecialchars($package['package_name']) ?></h3>
<div class="package-status">
<span class="status-badge <?= $package['is_active'] ? 'active' : 'inactive' ?>">
@@ -189,14 +171,14 @@ $packages = $stmt->fetchAll();
<p class="package-description"><?= htmlspecialchars($package['description']) ?></p>
<?php endif; ?>
<div class="package-details detail-grid">
<div class="package-details">
<div class="detail-item">
<span class="detail-label">基础时长</span>
<span class="detail-label">时长</span>
<span class="detail-value"><strong><?= $package['base_duration'] ?></strong>分钟</span>
</div>
<div class="detail-item">
<span class="detail-label">价格</span>
<span class="detail-value price"><strong><?= number_format($package['price'], 2) ?></strong></span>
<span class="detail-label">价格</span>
<span class="detail-value price"><strong>¥<?= number_format($package['price'], 2) ?></strong></span>
</div>
</div>
@@ -205,7 +187,7 @@ $packages = $stmt->fetchAll();
if ($services && !empty(trim($services[0]))):
?>
<div class="package-services">
<span class="detail-label">包含服务</span>
<span class="detail-label">包含服务</span>
<div class="services-tags">
<?php foreach ($services as $service): ?>
<?php if (trim($service)): ?>
@@ -217,11 +199,11 @@ $packages = $stmt->fetchAll();
<?php endif; ?>
<div class="package-actions">
<button class="btn-primary btn-sm" onclick="editPackage(<?= $package['id'] ?>)">编辑</button>
<button class="btn-primary btn-sm" onclick="editPackage(<?= $package['id'] ?>)"><span>✏️ 编辑</span></button>
<form method="POST" style="display: inline;" onsubmit="return confirmDelete()">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $package['id'] ?>">
<button type="submit" class="btn-danger btn-sm">删除</button>
<button type="submit" class="btn-danger btn-sm"><span>🗑️ 删除</span></button>
</form>
</div>
@@ -230,32 +212,38 @@ $packages = $stmt->fetchAll();
<input type="hidden" name="action" value="update">
<input type="hidden" name="id" value="<?= $package['id'] ?>">
<h4>编辑套餐</h4>
<h4>✏️ 编辑套餐</h4>
<div class="form-group">
<label>套餐名称</label>
<input type="text" name="package_name" value="<?= htmlspecialchars($package['package_name']) ?>" required placeholder="请输入套餐名称">
<label class="required">套餐名称</label>
<input type="text" name="package_name" value="<?= htmlspecialchars($package['package_name']) ?>" required placeholder="请输入套餐名称" class="form-control">
</div>
<div class="form-group">
<label>套餐描述</label>
<textarea name="description" rows="2" placeholder="请输入套餐描述"><?= htmlspecialchars($package['description']) ?></textarea>
<label>套餐描述</label>
<textarea name="description" rows="2" placeholder="请输入套餐描述" class="form-control"><?= htmlspecialchars($package['description']) ?></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label>基础时长(分钟):</label>
<input type="number" name="base_duration" min="15" step="15" value="<?= $package['base_duration'] ?>" required>
<label class="required">基础时长</label>
<div class="input-group">
<input type="number" name="base_duration" min="15" step="15" value="<?= $package['base_duration'] ?>" required class="form-control">
<span class="input-group-addon">分钟</span>
</div>
</div>
<div class="form-group">
<label>价格(元):</label>
<input type="number" name="price" min="0" step="0.01" value="<?= $package['price'] ?>" required placeholder="请输入套餐价格">
<label class="required">价格</label>
<div class="input-group">
<span class="input-group-addon">¥</span>
<input type="number" name="price" min="0" step="0.01" value="<?= $package['price'] ?>" required placeholder="0.00" class="form-control">
</div>
</div>
</div>
<div class="form-group">
<label>服务项目</label>
<label>服务项目</label>
<div class="services-container">
<?php
$services = explode(',', $package['services']);
@@ -263,15 +251,15 @@ $packages = $stmt->fetchAll();
if (trim($service)):
?>
<div class="service-item">
<input type="text" name="services[]" value="<?= htmlspecialchars(trim($service)) ?>">
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)">删除</button>
<input type="text" name="services[]" value="<?= htmlspecialchars(trim($service)) ?>" placeholder="请输入服务项目" class="form-control">
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)"><span>删除</span></button>
</div>
<?php
endif;
endforeach;
?>
</div>
<button type="button" class="btn-outline btn-sm" onclick="addService()">+ 添加服务项目</button>
<button type="button" class="btn-outline btn-sm" onclick="addService()"><span>+ 添加服务项目</span></button>
</div>
<div class="form-group">
@@ -282,8 +270,8 @@ $packages = $stmt->fetchAll();
</div>
<div class="form-actions">
<button type="submit" class="btn-primary">保存更改</button>
<button type="button" class="btn-outline" onclick="cancelEdit(<?= $package['id'] ?>)">取消</button>
<button type="submit" class="btn-primary"><span>💾 保存更改</span></button>
<button type="button" class="btn-outline" onclick="cancelEdit(<?= $package['id'] ?>)"><span>❌ 取消</span></button>
</div>
</form>
</div>
@@ -298,9 +286,18 @@ $packages = $stmt->fetchAll();
const container = document.querySelector('.services-container');
const serviceItem = document.createElement('div');
serviceItem.className = 'service-item';
serviceItem.style.display = 'flex';
serviceItem.style.gap = 'var(--el-spacing-base)';
serviceItem.style.marginBottom = 'var(--el-spacing-base)';
serviceItem.style.alignItems = 'flex-end';
serviceItem.innerHTML = `
<input type="text" name="services[]" placeholder="服务项目">
<button type="button" class="btn-remove" onclick="removeService(this)">删除</button>
<div style="flex: 1;">
<input type="text" name="service_names[]" placeholder="请输入服务名称" class="form-control" required>
</div>
<div style="flex: 0 0 120px;">
<input type="number" name="service_prices[]" placeholder="价格 (¥)" step="0.01" class="form-control" required>
</div>
<button type="button" class="btn-danger btn-sm" onclick="removeService(this)"><span>删除</span></button>
`;
container.appendChild(serviceItem);
}
+2 -2
View File
@@ -517,11 +517,11 @@ try {
<body>
<div class="pending-bookings-container">
<header class="header">
<h1>🚗 洗车预约系统 - 待预约处理</h1>
<h1>🚗 洗车预约系统 - 待处理预约</h1>
<nav class="nav">
<a href="index.php" class="nav-link">预约洗车</a>
<a href="bookings.php" class="nav-link">预约管理</a>
<a href="pending_bookings.php" class="nav-link active">待预约处理</a>
<a href="pending_bookings.php" class="nav-link active">待处理预约</a>
<a href="packages.php" class="nav-link">套餐管理</a>
<a href="vip.php" class="nav-link">VIP管理</a>
<a href="announcement.php" class="nav-link">今日待办</a>
+464 -161
View File
@@ -878,6 +878,85 @@ body {
margin: 0;
max-height: calc(100vh - 20px);
}
/* 套餐管理页面移动端优化 */
.pending-bookings-container {
padding: var(--el-spacing-small);
}
.pending-card {
padding: var(--el-spacing-base);
}
.pending-header h2 {
font-size: var(--el-font-size-large);
}
.package-card {
padding: var(--el-spacing-base);
margin-bottom: var(--el-spacing-base);
}
.package-header {
flex-direction: column;
align-items: flex-start;
gap: var(--el-spacing-small);
}
.package-details {
grid-template-columns: 1fr;
gap: var(--el-spacing-small);
}
.services-tags {
justify-content: flex-start;
gap: var(--el-spacing-small);
}
.service-tag {
font-size: var(--el-font-size-small);
padding: 3px 6px;
}
.package-actions {
flex-direction: column;
gap: var(--el-spacing-small);
}
/* 服务项目移动端布局 */
.service-item {
flex-direction: column;
align-items: stretch !important;
gap: var(--el-spacing-small) !important;
}
.service-item div {
flex: none !important;
}
/* 表单移动端优化 */
.form-group {
margin-bottom: var(--el-spacing-base);
}
.form-control {
padding: 14px 16px;
font-size: 16px; /* 防止iOS缩放 */
}
.input-group {
flex-direction: column;
}
.input-group .form-control {
border-radius: var(--el-border-radius-base);
margin-bottom: var(--el-spacing-small);
}
.input-group .btn {
border-radius: var(--el-border-radius-base);
width: 100%;
}
}
/* 小屏幕手机 */
@@ -963,6 +1042,171 @@ body {
to { transform: translateX(0); }
}
/* 页面加载动画 */
.page-fade-in {
animation: pageFadeIn 0.6s ease-out;
}
@keyframes pageFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* 套餐卡片入场动画 */
.package-card {
animation: cardFadeIn 0.4s ease-out forwards;
opacity: 0;
transform: translateY(20px);
}
@keyframes cardFadeIn {
to {
opacity: 1;
transform: translateY(0);
}
}
/* 卡片延迟动画,为每个卡片添加不同的延迟 */
.package-card:nth-child(1) { animation-delay: 0.1s; }
.package-card:nth-child(2) { animation-delay: 0.2s; }
.package-card:nth-child(3) { animation-delay: 0.3s; }
.package-card:nth-child(4) { animation-delay: 0.4s; }
.package-card:nth-child(5) { animation-delay: 0.5s; }
.package-card:nth-child(6) { animation-delay: 0.6s; }
/* 按钮波纹效果 */
.btn {
position: relative;
overflow: hidden;
}
.btn::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:hover::after {
width: 300px;
height: 300px;
}
.btn-primary::after {
background: rgba(255, 255, 255, 0.5);
}
/* 表单元素动画 */
.form-control {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 服务标签悬停动画 */
.service-tag {
transition: all 0.3s ease;
}
.service-tag:hover {
transform: translateY(-2px);
box-shadow: var(--el-shadow-light);
}
/* 状态徽章动画 */
.status-badge {
transition: all 0.3s ease;
}
/* 空状态动画 */
.empty-message {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
opacity: 0.8;
}
50% {
opacity: 1;
}
100% {
opacity: 0.8;
}
}
/* 表单基础样式 */
.form-control {
width: 100%;
padding: 12px 16px;
border: 1px solid var(--el-border-color);
border-radius: var(--el-border-radius-base);
font-size: var(--el-font-size-base);
color: var(--el-text-primary);
background-color: var(--el-bg-color);
transition: all 0.3s ease;
outline: none;
box-sizing: border-box;
}
.form-control:focus {
border-color: var(--el-primary-color);
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
.form-control:hover:not(:disabled) {
border-color: var(--el-primary-light);
}
.form-control:disabled {
background-color: var(--el-bg-color-page);
opacity: 0.7;
cursor: not-allowed;
}
/* 表单组样式 */
.form-group {
margin-bottom: var(--el-spacing-large);
}
.form-group label {
display: block;
margin-bottom: var(--el-spacing-small);
font-weight: 500;
color: var(--el-text-primary);
font-size: var(--el-font-size-base);
}
.form-group label.required::after {
content: " *";
color: var(--el-danger-color);
}
/* 输入组样式 */
.input-group {
display: flex;
align-items: stretch;
width: 100%;
gap: var(--el-spacing-small);
}
.input-group .form-control {
flex: 1;
margin-bottom: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group .btn {
flex: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* 表单操作区域 */
.form-actions {
display: flex;
@@ -1128,151 +1372,13 @@ label {
background: #999;
}
/* 套餐管理页面样式 */
.package-card {
transition: all 0.3s ease;
margin-bottom: 20px;
}
.package-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.package-card.inactive {
opacity: 0.7;
}
.package-card.inactive .package-title {
text-decoration: line-through;
}
.package-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.package-title {
font-size: 1.2rem;
margin: 0;
color: #2c3e50;
}
.package-description {
color: #666;
margin-bottom: 15px;
line-height: 1.5;
}
.package-details {
margin-bottom: 15px;
}
.package-actions {
display: flex;
gap: 10px;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #eee;
}
.package-services {
margin-top: 15px;
}
.services-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
}
.service-tag {
background: #f5f5f5;
color: #666;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.85rem;
border: 1px solid #eee;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #999;
}
.empty-icon {
font-size: 3rem;
margin-bottom: 15px;
}
.empty-message {
font-size: 1.2rem;
margin-bottom: 5px;
color: #666;
}
.empty-submessage {
font-size: 0.9rem;
}
/* 表单样式 */
.form-row {
display: flex;
gap: 20px;
margin-bottom: 15px;
}
.form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.services-container {
margin-bottom: 15px;
}
.service-item {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
.service-item input {
flex: 1;
}
/* 响应式设计 */
@media (max-width: 768px) {
.form-row {
flex-direction: column;
}
.packages-grid {
grid-template-columns: 1fr;
}
.package-actions {
flex-direction: column;
}
.package-actions button {
width: 100%;
}
}
.packages-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 20px;
}
/* 套餐管理页面样式 */
.package-form-container {
margin-bottom: var(--el-spacing-extra-large);
background: var(--el-bg-color);
border-radius: var(--el-border-radius-base);
box-shadow: var(--el-shadow-light);
padding: var(--el-spacing-large);
}
.package-form-container h2,
@@ -1285,6 +1391,13 @@ label {
border-bottom: 1px solid var(--el-border-lighter);
}
.packages-list {
background: var(--el-bg-color);
border-radius: var(--el-border-radius-base);
box-shadow: var(--el-shadow-light);
padding: var(--el-spacing-large);
}
/* 套餐卡片网格布局 */
.packages-grid {
display: grid;
@@ -1295,14 +1408,41 @@ label {
/* 套餐卡片样式 */
.package-card {
transition: all 0.3s ease;
background: var(--el-bg-color);
border-radius: 12px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
padding: var(--el-spacing-large);
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
border: 2px solid transparent;
background-clip: padding-box;
}
/* 渐变边框效果 */
.package-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, var(--el-primary-color), var(--el-success-color), var(--el-info-color));
border-radius: 12px;
z-index: -1;
margin: -2px;
opacity: 0;
transition: opacity 0.35s ease;
}
.package-card:hover {
transform: translateY(-4px);
box-shadow: var(--el-shadow-dark);
transform: translateY(-6px);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
border-color: transparent;
}
.package-card:hover::before {
opacity: 1;
}
.package-card.inactive {
@@ -1319,9 +1459,11 @@ label {
color: white;
padding: 4px 32px;
font-size: 12px;
font-weight: 500;
font-weight: 600;
transform: rotate(45deg);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1;
letter-spacing: 0.5px;
}
.package-header {
@@ -1329,15 +1471,38 @@ label {
justify-content: space-between;
align-items: flex-start;
margin-bottom: var(--el-spacing-base);
padding-bottom: var(--el-spacing-small);
border-bottom: 2px solid var(--el-border-color-lighter);
position: relative;
z-index: 2;
}
.package-title {
margin: 0;
font-size: var(--el-font-size-large);
font-weight: 600;
font-size: 1.35rem;
font-weight: 700;
color: var(--el-text-primary);
flex: 1;
margin-right: var(--el-spacing-base);
line-height: 1.4;
position: relative;
display: inline-block;
}
/* 标题悬停下划线动画 */
.package-title::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: var(--el-primary-color);
transition: width 0.3s ease;
}
.package-card:hover .package-title::after {
width: 100%;
}
.package-status {
@@ -1346,36 +1511,66 @@ label {
}
.status-badge {
padding: 4px 8px;
padding: 4px 12px;
border-radius: var(--el-border-radius-round);
font-size: var(--el-font-size-extra-small);
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
}
.status-badge.active {
background: rgba(103, 194, 58, 0.1);
color: var(--el-success-color);
border: 1px solid rgba(103, 194, 58, 0.2);
}
.status-badge.inactive {
background: rgba(245, 108, 108, 0.1);
color: var(--el-danger-color);
border: 1px solid rgba(245, 108, 108, 0.2);
}
.package-description {
margin: 0 0 var(--el-spacing-base) 0;
color: var(--el-text-secondary);
font-size: var(--el-font-size-small);
line-height: 1.5;
line-height: 1.6;
padding: 0 var(--el-spacing-small);
}
.package-details {
margin: var(--el-spacing-base) 0;
padding: var(--el-spacing-base);
background: var(--el-bg-color-page);
border-radius: var(--el-border-radius-base);
padding: var(--el-spacing-large);
background: linear-gradient(135deg, rgba(246, 248, 250, 0.8), rgba(238, 242, 246, 0.8));
border-radius: 10px;
border: 1px solid var(--el-border-color-lighter);
position: relative;
overflow: hidden;
transition: all 0.3s ease;
}
/* 详情区域悬停效果 */
.package-card:hover .package-details {
background: linear-gradient(135deg, rgba(240, 244, 248, 0.9), rgba(228, 232, 236, 0.9));
transform: scale(1.02);
}
/* 渐变光效 */
.package-details::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.4), transparent);
transition: left 0.6s ease;
}
.package-card:hover .package-details::before {
left: 100%;
}
.detail-item {
@@ -1393,6 +1588,7 @@ label {
.detail-label {
color: var(--el-text-secondary);
font-weight: 500;
font-size: var(--el-font-size-extra-small);
}
.detail-value {
@@ -1414,6 +1610,8 @@ label {
display: block;
margin-bottom: var(--el-spacing-small);
font-size: var(--el-font-size-small);
color: var(--el-text-regular);
font-weight: 500;
}
.services-tags {
@@ -1425,18 +1623,40 @@ label {
.service-tag {
background: var(--el-border-extra-light);
color: var(--el-text-regular);
padding: 4px 12px;
border-radius: var(--el-border-radius-round);
padding: 6px 16px;
border-radius: 20px;
font-size: var(--el-font-size-extra-small);
font-weight: 500;
font-weight: 600;
border: 1px solid var(--el-border-lighter);
transition: all 0.3s ease;
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1);
line-height: 1.5;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
position: relative;
overflow: hidden;
}
.service-tag:hover {
background: var(--el-primary-light);
color: var(--el-primary-color);
border-color: var(--el-primary-light);
background: var(--el-primary-color);
color: white;
border-color: var(--el-primary-color);
transform: translateY(-2px) scale(1.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 服务标签悬停光效 */
.service-tag::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
transition: left 0.4s ease;
}
.service-tag:hover::before {
left: 100%;
}
/* 套餐操作按钮 */
@@ -1445,6 +1665,8 @@ label {
display: flex;
gap: var(--el-spacing-small);
justify-content: flex-end;
padding-top: var(--el-spacing-base);
border-top: 1px solid var(--el-border-lighter);
}
/* 空状态样式 */
@@ -1458,9 +1680,17 @@ label {
}
.empty-icon {
font-size: 48px;
font-size: 64px;
margin-bottom: var(--el-spacing-base);
opacity: 0.5;
filter: grayscale(100%);
transition: all 0.3s ease;
}
.empty-state:hover .empty-icon {
opacity: 0.8;
filter: grayscale(0%);
transform: scale(1.05);
}
.empty-message {
@@ -1513,6 +1743,7 @@ label {
align-items: center;
cursor: pointer;
user-select: none;
margin-bottom: var(--el-spacing-small);
}
.checkbox-text {
@@ -1532,10 +1763,22 @@ label {
}
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.packages-grid {
grid-template-columns: 1fr;
gap: var(--el-spacing-base);
}
.package-header {
@@ -1545,6 +1788,7 @@ label {
.package-status {
margin-top: var(--el-spacing-small);
align-self: flex-start;
}
.form-row {
@@ -1554,4 +1798,63 @@ label {
.form-row .form-group {
width: 100%;
}
.package-actions {
flex-direction: column;
gap: var(--el-spacing-base);
}
.package-actions button {
width: 100%;
}
.package-form-container,
.packages-list {
padding: var(--el-spacing-base);
}
.package-card {
padding: var(--el-spacing-base);
}
}
/* 表单样式增强 */
.form-row {
display: flex;
gap: 20px;
margin-bottom: var(--el-spacing-large);
}
.form-row .form-group {
flex: 1;
margin-bottom: 0;
}
/* 按钮悬停效果增强 */
.btn {
position: relative;
overflow: hidden;
}
.btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:hover::before {
width: 300px;
height: 300px;
}
.btn span {
position: relative;
z-index: 1;
}