Ver Fonte

Your commit message

AAA123 há 3 meses atrás
pai
commit
49a6b482b1
100 ficheiros alterados com 4492 adições e 253 exclusões
  1. 100 46
      src/app/app-routing.module.ts
  2. 21 2
      src/app/app.component.ts
  3. 14 6
      src/app/app.module.ts
  4. 17 0
      src/app/case-detail/case-detail-routing.module.ts
  5. 20 0
      src/app/case-detail/case-detail.module.ts
  6. 30 0
      src/app/case-detail/case-detail.page.html
  7. 17 0
      src/app/case-detail/case-detail.page.scss
  8. 17 0
      src/app/case-detail/case-detail.page.spec.ts
  9. 47 0
      src/app/case-detail/case-detail.page.ts
  10. 17 0
      src/app/case/case-routing.module.ts
  11. 20 0
      src/app/case/case.module.ts
  12. 28 0
      src/app/case/case.page.html
  13. 8 0
      src/app/case/case.page.scss
  14. 17 0
      src/app/case/case.page.spec.ts
  15. 69 0
      src/app/case/case.page.ts
  16. 5 5
      src/app/consultation/consultation.page.ts
  17. 48 11
      src/app/edit-profile/edit-profile.page.html
  18. 97 64
      src/app/edit-profile/edit-profile.page.scss
  19. 73 15
      src/app/edit-profile/edit-profile.page.ts
  20. 17 0
      src/app/expert-lectures/expert-lectures-routing.module.ts
  21. 20 0
      src/app/expert-lectures/expert-lectures.module.ts
  22. 24 0
      src/app/expert-lectures/expert-lectures.page.html
  23. 42 0
      src/app/expert-lectures/expert-lectures.page.scss
  24. 17 0
      src/app/expert-lectures/expert-lectures.page.spec.ts
  25. 59 0
      src/app/expert-lectures/expert-lectures.page.ts
  26. 3 3
      src/app/eye-exam/eye-exam.page.ts
  27. 20 16
      src/app/faq/faq.page.html
  28. 104 12
      src/app/faq/faq.page.scss
  29. 6 3
      src/app/feedback/feedback.page.html
  30. 118 25
      src/app/feedback/feedback.page.scss
  31. 17 0
      src/app/health-community/health-community-routing.module.ts
  32. 20 0
      src/app/health-community/health-community.module.ts
  33. 40 0
      src/app/health-community/health-community.page.html
  34. 48 0
      src/app/health-community/health-community.page.scss
  35. 17 0
      src/app/health-community/health-community.page.spec.ts
  36. 138 0
      src/app/health-community/health-community.page.ts
  37. 17 0
      src/app/health-news/health-news-routing.module.ts
  38. 23 0
      src/app/health-news/health-news.module.ts
  39. 22 0
      src/app/health-news/health-news.page.html
  40. 92 0
      src/app/health-news/health-news.page.scss
  41. 17 0
      src/app/health-news/health-news.page.spec.ts
  42. 121 0
      src/app/health-news/health-news.page.ts
  43. 6 1
      src/app/health-record/health-record.page.html
  44. 92 20
      src/app/health-record/health-record.page.ts
  45. 82 10
      src/app/invite-friends/invite-friends.page.html
  46. 224 0
      src/app/invite-friends/invite-friends.page.scss
  47. 99 1
      src/app/invite-friends/invite-friends.page.ts
  48. 41 10
      src/app/manage-family/manage-family.page.html
  49. 85 0
      src/app/manage-family/manage-family.page.scss
  50. 156 3
      src/app/manage-family/manage-family.page.ts
  51. 17 0
      src/app/medical-services/medical-services-routing.module.ts
  52. 20 0
      src/app/medical-services/medical-services.module.ts
  53. 47 0
      src/app/medical-services/medical-services.page.html
  54. 89 0
      src/app/medical-services/medical-services.page.scss
  55. 17 0
      src/app/medical-services/medical-services.page.spec.ts
  56. 44 0
      src/app/medical-services/medical-services.page.ts
  57. 17 0
      src/app/medicine-detail/medicine-detail-routing.module.ts
  58. 20 0
      src/app/medicine-detail/medicine-detail.module.ts
  59. 37 0
      src/app/medicine-detail/medicine-detail.page.html
  60. 39 0
      src/app/medicine-detail/medicine-detail.page.scss
  61. 17 0
      src/app/medicine-detail/medicine-detail.page.spec.ts
  62. 50 0
      src/app/medicine-detail/medicine-detail.page.ts
  63. 17 0
      src/app/medicine-purchase/medicine-purchase-routing.module.ts
  64. 20 0
      src/app/medicine-purchase/medicine-purchase.module.ts
  65. 67 0
      src/app/medicine-purchase/medicine-purchase.page.html
  66. 232 0
      src/app/medicine-purchase/medicine-purchase.page.scss
  67. 17 0
      src/app/medicine-purchase/medicine-purchase.page.spec.ts
  68. 95 0
      src/app/medicine-purchase/medicine-purchase.page.ts
  69. 17 0
      src/app/new-post/new-post-routing.module.ts
  70. 20 0
      src/app/new-post/new-post.module.ts
  71. 22 0
      src/app/new-post/new-post.page.html
  72. 25 0
      src/app/new-post/new-post.page.scss
  73. 17 0
      src/app/new-post/new-post.page.spec.ts
  74. 44 0
      src/app/new-post/new-post.page.ts
  75. 17 0
      src/app/news-detail/news-detail-routing.module.ts
  76. 23 0
      src/app/news-detail/news-detail.module.ts
  77. 21 0
      src/app/news-detail/news-detail.page.html
  78. 60 0
      src/app/news-detail/news-detail.page.scss
  79. 17 0
      src/app/news-detail/news-detail.page.spec.ts
  80. 30 0
      src/app/news-detail/news-detail.page.ts
  81. 17 0
      src/app/orders/orders-routing.module.ts
  82. 20 0
      src/app/orders/orders.module.ts
  83. 33 0
      src/app/orders/orders.page.html
  84. 67 0
      src/app/orders/orders.page.scss
  85. 17 0
      src/app/orders/orders.page.spec.ts
  86. 78 0
      src/app/orders/orders.page.ts
  87. 38 0
      src/app/pipes/safe-html.pipe.spec.ts
  88. 14 0
      src/app/pipes/safe-html.pipe.ts
  89. 17 0
      src/app/points-and-coupons/points-and-coupons-routing.module.ts
  90. 20 0
      src/app/points-and-coupons/points-and-coupons.module.ts
  91. 62 0
      src/app/points-and-coupons/points-and-coupons.page.html
  92. 124 0
      src/app/points-and-coupons/points-and-coupons.page.scss
  93. 17 0
      src/app/points-and-coupons/points-and-coupons.page.spec.ts
  94. 42 0
      src/app/points-and-coupons/points-and-coupons.page.ts
  95. 17 0
      src/app/promotions/promotions-routing.module.ts
  96. 21 0
      src/app/promotions/promotions.module.ts
  97. 74 0
      src/app/promotions/promotions.page.html
  98. 50 0
      src/app/promotions/promotions.page.scss
  99. 17 0
      src/app/promotions/promotions.page.spec.ts
  100. 120 0
      src/app/promotions/promotions.page.ts

+ 100 - 46
src/app/app-routing.module.ts

@@ -1,61 +1,115 @@
-import { NgModule } from '@angular/core';
-import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
-
-const routes: Routes = [
-  {
-    path: '',
-    loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
-  },
-  {
-    path: 'appointment',
-    loadChildren: () => import('./appointment/appointment.module').then(m => m.AppointmentPageModule)
-  },
-  {
-    path: 'consultation',
-    loadChildren: () => import('./consultation/consultation.module').then(m => m.ConsultationPageModule)
-  },
-  {
-    path: 'details',
-    loadChildren: () => import('./details/details.module').then(m => m.DetailsPageModule)
-  },
-  {
-    path: 'edit-profile',
-    loadChildren: () => import('./edit-profile/edit-profile.module').then(m => m.EditProfilePageModule)
-  },
-  {
-    path: 'health-record',
-    loadChildren: () => import('./health-record/health-record.module').then(m => m.HealthRecordPageModule)
+import { NgModule } from '@angular/core';
+import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+  {
+    path: '',
+    loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
+  },
+  {
+    path: 'appointment',
+    loadChildren: () => import('./appointment/appointment.module').then(m => m.AppointmentPageModule)
+  },
+  {
+    path: 'consultation',
+    loadChildren: () => import('./consultation/consultation.module').then(m => m.ConsultationPageModule)
+  },
+  {
+    path: 'details',
+    loadChildren: () => import('./details/details.module').then(m => m.DetailsPageModule)
+  },
+  {
+    path: 'edit-profile',
+    loadChildren: () => import('./edit-profile/edit-profile.module').then(m => m.EditProfilePageModule)
+  },
+  {
+    path: 'health-record',
+    loadChildren: () => import('./health-record/health-record.module').then(m => m.HealthRecordPageModule)
+  },
+  {
+    path: 'annual-checkup/:index', // 添加 :index 参数
+    loadChildren: () => import('./annual-checkup/annual-checkup.module').then(m => m.AnnualCheckupPageModule)
+  },
+  {
+    path: 'eye-exam/:index', // 添加 :index 参数
+    loadChildren: () => import('./eye-exam/eye-exam.module').then(m => m.EyeExamPageModule)
+  },
+  {
+    path: 'faq',
+    loadChildren: () => import('./faq/faq.module').then( m => m.FaqPageModule)
+  },
+  {
+    path: 'feedback',
+    loadChildren: () => import('./feedback/feedback.module').then( m => m.FeedbackPageModule)
+  },
+  {
+    path: 'invite-friends',
+    loadChildren: () => import('./invite-friends/invite-friends.module').then( m => m.InviteFriendsPageModule)
+  },
+  {
+    path: 'manage-family',
+    loadChildren: () => import('./manage-family/manage-family.module').then( m => m.ManageFamilyPageModule)
+  },
+  {
+    path: 'case',
+    loadChildren: () => import('./case/case.module').then( m => m.CasePageModule)
+  },
+  {
+    path: 'case-detail/:id', // 使用 :id 参数来标识具体的病例
+    loadChildren: () => import('./case-detail/case-detail.module').then( m => m.CaseDetailPageModule)
+  },
+  {
+    path: 'health-news',
+    loadChildren: () => import('./health-news/health-news.module').then( m => m.HealthNewsPageModule)
+  },
+  {
+    path: 'news-detail',
+    loadChildren: () => import('./news-detail/news-detail.module').then( m => m.NewsDetailPageModule)
+  },
+  {
+    path: 'medicine-purchase',
+    loadChildren: () => import('./medicine-purchase/medicine-purchase.module').then( m => m.MedicinePurchasePageModule)
+  },
+  {
+    path: 'medicine-detail/:id', // 添加 :id 参数以匹配具体药品ID
+    loadChildren: () => import('./medicine-detail/medicine-detail.module').then( m => m.MedicineDetailPageModule)
+  },
  {
+    path: 'expert-lectures',
+    loadChildren: () => import('./expert-lectures/expert-lectures.module').then( m => m.ExpertLecturesPageModule)
   },
   {
-    path: 'annual-checkup/:index', // 添加 :index 参数
-    loadChildren: () => import('./annual-checkup/annual-checkup.module').then(m => m.AnnualCheckupPageModule)
+    path: 'health-community',
+    loadChildren: () => import('./health-community/health-community.module').then( m => m.HealthCommunityPageModule)
   },
   {
-    path: 'eye-exam/:index', // 添加 :index 参数
-    loadChildren: () => import('./eye-exam/eye-exam.module').then(m => m.EyeExamPageModule)
+    path: 'new-post',
+    loadChildren: () => import('./new-post/new-post.module').then( m => m.NewPostPageModule)
   },
   {
-    path: 'faq',
-    loadChildren: () => import('./faq/faq.module').then( m => m.FaqPageModule)
+    path: 'orders',
+    loadChildren: () => import('./orders/orders.module').then( m => m.OrdersPageModule)
   },
   {
-    path: 'feedback',
-    loadChildren: () => import('./feedback/feedback.module').then( m => m.FeedbackPageModule)
+    path: 'promotions',
+    loadChildren: () => import('./promotions/promotions.module').then( m => m.PromotionsPageModule)
   },
   {
-    path: 'invite-friends',
-    loadChildren: () => import('./invite-friends/invite-friends.module').then( m => m.InviteFriendsPageModule)
+    path: 'medical-services',
+    loadChildren: () => import('./medical-services/medical-services.module').then( m => m.MedicalServicesPageModule)
   },
   {
-    path: 'manage-family',
-    loadChildren: () => import('./manage-family/manage-family.module').then( m => m.ManageFamilyPageModule)
+    path: 'points-and-coupons',
+    loadChildren: () => import('./points-and-coupons/points-and-coupons.module').then( m => m.PointsAndCouponsPageModule)
   }
-];
 
-@NgModule({
-  imports: [
-    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
-  ],
-  exports: [RouterModule]
-})
+
+
+];
+
+@NgModule({
+  imports: [
+    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
+  ],
+  exports: [RouterModule]
+})
 export class AppRoutingModule {}

+ 21 - 2
src/app/app.component.ts

@@ -1,4 +1,7 @@
 import { Component } from '@angular/core';
+import { Platform } from '@ionic/angular';
+import { SplashScreen } from '@capacitor/splash-screen';
+import { UserService } from './services/user.service';
 
 @Component({
   selector: 'app-root',
@@ -6,5 +9,21 @@ import { Component } from '@angular/core';
   styleUrls: ['app.component.scss'],
 })
 export class AppComponent {
-  constructor() {}
-}
+  constructor(
+    private platform: Platform,
+    private userService: UserService
+  ) {
+    this.initializeApp();
+  }
+
+  initializeApp() {
+    this.platform.ready().then(() => {
+      // 初始化应用时尝试从本地存储加载用户信息
+      const storedUserInfo = localStorage.getItem('userInfo');
+      if (storedUserInfo) {
+        this.userService.userInfoSubject.next(JSON.parse(storedUserInfo));
+      }
+      SplashScreen.hide();
+    });
+  }
+}

+ 14 - 6
src/app/app.module.ts

@@ -1,27 +1,35 @@
 import { NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
 import { RouteReuseStrategy } from '@angular/router';
-
-
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { FormsModule } from '@angular/forms';
 import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
 
 import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
-
 import { HttpClientModule } from '@angular/common/http';
 
 @NgModule({
-  declarations: [AppComponent],
+  declarations: 
+  [
+    AppComponent,
+  ],
   imports: [
     BrowserModule,
     IonicModule.forRoot(),
     AppRoutingModule,
-    HttpClientModule // 导入 HttpClientModule
+    HttpClientModule, // 导入 HttpClientModule
+    BrowserAnimationsModule,
+    FormsModule, 
+    IonicModule,
   ],
   providers: [
   
     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
   ],
-  bootstrap: [AppComponent],
+  bootstrap: [
+    AppComponent,
+  ],
+
 })
 export class AppModule {}

+ 17 - 0
src/app/case-detail/case-detail-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { CaseDetailPage } from './case-detail.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: CaseDetailPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class CaseDetailPageRoutingModule {}

+ 20 - 0
src/app/case-detail/case-detail.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { CaseDetailPageRoutingModule } from './case-detail-routing.module';
+
+import { CaseDetailPage } from './case-detail.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    CaseDetailPageRoutingModule
+  ],
+  declarations: [CaseDetailPage]
+})
+export class CaseDetailPageModule {}

+ 30 - 0
src/app/case-detail/case-detail.page.html

@@ -0,0 +1,30 @@
+
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-button (click)="cancel()">
+        <ion-icon name="arrow-back"></ion-icon>
+        返回
+      </ion-button>
+    </ion-buttons>
+    <ion-title>病例详情</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="cancel()">取消</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="content-container">
+  <div class="form-container">
+    <ion-item>
+      <ion-label position="floating">病例标题</ion-label>
+      <ion-input [(ngModel)]="case.title" placeholder="请输入病例标题"></ion-input>
+    </ion-item>
+    <ion-item class="date-item">
+      <ion-label position="floating">日期</ion-label>
+      <ion-datetime displayFormat="YYYY-MM-DD" [(ngModel)]="case.date" placeholder="请选择日期"></ion-datetime>
+    </ion-item>
+    <!-- 添加更多字段如症状描述、诊断结果等 -->
+  </div>
+  <ion-button (click)="saveCase()" color="secondary" class="save-button">保存</ion-button>
+</ion-content>

+ 17 - 0
src/app/case-detail/case-detail.page.scss

@@ -0,0 +1,17 @@
+.date-item {
+    display: flex;
+    justify-content: space-between;
+  }
+  
+  .date-item ion-label {
+    flex-grow: 1;
+  }
+  
+  .date-item ion-datetime {
+    margin-left: auto;
+  }
+  
+  .save-button {
+    margin-top: 16px; /* 根据需要调整间距 */
+    align-self: flex-end;
+  }

+ 17 - 0
src/app/case-detail/case-detail.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CaseDetailPage } from './case-detail.page';
+
+describe('CaseDetailPage', () => {
+  let component: CaseDetailPage;
+  let fixture: ComponentFixture<CaseDetailPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CaseDetailPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 47 - 0
src/app/case-detail/case-detail.page.ts

@@ -0,0 +1,47 @@
+
+import { Component, OnInit } from '@angular/core';
+import { ModalController, NavParams } from '@ionic/angular';
+
+@Component({
+  selector: 'app-case-detail',
+  templateUrl: './case-detail.page.html',
+  styleUrls: ['./case-detail.page.scss'],
+})
+export class CaseDetailPage implements OnInit {
+
+  case: any = {
+    title: '',
+    date: new Date()
+  };
+  index: number | undefined;
+
+  constructor(
+    private modalCtrl: ModalController,
+    private navParams: NavParams
+  ) {}
+
+  ngOnInit() {
+    // 接收从父组件传递的数据
+    const caseData = this.navParams.get('case');
+    if (caseData) {
+      this.case = caseData;
+    } else {
+      this.case = { title: '', date: new Date() }; // 初始化一个新的空对象
+    }
+    this.index = this.navParams.get('index');
+
+    // 调试信息
+    console.log('Received case:', this.case);
+    console.log('Received index:', this.index);
+  }
+
+  saveCase() {
+    // 处理保存逻辑并返回数据
+    this.modalCtrl.dismiss({ case: this.case, index: this.index });
+  }
+
+  cancel() {
+    // 关闭模态窗口
+    this.modalCtrl.dismiss();
+  }
+}

+ 17 - 0
src/app/case/case-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { CasePage } from './case.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: CasePage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class CasePageRoutingModule {}

+ 20 - 0
src/app/case/case.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { CasePageRoutingModule } from './case-routing.module';
+
+import { CasePage } from './case.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    CasePageRoutingModule
+  ],
+  declarations: [CasePage]
+})
+export class CasePageModule {}

+ 28 - 0
src/app/case/case.page.html

@@ -0,0 +1,28 @@
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab1"></ion-back-button> <!-- 添加返回按钮 -->
+    </ion-buttons>
+    <ion-title>我的病例</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="addNewCase()">
+        <ion-icon name="add-circle"></ion-icon>
+        新增病例
+      </ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-list>
+    <ion-item *ngFor="let case of cases; let i = index" (click)="viewCaseDetails(i)">
+      <ion-label>
+        <h2>{{ case.title }}</h2>
+        <p>{{ case.date | date: 'yyyy-MM-dd' }}</p>
+      </ion-label>
+      <ion-button fill="clear" slot="end" (click)="deleteCase(i)">
+        <ion-icon name="trash"></ion-icon>
+      </ion-button>
+    </ion-item>
+  </ion-list>
+</ion-content>

+ 8 - 0
src/app/case/case.page.scss

@@ -0,0 +1,8 @@
+/* 可选:添加一些基本样式 */
+ion-list {
+    padding: 16px;
+  }
+  
+  ion-item {
+    margin-bottom: 8px;
+  }

+ 17 - 0
src/app/case/case.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CasePage } from './case.page';
+
+describe('CasePage', () => {
+  let component: CasePage;
+  let fixture: ComponentFixture<CasePage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CasePage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 69 - 0
src/app/case/case.page.ts

@@ -0,0 +1,69 @@
+import { Component, OnInit } from '@angular/core';
+import { ModalController } from '@ionic/angular';
+import { CaseDetailPage } from '../case-detail/case-detail.page';
+
+@Component({
+  selector: 'app-case',
+  templateUrl: './case.page.html',
+  styleUrls: ['./case.page.scss'],
+})
+export class CasePage implements OnInit {
+
+  cases: any[] = [
+    { title: '高血压', date: new Date('2024-01-15') },
+    { title: '糖尿病', date: new Date('2024-02-20') }
+    // 更多初始病例...
+  ];
+
+  constructor(private modalCtrl: ModalController) {}
+
+  ngOnInit() {
+    this.loadCases();
+  }
+
+  // 加载病例数据
+  loadCases() {
+    const storedCases = localStorage.getItem('cases');
+    if (storedCases) {
+      this.cases = JSON.parse(storedCases);
+    }
+  }
+
+  // 保存病例数据
+  saveCases() {
+    localStorage.setItem('cases', JSON.stringify(this.cases));
+  }
+
+  addNewCase() {
+    this.openCaseDetailModal(null);
+  }
+
+  viewCaseDetails(index: number) {
+    this.openCaseDetailModal(this.cases[index], index);
+  }
+
+  deleteCase(index: number) {
+    this.cases.splice(index, 1);
+    this.saveCases(); // 删除病例后立即保存更改
+  }
+
+  private async openCaseDetailModal(caseData?: any, index?: number) {
+    const modal = await this.modalCtrl.create({
+      component: CaseDetailPage,
+      componentProps: { case: caseData, index: index }
+    });
+
+    modal.onDidDismiss().then((data) => {
+      if (data.data && data.data.case) {
+        if (data.data.index !== undefined) {
+          this.cases[data.data.index] = data.data.case;
+        } else {
+          this.cases.push(data.data.case);
+        }
+        this.saveCases(); // 更新或添加病例后保存更改
+      }
+    });
+
+    return await modal.present();
+  }
+}

+ 5 - 5
src/app/consultation/consultation.page.ts

@@ -14,27 +14,27 @@ export class ConsultationPage {
   // 示例专家列表
   experts = [
     {
-      avatar: '../../assets/images/doctor.png',
+      avatar: '../../assets/images/医生1.jpg',
       name: '张医生',
       specialty: '心血管科'
     },
     {
-      avatar: '../../assets/images/doctor.png',
+      avatar: '../../assets/images/医生2.jpg',
       name: '李医生',
       specialty: '神经科'
     },
     {
-      avatar: '../../assets/images/doctor.png',
+      avatar: '../../assets/images/医生3.jpg',
       name: '王医生',
       specialty: '儿科'
     },
     {
-      avatar: '../../assets/images/doctor.png',
+      avatar: '../../assets/images/医生4.jpg',
       name: '赵医生',
       specialty: '外科'
     },
     {
-      avatar: '../../assets/images/doctor.png',
+      avatar: '../../assets/images/医生5.jpg',
       name: '陈医生',
       specialty: '内科'
     }

+ 48 - 11
src/app/edit-profile/edit-profile.page.html

@@ -13,18 +13,27 @@
     <ion-item>
       <ion-label position="floating">用户名</ion-label>
       <ion-input formControlName="username" type="text" required></ion-input>
+      <div *ngIf="profileForm.get('username')?.invalid && profileForm.get('username')?.touched" style="color: red;">
+        用户名是必填项。
+      </div>
     </ion-item>
-
+  
     <ion-item>
       <ion-label position="floating">邮箱</ion-label>
       <ion-input formControlName="email" type="email" required></ion-input>
+      <div *ngIf="profileForm.get('email')?.invalid && profileForm.get('email')?.touched" style="color: red;">
+        请输入有效的电子邮件地址。
+      </div>
     </ion-item>
-
+  
     <ion-item>
       <ion-label position="floating">手机号</ion-label>
       <ion-input formControlName="phone" type="tel" required></ion-input>
+      <div *ngIf="profileForm.get('phone')?.invalid && profileForm.get('phone')?.touched" style="color: red;">
+        请输入有效的手机号码。
+      </div>
     </ion-item>
-
+  
     <ion-item>
       <ion-label position="floating">性别</ion-label>
       <ion-select formControlName="gender" required>
@@ -32,17 +41,45 @@
         <ion-select-option value="female">女</ion-select-option>
         <ion-select-option value="other">其他</ion-select-option>
       </ion-select>
+      <div *ngIf="profileForm.get('gender')?.invalid && profileForm.get('gender')?.touched" style="color: red;">
+        性别是必选项。
+      </div>
     </ion-item>
-
-    <ion-item>
+    
+    <ion-item class="datetime-input-item">
       <ion-label position="floating">生日</ion-label>
-      <ion-datetime formControlName="birthday" displayFormat="YYYY-MM-DD" required></ion-datetime>
-    </ion-item>
-
-    <ion-item>
-      <ion-label position="floating">头像</ion-label>
-      <input type="file" accept="image/*" (change)="onFileSelected($event)">
+      <div class="datetime-container">
+        <ion-datetime formControlName="birthday" displayFormat="YYYY-MM-DD" required></ion-datetime>
+      </div>
+      <div *ngIf="profileForm.get('birthday')?.invalid && profileForm.get('birthday')?.touched" style="color: red;">
+        生日是必填项。
+      </div>
     </ion-item>
+  
+  <ion-item class="file-input-item">
+    <ion-label position="stacked" class="avatar-label">头像</ion-label>
+    <div class="file-input-container">
+      <div class="button-wrapper">
+        <label class="custom-file-button-wrapper">
+          <button ion-button class="custom-file-button" [disabled]="!profileForm.valid">
+            选择图片
+          </button>
+          <input 
+            id="fileInput"
+            type="file" 
+            accept="image/jpeg,image/png,image/gif" 
+            (change)="onFileSelected($event)"
+            style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;"
+          >
+        </label>
+      </div>
+      <p class="custom-file-label" *ngIf="selectedFile">{{ selectedFile.name }}</p>
+    </div>
+    <!-- 图片预览区 -->
+    <div *ngIf="previewImage" class="preview-image-container">
+      <img [src]="previewImage" alt="预览图片" class="preview-image">
+    </div>
+  </ion-item>
 
     <ion-button expand="block" type="submit" [disabled]="!profileForm.valid">保存</ion-button>
   </form>

+ 97 - 64
src/app/edit-profile/edit-profile.page.scss

@@ -1,70 +1,103 @@
-/* src/app/edit-profile/edit-profile.page.scss */
-ion-header ion-toolbar {
-    --background: var(--ion-color-primary);
-    --color: var(--ion-color-light);
-  }
-  
-  ion-content {
-    --padding-top: 0;
-    --padding-bottom: 0;
-  }
-  
-  form {
-    display: flex;
-    flex-direction: column;
-  
-    ion-item {
-      margin-bottom: 25px; // 增加每个表单项之间的间距
-    }
-  
-    ion-button {
-      margin-top: 20px;
-    }
-  }
-  
-  
-  ion-item {
-    --highlight-color: var(--ion-color-primary);
-    --padding-start: 16px; // 默认内边距
-    --padding-end: 16px;
-  }
-  
-  ion-select {
-    --placeholder-color: var(--ion-color-medium);
-  }
-  
-  ion-datetime {
-    --placeholder-color: var(--ion-color-medium);
- 
-    --padding-start: 24px; // 增加内边距以避免重叠
-    --padding-end: 24px;
-    --font-size: 16px; // 调整字体大小
-    text-align: center; // 居中文本
-    width: 100%; // 确保宽度占满父元素
+/* 定义颜色变量 */
+:root {
+  --ion-color-primary: #3880ff;
+  --ion-color-light: #ffffff;
+  --ion-color-medium: #555555;
+  --ion-color-primary-dark: #2f6fad; /* 更深的主色调,用于 hover 状态 */
+}
+
+/* 生日输入项样式 */
+.datetime-input-item {
+  display: flex;
+  align-items: center; /* 垂直居中对齐 */
+  justify-content: space-between; /* 左右分布 */
+  width: 100%; /* 确保整个容器占据全部宽度 */
+}
+
+.datetime-container {
+  margin-left: auto; /* 强制日期选择器靠右 */
+  display: flex;
+  align-items: center;
+}
+
+/* 错误信息样式 */
+.datetime-error {
+  color: red;
+  margin-top: 4px;
+}
+
+
+
+/* 文件输入项样式 */
+.file-input-item {
+  display: flex;
+  align-items: center; /* 垂直居中对齐 */
+  justify-content: space-between; /* 左右分布 */
+  width: 100%; /* 确保整个容器占据全部宽度 */
+}
+
+.file-input-container {
+  display: flex;
+  align-items: center;
+  width: 100%; /* 确保容器占据全部宽度 */
+}
+
+.button-wrapper {
+  margin-left: auto; /* 强制按钮靠右 */
+}
+
+.custom-file-button-wrapper {
+  position: relative;
+}
+
+.custom-file-button {
+  padding: 12px 24px;
+  background-color: var(--ion-color-primary);
+  color: var(--ion-color-light);
+  border: none;
+  border-radius: 4px;
+  font-size: 16px;
+  cursor: pointer;
+  text-align: center;
+  transition: background-color 0.3s ease; /* 添加过渡效果 */
+
+  &:hover {
+    background-color: var(--ion-color-primary-dark); /* 使用预先定义的深色变量 */
   }
-  
-  /* 自定义文件输入框的样式 */
-  input[type="file"] {
-    width: 100%;
-    padding: 12px; // 增加内边距
-    box-sizing: border-box;
-    border: 1px solid #ccc;
-    border-radius: 4px;
-    background-color: #fff;
-    font-size: 14px;
-    color: #555;
-    cursor: pointer;
+
+  &:active {
+    background-color: var(--ion-color-primary-darker); /* 更深的颜色表示按下状态 */
   }
-  /* 确保文件输入框不与其它元素重叠 */
-  ion-item input[type="file"] {
-    margin-top: 35px; // 增加上边距
+
+  &:focus {
+    outline: none;
+    box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
   }
-  
-  ion-button {
-    margin-top: 20px;
-    pointer-events: auto;
+
+  &.disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
   }
-  
+}
+
+.custom-file-label {
+  margin-top: 8px;
+  color: var(--ion-color-medium);
+  font-size: 14px;
+  text-align: right; /* 对齐到右侧 */
+}
+
+.avatar-label {
+  font-size: 1.3em; /* 增大字体大小 */
+  margin-right: 16px; /* 给标签添加一些右边距 */
+}
 
+/* 图片预览样式 */
+.preview-image-container {
+  margin-top: 8px;
+}
 
-  
+.preview-image {
+  max-width: 100%;
+  border-radius: 8px;
+}

+ 73 - 15
src/app/edit-profile/edit-profile.page.ts

@@ -1,8 +1,9 @@
-// src/app/edit-profile/edit-profile.page.ts
 import { Component, OnInit } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
-import { NavController } from '@ionic/angular';
+import { NavController, Platform } from '@ionic/angular';
 import { UserService } from '../services/user.service';
+import { ActivatedRoute, Router } from '@angular/router';
+
 
 @Component({
   selector: 'app-edit-profile',
@@ -10,26 +11,60 @@ import { UserService } from '../services/user.service';
   styleUrls: ['./edit-profile.page.scss'],
 })
 export class EditProfilePage implements OnInit {
-  // 在声明时初始化 profileForm
-  profileForm: FormGroup = new FormGroup({});
-
-  constructor(private fb: FormBuilder, private navCtrl: NavController,private userService: UserService) {}
+  profileForm: FormGroup;
+  previewImage: string | null = '../../assets/images/user-avatar.png'; // 默认头像路径
+  selectedFile: File | null = null;
 
-  ngOnInit() {
+  constructor(
+    private fb: FormBuilder,
+    private navCtrl: NavController,
+    private userService: UserService,
+    private router: Router,
+    private platform: Platform
+  ) {
+    // 初始化表单,并为 userAvatar 设置默认值
     this.profileForm = this.fb.group({
       username: ['', [Validators.required]],
       email: ['', [Validators.required, Validators.email]],
       phone: ['', [Validators.required, Validators.pattern('^[0-9]*$')]],
       gender: ['', [Validators.required]],
-      birthday: ['', [Validators.required]]
+      birthday: ['', [Validators.required]],
+      userAvatar: ['../../assets/images/user-avatar.png', []] as [string | null, Validators[]] // 设置默认值并明确类型
+    });
+
+    // 预填充表单(如果有初始用户信息)
+    this.userService.getUserInfo().subscribe(userInfo => {
+      if (userInfo) {
+        this.profileForm.patchValue(userInfo);
+        this.previewImage = userInfo.userAvatar ?? '../../assets/images/user-avatar.png'; // 确保预览图像是最新的头像或默认值
+      }
     });
   }
 
+  ngOnInit() {
+    // 如果需要在页面加载时执行额外的初始化逻辑,可以在这里添加
+  }
+
   onFileSelected(event: Event) {
     const input = event.target as HTMLInputElement;
     if (input.files && input.files[0]) {
-      // 这里可以添加处理文件的逻辑,例如上传到服务器
-      console.log('Selected file:', input.files[0]);
+      const file = input.files[0];
+      const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
+
+      if (allowedTypes.includes(file.type)) {
+        this.readFileAsBase64(file).then(base64Data => {
+          this.selectedFile = file;
+          this.previewImage = base64Data; // 设置预览图
+          this.profileForm.patchValue({ userAvatar: base64Data }); // 更新表单中的头像字段
+        }).catch(error => {
+          console.error('Failed to read file as Base64:', error);
+        });
+      } else {
+        alert('请选择有效的图片文件(支持的格式:JPEG, PNG, GIF)。');
+        input.value = '';
+        this.selectedFile = null;
+        this.previewImage = '../../assets/images/user-avatar.png'; // 清除预览图并恢复默认值
+      }
     }
   }
 
@@ -37,11 +72,34 @@ export class EditProfilePage implements OnInit {
     if (this.profileForm.valid) {
       const updatedUserInfo = this.profileForm.value;
       console.log('Profile saved:', updatedUserInfo);
-      
-      // 更新全局用户信息
-      this.userService.updateUserInfo(updatedUserInfo);
-
-      this.navCtrl.pop(); // 保存成功后返回上一页
+  
+      // 更新用户信息
+      this.userService.updateUserInfo(updatedUserInfo).then(() => {
+        this.navigateToTab3(); // 保存成功后跳转到 tab3 页面
+      }).catch(error => {
+        console.error('Failed to update user info:', error);
+      });
+    } else {
+      console.warn('Form is invalid. Please check the inputs.');
+      Object.keys(this.profileForm.controls).forEach(key => {
+        const control = this.profileForm.get(key);
+        if (control?.invalid) {
+          console.warn(`Invalid ${key}:`, control.errors);
+        }
+      });
     }
   }
+
+  private async readFileAsBase64(file: File): Promise<string> {
+    return new Promise((resolve, reject) => {
+      const reader = new FileReader();
+      reader.onloadend = () => resolve(reader.result as string || '');
+      reader.onerror = reject;
+      reader.readAsDataURL(file); // 读取文件为 Base64 编码的字符串
+    });
+  }
+
+  private navigateToTab3() {
+    this.router.navigate(['/tabs/tab3']);
+  }
 }

+ 17 - 0
src/app/expert-lectures/expert-lectures-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { ExpertLecturesPage } from './expert-lectures.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: ExpertLecturesPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class ExpertLecturesPageRoutingModule {}

+ 20 - 0
src/app/expert-lectures/expert-lectures.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { ExpertLecturesPageRoutingModule } from './expert-lectures-routing.module';
+
+import { ExpertLecturesPage } from './expert-lectures.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    ExpertLecturesPageRoutingModule
+  ],
+  declarations: [ExpertLecturesPage]
+})
+export class ExpertLecturesPageModule {}

+ 24 - 0
src/app/expert-lectures/expert-lectures.page.html

@@ -0,0 +1,24 @@
+<!-- src/app/pages/expert-lectures/expert-lectures.page.html -->
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab1"></ion-back-button>
+    </ion-buttons>
+    <ion-title>专家讲座</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-list>
+    <ion-item *ngFor="let lecture of lectures">
+      <ion-thumbnail slot="start">
+        <img [src]="lecture.imageUrl" alt="{{ lecture.title }}">
+      </ion-thumbnail>
+      <ion-label>
+        <h2>{{ lecture.title }}</h2>
+        <p>{{ lecture.speaker }} | {{ lecture.date | date:'mediumDate' }}</p>
+        <p>{{ lecture.description | slice:0:80 }}...</p>
+      </ion-label>
+    </ion-item>
+  </ion-list>
+</ion-content>

+ 42 - 0
src/app/expert-lectures/expert-lectures.page.scss

@@ -0,0 +1,42 @@
+/* src/app/pages/expert-lectures/expert-lectures.page.scss */
+ion-content {
+    --background: #f5f6fa;
+    padding-top: 20px; /* 确保内容区有合适的顶部间距 */
+  }
+  
+  ion-list {
+    margin: 0;
+    padding: 0;
+  }
+  
+  ion-item {
+    --padding-start: 16px;
+    --padding-end: 16px;
+    --border-radius: 8px;
+    --box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 10px;
+    background: white;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    display: flex;
+    align-items: center;
+  }
+  
+  ion-thumbnail img {
+    width: 60px;
+    height: 60px;
+    object-fit: cover;
+    border-radius: 8px;
+  }
+  
+  ion-label h2 {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 4px;
+  }
+  
+  ion-label p {
+    font-size: 14px;
+    color: #6c757d;
+    margin: 2px 0;
+  }

+ 17 - 0
src/app/expert-lectures/expert-lectures.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ExpertLecturesPage } from './expert-lectures.page';
+
+describe('ExpertLecturesPage', () => {
+  let component: ExpertLecturesPage;
+  let fixture: ComponentFixture<ExpertLecturesPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ExpertLecturesPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 59 - 0
src/app/expert-lectures/expert-lectures.page.ts

@@ -0,0 +1,59 @@
+// src/app/pages/expert-lectures/expert-lectures.page.ts
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router'; // 导入 Router
+
+@Component({
+  selector: 'app-expert-lectures',
+  templateUrl: './expert-lectures.page.html',
+  styleUrls: ['./expert-lectures.page.scss'],
+})
+export class ExpertLecturesPage implements OnInit {
+  lectures = [
+    {
+      title: '心血管疾病的预防与治疗',
+      speaker: '李教授',
+      date: '2024-12-25',
+      description: '了解如何通过生活方式改变和医学干预来预防心血管疾病...',
+      imageUrl: '../assets/images/病1.jpg' // 确保图片路径正确
+    },
+    {
+      title: '糖尿病管理的新进展',
+      speaker: '王博士',
+      date: '2024-12-30',
+      description: '探讨最新的糖尿病管理技术和方法,帮助患者更好地控制病情...',
+      imageUrl: '../assets/images/病2.jpg' // 确保图片路径正确
+    },
+    {
+      title: '心理健康的重要性',
+      speaker: '张心理学家',
+      date: '2024-12-27',
+      description: '心理健康对整体健康的影响及日常维护的方法...',
+      imageUrl: '../assets/images/病3.jpg' // 确保图片路径正确
+    },
+    {
+      title: '癌症早期筛查的意义',
+      speaker: '赵医生',
+      date: '2024-12-28',
+      description: '介绍癌症早期筛查的重要性和常用方法...',
+      imageUrl: '../assets/images/病4.jpg' // 确保图片路径正确
+    },
+    {
+      title: '营养与免疫系统的关系',
+      speaker: '孙营养师',
+      date: '2024-12-29',
+      description: '探讨营养在增强免疫系统中的作用及合理膳食建议...',
+      imageUrl: '../assets/images/病5.jpg' // 确保图片路径正确
+    },
+    // 添加更多讲座...
+  ];
+
+  constructor(private router: Router) {} // 注入 Router
+
+  ngOnInit() {}
+
+  // // 定义 goToDetail 方法
+  // goToDetail(lecture: any) {
+  //   // 这里可以根据需要调整路由参数
+  //   this.router.navigate(['/expert-lecture-detail', lecture.title]);
+  // }
+}

+ 3 - 3
src/app/eye-exam/eye-exam.page.ts

@@ -34,10 +34,10 @@ export class EyeExamPage implements OnInit {
     return {
       title: '眼科检查报告',
       date: new Date(),
-      details: '<p>视力良好,无异常。</p><p>建议定期复查。</p>',
+      details: '视力良好,无异常。建议定期复查。',
       attachments: [
-        { url: 'https://example.com/attachment1.jpg', name: '附件1' },
-        { url: 'https://example.com/attachment2.jpg', name: '附件2' }
+        { url: '../../assets/images/眼科图.jpg', name: '附件1' },
+        { url: '../../assets/images/眼科图2.jpg', name: '附件2' }
       ]
     };
   }

+ 20 - 16
src/app/faq/faq.page.html

@@ -1,47 +1,51 @@
 <ion-header>
   <ion-toolbar>
     <ion-buttons slot="start">
-      <ion-back-button defaultHref="/tab3"></ion-back-button>
+      <ion-back-button defaultHref="/tabs/tab3"></ion-back-button>
     </ion-buttons>
     <ion-title>常见问题</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content>
-  <ion-list>
-    <ion-accordion-group>
-      <ion-accordion value="first">
-        <ion-item slot="header" color="light">
+<ion-content class="faq-content">
+  <ion-list class="faq-list">
+    <ion-accordion-group class="faq-accordion-group">
+      <ion-accordion value="first" class="faq-accordion">
+        <ion-item slot="header" color="light" class="faq-item-header">
+          <ion-icon name="person-add-outline" slot="start"></ion-icon>
           <ion-label>问题 1: 如何注册账户?</ion-label>
         </ion-item>
-        <div class="ion-padding" slot="content">
+        <div class="faq-item-content ion-padding" slot="content">
           <p>要注册账户,请点击应用首页的“注册”按钮,然后按照提示填写相关信息并提交。</p>
         </div>
       </ion-accordion>
 
-      <ion-accordion value="second">
-        <ion-item slot="header" color="light">
+      <ion-accordion value="second" class="faq-accordion">
+        <ion-item slot="header" color="light" class="faq-item-header">
+          <ion-icon name="key-outline" slot="start"></ion-icon>
           <ion-label>问题 2: 如何找回密码?</ion-label>
         </ion-item>
-        <div class="ion-padding" slot="content">
+        <div class="faq-item-content ion-padding" slot="content">
           <p>如果您忘记了密码,可以在登录页面点击“忘记密码?”链接,然后按照提示操作来重置您的密码。</p>
         </div>
       </ion-accordion>
 
-      <ion-accordion value="third">
-        <ion-item slot="header" color="light">
+      <ion-accordion value="third" class="faq-accordion">
+        <ion-item slot="header" color="light" class="faq-item-header">
+          <ion-icon name="chatbubble-ellipses-outline" slot="start"></ion-icon>
           <ion-label>问题 3: 如何联系客服?</ion-label>
         </ion-item>
-        <div class="ion-padding" slot="content">
+        <div class="faq-item-content ion-padding" slot="content">
           <p>您可以通过应用内的“联系我们”功能或发送电子邮件至 support&#64;example.com 联系我们的客服团队。</p>
         </div>
       </ion-accordion>
 
-      <ion-accordion value="fourth">
-        <ion-item slot="header" color="light">
+      <ion-accordion value="fourth" class="faq-accordion">
+        <ion-item slot="header" color="light" class="faq-item-header">
+          <ion-icon name="person-circle-outline" slot="start"></ion-icon>
           <ion-label>问题 4: 如何修改个人信息?</ion-label>
         </ion-item>
-        <div class="ion-padding" slot="content">
+        <div class="faq-item-content ion-padding" slot="content">
           <p>您可以在应用的设置页面找到“个人信息”选项,点击后即可编辑和保存您的个人信息。</p>
         </div>
       </ion-accordion>

+ 104 - 12
src/app/faq/faq.page.scss

@@ -1,15 +1,107 @@
-ion-accordion {
-    --background: var(--ion-item-background, var(--ion-background-color, #fff));
+.faq-content {
+  --background: #f4f5f8; /* 设置内容区域的背景色 */
+  padding: 16px;
+}
+
+ion-title {
+  color:#3880ff;
+  font-weight: bold;
+  text-align: left;
+}
+
+.faq-list {
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  background: linear-gradient(135deg, #eaf5ff, #fff); /* 渐变背景 */
+}
+
+.faq-accordion-group {
+  background-color: #fff;
+}
+
+.faq-accordion {
+  --background: #fff; /* 默认关闭时的背景色 */
+  transition: background-color 0.3s ease;
+
+  &[expanded] {
+    --background: #f9f9f9; /* 展开时的背景色 */
   }
-  
-  ion-accordion[expanded] {
-    --background: var(--ion-item-background, var(--ion-background-color, #f0f0f0));
+}
+
+.faq-item-header {
+  --color: #333; /* 文本颜色 */
+  --border-width: 0;
+  --padding-start: 16px;
+  --padding-end: 16px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s ease;
+
+  &:hover {
+    background-color: #f0f0f0;
   }
-  
-  ion-accordion ion-item[slot="header"] {
-    --color: var(--ion-text-color, #000);
+
+  &[expanded] {
+    --color: #3880ff; /* 展开时的文本颜色 */
+    background-color: #eaf5ff;
   }
-  
-  ion-accordion[expanded] ion-item[slot="header"] {
-    --color: var(--ion-color-primary, #3880ff);
-  }
+
+  &::after {
+    content: "▼"; /* 关闭时显示向下的箭头 */
+    float: right;
+    margin-top: 4px;
+    color: #333;
+    transition: transform 0.3s ease;
+  }
+
+  &[expanded]::after {
+    content: "▲"; /* 展开时显示向上的箭头 */
+    color: #3880ff;
+    transform: rotate(-180deg);
+  }
+
+  ion-icon {
+    margin-right: 8px;
+    color: #3880ff;
+    font-size: 1.2rem;
+  }
+}
+
+.faq-item-content {
+  padding: 16px;
+  border-top: 1px solid #eaeaea;
+  background-color: #f9f9f9;
+  color: #555;
+  font-size: 0.95rem;
+  line-height: 1.6;
+}
+
+/* 分隔线 */
+.faq-accordion:not(:last-child) .faq-item-header {
+  border-bottom: 1px solid #eaeaea;
+}
+
+/* 页面顶部标题 */
+.faq-title {
+  text-align: center;
+  font-size: 1.8rem;
+  font-weight: bold;
+  margin-bottom: 24px;
+  color: #333;
+  letter-spacing: 0.5px;
+  text-transform: uppercase;
+  background: linear-gradient(90deg, #ffcc00, #ff9900);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+/* 添加一个欢迎信息 */
+.welcome-message {
+  text-align: center;
+  margin-bottom: 24px;
+  color: #666;
+  font-size: 1.2rem;
+  font-weight: 300;
+}

+ 6 - 3
src/app/feedback/feedback.page.html

@@ -1,5 +1,5 @@
 <ion-header>
-  <ion-toolbar>
+  <ion-toolbar color="primary">
     <ion-buttons slot="start">
       <ion-back-button defaultHref="/tabs/tab3"></ion-back-button>
     </ion-buttons>
@@ -7,17 +7,20 @@
   </ion-toolbar>
 </ion-header>
 
-<ion-content>
-  <form [formGroup]="feedbackForm">
+<ion-content class="feedback-content">
+  <form [formGroup]="feedbackForm" class="feedback-form">
     <ion-item>
+      <ion-icon name="person-outline" slot="start"></ion-icon>
       <ion-label position="floating">姓名</ion-label>
       <ion-input formControlName="name"></ion-input>
     </ion-item>
     <ion-item>
+      <ion-icon name="mail-outline" slot="start"></ion-icon>
       <ion-label position="floating">电子邮件</ion-label>
       <ion-input type="email" formControlName="email"></ion-input>
     </ion-item>
     <ion-item>
+      <ion-icon name="chatbubble-ellipses-outline" slot="start"></ion-icon>
       <ion-label position="floating">反馈内容</ion-label>
       <ion-textarea formControlName="message"></ion-textarea>
     </ion-item>

+ 118 - 25
src/app/feedback/feedback.page.scss

@@ -1,36 +1,129 @@
-ion-header {
-    --background: var(--ion-color-primary);
+/* 定义全局变量 */
+:root {
+  --ion-color-primary: #488aff;
+  --ion-color-light: #ffffff;
+}
+
+/* 设置页面整体背景 */
+.feedback-content {
+  background: linear-gradient(135deg, #f7f7f7, #eaf5ff);
+  padding: 20px;
+}
+
+/* 欢迎信息 */
+.welcome-message {
+  text-align: center;
+  margin-bottom: 24px;
+  font-size: 1.2rem;
+  color: var(--ion-color-primary);
+  font-weight: bold;
+  padding: 16px;
+  border-radius: 8px;
+  background: rgba(72, 138, 255, 0.1);
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
+}
+
+/* 表单容器 */
+.feedback-form {
+  max-width: 600px;
+  margin: 0 auto;
+  background: linear-gradient(135deg, #fff, #eaf5ff);
+  border-radius: 16px;
+  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
+  padding: 24px;
+  transition: transform 0.3s ease;
+
+  &:hover {
+    transform: translateY(-5px);
+  }
+}
+
+/* 工具栏样式 */
+ion-toolbar {
+  --background: var(--ion-color-primary);
+  --color: var(--ion-color-light);
+}
+
+/* 返回按钮样式 */
+ion-back-button {
+  --color: var(--ion-color-light);
+}
+
+/* 标题样式 */
+ion-title {
+  color: var(--ion-color-light);
+  font-weight: bold;
+  text-align: left;
+}
+
+/* 输入项样式 */
+ion-item {
+  margin-bottom: 16px;
+  --border-color: transparent;
+  --background: transparent;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+
+  &:focus-within {
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
   }
-  
-  ion-toolbar {
-    --color: var(--ion-color-light);
+
+  ion-icon.input-icon {
+    color: var(--ion-color-primary);
+    margin-right: 10px;
+    transition: transform 0.3s ease;
+
+    &.animate-spin {
+      animation: spin 2s infinite linear;
+    }
   }
-  
-  ion-content {
-    padding: 20px;
+}
+
+/* 动画 */
+@keyframes spin {
+  from { transform: rotate(0deg); }
+  to { transform: rotate(360deg); }
+}
+
+/* 按钮样式 */
+ion-button {
+  margin-top: 24px;
+  --background: var(--ion-color-primary);
+  --color: var(--ion-color-light);
+  transition: all 0.3s ease;
+
+  &[disabled] {
+    opacity: 0.5;
   }
-  
-  ion-item {
-    margin-bottom: 10px;
+
+  &:hover,
+  &:focus {
+    --background: darken(#488aff, 10%);
   }
-  
-  ion-button {
-    margin-top: 20px;
-    pointer-events: auto;
+
+  &:active {
+    transform: scale(0.98);
   }
+}
 
-  /* 确保返回按钮有明显的颜色 */
-ion-back-button {
-  --color: #ffffff; /* 使用白色或其他浅色 */
+/* 浮动标签样式 */
+ion-label {
+  color: #555;
 }
 
-/* 改进标题文字的颜色 */
-ion-title {
-  color: #ffffff; /* 使用白色或其他浅色 */
+/* 文本区域样式 */
+ion-textarea {
+  min-height: 100px;
 }
 
-/* 如果需要进一步调整工具栏的背景色 */
-ion-toolbar {
-  --background: var(--ion-color-primary); /* 保持或改变为合适的背景颜色 */
-  --color: #ffffff; /* 工具栏内元素(如标题)的文字颜色 */
+/* 确保提交按钮在所有设备上都能正确显示 */
+@media (max-width: 600px) {
+  .feedback-form {
+    padding: 16px;
+  }
+
+  .welcome-message {
+    font-size: 1rem;
+  }
 }

+ 17 - 0
src/app/health-community/health-community-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { HealthCommunityPage } from './health-community.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: HealthCommunityPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class HealthCommunityPageRoutingModule {}

+ 20 - 0
src/app/health-community/health-community.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { HealthCommunityPageRoutingModule } from './health-community-routing.module';
+
+import { HealthCommunityPage } from './health-community.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    HealthCommunityPageRoutingModule
+  ],
+  declarations: [HealthCommunityPage]
+})
+export class HealthCommunityPageModule {}

+ 40 - 0
src/app/health-community/health-community.page.html

@@ -0,0 +1,40 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab1"></ion-back-button>
+    </ion-buttons>
+    <ion-title>健康社区</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-list>
+    <ion-item *ngFor="let post of posts; let i = index" (click)="goToPostDetail(post)">
+      <ion-thumbnail slot="start">
+        <img [src]="post.imageUrl" alt="{{ post.title }}">
+      </ion-thumbnail>
+      <ion-label>
+        <div style="display: flex; align-items: center;">
+          <img *ngIf="post.authorAvatar" [src]="post.authorAvatar" alt="Author Avatar" style="width: 32px; height: 32px; border-radius: 50%; margin-right: 8px;" />
+          <h2>{{ post.title }}</h2>
+        </div>
+        <p>{{ post.author }} | {{ post.date | date:'mediumDate' }}</p>
+        <p>{{ post.content | slice:0:80 }}...</p>
+      </ion-label>
+
+      <!-- 删除按钮 -->
+      <ion-buttons *ngIf="isCurrentUser(post.author)" slot="end">
+        <ion-button (click)="confirmDeletePost(i)" fill="clear" color="danger">
+          <ion-icon name="trash-outline"></ion-icon>
+        </ion-button>
+      </ion-buttons>
+    </ion-item>
+  </ion-list>
+
+  <!-- 浮动操作按钮 -->
+  <ion-fab vertical="bottom" horizontal="end" slot="fixed">
+    <ion-fab-button (click)="openNewPost()">
+      <ion-icon name="add"></ion-icon>
+    </ion-fab-button>
+  </ion-fab>
+</ion-content>

+ 48 - 0
src/app/health-community/health-community.page.scss

@@ -0,0 +1,48 @@
+/* src/app/pages/health-community/health-community.page.scss */
+ion-content {
+    --background: #f5f6fa;
+    padding-top: 20px; /* 确保内容区有合适的顶部间距 */
+  }
+  
+  ion-list {
+    margin: 0;
+    padding: 0;
+  }
+  
+  ion-item {
+    --padding-start: 16px;
+    --padding-end: 16px;
+    --border-radius: 8px;
+    --box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 10px;
+    background: white;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    display: flex;
+    align-items: center;
+  }
+  
+  ion-thumbnail img {
+    width: 60px;
+    height: 60px;
+    object-fit: cover;
+    border-radius: 8px;
+  }
+  
+  ion-label h2 {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 4px;
+  }
+  
+  ion-label p {
+    font-size: 14px;
+    color: #6c757d;
+    margin: 2px 0;
+  }
+  
+  ion-fab-button {
+    --background: #4a90e2;
+    --color: white;
+    --border-radius: 50%;
+  }

+ 17 - 0
src/app/health-community/health-community.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { HealthCommunityPage } from './health-community.page';
+
+describe('HealthCommunityPage', () => {
+  let component: HealthCommunityPage;
+  let fixture: ComponentFixture<HealthCommunityPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(HealthCommunityPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 138 - 0
src/app/health-community/health-community.page.ts

@@ -0,0 +1,138 @@
+import { Component, OnInit } from '@angular/core';
+import { ModalController, AlertController } from '@ionic/angular';
+import { NewPostPage } from '../new-post/new-post.page'; // 假设我们有一个新帖子页面
+import { UserService } from '../services/user.service'; // 导入 UserService
+import { Subscription, forkJoin, firstValueFrom } from 'rxjs';
+
+@Component({
+  selector: 'app-health-community',
+  templateUrl: './health-community.page.html',
+  styleUrls: ['./health-community.page.scss'],
+})
+export class HealthCommunityPage implements OnInit {
+  posts = [
+    {
+      id: 1,
+      title: '如何保持健康的饮食习惯',
+      author: '张三',
+      date: new Date('2024-12-18'),
+      content: '保持健康的饮食习惯对于维持良好的身体状态非常重要...',
+      imageUrl: '../../assets/images/用户1.jpg', // 确保图片路径正确
+      authorAvatar: '' // 添加作者头像属性,默认为空字符串
+    },
+    {
+      id: 2,
+      title: '运动的好处及建议',
+      author: '李四',
+      date: new Date('2024-12-17'),
+      content: '适量的运动不仅有助于增强体质,还能改善心情...',
+      imageUrl: '../../assets/images/用户2.jpg', // 确保图片路径正确
+      authorAvatar: '' // 添加作者头像属性,默认为空字符串
+    },
+    // 添加更多帖子...
+  ];
+  private userSubscription: Subscription | undefined;
+  currentUser: string | null = null; // 存储当前用户名
+
+  constructor(
+    private modalCtrl: ModalController,
+    private userService: UserService, // 注入 UserService
+    private alertController: AlertController, // 注入 AlertController
+  ) {}
+
+  isCurrentUser(author: string): boolean {
+    return this.currentUser === author;
+  }
+
+  async confirmDeletePost(index: number) {
+    const alert = await this.alertController.create({
+      header: '确认删除',
+      message: '确定要删除这条帖子吗?',
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel',
+          cssClass: 'secondary'
+        },
+        {
+          text: '确定',
+          handler: () => {
+            this.deletePost(index);
+          }
+        }
+      ]
+    });
+
+    await alert.present();
+  }
+
+  deletePost(index: number) {
+    // 从帖子数组中移除指定索引的帖子
+    this.posts.splice(index, 1);
+
+    // 更新本地存储中的帖子数据
+    localStorage.setItem('posts', JSON.stringify(this.posts));
+
+    console.log('Post deleted:', index);
+  }
+
+  ngOnInit() {
+    // 加载本地存储中的帖子数据
+    const savedPosts = localStorage.getItem('posts');
+    if (savedPosts) {
+      this.posts = JSON.parse(savedPosts);
+    }
+  
+    // 获取当前用户的用户名
+    this.userService.getUserInfo().subscribe(userInfo => {
+      if (userInfo) {
+        this.currentUser = userInfo.username || '当前用户'; // 根据实际情况设置默认值
+        // 更新当前用户自己的帖子的作者头像
+        this.posts.forEach(post => {
+          if (post.author === this.currentUser) {
+            post.authorAvatar = userInfo.userAvatar || '';
+          }
+        });
+      }
+    });
+  }
+
+  goToPostDetail(post: any) {
+    // 这里可以实现导航到详细页面的逻辑
+    console.log('Go to post detail:', post);
+  }
+
+  async openNewPost() {
+    const modal = await this.modalCtrl.create({
+      component: NewPostPage,
+      cssClass: 'my-custom-class'
+    });
+
+    try {
+      await modal.present();
+
+      const data = await modal.onDidDismiss();
+
+      if (data && data.data) {
+        // 在创建新帖子之前获取当前用户的头像
+        const currentUserInfo = await firstValueFrom(this.userService.getUserInfo());
+        const authorAvatar = currentUserInfo?.userAvatar || '../../assets/images/user-avatar.png';
+
+        const newPost = {
+          id: this.posts.length + 1,
+          title: data.data.title,
+          author: this.currentUser || '当前用户', // 使用当前用户名
+          date: new Date(),
+          content: data.data.content,
+          imageUrl: data.data.imageUrl || '../assets/images/用户4.jpg', // 根据实际需求设置默认图片或允许上传图片
+          authorAvatar: authorAvatar // 添加作者头像
+        };
+        this.posts.unshift(newPost); // 将新帖子添加到最前面
+        // 保存更新后的帖子列表到本地存储
+        localStorage.setItem('posts', JSON.stringify(this.posts));
+      }
+    } catch (error) {
+      console.error('Error presenting modal or handling dismissal:', error);
+    }
+  }
+}

+ 17 - 0
src/app/health-news/health-news-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { HealthNewsPage } from './health-news.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: HealthNewsPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class HealthNewsPageRoutingModule {}

+ 23 - 0
src/app/health-news/health-news.module.ts

@@ -0,0 +1,23 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { HealthNewsPageRoutingModule } from './health-news-routing.module';
+
+import { HealthNewsPage } from './health-news.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    HealthNewsPageRoutingModule,
+
+  ],
+  declarations: [
+    HealthNewsPage,
+  ],
+})
+export class HealthNewsPageModule {}

+ 22 - 0
src/app/health-news/health-news.page.html

@@ -0,0 +1,22 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab3"></ion-back-button>
+    </ion-buttons>
+    <ion-title>健康资讯</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content padding>
+  <ion-list lines="none">
+    <ion-item-sliding *ngFor="let news of newsList" (click)="openNewsDetail(news)">
+      <ion-item button detail>
+        <ion-icon [name]="news.icon" slot="start" color="primary"></ion-icon>
+        <ion-label>
+          <h2>{{ news.title }}</h2>
+          <p>{{ getPlainTextContent(news.content) | slice:0:50 }}...</p>
+        </ion-label>
+      </ion-item>
+    </ion-item-sliding>
+  </ion-list>
+</ion-content>

+ 92 - 0
src/app/health-news/health-news.page.scss

@@ -0,0 +1,92 @@
+ion-list {
+    margin-top: 20px;
+  }
+  
+  ion-item {
+    --background: #f9f9f9;
+    --border-color: #ddd;
+    --padding-start: 16px;
+    --inner-padding-end: 16px;
+    --min-height: 80px;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 16px;
+  }
+  
+  ion-item ion-label h2 {
+    font-weight: bold;
+    margin-bottom: 4px;
+    font-size: 1.2em;
+    color: #333;
+  }
+  
+  ion-item ion-label p {
+    font-size: 0.9em;
+    color: #666;
+  }
+  
+  ion-icon {
+    font-size: 24px;
+    margin-right: 16px;
+    color: #007aff;
+  }
+  
+  ion-card-content div {
+    white-space: pre-wrap; /* 确保换行符生效 */
+    line-height: 1.6; /* 设置行高 */
+  }
+  
+  ion-card-content ul {
+    list-style-type: disc; /* 默认项目符号 */
+    padding-left: 20px; /* 缩进列表项 */
+  }
+  
+  ion-card-content li {
+    margin-bottom: 8px; /* 列表项之间的间距 */
+  }
+  
+  ion-card-content p {
+    margin-bottom: 16px; /* 段落之间的间距 */
+  }
+  
+  ion-card-content strong {
+    font-weight: bold; /* 加粗文本 */
+    color: #007aff;
+  }
+  
+  ion-card-content h3 {
+    font-weight: bold;
+    margin-bottom: 8px;
+    font-size: 1.1em;
+    color: #333;
+  }
+  
+  ion-card-content article {
+    margin-bottom: 16px;
+  }
+  
+  ion-card-content section {
+    margin-bottom: 20px;
+  }
+  
+  ion-card {
+    margin-bottom: 16px;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+  
+  ion-card-header {
+    background-color: #f9f9f9;
+    padding: 16px;
+    border-bottom: 1px solid #ddd;
+  }
+  
+  ion-card-header ion-card-subtitle {
+    font-size: 1.2em;
+    font-weight: bold;
+    color: #333;
+  }
+  
+  ion-card-content {
+    padding: 16px;
+  }

+ 17 - 0
src/app/health-news/health-news.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { HealthNewsPage } from './health-news.page';
+
+describe('HealthNewsPage', () => {
+  let component: HealthNewsPage;
+  let fixture: ComponentFixture<HealthNewsPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(HealthNewsPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 121 - 0
src/app/health-news/health-news.page.ts

@@ -0,0 +1,121 @@
+import { Component } from '@angular/core';
+import { ModalController } from '@ionic/angular';
+import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
+import { NewsDetailPage } from '../news-detail/news-detail.page';
+
+@Component({
+  selector: 'app-health-news',
+  templateUrl: './health-news.page.html',
+  styleUrls: ['./health-news.page.scss'],
+})
+export class HealthNewsPage {
+
+  newsList = [
+    {
+      title: "如何保持良好的睡眠习惯",
+      content: `
+        <section>
+          <p>保持良好的睡眠习惯对于身体健康至关重要。以下是一些有助于改善睡眠质量的小贴士:</p>
+          
+          <ul>
+            <li><strong>建立规律的睡眠时间</strong>:尽量每天在相同的时间上床睡觉和起床,即使在周末或假期也要保持这个习惯。这有助于调整你的生物钟,使你在晚上更容易入睡,并在早上更容易醒来。</li>
+            
+            <li><strong>创造一个舒适的睡眠环境</strong>:确保你的卧室安静、黑暗且温度适宜。使用遮光窗帘、耳塞或白噪音机来减少干扰。一个舒适的床垫和枕头也是良好睡眠的关键。</li>
+            
+            <li><strong>限制咖啡因和酒精的摄入</strong>:尤其是在睡前几小时内,避免摄入咖啡因(如咖啡、茶、可乐等)和酒精。这些物质会影响你的睡眠质量,使你难以入睡或导致夜间醒来。</li>
+            
+            <li><strong>晚餐不宜过饱</strong>:避免在睡前两小时内进食大餐或辛辣食物,这些食物可能会导致消化不良,影响你的睡眠。如果感到饥饿,可以选择一些轻食,如水果或一小份酸奶。</li>
+            
+            <li><strong>放松身心</strong>:在睡前进行一些放松活动,如阅读、冥想、深呼吸或热水浴,有助于降低你的压力和焦虑水平,使你更容易入睡。</li>
+            
+            <li><strong>减少电子设备的使用</strong>:在睡前一小时停止使用电子设备,如手机、电脑和电视。这些设备发出的蓝光会抑制褪黑素的产生,而褪黑素是一种促进睡眠的激素。</li>
+            
+            <li><strong>保持适度的锻炼</strong>:定期的身体活动可以提高你的睡眠质量,但应避免在睡前几小时内进行剧烈运动,以免过于兴奋而难以入睡。</li>
+            
+            <li><strong>管理你的压力和焦虑</strong>:学会有效地管理压力和焦虑,可以通过写日记、与朋友交流或寻求专业帮助来实现。这些活动有助于减轻你的心理负担,从而改善你的睡眠质量。</li>
+          </ul>
+          
+          <p>遵循这些小贴士,你可以逐步改善你的睡眠质量,享受更加健康、充满活力的生活。记住,良好的睡眠习惯需要时间和坚持来培养,所以请对自己有耐心。</p>
+        </section>
+      `,
+      icon: "moon"
+    },
+    {
+      title: "均衡饮食的重要性",
+      content: `
+        <section>
+          <p>均衡饮食是维持健康不可或缺的关键。在日常生活中,了解哪些食物富含我们身体所需的各类营养素,并合理地将它们纳入我们的饮食计划中,是确保身体健康、预防疾病的重要步骤。</p>
+          
+          <p>均衡饮食意味着从五大类食物中获取全面的营养:谷物、蔬菜、水果、蛋白质来源(如肉类、豆类、奶制品)以及适量的健康脂肪(如坚果、鱼类中的Omega-3脂肪酸)。每种食物类别都提供了不同的营养素,如碳水化合物、维生素、矿物质、膳食纤维和蛋白质,这些营养素对于维持身体的正常运作至关重要。</p>
+          
+          <p>谷物是我们主要的能量来源,提供了丰富的碳水化合物和B族维生素。蔬菜和水果富含维生素、矿物质和膳食纤维,有助于增强免疫力、促进消化和降低慢性病风险。蛋白质是构建和修复身体组织的基础,对于肌肉、骨骼、皮肤和内脏器官的健康都至关重要。而健康脂肪则对维持心脏健康、促进脑部发育和维持正常生理功能有着不可替代的作用。</p>
+          
+          <p>通过合理搭配这些食物,我们可以确保身体获得所需的所有营养素,从而保持健康状态。此外,均衡饮食还有助于控制体重、提高精力和心情,使我们能够更好地应对日常生活的挑战。</p>
+          
+          <p>因此,为了自己和家人的健康,请务必重视均衡饮食的重要性,将健康饮食的理念融入日常生活的每一个细节中。</p>
+        </section>
+      `,
+      icon: "restaurant"
+    },
+    {
+      title: "定期运动的好处",
+      content: `
+        <section>
+          <article>
+            <h3>控制体重和预防疾病</h3>
+            <p>定期进行体育活动不仅能够有效地帮助控制体重,防止肥胖及相关疾病的发生,还能显著提升心肺功能,增强身体的耐力和持久力。此外,运动在增强免疫力、提升整体健康水平方面扮演着至关重要的角色。</p>
+          </article>
+          
+          <article>
+            <h3>燃烧卡路里和塑造身材</h3>
+            <p>首先,通过定期运动,身体能够更有效地燃烧卡路里,促进脂肪的代谢,从而帮助维持健康的体重。这对于预防心血管疾病、糖尿病、高血压等慢性病具有积极作用。同时,运动还能塑造身材,提升个人形象与自信心。</p>
+          </article>
+          
+          <article>
+            <h3>增强心肺功能</h3>
+            <p>其次,运动能够显著提高心肺功能。在运动时,心脏跳动加快,肺部呼吸加深,这有助于增强心肌力量,提高血液循环效率,以及提升肺部的氧气交换能力。长期坚持运动的人,其心肺功能往往更为强健,能够更轻松地应对日常活动和突发状况。</p>
+          </article>
+          
+          <article>
+            <h3>提升免疫力</h3>
+            <p>再者,运动还能有效增强免疫力。通过促进血液循环,运动能够帮助身体更有效地输送营养物质和氧气到各个器官,同时加速毒素和废物的排出。这有助于提升身体的自我修复和抗病能力,减少感冒、流感等常见疾病的发生。</p>
+          </article>
+          
+          <article>
+            <h3>心理上的益处</h3>
+            <p>最后,定期运动还能带来心理上的益处。运动能够释放压力,改善情绪,提升幸福感和满足感。无论是通过跑步、游泳、瑜伽还是其他运动方式,人们都能在运动中找到释放压力、放松身心的途径。</p>
+          </article>
+          
+          <article>
+            <h3>总结</h3>
+            <p>综上所述,定期运动的好处是多方面的,它不仅能够提升身体健康水平,还能带来心理上的愉悦和满足。因此,我们应该将运动纳入日常生活的一部分,享受运动带来的健康和快乐。</p>
+          </article>
+        </section>
+      `,
+      icon: "walk"
+    }
+  ];
+
+  constructor(private modalController: ModalController, private sanitizer: DomSanitizer) {}
+
+  async openNewsDetail(news: any) {
+    const modal = await this.modalController.create({
+      component: NewsDetailPage,
+      componentProps: {
+        news: news
+      }
+    });
+    return await modal.present();
+  }
+
+  sanitizeContent(content: string): SafeHtml {
+    return this.sanitizer.bypassSecurityTrustHtml(content);
+  }
+
+  // 提取纯文本内容
+  getPlainTextContent(content: string): string {
+    const tempDiv = document.createElement('div');
+    tempDiv.innerHTML = content;
+    return tempDiv.textContent || '';
+  }
+}

+ 6 - 1
src/app/health-record/health-record.page.html

@@ -8,6 +8,11 @@
 </ion-header>
 
 <ion-content padding>
+
+  <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
+    <ion-refresher-content pullingIcon="chevron-down-circle" pullingText="下拉刷新" refreshingSpinner="circles" refreshingText="正在刷新..."></ion-refresher-content>
+  </ion-refresher>
+  
   <!-- 基本信息 -->
   <ion-card>
     <ion-card-header>
@@ -39,5 +44,5 @@
     </ion-list>
   </ion-card>
 
-  <ion-button expand="block" (click)="addNewReport()">添加新体检报告</ion-button>
+  <!-- <ion-button expand="block" (click)="addNewReport()">添加新体检报告</ion-button> -->
 </ion-content>

+ 92 - 20
src/app/health-record/health-record.page.ts

@@ -1,9 +1,12 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, OnDestroy } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 import { NavController } from '@ionic/angular';
+import { Subscription } from 'rxjs';
+import { UserService, UserInfo } from '../services/user.service';
 
 // 定义接口
-interface HealthReport {
+export interface HealthReport {
+  id?: string; // 唯一标识符
   title: string;
   date: Date;
   details: string;
@@ -15,38 +18,107 @@ interface HealthReport {
   templateUrl: './health-record.page.html',
   styleUrls: ['./health-record.page.scss'],
 })
-export class HealthRecordPage implements OnInit {
+export class HealthRecordPage implements OnInit, OnDestroy {
   healthRecord = {
     name: '',
     gender: '',
     age: null as number | null,
     contact: '',
     medicalHistory: '',
-    reports: [] as HealthReport[] // 使用 HealthReport 接口定义 reports 数组的类型
+    reports: [] as HealthReport[]
   };
 
-  constructor(private route: ActivatedRoute, private router: Router, private navCtrl: NavController) {}
+  private userSubscription: Subscription | null = null;
+
+  constructor(
+    private route: ActivatedRoute,
+    private router: Router,
+    private navCtrl: NavController,
+    private userService: UserService
+  ) {}
 
   ngOnInit() {
-    // 初始化健康档案数据
+    this.userSubscription = this.userService.userInfo$.subscribe(userInfo => {
+      if (userInfo) {
+        this.updateHealthRecordFromUserInfo(userInfo);
+      }
+    });
     this.loadHealthRecord();
   }
 
+  ngOnDestroy() {
+    if (this.userSubscription) {
+      this.userSubscription.unsubscribe();
+    }
+  }
+
   loadHealthRecord() {
-    // 这里可以加载用户健康档案数据
-    // 例如从服务中获取或从本地存储读取
-    // 示例数据
-    this.healthRecord = {
-      name: '张三',
-      gender: 'male',
-      age: 30,
-      contact: '12345678901',
-      medicalHistory: '高血压',
-      reports: [
-        { title: '年度体检', date: new Date(), details: '血压正常,血糖略高', type: 'annual' },
-        { title: '眼科检查', date: new Date('2024-01-01'), details: '视力良好,无异常', type: 'eye' }
-      ] as HealthReport[] // 显式指定类型
-    };
+    console.log('Loading health record...');
+    
+    const userInfo = this.userService.userInfoSubject.value;
+    console.log('Current user info:', userInfo); // 新增日志
+    
+    if (userInfo) {
+      this.updateHealthRecordFromUserInfo(userInfo);
+      console.log('Updated health record from user info:', this.healthRecord);
+    } else {
+      // 如果没有用户信息,则加载默认数据或等待用户信息加载
+      if (!this.healthRecord.reports || this.healthRecord.reports.length === 0) {
+        this.healthRecord = {
+          name: '张三',
+          gender: 'male',
+          age: 30,
+          contact: '12345678901',
+          medicalHistory: '高血压',
+          reports: [
+            { title: '年度体检', date: new Date(), details: '血压正常,血糖略高', type: 'annual' },
+            { title: '眼科检查', date: new Date('2024-01-01'), details: '视力良好,无异常', type: 'eye' }
+          ]
+        };
+        console.log('Loaded default health record:', this.healthRecord);
+      }
+    }
+  }
+
+  updateHealthRecordFromUserInfo(userInfo: UserInfo) {
+    this.healthRecord.name = userInfo.username || this.healthRecord.name || '';
+    this.healthRecord.gender = userInfo.gender || this.healthRecord.gender || '';
+    this.healthRecord.contact = userInfo.phone || this.healthRecord.contact || '';
+  
+    // 计算年龄(假设 birthday 是 ISO 8601 格式的字符串)
+    if (userInfo.birthday) {
+      const birthDate = new Date(userInfo.birthday);
+      const today = new Date();
+      let age = today.getFullYear() - birthDate.getFullYear();
+      const m = today.getMonth() - birthDate.getMonth();
+      if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
+        age--;
+      }
+      this.healthRecord.age = age;
+    } else {
+      this.healthRecord.age = this.healthRecord.age || null;
+    }
+  
+    // 更新其他相关字段...
+    this.healthRecord.medicalHistory = userInfo.medicalHistory || this.healthRecord.medicalHistory || '';
+  
+    // 如果 userInfo 包含 reports,则合并新旧报告,但避免重复
+    if (userInfo.reports && Array.isArray(userInfo.reports)) {
+      this.healthRecord.reports = [
+        ...this.healthRecord.reports,
+        ...userInfo.reports.filter(newReport => 
+          !this.healthRecord.reports.some(oldReport => oldReport.title === newReport.title)
+        )
+      ];
+    }
+  }
+
+  doRefresh(event: any) {
+    console.log('Begin async operation');
+    setTimeout(() => {
+      console.log('Async operations have ended');
+      event.target.complete();
+    }, 1000);
   }
 
   editBasicInfo() {

+ 82 - 10
src/app/invite-friends/invite-friends.page.html

@@ -1,13 +1,85 @@
-<ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title>invite-friends</ion-title>
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab3"></ion-back-button>
+    </ion-buttons>
+    <ion-title>邀请好友</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">invite-friends</ion-title>
-    </ion-toolbar>
-  </ion-header>
-</ion-content>
+<ion-content class="invite-content">
+  <!-- 欢迎信息 -->
+  <div class="welcome-message">
+    <h2>邀请您的好友加入我们,一起享受更多功能!</h2>
+    <p>每成功邀请一位好友注册,您将获得额外奖励积分。</p>
+  </div>
+  
+  <!-- 描述性文本 -->
+  <div class="invite-description">
+    <p>只需分享以下链接给您的好友,当他们通过此链接注册后,您就能立即获得奖励积分。</p>
+  </div>
+
+  <!-- 邀请按钮 -->
+  <ion-item button (click)="inviteFriends()" lines="none" class="invite-button">
+    <ion-icon name="people" slot="start" class="invite-icon"></ion-icon>
+    <ion-label>邀请好友</ion-label>
+  </ion-item>
+
+  <!-- 社交分享按钮 -->
+  <div class="social-sharing">
+    <ion-button expand="block" (click)="shareOnSocialMedia('facebook')">
+      <ion-icon name="logo-facebook" slot="start"></ion-icon>
+      分享到Facebook
+    </ion-button>
+    <ion-button expand="block" (click)="shareOnSocialMedia('twitter')">
+      <ion-icon name="logo-twitter" slot="start"></ion-icon>
+      分享到Twitter
+    </ion-button>
+    <ion-button expand="block" (click)="shareOnSocialMedia('wechat')">
+      <ion-icon name="logo-wechat" slot="start"></ion-icon>
+      分享到微信
+    </ion-button>
+  </div>
+
+  <!-- 如果需要显示邀请链接 -->
+  <div class="invite-link-section" *ngIf="showInviteLink">
+    <ion-item>
+      <ion-label position="floating">邀请链接</ion-label>
+      <ion-input [(ngModel)]="inviteLink" readonly></ion-input>
+      <ion-button fill="outline" (click)="copyToClipboard()">复制链接</ion-button>
+    </ion-item>
+  </div>
+
+<!-- 成就或进度展示 -->
+<div class="achievement-section" *ngIf="userAchievements.length > 0">
+  <h3>我的成就</h3>
+  <div class="achievements-container">
+    <div *ngFor="let achievement of userAchievements" class="achievement-item">
+      <ion-icon name="trophy-outline" class="achievement-icon"></ion-icon>
+      <span>{{ achievement }}</span>
+      <ion-button fill="clear" (click)="viewAchievementDetail(achievement)">
+        <ion-icon slot="icon-only" name="eye-outline"></ion-icon>
+      </ion-button>
+    </div>
+  </div>
+</div>
+
+<!-- 推荐理由 -->
+<div class="recommendation-section">
+  <h3>为什么加入我们?</h3>
+  <ul>
+    <li>
+      <ion-icon name="checkmark-circle-outline" class="reason-icon"></ion-icon>
+      超棒的功能和体验
+    </li>
+    <li>
+      <ion-icon name="people-outline" class="reason-icon"></ion-icon>
+      友好的社区氛围
+    </li>
+    <li>
+      <ion-icon name="refresh-outline" class="reason-icon"></ion-icon>
+      持续更新的内容
+    </li>
+  </ul>
+</div>
+</ion-content>

+ 224 - 0
src/app/invite-friends/invite-friends.page.scss

@@ -0,0 +1,224 @@
+/* 定义全局变量 */
+:root {
+    --ion-color-primary: #488aff;
+    --ion-color-light: #ffffff;
+    --ion-color-primary-darkened: #3b79e6; /* 手动计算的颜色值 */
+}
+
+/* 设置页面整体背景 */
+.invite-content {
+    background: linear-gradient(135deg, #f7f7f7, #eaf5ff);
+    padding: 20px;
+}
+
+/* 欢迎信息 */
+.welcome-message {
+    text-align: center;
+    margin-bottom: 24px;
+    font-size: 1.5rem;
+    color: var(--ion-color-primary);
+    font-weight: bold;
+    padding: 16px;
+    border-radius: 8px;
+    background: rgba(72, 138, 255, 0.1);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
+}
+
+/* 描述性文本 */
+.invite-description {
+    text-align: center;
+    margin-bottom: 24px;
+    font-size: 1.2rem;
+    color: #666;
+    line-height: 1.6;
+}
+
+/* 邀请按钮 */
+.invite-button {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    width: 100%;
+    max-width: 400px;
+    margin: 0 auto;
+    padding: 16px;
+    border-radius: 24px;
+    background: linear-gradient(135deg, var(--ion-color-primary), var(--ion-color-primary-darkened));
+    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
+    transition: transform 0.3s ease, box-shadow 0.3s ease;
+
+    &:hover,
+    &:focus {
+        box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
+        transform: translateY(-2px);
+    }
+
+    &:active {
+        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+        transform: translateY(2px);
+    }
+}
+
+/* 图标样式 */
+.invite-icon {
+    color: var(--ion-color-light);
+    font-size: 1.5rem;
+    margin-right: 10px;
+    transition: transform 0.3s ease;
+
+    .invite-button:hover &,
+    .invite-button:focus & {
+        transform: scale(1.2);
+    }
+}
+
+/* 社交分享按钮 */
+.social-sharing {
+    margin-top: 24px;
+    text-align: center;
+
+    ion-button {
+        margin: 8px 0;
+        width: 80%;
+        max-width: 400px;
+        margin-left: auto;
+        margin-right: auto;
+    }
+}
+
+/* 邀请链接部分 */
+.invite-link-section {
+    margin-top: 24px;
+    text-align: center;
+
+    ion-item {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        padding: 16px;
+        border-radius: 8px;
+        background: #fff;
+        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+
+        ion-button {
+            margin-left: 8px;
+        }
+    }
+}
+
+/* 成就或进度展示 */
+.achievement-section {
+    margin-top: 24px;
+    padding: 16px;
+    background-color: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+    text-align: center;
+  
+    h3 {
+      font-size: 1.2rem;
+      color: var(--ion-color-primary);
+      margin-bottom: 16px;
+    }
+  
+    .achievements-container {
+      display: flex;
+      flex-wrap: wrap;
+      justify-content: center;
+      gap: 16px; /* 使用gap属性为成就项之间提供间距 */
+    }
+  
+    .achievement-item {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      width: calc(33.333% - 32px); /* 适应三列布局,并考虑间隙 */
+      padding: 12px;
+      background-color: #f9f9f9;
+      border-radius: 8px;
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+      transition: transform 0.3s ease, box-shadow 0.3s ease;
+  
+      &:hover {
+        transform: translateY(-4px);
+        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+      }
+  
+      .achievement-icon {
+        font-size: 1.5rem;
+        color: var(--ion-color-primary);
+        margin-right: 8px;
+        transition: transform 0.3s ease;
+  
+        & + span {
+          flex-grow: 1;
+        }
+  
+        .achievement-item:hover & {
+          transform: scale(1.2);
+        }
+      }
+  
+      ion-button {
+        --background-focused: transparent;
+        --color: var(--ion-color-primary);
+        --border-radius: 50%;
+        padding: 0;
+        margin-left: 8px;
+      }
+    }
+  }
+
+/* 推荐理由 */
+.recommendation-section {
+    margin-top: 24px;
+    padding: 16px;
+    background-color: #fff;
+    border-radius: 8px;
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+    text-align: center;
+  
+    h3 {
+      font-size: 1.2rem;
+      color: var(--ion-color-primary);
+      margin-bottom: 16px;
+    }
+  
+    ul {
+      list-style-type: none;
+      padding: 0;
+      display: flex;
+      flex-direction: column;
+      gap: 12px; /* 使用gap属性为列表项之间提供间距 */
+    }
+  
+    li {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 1rem;
+      color: #333;
+      padding: 8px;
+      transition: transform 0.3s ease, box-shadow 0.3s ease;
+  
+      &:hover {
+        transform: scale(1.05);
+        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+      }
+    }
+  
+    .reason-icon {
+      font-size: 1.5rem;
+      margin-right: 8px;
+      color: var(--ion-color-primary);
+      transition: transform 0.3s ease;
+  
+      & + span {
+        flex-grow: 1;
+      }
+  
+      li:hover & {
+        transform: scale(1.2);
+      }
+    }
+  }

+ 99 - 1
src/app/invite-friends/invite-friends.page.ts

@@ -1,4 +1,5 @@
 import { Component, OnInit } from '@angular/core';
+import { ToastController, LoadingController, AlertController } from '@ionic/angular';
 
 @Component({
   selector: 'app-invite-friends',
@@ -6,10 +7,107 @@ import { Component, OnInit } from '@angular/core';
   styleUrls: ['./invite-friends.page.scss'],
 })
 export class InviteFriendsPage implements OnInit {
+  inviteLink = ''; // 从后端或其他来源动态获取
+  showInviteLink = false;
+  userAchievements: string[] = ['已邀请1位好友']; // 初始化成就列表
 
-  constructor() { }
+  constructor(
+    public toastController: ToastController,
+    public loadingController: LoadingController,
+    public alertController: AlertController // 添加 AlertController
+  ) {}
 
   ngOnInit() {
+    // 假设这里是获取邀请链接的地方
+    this.fetchInviteLink();
   }
 
+  private async fetchInviteLink() {
+    try {
+      // 这里应该是调用API来获取真实的邀请链接
+      this.inviteLink = await this.getInviteLinkFromApi(); // 替换为实际的API调用
+    } catch (error) {
+      console.error('获取邀请链接失败', error);
+      this.showErrorAlert('获取邀请链接失败,请重试');
+    }
+  }
+
+  private async getInviteLinkFromApi(): Promise<string> {
+    // 模拟API请求
+    return new Promise((resolve) => setTimeout(() => resolve('https://example.com/invite'), 1000));
+  }
+
+  async inviteFriends() {
+    const loading = await this.loadingController.create({
+      message: '正在生成邀请链接...',
+    });
+    await loading.present();
+
+    try {
+      // 如果有需要,可以在这里调用API以生成新的邀请链接
+      this.showInviteLink = true;
+    } catch (error) {
+      console.error('生成邀请链接失败', error);
+      this.showErrorAlert('生成邀请链接失败,请重试');
+    } finally {
+      loading.dismiss();
+    }
+  }
+
+  async copyToClipboard() {
+    try {
+      // 使用原生JavaScript方法复制文本到剪贴板
+      await navigator.clipboard.writeText(this.inviteLink);
+      this.showToast('邀请链接已复制到剪贴板!');
+    } catch (err) {
+      console.error('复制失败', err);
+      this.showErrorAlert('复制失败,请重试');
+    }
+  }
+
+  private async showToast(message: string) {
+    const toast = await this.toastController.create({
+      message,
+      duration: 2000,
+    });
+    await toast.present();
+  }
+
+  private async showErrorAlert(message: string) {
+    const alert = await this.alertController.create({
+      header: '操作失败',
+      message,
+      buttons: ['确定']
+    });
+    await alert.present();
+  }
+
+  // 添加查看成就详情的方法
+async viewAchievementDetail(achievement: string) {
+  const alert = await this.alertController.create({
+    header: '成就详情',
+    message: `您已经完成了:${achievement}`,
+    buttons: ['关闭']
+  });
+
+  await alert.present();
 }
+
+  async shareOnSocialMedia(platform?: string) {
+    if (navigator.share) {
+      try {
+        await navigator.share({
+          title: '我正在使用这个超棒的应用,快来加入吧!',
+          text: '我正在使用这个超棒的应用,快来加入吧!',
+          url: this.inviteLink,
+        });
+        this.showToast(`已分享`);
+      } catch (err) {
+        console.error('分享失败', err);
+        this.showErrorAlert('分享失败,请重试');
+      }
+    } else {
+      this.showErrorAlert('当前浏览器不支持分享功能,请手动复制链接分享。');
+    }
+  }
+}

+ 41 - 10
src/app/manage-family/manage-family.page.html

@@ -1,13 +1,44 @@
-<ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title>manage-family</ion-title>
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab3"></ion-back-button>
+    </ion-buttons>
+    <ion-title>家人管理</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">manage-family</ion-title>
-    </ion-toolbar>
-  </ion-header>
-</ion-content>
+<ion-content>
+  <!-- 错误信息 -->
+  <div *ngIf="error" class="error-message">
+    <p>{{ error }}</p>
+  </div>
+
+  <!-- 加载指示器 -->
+  <ion-spinner name="bubbles" *ngIf="isLoading"></ion-spinner>
+
+  <!-- 家庭成员列表 -->
+  <ion-list *ngIf="!isLoading && familyMembers.length > 0">
+    <ion-item *ngFor="let member of familyMembers" button (click)="editMember(member)">
+      <ion-avatar slot="start">
+        <img [src]="member.avatar || '../assets/images/用户4.jpg'" alt="Avatar" />
+      </ion-avatar>
+      <ion-label>
+        <h2>{{ member.name }}</h2>
+        <p>{{ member.relationship }}</p>
+      </ion-label>
+      <ion-icon name="ellipsis-vertical" slot="end" (click)="removeFamilyMember(member.id)"></ion-icon>
+    </ion-item>
+  </ion-list>
+
+  <!-- 提示信息 -->
+  <div *ngIf="!isLoading && familyMembers.length === 0" class="page-intro">
+    <p>您还没有添加任何家庭成员。点击右下角的加号按钮来添加新成员。</p>
+  </div>
+
+  <!-- 添加家庭成员的浮动按钮 -->
+  <ion-fab vertical="bottom" horizontal="end" slot="fixed">
+    <ion-fab-button (click)="addFamilyMember()">
+      <ion-icon name="add"></ion-icon>
+    </ion-fab-button>
+  </ion-fab>
+</ion-content>

+ 85 - 0
src/app/manage-family/manage-family.page.scss

@@ -0,0 +1,85 @@
+/* 页面顶部提示信息 */
+.page-intro {
+    padding: 16px;
+    text-align: center;
+    color: #777;
+  }
+
+  /* 错误信息 */
+.error-message {
+    padding: 16px;
+    text-align: center;
+    color: red;
+  }
+  
+  /* 加载指示器 */
+  ion-spinner {
+    display: block;
+    margin: 50px auto;
+  }
+  
+  /* 家庭成员列表 */
+  ion-list {
+    margin-top: 8px;
+  
+    ion-item {
+      --border-color: #ddd;
+  
+      ion-avatar img {
+        border-radius: 50%;
+        width: 40px;
+        height: 40px;
+      }
+  
+      h2 {
+        font-size: 1rem;
+        margin-bottom: 4px;
+      }
+  
+      p {
+        font-size: 0.9rem;
+        color: #777;
+      }
+    }
+  }
+  
+  /* 添加家庭成员的浮动按钮 */
+  ion-fab-button {
+    --background: var(--ion-color-primary);
+    --color: white;
+  }
+  
+  /* 成员详情模态框 */
+  ion-modal {
+    --height: auto;
+    --width: 90%;
+  
+    ion-header {
+      background-color: var(--ion-color-primary);
+      color: white;
+    }
+  
+    ion-content {
+      padding: 16px;
+    }
+  }
+  
+  /* 操作菜单 */
+  ion-popover {
+    --width: 150px;
+  
+    ion-list {
+      background-color: white;
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  
+      ion-item {
+        --background-hover: #f9f9f9;
+        padding: 12px 16px;
+        cursor: pointer;
+  
+        &:hover {
+          background-color: #f9f9f9;
+        }
+      }
+    }
+  }

+ 156 - 3
src/app/manage-family/manage-family.page.ts

@@ -1,15 +1,168 @@
 import { Component, OnInit } from '@angular/core';
-
+import { NavController, AlertController, ToastController } from '@ionic/angular';
+import { FamilyService } from '../services/family.service'; // 确认路径是否正确
+import { FamilyMember} from '../services/family.service';
 @Component({
   selector: 'app-manage-family',
   templateUrl: './manage-family.page.html',
   styleUrls: ['./manage-family.page.scss'],
 })
 export class ManageFamilyPage implements OnInit {
+  familyMembers: any[] = [];
+  isLoading = true; // 加载指示器
+  error: string | null = null;
 
-  constructor() { }
+  constructor(
+    private navCtrl: NavController,
+    private familyService: FamilyService,
+    private alertController: AlertController,
+    private toastCtrl: ToastController
+  ) {}
 
   ngOnInit() {
+    this.loadFamilyMembers();
+  }
+
+  loadFamilyMembers() {
+    this.isLoading = true;
+    this.error = null;
+
+    this.familyService.getFamilyMembers().subscribe(
+      (members: any[]) => {
+        this.familyMembers = members;
+        this.isLoading = false;
+      },
+      (err) => {
+        this.error = '无法加载家庭成员数据,请稍后再试。';
+        this.showToast('无法加载家庭成员数据,请稍后再试。');
+        this.isLoading = false;
+      }
+    );
+  }
+
+  async addFamilyMember() {
+    const alert = await this.alertController.create({
+      header: '添加家庭成员',
+      inputs: [
+        {
+          name: 'name',
+          type: 'text',
+          placeholder: '姓名'
+        },
+        {
+          name: 'relationship',
+          type: 'text',
+          placeholder: '关系'
+        },
+        {
+          name: 'avatar',
+          type: 'text',
+          placeholder: '头像URL (可选)'
+        }
+      ],
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel'
+        },
+        {
+          text: '确认',
+          handler: (data) => {
+            if (data.name && data.relationship) {
+              this.familyService.addFamilyMember(data).subscribe(
+                (newMember) => {
+                  this.showToast('家庭成员已成功添加。');
+                  this.loadFamilyMembers();
+                },
+                (error) => {
+                  this.showToast('添加家庭成员时发生错误,请稍后再试。');
+                }
+              );
+            } else {
+              this.showToast('请填写必填字段。');
+            }
+            return false; // 防止默认行为
+          }
+        }
+      ]
+    });
+    await alert.present();
+  }
+  
+  async editMember(member: FamilyMember) {
+    const alert = await this.alertController.create({
+      header: '编辑家庭成员',
+      inputs: [
+        {
+          name: 'name',
+          type: 'text',
+          value: member.name,
+          placeholder: '姓名'
+        },
+        {
+          name: 'relationship',
+          type: 'text',
+          value: member.relationship,
+          placeholder: '关系'
+        },
+        {
+          name: 'avatar',
+          type: 'text',
+          value: member.avatar || '',
+          placeholder: '头像URL (可选)'
+        }
+      ],
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel'
+        },
+        {
+          text: '确认',
+          handler: (data) => {
+            // Ensure that required fields are not undefined before updating
+            if (data.name !== undefined && data.relationship !== undefined) {
+              this.familyService.updateFamilyMember(member.id, data).subscribe(
+                () => {
+                  this.showToast('家庭成员信息已更新。');
+                  this.loadFamilyMembers();
+                },
+                (error) => {
+                  this.showToast('更新家庭成员时发生错误,请稍后再试。');
+                }
+              );
+            } else {
+              this.showToast('请填写必填字段。');
+            }
+            return false; // 防止默认行为
+          }
+        }
+      ]
+    });
+    await alert.present();
+  }
+
+  async removeFamilyMember(memberId: string) {
+    try {
+      await this.familyService.removeFamilyMember(memberId).toPromise();
+      this.showToast('家庭成员已成功移除。');
+      this.loadFamilyMembers(); // 刷新列表
+    } catch (error) {
+      this.showToast('移除家庭成员时发生错误,请稍后再试。');
+    }
   }
 
-}
+  backToPreviousPage() {
+    this.navCtrl.back();
+  }
+
+  // Toast提示方法
+  async showToast(message: string) {
+    const toast = await this.toastCtrl.create({
+      message,
+      duration: 3000,
+      position: 'bottom'
+    });
+    toast.present();
+  }
+}

+ 17 - 0
src/app/medical-services/medical-services-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { MedicalServicesPage } from './medical-services.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: MedicalServicesPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class MedicalServicesPageRoutingModule {}

+ 20 - 0
src/app/medical-services/medical-services.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { MedicalServicesPageRoutingModule } from './medical-services-routing.module';
+
+import { MedicalServicesPage } from './medical-services.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    MedicalServicesPageRoutingModule
+  ],
+  declarations: [MedicalServicesPage]
+})
+export class MedicalServicesPageModule {}

+ 47 - 0
src/app/medical-services/medical-services.page.html

@@ -0,0 +1,47 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab3" text="" icon="arrow-back"></ion-back-button>
+    </ion-buttons>
+    <ion-title>医疗服务</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="medical-services-page">
+  <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
+    <ion-refresher-content pullingIcon="chevron-down-circle" pullingText="下拉刷新" refreshingSpinner="circles" refreshingText="正在刷新..."></ion-refresher-content>
+  </ion-refresher>
+
+  <!-- 医疗服务列表 -->
+  <section class="services-section">
+    <!-- <h3>我们的服务</h3> -->
+    <ion-list>
+      <ion-item button *ngFor="let service of medicalServices" (click)="viewServiceDetails(service)" class="service-item">
+        <ion-icon [name]="service.icon" slot="start" class="service-icon"></ion-icon>
+        <ion-label>
+          <h2>{{ service.title }}</h2>
+          <p>{{ service.description }}</p>
+        </ion-label>
+      </ion-item>
+    </ion-list>
+  </section>
+
+  <!-- 未处理预约提醒 -->
+  <section class="appointment-section" *ngIf="hasPendingAppointments">
+    <ion-card>
+      <ion-card-header>
+        <ion-card-subtitle class="status-bar" [ngClass]="{'pending': hasPendingAppointments}">提醒</ion-card-subtitle>
+        <ion-card-title>您有 {{ pendingAppointmentsCount }} 条未处理的预约</ion-card-title>
+      </ion-card-header>
+      <ion-card-content>
+        请尽快处理您的预约。
+        <ion-button expand="block" (click)="manageAppointments()">管理预约</ion-button>
+      </ion-card-content>
+    </ion-card>
+  </section>
+
+  <!-- 在线咨询医生 -->
+  <section class="consultation-section">
+    <ion-button expand="full" (click)="consultDoctor()" color="primary">在线咨询医生</ion-button>
+  </section>
+</ion-content>

+ 89 - 0
src/app/medical-services/medical-services.page.scss

@@ -0,0 +1,89 @@
+.medical-services-page {
+    .ion-page {
+      background: linear-gradient(180deg, #f4f5f8 0%, #eef1f5 100%); /* 背景渐变 */
+    }
+  
+    ion-content {
+      --background: #fff;
+      padding: 16px;
+    }
+  
+    .services-section,
+    .appointment-section,
+    .consultation-section {
+      margin-bottom: 24px;
+    }
+  
+    h3 {
+      font-size: 1.2rem;
+      margin-bottom: 12px;
+      color: #333;
+    }
+  
+    .service-item {
+      --border-width: 0;
+      --padding-start: 16px;
+      --padding-end: 16px;
+  
+      &:not(:last-child) {
+        border-bottom: 1px solid #eaeaea;
+      }
+    }
+  
+    .service-icon {
+      font-size: 1.2rem;
+      color: #007aff;
+    }
+  
+    h2 {
+      font-size: 1.1rem;
+      font-weight: 500;
+    }
+  
+    p {
+      color: #666;
+      margin-top: 4px;
+    }
+  
+    ion-card {
+      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+      border-radius: 12px;
+      overflow: hidden;
+  
+      .status-bar {
+        display: block;
+        width: 100%;
+        padding: 4px 0;
+        text-align: center;
+        color: white;
+        &.pending {
+          background-color: #ff9900; /* 待处理预约的颜色 */
+        }
+      }
+  
+      ion-card-header {
+        background-color: #ffefef;
+        border-bottom: 1px solid #ffcccc;
+      }
+  
+      ion-card-content {
+        padding: 16px;
+      }
+    }
+  
+    ion-button {
+      margin-top: 16px;
+      width: 100%;
+      border-radius: 8px;
+      transition: transform 0.2s ease-in-out;
+  
+      &:active {
+        transform: scale(0.95); /* 按钮按下时缩小 */
+      }
+    }
+  
+    /* 返回按钮的样式 */
+    ion-back-button {
+      --color: #007aff;
+    }
+  }

+ 17 - 0
src/app/medical-services/medical-services.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MedicalServicesPage } from './medical-services.page';
+
+describe('MedicalServicesPage', () => {
+  let component: MedicalServicesPage;
+  let fixture: ComponentFixture<MedicalServicesPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MedicalServicesPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 44 - 0
src/app/medical-services/medical-services.page.ts

@@ -0,0 +1,44 @@
+import { Component } from '@angular/core';
+import { NavController } from '@ionic/angular';
+
+@Component({
+  selector: 'app-medical-services',
+  templateUrl: './medical-services.page.html',
+  styleUrls: ['./medical-services.page.scss'],
+})
+export class MedicalServicesPage {
+  medicalServices = [
+    { title: '预约挂号', description: '选择科室并预约挂号', icon: 'calendar' },
+    { title: '在线咨询', description: '在线与医生沟通', icon: 'chatbubbles' },
+    { title: '医疗建议', description: '获取专业医疗建议', icon: 'information-circle' },
+    // ... 添加更多服务项 ...
+  ];
+
+  hasPendingAppointments = true;
+  pendingAppointmentsCount = 3;
+
+  constructor(private navCtrl: NavController) {}
+
+  doRefresh(event: any) {
+    console.log('Begin async operation');
+    setTimeout(() => {
+      console.log('Async operations have ended');
+      event.target.complete();
+    }, 1000);
+  }
+
+  viewServiceDetails(service: any) {
+    console.log(`查看 ${service.title} 的详情`);
+    // 这里可以添加导航到特定服务详情页的逻辑
+  }
+
+  manageAppointments() {
+    console.log('管理预约');
+    // 导航到预约管理页面或弹出预约管理模态框
+  }
+
+  consultDoctor() {
+    console.log('在线咨询医生');
+    this.navCtrl.navigateForward('/consultation');
+  }
+}

+ 17 - 0
src/app/medicine-detail/medicine-detail-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { MedicineDetailPage } from './medicine-detail.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: MedicineDetailPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class MedicineDetailPageRoutingModule {}

+ 20 - 0
src/app/medicine-detail/medicine-detail.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { MedicineDetailPageRoutingModule } from './medicine-detail-routing.module';
+
+import { MedicineDetailPage } from './medicine-detail.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    MedicineDetailPageRoutingModule
+  ],
+  declarations: [MedicineDetailPage]
+})
+export class MedicineDetailPageModule {}

+ 37 - 0
src/app/medicine-detail/medicine-detail.page.html

@@ -0,0 +1,37 @@
+<!-- src/app/medicine-detail/medicine-detail.page.html -->
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/medicine-purchase"></ion-back-button>
+    </ion-buttons>
+    <ion-title>{{ medicine?.name || '加载中...' }}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <div *ngIf="loading" class="loading-container">
+    <p>正在加载...</p>
+  </div>
+  <div *ngIf="!loading && !error && medicine" class="medicine-details">
+    <img [src]="medicine.imageUrl" alt="{{ medicine.name }}" />
+    <h2>{{ medicine.name }}</h2>
+    <p>价格: ¥{{ medicine.price }}</p>
+    <p>{{ medicine.description }}</p>
+    <!-- 可选:添加更多详细信息 -->
+    <section>
+      <h3>用法用量</h3>
+      <p>{{ medicine.usage || '暂无相关信息' }}</p>
+    </section>
+    <section>
+      <h3>注意事项</h3>
+      <p>{{ medicine.precautions || '暂无相关信息' }}</p>
+    </section>
+    <section>
+      <h3>副作用</h3>
+      <p>{{ medicine.sideEffects || '暂无相关信息' }}</p>
+    </section>
+  </div>
+  <div *ngIf="error" class="error-container">
+    <p>{{ error }}</p>
+  </div>
+</ion-content>

+ 39 - 0
src/app/medicine-detail/medicine-detail.page.scss

@@ -0,0 +1,39 @@
+/* 在您的全局或页面特定样式文件中 */
+.loading-container, .error-container {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 80vh;
+  }
+  
+  .medicine-details {
+    padding: 16px;
+  }
+  
+  .medicine-details img {
+    max-width: 100%;
+    height: auto;
+    border-radius: 8px;
+    margin-bottom: 16px;
+  }
+  
+  .medicine-details h2 {
+    font-size: 24px;
+    margin-bottom: 8px;
+  }
+  
+  .medicine-details p {
+    font-size: 16px;
+    color: #6c757d;
+    margin: 4px 0;
+  }
+  
+  .medicine-details section {
+    margin-top: 16px;
+  }
+  
+  .medicine-details section h3 {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 8px;
+  }

+ 17 - 0
src/app/medicine-detail/medicine-detail.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MedicineDetailPage } from './medicine-detail.page';
+
+describe('MedicineDetailPage', () => {
+  let component: MedicineDetailPage;
+  let fixture: ComponentFixture<MedicineDetailPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MedicineDetailPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 50 - 0
src/app/medicine-detail/medicine-detail.page.ts

@@ -0,0 +1,50 @@
+// src/app/medicine-detail/medicine-detail.page.ts
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { MedicineService } from '../services/medicine.service'; // 确认路径是否正确
+import { Observable, throwError } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+import { Medicine } from '../services/medicine.service'; // 导入 Medicine 接口
+
+@Component({
+  selector: 'app-medicine-detail',
+  templateUrl: './medicine-detail.page.html',
+  styleUrls: ['./medicine-detail.page.scss']
+})
+export class MedicineDetailPage implements OnInit {
+  medicine: Medicine | null = null; // 更新为使用 Medicine 接口
+  loading: boolean = true;
+  error: string | null = null;
+
+  constructor(
+    private route: ActivatedRoute,
+    private medicineService: MedicineService // 确保已经定义了 MedicineService
+  ) {}
+
+  ngOnInit() {
+    const id = Number(this.route.snapshot.paramMap.get('id'));
+    this.loadMedicineDetails(id);
+  }
+
+  loadMedicineDetails(id: number) {
+    this.loading = true;
+    this.error = null;
+
+    this.medicineService.getMedicineById(id).pipe(
+      catchError((err) => {
+        this.error = err.message || 'An unexpected error occurred';
+        this.loading = false;
+        return throwError(() => err);
+      })
+    ).subscribe(
+      (data: Medicine) => { // 使用 Medicine 接口作为类型
+        this.medicine = data;
+        this.loading = false;
+      },
+      (error) => {
+        this.error = error.message || 'An unexpected error occurred';
+        this.loading = false;
+      }
+    );
+  }
+}

+ 17 - 0
src/app/medicine-purchase/medicine-purchase-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { MedicinePurchasePage } from './medicine-purchase.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: MedicinePurchasePage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class MedicinePurchasePageRoutingModule {}

+ 20 - 0
src/app/medicine-purchase/medicine-purchase.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { MedicinePurchasePageRoutingModule } from './medicine-purchase-routing.module';
+
+import { MedicinePurchasePage } from './medicine-purchase.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    MedicinePurchasePageRoutingModule
+  ],
+  declarations: [MedicinePurchasePage]
+})
+export class MedicinePurchasePageModule {}

+ 67 - 0
src/app/medicine-purchase/medicine-purchase.page.html

@@ -0,0 +1,67 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab1"></ion-back-button>
+    </ion-buttons>
+    <ion-title>药品选购</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-list>
+    <ion-item *ngFor="let medicine of medicines">
+      <div (click)="goToDetail(medicine.id)" style="display: flex; width: 100%;">
+        <ion-thumbnail slot="start">
+          <img [src]="medicine.imageUrl" alt="{{ medicine.name }}">
+        </ion-thumbnail>
+        <ion-label>
+          <h2>{{ medicine.name }}</h2>
+          <p>{{ medicine.description | slice:0:50 }}...</p>
+          <p>价格: ¥{{ medicine.price }}</p>
+        </ion-label>
+      </div>
+      <ion-button fill="clear" slot="end" (click)="addToCart(medicine)">加入购物车</ion-button>
+    </ion-item>
+  </ion-list>
+</ion-content>
+
+<!-- 购物车 -->
+<ion-footer>
+  <ion-card>
+    <div class="cart-header">
+      <ion-title>购物车</ion-title>
+      <ion-icon name="cart-outline"></ion-icon>
+    </div>
+    <ion-list>
+      <ion-item *ngFor="let item of cartItems$ | async" [@fadeItem]="{value:'enter'}">
+        <ion-thumbnail slot="start">
+          <img [src]="item.imageUrl || 'default-image-url.jpg'" alt="{{ item.name }}">
+        </ion-thumbnail>
+        <ion-label>
+          <h2>{{ item.name }}</h2>
+          <p>小计: ¥{{ item.price * item.quantity }}</p>
+        </ion-label>
+        <div class="item-actions">
+          <button (click)="decrementQuantity(item)">-</button>
+          <span class="quantity-input">
+            <input type="number" [(ngModel)]="item.quantity" min="1" (change)="updateQuantity(item)">
+          </span>
+          <button (click)="incrementQuantity(item)">+</button>
+          <button class="remove-btn" (click)="removeFromCart(item)">移除</button>
+        </div>
+      </ion-item>
+    </ion-list>
+    <ion-item class="total" lines="none">
+      <ion-grid>
+        <ion-row>
+          <ion-col size="6" style="text-align: left;">
+            <h2>总计: ¥{{ cartTotal$ | async }}</h2>
+          </ion-col>
+          <ion-col class="goumai">
+            <ion-button expand="block" color="success" (click)="purchase()">购买</ion-button>
+          </ion-col>
+        </ion-row>
+      </ion-grid>
+    </ion-item>
+  </ion-card>
+</ion-footer>

+ 232 - 0
src/app/medicine-purchase/medicine-purchase.page.scss

@@ -0,0 +1,232 @@
+body {
+    background-color: #f5f6fa;
+  }
+
+  .total {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px;
+  
+    h2 {
+      margin: 20;
+    }
+  }
+  .goumai{
+    size:4;
+    text-align: right;
+    margin-top: 10px;
+  }
+  
+  /* 药品选购头部样式 */
+  ion-header {
+    --background: #4a90e2;
+    --color: white;
+  
+    ion-toolbar {
+      --border-width: 0;
+    }
+  }
+  
+  /* 内容区域样式 */
+  ion-content {
+    --background: #f5f6fa;
+    padding-top: 20px; /* 确保内容区有合适的顶部间距 */
+  }
+  
+  /* 列表项样式 */
+  ion-list {
+    margin: 0;
+    padding: 0;
+  }
+  
+  ion-item {
+    --padding-start: 16px;
+    --padding-end: 16px;
+    --border-radius: 8px;
+    --box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 10px;
+    background: white;
+    padding-top: 10px; /* 可选:增加卡片顶部内边距 */
+    padding-bottom: 10px; /* 可选:增加卡片底部内边距 */
+  }
+  
+  ion-thumbnail img {
+    width: 60px;
+    height: 60px;
+    object-fit: cover;
+    border-radius: 8px;
+  }
+  
+  ion-label h2 {
+    font-size: 18px;
+    font-weight: bold;
+    margin-bottom: 4px;
+  }
+  
+  ion-label p {
+    font-size: 14px;
+    color: #6c757d;
+    margin: 2px 0;
+  }
+  
+  ion-button {
+    --background: #4a90e2;
+    --color: white;
+    --border-radius: 20px;
+    padding: 6px 16px;
+    font-size: 14px;
+  }
+  
+  ion-button[fill="clear"] {
+    --color: #4a90e2;
+    --background: transparent;
+    border: 1px solid #4a90e2;
+    transition: all 0.3s ease;
+  }
+  
+  ion-button[fill="clear"]:hover {
+    --background: rgba(74, 144, 226, 0.1);
+  }
+  
+ /* 购物车样式 */
+ion-footer {
+    position: fixed;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    z-index: 10;
+    background-color: white;
+    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
+    padding: 10px;
+  
+    ion-card {
+      margin: 0;
+      padding: 16px;
+      width: 100%;
+      border-top-left-radius: 16px;
+      border-top-right-radius: 16px;
+      box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.1);
+      transition: transform 0.3s ease;
+    }
+  
+    .cart-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-bottom: 10px;
+  
+      ion-title {
+        font-size: 18px;
+        font-weight: bold;
+      }
+  
+      ion-icon {
+        font-size: 24px;
+        color: #4a90e2;
+      }
+    }
+  
+    ion-list {
+      max-height: 200px; // 根据需要调整高度
+      overflow-y: auto;
+      padding: 0;
+      margin: 0;
+    }
+  
+    ion-item {
+      --padding-start: 16px;
+      --padding-end: 16px;
+      --border-radius: 8px;
+      --box-shadow: none;
+      margin-bottom: 10px;
+      background: #f5f6fa;
+      display: flex;
+      align-items: center;
+      transition: all 0.3s ease;
+  
+      &:last-child {
+        margin-bottom: 0;
+      }
+  
+      &.fade-enter-active,
+      &.fade-leave-active {
+        transition: opacity 0.3s, transform 0.3s;
+      }
+  
+      &.fade-enter,
+      &.fade-leave-to /* .fade-leave-active in < Angular 8 */ {
+        opacity: 0;
+        transform: translateY(20px);
+      }
+    }
+  
+    ion-thumbnail img {
+      width: 40px;
+      height: 40px;
+      object-fit: cover;
+      border-radius: 8px;
+    }
+  
+    ion-label {
+      flex-grow: 1;
+      margin-right: 10px;
+  
+      h2 {
+        font-size: 16px;
+        font-weight: bold;
+        margin-bottom: 4px;
+      }
+  
+      p {
+        font-size: 14px;
+        color: #6c757d;
+        margin: 2px 0;
+      }
+    }
+  
+    .item-actions {
+      display: flex;
+      align-items: center;
+  
+      button {
+        --background: transparent;
+        --color: #4a90e2;
+        --border-radius: 50%;
+        padding: 4px;
+        margin-left: 8px;
+        transition: all 0.3s ease;
+  
+        &:hover {
+          --background: rgba(74, 144, 226, 0.1);
+        }
+  
+        &.remove-btn {
+          --color: #dc3545;
+        }
+      }
+    }
+  
+    .quantity-input {
+      display: flex;
+      align-items: center;
+      font-size: 14px;
+  
+      input {
+        width: 30px;
+        text-align: center;
+        border: 1px solid #ced4da;
+        border-radius: 4px;
+        padding: 4px;
+        margin: 0 4px;
+      }
+    }
+  
+    .total {
+      font-size: 18px;
+      font-weight: bold;
+      color: #4a90e2;
+      text-align: right;
+      margin-top: 10px;
+    }
+  }

+ 17 - 0
src/app/medicine-purchase/medicine-purchase.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MedicinePurchasePage } from './medicine-purchase.page';
+
+describe('MedicinePurchasePage', () => {
+  let component: MedicinePurchasePage;
+  let fixture: ComponentFixture<MedicinePurchasePage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MedicinePurchasePage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 95 - 0
src/app/medicine-purchase/medicine-purchase.page.ts

@@ -0,0 +1,95 @@
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { CartService } from '../services/cart.service'; // 根据实际路径调整
+import { BehaviorSubject } from 'rxjs';
+import { CartItem } from '../services/cart.service'; // 确保路径正确
+import { OrderService } from '../services/order.service'; 
+import { take } from 'rxjs/operators';
+import { trigger, state, style, transition, animate } from '@angular/animations';
+
+@Component({
+  selector: 'app-medicine-purchase',
+  templateUrl: './medicine-purchase.page.html',
+  styleUrls: ['./medicine-purchase.page.scss'],
+  animations: [
+    trigger('fadeItem', [
+      state('void', style({ opacity: 0 })),
+      state('*', style({ opacity: 1 })),
+      transition(':enter', [animate('300ms ease-in')]),
+      transition(':leave', [animate('300ms ease-out')])
+    ])
+  ]
+})
+export class MedicinePurchasePage implements OnInit {
+  medicines = [
+    { id: 1, name: '阿司匹林', price: 15.99, description: '用于缓解轻度至中度疼痛...', imageUrl: '../assets/images/药1.png' },
+    { id: 2, name: '布洛芬', price: 12.99, description: '非甾体抗炎药...', imageUrl: '../assets/images/药2.png' },
+    // 添加更多药品...
+  ];
+
+  cartItems$ = this.cartService.cartItems$;
+  private cartTotalSubject = new BehaviorSubject<number>(0);
+  cartTotal$ = this.cartTotalSubject.asObservable();
+
+  constructor(
+    private router: Router,
+    private cartService: CartService,
+    private orderService: OrderService // 注入OrderService
+  ) {}
+
+  ngOnInit() {
+    this.cartService.cartItems$.subscribe(items => {
+      const total = this.cartService.getCartTotal();
+      this.cartTotalSubject.next(total);
+    });
+  }
+
+  goToDetail(id: number) {
+    this.router.navigate(['/medicine-detail', id]);
+  }
+
+  addToCart(medicine: any) {
+    this.cartService.addToCart({ ...medicine, quantity: 1 });
+  }
+
+  removeFromCart(item: CartItem) {
+    this.cartService.removeFromCart(item.id);
+  }
+
+  incrementQuantity(item: CartItem) {
+    this.cartService.updateCartItem(item.id, item.quantity + 1);
+  }
+
+  decrementQuantity(item: CartItem) {
+    if (item.quantity > 1) {
+      this.cartService.updateCartItem(item.id, item.quantity - 1);
+    } else {
+      this.removeFromCart(item);
+    }
+  }
+
+  updateQuantity(item: CartItem) {
+    this.cartService.updateCartItem(item.id, item.quantity);
+  }
+
+  purchase() {
+    this.cartService.cartItems$.pipe(take(1)).subscribe(cartItems => {
+      if (cartItems.length === 0) {
+        alert('购物车为空,请选择商品后再进行购买');
+        return;
+      }
+
+      // 创建订单
+      const orderId = this.orderService.createOrder(cartItems); // 确保类型匹配
+
+      // 清空购物车
+      this.cartService.clearCart();
+
+      // 提示用户购买成功
+      alert(`购买成功!订单号:${orderId}`);
+
+      // 导航到订单页面
+      this.router.navigate(['/orders']);
+    });
+  }
+}

+ 17 - 0
src/app/new-post/new-post-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { NewPostPage } from './new-post.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: NewPostPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class NewPostPageRoutingModule {}

+ 20 - 0
src/app/new-post/new-post.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { NewPostPageRoutingModule } from './new-post-routing.module';
+
+import { NewPostPage } from './new-post.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    NewPostPageRoutingModule
+  ],
+  declarations: [NewPostPage]
+})
+export class NewPostPageModule {}

+ 22 - 0
src/app/new-post/new-post.page.html

@@ -0,0 +1,22 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>发布新帖子</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="cancel()">取消</ion-button>
+      <ion-button (click)="submitPost()" [disabled]="!title || !content">发布</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-list>
+    <ion-item>
+      <ion-label position="floating">标题</ion-label>
+      <ion-input [(ngModel)]="title"></ion-input>
+    </ion-item>
+    <ion-item>
+      <ion-label position="floating">内容</ion-label>
+      <ion-textarea [(ngModel)]="content"></ion-textarea>
+    </ion-item>
+  </ion-list>
+</ion-content>

+ 25 - 0
src/app/new-post/new-post.page.scss

@@ -0,0 +1,25 @@
+/* src/app/pages/new-post/new-post.page.scss */
+ion-content {
+    --background: #f5f6fa;
+  }
+  
+  ion-list {
+    margin-top: 20px;
+  }
+  
+  ion-item {
+    --padding-start: 16px;
+    --padding-end: 16px;
+    --border-radius: 8px;
+    --box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    margin-bottom: 10px;
+    background: white;
+  }
+  
+  ion-input, ion-textarea {
+    font-size: 16px;
+  }
+  
+  ion-button {
+    margin-left: 10px;
+  }

+ 17 - 0
src/app/new-post/new-post.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { NewPostPage } from './new-post.page';
+
+describe('NewPostPage', () => {
+  let component: NewPostPage;
+  let fixture: ComponentFixture<NewPostPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NewPostPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 44 - 0
src/app/new-post/new-post.page.ts

@@ -0,0 +1,44 @@
+import { Component, OnInit } from '@angular/core';
+import { ModalController } from '@ionic/angular';
+import { UserService } from '../services/user.service';
+
+@Component({
+  selector: 'app-new-post',
+  templateUrl: './new-post.page.html',
+  styleUrls: ['./new-post.page.scss'],
+})
+export class NewPostPage implements OnInit {
+
+  title: string = ''; // 声明 title 属性
+  content: string = ''; // 声明 content 属性
+  user: any;
+  posts = [];
+
+  constructor(private modalCtrl: ModalController, private userService: UserService) {}
+
+  ngOnInit() {
+    this.userService.getUserInfo().subscribe(userInfo => {
+      if (userInfo) {
+        this.user = userInfo;
+      }
+    });
+  }
+
+  async submitPost() {
+    if (this.title.trim() === '' || this.content.trim() === '') {
+      console.warn('Title and content cannot be empty');
+      return;
+    }
+
+    // 打印日志以确认数据是否正确
+    console.log('Submit Post:', { title: this.title, content: this.content });
+
+    // 关闭模态窗口并返回数据
+    await this.modalCtrl.dismiss({ title: this.title, content: this.content });
+  }
+
+  async cancel() {
+    // 关闭模态窗口而不返回数据
+    await this.modalCtrl.dismiss();
+  }
+}

+ 17 - 0
src/app/news-detail/news-detail-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { NewsDetailPage } from './news-detail.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: NewsDetailPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class NewsDetailPageRoutingModule {}

+ 23 - 0
src/app/news-detail/news-detail.module.ts

@@ -0,0 +1,23 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { NewsDetailPageRoutingModule } from './news-detail-routing.module';
+
+import { NewsDetailPage } from './news-detail.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    NewsDetailPageRoutingModule,
+  ],
+  declarations: [
+    NewsDetailPage,
+  ],
+
+})
+export class NewsDetailPageModule {}

+ 21 - 0
src/app/news-detail/news-detail.page.html

@@ -0,0 +1,21 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button (click)="dismiss()">
+        <ion-icon name="close"></ion-icon>
+      </ion-button>
+    </ion-buttons>
+    <ion-title>{{ news.title }}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content padding>
+  <ion-card>
+    <ion-card-header>
+      <ion-card-subtitle>{{ news.title }}</ion-card-subtitle>
+    </ion-card-header>
+    <ion-card-content>
+      <div [innerHTML]="safeContent"></div>
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 60 - 0
src/app/news-detail/news-detail.page.scss

@@ -0,0 +1,60 @@
+/* 添加一些基本样式以确保内容格式正确 */
+ion-card-content div {
+    white-space: pre-wrap; /* 确保换行符生效 */
+    line-height: 1.6; /* 设置行高 */
+  }
+  
+  ion-card-content ul {
+    list-style-type: disc; /* 默认项目符号 */
+    padding-left: 20px; /* 缩进列表项 */
+  }
+  
+  ion-card-content li {
+    margin-bottom: 8px; /* 列表项之间的间距 */
+  }
+  
+  ion-card-content p {
+    margin-bottom: 16px; /* 段落之间的间距 */
+  }
+  
+  ion-card-content strong {
+    font-weight: bold; /* 加粗文本 */
+    color: #007aff;
+  }
+  
+  ion-card-content h3 {
+    font-weight: bold;
+    margin-bottom: 8px;
+    font-size: 1.1em;
+    color: #333;
+  }
+  
+  ion-card-content article {
+    margin-bottom: 16px;
+  }
+  
+  ion-card-content section {
+    margin-bottom: 20px;
+  }
+  
+  ion-card {
+    margin-bottom: 16px;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+  
+  ion-card-header {
+    background-color: #f9f9f9;
+    padding: 16px;
+    border-bottom: 1px solid #ddd;
+  }
+  
+  ion-card-header ion-card-subtitle {
+    font-size: 1.2em;
+    font-weight: bold;
+    color: #333;
+  }
+  
+  ion-card-content {
+    padding: 16px;
+  }

+ 17 - 0
src/app/news-detail/news-detail.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { NewsDetailPage } from './news-detail.page';
+
+describe('NewsDetailPage', () => {
+  let component: NewsDetailPage;
+  let fixture: ComponentFixture<NewsDetailPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NewsDetailPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 30 - 0
src/app/news-detail/news-detail.page.ts

@@ -0,0 +1,30 @@
+import { Component, OnInit } from '@angular/core';
+import { NavParams, ModalController } from '@ionic/angular';
+
+@Component({
+  selector: 'app-news-detail',
+  templateUrl: './news-detail.page.html',
+  styleUrls: ['./news-detail.page.scss'],
+})
+export class NewsDetailPage implements OnInit {
+
+  news: any;
+  safeContent?: string;
+
+  constructor(
+    private navParams: NavParams,
+    private modalController: ModalController
+  ) {}
+
+  ngOnInit() {
+    this.news = this.navParams.get('news');
+    this.safeContent = this.news.content; // 初始化 safeContent
+  }
+
+  dismiss() {
+    this.modalController.dismiss();
+  }
+}
+
+
+

+ 17 - 0
src/app/orders/orders-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { OrdersPage } from './orders.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: OrdersPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class OrdersPageRoutingModule {}

+ 20 - 0
src/app/orders/orders.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { OrdersPageRoutingModule } from './orders-routing.module';
+
+import { OrdersPage } from './orders.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    OrdersPageRoutingModule
+  ],
+  declarations: [OrdersPage]
+})
+export class OrdersPageModule {}

+ 33 - 0
src/app/orders/orders.page.html

@@ -0,0 +1,33 @@
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab1"></ion-back-button>
+    </ion-buttons>
+    <ion-title>订单管理</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content padding>
+  <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
+    <ion-refresher-content pullingIcon="chevron-down-circle" pullingText="下拉刷新" refreshingSpinner="circles" refreshingText="正在刷新..."></ion-refresher-content>
+  </ion-refresher>
+  <ion-list *ngIf="orders.length > 0" class="order-list">
+    <ion-item *ngFor="let order of orders" class="order-item" [@orderAnimation]>
+      <ion-label>
+        <h2>订单号: {{ order.id }}</h2>
+        <p>创建时间: {{ order.createdAt | date:'medium' }}</p>
+        <p>总计: ¥{{ order.total }}</p>
+        <p>订单详情:</p>
+        <ul class="order-details">
+          <li *ngFor="let item of order.items">
+            {{ item.name }} (数量: {{ item.quantity }}, 单价: ¥{{ item.price }})
+          </li>
+        </ul>
+      </ion-label>
+      <ion-button fill="clear" color="danger" slot="end" (click)="confirmDeleteOrder(order)">删除</ion-button>
+    </ion-item>
+  </ion-list>
+  <div *ngIf="orders.length === 0" class="no-orders">
+    <p>没有找到任何订单。</p>
+  </div>
+</ion-content>

+ 67 - 0
src/app/orders/orders.page.scss

@@ -0,0 +1,67 @@
+/* 基本样式 */
+ion-content {
+    --background: #f4f5f8; /* 设置背景颜色 */
+  }
+  
+  .order-list {
+    margin-top: 10px;
+  }
+  
+  .order-item {
+    border-bottom: 1px solid #e0e0e0; /* 分割线 */
+    padding: 16px;
+    background-color: white;
+    transition: box-shadow 0.3s ease;
+  
+    &:hover {
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    }
+  
+    &.ng-entering, &.ng-leaving {
+      position: relative;
+      z-index: 1;
+    }
+  }
+  
+  .order-item ion-label {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    height: 100%;
+  }
+  
+  .order-details {
+    margin-top: 10px;
+    list-style-type: none;
+    padding-left: 0;
+    li {
+      margin-bottom: 5px;
+    }
+  }
+  
+  .no-orders {
+    text-align: center;
+    margin-top: 20px;
+    p {
+      font-size: 16px;
+      color: #757575;
+    }
+  }
+  
+  /* 删除按钮样式 */
+  ion-button[color="danger"] {
+    --color: #d32f2f;
+    --color-activated: #c62828;
+  }
+  
+  /* 确认对话框样式 */
+  ion-alert {
+    --background: white;
+    --border-radius: 10px;
+    header {
+      font-weight: bold;
+    }
+    button {
+      font-weight: 500;
+    }
+  }

+ 17 - 0
src/app/orders/orders.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { OrdersPage } from './orders.page';
+
+describe('OrdersPage', () => {
+  let component: OrdersPage;
+  let fixture: ComponentFixture<OrdersPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(OrdersPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 78 - 0
src/app/orders/orders.page.ts

@@ -0,0 +1,78 @@
+import { Component, OnInit } from '@angular/core';
+import { OrderService } from '../services/order.service';
+import { AlertController } from '@ionic/angular';
+import { Order } from '../services/order.service'; // 确保路径正确
+import { trigger, state, style, transition, animate } from '@angular/animations';
+
+@Component({
+  selector: 'app-orders',
+  templateUrl: './orders.page.html',
+  styleUrls: ['./orders.page.scss'],
+  animations: [
+    trigger('orderAnimation', [
+      state('void', style({ opacity: 0, transform: 'translateY(-10px)' })),
+      state('*', style({ opacity: 1, transform: 'translateY(0)' })),
+      transition(':enter', [animate('300ms ease-in')]),
+      transition(':leave', [animate('300ms ease-out')])
+    ])
+  ]
+})
+export class OrdersPage implements OnInit {
+  orders: Order[] = [];
+
+  constructor(
+    private orderService: OrderService,
+    private alertController: AlertController
+  ) {}
+
+  ngOnInit() {
+    this.loadOrders();
+  }
+
+  loadOrders() {
+    this.orders = this.orderService.getOrders();
+  }
+
+  async confirmDeleteOrder(order: Order) {
+    const alert = await this.alertController.create({
+      header: '确认删除',
+      message: '确定要删除此订单吗?',
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel',
+          cssClass: 'secondary',
+          handler: () => {
+            console.log('Confirm Cancel');
+          }
+        }, {
+          text: '确定',
+          handler: () => {
+            this.deleteOrder(order);
+          }
+        }
+      ]
+    });
+
+    await alert.present();
+  }
+
+  deleteOrder(order: Order) {
+    this.orderService.deleteOrder(order.id);
+
+    // 重新加载订单列表以反映更改
+    this.loadOrders();
+
+    // 提示用户删除成功
+    console.log('订单删除成功');
+  }
+
+  doRefresh(event: any) {
+    console.log('Begin async operation');
+    setTimeout(() => {
+      console.log('Async operations have ended');
+      event.target.complete();
+    }, 1000);
+  }
+
+}

+ 38 - 0
src/app/pipes/safe-html.pipe.spec.ts

@@ -0,0 +1,38 @@
+import { TestBed } from '@angular/core/testing';
+import { SafeHtmlPipe } from './safe-html.pipe';
+import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
+
+class MockDomSanitizer {
+  bypassSecurityTrustHtml(value: string): SafeHtml {
+    return value as SafeHtml;
+  }
+}
+
+describe('SafeHtmlPipe', () => {
+  let pipe: SafeHtmlPipe;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [
+        SafeHtmlPipe,
+        { provide: DomSanitizer, useClass: MockDomSanitizer }
+      ]
+    });
+
+    pipe = TestBed.inject(SafeHtmlPipe);
+  });
+
+  it('create an instance', () => {
+    expect(pipe).toBeTruthy();
+  });
+
+  it('should sanitize and trust HTML content', () => {
+    const htmlContent = '<p>This is a <strong>test</strong> paragraph.</p>';
+    const sanitizedContent = pipe.transform(htmlContent);
+
+    expect(sanitizedContent.toString()).toContain('<p>This is a <strong>test</strong> paragraph.</p>');
+  });
+});
+
+
+

+ 14 - 0
src/app/pipes/safe-html.pipe.ts

@@ -0,0 +1,14 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
+
+@Pipe({
+  name: 'safeHtml'
+})
+export class SafeHtmlPipe implements PipeTransform {
+
+  constructor(private sanitizer: DomSanitizer) {}
+
+  transform(value: string): SafeHtml {
+    return this.sanitizer.bypassSecurityTrustHtml(value);
+  }
+}

+ 17 - 0
src/app/points-and-coupons/points-and-coupons-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { PointsAndCouponsPage } from './points-and-coupons.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: PointsAndCouponsPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class PointsAndCouponsPageRoutingModule {}

+ 20 - 0
src/app/points-and-coupons/points-and-coupons.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { PointsAndCouponsPageRoutingModule } from './points-and-coupons-routing.module';
+
+import { PointsAndCouponsPage } from './points-and-coupons.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    PointsAndCouponsPageRoutingModule
+  ],
+  declarations: [PointsAndCouponsPage]
+})
+export class PointsAndCouponsPageModule {}

+ 62 - 0
src/app/points-and-coupons/points-and-coupons.page.html

@@ -0,0 +1,62 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab3" text="" icon="arrow-back"></ion-back-button>
+    </ion-buttons>
+    <ion-title>积分与优惠</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="points-and-coupons-page">
+  <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
+    <ion-refresher-content pullingIcon="chevron-down-circle" pullingText="下拉刷新" refreshingSpinner="circles" refreshingText="正在刷新..."></ion-refresher-content>
+  </ion-refresher>
+
+  <!-- 用户积分展示 -->
+  <section class="user-points-section">
+    <ion-card>
+      <ion-card-header>
+        <ion-card-title>我的积分</ion-card-title>
+      </ion-card-header>
+      <ion-card-content>
+        <div class="points-display">
+          <h1>{{ userPoints }}</h1>
+          <p>可用积分</p>
+        </div>
+      </ion-card-content>
+    </ion-card>
+  </section>
+
+  <!-- 优惠活动列表 -->
+  <section class="promotions-section">
+    <h3 class="section-title">最新优惠活动</h3>
+    <ion-list>
+      <ion-item button *ngFor="let promotion of promotions" (click)="viewPromotionDetails(promotion)" class="promotion-item">
+        <ion-icon name="gift" slot="start"></ion-icon>
+        <ion-label>
+          <h2>{{ promotion.title }}</h2>
+          <p>{{ promotion.description }}</p>
+        </ion-label>
+        <ion-badge color="secondary" *ngIf="promotion.isNew">新</ion-badge>
+      </ion-item>
+    </ion-list>
+  </section>
+
+  <section class="redeem-section">
+    <h3 class="section-title">积分兑换礼品</h3>
+    <ion-grid>
+      <ion-row>
+        <ion-col size="6" *ngFor="let gift of gifts">
+          <ion-card (click)="viewGiftDetails(gift)">
+            <img [src]="gift.image" alt="{{ gift.name }}" class="gift-image" />
+            <ion-card-content>
+              <h2>{{ gift.name }}</h2>
+              <p>{{ gift.pointsRequired }} 积分</p>
+            </ion-card-content>
+          </ion-card>
+        </ion-col>
+      </ion-row>
+    </ion-grid>
+  </section>
+
+</ion-content>

+ 124 - 0
src/app/points-and-coupons/points-and-coupons.page.scss

@@ -0,0 +1,124 @@
+.points-and-coupons-page {
+    .ion-page {
+      background: linear-gradient(180deg, #f4f5f8 0%, #eef1f5 100%); /* 背景渐变 */
+    }
+  
+    ion-content {
+      --background: #fff;
+      padding: 16px;
+    }
+  
+    section {
+      margin-bottom: 24px;
+    }
+  
+    h3 {
+      font-size: 1.2rem;
+      margin-bottom: 12px;
+      color: #333;
+      text-align: center;
+    }
+
+    .section-title {
+        font-size: 1.6rem; /* 增大字体大小 */
+        margin-bottom: 24px; /* 增加下边距 */
+        color: #333;
+        text-align: center; /* 水平居中文本 */
+        font-weight: bold; /* 加粗字体 */
+        letter-spacing: 0.5px; /* 字符间距 */
+        text-transform: uppercase; /* 转换为大写 */
+        padding: 8px 0; /* 内边距 */
+        border-bottom: 2px solid #eaeaea; /* 底部细线 */
+        display: inline-block; /* 确保装饰线只应用于文本宽度 */
+        background: linear-gradient(90deg, #ffcc00, #ff9900); /* 渐变背景 */
+        -webkit-background-clip: text; /* 文字剪裁 */
+        -webkit-text-fill-color: transparent; /* 文字填充透明 */
+        box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* 添加轻微阴影 */
+      }
+  
+    .points-display {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      flex-direction: column;
+      padding: 24px;
+  
+      h1 {
+        font-size: 2.4rem;
+        font-weight: bold;
+        color: #007aff;
+      }
+  
+      p {
+        font-size: 1rem;
+        color: #666;
+      }
+    }
+  
+    .promotion-item {
+      --border-width: 0;
+      --padding-start: 16px;
+      --padding-end: 16px;
+  
+      &:not(:last-child) {
+        border-bottom: 1px solid #eaeaea;
+      }
+    }
+  
+    ion-card {
+      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+      border-radius: 12px;
+      overflow: hidden;
+  
+      img {
+        width: 100%;
+        height: auto;
+      }
+  
+      ion-card-content {
+        padding: 16px;
+        text-align: center;
+      }
+    }
+  
+    ion-button {
+      margin-top: 16px;
+      width: 100%;
+      border-radius: 8px;
+      transition: transform 0.2s ease-in-out;
+  
+      &:active {
+        transform: scale(0.95); /* 按钮按下时缩小 */
+      }
+    }
+  
+    /* 返回按钮的样式 */
+    ion-back-button {
+      --color: #007aff;
+    }
+
+    .gift-image {
+        width: 100%; /* 图片宽度填满容器 */
+        height: 150px; /* 固定高度 */
+        object-fit: cover; /* 保持图片比例并裁剪超出部分 */
+        display: block; /* 避免图片下方出现空隙 */
+      }
+    
+      ion-card {
+        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+        border-radius: 12px;
+        overflow: hidden;
+    
+        img {
+          width: 100%;
+          height: 150px; /* 继承上面定义的高度 */
+          object-fit: cover;
+        }
+    
+        ion-card-content {
+          padding: 16px;
+          text-align: center;
+        }
+      }
+    
+  }

+ 17 - 0
src/app/points-and-coupons/points-and-coupons.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { PointsAndCouponsPage } from './points-and-coupons.page';
+
+describe('PointsAndCouponsPage', () => {
+  let component: PointsAndCouponsPage;
+  let fixture: ComponentFixture<PointsAndCouponsPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PointsAndCouponsPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 42 - 0
src/app/points-and-coupons/points-and-coupons.page.ts

@@ -0,0 +1,42 @@
+import { Component } from '@angular/core';
+import { NavController } from '@ionic/angular';
+
+@Component({
+  selector: 'app-points-and-coupons',
+  templateUrl: './points-and-coupons.page.html',
+  styleUrls: ['./points-and-coupons.page.scss'],
+})
+export class PointsAndCouponsPage {
+  userPoints = 500; // 示例用户积分
+  hasNewPromotions = true;
+  promotions = [
+    { title: '迎新年特惠', description: '享受8折优惠', isNew: true },
+    { title: '会员日折扣', description: '每月特定日期额外9折', isNew: false },
+    // ... 添加更多优惠活动 ...
+  ];
+  gifts = [
+    { name: '精美保温杯', image: 'https://img.alicdn.com/bao/uploaded/i3/1689522943/O1CN01DCaxvA1XbwOqP1Gm7_!!0-item_pic.jpg', pointsRequired: 200 },
+    { name: '便携充电宝', image: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.F755jeHNi2oKZRUGpNfVlgHaEd?rs=1&pid=ImgDetMain', pointsRequired: 300 },
+    // ... 添加更多礼品 ...
+  ];
+
+  constructor(private navCtrl: NavController) {}
+
+  doRefresh(event: any) {
+    console.log('Begin async operation');
+    setTimeout(() => {
+      console.log('Async operations have ended');
+      event.target.complete();
+    }, 1000);
+  }
+
+  viewPromotionDetails(promotion: any) {
+    console.log(`查看优惠活动: ${promotion.title}`);
+    this.navCtrl.navigateForward('/promotions');
+  }
+
+  viewGiftDetails(gift: any) {
+    console.log(`查看礼品: ${gift.name}`);
+    this.navCtrl.navigateForward('/promotions');
+  }
+}

+ 17 - 0
src/app/promotions/promotions-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { PromotionsPage } from './promotions.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: PromotionsPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class PromotionsPageRoutingModule {}

+ 21 - 0
src/app/promotions/promotions.module.ts

@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule} from '@ionic/angular'; 
+
+import { PromotionsPageRoutingModule } from './promotions-routing.module';
+
+import { PromotionsPage } from './promotions.page';
+
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    PromotionsPageRoutingModule,
+  ],
+  declarations: [PromotionsPage]
+})
+export class PromotionsPageModule {}

+ 74 - 0
src/app/promotions/promotions.page.html

@@ -0,0 +1,74 @@
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab3"></ion-back-button>
+    </ion-buttons>
+    <ion-title>最新活动与优惠</ion-title>
+  </ion-toolbar>
+  
+  <!-- 搜索栏 -->
+  <ion-searchbar (ionInput)="searchPromotions($event)"></ion-searchbar>
+
+  <!-- 过滤器 -->
+  <ion-segment [(ngModel)]="viewMode" (ionChange)="filterPromotions()">
+    <ion-segment-button value="all">
+      <ion-label>所有活动</ion-label>
+    </ion-segment-button>
+    <ion-segment-button value="favorites">
+      <ion-label>已收藏活动</ion-label>
+    </ion-segment-button>
+  </ion-segment>
+
+  <!-- 排序选项 -->
+  <ion-item>
+    <ion-label>按</ion-label>
+    <ion-select [(ngModel)]="sortOption" (ionChange)="sortPromotions()">
+      <ion-select-option value="dateAsc">日期升序</ion-select-option>
+      <ion-select-option value="dateDesc">日期降序</ion-select-option>
+      <ion-select-option value="popularity">受欢迎程度</ion-select-option>
+    </ion-select>
+  </ion-item>
+</ion-header>
+
+<ion-content>
+
+  <ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
+    <ion-refresher-content pullingIcon="chevron-down-circle" pullingText="下拉刷新" refreshingSpinner="circles" refreshingText="正在刷新..."></ion-refresher-content>
+  </ion-refresher>
+  <!-- 加载指示 -->
+  <div *ngIf="isLoading" class="loading-container">
+    <ion-spinner name="crescent"></ion-spinner>
+  </div>
+
+  <!-- 错误信息 -->
+  <div *ngIf="hasError" class="error-message-container">
+    <p>加载失败,请刷新重试。</p>
+    <ion-button (click)="loadPromotions()" expand="block">刷新</ion-button>
+  </div>
+
+  <!-- 活动列表 -->
+  <ion-list *ngIf="!isLoading && !hasError && displayedPromotions.length > 0" class="promotion-list">
+    <ion-item *ngFor="let promotion of filteredPromotions" class="promotion-item">
+      <ion-thumbnail slot="start">
+        <img [src]="promotion.imageUrl" alt="promotion image"/>
+      </ion-thumbnail>
+      <ion-label>
+        <h2>{{promotion.title}}</h2>
+        <p>{{promotion.description}}</p>
+      </ion-label>
+      <ion-buttons slot="end">
+        <ion-button fill="clear" (click)="sharePromotion(promotion)">
+          <ion-icon name="share-outline"></ion-icon>
+        </ion-button>
+        <ion-button fill="clear" (click)="toggleFavorite(promotion)">
+          <ion-icon [name]="promotion.isFavorite ? 'heart' : 'heart-outline'"></ion-icon>
+        </ion-button>
+      </ion-buttons>
+    </ion-item>
+  </ion-list>
+
+  <!-- 空状态 -->
+  <div *ngIf="!isLoading && !hasError && displayedPromotions.length === 0" class="empty-state">
+    <p>暂无活动信息。</p>
+  </div>
+</ion-content>

+ 50 - 0
src/app/promotions/promotions.page.scss

@@ -0,0 +1,50 @@
+ion-header {
+    --background: linear-gradient(135deg, #ff6f61, #fe4a49); /* 渐变背景 */
+  }
+  
+  .promotion-card {
+    background-color: white;
+    border-radius: 10px;
+    padding: 20px;
+    margin: 20px;
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+    text-align: center;
+  
+    .promotion-image {
+      width: 100%;
+      height: auto;
+      border-radius: 10px;
+      margin-bottom: 10px;
+    }
+  
+    h2 {
+      font-size: 20px;
+      margin-bottom: 5px;
+      color: #333;
+    }
+  
+    p {
+      font-size: 14px;
+      color: #666;
+    }
+  
+    .card-actions {
+      display: flex;
+      justify-content: space-around;
+      margin-top: 10px;
+    }
+  }
+  
+  .loading-container, .error-message-container {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    height: 80vh;
+    text-align: center;
+  }
+  
+  .loading-container p, .error-message-container p {
+    margin-top: 10px;
+    font-size: 16px;
+  }

+ 17 - 0
src/app/promotions/promotions.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { PromotionsPage } from './promotions.page';
+
+describe('PromotionsPage', () => {
+  let component: PromotionsPage;
+  let fixture: ComponentFixture<PromotionsPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PromotionsPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 120 - 0
src/app/promotions/promotions.page.ts

@@ -0,0 +1,120 @@
+import { Component, OnInit } from '@angular/core';
+import { PromotionsService } from '../services/promotions.service';
+import { LoadingController, ToastController } from '@ionic/angular';
+
+@Component({
+  selector: 'app-promotions',
+  templateUrl: './promotions.page.html',
+  styleUrls: ['./promotions.page.scss'],
+})
+export class PromotionsPage implements OnInit {
+
+  promotions: any[] = [];
+  displayedPromotions: any[] = [];
+  isLoading = true;
+  hasError = false;
+  searchQuery = '';
+  viewMode = 'all'; // 默认查看所有活动
+  sortOption = 'dateDesc'; // 默认按照日期降序排列
+  filteredPromotions: any[] = []; // 用于显示经过过滤和排序后的活动
+
+  constructor(
+    private promotionsService: PromotionsService,
+    private loadingCtrl: LoadingController,
+    private toastCtrl: ToastController
+  ) {}
+
+  ngOnInit() {
+    this.loadPromotions();
+  }
+
+  doRefresh(event: any) {
+    console.log('Begin async operation');
+    setTimeout(() => {
+      console.log('Async operations have ended');
+      event.target.complete();
+    }, 1000);
+  }
+
+  async loadPromotions() {
+    const loading = await this.loadingCtrl.create({ message: 'Loading...' });
+    await loading.present();
+
+    try {
+      const data = await this.promotionsService.getPromotions().toPromise() || [];
+      this.promotions = Array.isArray(data) ? data : [];
+      this.filterAndSortPromotions(); // 初始加载后立即应用过滤和排序
+      this.isLoading = false;
+      loading.dismiss();
+    } catch (error) {
+      this.hasError = true;
+      this.isLoading = false;
+      loading.dismiss();
+      const toast = await this.toastCtrl.create({
+        message: '无法加载活动信息,请稍后再试。',
+        duration: 3000,
+        position: 'bottom'
+      });
+      await toast.present();
+    }
+  }
+
+  searchPromotions(event: any) {
+    this.searchQuery = event.detail.value;
+    this.updateFilteredPromotions(); // 在这里调用更新方法
+  }
+
+  sharePromotion(promotion: any) {
+    // 实现分享逻辑
+  }
+
+  toggleFavorite(promotion: any) {
+    promotion.isFavorite = !promotion.isFavorite;
+    this.filterAndSortPromotions(); // 更新显示列表
+  }
+
+  filterPromotions() {
+    this.filterAndSortPromotions(); // 当过滤条件改变时重新过滤和排序
+  }
+
+  sortPromotions() {
+    this.filterAndSortPromotions(); // 当排序条件改变时重新过滤和排序
+  }
+
+  private updateFilteredPromotions() {
+    if (this.searchQuery) {
+      const lowerCaseQuery = this.searchQuery.toLowerCase();
+      this.filteredPromotions = this.displayedPromotions.filter(promotion => 
+        promotion.title.toLowerCase().includes(lowerCaseQuery) ||
+        promotion.description.toLowerCase().includes(lowerCaseQuery)
+      );
+    } else {
+      this.filteredPromotions = this.displayedPromotions;
+    }
+  }
+
+  private filterAndSortPromotions() {
+    let filtered = this.promotions;
+
+    // 应用过滤
+    if (this.viewMode === 'favorites') {
+      filtered = filtered.filter(promotion => promotion.isFavorite);
+    }
+
+    // 应用排序
+    switch (this.sortOption) {
+      case 'dateAsc':
+        filtered.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
+        break;
+      case 'dateDesc':
+        filtered.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
+        break;
+      case 'popularity':
+        filtered.sort((a, b) => b.popularity - a.popularity); // 假设有一个 popularity 属性
+        break;
+    }
+
+    this.displayedPromotions = filtered;
+    this.updateFilteredPromotions(); // 更新过滤后的列表
+  }
+}

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff