未来全栈 4 kuukautta sitten
vanhempi
commit
ba8483787f
56 muutettua tiedostoa jossa 2232 lisäystä ja 131 poistoa
  1. 2 1
      angular.json
  2. 833 2
      package-lock.json
  3. 3 0
      package.json
  4. 14 1
      src/app/app-routing.module.ts
  5. 3 0
      src/app/app.component.ts
  6. 222 47
      src/app/tab1/tab1.page.html
  7. 132 0
      src/app/tab1/tab1.page.scss
  8. 36 71
      src/app/tab1/tab1.page.ts
  9. 3 0
      src/app/tab2/tab2.page.html
  10. 8 0
      src/app/tab2/tab2.page.ts
  11. 7 7
      src/app/tab3/tab3.page.html
  12. 6 2
      src/app/tab3/tab3.page.ts
  13. 12 0
      src/modules copy/aigc/aigc-routing.module.ts
  14. 14 0
      src/modules copy/aigc/aigc.module.ts
  15. 17 0
      src/modules copy/aigc/chat/chat-routing.module.ts
  16. 20 0
      src/modules copy/aigc/chat/chat.module.ts
  17. 24 0
      src/modules copy/aigc/chat/chat.page.html
  18. 0 0
      src/modules copy/aigc/chat/chat.page.scss
  19. 17 0
      src/modules copy/aigc/chat/chat.page.spec.ts
  20. 31 0
      src/modules copy/aigc/chat/chat.page.ts
  21. 99 0
      src/modules copy/aigc/chat/class-chat-completion.ts
  22. 17 0
      src/modules copy/contact/contact-detail/contact-detail-routing.module.ts
  23. 20 0
      src/modules copy/contact/contact-detail/contact-detail.module.ts
  24. 13 0
      src/modules copy/contact/contact-detail/contact-detail.page.html
  25. 0 0
      src/modules copy/contact/contact-detail/contact-detail.page.scss
  26. 17 0
      src/modules copy/contact/contact-detail/contact-detail.page.spec.ts
  27. 15 0
      src/modules copy/contact/contact-detail/contact-detail.page.ts
  28. 17 0
      src/modules copy/contact/contact-list/contact-list-routing.module.ts
  29. 20 0
      src/modules copy/contact/contact-list/contact-list.module.ts
  30. 34 0
      src/modules copy/contact/contact-list/contact-list.page.html
  31. 0 0
      src/modules copy/contact/contact-list/contact-list.page.scss
  32. 17 0
      src/modules copy/contact/contact-list/contact-list.page.spec.ts
  33. 42 0
      src/modules copy/contact/contact-list/contact-list.page.ts
  34. 12 0
      src/modules copy/contact/contact-routing.module.ts
  35. 14 0
      src/modules copy/contact/contact.module.ts
  36. 17 0
      src/modules/user/edit-info/edit-info-routing.module.ts
  37. 20 0
      src/modules/user/edit-info/edit-info.module.ts
  38. 47 0
      src/modules/user/edit-info/edit-info.page.html
  39. 0 0
      src/modules/user/edit-info/edit-info.page.scss
  40. 17 0
      src/modules/user/edit-info/edit-info.page.spec.ts
  41. 56 0
      src/modules/user/edit-info/edit-info.page.ts
  42. 17 0
      src/modules/user/login/login-routing.module.ts
  43. 20 0
      src/modules/user/login/login.module.ts
  44. 38 0
      src/modules/user/login/login.page.html
  45. 0 0
      src/modules/user/login/login.page.scss
  46. 17 0
      src/modules/user/login/login.page.spec.ts
  47. 93 0
      src/modules/user/login/login.page.ts
  48. 17 0
      src/modules/user/mine/mine-routing.module.ts
  49. 20 0
      src/modules/user/mine/mine.module.ts
  50. 29 0
      src/modules/user/mine/mine.page.html
  51. 0 0
      src/modules/user/mine/mine.page.scss
  52. 17 0
      src/modules/user/mine/mine.page.spec.ts
  53. 35 0
      src/modules/user/mine/mine.page.ts
  54. 14 0
      src/modules/user/user-routing.module.ts
  55. 14 0
      src/modules/user/user.module.ts
  56. 3 0
      tsconfig.doc.json

+ 2 - 1
angular.json

@@ -136,7 +136,8 @@
   "cli": {
     "schematicCollections": [
       "@ionic/angular-toolkit"
-    ]
+    ],
+    "analytics": "933a7f17-f45c-41cf-a139-ce17c6706c6e"
   },
   "schematics": {
     "@ionic/angular-toolkit:component": {

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 833 - 2
package-lock.json


+ 3 - 0
package.json

@@ -27,7 +27,9 @@
     "@capacitor/keyboard": "6.0.1",
     "@capacitor/status-bar": "6.0.0",
     "@ionic/angular": "^8.0.0",
+    "@types/parse": "^3.0.9",
     "ionicons": "^7.0.0",
+    "parse": "^5.2.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.14.2"
@@ -43,6 +45,7 @@
     "@angular/compiler-cli": "^18.0.0",
     "@angular/language-service": "^18.0.0",
     "@capacitor/cli": "6.1.0",
+    "@compodoc/compodoc": "^1.1.25",
     "@ionic/angular-toolkit": "^11.0.1",
     "@types/jasmine": "~5.1.0",
     "@typescript-eslint/eslint-plugin": "^6.0.0",

+ 14 - 1
src/app/app-routing.module.ts

@@ -5,7 +5,20 @@ const routes: Routes = [
   {
     path: '',
     loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
-  }
+  },
+  {
+    path: 'user',
+    loadChildren: () => import('../modules/user/user.module').then(m => m.UserModule)
+  },
+  {
+    path: 'user',
+    loadChildren: () => import('../modules/user/user.module').then(m => m.UserModule)
+  },
+  {
+    path: 'aigc',
+    loadChildren: () => import('../modules copy/aigc/aigc.module').then(m => m.AigcModule)
+  },
+  
 ];
 @NgModule({
   imports: [

+ 3 - 0
src/app/app.component.ts

@@ -1,4 +1,7 @@
 import { Component } from '@angular/core';
+import * as Parse from "parse";
+Parse.initialize("dev");
+(Parse as any).serverURL = 'http://web2023.fmode.cn:9999/parse'
 
 @Component({
   selector: 'app-root',

+ 222 - 47
src/app/tab1/tab1.page.html

@@ -1,55 +1,230 @@
-<!-- tab1.page.html -->
-
 <ion-header>
   <ion-toolbar>
-    <ion-title>
-      <ion-searchbar placeholder="搜索小说、作者或标签" class="larger-searchbar"></ion-searchbar>
-      <ion-button fill="clear" slot="end">
-        <ion-icon name="notifications-outline"></ion-icon>
+    <ion-buttons slot="start">
+      <ion-button (click)="goToRecommendedPage()">
+        返回
       </ion-button>
-    </ion-title>
+    </ion-buttons>
+
+    <ion-searchbar 
+      [(ngModel)]="searchTerm" 
+      (ionInput)="searchBooks($event)"
+      (click)="expandSearchBar()"
+      [class.expanded]="isSearchBarExpanded">
+    </ion-searchbar>
   </ion-toolbar>
 </ion-header>
 
 <ion-content>
-  <ion-segment mode="md"> <!-- 你可以根据需要选择合适的 mode -->
-    <ion-segment-button value="recommend">
-      <ion-label>推荐</ion-label>
-    </ion-segment-button>
-    <ion-segment-button value="ranking">
-      <ion-label>排行</ion-label>
-    </ion-segment-button>
-    <ion-segment-button value="categories">
-      <ion-label>分类</ion-label>
-    </ion-segment-button>
-  </ion-segment>
-
-  <ion-list lines="full" class="scrollable-content">
-    <ion-item *ngFor="let novel of novels">
-      <ion-thumbnail slot="start">
-        <img [src]="novel.cover" />
-      </ion-thumbnail>
-      <ion-label>
-        <h2>{{novel.title}}</h2>
-        <p>{{novel.author}}</p>
-        <p>{{novel.description}}</p>
-        <p>评分: {{novel.rating}}</p>
-      </ion-label>
-    </ion-item>
-  </ion-list>
-</ion-content>
+  <div *ngIf="!isSearchBarExpanded">
+    <ion-segment [(ngModel)]="selectedSegment" (ionChange)="segmentChanged()" mode="md" class="segment">
+      <ion-segment-button value="推荐">
+        推荐
+      </ion-segment-button>
+      <ion-segment-button value="经典">
+        经典
+      </ion-segment-button>
+      <ion-segment-button value="知识">
+        知识
+      </ion-segment-button>
+      <ion-segment-button value="听书">
+        听书
+      </ion-segment-button>
+      <ion-segment-button value="看剧">
+        看剧
+      </ion-segment-button>
+      <ion-segment-button value="视频">
+        视频
+      </ion-segment-button>
+      <ion-segment-button value="漫画">
+        漫画
+      </ion-segment-button>
+    </ion-segment>
+
+    <div *ngIf="selectedSegment === '推荐'">
+      <ion-card>
+        <ion-card-header>
+          <ion-card-title>排行榜</ion-card-title>
+          <ion-segment [(ngModel)]="rankingSegment" (ionChange)="rankingSegmentChanged()">
+            <ion-segment-button value="推荐榜">
+              推荐榜
+            </ion-segment-button>
+            <ion-segment-button value="完本榜">
+              完本榜
+            </ion-segment-button>
+            <ion-segment-button value="口碑榜">
+              口碑榜
+            </ion-segment-button>
+            <ion-segment-button value="巅峰榜">
+              巅峰榜
+            </ion-segment-button>
+            <ion-segment-button value="高分榜">
+              高分榜
+            </ion-segment-button>
+          </ion-segment>
+        </ion-card-header>
+
+        <ion-card-content>
+          <ion-list>
+            <ion-item *ngFor="let book of rankingBooks">
+              <ion-thumbnail slot="start">
+                <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+              </ion-thumbnail>
+              <ion-label>
+                <h2>{{ book.title }}</h2>
+                <p>{{ book.author }}</p>
+                <p>{{ book.popularity }} 热度</p>
+              </ion-label>
+            </ion-item>
+          </ion-list>
+        </ion-card-content>
+      </ion-card>
+
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of recommendedBooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
+
+    <div *ngIf="selectedSegment === '经典'">
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of classicBooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
 
-<style>
-  .scrollable-content {
-    overflow-y: auto;
-  }
-
-  .larger-searchbar {
-    --background: #f5f5f5;
-    --placeholder-color: #888;
-    --icon-color: #888;
-    --height: 44px;
-    --border-radius: 8px;
-    --box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-  }
-</style>
+    <div *ngIf="selectedSegment === '知识'">
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of knowledgeBooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
+
+    <div *ngIf="selectedSegment === '听书'">
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of audiobooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
+
+    <div *ngIf="selectedSegment === '看剧'">
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of dramaBooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
+
+    <div *ngIf="selectedSegment === '视频'">
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of videoBooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
+
+    <div *ngIf="selectedSegment === '漫画'">
+      <ion-card>
+        <ion-card-content>
+          <ion-grid>
+            <ion-row>
+              <ion-col size="6" *ngFor="let book of comicBooks">
+                <ion-card>
+                  <ion-img [src]="book.cover" [alt]="book.title"></ion-img>
+                  <ion-card-header>
+                    <ion-card-title>{{ book.title }}</ion-card-title>
+                  </ion-card-header>
+                </ion-card>
+              </ion-col>
+            </ion-row>
+          </ion-grid>
+        </ion-card-content>
+      </ion-card>
+    </div>
+  </div>
+
+  <div *ngIf="isSearchBarExpanded">
+    <ion-list>
+      <ion-item *ngFor="let book of filteredBooks">
+        <ion-thumbnail slot="start">
+          <ion-img [src]="book.cover"></ion-img>
+        </ion-thumbnail>
+        <ion-label>
+          <h2>{{ book.title }}</h2>
+          <p>{{ book.author }}</p>
+          <p>{{ book.popularity }}</p>
+        </ion-label>
+      </ion-item>
+    </ion-list>
+  </div>
+</ion-content>

+ 132 - 0
src/app/tab1/tab1.page.scss

@@ -0,0 +1,132 @@
+ion-header {
+    ion-toolbar {
+      ion-searchbar {
+        --background: #fff;
+        --border-radius: 10px;
+        margin: 10px;
+      }
+    }
+  }
+  
+  /*ion-segment {
+    margin: 10px;
+    --background: #fff;
+    --indicator-color: #f56c6c;
+    --indicator-height: 4px;
+  }*/
+  
+  ion-card {
+    margin: 10px;
+  
+    ion-card-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+  
+      ion-card-title {
+        font-size: 1.2em;
+        font-weight: bold;
+        margin: 0;
+      }
+    }
+  
+    ion-card-content {
+      ion-list {
+        ion-item {
+          --padding-start: 0;
+          --inner-padding-end: 0;
+  
+          ion-thumbnail {
+            width: 80px;
+            height: 80px;
+            margin-right: 10px;
+  
+            ion-img {
+              width: 100%;
+              height: auto;
+            }
+          }
+  
+          ion-label {
+            h2 {
+              font-size: 1.1em;
+              margin: 0;
+            }
+  
+            p {
+              font-size: 0.9em;
+              color: #666;
+              margin: 0;
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  ion-grid {
+    ion-row {
+      ion-col {
+        padding: 5px;
+  
+        ion-card {
+          ion-card-header {
+            padding: 10px 0;
+            ion-card-title {
+              font-size: 0.9em;
+              margin: 0;
+            }
+          }
+        }
+      }
+    }
+  }
+  .book-card {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  
+    ion-img {
+      width: 100%;
+      height: 200px; /* 或者根据需要设置图片的固定高度 */
+      object-fit: cover; /* 确保图片完整显示在容器内 */
+    }
+  
+    ion-card-header {
+      ion-card-title {
+        font-size: 0.9em;
+        margin: 0;
+      }
+    }
+  }
+  .segment {
+    display: flex;
+    justify-content: space-around; /* 在水平方向上均匀分布选项卡 */
+    align-items: center; /* 垂直居中选项卡 */
+    padding: 10px; /* 设置内边距 */
+  }
+  
+  ion-segment-button {
+    min-width: 60px; /* 设置最小宽度以确保每个选项卡的大小一致 */
+  }
+  ion-searchbar {
+    transition: all 0.3s ease-in-out;
+    max-width: 90%; // 初始状态下的最大宽度
+    margin: 0 auto; // 居中显示
+    display: block;
+  
+    &.expanded {
+      max-width: 85%; // 展开状态下的最大宽度
+      position: fixed;
+      top: 0;
+      left: 15;
+      right: 0;
+      z-index: 10;
+    }
+  }
+  
+  .search-results {
+    margin-top: 56px; // 调整为搜索栏高度
+  }
+  
+  

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 36 - 71
src/app/tab1/tab1.page.ts


+ 3 - 0
src/app/tab2/tab2.page.html

@@ -1,8 +1,11 @@
 <ion-header>
+  <ion-button expand="block" routerLink="/aigc/chat" class="ion-color-primary">Ai书籍推荐</ion-button>
   <ion-toolbar color="primary">
     <ion-title>
       我的书架
     </ion-title>
+  
+
     <ion-buttons slot="end">
       <ion-button (click)="changeCategory('全部')" [class.active]="currentCategory === '全部'">
         全部

+ 8 - 0
src/app/tab2/tab2.page.ts

@@ -32,4 +32,12 @@ export class Tab2Page {
     }
   }
 
+  openAiChat() {
+    // 在这里编写打开AI对话框或执行AI对话的逻辑
+    console.log('打开AI对话');
+    // 可以根据你的项目需求,调用相关的对话框组件或服务来实现与AI的交互
+    // 例如,你可以使用Ionic的ModalController来打开一个对话框
+    // 或者调用一个AI服务的方法来处理对话逻辑
+  }
+
 }

+ 7 - 7
src/app/tab3/tab3.page.html

@@ -10,14 +10,14 @@
     <ion-row>
       <ion-col>
         <ion-avatar>
-            <img src="https://via.placeholder.com/150" alt="Placeholder Image">
+            <img src="https://www.keaitupian.cn/cjpic/frombd/0/253/17551321/2476952379.jpg" alt="Placeholder Image">
 
         </ion-avatar>
       </ion-col>
       <ion-col>
-        <h2>用户名</h2>
-        <p>关注数</p >
-        <p>粉丝数</p >
+        <h2>用户名:</h2>
+        <p>关注数:</p >
+        <p>粉丝数:</p >
       </ion-col>
     </ion-row>
   </ion-grid>
@@ -27,13 +27,13 @@
     <ion-row>
       <ion-col>
         <h3>作家推荐:刘慈欣</h3>
-        <img src="https://via.placeholder.com/150" alt="Placeholder Image">
+        <img src="https://img2.jiemian.com/101/original/20160711/146820264092749000_a700x398.jpg" alt="Placeholder Image">
 
         <p>作家简介:刘慈欣是中国当代科幻小说的主要代表作家,被誉为中国科幻文学的领军人物。</p >
       </ion-col>
       <ion-col>
         <h3>精选好书:三体</h3>
-        <img src="https://via.placeholder.com/150" alt="Placeholder Image">
+        <img src="https://tse2-mm.cn.bing.net/th/id/OIP-C.TkVx9LbPKBzdM0nk22yAjwHaHa?rs=1&pid=ImgDetMain" alt="Placeholder Image">
 
         <p>书籍简介:作品讲述了地球人类文明和三体文明的信息交流、生死搏杀及两个文明在宇宙中的兴衰历程。</p >
       </ion-col>
@@ -48,7 +48,7 @@
         <ion-button>我的下载</ion-button>
       </ion-col>
       <ion-col>
-        <ion-button>设置中心</ion-button>
+        <ion-button (click)="goUrl()">设置中心</ion-button>
       </ion-col>
       <ion-col>
         <ion-button>创作中心</ion-button>

+ 6 - 2
src/app/tab3/tab3.page.ts

@@ -1,5 +1,5 @@
 import { Component, OnInit } from '@angular/core';
-
+import { Router } from '@angular/router';
 @Component({
   selector: 'app-tab3',
   templateUrl: 'tab3.page.html',
@@ -38,7 +38,11 @@ export class Tab3Page implements OnInit {
     // 更多互动
   ];
 
-  constructor() {}
+  constructor(private router: Router) {}
 
   ngOnInit() {}
+goUrl(){
+    console.log('6666')
+    this.router.navigate(['/user/mine'])
+}
 }

+ 12 - 0
src/modules copy/aigc/aigc-routing.module.ts

@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+  {path: 'chat', loadChildren: () => import('./chat/chat.module').then(mod => mod.ChatPageModule)},
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class AigcRoutingModule { }

+ 14 - 0
src/modules copy/aigc/aigc.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { AigcRoutingModule } from './aigc-routing.module';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    AigcRoutingModule
+  ]
+})
+export class AigcModule { }

+ 17 - 0
src/modules copy/aigc/chat/chat-routing.module.ts

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

+ 20 - 0
src/modules copy/aigc/chat/chat.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 { ChatPageRoutingModule } from './chat-routing.module';
+
+import { ChatPage } from './chat.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    ChatPageRoutingModule
+  ],
+  declarations: [ChatPage]
+})
+export class ChatPageModule {}

+ 24 - 0
src/modules copy/aigc/chat/chat.page.html

@@ -0,0 +1,24 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>
+      AIGC 消息发送
+    </ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-item>
+    <ion-input placeholder="输入消息" [(ngModel)]="userInput"></ion-input>
+  </ion-item>
+
+  <ion-button expand="block" (click)="sendMessage()">发送</ion-button>
+
+  <ion-card *ngFor="let message of messageList">
+    <ion-card-header>
+      {{message?.role}}
+    </ion-card-header>
+    <ion-card-content>
+      {{ message?.content }}
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 0 - 0
src/modules copy/aigc/chat/chat.page.scss


+ 17 - 0
src/modules copy/aigc/chat/chat.page.spec.ts

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

+ 31 - 0
src/modules copy/aigc/chat/chat.page.ts

@@ -0,0 +1,31 @@
+import { Component, OnInit } from '@angular/core';
+// 引用FmodeChatCompletion类
+import { TestChatCompletion, TestChatMessage } from './class-chat-completion';
+
+@Component({
+  selector: 'app-chat',
+  templateUrl: './chat.page.html',
+  styleUrls: ['./chat.page.scss'],
+})
+export class ChatPage implements OnInit {
+  messageList:Array<TestChatMessage> = []
+  userInput:string = ""
+
+  completion:TestChatCompletion
+  constructor() { 
+    this.completion = new TestChatCompletion(this.messageList)
+  }
+
+  ngOnInit() {
+  }
+  sendMessage(){
+    this.messageList.push({
+      role:"user",
+      content: this.userInput
+    })
+    this.userInput = ""
+    this.completion.createCompletionByStream()
+
+  }
+
+}

+ 99 - 0
src/modules copy/aigc/chat/class-chat-completion.ts

@@ -0,0 +1,99 @@
+export interface TestChatMessage{
+    role:string
+    content:string
+}
+export class TestChatCompletion{
+messageList:Array<TestChatMessage>
+constructor(messageList:Array<TestChatMessage>){
+    this.messageList = messageList
+}
+async createCompletionByStream() {
+
+let token = localStorage.getItem("token");
+let bodyJson = {
+  "token": `Bearer ${token}`,
+  "messages": this.messageList,
+  "model": "gpt-3.5-turbo",
+  "temperature": 0.5,
+  "presence_penalty": 0,
+  "frequency_penalty": 0,
+  "top_p": 1,
+  "stream":true
+};
+
+let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+  "headers": {
+    "accept": "text/event-stream",
+    "sec-fetch-dest": "empty",
+    "sec-fetch-mode": "cors",
+    "sec-fetch-site": "same-site"
+  },
+  "referrer": "https://ai.fmode.cn/",
+  "referrerPolicy": "strict-origin-when-cross-origin",
+  "body": JSON.stringify(bodyJson),
+  "method": "POST",
+  "mode": "cors",
+  "credentials": "omit"
+});
+
+let messageAiReply = ""
+let messageIndex = this.messageList.length
+let reader = response.body?.getReader();
+if (!reader) {
+  throw new Error("Failed to get the response reader.");
+}
+
+let decoder = new TextDecoder();
+let buffer = "";
+
+while (true) {
+  let { done, value } = await reader.read();
+  if (done) {
+    break;
+  }
+
+  buffer += decoder.decode(value);
+
+  // Split the buffer by newlines to get individual messages
+  let messages = buffer.split("\n");
+
+  // Process each message
+  for (let i = 0; i < messages.length - 1; i++) {
+    let message = messages[i];
+
+    // Process the message as needed
+    /**
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"gpt-3.5-turbo-0613","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
+     * data: [DONE]
+     */
+    let dataText = message.replace("data:\ ","")
+    if(dataText.startsWith("{")){
+      try{
+        let dataJson = JSON.parse(dataText)
+        console.log(dataJson)
+        messageAiReply += dataJson?.choices?.[0]?.delta?.content || ""
+        this.messageList[messageIndex] = {
+          role:"assistant",
+          content:messageAiReply
+        }
+      }catch(err){}
+    }
+    if(dataText.startsWith("[")){
+      console.log(message)
+      console.log("完成")
+      this.messageList[messageIndex] = {
+        role:"assistant",
+        content:messageAiReply
+      }
+      messageAiReply = ""
+    }
+    // Parse the message as JSON
+    // let data = JSON.parse(message);
+
+    // Clear the processed message from the buffer
+    buffer = buffer.slice(message.length + 1);
+  }
+}
+}
+}

+ 17 - 0
src/modules copy/contact/contact-detail/contact-detail-routing.module.ts

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

+ 20 - 0
src/modules copy/contact/contact-detail/contact-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 { ContactDetailPageRoutingModule } from './contact-detail-routing.module';
+
+import { ContactDetailPage } from './contact-detail.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    ContactDetailPageRoutingModule
+  ],
+  declarations: [ContactDetailPage]
+})
+export class ContactDetailPageModule {}

+ 13 - 0
src/modules copy/contact/contact-detail/contact-detail.page.html

@@ -0,0 +1,13 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>contact-detail</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">contact-detail</ion-title>
+    </ion-toolbar>
+  </ion-header>
+</ion-content>

+ 0 - 0
src/modules copy/contact/contact-detail/contact-detail.page.scss


+ 17 - 0
src/modules copy/contact/contact-detail/contact-detail.page.spec.ts

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

+ 15 - 0
src/modules copy/contact/contact-detail/contact-detail.page.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-contact-detail',
+  templateUrl: './contact-detail.page.html',
+  styleUrls: ['./contact-detail.page.scss'],
+})
+export class ContactDetailPage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 17 - 0
src/modules copy/contact/contact-list/contact-list-routing.module.ts

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

+ 20 - 0
src/modules copy/contact/contact-list/contact-list.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 { ContactListPageRoutingModule } from './contact-list-routing.module';
+
+import { ContactListPage } from './contact-list.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    ContactListPageRoutingModule
+  ],
+  declarations: [ContactListPage]
+})
+export class ContactListPageModule {}

+ 34 - 0
src/modules copy/contact/contact-list/contact-list.page.html

@@ -0,0 +1,34 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>通讯录</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">通讯录</ion-title>
+    </ion-toolbar>
+  </ion-header>
+  
+  <ion-searchbar [(ngModel)]="searchName" (ionInput)="search()"></ion-searchbar>
+
+  <ion-list>
+    <ng-container *ngFor="let contact of contactList;let index = index;">
+      <!-- 分组:根据下标首个出现的元素显示分组分隔符 -->
+      <ion-item-divider *ngIf="charGroupIndex[contact.get('firstChar')] == index">
+        <ion-label>{{contact.get('firstChar')}}</ion-label>
+      </ion-item-divider>
+      <ion-item lines="none">
+        <ion-avatar slot="start">
+          <img [src]="contact.get('avatarUrl') || 'https://ionicframework.com/docs/img/demos/avatar.svg'">
+        </ion-avatar>
+        <ion-label>
+          <h2>{{ contact.get('name') }}</h2>
+          <p>性别: {{ contact.get('gender') }}</p>
+          <p>手机: {{ contact.get('mobile') }}</p>
+        </ion-label>
+      </ion-item>
+    </ng-container>
+  </ion-list>
+</ion-content>

+ 0 - 0
src/modules copy/contact/contact-list/contact-list.page.scss


+ 17 - 0
src/modules copy/contact/contact-list/contact-list.page.spec.ts

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

+ 42 - 0
src/modules copy/contact/contact-list/contact-list.page.ts

@@ -0,0 +1,42 @@
+import { Component, OnInit } from '@angular/core';
+import * as Parse from "parse";
+@Component({
+  selector: 'app-contact-list',
+  templateUrl: './contact-list.page.html',
+  styleUrls: ['./contact-list.page.scss'],
+})
+export class ContactListPage implements OnInit {
+  searchName: string = '';
+  contactList: Array<Parse.Object> = [];
+
+  ngOnInit() {
+    this.loadContact();
+  }
+
+  charGroupIndex:any = {}
+  loadContact() {
+    const Contact = Parse.Object.extend('Contact');
+    const query = new Parse.Query(Contact);
+    query.ascending('firstChar');
+
+    if (this.searchName) {
+      query.contains('name', this.searchName);
+    }
+
+    query.find().then((results) => {
+      this.contactList = results;
+      this.contactList.forEach((contact,index)=>{
+        if(this.charGroupIndex[contact.get("firstChar")] == undefined){
+          this.charGroupIndex[contact.get("firstChar")] = index
+        }
+      })
+    }, (error) => {
+      console.error('Error while fetching contacts', error);
+    });
+  }
+
+  search() {
+    this.loadContact();
+  }
+
+}

+ 12 - 0
src/modules copy/contact/contact-routing.module.ts

@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+  {path: 'list', loadChildren: () => import('./contact-list/contact-list.module').then(mod => mod.ContactListPageModule)},
+  {path: 'detail/:id', loadChildren: () => import('./contact-detail/contact-detail.module').then(mod => mod.ContactDetailPageModule)},
+];
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class ContactRoutingModule { }

+ 14 - 0
src/modules copy/contact/contact.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { ContactRoutingModule } from './contact-routing.module';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    ContactRoutingModule
+  ]
+})
+export class ContactModule { }

+ 17 - 0
src/modules/user/edit-info/edit-info-routing.module.ts

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

+ 20 - 0
src/modules/user/edit-info/edit-info.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 { EditInfoPageRoutingModule } from './edit-info-routing.module';
+
+import { EditInfoPage } from './edit-info.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    EditInfoPageRoutingModule
+  ],
+  declarations: [EditInfoPage]
+})
+export class EditInfoPageModule {}

+ 47 - 0
src/modules/user/edit-info/edit-info.page.html

@@ -0,0 +1,47 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>资料编辑</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">资料编辑</ion-title>
+    </ion-toolbar>
+  </ion-header>
+
+  <ion-card>
+    <ion-card-header>
+      <ion-card-title>{{currentUser?.get('username')}} - {{currentUser?.id}}</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <ion-list>
+        <ion-item>
+          <ion-input label="姓名" type="text" [(ngModel)]="userInfo.name"></ion-input>
+        </ion-item>
+        <ion-item>
+          <ion-input label="手机" type="tel" [(ngModel)]="userInfo.mobile"></ion-input>
+        </ion-item>
+        <ion-item>
+          <ion-select label="性别" [(ngModel)]="userInfo.gender">
+            <ion-select-option value="男">男</ion-select-option>
+            <ion-select-option value="女">女</ion-select-option>
+          </ion-select>
+        </ion-item>
+        <ion-item>
+          <ion-label>生日</ion-label>
+          <ion-datetime-button datetime="birthday"></ion-datetime-button>
+          <ion-modal [keepContentsMounted]="true">
+            <ng-template>
+              <ion-datetime id="birthday" displayFormat="MM/DD/YYYY" [(ngModel)]="userInfo.birthday"></ion-datetime>
+            </ng-template>
+          </ion-modal>
+        </ion-item>
+      </ion-list>
+    </ion-card-content>
+  </ion-card>
+
+  <ion-button expand="block" (click)="save()">保存</ion-button>
+  <ion-button expand="block" (click)="cancel()">取消</ion-button>
+</ion-content>

+ 0 - 0
src/modules/user/edit-info/edit-info.page.scss


+ 17 - 0
src/modules/user/edit-info/edit-info.page.spec.ts

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

+ 56 - 0
src/modules/user/edit-info/edit-info.page.ts

@@ -0,0 +1,56 @@
+import { Component, OnInit } from '@angular/core';
+import { NavController } from '@ionic/angular';
+import * as Parse from 'parse';
+
+@Component({
+  selector: 'app-edit-info',
+  templateUrl: './edit-info.page.html',
+  styleUrls: ['./edit-info.page.scss'],
+})
+export class EditInfoPage implements OnInit {
+
+  userInfo: any = {
+    name: '',
+    mobile: '',
+    gender: '',
+    birthday: ''
+  };
+  currentUser:Parse.User|undefined
+  constructor(private navController: NavController) {}
+
+  ngOnInit() {
+    this.currentUser = Parse.User.current();
+    if (this.currentUser) {
+      // 修改uesrInfo赋值逻辑,仅加载被编辑的字段属性值
+      let json = this.currentUser.toJSON();
+      for (const key in json) {
+        if (this.userInfo.hasOwnProperty(key)) {
+          this.userInfo[key] = json[key]
+        }
+      }
+    }
+    console.log(this.userInfo)
+  }
+
+  save() {
+    this.currentUser = Parse.User.current();
+    if (this.currentUser) {
+      console.log(this.userInfo)
+      for (const key in this.userInfo) {
+        if (this.userInfo.hasOwnProperty(key)) {
+          this.currentUser.set(key, this.userInfo[key]);
+        }
+      }
+      this.currentUser.save().then(() => {
+        this.navController.back();
+      }).catch((error) => {
+        console.error('Error saving user data: ', error);
+      });
+    }
+  }
+
+  cancel() {
+    this.navController.back();
+  }
+
+}

+ 17 - 0
src/modules/user/login/login-routing.module.ts

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

+ 20 - 0
src/modules/user/login/login.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 { LoginPageRoutingModule } from './login-routing.module';
+
+import { LoginPage } from './login.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    LoginPageRoutingModule
+  ],
+  declarations: [LoginPage]
+})
+export class LoginPageModule {}

+ 38 - 0
src/modules/user/login/login.page.html

@@ -0,0 +1,38 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>登录/注册</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">登录/注册</ion-title>
+    </ion-toolbar>
+  </ion-header>
+
+  <ion-card>
+    <ion-card-header>
+      <ion-card-title>登录/注册</ion-card-title>
+    </ion-card-header>
+  
+    <ion-card-content>
+
+      <ion-list [inset]="true">
+        <ion-item>
+          <ion-input [(ngModel)]="username" label="账号" placeholder="请输入用户名"></ion-input>
+        </ion-item>
+        <ion-item>
+          <ion-input [(ngModel)]="password" label="密码" type="password" placeholder="请输入密码"></ion-input>
+        </ion-item>
+      </ion-list>
+     
+    </ion-card-content>
+  
+    <ion-button (click)="login()" fill="clear">登录</ion-button>
+    <ion-button (click)="register()" fill="clear">注册</ion-button>
+  </ion-card>
+
+  <!-- 新增路由返回逻辑,执行back函数 -->
+  <ion-button expand="block" (click)="back()">返回</ion-button>
+</ion-content>

+ 0 - 0
src/modules/user/login/login.page.scss


+ 17 - 0
src/modules/user/login/login.page.spec.ts

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

+ 93 - 0
src/modules/user/login/login.page.ts

@@ -0,0 +1,93 @@
+import { Component, OnInit } from '@angular/core';
+import { AlertController, NavController } from '@ionic/angular';
+import * as Parse from "parse"
+// 引用Router服务
+@Component({
+  selector: 'app-login',
+  templateUrl: './login.page.html',
+  styleUrls: ['./login.page.scss'],
+})
+export class LoginPage implements OnInit {
+
+  username:string = ""
+  password:string = ""
+  constructor(
+    // 新增:Router服务,用于路由跳转
+    private navCtrl:NavController,
+    private alertController:AlertController
+  ) { }
+
+  ngOnInit() {
+  }
+
+  async login(){
+    let user
+    try {
+      user = await Parse.User.logIn(this.username,this.password)
+    } catch (error:any) {
+      let message:string = ""
+      // 新增提示词详情,根据Parse.User.login方法返回的不同英文提示词,增加对应的中文内容转换
+      if(error?.message.indexOf("is required")>-1){
+        message = "必须输入账号或邮箱"
+      }
+      if(error?.message.indexOf("Invalid username")>-1){
+        message = "账号或密码错误,请检查"
+      }
+      this.presentAlert({
+        header:"登录失败",
+        subHeader:"状态码:"+error.code,
+        message:message || error.message
+      })
+    }
+    console.log(user)
+    if(user?.id){
+      this.navCtrl.back()
+    }
+  }
+  async register(){
+    let user = new Parse.User()
+    user.set("username",this.username)
+    user.set("password",this.password)
+    try {
+        let result = await user.signUp();
+        console.log(result)
+        if(result?.id){
+          this.navCtrl.back()
+        }
+        // Hooray! Let them use the app now.
+    } catch (error:any) {
+        // 新增提示词详情,根据Parse.User.signUp方法返回的不同英文提示词,增加对应的中文内容转换
+        let message:string = ""
+        if(error?.message.indexOf("already exists")>-1){
+          message = "该账号已存在请修改后重试"
+        }
+        if(error?.message.indexOf("empty")>-1){
+          message = "账号不能为空请输入后重试"
+        }
+        this.presentAlert({
+          header:"注册失败",
+          subHeader:"状态码:"+error.code,
+          message:message || error.message
+        })
+    }
+  }
+
+  async presentAlert(options:{header:string,subHeader:string,message:string}) {
+    const alert = await this.alertController.create({
+      header: options?.header,
+      subHeader: options?.subHeader,
+      message: options?.message,
+      buttons: ['好的'],
+    });
+
+    await alert.present();
+  }
+
+  /**
+   * 返回上级页面函数
+   * @desc
+   */
+  back(){
+    this.navCtrl.back()
+  }
+}

+ 17 - 0
src/modules/user/mine/mine-routing.module.ts

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

+ 20 - 0
src/modules/user/mine/mine.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 { MinePageRoutingModule } from './mine-routing.module';
+
+import { MinePage } from './mine.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    MinePageRoutingModule
+  ],
+  declarations: [MinePage]
+})
+export class MinePageModule {}

+ 29 - 0
src/modules/user/mine/mine.page.html

@@ -0,0 +1,29 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>我的</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">我的</ion-title>
+    </ion-toolbar>
+  </ion-header>
+
+  <ion-card>
+    <img alt="" src="https://ts1.cn.mm.bing.net/th/id/R-C.6b5df1bfe0e4778a44dba0753cd169c8?rik=QRQIMqvjWRCO5Q&riu=http%3a%2f%2fpic39.nipic.com%2f20140321%2f8857347_232251363165_2.jpg&ehk=7oAaMo6LCHJc%2bqpQ0IPvcH7v69jGRQhb2vDz%2fOd5720%3d&risl=&pid=ImgRaw&r=0" />
+    <ion-card-header>
+      <ion-card-title>{{user?.get("username") || '未登录'}}</ion-card-title>
+      <ion-card-subtitle *ngIf="!user?.id">请您登陆后继续使用</ion-card-subtitle>
+      <ion-card-subtitle *ngIf="user?.id">{{user?.get("name")}}-{{user?.get("gender")}}</ion-card-subtitle>
+    </ion-card-header>
+ 
+    <!-- 新增:根据用户状态,显示登录/登出按钮,执行跳转或登出函数 -->
+    <ion-button *ngIf="!user?.id" fill="clear" routerLink="/user/login">登录</ion-button>
+    <ion-button *ngIf="user?.id" fill="clear" routerLink="/user/edit/info">编辑资料</ion-button>
+    <ion-button *ngIf="user?.id" fill="clear" (click)="logout()">登出</ion-button>
+  </ion-card>
+
+
+</ion-content>

+ 0 - 0
src/modules/user/mine/mine.page.scss


+ 17 - 0
src/modules/user/mine/mine.page.spec.ts

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

+ 35 - 0
src/modules/user/mine/mine.page.ts

@@ -0,0 +1,35 @@
+import { Component, OnInit } from '@angular/core';
+// 由于Parse本身是js库,在ts中加载需要通过 * as Parse转换一下
+import * as Parse from "parse"
+@Component({
+  selector: 'app-mine',
+  templateUrl: './mine.page.html',
+  styleUrls: ['./mine.page.scss'],
+})
+export class MinePage implements OnInit {
+
+  constructor() {
+   
+  }
+
+  // 由于Parse.User.current()是随着localStorage变化的属性
+  // 为了避免首次复制后用户状态变化,页面不同步,通过get方法实现实时获取
+  user:Parse.User|undefined
+  /**计时器 */
+interval:any
+  async ngOnInit() {
+      this.user = await Parse.User.current()
+     this.interval =  setInterval(async ()=>{
+      this.user = await Parse.User.current()
+      console.log('666666')
+      console.log(this.user)
+      if(this.user?.id){
+        clearInterval(this.interval)
+      }
+    },1000)
+  }
+  logout(){
+    Parse.User.logOut();
+  }
+
+}

+ 14 - 0
src/modules/user/user-routing.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+    {path: 'login', loadChildren: () => import('./login/login.module').then(mod => mod.LoginPageModule)},
+    {path: 'mine', loadChildren: () => import('./mine/mine.module').then(mod => mod.MinePageModule)},
+    {path: 'edit/info', loadChildren: () => import('./edit-info/edit-info.module').then(mod => mod.EditInfoPageModule)},
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class UserRoutingModule { }

+ 14 - 0
src/modules/user/user.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { UserRoutingModule } from './user-routing.module';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    UserRoutingModule
+  ]
+})
+export class UserModule { }

+ 3 - 0
tsconfig.doc.json

@@ -0,0 +1,3 @@
+{
+    "include": ["src/**/*.ts"]
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä