0235624 3 hete
szülő
commit
32e2b0c92e

+ 286 - 34
travel-web/src/modules/pc-home/pages/page-dynamic/page-dynamic.html

@@ -45,35 +45,155 @@
       </div>
     </div>
     
-    <!-- 会员风采 -->
-    <div class="service-card">
-      <div class="service-header">
-        <div class="service-icon">
-          <i class="fas fa-vr-cardboard"></i>
-        </div>
-        <h3 class="service-title">会员风采</h3>
+    <!-- 会员风采部分 -->
+<div class="service-card">
+  <div class="service-header">
+    <div class="service-icon">
+      <i class="fas fa-vr-cardboard"></i>
+    </div>
+    <h3 class="service-title">会员风采</h3>
+  </div>
+  <div class="service-body">
+    <!-- 搜索和筛选区域 -->
+    <div class="achievement-filter">
+      <input type="text" placeholder="搜索成就..." 
+             [(ngModel)]="searchTerm" 
+             (input)="filterAchievements()"
+             class="search-input">
+      
+      <div class="category-filter">
+        <button *ngFor="let category of achievementCategories" 
+                [class.active]="selectedCategory === category"
+                (click)="selectCategory(category)">
+          {{category}}
+        </button>
       </div>
-      <div class="service-body">
-        <div class="vr-showcase">
-          <div class="drying-rack">
-            <div class="achievement-item floating" style="animation-delay: 0s;">
-              <i class="fas fa-award"></i>
-            </div>
-            <div class="achievement-item floating" style="animation-delay: 0.2s;">
-              <i class="fas fa-medal"></i>
-            </div>
-            <div class="achievement-item floating" style="animation-delay: 0.4s;">
-              <i class="fas fa-trophy"></i>
-            </div>
-            <div class="achievement-item floating" style="animation-delay: 0.6s;">
-              <i class="fas fa-star"></i>
+    </div>
+    
+    <!-- 成就展示区 -->
+    <div class="vr-showcase">
+      <div class="drying-rack">
+        <!-- 成就展示 -->
+        @for (achievement of filteredAchievements; track achievement.id) {
+        <div class="achievement-item floating" 
+             [class.user-achievement]="isUserAchievement(achievement)">
+          <div class="achievement-icon">
+            <i class="fas fa-{{getAchievementIcon(achievement.get('category'))}}"></i>
+          </div>
+          <div class="achievement-content">
+            <h4>{{achievement.get('title')}}</h4>
+            <p>{{achievement.get('description') | truncate: 30}}</p>
+            <div class="achievement-meta">
+              <span class="user">
+                <i class="fas fa-user"></i>
+                {{getUserName(achievement.get('user'))}}
+              </span>
+              <span class="date">
+                <i class="fas fa-calendar"></i>
+                {{achievement.get('createdAt') | date: 'yyyy-MM-dd'}}
+              </span>
             </div>
           </div>
+          
+          @if (isUserAchievement(achievement)) {
+          <div class="achievement-actions">
+            <button class="edit-btn" (click)="startEditAchievement(achievement)">
+              <i class="fas fa-edit"></i>
+            </button>
+            <button class="delete-btn" (click)="deleteAchievement(achievement)">
+              <i class="fas fa-trash"></i>
+            </button>
+          </div>
+          }
+        </div>
+        }
+        
+        <!-- 添加按钮 -->
+        <div class="achievement-item add-item floating" 
+             (click)="isAddingAchievement = true">
+          <i class="fas fa-plus-circle"></i>
+          <span>添加成就</span>
         </div>
-        <p>采用婺源晒秋场景,成就物品以辣椒/玉米形式悬挂展示,支持手势"晾晒"操作</p>
       </div>
     </div>
     
+    <!-- 添加成就表单 -->
+    @if (isAddingAchievement) {
+    <div class="achievement-form">
+      <h4><i class="fas fa-plus-circle"></i> 添加新成就</h4>
+      <div class="form-group">
+        <label><i class="fas fa-heading"></i> 标题</label>
+        <input type="text" [(ngModel)]="newAchievement.title" placeholder="成就标题">
+      </div>
+      <div class="form-group">
+        <label><i class="fas fa-align-left"></i> 描述</label>
+        <textarea [(ngModel)]="newAchievement.description" 
+                  placeholder="详细描述您的成就..."></textarea>
+      </div>
+      <div class="form-group">
+        <label><i class="fas fa-tag"></i> 类别</label>
+        <select [(ngModel)]="newAchievement.category">
+          <option *ngFor="let cat of achievementCategories" [value]="cat">
+            {{cat}}
+          </option>
+        </select>
+      </div>
+      <div class="form-group">
+        <label><i class="fas fa-image"></i> 图片URL</label>
+        <input type="text" [(ngModel)]="newAchievement.imageUrl" 
+               placeholder="https://example.com/image.jpg">
+      </div>
+      <div class="form-actions">
+        <button class="cancel-btn" (click)="isAddingAchievement = false">
+          <i class="fas fa-times"></i> 取消
+        </button>
+        <button class="save-btn" (click)="addAchievement()">
+          <i class="fas fa-save"></i> 保存成就
+        </button>
+      </div>
+    </div>
+    }
+    
+    <!-- 编辑成就表单 -->
+    @if (isEditingAchievement && editingAchievement) {
+    <div class="achievement-form">
+      <h4><i class="fas fa-edit"></i> 编辑成就</h4>
+      <div class="form-group">
+        <label><i class="fas fa-heading"></i> 标题</label>
+        <input type="text" 
+          [(ngModel)]="editingAchievement.data['title']">
+      </div>
+      <div class="form-group">
+        <label><i class="fas fa-align-left"></i> 描述</label>
+        <textarea 
+          [(ngModel)]="editingAchievement.data['description']"></textarea>
+      </div>
+      <div class="form-group">
+        <label><i class="fas fa-tag"></i> 类别</label>
+        <select [(ngModel)]="editingAchievement.data['category']">
+          <option *ngFor="let cat of achievementCategories" [value]="cat">
+            {{cat}}
+          </option>
+        </select>
+      </div>
+      <div class="form-group">
+        <label><i class="fas fa-image"></i> 图片URL</label>
+        <input type="text" 
+          [(ngModel)]="editingAchievement.data['imageUrl']">
+      </div>
+      <div class="form-actions">
+        <button class="cancel-btn" (click)="isEditingAchievement = false">
+          <i class="fas fa-times"></i> 取消
+        </button>
+        <button class="save-btn" (click)="updateAchievement()">
+          <i class="fas fa-save"></i> 更新成就
+        </button>
+      </div>
+    </div>
+    }
+  </div>
+</div>
+    
     <!-- 单位对接 -->
     <div class="service-card">
       <div class="service-header">
@@ -252,21 +372,153 @@
   </div>
   
   <div class="section-header" style="padding-top: 3rem;">
-    <h3 class="section-title">三维荣誉墙</h3>
+   <!-- 三维荣誉墙 -->
+<div class="section-header" style="padding-top: 3rem;">
+  <h3 class="section-title">三维荣誉墙</h3>
+</div>
+
+<!-- 筛选表单 -->
+<!-- 三维荣誉墙筛选部分修改 -->
+<div class="terrace-form" style="margin-bottom: 2rem; background: linear-gradient(135deg, #f8f9fa 0%, #e6f7ff 100%);">
+  <div style="display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: center;">
+    <div style="flex: 1; min-width: 200px;">
+      <h4 style="color: var(--primary-blue); margin-bottom: 0.5rem;">筛选条件</h4>
+      <div style="display: flex; gap: 1rem; flex-wrap: wrap;">
+        <!-- 年份下拉框 -->
+        <div class="form-group" style="flex: 1; min-width: 150px; margin-bottom: 0;">
+          <label>年份</label>
+          <select [(ngModel)]="filter.year" (change)="filterAwards()" class="form-input">
+            <option [value]="null">全部年份</option>
+            @for (year of years; track year) {
+              <option [value]="year">{{year}}</option>
+            }
+          </select>
+        </div>
+        
+        <!-- 类别下拉框 -->
+        <div class="form-group" style="flex: 1; min-width: 150px; margin-bottom: 0;">
+          <label>奖项类别</label>
+          <select [(ngModel)]="filter.categoryId" (change)="filterAwards()" class="form-input">
+            <option [value]="null">全部类别</option>
+            @for (category of awardCategories; track category.id) {
+              <option [value]="category.id">{{category.get('name')}}</option>
+            }
+          </select>
+        </div>
+      </div>
+    </div>
+    
+    <div style="display: flex; align-items: flex-end;">
+      <button class="ocr-btn" 
+              style="background: var(--gold-yellow); color: var(--dark-charcoal);"
+              (click)="filter.year = null; filter.categoryId = null; filterAwards()">
+        <i class="fas fa-sync-alt"></i> 重置筛选
+      </button>
+    </div>
   </div>
-  
-  <div class="pavilion-honor">
-    <div class="pavilion-model">
-      <div class="honor-item" style="top: 20px; left: 50px;">2023金奖</div>
-      <div class="honor-item" style="top: 60px; right: 40px;">2022创新奖</div>
-      <div class="honor-item" style="bottom: 80px; left: 30px;">2023银奖</div>
-      <div class="honor-item" style="bottom: 40px; right: 60px;">2022贡献奖</div>
-      <div class="honor-item" style="top: 100px; left: 100px;">2023最佳设计</div>
+</div>
+
+<!-- 荣誉墙展示 -->
+<div class="pavilion-honor">
+  <div class="pavilion-model">
+    <!-- 动态生成荣誉项 -->
+    @for (award of awardRecords; track award.id; let i = $index) {
+      <div class="honor-item" 
+           [style]="getHonorPosition(i)"
+           [class.floating]="i % 2 === 0"
+           [class.gold]="award.get('level') === '金奖'"
+           [class.silver]="award.get('level') === '银奖'"
+           [class.bronze]="award.get('level') === '铜奖'"
+           (click)="viewAwardDetail(award)">
+        <div class="award-name">{{award.get('awardName') | truncate: 6}}</div>
+        <div class="award-year">{{award.get('year')}}</div>
+        <div class="award-category">{{getCategoryName(award.get('categoryId')) | truncate: 4}}</div>
+      </div>
+    }
+    
+    <!-- 当没有奖项时显示提示 -->
+    @if (awardRecords.length === 0) {
+      <div class="no-awards">
+        <i class="fas fa-trophy" style="font-size: 3rem; margin-bottom: 1rem;"></i>
+        <h3>暂无获奖记录</h3>
+        <p>请尝试其他筛选条件</p>
+      </div>
+    }
+  </div>
+</div>
+
+<!-- 奖项详情模态框 -->
+@if (showAwardDetail && selectedAward) {
+<div class="modal-backdrop" (click)="showAwardDetail = false">
+  <div class="modal-content" (click)="$event.stopPropagation()">
+    <button class="modal-close" (click)="showAwardDetail = false">
+      <i class="fas fa-times"></i>
+    </button>
+    
+    <div class="award-header">
+      <div class="award-icon" [class.gold]="selectedAward.get('level') === '金奖'"
+           [class.silver]="selectedAward.get('level') === '银奖'"
+           [class.bronze]="selectedAward.get('level') === '铜奖'">
+        <i class="fas fa-trophy"></i>
+      </div>
+      <h3>{{selectedAward.get('awardName')}}</h3>
+      <div class="award-subtitle">
+        {{selectedAward.get('year')}} · {{getCategoryName(selectedAward.get('categoryId'))}}
+      </div>
+    </div>
+    
+    <div class="award-details">
+      <div class="detail-row">
+        <div class="detail-item">
+          <i class="fas fa-medal"></i>
+          <div>
+            <strong>奖项等级</strong>
+            <p>{{selectedAward.get('level')}}</p>
+          </div>
+        </div>
+        
+        <div class="detail-item">
+          <i class="fas fa-building"></i>
+          <div>
+            <strong>颁奖机构</strong>
+            <p>{{selectedAward.get('issuer')}}</p>
+          </div>
+        </div>
+      </div>
+      
+      <div class="detail-item full-width">
+        <i class="fas fa-file-alt"></i>
+        <div>
+          <strong>奖项描述</strong>
+          <p>{{selectedAward.get('description')}}</p>
+        </div>
+      </div>
+      
+      <div class="detail-item full-width">
+        <i class="fas fa-users"></i>
+        <div>
+          <strong>获奖者</strong>
+          <div class="winners-list">
+            @for (winner of getWinners(selectedAward); track $index) {
+              <div class="winner-item">
+                <i class="fas" [class.fa-user]="winner.type === '个人'" [class.fa-users]="winner.type === '团队'"></i>
+                {{winner.name}}
+                <span class="winner-type">{{winner.type}}</span>
+              </div>
+            }
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <div class="modal-footer">
+      <button class="ocr-btn" style="background: var(--gold-yellow); color: var(--dark-charcoal);">
+        <i class="fas fa-share-alt"></i> 分享荣誉
+      </button>
     </div>
   </div>
-  
-  <p style="text-align: center; margin-top: 1rem; color: #666;">鼠标滑动控制滕王阁楼层旋转查看不同年份奖项,沉浸式体验江西文化</p>
-</section>
+</div>
+}
 
 <!-- 页脚 -->
 <footer class="footer">

+ 650 - 52
travel-web/src/modules/pc-home/pages/page-dynamic/page-dynamic.scss

@@ -234,47 +234,299 @@
   transition: all 1s ease;
 }
 
-/* VR展示区 */
-.vr-showcase {
-  width: 100%;
-  height: 300px;
-  background: url('https://images.unsplash.com/photo-1551649001-7a2482d98d09?ixlib=rb-4.0.3&auto=format&fit=crop&w=1950&q=80') center/cover;
-  border-radius: 10px;
-  position: relative;
-  overflow: hidden;
+/* 成就筛选区 */
+.achievement-filter {
+  display: flex;
+  flex-direction: column;
+  gap: 1rem;
   margin-bottom: 1.5rem;
+  background: rgba(255, 255, 255, 0.8);
+  padding: 1.2rem;
+  border-radius: 10px;
+  box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+  
+  .search-input {
+    padding: 0.8rem 1.2rem;
+    border: 1px solid #ddd;
+    border-radius: 30px;
+    font-size: 1rem;
+    transition: all 0.3s ease;
+    
+    &:focus {
+      border-color: var(--primary-blue);
+      box-shadow: 0 0 0 3px rgba(74, 134, 232, 0.1);
+      outline: none;
+    }
+  }
+  
+  .category-filter {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 0.8rem;
+    
+    button {
+      padding: 0.5rem 1.2rem;
+      background: #f0f4f8;
+      border: none;
+      border-radius: 20px;
+      font-size: 0.9rem;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      
+      &.active, &:hover {
+        background: var(--primary-blue);
+        color: white;
+      }
+    }
+  }
 }
 
-.drying-rack {
-  position: absolute;
-  top: 30px;
-  left: 50%;
-  transform: translateX(-50%);
-  width: 80%;
-  height: 180px;
-  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="10" viewBox="0 0 200 10"><rect width="200" height="3" fill="%23d4a017" rx="1.5"/></svg>') repeat;
+/* 成就项样式 */
+.achievement-item {
+  width: 220px;
+  height: 260px;
+  background: white;
+  border-radius: 15px;
+  overflow: hidden;
   display: flex;
-  justify-content: space-around;
+  flex-direction: column;
   align-items: center;
+  padding: 1.2rem;
+  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
+  transition: all 0.4s ease;
+  position: relative;
+  
+  &.user-achievement {
+    border: 2px solid var(--gold-yellow);
+    box-shadow: 0 8px 25px rgba(232, 195, 77, 0.3);
+  }
+  
+  &.add-item {
+    background: rgba(232, 195, 77, 0.1);
+    border: 2px dashed var(--gold-yellow);
+    justify-content: center;
+    color: var(--gold-yellow);
+    cursor: pointer;
+    
+    i {
+      font-size: 3rem;
+      margin-bottom: 1rem;
+    }
+    
+    span {
+      font-weight: bold;
+    }
+    
+    &:hover {
+      background: rgba(232, 195, 77, 0.2);
+      transform: scale(1.05);
+    }
+  }
+  
+  .achievement-icon {
+    width: 70px;
+    height: 70px;
+    background: rgba(42, 93, 170, 0.1);
+    border-radius: 50%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-bottom: 1.2rem;
+    
+    i {
+      font-size: 2.2rem;
+      color: var(--primary-blue);
+    }
+  }
+  
+  .achievement-content {
+    text-align: center;
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    
+    h4 {
+      font-size: 1.2rem;
+      color: var(--dark-charcoal);
+      margin-bottom: 0.8rem;
+      line-height: 1.3;
+    }
+    
+    p {
+      color: #555;
+      font-size: 0.95rem;
+      line-height: 1.5;
+      margin-bottom: 1rem;
+      flex: 1;
+    }
+    
+    .achievement-meta {
+      display: flex;
+      justify-content: space-between;
+      font-size: 0.85rem;
+      color: #777;
+      
+      span {
+        display: flex;
+        align-items: center;
+        gap: 0.3rem;
+      }
+    }
+  }
+  
+  .achievement-actions {
+    position: absolute;
+    top: 10px;
+    right: 10px;
+    display: flex;
+    gap: 0.5rem;
+    opacity: 0;
+    transition: opacity 0.3s ease;
+    
+    button {
+      width: 30px;
+      height: 30px;
+      border-radius: 50%;
+      border: none;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      
+      &.edit-btn {
+        background: rgba(42, 93, 170, 0.1);
+        color: var(--primary-blue);
+        
+        &:hover {
+          background: var(--primary-blue);
+          color: white;
+        }
+      }
+      
+      &.delete-btn {
+        background: rgba(199, 62, 58, 0.1);
+        color: var(--ceramic-red);
+        
+        &:hover {
+          background: var(--ceramic-red);
+          color: white;
+        }
+      }
+    }
+  }
+  
+  &:hover {
+    transform: translateY(-10px) scale(1.03);
+    box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
+    
+    .achievement-actions {
+      opacity: 1;
+    }
+  }
 }
 
-.achievement-item {
-  width: 70px;
-  height: 70px;
-  border-radius: 50%;
-  background: var(--gold-yellow);
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  font-size: 2rem;
-  color: white;
-  cursor: pointer;
-  transition: all 0.3s ease;
-  box-shadow: 0 5px 15px rgba(0,0,0,0.2);
+/* 成就表单样式 */
+.achievement-form {
+  background: white;
+  border-radius: 15px;
+  padding: 1.8rem;
+  margin-top: 2rem;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+  border-top: 3px solid var(--gold-yellow);
+  
+  h4 {
+    color: var(--primary-blue);
+    margin-bottom: 1.5rem;
+    display: flex;
+    align-items: center;
+    gap: 0.8rem;
+    
+    i {
+      font-size: 1.4rem;
+    }
+  }
+  
+  .form-group {
+    margin-bottom: 1.5rem;
+    
+    label {
+      display: flex;
+      align-items: center;
+      gap: 0.5rem;
+      margin-bottom: 0.5rem;
+      font-weight: bold;
+      color: var(--primary-blue);
+    }
+    
+    input, textarea, select {
+      width: 100%;
+      padding: 0.8rem 1rem;
+      border: 1px solid #ddd;
+      border-radius: 8px;
+      font-size: 1rem;
+      transition: all 0.3s ease;
+      
+      &:focus {
+        border-color: var(--primary-blue);
+        box-shadow: 0 0 0 3px rgba(74, 134, 232, 0.1);
+        outline: none;
+      }
+    }
+    
+    textarea {
+      min-height: 100px;
+      resize: vertical;
+    }
+  }
+  
+  .form-actions {
+    display: flex;
+    justify-content: flex-end;
+    gap: 1rem;
+    margin-top: 1rem;
+    
+    button {
+      padding: 0.8rem 1.5rem;
+      border-radius: 30px;
+      font-weight: bold;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      display: flex;
+      align-items: center;
+      gap: 0.5rem;
+      
+      &.cancel-btn {
+        background: #f8f9fa;
+        border: 1px solid #ddd;
+        color: #555;
+        
+        &:hover {
+          background: #e9ecef;
+        }
+      }
+      
+      &.save-btn {
+        background: var(--primary-blue);
+        color: white;
+        border: none;
+        
+        &:hover {
+          background: #1d4a8d;
+          transform: translateY(-2px);
+        }
+      }
+    }
+  }
 }
 
-.achievement-item:hover {
-  transform: translateY(-10px);
+/* 晾晒架布局优化 */
+.drying-rack {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
+  gap: 1.5rem;
+  width: 100%;
+  padding: 1rem;
 }
 
 /* 单位对接 */
@@ -469,48 +721,308 @@
   transform: scaleX(1);
 }
 
-/* 滕王阁荣誉墙 */
+/* 三维荣誉墙样式 */
 .pavilion-honor {
   width: 100%;
-  height: 400px;
+  height: 500px;
   background: linear-gradient(to bottom, #e6f7ff, #d1e8ff);
   border-radius: 15px;
-  margin-top: 3rem;
+  margin-top: 1rem;
   position: relative;
   overflow: hidden;
   display: flex;
   justify-content: center;
   align-items: center;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
+  
+  .pavilion-model {
+    width: 320px;
+    height: 320px;
+    background: url('https://img.zcool.cn/community/01e8b35f4c7d8c11013e3187c926b0.png@1280w_1l_2o_100sh.png') center/contain no-repeat;
+    position: relative;
+    transition: transform 0.1s ease;
+  }
+  
+  .no-awards {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    text-align: center;
+    color: var(--primary-blue);
+    
+    h3 {
+      margin-bottom: 0.5rem;
+    }
+    
+    p {
+      color: #666;
+    }
+  }
 }
 
-.pavilion-model {
-  width: 300px;
-  height: 300px;
-  background: url('https://images.unsplash.com/photo-1600857062241-98c0a9e0f6f5?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80') center/contain no-repeat;
-  position: relative;
-  transition: transform 0.1s ease;
+.terrace-form {
+  .form-group {
+    margin-bottom: 0;
+    padding: 1rem;
+    
+    label {
+      display: block;
+      margin-bottom: 0.5rem;
+      font-weight: bold;
+      color: var(--primary-blue);
+    }
+    
+    select {
+      width: 100%;
+      padding: 0.8rem;
+      border: 1px solid #ddd;
+      border-radius: 5px;
+      font-size: 1rem;
+      background: white;
+      appearance: none;
+      background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232a5daa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
+      background-repeat: no-repeat;
+      background-position: right 1rem center;
+      background-size: 1rem;
+      cursor: pointer;
+      
+      &:focus {
+        border-color: var(--river-blue);
+        box-shadow: 0 0 0 3px rgba(74, 134, 232, 0.1);
+        outline: none;
+      }
+    }
+  }
+  
+  .ocr-btn {
+    padding: 0.8rem 1.5rem;
+    border-radius: 30px;
+    font-weight: bold;
+    transition: all 0.3s ease;
+    
+    &:hover {
+      transform: translateY(-3px);
+      box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+    }
+  }
 }
 
+/* 荣誉项样式 */
 .honor-item {
-  position: absolute;
-  width: 80px;
-  height: 50px;
-  background: white;
+  width: 100px;
+  height: 100px;
+  background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
   border: 2px solid var(--gold-yellow);
-  border-radius: 5px;
+  border-radius: 10px;
   display: flex;
+  flex-direction: column;
   justify-content: center;
   align-items: center;
-  font-weight: bold;
-  color: var(--primary-blue);
-  box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
   cursor: pointer;
   transition: all 0.3s ease;
+  z-index: 1;
+  padding: 10px;
+  box-sizing: border-box;
+  position: absolute;
+  text-align: center;
+  
+  &.gold {
+    border-color: #ffd700;
+    background: linear-gradient(135deg, #fff9db 0%, #ffffff 100%);
+    box-shadow: 0 5px 15px rgba(255, 215, 0, 0.3);
+  }
+  
+  &.silver {
+    border-color: #c0c0c0;
+    background: linear-gradient(135deg, #f0f0f0 0%, #ffffff 100%);
+    box-shadow: 0 5px 15px rgba(192, 192, 192, 0.3);
+  }
+  
+  &.bronze {
+    border-color: #cd7f32;
+    background: linear-gradient(135deg, #f8e9d9 0%, #ffffff 100%);
+    box-shadow: 0 5px 15px rgba(205, 127, 50, 0.3);
+  }
+  
+  .award-name {
+    font-weight: bold;
+    text-align: center;
+    font-size: 0.9rem;
+    color: var(--primary-blue);
+    margin-bottom: 5px;
+    line-height: 1.2;
+  }
+  
+  .award-year {
+    font-size: 1.2rem;
+    font-weight: bold;
+    color: var(--ceramic-red);
+    margin-bottom: 3px;
+  }
+  
+  .award-category {
+    font-size: 0.8rem;
+    color: var(--mountain-green);
+    background: rgba(232, 195, 77, 0.2);
+    padding: 3px 8px;
+    border-radius: 10px;
+    width: 100%;
+  }
+  
+  &:hover {
+    transform: scale(1.15) !important;
+    z-index: 10;
+    box-shadow: 0 8px 25px rgba(232, 195, 77, 0.4);
+  }
 }
 
-.honor-item:hover {
-  transform: scale(1.1);
-  z-index: 10;
+/* 模态框样式 */
+.modal-backdrop {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.7);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  background: white;
+  border-radius: 15px;
+  padding: 2rem;
+  width: 90%;
+  max-width: 600px;
+  max-height: 90vh;
+  overflow-y: auto;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+  position: relative;
+}
+
+.modal-close {
+  position: absolute;
+  top: 15px;
+  right: 15px;
+  background: none;
+  border: none;
+  font-size: 1.5rem;
+  cursor: pointer;
+  color: #999;
+  
+  &:hover {
+    color: var(--ceramic-red);
+  }
+}
+
+.award-header {
+  text-align: center;
+  margin-bottom: 1.5rem;
+  
+  .award-icon {
+    width: 80px;
+    height: 80px;
+    border-radius: 50%;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin: 0 auto 1rem;
+    font-size: 2.5rem;
+    
+    &.gold {
+      background: linear-gradient(135deg, #ffd700 0%, #ffec8b 100%);
+      color: #b8860b;
+    }
+    
+    &.silver {
+      background: linear-gradient(135deg, #e6e6e6 0%, #ffffff 100%);
+      color: #808080;
+    }
+    
+    &.bronze {
+      background: linear-gradient(135deg, #cd7f32 0%, #e9b384 100%);
+      color: #8b4513;
+    }
+  }
+  
+  h3 {
+    color: var(--primary-blue);
+    margin-bottom: 0.5rem;
+  }
+  
+  .award-subtitle {
+    color: #666;
+    font-size: 1.1rem;
+  }
+}
+
+.award-details {
+  .detail-row {
+    display: flex;
+    gap: 1rem;
+    margin-bottom: 1rem;
+  }
+  
+  .detail-item {
+    flex: 1;
+    background: var(--porcelain-white);
+    padding: 1rem;
+    border-radius: 8px;
+    display: flex;
+    align-items: flex-start;
+    gap: 0.8rem;
+    
+    i {
+      font-size: 1.5rem;
+      color: var(--primary-blue);
+      margin-top: 0.3rem;
+    }
+    
+    &.full-width {
+      flex: 0 0 100%;
+      margin-bottom: 1rem;
+    }
+    
+    strong {
+      display: block;
+      margin-bottom: 0.3rem;
+      color: var(--primary-blue);
+    }
+  }
+}
+
+.winners-list {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0.8rem;
+  margin-top: 0.5rem;
+  
+  .winner-item {
+    background: rgba(74, 134, 232, 0.1);
+    padding: 0.5rem 1rem;
+    border-radius: 20px;
+    display: flex;
+    align-items: center;
+    gap: 0.5rem;
+    
+    .winner-type {
+      background: rgba(232, 195, 77, 0.3);
+      padding: 0.2rem 0.5rem;
+      border-radius: 10px;
+      font-size: 0.8rem;
+      margin-left: 0.5rem;
+    }
+  }
+}
+
+.modal-footer {
+  display: flex;
+  justify-content: center;
+  margin-top: 1.5rem;
 }
 
 /* 页脚 */
@@ -626,4 +1138,90 @@
   .space-grid {
     grid-template-columns: 1fr;
   }
+}
+/* 新增成就项样式 */
+.achievement-item {
+  width: 120px;
+  height: 140px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  padding: 10px;
+  text-align: center;
+  position: relative;
+  
+  i {
+    font-size: 2.5rem;
+    margin-bottom: 10px;
+  }
+  
+  .achievement-details {
+    flex: 1;
+    overflow: hidden;
+  }
+  
+  .achievement-actions {
+    position: absolute;
+    bottom: 5px;
+    right: 5px;
+    display: flex;
+    gap: 5px;
+    
+    button {
+      background: rgba(255, 255, 255, 0.8);
+      border: none;
+      border-radius: 50%;
+      width: 25px;
+      height: 25px;
+      cursor: pointer;
+      
+      &:hover {
+        background: var(--gold-yellow);
+      }
+    }
+  }
+}
+
+.achievement-form {
+  background: white;
+  border-radius: 10px;
+  padding: 20px;
+  margin-top: 20px;
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+  
+  .form-group {
+    margin-bottom: 15px;
+    
+    label {
+      display: block;
+      margin-bottom: 5px;
+      font-weight: bold;
+    }
+    
+    input, textarea, select {
+      width: 100%;
+      padding: 8px;
+      border: 1px solid #ddd;
+      border-radius: 4px;
+    }
+  }
+  
+  .form-actions {
+    display: flex;
+    justify-content: flex-end;
+    gap: 10px;
+    
+    button {
+      padding: 8px 15px;
+      border: none;
+      border-radius: 4px;
+      cursor: pointer;
+      
+      &:first-child {
+        background: var(--primary-blue);
+        color: white;
+      }
+    }
+  }
 }

+ 443 - 4
travel-web/src/modules/pc-home/pages/page-dynamic/page-dynamic.ts

@@ -1,14 +1,26 @@
-// page-dynamic.component.ts
-import { Component, AfterViewInit } from '@angular/core';
+// page-dynamic.ts
+import { Component, AfterViewInit, ChangeDetectorRef, Pipe, PipeTransform } from '@angular/core'; 
 import { FormsModule } from '@angular/forms';
+import { CommonModule,DatePipe} from '@angular/common';
+import { CloudUser, CloudObject, CloudQuery } from '../../../../lib/ncloud';
+
+@Pipe({ name: 'truncate', standalone: true })
+export class TruncatePipe implements PipeTransform {
+  transform(value: string, limit: number = 20, trail: string = '...'): string {
+    return value.length > limit 
+      ? value.substring(0, limit) + trail 
+      : value;
+  }
+}
 
 @Component({
   selector: 'app-page-dynamic',
   standalone: true,
   templateUrl: './page-dynamic.html',
   styleUrls: ['./page-dynamic.scss'],
-  imports: [FormsModule]
+  imports: [FormsModule, TruncatePipe,DatePipe]
 })
+
 export class PageDynamic implements AfterViewInit {
   isOcrSuccess: boolean | null = null;
   activeLanterns = false;
@@ -19,12 +31,259 @@ export class PageDynamic implements AfterViewInit {
     description: '',
     document: null as File | null
   };
+  
+  currentUser: CloudUser | null = null;
+  achievements: CloudObject[] = []; // 成就列表
+  newAchievement: any = { 
+    title: '', 
+    description: '', 
+    category: '作品',
+    imageUrl: ''
+  };
+  editingAchievement: CloudObject | null = null;
+  isAddingAchievement = false;
+  isEditingAchievement = false;
 
-  ngAfterViewInit() {
+  // 新增属性
+  searchTerm: string = '';
+  selectedCategory: string | null = null;
+  filteredAchievements: CloudObject[] = [];
+  achievementCategories = ['作品', '证书', '奖项', '荣誉'];
+  userMap: Record<string, CloudObject> = {}; // 用户缓存
+  constructor(private cdr: ChangeDetectorRef) {} 
+
+  // 三维荣誉墙相关属性
+  awardRecords: CloudObject[] = []; // 奖项记录
+  awardCategories: CloudObject[] = []; // 奖项类别
+  years: number[] = this.generateYears(2015, 2025); // 生成2015-2025年
+  filter = {
+    year: null as number | null, // 默认选中"全部年份"
+    categoryId: null as string | null
+  };
+  selectedAward: CloudObject | null = null;
+  showAwardDetail = false;
+  
+  // 生成年份数组方法
+  generateYears(start: number, end: number): number[] {
+    const years = [];
+    for (let year = end; year >= start; year--) {
+      years.push(year);
+    }
+    return years;
+  }
+
+  // 预设的荣誉墙位置
+  honorPositions = [
+    { top: '20px', left: '50px' },
+    { top: '60px', right: '40px' },
+    { bottom: '80px', left: '30px' },
+    { bottom: '40px', right: '60px' },
+    { top: '100px', left: '100px' },
+    { top: '150px', right: '80px' },
+    { bottom: '120px', left: '120px' },
+    { top: '180px', left: '30px' },
+    { bottom: '100px', right: '120px' },
+    { top: '220px', right: '30px' }
+  ];
+
+  async ngAfterViewInit() {
     this.initCraneInteraction();
     this.initPavilionInteraction();
+    // 初始化当前用户
+    this.currentUser = new CloudUser();
+    await this.currentUser.current();
+    
+    // 加载成就列表
+    await this.loadAchievements();
+    await this.loadUsers(); // 加载用户数据
+    // 加载荣誉墙数据
+    await this.loadAwardData();
+
+    // 初始化模拟数据
+    this.createMockAwards();
+    await this.loadAwardData();
+  }
+
+  // 加载奖项数据
+  async loadAwardData() {
+    // 加载奖项类别
+    const categoryQuery = new CloudQuery("AwardCategory");
+    this.awardCategories = await categoryQuery.find();
+    
+    // 如果类别为空,创建模拟类别
+    if (this.awardCategories.length === 0) {
+      this.awardCategories = [
+        this.createMockCategory('1', '创新设计奖'),
+        this.createMockCategory('2', '文化传承奖'),
+        this.createMockCategory('3', '数字技术奖'),
+        this.createMockCategory('4', '社区贡献奖')
+      ];
+    }
+    
+    // 加载奖项记录
+    await this.filterAwards();
+    
+    // 如果奖项记录为空,创建模拟数据
+    if (this.awardRecords.length === 0) {
+      this.createMockAwards();
+    }
+  }
+
+  // 创建模拟类别
+  createMockCategory(id: string, name: string): CloudObject {
+    const category = new CloudObject("AwardCategory");
+    category.set({
+      name: name,
+      description: `${name}描述`
+    });
+    category.id = id;
+    return category;
+  }
+
+  // 创建模拟奖项数据
+  createMockAwards() {
+    const awards = [
+      { id: '1', awardName: '最佳创新设计', year: 2023, categoryId: '1', issuer: '江西省文化厅', level: '金奖', description: '表彰在文化产品设计方面的创新突破' },
+    { id: '2', awardName: '传统文化守护者', year: 2023, categoryId: '2', issuer: '江西省非遗保护中心', level: '银奖', description: '对传统文化保护有突出贡献的个人和机构' },
+    { id: '3', awardName: '数字技术先锋', year: 2022, categoryId: '3', issuer: '江西省科技厅', level: '金奖', description: '在文化数字化领域取得重大技术突破' },
+    { id: '4', awardName: '社区服务之星', year: 2022, categoryId: '4', issuer: '江西省民政厅', level: '铜奖', description: '为社区文化建设做出重要贡献' },
+    { id: '5', awardName: '文化传播大使', year: 2021, categoryId: '2', issuer: '江西省宣传部', level: '金奖', description: '有效推广江西文化的杰出代表' },
+    { id: '6', awardName: '数字创意新锐', year: 2021, categoryId: '3', issuer: '江西省文化厅', level: '银奖', description: '年轻一代在数字创意领域的优秀表现' },
+    { id: '7', awardName: '可持续发展奖', year: 2020, categoryId: '1', issuer: '江西省环保厅', level: '金奖', description: '在文化与环保结合方面的创新实践' },
+    { id: '8', awardName: '文化遗产保护', year: 2020, categoryId: '2', issuer: '江西省文物局', level: '银奖', description: '对重要文化遗产的保护和修复工作' },
+    { id: '9', awardName: '数字艺术创新', year: 2019, categoryId: '3', issuer: '江西省文化厅', level: '金奖', description: '在数字艺术创作方面的创新成果' },
+    { id: '10', awardName: '社区文化建设', year: 2018, categoryId: '4', issuer: '江西省民政厅', level: '铜奖', description: '推动社区文化建设的优秀案例' },
+    { id: '11', awardName: '传统工艺传承', year: 2017, categoryId: '2', issuer: '江西省非遗保护中心', level: '金奖', description: '对传统工艺的传承与创新' },
+    { id: '12', awardName: '文化科技创新', year: 2016, categoryId: '3', issuer: '江西省科技厅', level: '银奖', description: '科技创新在文化领域的应用' },
+    { id: '13', awardName: '文化公益项目', year: 2015, categoryId: '4', issuer: '江西省民政厅', level: '铜奖', description: '推动文化公益事业发展的优秀项目' }
+    ];
+    
+    this.awardRecords = awards.map(award => {
+      const obj = new CloudObject("AwardRecord");
+      obj.set(award);
+      obj.id = award.id;
+      return obj;
+    });
   }
 
+  // 筛选奖项
+  async filterAwards() {
+    // 尝试查询真实数据
+    try {
+      const awardQuery = new CloudQuery("AwardRecord");
+      
+      // 添加年份筛选条件
+      if (this.filter.year) {
+        awardQuery.equalTo("year", this.filter.year);
+      }
+      
+      // 添加类别筛选条件
+      if (this.filter.categoryId) {
+        awardQuery.equalTo("categoryId", this.filter.categoryId);
+      }
+      
+      // 关联查询类别信息
+      awardQuery.include("categoryId");
+      
+      this.awardRecords = await awardQuery.find();
+    } catch (e) {
+      console.log("使用模拟数据");
+      // 应用筛选条件到模拟数据
+      let filtered = [...this.mockAwards];
+      
+      if (this.filter.year) {
+        filtered = filtered.filter(a => a.year === this.filter.year);
+      }
+      
+      if (this.filter.categoryId) {
+        filtered = filtered.filter(a => a.categoryId === this.filter.categoryId);
+      }
+      
+      this.awardRecords = filtered.map(award => {
+        const obj = new CloudObject("AwardRecord");
+        obj.set(award);
+        obj.id = award.id;
+        return obj;
+      });
+    }
+  }
+
+  mockAwards = [
+    { id: '1', awardName: '最佳创新设计', year: 2023, categoryId: '1', issuer: '江西省文化厅', level: '金奖', description: '表彰在文化产品设计方面的创新突破' },
+    { id: '2', awardName: '传统文化守护者', year: 2023, categoryId: '2', issuer: '江西省非遗保护中心', level: '银奖', description: '对传统文化保护有突出贡献的个人和机构' },
+    { id: '3', awardName: '数字技术先锋', year: 2022, categoryId: '3', issuer: '江西省科技厅', level: '金奖', description: '在文化数字化领域取得重大技术突破' },
+    { id: '4', awardName: '社区服务之星', year: 2022, categoryId: '4', issuer: '江西省民政厅', level: '铜奖', description: '为社区文化建设做出重要贡献' },
+    { id: '5', awardName: '文化传播大使', year: 2021, categoryId: '2', issuer: '江西省宣传部', level: '金奖', description: '有效推广江西文化的杰出代表' },
+    { id: '6', awardName: '数字创意新锐', year: 2021, categoryId: '3', issuer: '江西省文化厅', level: '银奖', description: '年轻一代在数字创意领域的优秀表现' },
+    { id: '7', awardName: '可持续发展奖', year: 2020, categoryId: '1', issuer: '江西省环保厅', level: '金奖', description: '在文化与环保结合方面的创新实践' },
+    { id: '8', awardName: '文化遗产保护', year: 2020, categoryId: '2', issuer: '江西省文物局', level: '银奖', description: '对重要文化遗产的保护和修复工作' },
+    { id: '9', awardName: '数字艺术创新', year: 2019, categoryId: '3', issuer: '江西省文化厅', level: '金奖', description: '在数字艺术创作方面的创新成果' },
+    { id: '10', awardName: '社区文化建设', year: 2018, categoryId: '4', issuer: '江西省民政厅', level: '铜奖', description: '推动社区文化建设的优秀案例' },
+    { id: '11', awardName: '传统工艺传承', year: 2017, categoryId: '2', issuer: '江西省非遗保护中心', level: '金奖', description: '对传统工艺的传承与创新' },
+    { id: '12', awardName: '文化科技创新', year: 2016, categoryId: '3', issuer: '江西省科技厅', level: '银奖', description: '科技创新在文化领域的应用' },
+    { id: '13', awardName: '文化公益项目', year: 2015, categoryId: '4', issuer: '江西省民政厅', level: '铜奖', description: '推动文化公益事业发展的优秀项目' }
+  ];
+  // 查看奖项详情
+  viewAwardDetail(award: CloudObject) {
+    this.selectedAward = award;
+    this.showAwardDetail = true;
+  }
+
+  // 获取奖项类别名称
+  getCategoryName(categoryId: string): string {
+    const category = this.awardCategories.find(c => c.id === categoryId);
+    return category ? category.get('name') : '未知类别';
+  }
+  
+  // 获取荣誉项位置
+  getHonorPosition(index: number): any {
+    return this.honorPositions[index % this.honorPositions.length] || {};
+  }
+
+  // 获取获奖者(模拟方法)
+  getWinners(award: CloudObject): any[] {
+    // 确保 award.id 是字符串类型
+  const awardId = award.id ? award.id.toString() : '1';
+    // 根据奖项ID返回不同的获奖者
+    const winnersMap: Record<string, any[]> = {
+      '1': [
+        { name: '南昌文化设计院', type: '团队' },
+        { name: '李明', type: '个人' }
+      ],
+      '2': [
+        { name: '景德镇陶瓷研究院', type: '团队' },
+        { name: '王华', type: '个人' }
+      ],
+      '3': [
+        { name: '江西数字科技公司', type: '团队' },
+        { name: '张伟', type: '个人' },
+        { name: '刘芳', type: '个人' }
+      ],
+      '4': [
+        { name: '九江社区文化中心', type: '团队' }
+      ],
+      '5': [
+        { name: '江西电视台文化频道', type: '团队' },
+        { name: '陈明', type: '个人' }
+      ],
+      '6': [
+        { name: '青年创意工作室', type: '团队' },
+        { name: '赵阳', type: '个人' }
+      ],
+      '7': [
+        { name: '赣江环保组织', type: '团队' },
+        { name: '环保设计协会', type: '团队' }
+      ],
+      '8': [
+        { name: '庐山文物保护队', type: '团队' },
+        { name: '黄强', type: '个人' }
+      ]
+    };
+    
+    return winnersMap[awardId] || [{ name: '未知获奖者', type: '个人' }];
+  }
+  
+
   onOcrClick() {
     this.isProcessing = true;
     this.activeLanterns = false;
@@ -125,4 +384,184 @@ onFileSelected(event: Event) {
       document: null
     };
   }
+
+// 加载用户数据
+  async loadUsers() {
+    const query = new CloudQuery("_User");
+    const users = await query.find();
+    
+    // 创建用户ID到用户对象的映射
+    users.forEach(user => {
+    if (user.id) {
+  this.userMap[user.id] = user;
+} else {
+  console.warn('用户缺少 ID,无法缓存:', user);
+}
+    });
+  }
+
+  // 获取用户名
+  getUserName(userPointer: any): string {
+    // 添加空值检查
+    if (!userPointer || typeof userPointer !== 'object' || !userPointer.objectId) {
+      return '未知用户';
+    }
+    
+    const userId = userPointer.objectId;
+    
+    // 检查用户是否存在于缓存中
+    if (this.userMap[userId]) {
+      return this.userMap[userId].get('username') || '未知用户';
+    }
+    
+    // 如果用户不存在,异步加载
+    this.loadUserById(userId);
+    return '加载中...';
+  }
+
+  //按ID加载用户
+  async loadUserById(userId: string) {
+    // 避免重复加载
+    if (this.userMap[userId]) return;
+    
+    try {
+      const userQuery = new CloudQuery("_User");
+      const user = await userQuery.get(userId);
+      if (user) {
+        this.userMap[userId] = user;
+        // 触发UI更新
+        this.cdr.detectChanges();
+      }
+    } catch (e) {
+      console.error('加载用户失败:', e);
+    }
+  }
+
+  // 判断是否是当前用户的成就
+  isUserAchievement(achievement: CloudObject): boolean {
+    if (!this.currentUser) return false;
+    
+    const userPointer = achievement.get('user');
+    return userPointer && userPointer.objectId === this.currentUser.id;
+  }
+
+  // 筛选成就
+  filterAchievements() {
+    this.filteredAchievements = this.achievements.filter(achievement => {
+      // 安全获取属性
+      const title = achievement.get('title') || '';
+      const description = achievement.get('description') || '';
+      const category = achievement.get('category') || '';
+      
+      // 匹配搜索词
+      const matchesSearch = this.searchTerm ? 
+        title.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
+        description.toLowerCase().includes(this.searchTerm.toLowerCase()) :
+        true;
+      
+      // 匹配类别
+      const matchesCategory = this.selectedCategory ?
+        category === this.selectedCategory :
+        true;
+      
+      return matchesSearch && matchesCategory;
+    });
+  }
+
+  // 选择类别
+  selectCategory(category: string) {
+    if (this.selectedCategory === category) {
+      this.selectedCategory = null; // 取消选择
+    } else {
+      this.selectedCategory = category;
+    }
+    this.filterAchievements();
+  }
+
+
+  // 加载当前用户的成就
+  async loadAchievements() {
+    if (!this.currentUser?.id) return;
+    
+    const query = new CloudQuery("Achievement");
+    query.equalTo("user", this.currentUser.toPointer());
+    
+    this.achievements = await query.find();
+    this.filteredAchievements = [...this.achievements];
+  }
+
+  // 添加新成就
+  async addAchievement() {
+    if (!this.currentUser?.id) return;
+    
+    const achievement = new CloudObject("Achievement");
+    achievement.set({
+      ...this.newAchievement,
+      user: this.currentUser.toPointer()
+    });
+    
+    await achievement.save();
+    this.resetNewAchievement();
+    await this.loadAchievements();
+    this.filterAchievements(); // 更新筛选后的列表
+  }
+
+  // 开始编辑成就
+  startEditAchievement(achievement: CloudObject) {
+    // 使用类型断言指定 achievement 的 data 结构
+    this.editingAchievement = achievement as CloudObject & {
+      data: {
+        title: string;
+        description: string;
+        category: string;
+        imageUrl: string;
+      }
+    };
+    this.isEditingAchievement = true;
+  }
+
+  // 更新成就
+  async updateAchievement() {
+    if (!this.editingAchievement) return;
+    
+    // 创建新对象避免直接修改原对象
+    const updated = new CloudObject("Achievement");
+    updated.id = this.editingAchievement.id;
+    updated.set(this.editingAchievement.data);
+    
+    await updated.save();
+    await this.loadAchievements();
+    this.filterAchievements(); // 更新筛选后的列表
+  }
+
+  // 删除成就
+  async deleteAchievement(achievement: CloudObject) {
+    await achievement.destroy();
+    await this.loadAchievements();
+    this.filterAchievements(); // 更新筛选后的列表
+  }
+
+  // 重置新成就表单
+  resetNewAchievement() {
+    this.newAchievement = { 
+      title: '', 
+      description: '', 
+      category: '作品',
+      imageUrl: ''
+    };
+  }
+getAchievementIcon(category: string): string {
+  const icons: Record<string, string> = {
+    '作品': 'palette',
+    '证书': 'certificate',
+    '奖项': 'award',
+    '荣誉': 'medal'
+  };
+  return icons[category] || 'star';
+}
+
+
+
+  
+ 
 }