369 lines
8.2 KiB
Vue
369 lines
8.2 KiB
Vue
<script>
|
|
import { loadCourseStatuses } from '@/utils/index.js'
|
|
|
|
export default {
|
|
onLaunch: function() {
|
|
console.log('Coach App Launch')
|
|
// 从后端加载课程状态映射(避免硬编码)
|
|
loadCourseStatuses()
|
|
},
|
|
onShow: function() {
|
|
console.log('Coach App Show')
|
|
},
|
|
onHide: function() {
|
|
console.log('Coach App Hide')
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
/* ============================================
|
|
全局样式 - 基于 gym-manage-cuit 风格适配手机端
|
|
============================================ */
|
|
|
|
page {
|
|
background-color: #f6f8fc;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
color: #1e293b;
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
view, text, input, button, image, scroll-view {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* ============================================
|
|
页面进入动画
|
|
============================================ */
|
|
.page-enter {
|
|
opacity: 0;
|
|
transform: translateY(12px);
|
|
animation: pageSlideIn 0.35s ease-out forwards;
|
|
}
|
|
|
|
@keyframes pageSlideIn {
|
|
0% { opacity: 0; transform: translateY(12px); }
|
|
100% { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
/* ============================================
|
|
通用卡片
|
|
============================================ */
|
|
.card {
|
|
background: #ffffff;
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
margin: 12px 16px;
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
|
animation: cardFadeIn 0.4s ease-out both;
|
|
}
|
|
|
|
@keyframes cardFadeIn {
|
|
from { opacity: 0; transform: translateY(8px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
/* ============================================
|
|
通用按钮
|
|
============================================ */
|
|
.btn-primary {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: linear-gradient(145deg, #4f7cff, #3b5fd9);
|
|
color: #ffffff;
|
|
border: none;
|
|
border-radius: 10px;
|
|
padding: 12px 24px;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.btn-primary::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(135deg, rgba(255,255,255,0.15) 0%, transparent 60%);
|
|
opacity: 0;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.btn-primary:active::after { opacity: 1; }
|
|
|
|
.btn-primary:active {
|
|
transform: scale(0.97);
|
|
}
|
|
|
|
.btn-outline {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #ffffff;
|
|
color: #4f7cff;
|
|
border: 1px solid #4f7cff;
|
|
border-radius: 10px;
|
|
padding: 10px 20px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
.btn-outline:active {
|
|
background: #eef3ff;
|
|
transform: scale(0.97);
|
|
}
|
|
|
|
/* ============================================
|
|
按钮加载 Spinner
|
|
============================================ */
|
|
@keyframes btnSpin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
|
|
.btn-spinner {
|
|
display: inline-block;
|
|
width: 18px;
|
|
height: 18px;
|
|
border: 2px solid rgba(255,255,255,0.3);
|
|
border-top-color: #ffffff;
|
|
border-radius: 50%;
|
|
animation: btnSpin 0.6s linear infinite;
|
|
margin-right: 8px;
|
|
}
|
|
|
|
/* ============================================
|
|
标签
|
|
============================================ */
|
|
.tag {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 2px 10px;
|
|
border-radius: 20px;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
transition: all 0.25s ease;
|
|
}
|
|
|
|
.tag-green { background: #e6f7ee; color: #10b981; }
|
|
.tag-orange { background: #fff7ed; color: #f59e0b; }
|
|
.tag-blue { background: #eef3ff; color: #4f7cff; }
|
|
.tag-gray { background: #f1f5f9; color: #94a3b8; }
|
|
|
|
/* ============================================
|
|
骨架屏
|
|
============================================ */
|
|
@keyframes skeletonShimmer {
|
|
0% { background-position: -200% 0; }
|
|
100% { background-position: 200% 0; }
|
|
}
|
|
|
|
.skeleton {
|
|
background: linear-gradient(90deg, #f0f3f8 25%, #e2e8f0 50%, #f0f3f8 75%);
|
|
background-size: 200% 100%;
|
|
animation: skeletonShimmer 1.5s ease-in-out infinite;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
@keyframes skeletonPulse {
|
|
0%, 100% { opacity: 1; }
|
|
50% { opacity: 0.5; }
|
|
}
|
|
|
|
.skeleton-pulse {
|
|
animation: skeletonPulse 1.5s ease-in-out infinite;
|
|
}
|
|
|
|
/* 骨架屏行 */
|
|
.sk-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 16px;
|
|
background: #ffffff;
|
|
border-radius: 12px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.sk-circle {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.sk-line {
|
|
height: 14px;
|
|
border-radius: 7px;
|
|
}
|
|
|
|
.sk-line-short { width: 60%; }
|
|
.sk-line-medium { width: 80%; }
|
|
.sk-line-long { width: 100%; }
|
|
.sk-line-sm { height: 10px; border-radius: 5px; }
|
|
|
|
/* ============================================
|
|
空状态
|
|
============================================ */
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 48px 24px;
|
|
color: #94a3b8;
|
|
animation: emptyFadeIn 0.5s ease-out both;
|
|
}
|
|
|
|
@keyframes emptyFadeIn {
|
|
from { opacity: 0; transform: scale(0.95); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
|
|
.empty-state text {
|
|
font-size: 14px;
|
|
margin-top: 12px;
|
|
}
|
|
|
|
/* ============================================
|
|
脉冲圆点
|
|
============================================ */
|
|
@keyframes dotPulse {
|
|
0%, 100% { transform: scale(0.6); opacity: 0.4; }
|
|
50% { transform: scale(1); opacity: 1; }
|
|
}
|
|
|
|
.dot-pulse {
|
|
display: inline-block;
|
|
width: 8px;
|
|
height: 8px;
|
|
border-radius: 50%;
|
|
background: #4f7cff;
|
|
animation: dotPulse 1s ease-in-out infinite;
|
|
}
|
|
|
|
.dot-pulse:nth-child(2) { animation-delay: 0.2s; }
|
|
.dot-pulse:nth-child(3) { animation-delay: 0.4s; }
|
|
|
|
/* ============================================
|
|
列表交错入场
|
|
============================================ */
|
|
@keyframes listItemIn {
|
|
from { opacity: 0; transform: translateX(-10px); }
|
|
to { opacity: 1; transform: translateX(0); }
|
|
}
|
|
|
|
.list-item-enter {
|
|
animation: listItemIn 0.35s ease-out both;
|
|
}
|
|
|
|
/* ============================================
|
|
数字跳动
|
|
============================================ */
|
|
@keyframes numberPop {
|
|
0% { transform: scale(1); }
|
|
50% { transform: scale(1.15); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
.number-animate {
|
|
animation: numberPop 0.5s ease-out;
|
|
}
|
|
|
|
/* ============================================
|
|
加载中
|
|
============================================ */
|
|
@keyframes loadingDot {
|
|
0%, 80%, 100% { transform: scale(0); opacity: 0; }
|
|
40% { transform: scale(1); opacity: 1; }
|
|
}
|
|
|
|
.loading-dots {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
justify-content: center;
|
|
padding: 32px;
|
|
}
|
|
|
|
.loading-dot {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
background: #4f7cff;
|
|
animation: loadingDot 1.2s ease-in-out infinite;
|
|
}
|
|
|
|
.loading-dot:nth-child(2) { animation-delay: 0.15s; }
|
|
.loading-dot:nth-child(3) { animation-delay: 0.3s; }
|
|
|
|
.loading-center {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 32px;
|
|
color: #94a3b8;
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* ============================================
|
|
弹性缩放
|
|
============================================ */
|
|
@keyframes elasticIn {
|
|
0% { transform: scale(0.3); opacity: 0; }
|
|
50% { transform: scale(1.05); }
|
|
70% { transform: scale(0.95); }
|
|
100% { transform: scale(1); opacity: 1; }
|
|
}
|
|
|
|
.elastic-in {
|
|
animation: elasticIn 0.5s ease-out both;
|
|
}
|
|
|
|
/* ============================================
|
|
淡入
|
|
============================================ */
|
|
@keyframes fadeInUp {
|
|
from { opacity: 0; transform: translateY(16px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.fade-in-up {
|
|
animation: fadeInUp 0.4s ease-out both;
|
|
}
|
|
|
|
/* ============================================
|
|
安全区适配
|
|
============================================ */
|
|
.safe-area-bottom {
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
}
|
|
|
|
/* 分隔线 */
|
|
.divider {
|
|
height: 1px;
|
|
background: #e9edf4;
|
|
margin: 12px 0;
|
|
}
|
|
|
|
/* 文本省略 */
|
|
.text-ellipsis {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* ============================================
|
|
flex 工具
|
|
============================================ */
|
|
.flex-row { display: flex; flex-direction: row; align-items: center; }
|
|
.flex-between { display: flex; flex-direction: row; align-items: center; justify-content: space-between; }
|
|
.flex-center { display: flex; align-items: center; justify-content: center; }
|
|
.flex-1 { flex: 1; }
|
|
</style>
|