重写会员端,初步完善首页
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
unpackage/
|
||||||
|
.hbuilderx/
|
||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
onLaunch: function() {
|
||||||
|
console.log('App Launch')
|
||||||
|
},
|
||||||
|
onShow: function() {
|
||||||
|
console.log('App Show')
|
||||||
|
},
|
||||||
|
onHide: function() {
|
||||||
|
console.log('App Hide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
page {
|
||||||
|
background: #F5F7FA;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
color: #1E1E1E;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
view, text, button, input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,624 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||||
|
<title>健身房预约 · 配色方案展示</title>
|
||||||
|
<!-- 使用 Inter 字体,现代感更强 -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
/* ===== CSS Variables (核心色板) ===== */
|
||||||
|
:root {
|
||||||
|
--primary: #00E676;
|
||||||
|
--primary-dark: #00C853;
|
||||||
|
--primary-light: rgba(0, 230, 118, 0.15);
|
||||||
|
--secondary: #1A1A1A;
|
||||||
|
--background: #F5F7FA;
|
||||||
|
--text-primary: #1E1E1E;
|
||||||
|
--text-secondary: #7A7E84;
|
||||||
|
--highlight: #FF5252;
|
||||||
|
--white: #FFFFFF;
|
||||||
|
--shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
--radius: 20px;
|
||||||
|
--radius-sm: 12px;
|
||||||
|
--tab-height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 手机卡片容器 ===== */
|
||||||
|
.phone-mock {
|
||||||
|
max-width: 375px;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--background);
|
||||||
|
border-radius: 40px;
|
||||||
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 状态栏 (模拟) ===== */
|
||||||
|
.status-bar {
|
||||||
|
background: var(--secondary);
|
||||||
|
padding: 12px 20px 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: rgba(255,255,255,0.7);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
.status-bar span:last-child {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 导航栏 (深色) ===== */
|
||||||
|
.nav-bar {
|
||||||
|
background: var(--secondary);
|
||||||
|
padding: 8px 20px 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.nav-bar .title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.nav-bar .actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.nav-bar .actions .badge {
|
||||||
|
position: relative;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.nav-bar .actions .badge::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -2px;
|
||||||
|
right: -4px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: var(--highlight);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid var(--secondary);
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: var(--primary);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 主内容 ===== */
|
||||||
|
.content {
|
||||||
|
padding: 20px 16px 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 欢迎卡片 + 数据 */
|
||||||
|
.greeting-card {
|
||||||
|
background: var(--secondary);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 18px 20px 20px;
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.greeting-card .row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.greeting-card .name {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.greeting-card .badge-energy {
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--secondary);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 40px;
|
||||||
|
}
|
||||||
|
.greeting-card .stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item .number {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item .label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255,255,255,0.6);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 快速分类标签 */
|
||||||
|
.category-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.category-tabs::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.category-tabs .tab {
|
||||||
|
background: white;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
white-space: nowrap;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
transition: all 0.2s;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.category-tabs .tab.active {
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--secondary);
|
||||||
|
font-weight: 600;
|
||||||
|
border-color: var(--primary);
|
||||||
|
}
|
||||||
|
.category-tabs .tab:not(.active):hover {
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 课程卡片 ===== */
|
||||||
|
.course-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
transition: transform 0.1s ease;
|
||||||
|
}
|
||||||
|
.course-card .icon-placeholder {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
background: var(--primary-light);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
.course-card .info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.course-card .info .title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
.course-card .info .meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.course-card .info .meta .tag {
|
||||||
|
background: var(--primary-light);
|
||||||
|
color: var(--primary-dark);
|
||||||
|
padding: 2px 10px;
|
||||||
|
border-radius: 30px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.course-card .btn-book {
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--secondary);
|
||||||
|
border: none;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 40px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: default;
|
||||||
|
transition: background 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 230, 118, 0.3);
|
||||||
|
}
|
||||||
|
.course-card .btn-book.disabled {
|
||||||
|
background: #E0E0E0;
|
||||||
|
color: #BDBDBD;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 日期选择器 (模拟) */
|
||||||
|
.date-selector {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.date-item {
|
||||||
|
flex: 1;
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
transition: all 0.1s;
|
||||||
|
}
|
||||||
|
.date-item .day {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.date-item .week {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.date-item.active {
|
||||||
|
border-color: var(--primary);
|
||||||
|
background: var(--primary-light);
|
||||||
|
color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
.date-item.active .day {
|
||||||
|
color: var(--primary-dark);
|
||||||
|
}
|
||||||
|
.date-item.disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部 TabBar (深色) */
|
||||||
|
.tab-bar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: var(--secondary);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0 18px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.06);
|
||||||
|
height: var(--tab-height);
|
||||||
|
}
|
||||||
|
.tab-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.15s;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.tab-item .icon {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.tab-item.active {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.tab-item.active .icon {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
/* 中间大按钮 (预约) */
|
||||||
|
.tab-item.cta-tab {
|
||||||
|
position: relative;
|
||||||
|
top: -12px;
|
||||||
|
}
|
||||||
|
.tab-item.cta-tab .icon {
|
||||||
|
background: var(--primary);
|
||||||
|
color: var(--secondary);
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 230, 118, 0.4);
|
||||||
|
}
|
||||||
|
.tab-item.cta-tab.active .icon {
|
||||||
|
background: var(--primary-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 个人中心预览 (第二屏简易) ===== */
|
||||||
|
.profile-preview {
|
||||||
|
margin-top: 12px;
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.profile-preview .row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.profile-preview .row .big-avatar {
|
||||||
|
width: 52px;
|
||||||
|
height: 52px;
|
||||||
|
background: linear-gradient(135deg, var(--primary), #00BFA5);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 22px;
|
||||||
|
color: var(--secondary);
|
||||||
|
}
|
||||||
|
.profile-preview .row .info h4 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.profile-preview .row .info p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item {
|
||||||
|
background: var(--background);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item .emoji {
|
||||||
|
display: block;
|
||||||
|
font-size: 22px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item:first-child {
|
||||||
|
color: var(--primary-dark);
|
||||||
|
background: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 辅助文案 */
|
||||||
|
.footnote {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 18px;
|
||||||
|
opacity: 0.7;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 模拟分割线 */
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #EEEEEE;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式微调 */
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.phone-mock {
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
|
.nav-bar .title {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-mock">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="status-bar">
|
||||||
|
<span>9:41</span>
|
||||||
|
<span>📶 📶 🔋</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 导航栏 (深色) -->
|
||||||
|
<div class="nav-bar">
|
||||||
|
<div class="title">💪 今日训练</div>
|
||||||
|
<div class="actions">
|
||||||
|
<span class="badge">🔔</span>
|
||||||
|
<div class="avatar">J</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主要内容 -->
|
||||||
|
<div class="content">
|
||||||
|
|
||||||
|
<!-- 欢迎卡片 + 数据 (深色背景) -->
|
||||||
|
<div class="greeting-card">
|
||||||
|
<div class="row">
|
||||||
|
<span class="name">👋 你好,Jason</span>
|
||||||
|
<span class="badge-energy">🔥 今日 420 kcal</span>
|
||||||
|
</div>
|
||||||
|
<div class="stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">68</span>
|
||||||
|
<span class="label">总课时</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">12</span>
|
||||||
|
<span class="label">连续打卡</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">4.8</span>
|
||||||
|
<span class="label">⭐ 评分</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分类标签 (active 使用主色) -->
|
||||||
|
<div class="category-tabs">
|
||||||
|
<span class="tab active">全部</span>
|
||||||
|
<span class="tab">力量区</span>
|
||||||
|
<span class="tab">有氧</span>
|
||||||
|
<span class="tab">瑜伽</span>
|
||||||
|
<span class="tab">私教</span>
|
||||||
|
<span class="tab">团课</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 日期选择器 (模拟) -->
|
||||||
|
<div class="date-selector">
|
||||||
|
<div class="date-item disabled">
|
||||||
|
<span class="day">12</span>
|
||||||
|
<span class="week">周日</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">13</span>
|
||||||
|
<span class="week">周一</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item active">
|
||||||
|
<span class="day">14</span>
|
||||||
|
<span class="week">周二</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">15</span>
|
||||||
|
<span class="week">周三</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">16</span>
|
||||||
|
<span class="week">周四</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 1 (可预约) -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🏋️</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">综合力量训练</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 45 min</span>
|
||||||
|
<span class="tag">🔥 热门</span>
|
||||||
|
<span>📍 力量区</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book">预约</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 2 (已约满) -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🧘</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">流瑜伽 · 中级</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 60 min</span>
|
||||||
|
<span class="tag">🧘 瑜伽</span>
|
||||||
|
<span>📍 3号教室</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book disabled">已约满</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 3 (可预约) -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🚴</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">动感单车 · 冲刺</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 40 min</span>
|
||||||
|
<span class="tag">⚡ 有氧</span>
|
||||||
|
<span>📍 单车房</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book">预约</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 个人中心预览 (展示辅助色及卡片) -->
|
||||||
|
<div class="profile-preview">
|
||||||
|
<div class="row">
|
||||||
|
<div class="big-avatar">J</div>
|
||||||
|
<div class="info">
|
||||||
|
<h4>Jason Wang</h4>
|
||||||
|
<p>🏆 高级会员 · 已练 68 课时</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-grid">
|
||||||
|
<div class="menu-item"><span class="emoji">📊</span> 数据</div>
|
||||||
|
<div class="menu-item"><span class="emoji">🏅</span> 成就</div>
|
||||||
|
<div class="menu-item"><span class="emoji">⚙️</span> 设置</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footnote">配色方案 · 能量黑 + 荧光绿 · 预约小程序</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== 底部 TabBar (深色背景 + 主色激活) ===== -->
|
||||||
|
<div class="tab-bar">
|
||||||
|
<div class="tab-item active">
|
||||||
|
<span class="icon">🏠</span>
|
||||||
|
<span>首页</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">📅</span>
|
||||||
|
<span>课程</span>
|
||||||
|
</div>
|
||||||
|
<!-- 中间大按钮 (预约 CTA) -->
|
||||||
|
<div class="tab-item cta-tab active">
|
||||||
|
<span class="icon">➕</span>
|
||||||
|
<span>预约</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">💬</span>
|
||||||
|
<span>消息</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">👤</span>
|
||||||
|
<span>我的</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,590 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||||
|
<title>健身房预约 · 极光紫配色</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&display=swap" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
/* ==========================================================
|
||||||
|
配色方案:极光紫 (Aurora Purple)
|
||||||
|
主色:深邃紫罗兰 + 霓虹蓝紫渐变
|
||||||
|
性格:科技感、神秘、高级、时尚
|
||||||
|
========================================================== */
|
||||||
|
:root {
|
||||||
|
/* ----- 品牌主色 (Primary) ----- */
|
||||||
|
--primary: #7C3AED; /* 紫罗兰主色 */
|
||||||
|
--primary-dark: #5B21B6; /* 深紫按压态 */
|
||||||
|
--primary-light: rgba(124, 58, 237, 0.15); /* 浅紫背景 */
|
||||||
|
--primary-gradient: linear-gradient(135deg, #7C3AED, #4F46E5); /* 紫蓝渐变 */
|
||||||
|
|
||||||
|
/* ----- 中性色 (Neutral) ----- */
|
||||||
|
--bg-primary: #F8F7FC; /* 极浅灰紫背景 */
|
||||||
|
--bg-card: #FFFFFF; /* 卡片纯白 */
|
||||||
|
--text-primary: #1E1028; /* 深紫黑文字 */
|
||||||
|
--text-secondary: #6B5E7E; /* 紫灰辅助文字 */
|
||||||
|
--text-disabled: #B8AED0; /* 浅灰紫禁用 */
|
||||||
|
--border-light: #EDE9F5; /* 浅紫分割线 */
|
||||||
|
--shadow-card: 0 4px 16px rgba(94, 48, 176, 0.10);
|
||||||
|
|
||||||
|
/* ----- 功能色 (Functional) ----- */
|
||||||
|
--highlight: #EF4444; /* 红点/警告 */
|
||||||
|
--success: #10B981; /* 翠绿成功 */
|
||||||
|
--disabled-bg: #E8E3F0;
|
||||||
|
--disabled-text: #B8AED0;
|
||||||
|
|
||||||
|
/* ----- 尺寸 (Size) ----- */
|
||||||
|
--radius-large: 20px;
|
||||||
|
--radius-medium: 12px;
|
||||||
|
--radius-full: 40px;
|
||||||
|
--tab-height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局重置 */
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 手机容器 */
|
||||||
|
.phone-mock {
|
||||||
|
max-width: 375px;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: 40px;
|
||||||
|
box-shadow: 0 20px 60px rgba(94, 48, 176, 0.15);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid rgba(124, 58, 237, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态栏 */
|
||||||
|
.status-bar {
|
||||||
|
background: var(--text-primary);
|
||||||
|
padding: 12px 20px 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: rgba(255,255,255,0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.status-bar span:last-child { display: flex; gap: 6px; }
|
||||||
|
|
||||||
|
/* 导航栏 (深色渐变) */
|
||||||
|
.nav-bar {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
padding: 8px 20px 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.nav-bar .title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.3px;
|
||||||
|
}
|
||||||
|
.nav-bar .actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.nav-bar .actions .badge {
|
||||||
|
position: relative;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.nav-bar .actions .badge::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -2px;
|
||||||
|
right: -4px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: var(--highlight);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid var(--primary-dark);
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: rgba(255,255,255,0.25);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区 */
|
||||||
|
.content { padding: 20px 16px 100px; }
|
||||||
|
|
||||||
|
/* 欢迎卡片 (渐变) */
|
||||||
|
.greeting-card {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
padding: 18px 20px 20px;
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 6px 20px rgba(124, 58, 237, 0.25);
|
||||||
|
}
|
||||||
|
.greeting-card .row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.greeting-card .name { font-size: 18px; font-weight: 600; }
|
||||||
|
.greeting-card .badge-energy {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 14px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.greeting-card .stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item { display: flex; flex-direction: column; }
|
||||||
|
.greeting-card .stats .stat-item .number {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(255,255,255,0.95);
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item .label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255,255,255,0.7);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分类标签 */
|
||||||
|
.category-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.category-tabs::-webkit-scrollbar { display: none; }
|
||||||
|
.category-tabs .tab {
|
||||||
|
background: white;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
white-space: nowrap;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.category-tabs .tab.active {
|
||||||
|
background: var(--primary);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 4px 12px rgba(124, 58, 237, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 日期选择器 */
|
||||||
|
.date-selector {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.date-item {
|
||||||
|
flex: 1;
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-medium);
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
transition: all 0.1s;
|
||||||
|
}
|
||||||
|
.date-item .day {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.date-item .week { font-size: 12px; }
|
||||||
|
.date-item.active {
|
||||||
|
border-color: var(--primary);
|
||||||
|
background: var(--primary-light);
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.date-item.active .day { color: var(--primary-dark); }
|
||||||
|
.date-item.disabled { opacity: 0.35; }
|
||||||
|
|
||||||
|
/* 课程卡片 */
|
||||||
|
.course-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
.course-card .icon-placeholder {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: var(--radius-medium);
|
||||||
|
background: var(--primary-light);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.course-card .info { flex: 1; }
|
||||||
|
.course-card .info .title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
.course-card .info .meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.course-card .info .meta .tag {
|
||||||
|
background: var(--primary-light);
|
||||||
|
color: var(--primary-dark);
|
||||||
|
padding: 2px 12px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.course-card .btn-book {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 20px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: default;
|
||||||
|
box-shadow: 0 4px 12px rgba(124, 58, 237, 0.25);
|
||||||
|
transition: all 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.course-card .btn-book.disabled {
|
||||||
|
background: var(--disabled-bg);
|
||||||
|
color: var(--disabled-text);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 个人中心预览 */
|
||||||
|
.profile-preview {
|
||||||
|
margin-top: 12px;
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
}
|
||||||
|
.profile-preview .row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.profile-preview .row .big-avatar {
|
||||||
|
width: 52px;
|
||||||
|
height: 52px;
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 22px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.profile-preview .row .info h4 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.profile-preview .row .info p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: var(--radius-medium);
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item .emoji {
|
||||||
|
display: block;
|
||||||
|
font-size: 22px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item:first-child {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 脚注 */
|
||||||
|
.footnote {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 18px;
|
||||||
|
opacity: 0.7;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部 TabBar */
|
||||||
|
.tab-bar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: var(--text-primary);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0 18px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.06);
|
||||||
|
height: var(--tab-height);
|
||||||
|
}
|
||||||
|
.tab-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(255,255,255,0.45);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.15s;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.tab-item .icon { font-size: 24px; margin-bottom: 2px; line-height: 1; }
|
||||||
|
.tab-item.active { color: #A78BFA; }
|
||||||
|
.tab-item.active .icon { color: #A78BFA; }
|
||||||
|
|
||||||
|
.tab-item.cta-tab { position: relative; top: -12px; }
|
||||||
|
.tab-item.cta-tab .icon {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
color: white;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
box-shadow: 0 6px 20px rgba(124, 58, 237, 0.35);
|
||||||
|
}
|
||||||
|
.tab-item.cta-tab.active .icon { background: var(--primary-dark); }
|
||||||
|
|
||||||
|
/* 响应式 */
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.phone-mock { border-radius: 24px; }
|
||||||
|
.nav-bar .title { font-size: 18px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-mock">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="status-bar">
|
||||||
|
<span>9:41</span>
|
||||||
|
<span>📶 📶 🔋</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 导航栏 (渐变) -->
|
||||||
|
<div class="nav-bar">
|
||||||
|
<div class="title">💪 今日训练</div>
|
||||||
|
<div class="actions">
|
||||||
|
<span class="badge">🔔</span>
|
||||||
|
<div class="avatar">J</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主要内容 -->
|
||||||
|
<div class="content">
|
||||||
|
<!-- 欢迎卡片 (渐变) -->
|
||||||
|
<div class="greeting-card">
|
||||||
|
<div class="row">
|
||||||
|
<span class="name">👋 你好,Jason</span>
|
||||||
|
<span class="badge-energy">🔥 今日 420 kcal</span>
|
||||||
|
</div>
|
||||||
|
<div class="stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">68</span>
|
||||||
|
<span class="label">总课时</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">12</span>
|
||||||
|
<span class="label">连续打卡</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">4.8</span>
|
||||||
|
<span class="label">⭐ 评分</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分类标签 -->
|
||||||
|
<div class="category-tabs">
|
||||||
|
<span class="tab active">全部</span>
|
||||||
|
<span class="tab">力量区</span>
|
||||||
|
<span class="tab">有氧</span>
|
||||||
|
<span class="tab">瑜伽</span>
|
||||||
|
<span class="tab">私教</span>
|
||||||
|
<span class="tab">团课</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 日期选择器 -->
|
||||||
|
<div class="date-selector">
|
||||||
|
<div class="date-item disabled">
|
||||||
|
<span class="day">12</span>
|
||||||
|
<span class="week">周日</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">13</span>
|
||||||
|
<span class="week">周一</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item active">
|
||||||
|
<span class="day">14</span>
|
||||||
|
<span class="week">周二</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">15</span>
|
||||||
|
<span class="week">周三</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">16</span>
|
||||||
|
<span class="week">周四</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 1 -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🏋️</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">综合力量训练</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 45 min</span>
|
||||||
|
<span class="tag">🔥 热门</span>
|
||||||
|
<span>📍 力量区</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book">预约</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 2 (已约满) -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🧘</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">流瑜伽 · 中级</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 60 min</span>
|
||||||
|
<span class="tag">🧘 瑜伽</span>
|
||||||
|
<span>📍 3号教室</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book disabled">已约满</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 3 -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🚴</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">动感单车 · 冲刺</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 40 min</span>
|
||||||
|
<span class="tag">⚡ 有氧</span>
|
||||||
|
<span>📍 单车房</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book">预约</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 个人中心预览 -->
|
||||||
|
<div class="profile-preview">
|
||||||
|
<div class="row">
|
||||||
|
<div class="big-avatar">J</div>
|
||||||
|
<div class="info">
|
||||||
|
<h4>Jason Wang</h4>
|
||||||
|
<p>🏆 高级会员 · 已练 68 课时</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-grid">
|
||||||
|
<div class="menu-item"><span class="emoji">📊</span> 数据</div>
|
||||||
|
<div class="menu-item"><span class="emoji">🏅</span> 成就</div>
|
||||||
|
<div class="menu-item"><span class="emoji">⚙️</span> 设置</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footnote">配色方案 · 极光紫 · 科技感预约小程序</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部 TabBar -->
|
||||||
|
<div class="tab-bar">
|
||||||
|
<div class="tab-item active">
|
||||||
|
<span class="icon">🏠</span>
|
||||||
|
<span>首页</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">📅</span>
|
||||||
|
<span>课程</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item cta-tab active">
|
||||||
|
<span class="icon">➕</span>
|
||||||
|
<span>预约</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">💬</span>
|
||||||
|
<span>消息</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">👤</span>
|
||||||
|
<span>我的</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,591 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||||
|
<title>健身房预约 · 珊瑚橙配色</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&display=swap" rel="stylesheet" />
|
||||||
|
<style>
|
||||||
|
/* ==========================================================
|
||||||
|
配色方案:珊瑚橙 (Coral Orange)
|
||||||
|
主色:温暖珊瑚橙 + 柔和米白
|
||||||
|
性格:亲切、阳光、活力、温暖
|
||||||
|
适用:轻运动、瑜伽、女性友好、社区型健身房
|
||||||
|
========================================================== */
|
||||||
|
:root {
|
||||||
|
/* ----- 品牌主色 (Primary) ----- */
|
||||||
|
--primary: #FF6B4A; /* 珊瑚橙主色 */
|
||||||
|
--primary-dark: #E55A3A; /* 深橙按压态 */
|
||||||
|
--primary-light: rgba(255, 107, 74, 0.15); /* 浅橙背景 */
|
||||||
|
--primary-gradient: linear-gradient(135deg, #FF6B4A, #FF8A65); /* 橙红渐变 */
|
||||||
|
|
||||||
|
/* ----- 中性色 (Neutral) ----- */
|
||||||
|
--bg-primary: #FDF8F5; /* 暖白米色背景 */
|
||||||
|
--bg-card: #FFFFFF; /* 卡片纯白 */
|
||||||
|
--text-primary: #2D1F1A; /* 暖棕黑文字 */
|
||||||
|
--text-secondary: #8A7A72; /* 暖灰辅助文字 */
|
||||||
|
--text-disabled: #C5B5AD; /* 浅暖灰禁用 */
|
||||||
|
--border-light: #F0E8E3; /* 暖色分割线 */
|
||||||
|
--shadow-card: 0 4px 16px rgba(255, 107, 74, 0.12);
|
||||||
|
|
||||||
|
/* ----- 功能色 (Functional) ----- */
|
||||||
|
--highlight: #FF4757; /* 红点/警告 */
|
||||||
|
--success: #2ED573; /* 翠绿成功 */
|
||||||
|
--disabled-bg: #F0E8E3;
|
||||||
|
--disabled-text: #C5B5AD;
|
||||||
|
|
||||||
|
/* ----- 尺寸 (Size) ----- */
|
||||||
|
--radius-large: 20px;
|
||||||
|
--radius-medium: 12px;
|
||||||
|
--radius-full: 40px;
|
||||||
|
--tab-height: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局重置 */
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 手机容器 */
|
||||||
|
.phone-mock {
|
||||||
|
max-width: 375px;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: 40px;
|
||||||
|
box-shadow: 0 20px 60px rgba(255, 107, 74, 0.12);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid rgba(255, 107, 74, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态栏 */
|
||||||
|
.status-bar {
|
||||||
|
background: var(--text-primary);
|
||||||
|
padding: 12px 20px 8px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: rgba(255,255,255,0.65);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.status-bar span:last-child { display: flex; gap: 6px; }
|
||||||
|
|
||||||
|
/* 导航栏 (暖色渐变) */
|
||||||
|
.nav-bar {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
padding: 8px 20px 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.nav-bar .title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.3px;
|
||||||
|
}
|
||||||
|
.nav-bar .actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.nav-bar .actions .badge {
|
||||||
|
position: relative;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.nav-bar .actions .badge::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -2px;
|
||||||
|
right: -4px;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: var(--highlight);
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid var(--primary-dark);
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: rgba(255,255,255,0.25);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区 */
|
||||||
|
.content { padding: 20px 16px 100px; }
|
||||||
|
|
||||||
|
/* 欢迎卡片 (渐变) */
|
||||||
|
.greeting-card {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
padding: 18px 20px 20px;
|
||||||
|
color: white;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 6px 20px rgba(255, 107, 74, 0.25);
|
||||||
|
}
|
||||||
|
.greeting-card .row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.greeting-card .name { font-size: 18px; font-weight: 600; }
|
||||||
|
.greeting-card .badge-energy {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 4px 14px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.greeting-card .stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item { display: flex; flex-direction: column; }
|
||||||
|
.greeting-card .stats .stat-item .number {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(255,255,255,0.95);
|
||||||
|
}
|
||||||
|
.greeting-card .stats .stat-item .label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255,255,255,0.7);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分类标签 */
|
||||||
|
.category-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.category-tabs::-webkit-scrollbar { display: none; }
|
||||||
|
.category-tabs .tab {
|
||||||
|
background: white;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
white-space: nowrap;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.category-tabs .tab.active {
|
||||||
|
background: var(--primary);
|
||||||
|
color: white;
|
||||||
|
font-weight: 600;
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 4px 12px rgba(255, 107, 74, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 日期选择器 */
|
||||||
|
.date-selector {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.date-item {
|
||||||
|
flex: 1;
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-medium);
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
transition: all 0.1s;
|
||||||
|
}
|
||||||
|
.date-item .day {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.date-item .week { font-size: 12px; }
|
||||||
|
.date-item.active {
|
||||||
|
border-color: var(--primary);
|
||||||
|
background: var(--primary-light);
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.date-item.active .day { color: var(--primary-dark); }
|
||||||
|
.date-item.disabled { opacity: 0.35; }
|
||||||
|
|
||||||
|
/* 课程卡片 */
|
||||||
|
.course-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
}
|
||||||
|
.course-card .icon-placeholder {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: var(--radius-medium);
|
||||||
|
background: var(--primary-light);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
.course-card .info { flex: 1; }
|
||||||
|
.course-card .info .title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
.course-card .info .meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.course-card .info .meta .tag {
|
||||||
|
background: var(--primary-light);
|
||||||
|
color: var(--primary-dark);
|
||||||
|
padding: 2px 12px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
.course-card .btn-book {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 20px;
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: default;
|
||||||
|
box-shadow: 0 4px 12px rgba(255, 107, 74, 0.25);
|
||||||
|
transition: all 0.15s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.course-card .btn-book.disabled {
|
||||||
|
background: var(--disabled-bg);
|
||||||
|
color: var(--disabled-text);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 个人中心预览 */
|
||||||
|
.profile-preview {
|
||||||
|
margin-top: 12px;
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-large);
|
||||||
|
padding: 16px;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
}
|
||||||
|
.profile-preview .row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.profile-preview .row .big-avatar {
|
||||||
|
width: 52px;
|
||||||
|
height: 52px;
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 22px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.profile-preview .row .info h4 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.profile-preview .row .info p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-radius: var(--radius-medium);
|
||||||
|
padding: 10px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item .emoji {
|
||||||
|
display: block;
|
||||||
|
font-size: 22px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.profile-preview .menu-grid .menu-item:first-child {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--primary-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 脚注 */
|
||||||
|
.footnote {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 18px;
|
||||||
|
opacity: 0.7;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部 TabBar */
|
||||||
|
.tab-bar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: var(--text-primary);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 0 18px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.06);
|
||||||
|
height: var(--tab-height);
|
||||||
|
}
|
||||||
|
.tab-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(255,255,255,0.45);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: color 0.15s;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.tab-item .icon { font-size: 24px; margin-bottom: 2px; line-height: 1; }
|
||||||
|
.tab-item.active { color: #FF8A65; }
|
||||||
|
.tab-item.active .icon { color: #FF8A65; }
|
||||||
|
|
||||||
|
.tab-item.cta-tab { position: relative; top: -12px; }
|
||||||
|
.tab-item.cta-tab .icon {
|
||||||
|
background: var(--primary-gradient);
|
||||||
|
color: white;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
box-shadow: 0 6px 20px rgba(255, 107, 74, 0.35);
|
||||||
|
}
|
||||||
|
.tab-item.cta-tab.active .icon { background: var(--primary-dark); }
|
||||||
|
|
||||||
|
/* 响应式 */
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.phone-mock { border-radius: 24px; }
|
||||||
|
.nav-bar .title { font-size: 18px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="phone-mock">
|
||||||
|
<!-- 状态栏 -->
|
||||||
|
<div class="status-bar">
|
||||||
|
<span>9:41</span>
|
||||||
|
<span>📶 📶 🔋</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 导航栏 (渐变) -->
|
||||||
|
<div class="nav-bar">
|
||||||
|
<div class="title">💪 今日训练</div>
|
||||||
|
<div class="actions">
|
||||||
|
<span class="badge">🔔</span>
|
||||||
|
<div class="avatar">J</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主要内容 -->
|
||||||
|
<div class="content">
|
||||||
|
<!-- 欢迎卡片 (渐变) -->
|
||||||
|
<div class="greeting-card">
|
||||||
|
<div class="row">
|
||||||
|
<span class="name">👋 你好,Jason</span>
|
||||||
|
<span class="badge-energy">🔥 今日 420 kcal</span>
|
||||||
|
</div>
|
||||||
|
<div class="stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">68</span>
|
||||||
|
<span class="label">总课时</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">12</span>
|
||||||
|
<span class="label">连续打卡</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<span class="number">4.8</span>
|
||||||
|
<span class="label">⭐ 评分</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分类标签 -->
|
||||||
|
<div class="category-tabs">
|
||||||
|
<span class="tab active">全部</span>
|
||||||
|
<span class="tab">力量区</span>
|
||||||
|
<span class="tab">有氧</span>
|
||||||
|
<span class="tab">瑜伽</span>
|
||||||
|
<span class="tab">私教</span>
|
||||||
|
<span class="tab">团课</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 日期选择器 -->
|
||||||
|
<div class="date-selector">
|
||||||
|
<div class="date-item disabled">
|
||||||
|
<span class="day">12</span>
|
||||||
|
<span class="week">周日</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">13</span>
|
||||||
|
<span class="week">周一</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item active">
|
||||||
|
<span class="day">14</span>
|
||||||
|
<span class="week">周二</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">15</span>
|
||||||
|
<span class="week">周三</span>
|
||||||
|
</div>
|
||||||
|
<div class="date-item">
|
||||||
|
<span class="day">16</span>
|
||||||
|
<span class="week">周四</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 1 -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🏋️</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">综合力量训练</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 45 min</span>
|
||||||
|
<span class="tag">🔥 热门</span>
|
||||||
|
<span>📍 力量区</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book">预约</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 2 (已约满) -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🧘</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">流瑜伽 · 中级</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 60 min</span>
|
||||||
|
<span class="tag">🧘 瑜伽</span>
|
||||||
|
<span>📍 3号教室</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book disabled">已约满</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 课程卡片 3 -->
|
||||||
|
<div class="course-card">
|
||||||
|
<div class="icon-placeholder">🚴</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="title">动感单车 · 冲刺</div>
|
||||||
|
<div class="meta">
|
||||||
|
<span>⏱️ 40 min</span>
|
||||||
|
<span class="tag">⚡ 有氧</span>
|
||||||
|
<span>📍 单车房</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn-book">预约</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 个人中心预览 -->
|
||||||
|
<div class="profile-preview">
|
||||||
|
<div class="row">
|
||||||
|
<div class="big-avatar">J</div>
|
||||||
|
<div class="info">
|
||||||
|
<h4>Jason Wang</h4>
|
||||||
|
<p>🏆 高级会员 · 已练 68 课时</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu-grid">
|
||||||
|
<div class="menu-item"><span class="emoji">📊</span> 数据</div>
|
||||||
|
<div class="menu-item"><span class="emoji">🏅</span> 成就</div>
|
||||||
|
<div class="menu-item"><span class="emoji">⚙️</span> 设置</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footnote">配色方案 · 珊瑚橙 · 温暖活力预约小程序</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部 TabBar -->
|
||||||
|
<div class="tab-bar">
|
||||||
|
<div class="tab-item active">
|
||||||
|
<span class="icon">🏠</span>
|
||||||
|
<span>首页</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">📅</span>
|
||||||
|
<span>课程</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item cta-tab active">
|
||||||
|
<span class="icon">➕</span>
|
||||||
|
<span>预约</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">💬</span>
|
||||||
|
<span>消息</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item">
|
||||||
|
<span class="icon">👤</span>
|
||||||
|
<span>我的</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script>
|
||||||
|
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||||
|
CSS.supports('top: constant(a)'))
|
||||||
|
document.write(
|
||||||
|
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||||
|
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||||
|
</script>
|
||||||
|
<title></title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"><!--app-html--></div>
|
||||||
|
<script type="module" src="/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import App from './App'
|
||||||
|
|
||||||
|
// #ifndef VUE3
|
||||||
|
import Vue from 'vue'
|
||||||
|
import './uni.promisify.adaptor'
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
App.mpType = 'app'
|
||||||
|
const app = new Vue({
|
||||||
|
...App
|
||||||
|
})
|
||||||
|
app.$mount()
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef VUE3
|
||||||
|
import { createSSRApp } from 'vue'
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App)
|
||||||
|
return {
|
||||||
|
app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name" : "gym-manage-uniapp",
|
"name" : "gym-manage-uniapp",
|
||||||
"appid" : "",
|
"appid" : "",
|
||||||
"description": "Gym Management System Mobile App",
|
"description" : "",
|
||||||
"versionName" : "1.0.0",
|
"versionName" : "1.0.0",
|
||||||
"versionCode" : "100",
|
"versionCode" : "100",
|
||||||
"transformPx" : false,
|
"transformPx" : false,
|
||||||
|
/* 5+App特有相关 */
|
||||||
"app-plus" : {
|
"app-plus" : {
|
||||||
"usingComponents" : true,
|
"usingComponents" : true,
|
||||||
"nvueStyleCompiler" : "uni-app",
|
"nvueStyleCompiler" : "uni-app",
|
||||||
@@ -15,8 +16,11 @@
|
|||||||
"autoclose" : true,
|
"autoclose" : true,
|
||||||
"delay" : 0
|
"delay" : 0
|
||||||
},
|
},
|
||||||
|
/* 模块配置 */
|
||||||
"modules" : {},
|
"modules" : {},
|
||||||
|
/* 应用发布信息 */
|
||||||
"distribute" : {
|
"distribute" : {
|
||||||
|
/* android打包配置 */
|
||||||
"android" : {
|
"android" : {
|
||||||
"permissions" : [
|
"permissions" : [
|
||||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||||
@@ -36,11 +40,15 @@
|
|||||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
/* ios打包配置 */
|
||||||
"ios" : {},
|
"ios" : {},
|
||||||
|
/* SDK配置 */
|
||||||
"sdkConfigs" : {}
|
"sdkConfigs" : {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/* 快应用特有相关 */
|
||||||
"quickapp" : {},
|
"quickapp" : {},
|
||||||
|
/* 小程序特有相关 */
|
||||||
"mp-weixin" : {
|
"mp-weixin" : {
|
||||||
"appid" : "",
|
"appid" : "",
|
||||||
"setting" : {
|
"setting" : {
|
||||||
@@ -60,5 +68,5 @@
|
|||||||
"uniStatistics" : {
|
"uniStatistics" : {
|
||||||
"enable" : false
|
"enable" : false
|
||||||
},
|
},
|
||||||
"vueVersion": "3"
|
"vueVersion" : "2"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+22
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "gym-manage-uniapp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "gym-manage-uniapp",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@dcloudio/uni-ui": "^1.5.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@dcloudio/uni-ui": {
|
||||||
|
"version": "1.5.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.12.tgz",
|
||||||
|
"integrity": "sha512-mGDl2OZSz7D8xcUAzJegWDHOqB4MEFBSW9Esb/oJiu2/3Gk9+P/Z4bA4JZ9jv9VWBYbMrYwaTfK1Z728kABdYg==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "gym-manage-uniapp",
|
"name": "gym-manage-uniapp",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Gym Management System Mobile App",
|
"description": "",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:mp-weixin": "uni -p mp-weixin",
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
"build:mp-weixin": "uni build -p mp-weixin",
|
|
||||||
"dev:h5": "uni",
|
|
||||||
"build:h5": "uni build"
|
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [],
|
||||||
"uniapp",
|
"author": "",
|
||||||
"gym",
|
"license": "ISC",
|
||||||
"management"
|
"type": "commonjs",
|
||||||
],
|
"dependencies": {
|
||||||
"author": "Novalon",
|
"@dcloudio/uni-ui": "^1.5.12"
|
||||||
"license": "MIT"
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,66 @@
|
|||||||
{
|
{
|
||||||
"pages": [
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "pages/login/login",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "登录",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/index/index",
|
"path": "pages/index/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "首页"
|
"navigationBarTitleText": "首页",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/search/search",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "团课搜索",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/course-detail/course-detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "课程详情",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/profile/profile",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "个人中心",
|
||||||
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "white",
|
||||||
"navigationBarTitleText": "健身房管理系统",
|
"navigationBarTitleText": "Novalon健身房",
|
||||||
"navigationBarBackgroundColor": "#F8F8F8",
|
"navigationBarBackgroundColor": "#1A1A1A",
|
||||||
"backgroundColor": "#F8F8F8"
|
"backgroundColor": "#F5F7FA"
|
||||||
},
|
},
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"color": "#7A7E83",
|
"color": "#7A7E84",
|
||||||
"selectedColor": "#007AFF",
|
"selectedColor": "#00E676",
|
||||||
|
"backgroundColor": "#1A1A1A",
|
||||||
"borderStyle": "black",
|
"borderStyle": "black",
|
||||||
"backgroundColor": "#F8F8F8",
|
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"pagePath": "pages/index/index",
|
"pagePath": "pages/index/index",
|
||||||
"text": "首页"
|
"text": "首页"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/search/search",
|
||||||
|
"text": "课程"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/profile/profile",
|
||||||
|
"text": "我的"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"uniIdRouter": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<view class="detail-root">
|
||||||
|
<view class="detail-page">
|
||||||
|
<view class="header-wrap" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
|
<view class="nav-bar" :style="{ height: navBarHeight + 'px' }">
|
||||||
|
<text class="back-btn" @click="goBack">‹</text>
|
||||||
|
<text class="nav-title">课程详情</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="cover-area">
|
||||||
|
<view class="cover-bg">
|
||||||
|
<text class="cover-text">{{ course.typeChar }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="status-tag" v-if="course.isFull">已约满</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="content" scroll-y :style="{ height: 'calc(100vh - ' + totalHeaderHeight + 'px)' }">
|
||||||
|
<view class="content-inner">
|
||||||
|
<view class="course-header">
|
||||||
|
<view class="header-top">
|
||||||
|
<text class="course-title">{{ course.courseName }}</text>
|
||||||
|
<view class="difficulty-badge" :class="'diff-' + course.difficultyLevel">
|
||||||
|
{{ course.difficultyLabel }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="header-meta">
|
||||||
|
<text class="meta-type">{{ course.tag }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="info-card">
|
||||||
|
<view class="info-row">
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">教练</text>
|
||||||
|
<text class="info-value">{{ course.coachName }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">地点</text>
|
||||||
|
<text class="info-value">{{ course.location }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="divider"></view>
|
||||||
|
<view class="info-row">
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">日期时间</text>
|
||||||
|
<text class="info-value">{{ course.startTime }} - {{ course.endTime }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="divider"></view>
|
||||||
|
<view class="info-row">
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">时长</text>
|
||||||
|
<text class="info-value">{{ course.duration }} 分钟</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-item">
|
||||||
|
<text class="info-label">人数</text>
|
||||||
|
<text class="info-value">
|
||||||
|
{{ course.currentMembers }} / {{ course.maxMembers }}
|
||||||
|
<text v-if="course.maxMembers - course.currentMembers > 0" class="remain-text">
|
||||||
|
(剩{{ course.maxMembers - course.currentMembers }}位)
|
||||||
|
</text>
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="section-card">
|
||||||
|
<text class="section-title">• 课程介绍</text>
|
||||||
|
<text class="desc-text">{{ course.description }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="section-card">
|
||||||
|
<text class="section-title">• 课程信息</text>
|
||||||
|
<view class="detail-grid">
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">课程类型</text>
|
||||||
|
<text class="detail-value">{{ course.typeName || '团课' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">基础难度</text>
|
||||||
|
<view class="stars">
|
||||||
|
<text v-for="i in 10" :key="i" class="star" :class="{ filled: i <= course.difficulty }">
|
||||||
|
{{ i <= course.difficulty ? '★' : '☆' }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">分类</text>
|
||||||
|
<text class="detail-value">{{ course.categoryLabel || '综合' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">储值消耗</text>
|
||||||
|
<text class="detail-value price">{{ course.storedValueAmount > 0 ? course.storedValueAmount + '元' : '免费' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bottom-safe"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bottom-bar">
|
||||||
|
<view class="bottom-info">
|
||||||
|
<text class="bottom-price" :class="{ free: course.storedValueAmount === 0 }">
|
||||||
|
{{ course.storedValueAmount > 0 ? course.storedValueAmount : '免费' }}
|
||||||
|
</text>
|
||||||
|
<text class="bottom-desc">/ 次</text>
|
||||||
|
</view>
|
||||||
|
<button class="booking-btn" :class="{ disabled: course.isFull }" :disabled="course.isFull"
|
||||||
|
@click="handleBooking">
|
||||||
|
{{ course.isFull ? '已约满' : '立即预约' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusBarHeight: 0,
|
||||||
|
navBarHeight: 44,
|
||||||
|
totalHeaderHeight: 44,
|
||||||
|
course: { id: 1, courseName: '综合力量训练', coachName: '张教练', location: '力量区', typeChar: '力', tag: '热门', category: 'strength', categoryLabel: '力量训练', typeName: '自由重量杠铃/哑铃', startTime: '2026-07-15 10:00', endTime: '2026-07-15 10:45', duration: 45, maxMembers: 20, currentMembers: 8, isFull: false, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', storedValueAmount: 0, description: '综合力量训练课程,涵盖杠铃、哑铃等自由重量训练,适合有一定基础的学员。' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
const statusBarHeight = systemInfo.statusBarHeight || 20
|
||||||
|
let navBarHeight = 44
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect()
|
||||||
|
if (menuButton) {
|
||||||
|
navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.statusBarHeight = statusBarHeight
|
||||||
|
this.navBarHeight = navBarHeight
|
||||||
|
this.totalHeaderHeight = statusBarHeight + navBarHeight
|
||||||
|
if (options.id) this.loadCourseDetail(options.id)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadCourseDetail(id) {
|
||||||
|
const m = { 1: { courseName: '综合力量训练', coachName: '张教练', location: '力量区', typeChar: '力', tag: '热门', category: 'strength', categoryLabel: '力量训练', typeName: '自由重量杠铃/哑铃', startTime: '2026-07-15 10:00', endTime: '2026-07-15 10:45', duration: 45, maxMembers: 20, currentMembers: 8, isFull: false, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', description: '综合力量训练课程,涵盖杠铃、哑铃等自由重量训练,适合有一定基础的学员。课程包括热身、主要力量训练组和拉伸放松三个环节,全面提升力量水平和身体协调性。' }, 2: { courseName: '流瑜伽 · 中级', coachName: '李教练', location: '3号教室', typeChar: '瑜', tag: '瑜伽', category: 'yoga', categoryLabel: '瑜伽', typeName: '柔韧与平衡类', startTime: '2026-07-15 14:00', endTime: '2026-07-15 15:00', duration: 60, maxMembers: 15, currentMembers: 15, isFull: true, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', description: '流瑜伽中级课程,适合有一定瑜伽基础的学员。通过连贯的体式流动,提升身体柔韧性、核心力量和平衡能力。' }, 3: { courseName: '动感单车 · 冲刺', coachName: '王教练', location: '单车房', typeChar: '车', tag: '有氧', category: 'cardio', categoryLabel: '有氧运动', typeName: '基础有氧与热身', startTime: '2026-07-15 18:00', endTime: '2026-07-15 18:40', duration: 40, maxMembers: 25, currentMembers: 12, isFull: false, difficulty: 4, difficultyLevel: 'low', difficultyLabel: '入门', description: '高强度动感单车课程,结合节奏音乐,在教练的带领下进行冲刺、爬坡、耐力等训练。' }, 4: { courseName: 'HIIT训练', coachName: '赵教练', location: '多功能厅', typeChar: 'HI', tag: '有氧', category: 'cardio', categoryLabel: '有氧运动', typeName: '高强度与爆发力', startTime: '2026-07-15 12:00', endTime: '2026-07-15 12:30', duration: 30, maxMembers: 15, currentMembers: 10, isFull: false, difficulty: 7, difficultyLevel: 'high', difficultyLabel: '困难', description: '高强度间歇训练(HIIT),通过短时间高强度运动和短暂休息交替进行,高效燃脂并提升心肺功能。' }, 5: { courseName: '普拉提', coachName: '李教练', location: '2号教室', typeChar: '普', tag: '瑜伽', category: 'yoga', categoryLabel: '瑜伽', typeName: '柔韧与平衡类', startTime: '2026-07-15 16:00', endTime: '2026-07-15 16:50', duration: 50, maxMembers: 12, currentMembers: 5, isFull: false, difficulty: 4, difficultyLevel: 'low', difficultyLabel: '入门', description: '普拉提课程注重核心力量和身体控制,通过精准的动作改善体态、增强核心稳定性和身体柔韧性。' }, 6: { courseName: '搏击操', coachName: '刘教练', location: '搏击区', typeChar: '搏', tag: '有氧', category: 'cardio', categoryLabel: '有氧运动', typeName: '高强度与爆发力', startTime: '2026-07-15 07:00', endTime: '2026-07-15 07:45', duration: 45, maxMembers: 20, currentMembers: 6, isFull: false, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', description: '搏击操结合拳击、踢拳等动作元素,在动感音乐下进行高强度有氧训练。' } }
|
||||||
|
if (m[id]) this.course = { ...this.course, ...m[id], id: parseInt(id) }
|
||||||
|
},
|
||||||
|
goBack() { uni.navigateBack() },
|
||||||
|
handleBooking() { if (this.course.isFull) return; uni.showToast({ title: '预约成功', icon: 'success' }); setTimeout(() => { uni.navigateBack() }, 1000) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.detail-page { min-height: 100vh; background: #F5F7FA; overflow-x: hidden; }
|
||||||
|
.header-wrap { background: #1A1A1A; }
|
||||||
|
.nav-bar { background: #1A1A1A; padding: 0 20px; display: flex; align-items: center; }
|
||||||
|
.back-btn { font-size: 26px; color: #FFFFFF; font-weight: 700; margin-right: 10px; line-height: 1; }
|
||||||
|
.nav-title { font-size: 18px; font-weight: 700; color: #FFFFFF; }
|
||||||
|
.cover-area { height: 180px; position: relative; overflow: hidden; }
|
||||||
|
.cover-bg { width: 100%; height: 100%; background: linear-gradient(135deg, #00C853, #00BFA5); display: flex; align-items: center; justify-content: center; }
|
||||||
|
.cover-text { font-size: 56px; font-weight: 700; color: rgba(255,255,255,0.9); }
|
||||||
|
.status-tag { position: absolute; top: 14px; right: 16px; background: #FF5252; color: #FFFFFF; font-size: 12px; font-weight: 600; padding: 4px 12px; border-radius: 40px; }
|
||||||
|
.content-inner { padding-bottom: 100px; }
|
||||||
|
.course-header { background: #FFFFFF; padding: 20px 16px 16px; border-radius: 20px 20px 0 0; margin-top: -16px; position: relative; z-index: 1; }
|
||||||
|
.header-top { display: flex; justify-content: space-between; align-items: center; }
|
||||||
|
.course-title { font-size: 22px; font-weight: 700; color: #1E1E1E; }
|
||||||
|
.difficulty-badge { padding: 4px 12px; border-radius: 40px; font-size: 12px; font-weight: 600; flex-shrink: 0; }
|
||||||
|
.diff-low { background: rgba(0,230,118,0.15); color: #00C853; }
|
||||||
|
.diff-mid { background: rgba(255,165,2,0.15); color: #FFA502; }
|
||||||
|
.diff-high { background: rgba(255,82,82,0.15); color: #FF5252; }
|
||||||
|
.header-meta { margin-top: 8px; }
|
||||||
|
.meta-type { font-size: 13px; color: #00C853; background: rgba(0,230,118,0.15); padding: 3px 10px; border-radius: 20px; font-weight: 500; }
|
||||||
|
.info-card { background: #FFFFFF; margin: 0 16px; border-radius: 20px; padding: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); margin-top: 12px; }
|
||||||
|
.info-row { display: flex; justify-content: space-between; }
|
||||||
|
.info-item { display: flex; flex-direction: column; flex: 1; }
|
||||||
|
.info-label { font-size: 12px; color: #7A7E84; margin-bottom: 4px; }
|
||||||
|
.info-value { font-size: 14px; font-weight: 600; color: #1E1E1E; }
|
||||||
|
.remain-text { font-size: 12px; color: #00C853; font-weight: 500; }
|
||||||
|
.divider { height: 1px; background: #EEEEEE; margin: 14px 0; }
|
||||||
|
.section-card { background: #FFFFFF; margin: 12px 16px; border-radius: 20px; padding: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); }
|
||||||
|
.section-title { font-size: 16px; font-weight: 700; color: #1E1E1E; display: block; margin-bottom: 12px; }
|
||||||
|
.desc-text { font-size: 14px; color: #7A7E84; line-height: 1.7; }
|
||||||
|
.detail-grid { display: flex; flex-wrap: wrap; }
|
||||||
|
.detail-item { width: 50%; display: flex; flex-direction: column; margin-bottom: 14px; }
|
||||||
|
.detail-label { font-size: 12px; color: #7A7E84; }
|
||||||
|
.detail-value { font-size: 14px; font-weight: 600; color: #1E1E1E; margin-top: 4px; }
|
||||||
|
.detail-value.price { color: #00C853; }
|
||||||
|
.stars { display: flex; flex-wrap: wrap; }
|
||||||
|
.star { font-size: 13px; color: #E0E0E0; }
|
||||||
|
.star.filled { color: #FFA502; }
|
||||||
|
.bottom-safe { height: 30px; }
|
||||||
|
.bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; background: #FFFFFF; padding: 12px 16px; padding-bottom: calc(12px + env(safe-area-inset-bottom)); display: flex; align-items: center; justify-content: space-between; box-shadow: 0 -2px 12px rgba(0,0,0,0.06); z-index: 100; }
|
||||||
|
.bottom-info { display: flex; align-items: baseline; }
|
||||||
|
.bottom-price { font-size: 22px; font-weight: 700; color: #00C853; }
|
||||||
|
.bottom-price.free { color: #00C853; }
|
||||||
|
.bottom-desc { font-size: 13px; color: #7A7E84; margin-left: 2px; }
|
||||||
|
.booking-btn { background: #00E676; color: #1A1A1A; border: none; padding: 12px 32px; border-radius: 40px; font-weight: 700; font-size: 16px; box-shadow: 0 4px 14px rgba(0,230,118,0.35); line-height: 1.2; }
|
||||||
|
.booking-btn::after { border: none; }
|
||||||
|
.booking-btn.disabled { background: #E0E0E0; color: #BDBDBD; box-shadow: none; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<view class="home-page">
|
||||||
|
<!-- 状态栏 + 胶囊按钮占位 -->
|
||||||
|
<view class="header-wrap" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
|
<view class="nav-bar" :style="{ height: navBarHeight + 'px' }">
|
||||||
|
<text class="nav-title">✯ 今日训练</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="content" scroll-y :style="{ height: 'calc(100vh - ' + totalHeaderHeight + 'px)' }">
|
||||||
|
<view class="content-inner">
|
||||||
|
<!-- 个人信息卡片(深色)+ 轮播图 -->
|
||||||
|
<view class="greeting-card">
|
||||||
|
<view class="greeting-header">
|
||||||
|
<view class="member-info">
|
||||||
|
<text class="member-name">你好,{{ memberInfo.nickname }}</text>
|
||||||
|
<text class="member-no">{{ memberInfo.memberNo }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="checkin-badge" v-if="memberInfo.checkedInToday">
|
||||||
|
<text class="checkin-icon">✓</text>
|
||||||
|
<text>今日已签到</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="stats">
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="stat-number">{{ memberInfo.totalSignDays }}</text>
|
||||||
|
<text class="stat-label">累计签到(天)</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="stat-number">{{ memberInfo.pendingBookings }}</text>
|
||||||
|
<text class="stat-label">待上团课</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 轮播图 -->
|
||||||
|
<swiper class="banner-swiper" :indicator-dots="true" :autoplay="true" :interval="4000" :duration="500" circular>
|
||||||
|
<swiper-item v-for="(banner, idx) in banners" :key="idx">
|
||||||
|
<view class="banner-slide" :style="{ backgroundImage: 'url(' + banner.imageUrl + ')' }">
|
||||||
|
<text class="banner-title">{{ banner.title }}</text>
|
||||||
|
<text class="banner-subtitle">{{ banner.subtitle }}</text>
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 今日推荐 -->
|
||||||
|
<view class="recommend-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">✯ 今日推荐</text>
|
||||||
|
<text class="section-more" @click="goToSearch">查看全部 ›</text>
|
||||||
|
</view>
|
||||||
|
<view class="recommend-list">
|
||||||
|
<view v-for="(course, idx) in recommendCourses" :key="idx" class="recommend-card"
|
||||||
|
@click="goToCourseDetail(course.id)">
|
||||||
|
<view class="card-cover" :style="{ backgroundImage: 'url(' + course.imageUrl + ')' }">
|
||||||
|
<view class="card-tag" v-if="course.recommendTitle">{{ course.recommendTitle }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="card-body">
|
||||||
|
<text class="card-name">{{ course.courseName }}</text>
|
||||||
|
<text class="card-reason">{{ course.recommendReason }}</text>
|
||||||
|
<view class="card-bottom">
|
||||||
|
<text class="card-price">{{ course.priceLabel }}</text>
|
||||||
|
<text class="card-count">{{ course.bookedCount }}人已预约</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bottom-safe"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusBarHeight: 0,
|
||||||
|
navBarHeight: 44,
|
||||||
|
totalHeaderHeight: 44,
|
||||||
|
memberInfo: {
|
||||||
|
nickname: 'Jason',
|
||||||
|
memberNo: 'MEM20260715001',
|
||||||
|
checkedInToday: true,
|
||||||
|
totalSignDays: 128,
|
||||||
|
pendingBookings: 3
|
||||||
|
},
|
||||||
|
banners: [
|
||||||
|
{ imageUrl: 'https://img.zcool.cn/community/01f5c65e5d9c6ca801216518e1d2e0.jpg@1280w_1l_2o_100sh.jpg', title: '夏季燃脂计划', subtitle: 'HIIT + 动感单车,高效燃脂 7 天挑战' },
|
||||||
|
{ imageUrl: 'https://img.zcool.cn/community/01a5fe5e5d9c4ba80121985ac87c5f.jpg@1280w_1l_2o_100sh.jpg', title: '瑜伽月卡特惠', subtitle: '新人专享 5 折,流瑜伽 / 普拉提任选' },
|
||||||
|
{ imageUrl: 'https://img.zcool.cn/community/0177c85e5d9c84a8012165182ef63f.jpg@1280w_1l_2o_100sh.jpg', title: '私教一对一体验', subtitle: '免费体测 + 定制训练计划,限 30 名' }
|
||||||
|
],
|
||||||
|
recommendCourses: [
|
||||||
|
{ id: 1, courseName: '极速燃脂单车', recommendTitle: '热门', tagColor: '', imageUrl: 'https://img.zcool.cn/community/01f5c65e5d9c6ca801216518e1d2e0.jpg@1280w_1l_2o_100sh.jpg', recommendReason: '教练专业 · 燃脂效果显著', priceLabel: '¥50', bookedCount: 186 },
|
||||||
|
{ id: 2, courseName: '清晨流瑜伽', recommendTitle: '新手推荐', tagColor: '', imageUrl: 'https://img.zcool.cn/community/01a5fe5e5d9c4ba80121985ac87c5f.jpg@1280w_1l_2o_100sh.jpg', recommendReason: '教练耐心 · 节奏适中', priceLabel: '¥50', bookedCount: 142 },
|
||||||
|
{ id: 3, courseName: '核心力量训练', recommendTitle: '塑形', tagColor: '', imageUrl: 'https://img.zcool.cn/community/0165ed5e5d9c6ca80121985a0733a5.jpg@1280w_1l_2o_100sh.jpg', recommendReason: '核心专项 · 适合所有水平', priceLabel: '¥50', bookedCount: 97 },
|
||||||
|
{ id: 4, courseName: 'HIIT燃脂训练', recommendTitle: '高强度', tagColor: '', imageUrl: 'https://img.zcool.cn/community/0148fa5e5d9c4ba80121985a1b52e4.jpg@1280w_1l_2o_100sh.jpg', recommendReason: '挑战心肺极限 · 快速燃脂', priceLabel: '¥50', bookedCount: 211 },
|
||||||
|
{ id: 5, courseName: '晚间普拉提', recommendTitle: '新上', tagColor: '', imageUrl: 'https://img.zcool.cn/community/01c3b25e5d9c6ca80121985ab2b7e6.jpg@1280w_1l_2o_100sh.jpg', recommendReason: '核心力量 · 放松一天疲劳', priceLabel: '¥50', bookedCount: 68 },
|
||||||
|
{ id: 6, courseName: '周末瑜伽', recommendTitle: '进阶', tagColor: '', imageUrl: 'https://img.zcool.cn/community/0177c85e5d9c84a8012165182ef63f.jpg@1280w_1l_2o_100sh.jpg', recommendReason: '有基础的进阶课程', priceLabel: '¥50', bookedCount: 55 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
const statusBarHeight = systemInfo.statusBarHeight || 20
|
||||||
|
let navBarHeight = 44
|
||||||
|
// 获取胶囊按钮信息,对齐导航栏高度
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect()
|
||||||
|
if (menuButton) {
|
||||||
|
navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.statusBarHeight = statusBarHeight
|
||||||
|
this.navBarHeight = navBarHeight
|
||||||
|
this.totalHeaderHeight = statusBarHeight + navBarHeight
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
goToCourseDetail(id) { uni.navigateTo({ url: '/pages/course-detail/course-detail?id=' + id }) },
|
||||||
|
goToSearch() { uni.switchTab({ url: '/pages/search/search' }) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.home-page { min-height: 100vh; background: #F5F7FA; overflow-x: hidden; }
|
||||||
|
.header-wrap { background: #1A1A1A; }
|
||||||
|
.nav-bar { background: #1A1A1A; padding: 0 20px; display: flex; align-items: center; }
|
||||||
|
.nav-title { font-size: 18px; font-weight: 700; color: #FFFFFF; }
|
||||||
|
.content-inner { padding: 16px; }
|
||||||
|
|
||||||
|
/* 个人信息卡片 */
|
||||||
|
.greeting-card { background: #1A1A1A; border-radius: 20px; padding: 18px 20px 0; color: #FFFFFF; margin-bottom: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); overflow: hidden; }
|
||||||
|
.greeting-header { display: flex; justify-content: space-between; align-items: flex-start; }
|
||||||
|
.member-info { display: flex; flex-direction: column; }
|
||||||
|
.member-name { font-size: 18px; font-weight: 600; }
|
||||||
|
.member-no { font-size: 11px; color: rgba(255,255,255,0.5); margin-top: 2px; }
|
||||||
|
.checkin-badge { background: rgba(0,230,118,0.2); color: #00E676; font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: 12px; display: flex; align-items: center; }
|
||||||
|
.checkin-icon { font-size: 11px; margin-right: 3px; }
|
||||||
|
|
||||||
|
.stats { display: flex; margin-top: 16px; }
|
||||||
|
.stat-item { display: flex; flex-direction: column; margin-right: 24px; }
|
||||||
|
.stat-number { font-size: 22px; font-weight: 700; color: #00E676; }
|
||||||
|
.stat-label { font-size: 12px; color: rgba(255,255,255,0.6); margin-top: 2px; }
|
||||||
|
|
||||||
|
|
||||||
|
/* 轮播图 */
|
||||||
|
.banner-swiper { height: 160px; margin: 14px -20px 0; }
|
||||||
|
.banner-slide { height: 100%; background-size: cover; background-position: center; background-color: #2A2A2A; display: flex; flex-direction: column; justify-content: flex-end; padding: 16px 20px; }
|
||||||
|
.banner-title { font-size: 20px; font-weight: 700; color: #FFFFFF; text-shadow: 0 2px 6px rgba(0,0,0,0.5); }
|
||||||
|
.banner-subtitle { font-size: 14px; color: rgba(255,255,255,0.9); margin-top: 6px; text-shadow: 0 1px 4px rgba(0,0,0,0.5); }
|
||||||
|
|
||||||
|
/* 今日推荐 */
|
||||||
|
.recommend-section { margin-bottom: 16px; }
|
||||||
|
.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
|
||||||
|
.section-title { font-size: 18px; font-weight: 700; color: #1E1E1E; }
|
||||||
|
.section-more { font-size: 13px; color: #00C853; }
|
||||||
|
.recommend-list { display: flex; flex-wrap: wrap; justify-content: space-between; }
|
||||||
|
.recommend-card { width: calc(50% - 6px); background: #FFFFFF; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.06); margin-bottom: 12px; }
|
||||||
|
.card-cover { height: 130px; background-size: cover; background-position: center; background-color: #E8E8E8; display: flex; align-items: flex-start; justify-content: flex-end; padding: 8px; }
|
||||||
|
.card-tag { background: #00E676; color: #1A1A1A; font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 20px; }
|
||||||
|
.card-body { padding: 10px 12px 14px; }
|
||||||
|
.card-name { font-size: 14px; font-weight: 600; color: #1E1E1E; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; margin-bottom: 4px; }
|
||||||
|
.card-reason { font-size: 12px; color: #7A7E84; display: block; margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||||
|
.card-bottom { display: flex; justify-content: space-between; align-items: center; margin-top: 2px; }
|
||||||
|
.card-price { font-size: 14px; font-weight: 700; color: #00C853; }
|
||||||
|
.card-count { font-size: 11px; color: #BDBDBD; }
|
||||||
|
.bottom-safe { height: 20px; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<view class="login-page" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
|
<view class="brand-area">
|
||||||
|
<view class="logo-icon">
|
||||||
|
<text class="logo-symbol">✦</text>
|
||||||
|
</view>
|
||||||
|
<text class="app-name">Novalon 健身房</text>
|
||||||
|
<text class="app-slogan">专业预约 · 科学训练</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="login-btn-area">
|
||||||
|
<button class="wechat-login-btn" @click="handleLogin">
|
||||||
|
<text class="wechat-symbol">微</text>
|
||||||
|
<text class="btn-text">微信一键登录</text>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<view class="agreement-row">
|
||||||
|
<view class="checkbox-wrapper" @click="toggleAgree">
|
||||||
|
<view class="checkbox" :class="{ checked: agreed }">
|
||||||
|
<text v-if="agreed" class="check-mark">✓</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<text class="agreement-text">
|
||||||
|
已阅读并同意
|
||||||
|
<text class="link">《用户协议》</text>
|
||||||
|
和
|
||||||
|
<text class="link">《隐私政策》</text>
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="other-login">
|
||||||
|
<text class="divider-text">其他登录方式</text>
|
||||||
|
<view class="other-icons">
|
||||||
|
<view class="other-item">
|
||||||
|
<view class="other-icon-circle">
|
||||||
|
<text class="other-symbol">☏</text>
|
||||||
|
</view>
|
||||||
|
<text class="other-label">手机号</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="footer-tip">
|
||||||
|
<text>首次登录将自动注册账号</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusBarHeight: 0,
|
||||||
|
agreed: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
this.statusBarHeight = systemInfo.statusBarHeight || 20
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleAgree() { this.agreed = !this.agreed },
|
||||||
|
handleLogin() { uni.switchTab({ url: '/pages/index/index' }) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.login-page { min-height: 100vh; background: #F5F7FA; display: flex; flex-direction: column; align-items: center; padding: 0 32px; overflow-x: hidden; }
|
||||||
|
|
||||||
|
.brand-area { display: flex; flex-direction: column; align-items: center; margin-top: 60px; margin-bottom: 80px; }
|
||||||
|
.logo-icon { width: 80px; height: 80px; background: rgba(0,230,118,0.15); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 20px; }
|
||||||
|
.logo-symbol { font-size: 36px; color: #00C853; }
|
||||||
|
.app-name { font-size: 28px; font-weight: 700; color: #1E1E1E; letter-spacing: 1px; }
|
||||||
|
.app-slogan { font-size: 14px; color: #7A7E84; margin-top: 8px; letter-spacing: 2px; }
|
||||||
|
|
||||||
|
.login-btn-area { width: 100%; display: flex; flex-direction: column; align-items: center; }
|
||||||
|
.wechat-login-btn { width: 100%; height: 52px; background: #00E676; border-radius: 40px; display: flex; align-items: center; justify-content: center; border: none; padding: 0; box-shadow: 0 4px 16px rgba(0,230,118,0.35); }
|
||||||
|
.wechat-login-btn::after { border: none; }
|
||||||
|
.wechat-symbol { font-size: 18px; font-weight: 700; color: #1A1A1A; margin-right: 8px; }
|
||||||
|
.btn-text { font-size: 17px; font-weight: 700; color: #1A1A1A; }
|
||||||
|
|
||||||
|
.agreement-row { display: flex; align-items: center; margin-top: 16px; }
|
||||||
|
.checkbox-wrapper { margin-right: 6px; }
|
||||||
|
.checkbox { width: 18px; height: 18px; border-radius: 50%; border: 2px solid #BDBDBD; display: flex; align-items: center; justify-content: center; }
|
||||||
|
.checkbox.checked { background: #00E676; border-color: #00E676; }
|
||||||
|
.check-mark { font-size: 12px; color: #1A1A1A; font-weight: 700; }
|
||||||
|
.agreement-text { font-size: 12px; color: #7A7E84; }
|
||||||
|
.link { color: #00C853; }
|
||||||
|
|
||||||
|
.other-login { margin-top: 60px; width: 100%; display: flex; flex-direction: column; align-items: center; }
|
||||||
|
.divider-text { font-size: 13px; color: #BDBDBD; margin-bottom: 20px; }
|
||||||
|
.other-icons { display: flex; }
|
||||||
|
.other-item { display: flex; flex-direction: column; align-items: center; }
|
||||||
|
.other-icon-circle { width: 48px; height: 48px; background: #FFFFFF; border-radius: 50%; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(0,0,0,0.06); }
|
||||||
|
.other-symbol { font-size: 22px; color: #7A7E84; }
|
||||||
|
.other-label { font-size: 12px; color: #7A7E84; }
|
||||||
|
|
||||||
|
.footer-tip { position: absolute; bottom: 60px; font-size: 12px; color: #BDBDBD; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
<template>
|
||||||
|
<view class="profile-page">
|
||||||
|
<view class="header-wrap" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
|
<view class="nav-bar" :style="{ height: navBarHeight + 'px' }">
|
||||||
|
<text class="nav-title">● 个人中心</text>
|
||||||
|
<text class="settings-symbol" @click="goToSettings">⚙</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="content" scroll-y :style="{ height: 'calc(100vh - ' + totalHeaderHeight + 'px)' }">
|
||||||
|
<view class="content-inner">
|
||||||
|
<view class="user-card">
|
||||||
|
<view class="user-row">
|
||||||
|
<view class="big-avatar"><text>J</text></view>
|
||||||
|
<view class="user-info">
|
||||||
|
<text class="user-name">{{ userInfo.nickname }}</text>
|
||||||
|
<view class="user-tag">
|
||||||
|
<text class="tag-symbol">★</text>
|
||||||
|
<text>{{ userInfo.membershipLevel }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<text class="edit-symbol" @click="editProfile">✎</text>
|
||||||
|
</view>
|
||||||
|
<view class="user-details">
|
||||||
|
<view class="detail-row">
|
||||||
|
<text class="detail-label">会员编号</text>
|
||||||
|
<text class="detail-value">{{ userInfo.memberNo }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="detail-row">
|
||||||
|
<text class="detail-label">手机号</text>
|
||||||
|
<text class="detail-value">{{ userInfo.phone }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="detail-row">
|
||||||
|
<text class="detail-label">性别</text>
|
||||||
|
<text class="detail-value">{{ userInfo.gender === 1 ? '男' : userInfo.gender === 2 ? '女' : '未设置' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="detail-row">
|
||||||
|
<text class="detail-label">生日</text>
|
||||||
|
<text class="detail-value">{{ userInfo.birthday || '未设置' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="stats-card">
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="stat-number">{{ userInfo.totalCourses }}</text>
|
||||||
|
<text class="stat-label">总课时</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-divider"></view>
|
||||||
|
<view class="stat-item">
|
||||||
|
<text class="stat-number">{{ userInfo.streakDays }}</text>
|
||||||
|
<text class="stat-label">连续打卡</text>
|
||||||
|
</view>
|
||||||
|
<view class="stat-divider"></view>
|
||||||
|
<view class="stat-item">
|
||||||
|
<view class="stat-rating-row">
|
||||||
|
<text class="stat-number">{{ userInfo.rating }}</text>
|
||||||
|
<text class="star-icon">★</text>
|
||||||
|
</view>
|
||||||
|
<text class="stat-label">评分</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="card-section">
|
||||||
|
<view class="section-title-row">
|
||||||
|
<text class="section-symbol">◆</text>
|
||||||
|
<text class="section-title">我的会员卡</text>
|
||||||
|
</view>
|
||||||
|
<scroll-view class="card-scroll" scroll-x>
|
||||||
|
<view v-for="(card, idx) in memberCards" :key="idx" class="member-card-item"
|
||||||
|
:class="'card-type-' + card.cardType">
|
||||||
|
<text class="card-name">{{ card.cardName }}</text>
|
||||||
|
<text class="card-type-label">{{ card.typeLabel }}</text>
|
||||||
|
<view class="card-details">
|
||||||
|
<text v-if="card.remainingTimes !== null" class="card-remain">剩余 <text class="card-remain-num">{{ card.remainingTimes }}</text> 次</text>
|
||||||
|
<text v-if="card.remainingAmount !== null" class="card-remain">余额 <text class="card-remain-num">{{ card.remainingAmount }}</text></text>
|
||||||
|
<text v-if="card.expireTime" class="card-expire">有效期至 {{ card.expireTime }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="card-status" :class="card.status">{{ card.statusLabel }}</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="menu-section">
|
||||||
|
<view class="menu-grid">
|
||||||
|
<view class="menu-item" v-for="(menu, idx) in menus" :key="idx" @click="handleMenuClick(menu.key)">
|
||||||
|
<text class="menu-symbol">{{ menu.symbol }}</text>
|
||||||
|
<text class="menu-label">{{ menu.label }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="sign-section">
|
||||||
|
<view class="sign-header">
|
||||||
|
<view class="section-title-row">
|
||||||
|
<text class="section-symbol">☰</text>
|
||||||
|
<text class="section-title">最近签到</text>
|
||||||
|
</view>
|
||||||
|
<text class="section-more" @click="viewAllSignIn">查看全部</text>
|
||||||
|
</view>
|
||||||
|
<view v-for="(record, idx) in signInRecords" :key="idx" class="sign-item">
|
||||||
|
<view class="sign-left">
|
||||||
|
<text class="sign-date">{{ record.date }}</text>
|
||||||
|
<text class="sign-time">{{ record.time }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="sign-right">
|
||||||
|
<text class="sign-type">{{ record.typeLabel }}</text>
|
||||||
|
<text class="sign-status" :class="record.status">{{ record.statusLabel }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="bottom-safe"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusBarHeight: 0,
|
||||||
|
navBarHeight: 44,
|
||||||
|
totalHeaderHeight: 44,
|
||||||
|
userInfo: { nickname: 'Jason Wang', membershipLevel: '高级会员', memberNo: 'MEM2024A7K3', phone: '138****8888', gender: 1, birthday: '1995-06-15', totalCourses: 68, streakDays: 12, rating: '4.8' },
|
||||||
|
memberCards: [{ cardName: '年卡 · 无限次', cardType: 'time', typeLabel: '时长卡', expireTime: '2027-06-15', status: 'active', statusLabel: '有效' }, { cardName: '储值卡 · 白金', cardType: 'stored', typeLabel: '储值卡', remainingAmount: 2580, expireTime: '2027-06-15', status: 'active', statusLabel: '有效' }, { cardName: '10次体验卡', cardType: 'count', typeLabel: '次卡', remainingTimes: 3, expireTime: '2026-12-31', status: 'active', statusLabel: '有效' }],
|
||||||
|
menus: [{ symbol: '☰', label: '训练数据', key: 'data' }, { symbol: '★', label: '成就徽章', key: 'achievement' }, { symbol: '⚙', label: '账户设置', key: 'settings' }, { symbol: '▤', label: '我的预约', key: 'booking' }, { symbol: '◆', label: '购卡记录', key: 'cardPurchase' }, { symbol: '?', label: '帮助中心', key: 'help' }],
|
||||||
|
signInRecords: [{ date: '07-15', time: '09:30', typeLabel: '扫码签到', status: 'success', statusLabel: '成功' }, { date: '07-14', time: '18:00', typeLabel: '扫码签到', status: 'success', statusLabel: '成功' }, { date: '07-13', time: '10:15', typeLabel: '手动签到', status: 'success', statusLabel: '成功' }, { date: '07-12', time: '08:45', typeLabel: '扫码签到', status: 'success', statusLabel: '成功' }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
const statusBarHeight = systemInfo.statusBarHeight || 20
|
||||||
|
let navBarHeight = 44
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect()
|
||||||
|
if (menuButton) {
|
||||||
|
navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.statusBarHeight = statusBarHeight
|
||||||
|
this.navBarHeight = navBarHeight
|
||||||
|
this.totalHeaderHeight = statusBarHeight + navBarHeight
|
||||||
|
},
|
||||||
|
methods: { editProfile() { uni.showToast({ title: '编辑资料', icon: 'none' }) }, goToSettings() { uni.showToast({ title: '设置页面', icon: 'none' }) }, handleMenuClick(key) { uni.showToast({ title: '功能: ' + key, icon: 'none' }) }, viewAllSignIn() { uni.showToast({ title: '全部签到记录', icon: 'none' }) } }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.profile-page { min-height: 100vh; background: #F5F7FA; overflow-x: hidden; }
|
||||||
|
.header-wrap { background: #1A1A1A; }
|
||||||
|
.nav-bar { background: #1A1A1A; padding: 0 20px; display: flex; justify-content: space-between; align-items: center; }
|
||||||
|
.nav-title { font-size: 18px; font-weight: 700; color: #FFFFFF; }
|
||||||
|
.settings-symbol { font-size: 20px; color: rgba(255,255,255,0.8); }
|
||||||
|
.content-inner { padding: 16px 16px 0; }
|
||||||
|
.user-card { background: #FFFFFF; border-radius: 20px; padding: 20px; margin-bottom: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); }
|
||||||
|
.user-row { display: flex; align-items: center; margin-bottom: 18px; }
|
||||||
|
.big-avatar { width: 56px; height: 56px; background: linear-gradient(135deg, #00E676, #00BFA5); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 24px; color: #1A1A1A; flex-shrink: 0; margin-right: 14px; }
|
||||||
|
.user-info { flex: 1; display: flex; flex-direction: column; }
|
||||||
|
.user-name { font-size: 18px; font-weight: 700; color: #1E1E1E; }
|
||||||
|
.user-tag { font-size: 13px; color: #00C853; font-weight: 500; display: flex; align-items: center; }
|
||||||
|
.tag-symbol { font-size: 12px; margin-right: 4px; }
|
||||||
|
.edit-symbol { font-size: 20px; color: #7A7E84; }
|
||||||
|
.user-details { background: #F5F7FA; border-radius: 12px; padding: 14px 16px; display: flex; flex-direction: column; }
|
||||||
|
.detail-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
|
||||||
|
.detail-label { font-size: 13px; color: #7A7E84; }
|
||||||
|
.detail-value { font-size: 14px; font-weight: 600; color: #1E1E1E; }
|
||||||
|
.stats-card { background: #1A1A1A; border-radius: 20px; padding: 18px 20px; display: flex; justify-content: space-around; margin-bottom: 16px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); }
|
||||||
|
.stat-item { display: flex; flex-direction: column; align-items: center; }
|
||||||
|
.stat-number { font-size: 24px; font-weight: 700; color: #00E676; }
|
||||||
|
.stat-label { font-size: 12px; color: rgba(255,255,255,0.6); margin-top: 4px; }
|
||||||
|
.stat-divider { width: 1px; background: rgba(255,255,255,0.15); }
|
||||||
|
.stat-rating-row { display: flex; align-items: center; }
|
||||||
|
.star-icon { font-size: 14px; color: #00E676; }
|
||||||
|
.card-section { margin-bottom: 16px; }
|
||||||
|
.section-title-row { display: flex; align-items: center; margin-bottom: 12px; }
|
||||||
|
.section-symbol { font-size: 16px; color: #00E676; margin-right: 8px; }
|
||||||
|
.section-title { font-size: 16px; font-weight: 700; color: #1E1E1E; }
|
||||||
|
.card-scroll { display: flex; white-space: nowrap; }
|
||||||
|
.member-card-item { display: inline-block; width: 200px; background: #FFFFFF; border-radius: 20px; padding: 16px; margin-right: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); position: relative; overflow: hidden; }
|
||||||
|
.member-card-item::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; }
|
||||||
|
.card-type-time::before { background: #00E676; }
|
||||||
|
.card-type-stored::before { background: linear-gradient(135deg, #FFA502, #FF6B4A); }
|
||||||
|
.card-type-count::before { background: #4A90D9; }
|
||||||
|
.card-name { font-size: 15px; font-weight: 700; color: #1E1E1E; display: block; margin-top: 4px; }
|
||||||
|
.card-type-label { font-size: 11px; color: #7A7E84; background: #F5F7FA; padding: 2px 8px; border-radius: 10px; margin-top: 4px; display: inline-block; }
|
||||||
|
.card-details { margin-top: 12px; display: flex; flex-direction: column; }
|
||||||
|
.card-remain { font-size: 13px; color: #7A7E84; }
|
||||||
|
.card-remain-num { font-size: 16px; font-weight: 700; color: #00C853; margin: 0 2px; }
|
||||||
|
.card-expire { font-size: 11px; color: #BDBDBD; }
|
||||||
|
.card-status { position: absolute; top: 12px; right: 12px; font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 20px; }
|
||||||
|
.card-status.active { background: rgba(0,230,118,0.15); color: #00C853; }
|
||||||
|
.menu-section { margin-bottom: 16px; }
|
||||||
|
.menu-grid { display: flex; flex-wrap: wrap; }
|
||||||
|
.menu-item { width: calc(33.33% - 8px); background: #FFFFFF; border-radius: 12px; padding: 16px 0; text-align: center; box-shadow: 0 4px 12px rgba(0,0,0,0.06); display: flex; flex-direction: column; align-items: center; margin-right: 12px; margin-bottom: 12px; }
|
||||||
|
.menu-symbol { font-size: 22px; color: #7A7E84; }
|
||||||
|
.menu-label { font-size: 13px; font-weight: 500; color: #7A7E84; }
|
||||||
|
.sign-section { margin-bottom: 16px; }
|
||||||
|
.sign-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
|
||||||
|
.sign-header .section-title-row { margin-bottom: 0; }
|
||||||
|
.section-more { font-size: 13px; color: #00C853; }
|
||||||
|
.sign-item { background: #FFFFFF; border-radius: 12px; padding: 12px 16px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); }
|
||||||
|
.sign-left { display: flex; flex-direction: column; }
|
||||||
|
.sign-date { font-size: 14px; font-weight: 600; color: #1E1E1E; }
|
||||||
|
.sign-time { font-size: 12px; color: #7A7E84; margin-top: 2px; }
|
||||||
|
.sign-right { display: flex; align-items: center; }
|
||||||
|
.sign-type { font-size: 12px; color: #7A7E84; margin-right: 10px; }
|
||||||
|
.sign-status { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 20px; }
|
||||||
|
.sign-status.success { background: rgba(0,230,118,0.15); color: #00C853; }
|
||||||
|
.bottom-safe { height: 50px; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
<template>
|
||||||
|
<view class="search-page">
|
||||||
|
<view class="header-wrap" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
|
<view class="nav-bar" :style="{ height: navBarHeight + 'px' }">
|
||||||
|
<text class="nav-title">⌕ 团课搜索</text>
|
||||||
|
</view>
|
||||||
|
<view class="search-area">
|
||||||
|
<view class="search-box">
|
||||||
|
<text class="search-symbol">⌕</text>
|
||||||
|
<input class="search-input" v-model="searchKeyword" placeholder="搜索课程名称、教练、场地..."
|
||||||
|
placeholder-style="color: rgba(255,255,255,0.35);" @input="onSearchInput" />
|
||||||
|
<text v-if="searchKeyword" class="clear-btn" @click="clearSearch">✕</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="date-range-row">
|
||||||
|
<view class="date-range-item" @click="openStartDatePicker">
|
||||||
|
<text class="range-label">开始</text>
|
||||||
|
<text class="range-value" :class="{ placeholder: !startDate }">{{ startDate || '选择日期' }}</text>
|
||||||
|
</view>
|
||||||
|
<text class="range-sep">至</text>
|
||||||
|
<view class="date-range-item" @click="openEndDatePicker">
|
||||||
|
<text class="range-label">结束</text>
|
||||||
|
<text class="range-value" :class="{ placeholder: !endDate }">{{ endDate || '选择日期' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="period-selector">
|
||||||
|
<text class="period-label">时段</text>
|
||||||
|
<scroll-view class="period-scroll" scroll-x>
|
||||||
|
<view v-for="(period, idx) in periods" :key="idx" class="period-item"
|
||||||
|
:class="{ active: currentPeriod === period.value }" @click="selectPeriod(period.value)">
|
||||||
|
<text class="period-symbol">{{ period.symbol }}</text>
|
||||||
|
<text>{{ period.label }}</text>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="filter-tabs" scroll-x>
|
||||||
|
<view class="filter-tabs-inner">
|
||||||
|
<view v-for="(tab, idx) in filterTabs" :key="idx" class="filter-tab"
|
||||||
|
:class="{ active: currentFilter === tab.value }" @click="switchFilter(tab.value)">
|
||||||
|
{{ tab.label }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<view class="sort-bar">
|
||||||
|
<text class="result-count">共 {{ filteredCourses.length }} 个课程</text>
|
||||||
|
<view class="sort-options">
|
||||||
|
<text v-for="(sort, idx) in sortOptions" :key="idx" class="sort-item"
|
||||||
|
:class="{ active: currentSort === sort.value }" @click="switchSort(sort.value)">
|
||||||
|
{{ sort.label }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<scroll-view class="course-list" scroll-y :style="{ height: 'calc(100vh - ' + totalHeaderHeight + 'px - 104px)' }">
|
||||||
|
<view class="course-list-inner">
|
||||||
|
<view v-for="(course, idx) in filteredCourses" :key="idx" class="course-card" @click="goToDetail(course)">
|
||||||
|
<view class="course-cover">
|
||||||
|
<text class="cover-text">{{ course.typeChar }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="course-body">
|
||||||
|
<text class="course-name">{{ course.courseName }}</text>
|
||||||
|
<view class="course-row">
|
||||||
|
<text class="course-coach">教练 {{ course.coachName }}</text>
|
||||||
|
<text class="course-difficulty" :class="'diff-' + course.difficultyLevel">{{ course.difficultyLabel }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="course-row">
|
||||||
|
<text class="course-time">日期 {{ course.startTime }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="course-row">
|
||||||
|
<text class="course-location">{{ course.location }}</text>
|
||||||
|
<text class="course-capacity">{{ course.currentMembers }}/{{ course.maxMembers }}人</text>
|
||||||
|
</view>
|
||||||
|
<view class="course-bottom">
|
||||||
|
<text class="course-price" :class="{ free: course.storedValueAmount === 0 }">
|
||||||
|
{{ course.storedValueAmount > 0 ? course.storedValueAmount + '元/次' : '免费' }}
|
||||||
|
</text>
|
||||||
|
<button class="btn-book" :class="{ disabled: course.isFull }" :disabled="course.isFull"
|
||||||
|
@click.stop="bookCourse(course)">
|
||||||
|
{{ course.isFull ? '已约满' : '预约' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="filteredCourses.length === 0" class="empty-state">
|
||||||
|
<text class="empty-symbol">⊙</text>
|
||||||
|
<text class="empty-text">暂无匹配的课程</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bottom-safe"></view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusBarHeight: 0,
|
||||||
|
navBarHeight: 44,
|
||||||
|
totalHeaderHeight: 44,
|
||||||
|
searchKeyword: '', startDate: '', endDate: '',
|
||||||
|
currentPeriod: 'all', currentFilter: 'all', currentSort: 'time',
|
||||||
|
periods: [
|
||||||
|
{ label: '全部', value: 'all', symbol: '◴' },
|
||||||
|
{ label: '早晨', value: 'morning', symbol: '☀' },
|
||||||
|
{ label: '上午', value: 'forenoon', symbol: '☀' },
|
||||||
|
{ label: '下午', value: 'afternoon', symbol: '☼' },
|
||||||
|
{ label: '晚间', value: 'evening', symbol: '☾' }
|
||||||
|
],
|
||||||
|
filterTabs: [
|
||||||
|
{ label: '全部', value: 'all' }, { label: '力量区', value: 'strength' },
|
||||||
|
{ label: '有氧', value: 'cardio' }, { label: '瑜伽', value: 'yoga' },
|
||||||
|
{ label: '私教', value: 'pt' }, { label: '团课', value: 'group' },
|
||||||
|
{ label: '免费', value: 'free' }
|
||||||
|
],
|
||||||
|
sortOptions: [
|
||||||
|
{ label: '时间', value: 'time' },
|
||||||
|
{ label: '难度', value: 'difficulty' },
|
||||||
|
{ label: '热度', value: 'popular' }
|
||||||
|
],
|
||||||
|
courses: [
|
||||||
|
{ id: 1, courseName: '综合力量训练', coachName: '张教练', location: '力量区', category: 'strength', typeChar: '力', startTime: '07-15 10:00', endTime: '07-15 10:45', maxMembers: 20, currentMembers: 8, isFull: false, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', period: 'forenoon', storedValueAmount: 0 },
|
||||||
|
{ id: 2, courseName: '流瑜伽 · 中级', coachName: '李教练', location: '3号教室', category: 'yoga', typeChar: '瑜', startTime: '07-15 14:00', endTime: '07-15 15:00', maxMembers: 15, currentMembers: 15, isFull: true, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', period: 'afternoon', storedValueAmount: 0 },
|
||||||
|
{ id: 3, courseName: '动感单车 · 冲刺', coachName: '王教练', location: '单车房', category: 'cardio', typeChar: '车', startTime: '07-15 18:00', endTime: '07-15 18:40', maxMembers: 25, currentMembers: 12, isFull: false, difficulty: 4, difficultyLevel: 'low', difficultyLabel: '入门', period: 'evening', storedValueAmount: 0 },
|
||||||
|
{ id: 4, courseName: 'HIIT训练', coachName: '赵教练', location: '多功能厅', category: 'cardio', typeChar: 'HI', startTime: '07-15 12:00', endTime: '07-15 12:30', maxMembers: 15, currentMembers: 10, isFull: false, difficulty: 7, difficultyLevel: 'high', difficultyLabel: '困难', period: 'forenoon', storedValueAmount: 0 },
|
||||||
|
{ id: 5, courseName: '普拉提', coachName: '李教练', location: '2号教室', category: 'yoga', typeChar: '普', startTime: '07-15 16:00', endTime: '07-15 16:50', maxMembers: 12, currentMembers: 5, isFull: false, difficulty: 4, difficultyLevel: 'low', difficultyLabel: '入门', period: 'afternoon', storedValueAmount: 0 },
|
||||||
|
{ id: 6, courseName: '搏击操', coachName: '刘教练', location: '搏击区', category: 'cardio', typeChar: '搏', startTime: '07-15 07:00', endTime: '07-15 07:45', maxMembers: 20, currentMembers: 6, isFull: false, difficulty: 5, difficultyLevel: 'mid', difficultyLabel: '中等', period: 'morning', storedValueAmount: 0 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
const systemInfo = uni.getSystemInfoSync()
|
||||||
|
const statusBarHeight = systemInfo.statusBarHeight || 20
|
||||||
|
let navBarHeight = 44
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect()
|
||||||
|
if (menuButton) {
|
||||||
|
navBarHeight = (menuButton.top - statusBarHeight) * 2 + menuButton.height
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.statusBarHeight = statusBarHeight
|
||||||
|
this.navBarHeight = navBarHeight
|
||||||
|
this.totalHeaderHeight = statusBarHeight + navBarHeight
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredCourses() {
|
||||||
|
let list = this.courses
|
||||||
|
if (this.searchKeyword) {
|
||||||
|
const kw = this.searchKeyword.toLowerCase()
|
||||||
|
list = list.filter(c => c.courseName.toLowerCase().includes(kw) || c.coachName.toLowerCase().includes(kw) || c.location.toLowerCase().includes(kw))
|
||||||
|
}
|
||||||
|
if (this.currentFilter === 'free') list = list.filter(c => c.storedValueAmount === 0)
|
||||||
|
else if (this.currentFilter !== 'all') list = list.filter(c => c.category === this.currentFilter)
|
||||||
|
if (this.currentPeriod !== 'all') list = list.filter(c => c.period === this.currentPeriod)
|
||||||
|
if (this.currentSort === 'difficulty') list = [...list].sort((a, b) => a.difficulty - b.difficulty)
|
||||||
|
else if (this.currentSort === 'popular') list = [...list].sort((a, b) => b.currentMembers - a.currentMembers)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onSearchInput() {},
|
||||||
|
clearSearch() { this.searchKeyword = '' },
|
||||||
|
openStartDatePicker() { uni.showToast({ title: '选择开始日期', icon: 'none' }) },
|
||||||
|
openEndDatePicker() { uni.showToast({ title: '选择结束日期', icon: 'none' }) },
|
||||||
|
selectPeriod(value) { this.currentPeriod = value },
|
||||||
|
switchFilter(value) { this.currentFilter = value },
|
||||||
|
switchSort(value) { this.currentSort = value },
|
||||||
|
goToDetail(course) { uni.navigateTo({ url: '/pages/course-detail/course-detail?id=' + course.id }) },
|
||||||
|
bookCourse(course) { if (!course.isFull) uni.navigateTo({ url: '/pages/course-detail/course-detail?id=' + course.id }) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-page { min-height: 100vh; background: #F5F7FA; overflow-x: hidden; }
|
||||||
|
.header-wrap { background: #1A1A1A; }
|
||||||
|
.nav-bar { background: #1A1A1A; padding: 0 20px; display: flex; align-items: center; }
|
||||||
|
.nav-title { font-size: 18px; font-weight: 700; color: #FFFFFF; }
|
||||||
|
|
||||||
|
.search-area { background: #1A1A1A; padding: 0 16px 20px; }
|
||||||
|
.search-box { background: rgba(255,255,255,0.12); border-radius: 40px; padding: 0 16px; display: flex; align-items: center; height: 42px; margin-bottom: 14px; }
|
||||||
|
.search-symbol { font-size: 15px; color: rgba(255,255,255,0.5); flex-shrink: 0; margin-right: 8px; }
|
||||||
|
.search-input { flex: 1; font-size: 14px; color: #FFFFFF; height: 100%; }
|
||||||
|
.clear-btn { font-size: 15px; color: rgba(255,255,255,0.5); padding: 4px; flex-shrink: 0; }
|
||||||
|
|
||||||
|
.date-range-row { display: flex; align-items: center; margin-bottom: 14px; }
|
||||||
|
.date-range-item { flex: 1; background: rgba(255,255,255,0.1); border-radius: 12px; padding: 10px 14px; margin-right: 10px; }
|
||||||
|
.range-label { font-size: 11px; color: rgba(255,255,255,0.5); display: block; margin-bottom: 2px; }
|
||||||
|
.range-value { font-size: 14px; font-weight: 600; color: #FFFFFF; }
|
||||||
|
.range-value.placeholder { color: rgba(255,255,255,0.35); font-weight: 400; }
|
||||||
|
.range-sep { color: rgba(255,255,255,0.5); font-size: 14px; flex-shrink: 0; margin-right: 10px; }
|
||||||
|
|
||||||
|
.period-selector { display: flex; align-items: center; }
|
||||||
|
.period-label { font-size: 13px; color: rgba(255,255,255,0.6); flex-shrink: 0; margin-right: 10px; }
|
||||||
|
.period-scroll { flex: 1; display: flex; white-space: nowrap; }
|
||||||
|
.period-item { display: inline-flex; align-items: center; padding: 6px 14px; border-radius: 40px; font-size: 13px; color: rgba(255,255,255,0.7); background: rgba(255,255,255,0.08); margin-right: 8px; }
|
||||||
|
.period-item.active { background: #00E676; color: #1A1A1A; font-weight: 600; }
|
||||||
|
.period-symbol { font-size: 13px; margin-right: 4px; }
|
||||||
|
|
||||||
|
.filter-tabs { background: #FFFFFF; display: flex; white-space: nowrap; border-bottom: 1px solid #EEEEEE; }
|
||||||
|
.filter-tabs-inner { padding: 14px 16px; display: flex; white-space: nowrap; }
|
||||||
|
.filter-tab { display: inline-block; padding: 6px 16px; border-radius: 40px; font-size: 13px; color: #7A7E84; background: #F5F7FA; margin-right: 8px; }
|
||||||
|
.filter-tab.active { background: #00E676; color: #1A1A1A; font-weight: 600; }
|
||||||
|
|
||||||
|
.sort-bar { display: flex; justify-content: space-between; align-items: center; padding: 10px 16px; background: #FFFFFF; border-bottom: 1px solid #EEEEEE; }
|
||||||
|
.result-count { font-size: 13px; color: #7A7E84; }
|
||||||
|
.sort-options { display: flex; }
|
||||||
|
.sort-item { font-size: 13px; color: #7A7E84; margin-right: 16px; }
|
||||||
|
.sort-item.active { color: #00C853; font-weight: 600; }
|
||||||
|
|
||||||
|
.course-list-inner { padding: 12px 16px 0; }
|
||||||
|
.course-card { background: #FFFFFF; border-radius: 20px; padding: 14px; margin-bottom: 12px; box-shadow: 0 4px 12px rgba(0,0,0,0.06); display: flex; }
|
||||||
|
.course-cover { width: 72px; height: 72px; border-radius: 12px; background: rgba(0,230,118,0.15); display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin-right: 14px; }
|
||||||
|
.cover-text { font-size: 24px; font-weight: 700; color: #00C853; }
|
||||||
|
.course-body { flex: 1; display: flex; flex-direction: column; }
|
||||||
|
.course-name { font-size: 16px; font-weight: 700; color: #1E1E1E; }
|
||||||
|
.course-row { display: flex; align-items: center; font-size: 12px; color: #7A7E84; }
|
||||||
|
.course-row > * { margin-right: 12px; }
|
||||||
|
.course-difficulty { padding: 1px 8px; border-radius: 20px; font-size: 11px; font-weight: 600; }
|
||||||
|
.diff-low { background: rgba(0,230,118,0.15); color: #00C853; }
|
||||||
|
.diff-mid { background: rgba(255,165,2,0.15); color: #FFA502; }
|
||||||
|
.diff-high { background: rgba(255,82,82,0.15); color: #FF5252; }
|
||||||
|
.course-bottom { display: flex; justify-content: space-between; align-items: center; margin-top: 4px; }
|
||||||
|
.course-price { font-size: 13px; font-weight: 600; color: #00C853; }
|
||||||
|
.course-price.free { color: #00C853; }
|
||||||
|
.btn-book { background: #00E676; color: #1A1A1A; border: none; padding: 6px 16px; border-radius: 40px; font-weight: 700; font-size: 13px; line-height: 1.4; box-shadow: 0 2px 6px rgba(0,230,118,0.3); }
|
||||||
|
.btn-book::after { border: none; }
|
||||||
|
.btn-book.disabled { background: #E0E0E0; color: #BDBDBD; box-shadow: none; }
|
||||||
|
|
||||||
|
.empty-state { display: flex; flex-direction: column; align-items: center; padding: 60px 0; }
|
||||||
|
.empty-symbol { font-size: 40px; color: #BDBDBD; }
|
||||||
|
.empty-text { font-size: 14px; color: #BDBDBD; }
|
||||||
|
.bottom-safe { height: 30px; }
|
||||||
|
</style>
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
const BASE_URL = 'http://localhost:8080/api'
|
|
||||||
|
|
||||||
export const request = (options) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
uni.request({
|
|
||||||
url: BASE_URL + options.url,
|
|
||||||
method: options.method || 'GET',
|
|
||||||
data: options.data || {},
|
|
||||||
header: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
...options.header
|
|
||||||
},
|
|
||||||
success: (res) => {
|
|
||||||
if (res.statusCode === 200) {
|
|
||||||
resolve(res.data)
|
|
||||||
} else {
|
|
||||||
reject(res)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
reject(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
request
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="container">
|
|
||||||
<text class="title">健身房管理系统</text>
|
|
||||||
<text class="subtitle">欢迎使用 UniApp 移动端</text>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
title: '健身房管理系统'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLoad() {
|
|
||||||
console.log('Index page loaded')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
font-size: 16px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import { createPinia } from 'pinia'
|
|
||||||
|
|
||||||
const pinia = createPinia()
|
|
||||||
|
|
||||||
export default pinia
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', {
|
|
||||||
state: () => ({
|
|
||||||
token: '',
|
|
||||||
userInfo: null
|
|
||||||
}),
|
|
||||||
|
|
||||||
getters: {
|
|
||||||
isLoggedIn: (state) => !!state.token
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
setToken(token) {
|
|
||||||
this.token = token
|
|
||||||
},
|
|
||||||
|
|
||||||
setUserInfo(userInfo) {
|
|
||||||
this.userInfo = userInfo
|
|
||||||
},
|
|
||||||
|
|
||||||
logout() {
|
|
||||||
this.token = ''
|
|
||||||
this.userInfo = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* ============================================================
|
||||||
|
* 健身房预约小程序 · 全局配色方案 (CSS Variables)
|
||||||
|
* ============================================================
|
||||||
|
*
|
||||||
|
* 主题风格:能量黑 + 荧光绿 + 科技灰
|
||||||
|
* 适用场景:健身/运动/预约类小程序或移动端H5
|
||||||
|
* 设计理念:硬核力量感 + 现代科技感 + 清晰易用
|
||||||
|
*
|
||||||
|
* 使用方式:在项目入口文件中引入本文件,或在 :root 中复制变量
|
||||||
|
* 示例:color: var(--primary); background: var(--bg-primary);
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* ==========================================================
|
||||||
|
1. 品牌主色 (Primary) —— 荧光绿 / 能量绿
|
||||||
|
用于核心操作按钮、选中状态、品牌高亮
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 主色:明亮荧光绿,代表活力与健康指标 */
|
||||||
|
--primary: #00E676;
|
||||||
|
|
||||||
|
/** 主色按压态:用于按钮点击、加载进度条等反馈 */
|
||||||
|
--primary-dark: #00C853;
|
||||||
|
|
||||||
|
/** 主色浅色背景:用于标签、选中态背景、轻量高亮 (半透明) */
|
||||||
|
--primary-light: rgba(0, 230, 118, 0.15);
|
||||||
|
|
||||||
|
/** 主色渐变终点:用于数据卡片、图表渐变的辅助色 (蓝绿) */
|
||||||
|
--primary-gradient-end: #00BFA5;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
2. 中性色 (Neutral) —— 深色/灰色/白色
|
||||||
|
用于背景、文字、分割线等基础界面
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 深空黑:顶部导航、底部TabBar、卡片深色背景 */
|
||||||
|
--secondary: #1A1A1A;
|
||||||
|
|
||||||
|
/** 全局背景色:浅灰,使主色更突出,视觉干净 */
|
||||||
|
--bg-primary: #F5F7FA;
|
||||||
|
|
||||||
|
/** 纯白色:卡片、浮层、按钮文字 */
|
||||||
|
--white: #FFFFFF;
|
||||||
|
|
||||||
|
/** 深灰色:用于重要标题、用户名等主要文字 */
|
||||||
|
--text-primary: #1E1E1E;
|
||||||
|
|
||||||
|
/** 中灰色:用于次要描述、场馆地址、日期等辅助文字 */
|
||||||
|
--text-secondary: #7A7E84;
|
||||||
|
|
||||||
|
/** 浅灰色:用于禁用状态文字、占位符 */
|
||||||
|
--text-disabled: #BDBDBD;
|
||||||
|
|
||||||
|
/** 极浅灰:分割线、边框、轻量背景区分 */
|
||||||
|
--border-light: #EEEEEE;
|
||||||
|
|
||||||
|
/** 卡片阴影:轻度投影,提升层次感 */
|
||||||
|
--shadow-card: 0 4px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
3. 功能色 (Functional) —— 反馈/状态/警告
|
||||||
|
用于提示、错误、成功等交互反馈
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 高亮警告红:未读消息红点、取消预约、倒计时、危险操作 */
|
||||||
|
--highlight: #FF5252;
|
||||||
|
|
||||||
|
/** 成功状态:通常复用主色,但独立定义便于统一调整 */
|
||||||
|
--success: var(--primary);
|
||||||
|
|
||||||
|
/** 禁用/不可用状态:背景色和文字色 */
|
||||||
|
--disabled-bg: #E0E0E0;
|
||||||
|
--disabled-text: #BDBDBD;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
4. 圆角 & 尺寸 (Radius & Size)
|
||||||
|
便于统一界面风格
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 大圆角:卡片、弹窗、主要容器 */
|
||||||
|
--radius-large: 20px;
|
||||||
|
|
||||||
|
/** 中圆角:按钮、输入框、次级卡片 */
|
||||||
|
--radius-medium: 12px;
|
||||||
|
|
||||||
|
/** 小圆角:标签、头像、小元素 */
|
||||||
|
--radius-small: 8px;
|
||||||
|
|
||||||
|
/** 全圆角:胶囊按钮、标签 */
|
||||||
|
--radius-full: 40px;
|
||||||
|
|
||||||
|
/** 底部TabBar高度 */
|
||||||
|
--tab-height: 72px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* ============================================================
|
||||||
|
* 健身房预约小程序 · 珊瑚橙配色方案 (CSS Variables)
|
||||||
|
* ============================================================
|
||||||
|
*
|
||||||
|
* 主题风格:珊瑚橙 (Coral Orange)
|
||||||
|
* 主色:温暖珊瑚橙 + 柔和米白
|
||||||
|
* 性格:亲切、阳光、活力、温暖
|
||||||
|
* 适用场景:轻运动、瑜伽、女性友好、社区型健身房
|
||||||
|
*
|
||||||
|
* 使用方式:在项目入口文件中引入本文件,或在 :root 中复制变量
|
||||||
|
* 示例:color: var(--primary); background: var(--bg-primary);
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* ==========================================================
|
||||||
|
1. 品牌主色 (Primary) —— 珊瑚橙 / 暖橙渐变
|
||||||
|
用于核心操作按钮、品牌高亮、渐变背景
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 主色:温暖珊瑚橙,代表活力与亲切感 */
|
||||||
|
--primary: #FF6B4A;
|
||||||
|
|
||||||
|
/** 主色按压态:深橙,用于按钮点击反馈 */
|
||||||
|
--primary-dark: #E55A3A;
|
||||||
|
|
||||||
|
/** 主色浅色背景:半透明橙,用于标签、选中态背景 */
|
||||||
|
--primary-light: rgba(255, 107, 74, 0.15);
|
||||||
|
|
||||||
|
/** 主色渐变:珊瑚橙到浅橙红,用于导航栏、欢迎卡片、按钮 */
|
||||||
|
--primary-gradient: linear-gradient(135deg, #FF6B4A, #FF8A65);
|
||||||
|
|
||||||
|
/** 渐变辅助色:用于数据卡片或图表的渐变更丰富 */
|
||||||
|
--primary-gradient-start: #FF6B4A;
|
||||||
|
--primary-gradient-end: #FF8A65;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
2. 中性色 (Neutral) —— 暖色系/米白/暖灰
|
||||||
|
用于背景、文字、分割线等基础界面
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 暖棕黑:底部TabBar、导航栏背景、重要文字 */
|
||||||
|
--secondary: #2D1F1A;
|
||||||
|
|
||||||
|
/** 全局背景色:暖白米色,营造温馨舒适感 */
|
||||||
|
--bg-primary: #FDF8F5;
|
||||||
|
|
||||||
|
/** 纯白色:卡片、浮层、按钮文字 */
|
||||||
|
--white: #FFFFFF;
|
||||||
|
|
||||||
|
/** 暖棕黑:用于重要标题、用户名等主要文字 */
|
||||||
|
--text-primary: #2D1F1A;
|
||||||
|
|
||||||
|
/** 暖灰色:用于次要描述、场馆地址、日期等辅助文字 */
|
||||||
|
--text-secondary: #8A7A72;
|
||||||
|
|
||||||
|
/** 浅暖灰:用于禁用状态文字、占位符 */
|
||||||
|
--text-disabled: #C5B5AD;
|
||||||
|
|
||||||
|
/** 暖色分割线:用于列表、卡片分割 */
|
||||||
|
--border-light: #F0E8E3;
|
||||||
|
|
||||||
|
/** 卡片阴影:带有橙色调的轻度投影 */
|
||||||
|
--shadow-card: 0 4px 16px rgba(255, 107, 74, 0.12);
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
3. 功能色 (Functional) —— 反馈/状态/警告
|
||||||
|
用于提示、错误、成功等交互反馈
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 高亮警告红:未读消息红点、取消预约、危险操作 */
|
||||||
|
--highlight: #FF4757;
|
||||||
|
|
||||||
|
/** 成功状态:翠绿色,用于完成、通过等正向反馈 */
|
||||||
|
--success: #2ED573;
|
||||||
|
|
||||||
|
/** 警告状态:琥珀色,用于提醒、注意 */
|
||||||
|
--warning: #FFA502;
|
||||||
|
|
||||||
|
/** 信息状态:淡蓝色,用于一般提示 */
|
||||||
|
--info: #4A90D9;
|
||||||
|
|
||||||
|
/** 禁用/不可用状态:背景色和文字色 */
|
||||||
|
--disabled-bg: #F0E8E3;
|
||||||
|
--disabled-text: #C5B5AD;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
4. 圆角 & 尺寸 (Radius & Size)
|
||||||
|
便于统一界面风格
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 大圆角:卡片、弹窗、主要容器 */
|
||||||
|
--radius-large: 20px;
|
||||||
|
|
||||||
|
/** 中圆角:按钮、输入框、次级卡片 */
|
||||||
|
--radius-medium: 12px;
|
||||||
|
|
||||||
|
/** 小圆角:标签、头像、小元素 */
|
||||||
|
--radius-small: 8px;
|
||||||
|
|
||||||
|
/** 全圆角:胶囊按钮、标签、头像 */
|
||||||
|
--radius-full: 40px;
|
||||||
|
|
||||||
|
/** 底部TabBar高度 */
|
||||||
|
--tab-height: 72px;
|
||||||
|
|
||||||
|
/** 导航栏高度 */
|
||||||
|
--nav-height: 56px;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
5. 额外辅助变量 (Extra Utilities)
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 主色文字颜色 (通常为白色) */
|
||||||
|
--primary-text-color: #FFFFFF;
|
||||||
|
|
||||||
|
/** 渐变背景的文本颜色 (通常为白色) */
|
||||||
|
--gradient-text-color: #FFFFFF;
|
||||||
|
|
||||||
|
/** 卡片内边距 (统一) */
|
||||||
|
--card-padding: 16px;
|
||||||
|
|
||||||
|
/** 页面左右安全间距 */
|
||||||
|
--page-padding: 16px;
|
||||||
|
|
||||||
|
/** 字体家族 */
|
||||||
|
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/**
|
||||||
|
* ============================================================
|
||||||
|
* 健身房预约小程序 · 极光紫配色方案 (CSS Variables)
|
||||||
|
* ============================================================
|
||||||
|
*
|
||||||
|
* 主题风格:极光紫 (Aurora Purple)
|
||||||
|
* 主色:深邃紫罗兰 + 霓虹蓝紫渐变
|
||||||
|
* 性格:科技感、神秘、高级、时尚
|
||||||
|
* 适用场景:高端健身、时尚运动、科技感预约类小程序
|
||||||
|
*
|
||||||
|
* 使用方式:在项目入口文件中引入本文件,或在 :root 中复制变量
|
||||||
|
* 示例:color: var(--primary); background: var(--bg-primary);
|
||||||
|
* ============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
/* ==========================================================
|
||||||
|
1. 品牌主色 (Primary) —— 极光紫 / 蓝紫渐变
|
||||||
|
用于核心操作按钮、品牌高亮、渐变背景
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 主色:深邃紫罗兰,代表神秘与高级感 */
|
||||||
|
--primary: #7C3AED;
|
||||||
|
|
||||||
|
/** 主色按压态:深紫,用于按钮点击反馈 */
|
||||||
|
--primary-dark: #5B21B6;
|
||||||
|
|
||||||
|
/** 主色浅色背景:半透明紫,用于标签、选中态背景 */
|
||||||
|
--primary-light: rgba(124, 58, 237, 0.15);
|
||||||
|
|
||||||
|
/** 主色渐变:紫罗兰到靛蓝,用于导航栏、欢迎卡片、按钮 */
|
||||||
|
--primary-gradient: linear-gradient(135deg, #7C3AED, #4F46E5);
|
||||||
|
|
||||||
|
/** 渐变辅助色:用于数据卡片或图表的渐变更丰富 */
|
||||||
|
--primary-gradient-start: #7C3AED;
|
||||||
|
--primary-gradient-end: #4F46E5;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
2. 中性色 (Neutral) —— 深色/灰色/白色
|
||||||
|
用于背景、文字、分割线等基础界面
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 深紫黑:底部TabBar、导航栏背景、重要文字 */
|
||||||
|
--secondary: #1E1028;
|
||||||
|
|
||||||
|
/** 全局背景色:极浅灰紫,营造柔和科技感 */
|
||||||
|
--bg-primary: #F8F7FC;
|
||||||
|
|
||||||
|
/** 纯白色:卡片、浮层、按钮文字 */
|
||||||
|
--white: #FFFFFF;
|
||||||
|
|
||||||
|
/** 深紫黑:用于重要标题、用户名等主要文字 */
|
||||||
|
--text-primary: #1E1028;
|
||||||
|
|
||||||
|
/** 紫灰色:用于次要描述、场馆地址、日期等辅助文字 */
|
||||||
|
--text-secondary: #6B5E7E;
|
||||||
|
|
||||||
|
/** 浅灰紫:用于禁用状态文字、占位符 */
|
||||||
|
--text-disabled: #B8AED0;
|
||||||
|
|
||||||
|
/** 浅紫分割线:用于列表、卡片分割 */
|
||||||
|
--border-light: #EDE9F5;
|
||||||
|
|
||||||
|
/** 卡片阴影:带有紫色调的轻度投影 */
|
||||||
|
--shadow-card: 0 4px 16px rgba(94, 48, 176, 0.10);
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
3. 功能色 (Functional) —— 反馈/状态/警告
|
||||||
|
用于提示、错误、成功等交互反馈
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 高亮警告红:未读消息红点、取消预约、危险操作 */
|
||||||
|
--highlight: #EF4444;
|
||||||
|
|
||||||
|
/** 成功状态:翠绿色,用于完成、通过等正向反馈 */
|
||||||
|
--success: #10B981;
|
||||||
|
|
||||||
|
/** 警告状态:琥珀色,用于提醒、注意 */
|
||||||
|
--warning: #F59E0B;
|
||||||
|
|
||||||
|
/** 信息状态:淡蓝色,用于一般提示 */
|
||||||
|
--info: #3B82F6;
|
||||||
|
|
||||||
|
/** 禁用/不可用状态:背景色和文字色 */
|
||||||
|
--disabled-bg: #E8E3F0;
|
||||||
|
--disabled-text: #B8AED0;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
4. 圆角 & 尺寸 (Radius & Size)
|
||||||
|
便于统一界面风格
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 大圆角:卡片、弹窗、主要容器 */
|
||||||
|
--radius-large: 20px;
|
||||||
|
|
||||||
|
/** 中圆角:按钮、输入框、次级卡片 */
|
||||||
|
--radius-medium: 12px;
|
||||||
|
|
||||||
|
/** 小圆角:标签、头像、小元素 */
|
||||||
|
--radius-small: 8px;
|
||||||
|
|
||||||
|
/** 全圆角:胶囊按钮、标签、头像 */
|
||||||
|
--radius-full: 40px;
|
||||||
|
|
||||||
|
/** 底部TabBar高度 */
|
||||||
|
--tab-height: 72px;
|
||||||
|
|
||||||
|
/** 导航栏高度 */
|
||||||
|
--nav-height: 56px;
|
||||||
|
|
||||||
|
/* ==========================================================
|
||||||
|
5. 额外辅助变量 (Extra Utilities)
|
||||||
|
========================================================== */
|
||||||
|
|
||||||
|
/** 主色文字颜色 (通常为白色) */
|
||||||
|
--primary-text-color: #FFFFFF;
|
||||||
|
|
||||||
|
/** 渐变背景的文本颜色 (通常为白色) */
|
||||||
|
--gradient-text-color: #FFFFFF;
|
||||||
|
|
||||||
|
/** 卡片内边距 (统一) */
|
||||||
|
--card-padding: 16px;
|
||||||
|
|
||||||
|
/** 页面左右安全间距 */
|
||||||
|
--page-padding: 16px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
uni.addInterceptor({
|
||||||
|
returnValue (res) {
|
||||||
|
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
res.then((res) => {
|
||||||
|
if (!res) return resolve(res)
|
||||||
|
return res[0] ? reject(res[0]) : resolve(res[1])
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* 这里是uni-app内置的常用样式变量
|
||||||
|
*
|
||||||
|
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||||
|
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||||
|
*
|
||||||
|
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 颜色变量 */
|
||||||
|
|
||||||
|
/* 行为相关颜色 */
|
||||||
|
$uni-color-primary: #007aff;
|
||||||
|
$uni-color-success: #4cd964;
|
||||||
|
$uni-color-warning: #f0ad4e;
|
||||||
|
$uni-color-error: #dd524d;
|
||||||
|
|
||||||
|
/* 文字基本颜色 */
|
||||||
|
$uni-text-color:#333;//基本色
|
||||||
|
$uni-text-color-inverse:#fff;//反色
|
||||||
|
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||||
|
$uni-text-color-placeholder: #808080;
|
||||||
|
$uni-text-color-disable:#c0c0c0;
|
||||||
|
|
||||||
|
/* 背景颜色 */
|
||||||
|
$uni-bg-color:#ffffff;
|
||||||
|
$uni-bg-color-grey:#f8f8f8;
|
||||||
|
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||||
|
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||||
|
|
||||||
|
/* 边框颜色 */
|
||||||
|
$uni-border-color:#c8c7cc;
|
||||||
|
|
||||||
|
/* 尺寸变量 */
|
||||||
|
|
||||||
|
/* 文字尺寸 */
|
||||||
|
$uni-font-size-sm:12px;
|
||||||
|
$uni-font-size-base:14px;
|
||||||
|
$uni-font-size-lg:16px;
|
||||||
|
|
||||||
|
/* 图片尺寸 */
|
||||||
|
$uni-img-size-sm:20px;
|
||||||
|
$uni-img-size-base:26px;
|
||||||
|
$uni-img-size-lg:40px;
|
||||||
|
|
||||||
|
/* Border Radius */
|
||||||
|
$uni-border-radius-sm: 2px;
|
||||||
|
$uni-border-radius-base: 3px;
|
||||||
|
$uni-border-radius-lg: 6px;
|
||||||
|
$uni-border-radius-circle: 50%;
|
||||||
|
|
||||||
|
/* 水平间距 */
|
||||||
|
$uni-spacing-row-sm: 5px;
|
||||||
|
$uni-spacing-row-base: 10px;
|
||||||
|
$uni-spacing-row-lg: 15px;
|
||||||
|
|
||||||
|
/* 垂直间距 */
|
||||||
|
$uni-spacing-col-sm: 4px;
|
||||||
|
$uni-spacing-col-base: 8px;
|
||||||
|
$uni-spacing-col-lg: 12px;
|
||||||
|
|
||||||
|
/* 透明度 */
|
||||||
|
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||||
|
|
||||||
|
/* 文章场景相关 */
|
||||||
|
$uni-color-title: #2C405A; // 文章标题颜色
|
||||||
|
$uni-font-size-title:20px;
|
||||||
|
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||||
|
$uni-font-size-subtitle:26px;
|
||||||
|
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||||
|
$uni-font-size-paragraph:15px;
|
||||||
Reference in New Issue
Block a user