| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- <template>
- <view class="badge-page">
- <!-- 顶部段位横幅 -->
- <view class="grade-banner" :style="{ backgroundColor: gradeColor }">
- <view class="grade-info">
- <text class="grade-title">{{ gradeText }}</text>
- <text class="grade-sub">{{ gradeSubText }}</text>
- </view>
- <view class="grade-progress">
- <text class="progress-text">已获得 {{ earnedCount }}/32</text>
- </view>
- </view>
- <!-- 徽章分区 -->
- <view class="badge-section" v-for="(group, gIdx) in badgeGroups" :key="gIdx">
- <view class="section-header">
- <text class="section-title">{{ group.title }}</text>
- </view>
- <view class="badge-grid">
- <view
- class="badge-card"
- v-for="(badge, bIdx) in group.list"
- :key="bIdx"
- @click="handleBadgeClick(badge)"
- :style="badge.earned ? 'background-color:' + badge.color : ''"
- >
- <view class="badge-content">
- <text class="badge-icon" :class="badge.earned ? 'icon-earned' : ''">{{ badge.earned ? '✓' : '🔒' }}</text>
- <text class="badge-name" :class="badge.earned ? 'name-earned' : ''">{{ badge.name }}</text>
- </view>
- </view>
- </view>
- </view>
-
- <view class="footer-space"></view>
- </view>
- </template>
- <script>
- import { getMyBadges } from '@/utils/api.js'
- export default {
- data() {
- return {
- loading: true,
- grade: null,
- earnedCount: 0,
- badges: [],
- gradeColorMap: {
- novice: '#94A3B8',
- starter: '#7C3AED',
- expert: '#F59E0B',
- system: '#14B8A6',
- lecturer: '#F97316'
- },
- categoryMap: {
- module: '模块徽章',
- course: '课程徽章',
- skill: '技能徽章',
- milestone: '里程碑',
- lecturer: '讲师荣誉'
- }
- }
- },
- computed: {
- gradeColor() {
- if (!this.grade || !this.grade.key) return '#CBD5E1'
- return this.gradeColorMap[this.grade.key] || '#CBD5E1'
- },
- gradeText() {
- if (!this.grade || !this.grade.name) return '未入门'
- return this.grade.name
- },
- gradeSubText() {
- if (!this.grade) return '参加沙龙开启成长之旅'
- return '持续探索,攀登更高峰'
- },
- badgeGroups() {
- var groups = []
- var cats = ['module', 'course', 'skill', 'milestone', 'lecturer']
- for (var i = 0; i < cats.length; i++) {
- var cat = cats[i]
- var list = this.badges.filter(function(b) {
- return b.category === cat
- })
- if (list.length > 0) {
- groups.push({
- title: this.categoryMap[cat] || cat,
- list: list
- })
- }
- }
- return groups
- }
- },
- onLoad() {
- this.fetchBadges()
- },
- methods: {
- fetchBadges() {
- var self = this
- self.loading = true
- getMyBadges().then(function(resp) {
- var data = resp.data || {}
- self.grade = data.grade || null
- self.earnedCount = data.earnedCount || 0
- self.badges = data.badges || []
- }).catch(function(err) {
- uni.showToast({
- title: (err && err.message) || '加载失败',
- icon: 'none'
- })
- }).finally(function() {
- self.loading = false
- })
- },
- handleBadgeClick(badge) {
- if (badge.earned) {
- uni.showToast({
- title: '已获得',
- icon: 'success'
- })
- } else {
- uni.showModal({
- title: '获得条件',
- content: badge.condition || '暂无条件说明',
- showCancel: false
- })
- }
- }
- }
- }
- </script>
- <style scoped>
- .badge-page {
- min-height: 100vh;
- background: #F8FAFC;
- padding: 32rpx;
- }
- .grade-banner {
- border-radius: 24rpx;
- padding: 48rpx 32rpx;
- display: flex;
- justify-content: space-between;
- align-items: center;
- color: #FFF;
- margin-bottom: 40rpx;
- box-shadow: 0 8rpx 24rpx rgba(0,0,0,0.1);
- }
- .grade-info {
- display: flex;
- flex-direction: column;
- }
- .grade-title {
- font-size: 44rpx;
- font-weight: 700;
- margin-bottom: 8rpx;
- }
- .grade-sub {
- font-size: 26rpx;
- opacity: 0.9;
- }
- .grade-progress {
- background: rgba(255,255,255,0.2);
- padding: 12rpx 24rpx;
- border-radius: 32rpx;
- backdrop-filter: blur(4px);
- }
- .progress-text {
- font-size: 24rpx;
- font-weight: 600;
- }
- .badge-section {
- margin-bottom: 40rpx;
- }
- .section-header {
- margin-bottom: 24rpx;
- padding-left: 16rpx;
- border-left: 8rpx solid #CBD5E1;
- }
- .section-title {
- font-size: 32rpx;
- font-weight: 700;
- color: #1E293B;
- }
- .badge-grid {
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-start;
- }
- .badge-card {
- width: 180rpx;
- height: 180rpx;
- margin: 12rpx;
- border-radius: 20rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- transition: transform 0.1s;
- background: #F1F5F9; /* Default locked color */
- border: 2rpx solid #E2E8F0;
- }
- .badge-card:active {
- transform: scale(0.95);
- }
- .badge-content {
- display: flex;
- flex-direction: column;
- align-items: center;
- text-align: center;
- }
- .badge-icon {
- font-size: 40rpx;
- margin-bottom: 8rpx;
- color: #94A3B8;
- }
- .badge-name {
- font-size: 24rpx;
- color: #64748B;
- width: 140rpx;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: pre-wrap;
- line-height: 1.4;
- }
- /* Earned state overrides */
- .icon-earned {
- color: #FFF;
- }
- .name-earned {
- color: rgba(255,255,255,0.9);
- }
- .footer-space {
- height: 60rpx;
- }
- </style>
|