Переглянути джерело

完善社区功能:点赞、评论点赞、增加首页图标动画

s202226701053 5 місяців тому
батько
коміт
4ddc2fb04c

+ 5 - 0
E-Cover-app/src/app/app.routes.ts

@@ -61,4 +61,9 @@ export const routes: Routes = [
     loadComponent:()=>
       import('./eco-fashion/eco-fashion.component').then((m)=>m.EcoFashionComponent),
   },
+  {
+    path:'attention',
+    loadComponent:()=>
+      import('./attention/attention.component').then((m)=>m.AttentionComponent),
+  },
 ];

+ 48 - 0
E-Cover-app/src/app/attention/attention.component.html

@@ -0,0 +1,48 @@
+<!--头部-->
+<ion-header id="header">
+  <div class="header-container">
+    <ion-icon name="chevron-back-outline" size="large" (click)="goBack()"></ion-icon>
+    <div class="left-title" (click)="toattention()" [style.color]="currentTab ? 'black' : 'gray'">关注</div>
+    <div class="right-title" (click)="tofan()" [style.color]="currentTab ? 'gray' : 'black'">粉丝</div>
+  </div>
+</ion-header>
+<ion-content>
+  <!--关注列表-->
+  <div *ngIf="currentTab">
+    <ion-list lines="none" *ngFor="let attention of attentionList">
+      <ion-item >
+        <ion-avatar slot="start">
+          <img [src]="attention.get('attentionID').avatar" />
+        </ion-avatar>
+        <ion-label>
+          <span class="font"> {{attention.get('attentionID').name}} </span>
+        </ion-label>
+        <ion-button fill="clear" (click)="toggleFollow(attention)" 
+        [ngClass]="{'dark': !attention.isFollowed}"  
+        slot="end" class="follow-button">
+        {{ attention.isFollowed ? '已关注' : '+&nbsp;关注' }}
+        </ion-button>
+      </ion-item>
+    </ion-list>
+  </div>
+  <!--粉丝列表-->
+  <div *ngIf="!currentTab">
+    <ion-list lines="none" *ngFor="let fan of fanList">
+      <ion-item >
+        <ion-avatar slot="start">
+          <img [src]="fan.get('UserID').avatar" />
+        </ion-avatar>
+        <ion-label>
+          <span class="font"> {{fan.get('UserID').name}} </span>
+        </ion-label>
+        <ion-button fill="clear" (click)="tofanFollow(fan)"
+        [ngClass]="{'dark': !fan.isFollowed}"  
+        slot="end" class="follow-button">
+        {{ fan.isFollowed ? '已关注' : '+&nbsp;关注' }}
+        </ion-button>
+      </ion-item>
+    </ion-list>
+  </div>
+
+
+  </ion-content>

+ 81 - 0
E-Cover-app/src/app/attention/attention.component.scss

@@ -0,0 +1,81 @@
+.follow-button {
+    border-radius: 20px;
+    background-color: lightgray;
+    height:40px;
+    width: 80px;
+    font-size: 16px;
+    color:black;
+  }
+
+  .follow-button.dark {
+        background-color: black; // 黑色背景
+        color: white; // 白色字体
+    }
+
+
+  ion-item{
+    height:90px;
+    width: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-top: 5px;
+  }
+
+  ion-avatar{
+    height: 50px;
+    width: 50px;
+  }
+
+  .font{
+    font-size: 25px;
+    letter-spacing:normal
+  }
+
+  ion-header {
+    background-color: #f8f8f8;
+    color: black;
+    box-shadow: none;
+    height: 70px;
+
+    .header-container {
+        padding:0 10px;
+        height: 70px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+    }
+
+}
+
+.left-title {
+    position: absolute;
+    font-size: 22px;
+
+    @font-face {
+        font-family: 'header-font';
+        src: url(/assets/fonts/header.TTF);
+    }
+
+    font-family: 'header-font';
+    top: 24px;
+    left:35vw;
+    text-align: center;
+}
+
+.right-title {
+  position: absolute;
+  font-size: 22px;
+
+  @font-face {
+      font-family: 'header-font';
+      src: url(/assets/fonts/header.TTF);
+  }
+
+  font-family: 'header-font';
+  top: 24px;
+  left: 60vw; 
+  text-align: center;
+}
+
+

+ 22 - 0
E-Cover-app/src/app/attention/attention.component.spec.ts

@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+
+import { AttentionComponent } from './attention.component';
+
+describe('AttentionComponent', () => {
+  let component: AttentionComponent;
+  let fixture: ComponentFixture<AttentionComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      imports: [AttentionComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(AttentionComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 144 - 0
E-Cover-app/src/app/attention/attention.component.ts

@@ -0,0 +1,144 @@
+import { CommonModule } from '@angular/common';
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+
+import { IonAvatar, IonButton, IonContent, IonHeader, IonIcon, IonItem, IonLabel, IonList } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
+import { chevronBackOutline } from 'ionicons/icons';
+import { CustomHeaderComponent } from 'src/lib/component/custom-header/custom-header.component';
+import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
+
+addIcons({ chevronBackOutline,});
+
+
+@Component({
+  selector: 'app-attention',
+  templateUrl: './attention.component.html',
+  styleUrls: ['./attention.component.scss'],
+  standalone: true,
+  imports: [IonContent,IonList,IonItem,IonAvatar,IonLabel,IonButton,CommonModule,CustomHeaderComponent,IonHeader,IonIcon]
+})
+export class AttentionComponent  implements OnInit {
+
+  constructor(private router: Router) {
+    
+   }
+
+  ngOnInit() {
+    const navigation = this.router.getCurrentNavigation();
+    if (navigation && navigation.extras.state) {
+      this.currentTab = navigation.extras.state['currentTab']; // 获取传递的状态
+    }
+    this.loadAttentionList();
+    this.loadFanList();
+  }
+
+  attentionList:CloudObject[] | any;
+  fanList:CloudObject[] | any;
+  currentTab=true; //为true时显示关注列表,为false时显示粉丝列表
+  
+//加载关注列表
+ async loadAttentionList() {
+    const query = new CloudQuery('attention');
+    const user = new CloudUser().toPointer();
+    query.equalTo('UserID', user);
+    query.include('attentionID');
+    this.attentionList= await query.find();
+    console.log(this.attentionList);
+  }
+//切换关注状态并更新数据库
+  async toggleFollow(attention: CloudObject) {
+    attention.isFollowed = !attention.isFollowed;
+    if(attention.isFollowed) {
+      await this.saveAttentionRecord(attention.get('attentionID').objectId);
+    }
+    else {
+      await this.removePostLikeRecord(attention.get('attentionID').objectId);
+    }
+}
+
+ // 保存关注记录
+ async saveAttentionRecord( attentionId:any){
+  // 创建新的关注对象
+  const attentionRecord = new CloudObject("attention"); 
+  const user = new CloudUser();
+  const currentUser =  user.current(); // 获取当前用户信息
+if (currentUser!=null) {
+// 设置关注记录的字段
+await attentionRecord.set({
+   UserID: new CloudUser().toPointer(), // 指向当前用户
+   attentionID: { "__type": "Pointer", "className": "_User", "objectId": attentionId }, // 关注对象指针
+});
+// 保存关注记录
+await attentionRecord.save().then(() => {
+  console.log('关注记录已保存:');
+})
+}
+}
+
+// 删除关注记录
+async removePostLikeRecord(attentionId:any){
+const query = new CloudQuery('attention'); // 创建查询对象
+query.equalTo('attentionID', attentionId); // 根据帖子ID查询
+query.equalTo('UserID', new CloudUser().toPointer()); // 根据用户ID查询
+const attentionRecord = await query.first(); // 获取关注记录对象
+//console.log(likeRecord);
+if(attentionRecord){
+  await attentionRecord.destroy().then(() => {
+    console.log('关注记录已删除:');
+  })
+}
+
+}
+
+
+//加载粉丝列表
+async loadFanList() {
+  const query = new CloudQuery('attention');
+  const user = new CloudUser().toPointer();
+  query.equalTo('attentionID', user);
+  query.include('UserID');
+  this.fanList= await query.find();
+  console.log(this.fanList);
+
+  for(const fan of this.fanList){
+    const query = new CloudQuery('attention'); // 创建查询对象
+    query.equalTo('attentionID', {objectId: fan.get('UserID').objectId, __type: 'Pointer', className: '_User'}); 
+    query.equalTo('UserID', new CloudUser().toPointer()); 
+    const attentionRecord = await query.first(); // 获取关注记录对象
+    if(attentionRecord){
+      fan.isFollowed=true;
+    }
+    else{
+      fan.isFollowed=false;
+    }
+  }
+}
+
+//切换关注状态并更新数据库
+async tofanFollow(fan: CloudObject) {
+  fan.isFollowed = !fan.isFollowed;
+  if(fan.isFollowed) {
+    await this.saveAttentionRecord(fan.get('UserID').objectId);
+  }
+  else {
+    await this.removePostLikeRecord(fan.get('UserID').objectId);
+  }
+}
+
+
+
+goBack() {
+  window.history.back();
+}
+
+tofan(){
+  this.currentTab=false;
+}
+
+toattention(){
+  this.currentTab=true;
+
+}
+
+}

+ 20 - 12
E-Cover-app/src/app/tab3/tab3.page.html

@@ -30,10 +30,14 @@
       }
       <!--统计-->
       <div id="count">
-        <h3 style="display: inline;">{{ currentUser?.get('fans') }}</h3>
-        <p style="display: inline;">粉丝</p>
-        <h3 style="display: inline;">{{ currentUser?.get('subscription') }}</h3>
-        <p style="display: inline;">关注</p>
+        <div (click)="goAttention(false)">
+          <h3 style="display: inline;">{{ fanList.length}}</h3>
+          <p style="display: inline;">粉丝</p>
+        </div>
+        <div (click)="goAttention(true)">
+          <h3 style="display: inline;">{{ attentionList.length }}</h3>
+          <p style="display: inline;">关注</p>
+        </div>
         <h3 style="display: inline;">{{ formatNumber(currentUser?.get('like')) }}</h3>
         <p style="display: inline;">获赞</p>
       </div>
@@ -49,20 +53,24 @@
   <ion-card style="--background:white;box-shadow: none;border-bottom-left-radius: 0;
   border-bottom-right-radius: 0;top:-20px;">
     <div class="card">
-      <p>赞过帖子</p>
-      <p>11</p>
+      <img class="img-background" [src]="(postList[0]?.get('postID')?.image[0]!='') ? (postList[0]?.get('postID')?.image[0]) : ('/assets/icon/favicon.png')">
+      <img class="img-shade" />
+      <p>赞过帖子<br/>{{postList.length}}</p>
     </div>
     <div class="card">
-      <p>我的风格</p>
-      <p>11</p>
+      <img class="img-background" [src]="(postList[0]?.get('postID')?.image[0]!='') ? (postList[0]?.get('postID')?.image[0]) : ('/assets/icon/favicon.png')">
+      <img class="img-shade" />
+      <p>我的风格<br/>{{postList.length}}</p>
     </div>
     <div class="card">
-      <p>收藏帖子</p>
-      <p>11</p>
+      <img class="img-background" [src]="(postList[0]?.get('postID')?.image[0]!='') ? (postList[0]?.get('postID')?.image[0]) : ('/assets/icon/favicon.png')">
+      <img class="img-shade" />
+      <p>收藏帖子<br/>{{postList.length}}</p>
     </div>
     <div class="card" (click)="goGenerateHistory()">
-      <p>生成历史</p>
-      <p>11</p>
+      <img class="img-background" [src]="(postList[0]?.get('postID')?.image[0]!='') ? (postList[0]?.get('postID')?.image[0]) : ('/assets/icon/favicon.png')">
+      <img class="img-shade" />
+      <p>生成历史<br/>{{postList.length}}</p>
     </div>
 
     <ion-segment value="myPost" swipeGesture="true">

+ 36 - 3
E-Cover-app/src/app/tab3/tab3.page.scss

@@ -126,13 +126,46 @@ ion-content {
 
 .card {
     width: 21%;
-    height: 20vw;
-    background-color: #414040;
+    height: 21vw;
+    background: white;
     float: left;
     margin: 15px 2%;
     border-radius: 10px;
     padding: 10px;
-    top: -20px;
+    position: relative;
+    box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
+
+    img {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 0;
+        left: 0;
+        border-radius: 10px;
+    }
+
+    img.img-background {
+        z-index: 1;
+    }
+
+    img.img-shade {
+        background-color: rgba(0, 0, 0, 0.5); // 设置遮罩颜色和透明度
+        z-index: 2;
+    }
+
+    p{
+        z-index: 4;
+        color: #f8f8f8;
+        position: absolute;
+        @font-face {
+            font-family: 'title-font';
+            src: url(/assets/fonts/mainButton.TTC);
+        }
+        font-family: 'title-font';
+        display: block;
+        width: 100%;
+        line-height: 1.5;
+    }
 }
 
 #myPost {

+ 50 - 0
E-Cover-app/src/app/tab3/tab3.page.ts

@@ -18,7 +18,16 @@ addIcons({ personAddOutline, cardOutline, flameOutline, chevronForwardOutline })
 })
 export class Tab3Page {
   currentUser: CloudUser | undefined;
+  attentionList: CloudObject[] = [];
+  fanList: CloudObject[] = [];
+  postList: CloudObject[] = [];
   constructor(private modalCtrl: ModalController, private router: Router) { }
+  async ngOnInit() {
+    await this.loadAttentionList();
+    await this.loadFanList();
+    await this.loadPostList();
+    this.getBackgroundImageStyle();
+  }
   async ionViewWillEnter() {
     console.warn("-------------------------\n" + "进入tab3界面,执行ionViewWillEnter\n" + "验证用户是否登录")
     let user: any = new CloudUser();
@@ -64,6 +73,9 @@ export class Tab3Page {
   goGenerateHistory() {
     this.router.navigate(["generateHistory"]);
   }
+  goAttention(isFollowing: boolean) {
+    this.router.navigate(['/attention'], { state: { currentTab: isFollowing } }); // 传递状态
+  }
   /**
    * @读取用户发布的帖子
    */
@@ -76,4 +88,42 @@ export class Tab3Page {
     console.log(this.posts);
     this.posts = this.posts.reverse();
   }
+  //加载关注列表
+  async loadAttentionList() {
+    const query = new CloudQuery('attention');
+    const user = new CloudUser().toPointer();
+    query.equalTo('UserID', user);
+    this.attentionList = await query.find();
+    console.log(this.attentionList);
+  }
+  //加载粉丝列表
+  async loadFanList() {
+    const query = new CloudQuery('attention');
+    const user = new CloudUser().toPointer();
+    query.equalTo('attentionID', user);
+    this.fanList = await query.find();
+    //console.log(this.fanList);
+  }
+  /*加载点赞帖子列表*/
+  async loadPostList() {
+    const query = new CloudQuery('postLikesRecord');
+    const user = new CloudUser().toPointer();
+    query.equalTo('UserID', user);
+    query.include('postID');
+    this.postList = await query.find();
+    this.postList = this.postList.reverse();
+    console.log(this.postList);
+  }
+  /*返回赞过图片*/
+  getBackgroundImageStyle() {
+    const imageUrl = this.postList[0]?.get('postID')?.image[0];
+    console.log("检测背景url:" + imageUrl);
+    let element = document.getElementById('liked');
+    if(element)
+      element.style.background = `url(${imageUrl})`
+  }
 }
+
+
+
+

+ 6 - 6
E-Cover-app/src/app/tabs/tabs.page.html

@@ -1,18 +1,18 @@
 <!--工具栏-->
 <ion-tabs>
   <ion-tab-bar slot="bottom">
-    <ion-tab-button tab="tab1" href="/tabs/tab1">
-      <ion-icon aria-hidden="true" name="home"></ion-icon>
+    <ion-tab-button tab="tab1" href="/tabs/tab1" (click)="changeStatus('tab1')">
+      <img id="index" src="https://s1.imagehub.cc/images/2025/01/10/05e0d3d946096d0de3f98b7675cb7150.png" />
       <ion-label>首页</ion-label>
     </ion-tab-button>
 
-    <ion-tab-button tab="tab2" href="/tabs/tab2">
-      <ion-icon aria-hidden="true" name="ellipse"></ion-icon>
+    <ion-tab-button tab="tab2" href="/tabs/tab2" (click)="changeStatus('tab2')">
+      <img id="community" src="https://s1.imagehub.cc/images/2025/01/10/8bc1ff138c4982ac236042bb43934105.png" />
       <ion-label>社区</ion-label>
     </ion-tab-button>
 
-    <ion-tab-button tab="tab3" href="/tabs/tab3">
-      <ion-icon aria-hidden="true" name="square"></ion-icon>
+    <ion-tab-button tab="tab3" href="/tabs/tab3" (click)="changeStatus('tab3')">
+      <img id="my" src="https://s1.imagehub.cc/images/2025/01/10/888ebde8d6866f1f7df8d6b384109bee.png" />
       <ion-label>我的</ion-label>
     </ion-tab-button>
   </ion-tab-bar>

+ 25 - 1
E-Cover-app/src/app/tabs/tabs.page.scss

@@ -9,6 +9,11 @@ ion-tab-bar {
   
     ion-tab-button {
       background-color: hsla(0, 0, 0, 0);
+
+      img{
+        width: 40px;
+        height: 40px;
+      }
   
       ion-label {
         color: white;
@@ -24,4 +29,23 @@ ion-tab-bar {
         font-weight: 1000;
       }
     }
-  }
+  }
+
+  /* CSS 动画定义 */
+@keyframes bounceAndScale {
+  0%, 100% {
+    transform: translateY(0) scale(1);
+  }
+  50% {
+    transform: translateY(-10px) scale(1.1);
+  }
+}
+
+img {
+  transition: transform 0.3s ease; /* 添加平滑过渡 */
+}
+
+/* 在动画时应用的类 */
+.animate {
+  animation: bounceAndScale 0.6s ease forwards; /* 使用定义的动画 */
+}

+ 42 - 5
E-Cover-app/src/app/tabs/tabs.page.ts

@@ -1,7 +1,6 @@
 import { Component, EnvironmentInjector, inject } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
 import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, ModalController } from '@ionic/angular/standalone';
-import { addIcons } from 'ionicons';
-import { triangle, ellipse, square,home } from 'ionicons/icons';
 
 @Component({
   selector: 'app-tabs',
@@ -12,8 +11,46 @@ import { triangle, ellipse, square,home } from 'ionicons/icons';
 })
 export class TabsPage {
   public environmentInjector = inject(EnvironmentInjector);
+  constructor(private modalCtrl: ModalController,private router: Router, private route: ActivatedRoute) { }
 
-  constructor(private modalCtrl: ModalController) {
-    addIcons({ triangle, ellipse, square, home });
+  ngOnInit() {
+    // 获取当前激活的 tab
+    this.route.url.subscribe(url => {
+      const fullPath = this.router.url; // 获取完整的当前路由
+      const currentTab = fullPath.split('/').pop(); // 获取最后一部分作为当前 tab
+      console.log(currentTab);
+      this.changeStatus(currentTab as string);
+    });
   }
-}
+  /*更改激活图标状态*/
+  defaultSrc = {
+    index: 'https://s1.imagehub.cc/images/2025/01/10/05e0d3d946096d0de3f98b7675cb7150.png',
+    community: 'https://s1.imagehub.cc/images/2025/01/10/8bc1ff138c4982ac236042bb43934105.png',
+    my: 'https://s1.imagehub.cc/images/2025/01/10/888ebde8d6866f1f7df8d6b384109bee.png'
+  };
+  changeStatus(id: string) {
+    const element_index = document.getElementById('index') as HTMLImageElement;
+    const element_community = document.getElementById('community') as HTMLImageElement;
+    const element_my = document.getElementById('my') as HTMLImageElement;
+    // 恢复其他元素的 src 为默认值
+    if (id !== 'tab1') { element_index.src = this.defaultSrc.index; }
+    if (id !== 'tab2') { element_community.src = this.defaultSrc.community; }
+    if (id !== 'tab3') { element_my.src = this.defaultSrc.my; }
+    // 清除之前的动画类
+    element_index.classList.remove('animate');
+    element_community.classList.remove('animate');
+    element_my.classList.remove('animate');
+
+    // 根据 id 设置当前元素的 src 并添加动画
+    if (id === 'tab1') {
+      element_index.src = 'https://s1.imagehub.cc/images/2025/01/10/0543f2a000861f7671ffe0afce7c39fe.png';
+      element_index.classList.add('animate');
+    } else if (id === 'tab2') {
+      element_community.src = 'https://s1.imagehub.cc/images/2025/01/10/a3242c545972d383223e843cb8fec27e.png';
+      element_community.classList.add('animate');
+    } else {
+      element_my.src = 'https://s1.imagehub.cc/images/2025/01/10/ce2df038038d90fff4a4c5c821c0ff96.png';
+      element_my.classList.add('animate');
+    }
+  }
+}

+ 8 - 6
E-Cover-app/src/lib/component/post-detail/post-detail.component.html

@@ -57,9 +57,11 @@
           </div>
         </div>
         
-        <div class="comment-right">
-          <ion-icon name="heart-outline" class="like-icon" ></ion-icon>
-          <span class="like-count">{{ comment.get('heart') }}</span>
+        <div class="comment-right" (click)="toggleLike(comment)">
+          <ion-icon name="heart-outline" class="like-icon" style=" margin-right:8px" 
+          [name]="comment.commentisLiked ? 'heart' : 'heart-outline'" 
+          [style.color]="comment.commentisLiked ? 'red' : 'black'" ></ion-icon>
+          <span class="like-count">{{ comment.data['like'] }}</span>
         </div>
       </div>
     </div>
@@ -92,9 +94,9 @@
           <ion-icon name="chatbubble-ellipses-outline" style="font-size: 30px; margin-right:8px"></ion-icon> 
           <span>{{comments.length}}</span>
         </ion-button>
-            
-        <ion-icon name="heart-outline" class="like-button" style=" margin-right:8px"></ion-icon>
-        <span>0</span>
+        <ion-icon class="like-button" [name]="post?.postisLiked ? 'heart' : 'heart-outline'"
+        [style.color]="post?.postisLiked ? 'red' : 'black'" (click)="toLike()"></ion-icon>
+        <span>{{post?.data['like']}}</span>
       </div>
     </div>
   </ion-footer>

+ 175 - 3
E-Cover-app/src/lib/component/post-detail/post-detail.component.ts

@@ -46,7 +46,37 @@ export class PostDetailComponent implements OnInit {
     await this.loadComments(); // 组件初始化时加载评论
   }
 
-  toggleFollow() {
+  //关注
+  async toggleFollow() {
+    const user=new CloudUser();
+    const userId = user.toPointer(); // 获取当前用户ID
+    if(user){
+    if (this.isFollowed ) {
+        // 如果已经关注,删除用户的关注记录
+        const query = new CloudQuery('attention'); // 创建查询对象
+        query.equalTo('attentionID', this.post.get('UserID').objectId); // 根据帖子作者ID查询
+        query.equalTo('UserID', userId); // 根据用户ID查询
+        const attentionRecord = await query.first(); // 获取关注记录对象
+        //console.log(likeRecord);
+        if(attentionRecord){
+          await attentionRecord.destroy().then(() => {
+            console.log('关注记录已删除:');
+          })
+        }   
+    } else {
+// 创建新的关注对象
+const attention = new CloudObject("attention"); 
+// 设置点赞记录的字段
+await attention.set({
+ UserID: new CloudUser().toPointer(), // 指向当前用户
+ attentionID: { "__type": "Pointer", "className": "_User", "objectId":this.post.get('UserID').objectId }, // 关注对象指针
+});
+// 保存关注记录
+await attention.save().then(() => {
+console.log('关注记录已保存:');
+})
+}
+    }
     this.isFollowed = !this.isFollowed; // 切换关注状态
   }
   /**
@@ -58,7 +88,27 @@ export class PostDetailComponent implements OnInit {
     query.equalTo("objectId", this.postId);
     let result = await query.find();
     this.post = result[0];
-    console.log(this.post);
+     // 判断用户有没有点赞过该帖子
+     const Query = new CloudQuery('postLikesRecord'); // 创建查询对象
+     Query.equalTo('UserID', new CloudUser().toPointer()); // 根据用户ID查询
+     Query.equalTo('postID', this.post.toPointer()); // 根据帖子指针查询
+     const likeRecord = await Query.first(); // 获取点赞记录
+     if (likeRecord) {
+      this.post.postisLiked = true; // 如果存在点赞记录,则帖子被当前用户点赞过
+     } else {
+      this.post.postisLiked = false; 
+     }
+    //console.log(this.post.get('UserID').objectId);
+    // 判断用户有没有关注过该帖子发布者,显示相应的状态
+    const query1 = new CloudQuery('attention'); // 创建查询对象
+    query1.equalTo('attentionID', this.post.get('UserID').objectId); // 根据帖子作者ID查询
+    query1.equalTo('UserID', new CloudUser().toPointer()); // 根据用户ID查询
+    const attentionRecord = await query1.first(); // 获取关注记录对象
+    if(attentionRecord){
+      this.isFollowed = true; // 如果存在关注记录,则帖子发布者被当前用户关注过
+    }else{
+      this.isFollowed = false; // 如果不存在关注记录,则帖子发布者未被当前用户关注过
+    }
 
   }
 
@@ -70,8 +120,130 @@ export class PostDetailComponent implements OnInit {
     this.comments = await query.find(); // 获取评论
     console.log('加载的评论:', this.comments);
 
+    for (const comment of this.comments) {
+      // 判断用户有没有点赞过该评论
+     const Query = new CloudQuery('commentLikesRecord'); // 创建查询对象
+     Query.equalTo('UserID', new CloudUser().toPointer()); // 根据用户ID查询
+     Query.equalTo('commentID', comment.toPointer()); // 根据评论指针查询
+     const likeRecord = await Query.first(); // 获取点赞记录
+     if (likeRecord) {
+      comment.commentisLiked = true; // 如果存在点赞记录,则该评论被当前用户点赞过
+     } else { // 如果不存在点赞记录,则该评论未被当前用户点赞过
+      comment.commentisLiked = false; 
+     }
+    }
+  }
+
+  // 切换评论点赞状态并更新数据库
+async toggleLike(comment: any) {
+  comment.commentisLiked = !comment.commentisLiked; // 切换当前评论的点赞状态
+  const commentId = comment.id; // 获取评论ID
+  const userId = new CloudUser().toPointer() // 获取当前用户ID
+
+  if (comment.commentisLiked) {   // 点赞
+    comment.data.like += 1; // 增加点赞数
+    await this.updateCommentLikeCount(commentId, 1,'comment'); // 更新数据库中的点赞数
+    await this.saveCommentLikeRecord( commentId,"commentLikesRecord",true); // 保存点赞记录
+  } else {
+    // 取消点赞
+    comment.data.like -= 1; // 减少点赞数
+    await this.updateCommentLikeCount(commentId, -1,'comment'); // 更新数据库中的点赞数
+    await this.removeCommentLikeRecord(userId, commentId,'commentLikesRecord',true); // 删除点赞记录
   }
 
+}
+
+
+// 切换帖子点赞状态并更新数据库
+async toLike() {
+  this.post.postisLiked = !this.post.postisLiked; // 切换当前帖子的点赞状态
+  const postId = this.post.id; // 获取帖子ID
+  const userId = new CloudUser().toPointer() // 获取当前用户ID
+
+  if (this.post.postisLiked) {   // 点赞
+    this.post.data.like += 1; // 增加点赞数
+    await this.updateCommentLikeCount(postId, 1,'post'); // 更新数据库中的点赞数
+    await this.saveCommentLikeRecord( postId,"postLikesRecord",false); // 保存点赞记录
+  } else {
+    // 取消点赞
+    this.post.data.like -= 1; // 减少点赞数
+    await this.updateCommentLikeCount(postId, -1,'post'); // 更新数据库中的点赞数
+    await this.removeCommentLikeRecord(userId, postId,'postLikesRecord',false); // 删除点赞记录
+  }
+
+}
+
+
+// 保存点赞记录
+async saveCommentLikeRecord( Id:any,RecordTable:any,flag:boolean){
+  // 创建新的点赞对象
+  const likeRecord = new CloudObject(RecordTable); 
+  const user = new CloudUser();
+  const currentUser =  user.current(); // 获取当前用户信息
+if (currentUser!=null) {
+// 设置点赞记录的字段
+if(flag){//如果为true则保存评论点赞记录
+await likeRecord.set({
+   UserID: new CloudUser().toPointer(), // 指向当前用户
+   commentID: { "__type": "Pointer", "className": "comment", "objectId": Id }, // 评论指针
+   
+});
+}
+else{ //否则保存帖子点赞记录
+  await likeRecord.set({
+    UserID: new CloudUser().toPointer(), // 指向当前用户
+    postID: { "__type": "Pointer", "className": "post", "objectId":Id  }, // 帖子指针
+    
+ });
+}
+
+console.log(likeRecord);
+
+// 保存点赞记录
+await likeRecord.save().then(() => {
+  console.log('点赞记录已保存:');
+})
+}
+}
+
+// 更新评论点赞数
+async updateCommentLikeCount(Id:any, count:number,Table:any){
+  const query = new CloudQuery(Table); // 创建查询对象
+  query.equalTo('objectId', Id); // 根据帖子ID查询
+  //console.log(postId);
+  const comment = await query.first(); // 获取对象
+  //console.log(post);
+  if(comment){
+    comment.data['like'] += count; // 更新点赞数
+   comment.id=Id;
+  await comment.save().then(() => {
+    console.log('评论点赞数已更新:');
+  })
+  }
+
+}
+
+ // 删除点赞记录
+ async removeCommentLikeRecord(userId:any, Id:any,Table:any,flag:boolean){
+  const query = new CloudQuery(Table); // 创建查询对象
+  if(flag){
+  query.equalTo('commentID', Id); // 根据评论ID查询
+  }
+  else{
+    query.equalTo('postID', Id); // 根据帖子ID查询
+  }
+  query.equalTo('UserID', userId); // 根据用户ID查询
+  const likeRecord = await query.first(); // 获取点赞记录对象
+  //console.log(likeRecord);
+  if(likeRecord){
+    await likeRecord.destroy().then(() => {
+      console.log('点赞记录已删除:');
+    })
+  }
+
+}
+
+
 
   tocomment() {
     this.isfooter = false; // 切换底部栏的显示样式
@@ -94,7 +266,7 @@ export class PostDetailComponent implements OnInit {
           UserID: new CloudUser().toPointer(), // 指向当前用户
           postID: { "__type": "Pointer", "className": "post", "objectId": this.post.id }, // 帖子指针
           content: this.newComment.trim(), // 评论内容
-          heart: 0 // 初始点赞数为0
+          like: 0 // 初始点赞数为0
         });
 
         // 保存评论

+ 8 - 6
E-Cover-app/src/lib/component/post-list/post-list.component.html

@@ -1,4 +1,4 @@
-<div class="post" *ngFor="let post of posts" (click)="goPostDetail(post)">
+<div class="post" *ngFor="let post of posts" >
   <div class="post-header">
     <div class="avatar">
       <ion-img
@@ -10,6 +10,8 @@
       <ion-icon name="ellipsis-horizontal" class="more-icon"></ion-icon>
     </div>
   </div>
+  <!--点击内容区域跳转到详情-->
+  <div (click)="goPostDetail(post)">
   <h2 class="post-title">{{ post?.get('title') }}</h2>
   <!--标签-->
   <div class="tag-container">
@@ -22,6 +24,7 @@
   <div class="image-gallery">
     <img *ngFor="let image of post.get('image')" [src]="image" alt="Post Image" class="post-image">
   </div>
+</div>
 
   <!-- 按钮区域 -->
   <div class="button-container">
@@ -29,14 +32,13 @@
       <ion-icon name="share-social-outline" class=""></ion-icon>
       <span>分享</span>
     </ion-button>
-    <ion-button fill="clear" class="action-button">
+    <ion-button fill="clear" class="action-button" (click)="goPostDetail(post)">
       <ion-icon name="chatbubble-outline"></ion-icon>
       <span>{{ post.commentCount  }}</span>
     </ion-button>
-    <ion-button fill="clear" class="action-button" (click)="toggleLike()">
-      <ion-icon name="heart-outline" [name]="isLiked ? 'heart' : 'heart-outline'"
-        [style.color]="isLiked ? 'red' : 'black'"></ion-icon>
-      <span>点赞</span>
+    <ion-button fill="clear" class="action-button" (click)="toggleLike(post)">
+      <ion-icon name="heart-outline" [name]="post.postisLiked ? 'heart' : 'heart-outline'" [style.color]="post.postisLiked ? 'red' : 'black'"></ion-icon>
+      <span>{{post.data['like']}}</span>
     </ion-button>
   </div>
 

+ 81 - 5
E-Cover-app/src/lib/component/post-list/post-list.component.ts

@@ -38,16 +38,92 @@ export class PostListComponent implements OnInit {
       const comments = await commentQuery.find(); // 获取评论
       post.commentCount = comments.length; // 将评论数存储在帖子对象中
       console.log('帖子评论数',post.commentCount);
+       // 判断用户有没有点赞过该帖子
+     const Query = new CloudQuery('postLikesRecord'); // 创建查询对象
+     Query.equalTo('UserID', new CloudUser().toPointer()); // 根据用户ID查询
+     Query.equalTo('postID', post.toPointer()); // 根据帖子指针查询
+     const likeRecord = await Query.first(); // 获取点赞记录
+     if (likeRecord) {
+      post.postisLiked = true; // 如果存在点赞记录,则帖子被当前用户点赞过
+     } else {
+      post.postisLiked = false; 
+     }
     }
   }
 
-  // 用于跟踪点赞状态
-  isLiked: boolean = false;
 
-  // 切换点赞状态
-  toggleLike() {
-    this.isLiked = !this.isLiked; // 切换状态
+  // 切换点赞状态并更新数据库
+  async toggleLike(post: any) {
+    post.postisLiked = !post.postisLiked; // 切换当前帖子的点赞状态
+    const postId = post.id; // 获取帖子ID
+    const userId = new CloudUser().toPointer() // 获取当前用户ID
+
+    if (post.postisLiked) {   // 点赞
+      post.data.like += 1; // 增加点赞数
+      await this.updatePostLikeCount(postId, 1); // 更新数据库中的点赞数
+      await this.savePostLikeRecord( postId); // 保存点赞记录
+    } else {
+      // 取消点赞
+      post.data.like -= 1; // 减少点赞数
+      await this.updatePostLikeCount(postId, -1); // 更新数据库中的点赞数
+      await this.removePostLikeRecord(userId, postId); // 删除点赞记录
+    }
+  
+}
+
+ // 保存点赞记录
+async savePostLikeRecord( postId:any){
+    // 创建新的点赞对象
+    const likeRecord = new CloudObject("postLikesRecord"); 
+    const user = new CloudUser();
+    const currentUser =  user.current(); // 获取当前用户信息
+  if (currentUser!=null) {
+ // 设置点赞记录的字段
+ await likeRecord.set({
+     UserID: new CloudUser().toPointer(), // 指向当前用户
+     postID: { "__type": "Pointer", "className": "post", "objectId": postId }, // 帖子指针
+ });
+
+ console.log(likeRecord);
+
+  // 保存点赞记录
+  await likeRecord.save().then(() => {
+    console.log('点赞记录已保存:');
+})
+}
+}
+
+// 更新帖子点赞数
+async updatePostLikeCount(postId:any, count:number){
+  const query = new CloudQuery('post'); // 创建查询对象
+  query.equalTo('objectId', postId); // 根据帖子ID查询
+  //console.log(postId);
+  const post = await query.first(); // 获取帖子对象
+  //console.log(post);
+  if(post){
+    post.data['like'] += count; // 更新点赞数
+   post.id=postId;
+  await post.save().then(() => {
+    console.log('帖子点赞数已更新:');
+  })
+  }
+
+}
+
+ // 删除点赞记录
+ async removePostLikeRecord(userId:any, postId:any){
+  const query = new CloudQuery('postLikesRecord'); // 创建查询对象
+  query.equalTo('postID', postId); // 根据帖子ID查询
+  query.equalTo('UserID', userId); // 根据用户ID查询
+  const likeRecord = await query.first(); // 获取点赞记录对象
+  //console.log(likeRecord);
+  if(likeRecord){
+    await likeRecord.destroy().then(() => {
+      console.log('点赞记录已删除:');
+    })
   }
+
+}
   goPostDetail(post:CloudObject) {
     this.router.navigate(['postDetail',post.id]);
   }

+ 3 - 0
E-Cover-app/src/lib/ncloud.ts

@@ -6,6 +6,9 @@ export class CloudObject {
     updatedAt: any;
     data: Record<string, any> = {};
     commentCount: number = 0;
+    postisLiked: boolean = false;
+    commentisLiked: boolean = false;
+    isFollowed: boolean = true;
 
     constructor(className: string) {
         this.className = className;