flowaaa 1 yıl önce
ebeveyn
işleme
2885f1a158
85 değiştirilmiş dosya ile 3474 ekleme ve 172 silme
  1. 4 0
      app-angular/.gitignore
  2. 1 1
      app-angular/README.md
  3. 48 2
      app-angular/angular.json
  4. 12 0
      app-angular/capacitor.config.ts
  5. 5 0
      app-angular/ionic.config.json
  6. 687 41
      app-angular/package-lock.json
  7. 14 5
      app-angular/package.json
  8. 14 0
      app-angular/resources/xml/network_security_config.xml
  9. 15 2
      app-angular/src/app/app-routing.module.ts
  10. 0 13
      app-angular/src/app/app.component.html
  11. 6 42
      app-angular/src/app/app.component.scss
  12. 1 16
      app-angular/src/app/app.component.ts
  13. 7 0
      app-angular/src/app/app.module.ts
  14. 80 0
      app-angular/src/modules/lesson/attention-detail/attention-detail.component.html
  15. 19 0
      app-angular/src/modules/lesson/attention-detail/attention-detail.component.scss
  16. 21 0
      app-angular/src/modules/lesson/attention-detail/attention-detail.component.spec.ts
  17. 42 0
      app-angular/src/modules/lesson/attention-detail/attention-detail.component.ts
  18. 19 0
      app-angular/src/modules/lesson/community/community-routing.module.ts
  19. 120 0
      app-angular/src/modules/lesson/community/community.component.html
  20. 28 0
      app-angular/src/modules/lesson/community/community.component.scss
  21. 21 0
      app-angular/src/modules/lesson/community/community.component.spec.ts
  22. 81 0
      app-angular/src/modules/lesson/community/community.component.ts
  23. 26 0
      app-angular/src/modules/lesson/community/community.module.ts
  24. 27 25
      app-angular/src/modules/lesson/lesson-routing.module.ts
  25. 28 23
      app-angular/src/modules/lesson/lesson.module.ts
  26. 187 0
      app-angular/src/modules/lesson/me/me.component.html
  27. 57 0
      app-angular/src/modules/lesson/me/me.component.scss
  28. 21 0
      app-angular/src/modules/lesson/me/me.component.spec.ts
  29. 71 0
      app-angular/src/modules/lesson/me/me.component.ts
  30. 60 0
      app-angular/src/modules/lesson/near/near.component.html
  31. 17 0
      app-angular/src/modules/lesson/near/near.component.scss
  32. 21 0
      app-angular/src/modules/lesson/near/near.component.spec.ts
  33. 11 0
      app-angular/src/modules/lesson/near/near.component.ts
  34. 3 1
      app-angular/src/modules/lesson/page-mine/nav-tabs/nav-tabs.component.html
  35. 95 0
      app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.html
  36. 31 0
      app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.scss
  37. 21 0
      app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.spec.ts
  38. 50 0
      app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.ts
  39. 91 0
      app-angular/src/modules/lesson/science-detail/science-detail.component.html
  40. 19 0
      app-angular/src/modules/lesson/science-detail/science-detail.component.scss
  41. 21 0
      app-angular/src/modules/lesson/science-detail/science-detail.component.spec.ts
  42. 49 0
      app-angular/src/modules/lesson/science-detail/science-detail.component.ts
  43. 150 0
      app-angular/src/modules/lesson/share/share.component.html
  44. 14 0
      app-angular/src/modules/lesson/share/share.component.scss
  45. 21 0
      app-angular/src/modules/lesson/share/share.component.spec.ts
  46. 10 0
      app-angular/src/modules/lesson/share/share.component.ts
  47. 83 0
      app-angular/src/modules/lesson/they-detail/they-detail.component.html
  48. 25 0
      app-angular/src/modules/lesson/they-detail/they-detail.component.scss
  49. 21 0
      app-angular/src/modules/lesson/they-detail/they-detail.component.spec.ts
  50. 39 0
      app-angular/src/modules/lesson/they-detail/they-detail.component.ts
  51. 64 0
      app-angular/src/modules/lesson/they/they.component.html
  52. 46 0
      app-angular/src/modules/lesson/they/they.component.scss
  53. 21 0
      app-angular/src/modules/lesson/they/they.component.spec.ts
  54. 61 0
      app-angular/src/modules/lesson/they/they.component.ts
  55. 38 0
      app-angular/src/modules/lesson/user-collection/user-collection.component.html
  56. 9 0
      app-angular/src/modules/lesson/user-collection/user-collection.component.scss
  57. 21 0
      app-angular/src/modules/lesson/user-collection/user-collection.component.spec.ts
  58. 10 0
      app-angular/src/modules/lesson/user-collection/user-collection.component.ts
  59. 56 0
      app-angular/src/modules/lesson/user-follow/user-follow.component.html
  60. 31 0
      app-angular/src/modules/lesson/user-follow/user-follow.component.scss
  61. 21 0
      app-angular/src/modules/lesson/user-follow/user-follow.component.spec.ts
  62. 10 0
      app-angular/src/modules/lesson/user-follow/user-follow.component.ts
  63. 62 0
      app-angular/src/modules/lesson/user-tag/user-tag.component.html
  64. 18 0
      app-angular/src/modules/lesson/user-tag/user-tag.component.scss
  65. 21 0
      app-angular/src/modules/lesson/user-tag/user-tag.component.spec.ts
  66. 10 0
      app-angular/src/modules/lesson/user-tag/user-tag.component.ts
  67. 17 0
      app-angular/src/modules/user/guard-auth/auth.guard.spec.ts
  68. 20 0
      app-angular/src/modules/user/guard-auth/auth.guard.ts
  69. 31 0
      app-angular/src/modules/user/page-info/page-info.component.html
  70. 10 0
      app-angular/src/modules/user/page-info/page-info.component.scss
  71. 21 0
      app-angular/src/modules/user/page-info/page-info.component.spec.ts
  72. 35 0
      app-angular/src/modules/user/page-info/page-info.component.ts
  73. 55 0
      app-angular/src/modules/user/page-login/page-login.component.html
  74. 21 0
      app-angular/src/modules/user/page-login/page-login.component.scss
  75. 21 0
      app-angular/src/modules/user/page-login/page-login.component.spec.ts
  76. 56 0
      app-angular/src/modules/user/page-login/page-login.component.ts
  77. 35 0
      app-angular/src/modules/user/page-register/page-register.component.html
  78. 3 0
      app-angular/src/modules/user/page-register/page-register.component.scss
  79. 21 0
      app-angular/src/modules/user/page-register/page-register.component.spec.ts
  80. 20 0
      app-angular/src/modules/user/page-register/page-register.component.ts
  81. 16 0
      app-angular/src/modules/user/service-user/user.service.spec.ts
  82. 32 0
      app-angular/src/modules/user/service-user/user.service.ts
  83. 21 0
      app-angular/src/modules/user/user-routing.module.ts
  84. 25 0
      app-angular/src/modules/user/user.module.ts
  85. 1 1
      docs/product.md

+ 4 - 0
app-angular/.gitignore

@@ -1,5 +1,9 @@
 # See http://help.github.com/ignore-files/ for more about ignoring files.
 
+
+/www
+/androidionic cap run android --project=app-angular
+
 # Compiled output
 /dist
 /tmp

+ 1 - 1
app-angular/README.md

@@ -1,6 +1,6 @@
 # AppAngular
 
-This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.2.3.
+This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 16.2.2.
 
 ## Development server
 

+ 48 - 2
app-angular/angular.json

@@ -17,7 +17,7 @@
         "build": {
           "builder": "@angular-devkit/build-angular:browser",
           "options": {
-            "outputPath": "dist/app-angular",
+            "outputPath": "www",
             "index": "src/index.html",
             "main": "src/main.ts",
             "polyfills": [
@@ -28,6 +28,11 @@
             "assets": [
               "src/favicon.ico",
               "src/assets",
+              {
+                "glob": "**/*.svg",
+                "input": "node_modules/ionicons/dist/ionicons/svg",
+                "output": "./svg"
+              },
               {
                 "glob": "**/*.svg",
                 "input": "node_modules/ionicons/dist/ionicons/svg",
@@ -66,6 +71,39 @@
               {
                 "input": "node_modules/@ionic/angular/css/flex-utils.css"
               },
+              {
+                "input": "src/theme/variables.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/core.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/normalize.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/structure.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/typography.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/display.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/padding.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/float-elements.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/text-alignment.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/text-transformation.css"
+              },
+              {
+                "input": "node_modules/@ionic/angular/css/flex-utils.css"
+              },
               {
                 "input": "src/theme/variables.css"
               }
@@ -77,7 +115,7 @@
               "budgets": [
                 {
                   "type": "initial",
-                  "maximumWarning": "500kb",
+                  "maximumWarning": "900kb",
                   "maximumError": "1mb"
                 },
                 {
@@ -129,6 +167,11 @@
             "assets": [
               "src/favicon.ico",
               "src/assets",
+              {
+                "glob": "**/*.svg",
+                "input": "node_modules/ionicons/dist/ionicons/svg",
+                "output": "./svg"
+              },
               {
                 "glob": "**/*.svg",
                 "input": "node_modules/ionicons/dist/ionicons/svg",
@@ -167,5 +210,8 @@
         }
       }
     }
+  },
+  "cli": {
+    "analytics": "bc2f0891-ea37-49cd-809c-9ae3fc6e37cf"
   }
 }

+ 12 - 0
app-angular/capacitor.config.ts

@@ -0,0 +1,12 @@
+import { CapacitorConfig } from '@capacitor/cli';
+
+const config: CapacitorConfig = {
+  appId: 'com.jxufe.ycc',
+  appName: 'FavorPet',
+  webDir: 'www',
+  server: {
+    androidScheme: 'https'
+  }
+};
+
+export default config;

+ 5 - 0
app-angular/ionic.config.json

@@ -0,0 +1,5 @@
+{
+  "name": "FavorPet",
+  "integrations": {},
+  "type": "angular"
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 687 - 41
app-angular/package-lock.json


+ 14 - 5
app-angular/package.json

@@ -18,23 +18,32 @@
     "@angular/platform-browser": "^16.2.0",
     "@angular/platform-browser-dynamic": "^16.2.0",
     "@angular/router": "^16.2.0",
+    "@capacitor/android": "^5.5.1",
+    "@capacitor/app": "5.0.6",
+    "@capacitor/core": "5.5.1",
+    "@capacitor/haptics": "5.0.6",
+    "@capacitor/keyboard": "5.0.6",
+    "@capacitor/status-bar": "5.0.6",
     "@ionic/angular": "^7.5.0",
+    "parse": "^4.3.1",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.13.0"
   },
   "devDependencies": {
-    "@angular-devkit/build-angular": "^16.2.3",
-    "@angular/cli": "~16.2.3",
+    "@angular-devkit/build-angular": "^16.2.2",
+    "@angular/cli": "~16.2.2",
     "@angular/compiler-cli": "^16.2.0",
+    "@capacitor/cli": "5.5.1",
+    "@ionic/angular-toolkit": "latest",
     "@types/jasmine": "~4.3.0",
+    "@types/parse": "^3.0.9",
     "jasmine-core": "~4.6.0",
     "karma": "~6.4.0",
     "karma-chrome-launcher": "~3.2.0",
     "karma-coverage": "~2.2.0",
     "karma-jasmine": "~5.1.0",
     "karma-jasmine-html-reporter": "~2.1.0",
-    "typescript": "~5.1.3",
-    "@ionic/angular-toolkit": "latest"
+    "typescript": "~5.1.3"
   }
-}
+}

+ 14 - 0
app-angular/resources/xml/network_security_config.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">nova-cloud.obs.cn-south-1.myhuaweicloud.com</domain>
+        <domain includeSubdomains="true">localhost</domain>
+        <domain includeSubdomains="true">*.fmode.cn</domain>
+        <domain includeSubdomains="true">fmode.cn</domain>
+        <domain includeSubdomains="true">server.fmode.cn</domain>
+        <domain includeSubdomains="true">upload-z2.qiniup.com</domain>
+        <domain includeSubdomains="true">*.qiniup.com</domain>
+        <domain includeSubdomains="true">webapi.amap.com</domain>
+        <domain includeSubdomains="true">*.amap.com</domain>
+    </domain-config>
+</network-security-config>

+ 15 - 2
app-angular/src/app/app-routing.module.ts

@@ -2,9 +2,13 @@ import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
 
 const routes: Routes = [
+
+  {
+    path: "", redirectTo: "/lesson/community", pathMatch: "full"
+  },
   {
-    path: 'lesson',
-    loadChildren: () => import('../modules/lesson/lesson.module').then(m => m.LessonModule)
+    path: 'user',
+    loadChildren: () => import('../modules/user/user.module').then(m => m.UserModule)
   }
 ];
 
@@ -13,3 +17,12 @@ const routes: Routes = [
   exports: [RouterModule]
 })
 export class AppRoutingModule { }
+
+let lessonRoute = {
+
+  path: 'lesson',
+  loadChildren: () => import('../modules/lesson/lesson.module').then(m => m.LessonModule)
+
+}
+
+routes.push(lessonRoute)

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 13
app-angular/src/app/app.component.html


+ 6 - 42
app-angular/src/app/app.component.scss

@@ -1,44 +1,8 @@
+ion-tabs {
+    pointer-events: none;
 
-.bottom-navigation {
-  display: flex;
-  justify-content: space-evenly;
-  padding: 10px;
-  background-color: #f5f5f5;
-  position: fixed;
-  bottom: 0px;
-  left:0px;
-  width: 100vw;
-
-  .tab-button {
-    button {
-      border:none;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: center;
-      background: none;
-      color: #888;
-
-      svg {
-        width: 2em;height: 2em;
-        // width: 24px;
-        // height: 24px;
-        margin-bottom: 5px;
-      }
-      img {
-        width: 24px;
-        height: 24px;
-        margin-bottom: 5px;
-      }
-
-      span {
-        font-size: 12px;
-      }
-    }
-
-    .active {
-      color: #000;
-      font-weight: bold;
-    }
-  }
 }
+
+ion-tab-button {
+    pointer-events: all;
+}

+ 1 - 16
app-angular/src/app/app.component.ts

@@ -1,5 +1,4 @@
 import { Component } from '@angular/core';
-import { ActivatedRoute, Router } from '@angular/router';
 
 @Component({
   selector: 'app-root',
@@ -7,19 +6,5 @@ import { ActivatedRoute, Router } from '@angular/router';
   styleUrls: ['./app.component.scss']
 })
 export class AppComponent {
-  title = '第一个项目app-angular';
-  onClick(){
-    alert("我被点击了")
-  }
-  path = ""
-  constructor(private route:ActivatedRoute,private router:Router){
-    this.route.queryParams.subscribe(params=>{
-      this.path = location.pathname;
-    })
-  }
-  // 
-  goTab(path:string){
-    this.path = path;
-    this.router.navigate([path])
-  }
+  title = 'app-angular';
 }

+ 7 - 0
app-angular/src/app/app.module.ts

@@ -1,17 +1,24 @@
 import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
 import { BrowserModule } from '@angular/platform-browser';
 
 import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
 import { IonicModule } from '@ionic/angular';
 
+import * as Parse from "parse"
+(Parse as any).serverURL = "http://web2023.fmode.cn:9999/parse"
+Parse.initialize("dev")
+
 @NgModule({
   declarations: [
     AppComponent,
+
   ],
   imports: [
     BrowserModule,
     AppRoutingModule,
+    FormsModule,
     IonicModule.forRoot()
   ],
   providers: [],

+ 80 - 0
app-angular/src/modules/lesson/attention-detail/attention-detail.component.html

@@ -0,0 +1,80 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/community" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>返回</ion-button>
+        </ion-buttons>
+        <ion-buttons slot="end">
+            <ion-button fill="clear" color="dark">
+                收藏</ion-button>
+        </ion-buttons>
+
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <ion-card>
+        <img alt="角色图" [src]="attention?.get('img')" />
+        <ion-card-header>
+            <ion-card-title>{{attention?.get('name')}}</ion-card-title>
+            <ion-card-subtitle>作者:{{attention?.get('user')?.get('name')||"无名"}}</ion-card-subtitle>
+            <ion-card-subtitle>{{attention?.get('type')||"角色类型"}}</ion-card-subtitle>
+            <ion-card-subtitle>{{attention?.get('createdAt')| date: 'YYYY/MM/dd/HH:mm'||"发布时间"}}</ion-card-subtitle>
+        </ion-card-header>
+        <ion-card-content>
+            {{attention?.get('cueword')||"角色生成的提示词..."}}
+        </ion-card-content>
+    </ion-card>
+    <!-- 评论区 -->
+    <ion-list [inset]="true">
+        <ion-item>
+            <ion-textarea label="评论一下吧" labelPlacement="floating" rows="5" [(ngModel)]="comment">
+            </ion-textarea>
+        </ion-item>
+        <ion-item>
+            <ion-buttons slot="end">
+                <ion-button color="medium" fill="outline" (click)="addComment()" shape="round">确定</ion-button>
+            </ion-buttons>
+        </ion-item>
+    </ion-list>
+    <ion-list [inset]="true">
+        <ng-container *ngFor="let comment of comments">
+            <ion-item class="comment-list">
+                <ion-label>
+                    <p class="commentator">用户昵称</p>
+                    <ion-note class="comment-content">{{comment}}</ion-note>
+                </ion-label>
+                <div class="comment-time">
+                    <ion-note color="medium">{{currentDate|date: 'HH:mm'}}</ion-note>
+                </div>
+            </ion-item>
+        </ng-container>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">邱依依</p>
+                <ion-note class="comment-content">好看 ♥</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">03:44</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">秦酒</p>
+                <ion-note class="comment-content">也想试试</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">Yesterday</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">文斯斯</p>
+                <ion-note class="comment-content">更想吃=。=</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">Yesterday</ion-note>
+            </div>
+        </ion-item>
+    </ion-list>
+
+</ion-content>

+ 19 - 0
app-angular/src/modules/lesson/attention-detail/attention-detail.component.scss

@@ -0,0 +1,19 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.commentator {
+    font-size: 0.7rem;
+}
+
+.comment-time {
+    position: absolute;
+
+    bottom: 0px;
+    inset-inline-end: 10px;
+
+    font-size: 0.4rem;
+    z-index: 100;
+    display: flex;
+    align-items: center;
+}

+ 21 - 0
app-angular/src/modules/lesson/attention-detail/attention-detail.component.spec.ts

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

+ 42 - 0
app-angular/src/modules/lesson/attention-detail/attention-detail.component.ts

@@ -0,0 +1,42 @@
+import { Component } from '@angular/core';
+
+// 引入服务
+import { ActivatedRoute } from '@angular/router';
+
+// 引入Parse第三方库
+import * as Parse from "parse"
+(Parse as any).serverURL = "http://metapunk.cn:9999/parse"
+Parse.initialize("dev")
+
+
+@Component({
+  selector: 'app-attention-detail',
+  templateUrl: './attention-detail.component.html',
+  styleUrls: ['./attention-detail.component.scss']
+})
+export class AttentionDetailComponent {
+
+  //添加评论
+  comments: string[] = [];
+  comment: string = '';
+  currentDate = new Date();
+  addComment() {
+    console.log(this.comment)
+    if (this.comment.trim() !== '') {
+      this.comments.push(this.comment);
+      this.comment = '';
+    }
+  }
+
+  attention: Parse.Object | undefined;
+  constructor(private router: ActivatedRoute) {
+    this.router.queryParams.subscribe(param => {
+      this.getRoleInfoById(param["id"])
+    })
+  }
+  async getRoleInfoById(id: string) {
+    let query = new Parse.Query("SqzRoleInfo")
+    this.attention = await query.get(id)
+  }
+
+}

+ 19 - 0
app-angular/src/modules/lesson/community/community-routing.module.ts

@@ -0,0 +1,19 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { ShareComponent } from '../share/share.component';
+import { RecommandDetailComponent } from '../recommend-detail/recommend-detail.component';
+import { AttentionDetailComponent } from '../attention-detail/attention-detail.component';
+import { ScienceDetailComponent } from '../science-detail/science-detail.component';
+
+const routes: Routes = [
+    { path: "share", component: ShareComponent }, // 当路径为 "share" 时,加载 ShareComponent 组件
+    { path: "recommend", component: RecommandDetailComponent }, // 当路径为 "recommend" 时,加载 RecommandDetailComponent 组件
+    { path: "attention", component: AttentionDetailComponent }, // 当路径为 "attention" 时,加载 AttentionDetailComponent 组件
+    { path: "sciene", component: ScienceDetailComponent }, // 当路径为 "sciene" 时,加载 ScienceDetailComponent 组件
+]
+
+@NgModule({
+    imports: [RouterModule.forChild(routes)], // 导入路由配置
+    exports: [RouterModule] // 导出路由模块
+})
+export class CommunityRoutingModule { }

+ 120 - 0
app-angular/src/modules/lesson/community/community.component.html

@@ -0,0 +1,120 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-icon name="compass-outline" size="large" color="dark"></ion-icon>
+        <ion-title>首页</ion-title>
+        <ion-button slot="end" fill="clear" size="small" routerLink="share">
+            <ion-icon name="add-circle-outline" size="large" color="dark"></ion-icon>
+            <ion-note>发布</ion-note>
+        </ion-button>
+        
+    </ion-toolbar>
+</ion-header>
+
+<ion-content color="light">
+    <!-- 导航 -->
+    <ion-card class="navbar">
+        <ion-toolbar>
+            <ion-segment value="推荐">
+                <!-- <ion-segment-button value="推荐"  (click)="cate='推荐'"> -->
+                    <ion-segment-button value="推荐" (click)="showCate('推荐')">
+                    <ion-label>推荐</ion-label>
+                </ion-segment-button>
+                <!-- <ion-segment-button value="关注" (click)="cate='关注'"> -->
+                    <ion-segment-button value="关注" (click)="showCate('关注')">
+                    <ion-label>关注</ion-label>
+                </ion-segment-button>
+                <!-- <ion-segment-button value="科普" (click)="cate='科普'"> -->
+                    <ion-segment-button value="科普" (click)="showCate('科普')">
+                    <ion-label>科普</ion-label>
+                </ion-segment-button>
+            </ion-segment>
+        </ion-toolbar>
+    </ion-card>
+
+    <!-- 推荐 -->
+    <ng-container *ngIf=" currentCate =='推荐'">
+        <ion-grid>
+            <ion-row>
+                <ng-container *ngFor="let attention of recommendList">
+                    <ion-col size="6">
+                        <ion-card class="attentionCard" (click)="goAttentionDetail(attention)">
+                            <img alt="推荐图" [src]="attention?.get('img')" />
+                            <ion-card-header>
+                                <ion-card-title>
+                                    {{attention?.get('name')}}
+                                </ion-card-title>
+                                <ion-card-subtitle style="font-size:0.7rem;">
+                                    作者:{{attention?.get('user')?.get('name')||"无名"}}
+                                </ion-card-subtitle>
+                            </ion-card-header>
+                            <div class="metadata-end-wrapper">
+                                <ion-button shape="round" size="small" color="danger">
+                                    <ion-icon name="heart-outline" size="small"></ion-icon>
+                                    {{attention?.get('like')}}
+                                </ion-button>
+                            </div>
+                        </ion-card>
+                    </ion-col>
+                </ng-container>
+            </ion-row>
+        </ion-grid>
+    </ng-container>
+
+
+   <!-- 关注 -->
+<ng-container *ngIf=" currentCate =='发现'"> <!-- 当 cate 变量的值为 '发现' 时,显示以下内容 -->
+    <ion-grid> <!-- 使用 Ionic 的网格布局 -->
+        <ion-row> <!-- 网格的一行 -->
+            <ng-container *ngFor="let attention of attentionList"> <!-- 对 attentionList 数组进行循环 -->
+                <ion-col size="6"> <!-- 网格的一列,占据一半的宽度 -->
+                    <ion-card class="attentionCard" (click)="goAttentionDetail(attention)"> <!-- 使用 Ionic 的卡片组件,点击时触发 goAttentionDetail 方法 -->
+                        <!-- <img alt="关注图" [src]="attention?.get('img')" /> 显示关注的图像,使用 attention 对象的 'img' 属性作为图片源 -->
+                        <ion-card-header> <!-- 卡片的头部 -->
+                            <ion-card-title> <!-- 卡片的标题 -->
+                                {{attention?.get('name')}} <!-- 显示关注的名称,使用 attention 对象的 'name' 属性 -->
+                            </ion-card-title>
+                            <ion-card-subtitle style="font-size:0.7rem;"> <!-- 卡片的副标题,字体大小为0.7rem -->
+                                作者:{{attention?.get('user')?.get('name')||"无名"}} <!-- 显示关注的作者名称,使用 attention 对象的 'user' 属性的 'name' 属性。如果没有作者名称,则显示 "无名" -->
+                            </ion-card-subtitle>
+                        </ion-card-header>
+                        <div class="metadata-end-wrapper"> <!-- 元数据的末尾包装器 -->
+                            <ion-button shape="round" size="small" color="danger"> <!-- 使用 Ionic 的按钮组件,圆形形状,小号尺寸,红色背景色 -->
+                                <ion-icon name="heart-outline" size="small"></ion-icon> <!-- 显示一个带有小号尺寸的心形图标 -->
+                                {{attention?.get('like')}} <!-- 显示关注的点赞数,使用 attention 对象的 'like' 属性 -->
+                            </ion-button>
+                        </div>
+                    </ion-card>
+                </ion-col>
+            </ng-container>
+        </ion-row>
+    </ion-grid>
+</ng-container>
+
+
+    <!-- 科普 -->
+    <ng-container *ngIf=" currentCate =='科普'">
+        <ng-container *ngFor="let sciene of scieneList">
+            <ion-card (click)="goScieneDetail(sciene)">
+                <img alt="科普图" [src]="sciene?.get('img')" />
+                <ion-card-header>
+                    <ion-card-title>{{sciene?.get('name')}}</ion-card-title>
+                    <ion-card-subtitle>{{sciene?.get('createdAt')| date: 'YYYY/MM/dd'||"发布时间"}}</ion-card-subtitle>
+                    <div class="metadata-end-wrapper">
+                        <ion-button fill="clear" color="dark" size="small" class="see">
+                            <ion-icon name="eye-outline" size="small"></ion-icon>
+                            <ion-note>{{sciene?.get('see')}}</ion-note>
+                        </ion-button>
+                        <ion-button fill="clear" color="dark" size="small" class="like">
+                            <ion-icon name="heart-outline" size="small"></ion-icon>
+                            <ion-note>{{sciene?.get('like')}}</ion-note>
+                        </ion-button>
+                    </div>
+                </ion-card-header>
+                <ion-card-content>
+                    <p class="scieneContent">{{sciene?.get('content')}}</p>
+                </ion-card-content>
+            </ion-card>
+        </ng-container>
+    </ng-container>
+
+</ion-content>

+ 28 - 0
app-angular/src/modules/lesson/community/community.component.scss

@@ -0,0 +1,28 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.scieneContent {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.attentionCard {
+    margin: 0px;
+}
+
+.metadata-end-wrapper {
+    position: absolute;
+
+    top: 3px;
+    inset-inline-end: 3px;
+
+    font-size: 0.6rem;
+
+    display: flex;
+    align-items: center;
+
+}

+ 21 - 0
app-angular/src/modules/lesson/community/community.component.spec.ts

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

+ 81 - 0
app-angular/src/modules/lesson/community/community.component.ts

@@ -0,0 +1,81 @@
+import { Component } from '@angular/core';
+
+// 引用服务
+import { Router } from '@angular/router';
+
+// 引入Parse第三方库
+import * as Parse from "parse"
+(Parse as any).serverURL = "http://metapunk.cn:9999/parse"
+Parse.initialize("dev")
+
+
+@Component({
+  selector: 'app-community',
+  templateUrl: './community.component.html',
+  styleUrls: ['./community.component.scss']
+})
+export class CommunityComponent {
+
+  scieneList: Array<Parse.Object> = [] // 科普列表
+  recommendList: Array<Parse.Object> = [] // 推荐列表
+  attentionList: Array<Parse.Object> = [] // 关注列表
+
+  // 依赖注入
+  constructor(private router: Router) {
+    this.initPage(); // 初始化页面
+  }
+
+  // 首次进入页面,默认加载首批数据
+  async initPage() {
+    this.scieneList = await this.getScieneData(); // 获取科普数据
+    this.recommendList = await this.getRecommendData(); // 获取推荐数据
+    this.attentionList = await this.getAttentionData(); // 获取关注数据
+  }
+
+currentCate:string ='推荐'
+
+  //页面切换
+  showCate(cate:string):void {
+    this.currentCate = cate;
+  }
+
+  // 数据加载相关函数
+  async getScieneData() {
+    let query = new Parse.Query("PetScience"); // 创建PetScience查询
+    let list = await query.find(); // 执行查询
+    return list; // 返回查询结果
+  }
+
+  async getRecommendData() {
+    let query = new Parse.Query("PetRecommend"); // 创建PetRecommend查询
+    let list = await query.find(); // 执行查询
+    return list; // 返回查询结果
+  }
+
+  async getAttentionData() {
+    let query = new Parse.Query("PetAttention"); // 创建PetAttention查询
+    let list = await query.find(); // 执行查询
+    return list; // 返回查询结果
+  }
+
+  cate: string = "推荐" // 类别,默认为"推荐"
+
+  // 跳转函数
+  goScieneDetail(sciene: Parse.Object) {
+    this.router.navigate(["/lesson/community/scieneDetail"], {
+      queryParams: sciene // 导航到科普详情页面,并传递科普参数
+    })
+  }
+
+  goRecommendDetail(recommend: Parse.Object) {
+    this.router.navigate(["/lesson/community/recommendDetail"], {
+      queryParams: recommend // 导航到推荐详情页面,并传递推荐参数
+    })
+  }
+
+  goAttentionDetail(attention: Parse.Object) {
+    this.router.navigate(["/lesson/community/attentionDetail"], {
+      queryParams: attention // 导航到关注详情页面,并传递关注参数
+    })
+  }
+}

+ 26 - 0
app-angular/src/modules/lesson/community/community.module.ts

@@ -0,0 +1,26 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+
+import { CommunityRoutingModule } from './community-routing.module';
+import { ScienceDetailComponent } from '../science-detail/science-detail.component';
+import { RecommandDetailComponent } from '../recommend-detail/recommend-detail.component';
+
+@NgModule({
+
+    declarations: [
+        ScienceDetailComponent,
+        RecommandDetailComponent,
+    ],
+    imports: [
+        CommonModule,
+        CommunityRoutingModule,
+        FormsModule,
+        IonicModule
+    ]
+})
+
+export class community {
+
+}

+ 27 - 25
app-angular/src/modules/lesson/lesson-routing.module.ts

@@ -1,32 +1,34 @@
 import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
-import { DetailComponent } from './detail/detail.component';
-import { HomeComponent } from './home/home.component';
-import { PageMineComponent } from './page-mine/page-mine.component';
-import { PageStudentComponent } from './page-student/page-student.component';
-import { PageStudentDetailComponent } from './page-student-detail/page-student-detail.component';
+import { MeComponent } from './me/me.component';
+import { TheyComponent } from './they/they.component';
+import { NearComponent } from './near/near.component';
+import { TheyDetailComponent } from './they-detail/they-detail.component';
+import { CommunityComponent } from './community/community.component';
+import { ScienceDetailComponent } from './science-detail/science-detail.component';
+import { ShareComponent } from './share/share.component';
+import { AttentionDetailComponent } from './attention-detail/attention-detail.component';
+import { RecommandDetailComponent } from './recommend-detail/recommend-detail.component';
+import { UserFollowComponent } from './user-follow/user-follow.component';
+import { UserTagComponent } from './user-tag/user-tag.component';
+import { UserCollectionComponent } from './user-collection/user-collection.component';
+
 
-import { FindComponent } from './find/find.component';
 const routes: Routes = [
-  {
-    path:"home",component:HomeComponent
-  },
-  {
-    path:"detail",component:DetailComponent
-  },
-  {
-    path:"mine",component:PageMineComponent
-  },
-  {
-    path:"student",component:PageStudentComponent
-  },
-  {
-    path:"student/detail",component:PageStudentDetailComponent
-  }
-  ,
-  {
-    path:"find",component:FindComponent
-  }
+  { path: 'me', component: MeComponent },
+  { path: 'they', component: TheyComponent },
+  { path: 'community', component: CommunityComponent },
+  { path: 'near', component: NearComponent },
+  { path: 'they/detail', component: TheyDetailComponent },
+  { path: 'community/scieneDetail', component: ScienceDetailComponent },
+  { path: 'community/share', component: ShareComponent },
+  { path: 'community/attentionDetail', component: AttentionDetailComponent },
+  { path: 'community/recommendDetail', component: RecommandDetailComponent },
+  { path: "me/userFollow", component: UserFollowComponent },
+  { path: "me/userTag", component: UserTagComponent },
+  { path: "me/userCollection", component: UserCollectionComponent },
+
+
 ];
 
 @NgModule({

+ 28 - 23
app-angular/src/modules/lesson/lesson.module.ts

@@ -1,38 +1,43 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
-
-import { LessonRoutingModule } from './lesson-routing.module';
-import { HomeComponent } from './home/home.component';
-import { DetailComponent } from './detail/detail.component';
 import { FormsModule } from '@angular/forms';
-import { CompLessonCardComponent } from './comp-lesson-card/comp-lesson-card.component';
-import { PageMineComponent } from './page-mine/page-mine.component';
-import { CompNavButtonComponent } from './comp-nav-button/comp-nav-button.component';
-import { PageStudentComponent } from './page-student/page-student.component';
-import { PageStudentDetailComponent } from './page-student-detail/page-student-detail.component';
-import { TokPipe } from './tok.pipe';
-
-import { FindComponent } from './find/find.component';
 import { IonicModule } from '@ionic/angular';
 
+import { LessonRoutingModule } from './lesson-routing.module';
+import { TheyComponent } from './they/they.component';
+import { MeComponent } from './me/me.component';
+import { NearComponent } from './near/near.component';
+import { TheyDetailComponent } from './they-detail/they-detail.component';
+import { CommunityComponent } from './community/community.component';
+import { ScienceDetailComponent } from './science-detail/science-detail.component';
+import { ShareComponent } from './share/share.component';
+import { RecommandDetailComponent } from './recommend-detail/recommend-detail.component';
+import { AttentionDetailComponent } from './attention-detail/attention-detail.component';
+import { UserFollowComponent } from './user-follow/user-follow.component';
+import { UserTagComponent } from './user-tag/user-tag.component';
+import { UserCollectionComponent } from './user-collection/user-collection.component';
 
 @NgModule({
   declarations: [
-    HomeComponent,
-    DetailComponent,
-    CompLessonCardComponent,
-    PageMineComponent,
-    CompNavButtonComponent,
-    PageStudentComponent,
-    PageStudentDetailComponent,
-    TokPipe,
-    
-    FindComponent
+    TheyComponent,
+    MeComponent,
+    NearComponent,
+    TheyDetailComponent,
+    CommunityComponent,
+    ScienceDetailComponent,
+    ShareComponent,
+    RecommandDetailComponent,
+    AttentionDetailComponent,
+    UserFollowComponent,
+    UserTagComponent,
+    UserCollectionComponent,
+
+
   ],
   imports: [
     CommonModule,
-    FormsModule,
     LessonRoutingModule,
+    FormsModule,
     IonicModule
   ]
 })

+ 187 - 0
app-angular/src/modules/lesson/me/me.component.html

@@ -0,0 +1,187 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-title>我的</ion-title>
+        <!-- 编辑信息按钮 -->
+        <ion-buttons slot="end">
+            <ion-button routerLink="/user/info">
+                <ion-icon slot="start" name="create-outline"></ion-icon>
+            </ion-button>
+            <ion-button id="myMenu">
+                <ion-icon name="menu-outline"></ion-icon>
+            </ion-button>
+            <ion-popover trigger="myMenu" triggerAction="click">
+                <ng-template>
+                    <ion-list>
+                        <ion-item [button]="true">
+                            <ion-icon name="scan-outline" size="small"></ion-icon>
+                            <ion-text>扫一扫</ion-text>
+                        </ion-item>
+                        <ion-item [button]="true">
+                            <ion-icon name="share-social-outline" size="small"></ion-icon>
+                            <ion-text>分享</ion-text>
+                        </ion-item>
+                        <ion-item [button]="true">
+                            <ion-icon name="pulse-outline" size="small"></ion-icon>
+                            <ion-text>客服</ion-text>
+                        </ion-item>
+
+                        <ion-item [button]="true">
+                            <ion-icon name="settings-outline" size="small"></ion-icon>
+                            <ion-text>设置</ion-text>
+                        </ion-item>
+                    </ion-list>
+                </ng-template>
+            </ion-popover>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <!-- 基本信息栏 -->
+    <ion-card>
+        <ion-list [inset]="true">
+            <ion-item lines="full">
+                <ion-avatar slot="start">
+                    <img alt="头像" src="https://ionicframework.com/docs/img/demos/avatar.svg" />
+                </ion-avatar>
+                <ion-label>
+                    {{currentUser?.get("name") || '昵称'}}
+                </ion-label>
+                <ion-buttons slot="end">
+                    <ion-button>
+                        <ion-icon name="heart-outline"></ion-icon>
+                        <ion-note>{{currentUser?.get("like") || '99'}}</ion-note>
+                    </ion-button>
+                </ion-buttons>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-badge slot="start">{{currentUser?.get("tag") || '标签'}}</ion-badge>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-label color="medium">
+                    {{currentUser?.get("desc") || '介绍一下自己吧'}}
+                </ion-label>
+            </ion-item>
+        </ion-list>
+    </ion-card>
+
+    <!-- 列表 -->
+    <ion-card class="myList">
+        <ion-list [inset]="true">
+            <ion-item button detail="true" routerLink="/lesson/me/userFollow">
+                <ion-label>
+                    <ion-note>关注</ion-note>
+                </ion-label>
+            </ion-item>
+            <ion-item button detail="true" routerLink="/lesson/me/userTag">
+                <ion-label>
+                    <ion-note>成就</ion-note>
+                </ion-label>
+            </ion-item>
+            <ion-item button detail="true" routerLink="/lesson/me/userCollection">
+                <ion-label>
+                    <ion-note>收藏</ion-note>
+                </ion-label>
+            </ion-item>
+        </ion-list>
+    </ion-card>
+
+
+    <!-- 详细内容 -->
+    <!-- 导航 -->
+    <ion-card>
+        <ion-toolbar>
+            <ion-segment value="关注">
+                <ion-segment-button value="推荐" (click)="cate='推荐'">
+                    <ion-icon name="bicycle-outline"></ion-icon>
+                    <ion-label>推荐</ion-label>
+                </ion-segment-button>
+                <ion-segment-button value="关注" (click)="cate='关注'">
+                    <ion-icon name="person-outline"></ion-icon>
+                    <ion-label>关注</ion-label>
+                </ion-segment-button>
+                <ion-segment-button value="科普" (click)="cate='科普'">
+                    <ion-icon name="fast-food-outline"></ion-icon>
+                    <ion-label>笔记</ion-label>
+                </ion-segment-button>
+            </ion-segment>
+            <ion-buttons slot="end"><ion-button>编辑</ion-button></ion-buttons>
+        </ion-toolbar>
+    </ion-card>
+
+    <!-- 美景推荐 -->
+
+    <ng-container *ngIf="cate=='推荐'">
+        <ion-list [inset]="true" lines="inset">
+            <ng-container *ngFor="let recommand of myViewList">
+                <ion-item>
+                    <ion-thumbnail slot="end">
+                        <img alt="推荐图" [src]="recommand?.get('img')" />
+                    </ion-thumbnail>
+                    <ion-label>
+                        <h2>{{recommand?.get('title')}}</h2>
+                        <p>{{recommand?.get('content')}}</p>
+                        <ion-note slot="start">{{recommand?.get('createdAt')| date: 'YYYY/MM/dd'||"发布时间"}}</ion-note>
+                    </ion-label>
+                </ion-item>
+            </ng-container>
+        </ion-list>
+    </ng-container>
+
+    <!-- 科普关注 -->
+    <ng-container *ngIf="cate=='关注'">
+        <ion-grid>
+            <ion-row>
+                <ng-container *ngFor="let attention of myRoleList">
+                    <ion-col size="6">
+                        <ion-card class="attentionCard">
+                            <img alt="关注图" [src]="attention?.get('img')" />
+                            <ion-card-header>
+                                <ion-card-title>
+                                    {{attention?.get('name')}}
+                                </ion-card-title>
+                                <ion-card-subtitle>{{attention?.get('createdAt')| date:
+                                    'YYYY/MM/dd'||"发布时间"}}</ion-card-subtitle>
+                            </ion-card-header>
+
+                        </ion-card>
+                    </ion-col>
+                </ng-container>
+            </ion-row>
+        </ion-grid>
+    </ng-container>
+
+    <!-- 科普笔记 -->
+    <ng-container *ngIf="cate=='科普'">
+        <ng-container *ngFor="let sciene of myFoodList">
+            <ion-card>
+                <img alt="科普图" [src]="sciene?.get('img')" />
+                <ion-card-header>
+                    <ion-card-title>{{sciene?.get('name')}}</ion-card-title>
+                    <ion-card-subtitle>{{sciene?.get('createdAt')| date:
+                        'YYYY/MM/dd/HH:mm'||"发布时间"}}</ion-card-subtitle>
+                    <div class="metadata-end-wrapper-sciene">
+                        <ion-buttons slot="end">
+                            <ion-button>
+                                <ion-icon name="eye-outline" size="small"></ion-icon>
+                                <ion-note>{{sciene?.get('see')}}</ion-note>
+                            </ion-button>
+                            <ion-button>
+                                <ion-icon name="heart-outline" size="small"></ion-icon>
+                                <ion-note>{{sciene?.get('like')}}</ion-note>
+                            </ion-button>
+                        </ion-buttons>
+                    </div>
+                </ion-card-header>
+                <ion-card-content>
+                    <p class="scieneContent">{{sciene?.get('content')}}</p>
+                </ion-card-content>
+            </ion-card>
+        </ng-container>
+    </ng-container>
+
+    <ion-list [inset]="true">
+        <ion-button *ngIf="!currentUser?.id" expand="block" routerLink="/user/login">登录</ion-button>
+        <ion-button *ngIf="currentUser?.id" fill="clear" expand="block" (click)="logout()">登出</ion-button>
+    </ion-list>
+
+</ion-content>

+ 57 - 0
app-angular/src/modules/lesson/me/me.component.scss

@@ -0,0 +1,57 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+ion-item {
+    ion-icon {
+        margin-right: 9px;
+    }
+
+    font-size: 0.9rem;
+}
+
+.scieneContent {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.myList {
+    padding: 0%;
+
+    ion-list {
+        margin: 0%;
+    }
+}
+
+
+.attentionCard {
+    margin: 0px;
+}
+
+.metadata-end-wrapper {
+    position: absolute;
+
+    bottom: 0px;
+    inset-inline-end: 6px;
+
+    font-size: 0.6rem;
+
+    display: flex;
+    align-items: center;
+}
+
+.metadata-end-wrapper-sciene {
+    position: absolute;
+
+    top: 0px;
+    inset-inline-end: 0px;
+
+    font-size: 0.6rem;
+
+    display: flex;
+    align-items: center;
+
+}

+ 21 - 0
app-angular/src/modules/lesson/me/me.component.spec.ts

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

+ 71 - 0
app-angular/src/modules/lesson/me/me.component.ts

@@ -0,0 +1,71 @@
+import { Component } from '@angular/core';
+import { ToastController } from '@ionic/angular';
+import { UserService } from 'src/modules/user/service-user/user.service';
+import * as Parse from "parse";
+
+@Component({
+  selector: 'app-me',
+  templateUrl: './me.component.html',
+  styleUrls: ['./me.component.scss']
+})
+export class MeComponent {
+
+  currentUser: Parse.User | undefined;
+
+  constructor(
+    private toastCtrl: ToastController,
+    public userServ: UserService
+  ) {
+    this.currentUser = Parse.User.current(); // 获取当前已登录的用户
+  }
+
+  async ngOnInit() {
+    this.myRoleList = await this.getAttentionData(); // 获取关注数据
+    this.myFoodList = await this.getScieneData(); // 获取科普数据
+    this.myViewList = await this.getViewDate(); // 获取推荐分享数据
+  }
+
+  cate: string = "关注"; // 当前分类,默认为"关注"
+
+  // 我的推荐分享
+  myViewList: Array<Parse.Object> = [];
+  async getViewDate() {
+    let query = new Parse.Query("PetRecommend"); // 创建 PetRecommend 类的查询
+    query.equalTo("user", Parse.User.current()?.toPointer()); // 查询当前用户发布的推荐分享
+    query.include("user"); // 包含用户信息
+    let list = await query.find(); // 执行查询
+    return list; // 返回查询结果
+  }
+
+  // 我的科普关注
+  myRoleList: Array<Parse.Object> = [];
+  async getAttentionData() {
+    let query = new Parse.Query("PetAttention"); // 创建 PetAttention 类的查询
+    query.equalTo("user", Parse.User.current()?.toPointer()); // 查询当前用户发布的科普关注
+    query.include("user"); // 包含用户信息
+    let list = await query.find(); // 执行查询
+    return list; // 返回查询结果
+  }
+
+  // 我的科普分享
+  myFoodList: Array<Parse.Object> = [];
+  async getScieneData() {
+    let query = new Parse.Query("PetScience"); // 创建 PetScience 类的查询
+    query.equalTo("user", Parse.User.current()?.toPointer()); // 查询当前用户发布的科普分享
+    query.include("user"); // 包含用户信息
+    let list = await query.find(); // 执行查询
+    return list; // 返回查询结果
+  }
+
+  async logout() {
+    await Parse.User.logOut(); // 登出当前用户
+    this.currentUser = undefined; // 将当前用户设置为 undefined
+    let toast = await this.toastCtrl.create({
+      message: "登出成功",
+      position: "top",
+      duration: 500
+    });
+    toast.present(); // 显示登出成功的提示消息
+  }
+
+}

+ 60 - 0
app-angular/src/modules/lesson/near/near.component.html

@@ -0,0 +1,60 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-title>附近</ion-title>
+    </ion-toolbar>
+</ion-header>
+<ion-content>
+    <!-- 搜索栏 -->
+    <ion-searchbar animated="true" placeholder="搜索你要去的目的地"></ion-searchbar>
+
+    <!-- 地图导航 -->
+    <ion-card>
+        <img alt="定位" src="https://ionicframework.com/docs/img/demos/card-media.png" />
+    </ion-card>
+
+    <!-- 打卡签到卡片 -->
+    <ion-list>
+        <ion-item>
+            <ion-label>
+                当前区域科普商户列表
+            </ion-label>
+        </ion-item>
+        <ion-item>
+            <ion-thumbnail slot="start"><img alt="附近店面图"
+                    src="https://ionicframework.com/docs/img/demos/avatar.svg" /></ion-thumbnail>
+            <ion-label>
+                <strong>科普商户名</strong>
+                <p>评分:5.0分</p>
+                <p class="introduction">标签|地址</p>
+                <p class="introduction">推荐菜/食客评价</p>
+            </ion-label>
+        </ion-item>
+        <ion-item>
+            <ion-thumbnail slot="start"><img alt="附近店面图"
+                    src="http://qcloud.dpfile.com/pc/1S_E0Yzjk4BnRYSSRSfOXdJb2nYCnhCN45WXWlrPHJtCPkWLDk0eI9B8Xgm4UCmmbKcq9vnEaGy3xLEf-_v_oA.jpg" /></ion-thumbnail>
+            <ion-label>
+                <strong>黄记瓦罐煨汤(广场东路店)</strong>
+                <p>评分:3.8分</p>
+                <p class="introduction">标签|地址</p>
+                <p class="introduction">推荐菜/食客评价</p>
+            </ion-label>
+        </ion-item>
+        <ion-item>
+            <ion-thumbnail slot="start"><img alt="附近店面图"
+                    src="http://p0.meituan.net/biztone/882341109_1695830077224.jpeg%40340w_255h_1e_1c_1l%7Cwatermark%3D0" /></ion-thumbnail>
+            <ion-label>
+                <strong>堂瓦里·正宗赣菜(建德观店)</strong>
+                <p>评分:4.0分</p>
+                <p class="introduction">标签|地址</p>
+                <p class="introduction">推荐菜/食客评价</p>
+            </ion-label>
+        </ion-item>
+    </ion-list>
+
+
+
+
+    <!-- 测试 -->
+
+
+</ion-content>

+ 17 - 0
app-angular/src/modules/lesson/near/near.component.scss

@@ -0,0 +1,17 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.introduction {
+    padding: 0%;
+    margin: 0%;
+    font-size: 0.6rem;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: 2;
+    overflow: hidden;
+    text-overflow: ellipsis;
+
+}
+
+// 测试

+ 21 - 0
app-angular/src/modules/lesson/near/near.component.spec.ts

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

+ 11 - 0
app-angular/src/modules/lesson/near/near.component.ts

@@ -0,0 +1,11 @@
+import { Component } from '@angular/core';
+
+
+@Component({
+  selector: 'app-near',
+  templateUrl: './near.component.html',
+  styleUrls: ['./near.component.scss']
+})
+export class NearComponent {
+
+}

+ 3 - 1
app-angular/src/modules/lesson/page-mine/nav-tabs/nav-tabs.component.html

@@ -5,6 +5,7 @@
     <div class="tab-button">
       <button [class.active]="path == '/lesson/home' " (click)="goTab('/lesson/home')">
         <svg class="icon" style="vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2919"><path d="M0 0h1024v1024H0V0z" fill="#202425" opacity=".01" p-id="2920"></path><path d="M34.133333 90.897067a17.066667 17.066667 0 0 1 21.742934-16.384L413.013333 176.469333A136.533333 136.533333 0 0 1 512 307.780267V955.733333L83.626667 833.365333A68.266667 68.266667 0 0 1 34.133333 767.658667V90.897067z" fill="#11AA66" p-id="2921"></path><path d="M989.866667 90.897067a17.066667 17.066667 0 0 0-21.742934-16.384L610.986667 176.469333A136.533333 136.533333 0 0 0 512 307.780267V955.733333l428.373333-122.368A68.266667 68.266667 0 0 0 989.866667 767.658667V90.897067z" fill="#FFAA44" p-id="2922"></path><path d="M213.0944 376.490667a34.133333 34.133333 0 0 0-16.5888 66.218666l136.533333 34.133334a34.133333 34.133333 0 1 0 16.5888-66.218667l-136.533333-34.133333z m597.8112 0a34.133333 34.133333 0 0 1 16.554667 66.218666l-136.533334 34.133334a34.133333 34.133333 0 1 1-16.554666-66.218667l136.533333-34.133333zM171.690667 606.139733a34.133333 34.133333 0 0 1 41.403733-24.849066l136.533333 34.133333a34.133333 34.133333 0 1 1-16.5888 66.218667l-136.533333-34.133334a34.133333 34.133333 0 0 1-24.814933-41.3696z m639.214933-24.849066a34.133333 34.133333 0 1 1 16.554667 66.218666l-136.533334 34.133334a34.133333 34.133333 0 1 1-16.554666-66.218667l136.533333-34.133333z" fill="#FFFFFF" p-id="2923"></path></svg>
+        <!-- <svg t="1703070292010" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5093" width="200" height="200"><path d="M957.9 391.5c-1.1-7.5-5.5-14.2-12-18.5L527.4 98.9c-4.6-3.1-10.1-4.7-15.7-4.7-5.7 0-11.1 1.6-15.7 4.7L77.4 373.1c-6.2 4.1-10.4 10.3-11.6 17.4-1.2 7 0.5 14 4.8 19.7 5.2 6.9 13.7 11.1 22.6 11.1 5.6 0 11.1-1.6 15.7-4.7l40.2-26.3v435.4c0 57.8 45.8 104.7 102.2 104.7h520.8c56.3 0 102.2-47 102.2-104.7V390.2l40.4 26.5c5.7 3.5 11.1 5.2 16.4 5.2 7.9 0 15.2-3.8 21.5-11.4 4.4-5.4 6.3-12.1 5.3-19zM616.3 884.4H407V631.7c0-54 46.9-97.9 104.6-97.9 57.7 0 104.6 43.9 104.6 97.9v252.7z m202.4-58.8c0 28.6-20.9 51.9-46.6 51.9H665V631.7c0-79.4-68.8-143.9-153.3-143.9-84.5 0-153.3 64.6-153.3 143.9v245.9H251.3c-25.7 0-46.7-23.3-46.7-51.9V353.9l307.1-201.2 307.1 201.2v471.7z" fill="#6B400D" p-id="5094"></path><path d="M511.7 533.8c-57.7 0-104.6 43.9-104.6 97.9v252.7h209.3V631.7c-0.1-54-47-97.9-104.7-97.9z" fill="#FFD524" p-id="5095"></path><path d="M270.3 504.3c-17.5 0-31.7 14.7-31.7 32.8 0 18.1 14.2 32.8 31.7 32.8s31.7-14.7 31.7-32.8c-0.1-18.1-14.3-32.8-31.7-32.8zM270.3 592.9h-1.4c-13.1 0-23.8 10.7-23.8 23.8v212.5c0 13.1 10.7 23.8 23.8 23.8h1.4c13.1 0 23.8-10.7 23.8-23.8V616.7c0-13.1-10.7-23.8-23.8-23.8z" fill="#6B400D" p-id="5096"></path></svg> -->
         <span>首页</span>
       </button>
     </div>
@@ -20,4 +21,5 @@
         <span>我的</span>
       </button>
     </div>
-  </footer>
+  </footer>
+  

+ 95 - 0
app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.html

@@ -0,0 +1,95 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/community" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>返回</ion-button>
+        </ion-buttons>
+        <ion-buttons slot="end">
+            <ion-button fill="clear" color="dark">
+                <ion-note>收藏</ion-note>
+            </ion-button>
+        </ion-buttons>
+
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <ion-card>
+        <img alt="美景图" [src]="recommend?.get('img')" />
+        <ion-card-header>
+            <ion-card-title>{{recommend?.get('name')}}</ion-card-title>
+            <ion-card-subtitle>作者:{{recommend?.get('user')?.get('name')||"无名"}}</ion-card-subtitle>
+            <ion-card-subtitle>{{recommend?.get('createdAt')| date: 'YYYY/MM/dd/HH:mm'||"发布时间"}}</ion-card-subtitle>
+            <div class="metadata-end-wrapper">
+                <ion-button fill="clear" color="dark" size="small" class="see">
+                    <ion-icon name="eye-outline" size="small"></ion-icon>
+                    <ion-note>{{recommend?.get('see')}}</ion-note>
+                </ion-button>
+            </div>
+        </ion-card-header>
+        <ion-card-content>
+            {{recommend?.get('content')}}
+        </ion-card-content>
+    </ion-card>
+    <!-- 评论区 -->
+    <ion-list [inset]="true">
+        <ion-item>
+            <ion-textarea label="评论一下吧" labelPlacement="floating" rows="5" [(ngModel)]="comment">
+            </ion-textarea>
+        </ion-item>
+        <ion-item>
+            <ion-buttons slot="end">
+                <ion-button color="medium" fill="outline" (click)="addComment()" shape="round">确定</ion-button>
+            </ion-buttons>
+        </ion-item>
+    </ion-list>
+    <ion-list [inset]="true">
+        <ng-container *ngFor="let comment of comments">
+            <ion-item class="comment-list">
+                <ion-label>
+                    <p class="commentator">用户昵称</p>
+                    <ion-note class="comment-content">{{comment}}</ion-note>
+                </ion-label>
+                <div class="comment-time">
+                    <ion-note color="medium">{{currentDate|date: 'HH:mm'}}</ion-note>
+                </div>
+            </ion-item>
+        </ng-container>
+
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">肖哈哈</p>
+                <ion-note class="comment-content">666!</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">06:11</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">邱依依</p>
+                <ion-note class="comment-content">精彩的旅程 ♥</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">03:44</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">秦酒</p>
+                <ion-note class="comment-content">很想去!!</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">Yesterday</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">文斯斯</p>
+                <ion-note class="comment-content">下次一定要试试!!</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">Yesterday</ion-note>
+            </div>
+        </ion-item>
+    </ion-list>
+</ion-content>

+ 31 - 0
app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.scss

@@ -0,0 +1,31 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.metadata-end-wrapper {
+    position: absolute;
+
+    top: 3px;
+    inset-inline-end: 10px;
+
+    font-size: 0.4rem;
+    z-index: 100;
+    display: flex;
+    align-items: center;
+}
+
+.commentator {
+    font-size: 0.7rem;
+}
+
+.comment-time {
+    position: absolute;
+
+    bottom: 0px;
+    inset-inline-end: 10px;
+
+    font-size: 0.4rem;
+    z-index: 100;
+    display: flex;
+    align-items: center;
+}

+ 21 - 0
app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.spec.ts

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

+ 50 - 0
app-angular/src/modules/lesson/recommend-detail/recommend-detail.component.ts

@@ -0,0 +1,50 @@
+import { Component } from '@angular/core';
+
+// 引入服务
+import { ActivatedRoute } from '@angular/router';
+
+// 引入 Parse 第三方库
+import * as Parse from "parse"
+(Parse as any).serverURL = "http://metapunk.cn:9999/parse"
+Parse.initialize("dev")
+
+
+@Component({
+  selector: 'app-recommend-detail',
+  templateUrl: './recommend-detail.component.html',
+  styleUrls: ['./recommend-detail.component.scss']
+})
+export class RecommandDetailComponent {
+
+  comments: string[] = [] // 存储评论的数组
+  comment: string = '' // 当前评论的内容
+  currentDate = new Date() // 当前日期
+
+  addComment() {
+    console.log(this.comment)
+    if (this.comment.trim() !== '') {
+      this.comments.push(this.comment); // 将评论添加到数组中
+      this.comment = ''; // 清空当前评论的内容
+    }
+  }
+
+  // 预设值变量
+  recommend: Parse.Object | undefined; // 存储推荐信息的变量
+
+  // 依赖注入
+  constructor(private route: ActivatedRoute) {
+    // 查询参数获取并赋值给 this.recommend
+    this.route.queryParams.subscribe(params => {
+      this.getViewInfoById(params["id"]) // 根据 ID 获取推荐信息
+    })
+  }
+
+  /**
+   * 根据 ID 获取推荐信息
+   * @param id 推荐 ID
+   */
+  async getViewInfoById(id: string) {
+    let query = new Parse.Query("PetRecommend") // 创建 Parse 查询对象
+    this.recommend = await query.get(id) // 根据 ID 查询推荐信息并赋值给 this.recommend
+  }
+}

+ 91 - 0
app-angular/src/modules/lesson/science-detail/science-detail.component.html

@@ -0,0 +1,91 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/community" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>返回</ion-button>
+        </ion-buttons>
+        <ion-buttons slot="end">
+            <ion-button fill="clear" color="dark">
+                收藏</ion-button>
+        </ion-buttons>
+
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <ion-card>
+        <img alt="科普图" [src]="sciene?.get('img')" />
+        <ion-card-header>
+            <ion-card-title>{{sciene?.get('name')}}</ion-card-title>
+            <ion-card-subtitle>作者:{{sciene?.get('user')?.get('name')||"无名"}}</ion-card-subtitle>
+            <ion-card-subtitle>{{sciene?.get('type')||"科普类别"}}</ion-card-subtitle>
+            <ion-card-subtitle>{{sciene?.get('createdAt')| date: 'YYYY/MM/dd/HH:mm'||"发布时间"}}</ion-card-subtitle>
+        </ion-card-header>
+        <ion-card-content>
+            {{sciene?.get('content')}}
+        </ion-card-content>
+    </ion-card>
+    <!-- 评论区 -->
+    <ion-list [inset]="true">
+        <ion-item>
+            <ion-textarea label="评论一下吧" labelPlacement="floating" rows="5" [(ngModel)]="comment">
+            </ion-textarea>
+
+        </ion-item>
+        <ion-item>
+            <ion-buttons slot="end">
+                <ion-button color="medium" fill="outline" (click)="addComment()" shape="round">确定</ion-button>
+            </ion-buttons>
+        </ion-item>
+    </ion-list>
+    <ion-list [inset]="true">
+        <ng-container *ngFor="let comment of comments">
+            <ion-item class="comment-list">
+                <ion-label>
+                    <p class="commentator">用户昵称</p>
+                    <ion-note class="comment-content">{{comment}}</ion-note>
+                </ion-label>
+                <div class="comment-time">
+                    <ion-note color="medium">{{currentDate|date: 'HH:mm'}}</ion-note>
+                </div>
+            </ion-item>
+        </ng-container>
+
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">肖哈哈</p>
+                <ion-note class="comment-content">大神指教O.O</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">06:11</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">邱依依</p>
+                <ion-note class="comment-content"> ♥</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">03:44</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">秦酒</p>
+                <ion-note class="comment-content">很好吃的亚子!!</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">Yesterday</ion-note>
+            </div>
+        </ion-item>
+        <ion-item class="comment-list">
+            <ion-label>
+                <p class="commentator">文斯斯</p>
+                <ion-note class="comment-content">下次一定要试试!!</ion-note>
+            </ion-label>
+            <div class="comment-time">
+                <ion-note color="medium">Yesterday</ion-note>
+            </div>
+        </ion-item>
+    </ion-list>
+
+</ion-content>

+ 19 - 0
app-angular/src/modules/lesson/science-detail/science-detail.component.scss

@@ -0,0 +1,19 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.commentator {
+    font-size: 0.7rem;
+}
+
+.comment-time {
+    position: absolute;
+
+    bottom: 0px;
+    inset-inline-end: 10px;
+
+    font-size: 0.4rem;
+    z-index: 100;
+    display: flex;
+    align-items: center;
+}

+ 21 - 0
app-angular/src/modules/lesson/science-detail/science-detail.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ScienceDetailComponent } from './science-detail.component';
+
+describe('ScienceDetailComponent', () => {
+  let component: ScienceDetailComponent;
+  let fixture: ComponentFixture<ScienceDetailComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [ScienceDetailComponent]
+    });
+    fixture = TestBed.createComponent(ScienceDetailComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 49 - 0
app-angular/src/modules/lesson/science-detail/science-detail.component.ts

@@ -0,0 +1,49 @@
+import { Component } from '@angular/core';
+
+// 引入服务
+import { ActivatedRoute } from '@angular/router';
+
+// 引入 Parse 第三方库
+import * as Parse from "parse"
+(Parse as any).serverURL = "http://metapunk.cn:9999/parse"
+Parse.initialize("dev")
+//设置了 Parse 服务器的 URL 和应用程序密钥
+@Component({
+  selector: 'app-science-detail',
+  templateUrl: './science-detail.component.html',
+  styleUrls: ['./science-detail.component.scss']
+})
+export class ScienceDetailComponent {
+
+  // 添加评论
+  comments: string[] = [];
+  comment: string = '';
+  currentDate = new Date();
+
+  // 添加评论的方法
+  addComment() {
+    console.log(this.comment)
+    if (this.comment.trim() !== '') {
+      this.comments.push(this.comment);
+      this.comment = '';
+    }
+  }
+
+  // 预设值变量
+  sciene: Parse.Object | undefined;
+
+  // 依赖注入
+  constructor(private route: ActivatedRoute) {
+    // 查询参数获取并赋值给 this.sciene
+    this.route.queryParams.subscribe(params => {
+      this.getFoodInfoById(params["id"])
+    })
+  }
+
+  // 通过 ID 获取科普信息的方法
+  async getFoodInfoById(id: string) {
+    let query = new Parse.Query("PetScience")
+    this.sciene = await query.get(id)
+  }
+
+}

+ 150 - 0
app-angular/src/modules/lesson/share/share.component.html

@@ -0,0 +1,150 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/community" fill="clear" color="dark">
+                <ion-icon name="close-outline" size="large"></ion-icon>
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+
+<ion-content color="light">
+    <ion-toolbar>
+        <ion-segment value="推荐">
+            <ion-segment-button value="推荐" (click)="cate='推荐'">
+                <ion-label>推荐分享</ion-label>
+            </ion-segment-button>
+            <ion-segment-button value="关注" (click)="cate='关注'">
+                <ion-label>关注分享</ion-label>
+            </ion-segment-button>
+            <ion-segment-button value="科普" (click)="cate='科普'">
+                <ion-label>科普分享</ion-label>
+            </ion-segment-button>
+        </ion-segment>
+    </ion-toolbar>
+    <!-- 推荐分享 -->
+    <ng-container *ngIf="cate=='推荐'">
+        <ion-list [inset]="true">
+            <ion-item lines="full">
+                <!-- <ion-thumbnail><img alt="封面" [src]=" " /></ion-thumbnail> -->
+                <ion-icon name="image-outline" style="margin-right: 3px;"></ion-icon>添加封面
+            </ion-item>
+            <ion-item lines="none">
+                <ion-input placeholder="好的标题能吸引更多读者" [counter]="true" maxlength="30"></ion-input>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-textarea placeholder="分享你的旅途经历" rows="9" [counter]="true" maxlength="30000">
+                </ion-textarea>
+            </ion-item>
+            <ion-item lines="full">
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="image-outline"></ion-icon>添加图片</ion-button>
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="videocam-outline"></ion-icon>添加视频</ion-button>
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="camera-outline"></ion-icon>选择拍摄</ion-button>
+            </ion-item>
+            <ion-item lines="none"><ion-label style="font-size: 0.9rem;">
+                    参与话题:
+                    <ion-note class="viewTopic" button>#雪域奇景</ion-note><ion-note class="viewTopic">#自由行</ion-note>...
+                    <ion-note button>更多</ion-note>
+                </ion-label>
+            </ion-item>
+            <ion-item>
+                <ion-buttons slot="end">
+                    <ion-button routerLink="/lesson/community" fill="clear">
+                        确认发布
+                    </ion-button>
+                </ion-buttons>
+            </ion-item>
+        </ion-list>
+    </ng-container>
+
+    <!-- 关注分享 -->
+    <ng-container *ngIf="cate=='关注'">
+        <ion-list [inset]="true">
+            <ion-item lines="full">
+                <!-- <ion-thumbnail><img alt="封面" [src]=" " /></ion-thumbnail> -->
+                <ion-icon name="image-outline" style="margin-right: 3px;"></ion-icon>添加封面
+            </ion-item>
+            <ion-item lines="none">
+                <ion-input placeholder="科普名称/标题(30)" maxlength="30"></ion-input>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-select label="关注类型" interface="popover">
+                    <ion-select-option value="二次元">二次元</ion-select-option>
+                    <ion-select-option value="水彩">水彩</ion-select-option>
+                    <ion-select-option value="真人写实">真人写实</ion-select-option>
+                    <ion-select-option value="泼墨">泼墨</ion-select-option>
+                </ion-select>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-textarea placeholder="分享你的关注生成提示词" rows="9">
+                </ion-textarea>
+            </ion-item>
+            <ion-item lines="full">
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="image-outline"></ion-icon>更多图片</ion-button>
+            </ion-item>
+            <ion-item lines="none"><ion-label style="font-size: 0.9rem;">
+                    参与话题:
+                    <ion-note class="viewTopic" button>#二次元世界</ion-note>...
+                    <ion-note button>更多</ion-note>
+                </ion-label>
+            </ion-item>
+            <ion-item>
+                <ion-buttons slot="end">
+                    <ion-button routerLink="/lesson/community" fill="clear">
+                        确认发布
+                    </ion-button>
+                </ion-buttons>
+            </ion-item>
+        </ion-list>
+
+    </ng-container>
+
+    <!-- 科普分享 -->
+    <ng-container *ngIf="cate=='科普'">
+        <ion-list [inset]="true">
+            <ion-item lines="full">
+                <!-- <ion-thumbnail><img alt="封面" [src]=" " /></ion-thumbnail> -->
+                <ion-icon name="image-outline" style="margin-right: 3px;"></ion-icon>添加封面
+            </ion-item>
+            <ion-item lines="none">
+                <ion-input placeholder="不要把标题吃了" maxlength="30"></ion-input>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-select label="属于" interface="popover">
+                    <ion-select-option value="中餐">中餐</ion-select-option>
+                    <ion-select-option value="西餐">西餐</ion-select-option>
+                </ion-select>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-textarea placeholder="分享你的科普经历" rows="9" [counter]="true" maxlength="3000">
+                </ion-textarea>
+            </ion-item>
+            <ion-item lines="full">
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="image-outline"></ion-icon>添加图片</ion-button>
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="videocam-outline"></ion-icon>添加视频</ion-button>
+                <ion-button fill="clear" color="dark" class="viewUpload"><ion-icon
+                        name="camera-outline"></ion-icon>选择拍摄</ion-button>
+            </ion-item>
+            <ion-item lines="none"><ion-label style="font-size: 0.9rem;">
+                    参与/添加话题:
+                    <ion-note class="viewTopic" button>#火锅</ion-note><ion-note class="viewTopic">#变态辣</ion-note>...
+                    <ion-note button>更多</ion-note>
+                </ion-label>
+            </ion-item>
+            <ion-item>
+                <ion-buttons slot="end">
+                    <ion-button routerLink="/lesson/community" fill="clear">
+                        确认发布
+                    </ion-button>
+                </ion-buttons>
+            </ion-item>
+        </ion-list>
+    </ng-container>
+
+</ion-content>

+ 14 - 0
app-angular/src/modules/lesson/share/share.component.scss

@@ -0,0 +1,14 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+ion-icon {
+    margin-right: 3px;
+}
+
+.viewTopic {
+    margin: 5px;
+    padding: 3px;
+    background-color: rgb(167, 167, 156);
+    border-radius: 30%
+}

+ 21 - 0
app-angular/src/modules/lesson/share/share.component.spec.ts

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

+ 10 - 0
app-angular/src/modules/lesson/share/share.component.ts

@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-share',
+  templateUrl: './share.component.html',
+  styleUrls: ['./share.component.scss']
+})
+export class ShareComponent {
+  cate: string = "推荐"
+}

+ 83 - 0
app-angular/src/modules/lesson/they-detail/they-detail.component.html

@@ -0,0 +1,83 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/they" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>
+                返回
+            </ion-button>
+        </ion-buttons>
+        <ion-buttons slot="end">
+            <ion-button>
+                <ion-icon name="arrow-redo-outline"></ion-icon>
+                分享
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+
+<ion-content color="light">
+    <!-- 用户信息 -->
+    <ion-card>
+        <ion-card-header>
+            <ion-item lines="full">
+                <ion-avatar slot="start">
+                    <img alt="头像" [src]="they?.get('avatar')" />
+                </ion-avatar>
+                <ion-label>{{they?.get("name")}}</ion-label>
+                <ion-button slot="end">
+                    <ion-icon name="heart-outline" size="small"></ion-icon>
+                    <ion-label>关注</ion-label>
+                </ion-button>
+            </ion-item>
+            <ion-card-title>
+                <ion-list *ngIf="they?.get('tag')?.length">
+                    <ion-note lines="none" *ngFor="let t of they?.get('tag')" class="tags">{{t}}</ion-note>
+                </ion-list>
+            </ion-card-title>
+            <ion-card-subtitle>注册时间:{{they?.get("createdAt") |date: 'YYYY/MM/dd'||"注册时间"}}</ion-card-subtitle>
+            <ion-card-subtitle>{{they?.get("gender"||"性别")}}|{{they?.get("age")||"年龄"}}|星座|地址|身份|邮箱|...</ion-card-subtitle>
+        </ion-card-header>
+        <ion-card-content>
+            简单的自我介绍...
+        </ion-card-content>
+    </ion-card>
+
+    <!-- 列表 -->
+    <ion-card class="theyLists">
+        <ion-button fill="clear">
+            <ion-icon name="restaurant-outline" color="medium"></ion-icon>
+            <ion-note>关注</ion-note>
+        </ion-button>
+        <ion-button fill="clear">
+            <ion-icon name="medal-outline" color="medium"></ion-icon>
+            <ion-note>成就</ion-note>
+        </ion-button>
+        <ion-button fill="clear">
+            <ion-icon name="extension-puzzle-outline" color="medium"></ion-icon>
+            <ion-note>收藏</ion-note>
+        </ion-button>
+    </ion-card>
+
+
+    <!-- 详细内容 -->
+    <ion-card>
+        <ion-segment value="推荐">
+            <ion-segment-button value="推荐">
+                <ion-label>推荐</ion-label>
+            </ion-segment-button>
+            <ion-segment-button value="关注">
+                <ion-label>关注</ion-label>
+            </ion-segment-button>
+            <ion-segment-button value="分享">
+                <ion-label>笔记</ion-label>
+            </ion-segment-button>
+        </ion-segment>
+    </ion-card>
+
+    <ion-item button detail="false" lines="none" class="tip">
+        <ion-label color="medium">
+            还未收藏任何东西哦
+        </ion-label>
+    </ion-item>
+
+</ion-content>

+ 25 - 0
app-angular/src/modules/lesson/they-detail/they-detail.component.scss

@@ -0,0 +1,25 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.tags {
+    margin-right: 5px;
+}
+
+.theyLists {
+    padding: 0%;
+    text-align: center;
+    justify-content: center;
+
+    ion-button {
+        ion-icon {
+            margin-right: 9px;
+        }
+    }
+}
+
+.tip {
+    ion-label {
+        text-align: center;
+    }
+}

+ 21 - 0
app-angular/src/modules/lesson/they-detail/they-detail.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TheyDetailComponent } from './they-detail.component';
+
+describe('TheyDetailComponent', () => {
+  let component: TheyDetailComponent;
+  let fixture: ComponentFixture<TheyDetailComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [TheyDetailComponent]
+    });
+    fixture = TestBed.createComponent(TheyDetailComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 39 - 0
app-angular/src/modules/lesson/they-detail/they-detail.component.ts

@@ -0,0 +1,39 @@
+import { Component } from '@angular/core';
+// 引入服务
+import { ActivatedRoute } from '@angular/router';
+
+// 引入Parse第三方库
+import * as Parse from "parse";
+(Parse as any).serverURL = "http://metapunk.cn:9999/parse"; // 设置 Parse 服务器的 URL
+Parse.initialize("dev"); // 初始化 Parse
+
+@Component({
+  selector: 'app-they-detail',
+  templateUrl: './they-detail.component.html',
+  styleUrls: ['./they-detail.component.scss']
+})
+export class TheyDetailComponent {
+  // 预设值变量
+  they: Parse.Object | undefined;
+
+  // 依赖注入
+  constructor(private route: ActivatedRoute) {
+    // 查询参数获取并赋值给 this.they
+    this.route.queryParams.subscribe(params => {
+      this.getTheyById(params["id"]); // 根据参数中的 id 获取 they 对象
+    });
+  }
+
+  async getTheyById(id: string) {
+    let query = new Parse.Query("SqzPerson"); // 创建 SqzPerson 类的查询
+    this.they = await query.get(id); // 根据 id 执行查询获取 they 对象
+  }
+
+  // getDateString(datestr: string) {
+  //   if (datestr) {
+  //     let now = new Date(datestr)
+  //     return `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`
+  //   }
+  //   return ""
+  // }
+}

+ 64 - 0
app-angular/src/modules/lesson/they/they.component.html

@@ -0,0 +1,64 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-title>
+            消息
+        </ion-title>
+        <ion-buttons slot="end">
+            <!-- 添加按钮 -->
+            <ion-button id="person-add">
+                <ion-icon name="add-outline"></ion-icon>
+            </ion-button>
+            <ion-popover trigger="person-add" triggerAction="click">
+                <ng-template>
+                    <ion-list>
+                        <ion-item button detail="false">
+                            <ion-icon name="person-add-outline" size="small"></ion-icon>
+                            <ion-text>添加</ion-text>
+                        </ion-item>
+                        <ion-item button detail="false">
+                            <ion-icon name="scan-outline" size="small"></ion-icon>
+                            <ion-text>扫一扫</ion-text>
+                        </ion-item>
+                    </ion-list>
+                </ng-template>
+            </ion-popover>
+            <!-- 搜索按钮 -->
+            <ion-button>
+                <ion-icon name="search-outline"></ion-icon>
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+
+<ion-content color="light">
+    <!-- 消息列表 -->
+    <ion-list [inset]="true">
+        <ng-container *ngFor="let they of theyList">
+            <ion-item-sliding>
+                <ion-item button detail="false">
+                    <ion-avatar slot="start">
+                        <img alt="头像" [src]="they?.get('avatar')" (click)="goTheyDetail(they)" />
+                    </ion-avatar>
+                    <ion-label>
+                        <p>{{they?.get("name")}}</p>
+                        <ion-text>聊天内容</ion-text><br />
+                    </ion-label>
+                    <div class="metadata-end-wrapper" slot="end">
+                        <ion-text color="medium">最近聊天时间</ion-text>
+                        <ion-icon color="medium" name="chevron-forward"></ion-icon>
+                    </div>
+                </ion-item>
+                <ion-item-options side="end">
+                    <ion-item-option color="danger">删除</ion-item-option>
+                </ion-item-options>
+            </ion-item-sliding>
+        </ng-container>
+    </ion-list>
+
+
+    <!-- 触底控制区域
+    <ion-infinite-scroll #infiScroll (ionInfinite)="onBottomLoad($event,infiScroll)">
+        <ion-infinite-scroll-content loadingText="Please wait..."
+            loadingSpinner="bubbles"></ion-infinite-scroll-content>
+    </ion-infinite-scroll> -->
+</ion-content>

+ 46 - 0
app-angular/src/modules/lesson/they/they.component.scss

@@ -0,0 +1,46 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+ion-item {
+    ion-icon {
+        margin-right: 9px;
+    }
+
+    font-size: 0.9rem;
+}
+
+
+/* 消息列表 */
+.metadata-end-wrapper {
+    position: absolute;
+
+    top: 10px;
+    inset-inline-end: 10px;
+
+    font-size: 0.8rem;
+
+    display: flex;
+    align-items: center;
+
+    ion-text {
+        font-size: 0.6rem
+    }
+}
+
+ion-label p {
+    font-size: 0.7rem;
+    display: block;
+    max-width: calc(100% - 60px);
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+ion-label {
+    ion-text {
+        font-size: 0.9rem;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+}

+ 21 - 0
app-angular/src/modules/lesson/they/they.component.spec.ts

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

+ 61 - 0
app-angular/src/modules/lesson/they/they.component.ts

@@ -0,0 +1,61 @@
+import { Component } from '@angular/core';
+// 引用服务
+import { Router } from '@angular/router';
+
+// 引入Parse第三方库
+import * as Parse from "parse"
+(Parse as any).serverURL = "http://metapunk.cn:9999/parse"
+Parse.initialize("dev")
+
+
+@Component({
+  selector: 'app-they',
+  templateUrl: './they.component.html',
+  styleUrls: ['./they.component.scss']
+})
+export class TheyComponent {
+
+  theyList: Array<Parse.Object> = []
+
+  // 依赖注入
+  constructor(private router: Router) {
+    this.initPage();
+  }
+  // 首次进入页面,默认加载首批数据
+  async initPage() {
+    this.theyList = await this.getTheyData()
+  }
+
+  // // 触底加载函数逻辑
+  // pageSize = 20
+  // skip: number = 0 // 跳过多少条进行加载
+  // async onBottomLoad(event: any, infiScroll: any) {
+  //   console.log("onBottomLoad", this.theyList.length)
+  //   this.skip = this.theyList.length;
+  //   let list = await this.getTheyData();
+  //   this.theyList = this.theyList.concat(list)
+  //   infiScroll?.complete();
+  // }
+
+  // 数据加载相关函数
+  async getTheyData() {
+    let query = new Parse.Query("SqzPerson");
+    query.addAscending("createdAt")
+    let list = await query.find();
+    return list
+  }
+
+  // 跳转函数
+  goTheyDetail(they: Parse.Object) {
+    this.router.navigate(["/lesson/they/detail"], {
+      queryParams: they
+    })
+  }
+}
+
+
+
+
+
+
+

+ 38 - 0
app-angular/src/modules/lesson/user-collection/user-collection.component.html

@@ -0,0 +1,38 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/me" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon></ion-button>
+        </ion-buttons>
+        <ion-segment value="推荐">
+            <ion-segment-button value="推荐">
+                <ion-label>推荐</ion-label>
+            </ion-segment-button>
+            <ion-segment-button value="关注">
+                <ion-label>关注</ion-label>
+            </ion-segment-button>
+            <ion-segment-button value="分享">
+                <ion-label>笔记</ion-label>
+            </ion-segment-button>
+        </ion-segment>
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <ion-item>
+        <ion-buttons slot="end">
+            <ion-button color="dark">
+                <ion-icon name="search-outline"></ion-icon>
+                搜索
+            </ion-button>
+            <ion-button color="dark">
+                <ion-icon name="create-outline"></ion-icon>
+                编辑
+            </ion-button>
+        </ion-buttons>
+    </ion-item>
+    <ion-item button detail="false" lines="none" class="tip">
+        <ion-label color="medium">
+            还未收藏任何东西哦
+        </ion-label>
+    </ion-item>
+</ion-content>

+ 9 - 0
app-angular/src/modules/lesson/user-collection/user-collection.component.scss

@@ -0,0 +1,9 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+.tip {
+    ion-label {
+        text-align: center;
+    }
+}

+ 21 - 0
app-angular/src/modules/lesson/user-collection/user-collection.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UserCollectionComponent } from './user-collection.component';
+
+describe('UserCollectionComponent', () => {
+  let component: UserCollectionComponent;
+  let fixture: ComponentFixture<UserCollectionComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [UserCollectionComponent]
+    });
+    fixture = TestBed.createComponent(UserCollectionComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 10 - 0
app-angular/src/modules/lesson/user-collection/user-collection.component.ts

@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-user-collection',
+  templateUrl: './user-collection.component.html',
+  styleUrls: ['./user-collection.component.scss']
+})
+export class UserCollectionComponent {
+
+}

+ 56 - 0
app-angular/src/modules/lesson/user-follow/user-follow.component.html

@@ -0,0 +1,56 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/me" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>返回</ion-button>
+        </ion-buttons>
+        <ion-buttons slot="end">
+            <ion-button fill="clear" color="dark">
+                <ion-icon name="person-add-outline"></ion-icon>
+            </ion-button>
+
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <ion-list [inset]="true">
+        <ion-item-group>
+            <ion-item-divider>
+                <ion-icon name="people"></ion-icon>
+                <ion-label>关注列表:</ion-label>
+            </ion-item-divider>
+            <ng-container>
+                <ion-item button detail="false" lines="full">
+                    <ion-avatar slot="start">
+                        <img alt="头像" src="https://ionicframework.com/docs/img/demos/avatar.svg" />
+                    </ion-avatar>
+                    <ion-label>
+                        <p>昵称</p>
+                        <ion-badge slot="start">标签</ion-badge>
+                    </ion-label>
+                    <ion-buttons slot="end">
+                        <ion-button fill="clear" color="dark">
+                            <ion-icon name="chatbox-ellipses-outline"></ion-icon>
+                            发消息
+                        </ion-button>
+                    </ion-buttons>
+                </ion-item>
+            </ng-container>
+            <ion-item button detail="false" lines="full">
+                <ion-avatar slot="start">
+                    <img alt="头像" src="https://ionicframework.com/docs/img/demos/avatar.svg" />
+                </ion-avatar>
+                <ion-label>
+                    <p>昵称</p>
+                    <ion-badge slot="start">标签</ion-badge>
+                </ion-label>
+                <ion-buttons slot="end">
+                    <ion-button fill="clear" color="dark">
+                        <ion-icon name="chatbox-ellipses-outline"></ion-icon>
+                        发消息
+                    </ion-button>
+                </ion-buttons>
+            </ion-item>
+        </ion-item-group>
+    </ion-list>
+</ion-content>

+ 31 - 0
app-angular/src/modules/lesson/user-follow/user-follow.component.scss

@@ -0,0 +1,31 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+ion-item-divider {
+    ion-icon {
+        margin-right: 9px;
+    }
+}
+
+ion-label p {
+    display: block;
+    max-width: calc(100% - 60px);
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+ion-label {
+    ion-text {
+        font-size: 0.9rem;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+}
+
+ion-button {
+    ion-icon {
+        margin-right: 3px;
+    }
+}

+ 21 - 0
app-angular/src/modules/lesson/user-follow/user-follow.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UserFollowComponent } from './user-follow.component';
+
+describe('UserFollowComponent', () => {
+  let component: UserFollowComponent;
+  let fixture: ComponentFixture<UserFollowComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [UserFollowComponent]
+    });
+    fixture = TestBed.createComponent(UserFollowComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 10 - 0
app-angular/src/modules/lesson/user-follow/user-follow.component.ts

@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-user-follow',
+  templateUrl: './user-follow.component.html',
+  styleUrls: ['./user-follow.component.scss']
+})
+export class UserFollowComponent {
+
+}

+ 62 - 0
app-angular/src/modules/lesson/user-tag/user-tag.component.html

@@ -0,0 +1,62 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button routerLink="/lesson/me" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>返回</ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <ion-list [inset]="true">
+        <ion-item-group>
+            <ion-item-divider>
+                <ion-icon name="medal"></ion-icon>
+                <ion-label>成就列表:</ion-label>
+            </ion-item-divider>
+            <ion-segment>
+                <ion-segment-button value="已得" (click)="cate='已得'">
+                    <ion-label>已得</ion-label>
+                </ion-segment-button>
+                <ion-segment-button value="未获" (click)="cate='未获'">
+                    <ion-label>未获</ion-label>
+                </ion-segment-button>
+            </ion-segment>
+            <ng-container *ngIf="cate=='未获'">
+                <ion-item button detail="false" lines="full">
+                    <ion-label>
+                        <p>
+                            未获标签成就
+                        </p>
+                        <ion-note>
+                            获取条件
+                        </ion-note>
+                    </ion-label>
+                    <ion-buttons slot="end">
+                        <ion-button color="medium">
+                            <ion-icon name="heart-circle" size="large"></ion-icon>
+                        </ion-button>
+                    </ion-buttons>
+                </ion-item>
+            </ng-container>
+            <ng-container *ngIf="cate=='已得'">
+                <ion-item button detail="false" lines="full">
+                    <ion-label>
+                        <p>
+                            已得标签成就
+                        </p>
+                        <ion-note>
+                            获取条件
+                        </ion-note>
+                    </ion-label>
+                    <ion-buttons slot="end">
+                        <ion-button color="danger">
+                            <ion-icon name="heart-circle" size="large"></ion-icon>
+                        </ion-button>
+                    </ion-buttons>
+                </ion-item>
+            </ng-container>
+
+        </ion-item-group>
+    </ion-list>
+
+</ion-content>

+ 18 - 0
app-angular/src/modules/lesson/user-tag/user-tag.component.scss

@@ -0,0 +1,18 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+ion-item-divider {
+    ion-icon {
+        margin-right: 9px;
+    }
+}
+
+ion-label {
+    ion-note {
+        font-size: 0.7rem;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+}

+ 21 - 0
app-angular/src/modules/lesson/user-tag/user-tag.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UserTagComponent } from './user-tag.component';
+
+describe('UserTagComponent', () => {
+  let component: UserTagComponent;
+  let fixture: ComponentFixture<UserTagComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [UserTagComponent]
+    });
+    fixture = TestBed.createComponent(UserTagComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 10 - 0
app-angular/src/modules/lesson/user-tag/user-tag.component.ts

@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-user-tag',
+  templateUrl: './user-tag.component.html',
+  styleUrls: ['./user-tag.component.scss']
+})
+export class UserTagComponent {
+  cate: string = "已得"
+}

+ 17 - 0
app-angular/src/modules/user/guard-auth/auth.guard.spec.ts

@@ -0,0 +1,17 @@
+import { TestBed } from '@angular/core/testing';
+import { CanActivateFn } from '@angular/router';
+
+import { authGuard } from './auth.guard';
+
+describe('authGuard', () => {
+  const executeGuard: CanActivateFn = (...guardParameters) => 
+      TestBed.runInInjectionContext(() => authGuard(...guardParameters));
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+  });
+
+  it('should be created', () => {
+    expect(executeGuard).toBeTruthy();
+  });
+});

+ 20 - 0
app-angular/src/modules/user/guard-auth/auth.guard.ts

@@ -0,0 +1,20 @@
+import { CanActivateFn } from '@angular/router';
+import * as Parse from "parse";
+
+export const authGuard: CanActivateFn = (route, state) => {
+  // 检查当前本地存储中,是否有用户验证信息
+  let userAuth = Parse.User.current();
+  if (userAuth?.id) {
+    return true;
+  } else {
+    // 暂时存储登陆前用户所在页面
+    let REDIRECT_URL = location.pathname;
+    localStorage.setItem("REDIRECT_URL", REDIRECT_URL);
+    if (location.pathname?.startsWith("/s0210463")) {
+      location.href = "/s0210463/user/login"
+    } else {
+      location.href = "/user/login"
+    }
+    return false;
+  }
+};

+ 31 - 0
app-angular/src/modules/user/page-info/page-info.component.html

@@ -0,0 +1,31 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button routerLink="/lesson/me" fill="clear" color="dark">
+        <ion-icon name="chevron-back-outline" size="small"></ion-icon>
+        <ion-note>返回</ion-note>
+      </ion-button>
+    </ion-buttons>
+
+  </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+  <ion-card>
+    <ion-list>
+      <ion-item>
+        <ion-input [(ngModel)]="userInfo.name" label="昵称:"></ion-input>
+      </ion-item>
+      <ion-item>
+        <ion-input [(ngModel)]="userInfo.tag" label="标签:"></ion-input>
+      </ion-item>
+      <ion-item>
+        <ion-input [(ngModel)]="userInfo.desc" label="签名:"></ion-input>
+      </ion-item>
+    </ion-list>
+  </ion-card>
+
+  <ion-list [inset]="true">
+    <ion-button expand="block" (click)="saveInfo()">保存</ion-button>
+  </ion-list>
+
+</ion-content>

+ 10 - 0
app-angular/src/modules/user/page-info/page-info.component.scss

@@ -0,0 +1,10 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}
+
+ion-item {
+    ion-input {
+        color: rgb(95, 93, 90);
+        font-size: 0.9rem;
+    }
+}

+ 21 - 0
app-angular/src/modules/user/page-info/page-info.component.spec.ts

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

+ 35 - 0
app-angular/src/modules/user/page-info/page-info.component.ts

@@ -0,0 +1,35 @@
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { UserService } from '../service-user/user.service';
+import * as Parse from "parse";
+
+@Component({
+  selector: 'app-page-info',
+  templateUrl: './page-info.component.html',
+  styleUrls: ['./page-info.component.scss']
+})
+export class PageInfoComponent {
+  constructor(
+    public userServ: UserService, // 用户服务
+    private router: Router // 路由器
+  ) {
+    this.userInfo = Parse.User.current()?.toJSON(); // 获取当前用户信息
+  }
+
+  userInfo: any = {}; // 用户信息对象
+
+  async saveInfo() {
+    let user = Parse.User.current(); // 获取当前用户实例
+    console.log(this.userInfo); // 打印用户信息
+
+    // 删除不需要保存的属性
+    delete this.userInfo.objectId;
+    delete this.userInfo.username;
+    delete this.userInfo.sessionToken;
+    delete this.userInfo.updatedAt;
+
+    user?.set(this.userInfo); // 设置用户实例属性
+    await user?.save(); // 保存用户实例到数据库
+    this.router.navigate(["/lesson/me"]); // 导航到指定路由
+  }
+}

+ 55 - 0
app-angular/src/modules/user/page-login/page-login.component.html

@@ -0,0 +1,55 @@
+<!-- IonicModule + FormsModule实现,默认好看 -->
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons slot="start">
+            <ion-button (click)="goBack()" fill="clear" color="dark">
+                <ion-icon name="chevron-back-outline" size="small"></ion-icon>返回
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+
+    <div class="login-modal">
+        <ion-card>
+            <ion-card-header>
+                <ion-card-title>登录</ion-card-title>
+                <ion-card-subtitle>该页面需登陆可继续使用</ion-card-subtitle>
+            </ion-card-header>
+
+            <ion-card-content>
+                <ion-input [(ngModel)]="userData.username" placeholder="账号/手机" [clearInput]="true" [counter]="true"
+                    maxlength="11">
+                </ion-input>
+                <ion-input [(ngModel)]="userData.password" placeholder="密码" [clearInput]="true" [counter]="true"
+                    maxlength="20" type="password">
+                </ion-input>
+            </ion-card-content>
+            <ion-button expand="block" (click)="login()">登录</ion-button>
+        </ion-card>
+    </div>
+    <ion-list [inset]="true">
+        <ion-item>
+            <ion-label class="register-modal">
+                未有账号?选择:ヘ(_ _ヘ)<ion-button fill="outline" color="dark" (click)="goRegister()" class="register">
+                    注册一下
+                </ion-button>
+            </ion-label>
+        </ion-item>
+    </ion-list>
+</ion-content>
+
+
+<!-- 纯HTML + FormsModule实现,可任意定制样式 -->
+<ng-container *ngIf="false">
+
+    请输入用户名:{{userData.username}} <br />
+
+    <input [(ngModel)]="userData.username" type="text" /><br />
+
+    请输入密码:{{userData.password}}<br />
+    <input [(ngModel)]="userData.password" type="password" /><br />
+
+    <button (click)="login()">登录</button>
+
+</ng-container>

+ 21 - 0
app-angular/src/modules/user/page-login/page-login.component.scss

@@ -0,0 +1,21 @@
+.login-modal {
+    width: 100vw;
+    display: flex;
+    flex-direction: column;
+    vertical-align: middle;
+}
+
+.register-modal {
+    display: flex;
+    flex-direction: column;
+    vertical-align: middle;
+
+}
+
+.register {
+    font-size: 0.9rem;
+}
+
+ion-content {
+    height: calc(100vh - 121px) !important;
+}

+ 21 - 0
app-angular/src/modules/user/page-login/page-login.component.spec.ts

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

+ 56 - 0
app-angular/src/modules/user/page-login/page-login.component.ts

@@ -0,0 +1,56 @@
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { AlertController } from '@ionic/angular';
+import { UserService } from '../service-user/user.service';
+
+@Component({
+  selector: 'app-page-login',
+  templateUrl: './page-login.component.html',
+  styleUrls: ['./page-login.component.scss']
+})
+export class PageLoginComponent {
+
+  constructor(
+    private userServ: UserService,
+    private router: Router,
+    private alertCtrl: AlertController
+  ) { }
+  userData: any = {
+    username: "",
+    password: ""
+  }
+
+  goBack() {
+    let path = localStorage.getItem("REDIRECT_URL") || "/lesson/me"
+    this.router.navigate([path])
+  }
+
+  goRegister() {
+    let path = "/user/register"
+    this.router.navigate([path])
+
+  }
+
+  async login() {
+    console.log(this.userData)
+    try {
+      let isLogin = await this.userServ.checkUserPassword(this.userData)
+      if (isLogin) {
+        this.goBack()
+      }
+    } catch (err) {
+      let msg: any = err
+      this.alertError(msg)
+    }
+  }
+  async alertError(err: string | undefined) {
+    const alert = await this.alertCtrl.create({
+      header: '登陆失败',
+      subHeader: '请检查用户名密码',
+      message: err,
+      buttons: ['好的'],
+    });
+
+    await alert.present();
+  }
+}

+ 35 - 0
app-angular/src/modules/user/page-register/page-register.component.html

@@ -0,0 +1,35 @@
+<ion-header>
+    <ion-toolbar>
+        <ion-buttons>
+            <ion-button (click)="goBack()" fill="clear" color="dark">
+                <ion-icon name="arrow-back-outline" size="large"></ion-icon>
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+<ion-content color="light">
+    <div class="register-modal">
+        <ion-list [inset]="true">
+            <ion-item lines="none">
+                <ion-label>
+                    <strong>
+                        填写注册信息:
+                    </strong>
+                </ion-label>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-input placeholder="昵称" [clearInput]="true" [counter]="true" maxlength="10">
+                </ion-input>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-input placeholder="账号/手机" [clearInput]="true" [counter]="true" maxlength="11">
+                </ion-input>
+            </ion-item>
+            <ion-item lines="none">
+                <ion-input placeholder="密码" [clearInput]="true" [counter]="true" maxlength="20" type="password">
+                </ion-input>
+            </ion-item>
+            <ion-button expand="block">确定</ion-button>
+        </ion-list>
+    </div>
+</ion-content>

+ 3 - 0
app-angular/src/modules/user/page-register/page-register.component.scss

@@ -0,0 +1,3 @@
+ion-content {
+    height: calc(100vh - 121px) !important;
+}

+ 21 - 0
app-angular/src/modules/user/page-register/page-register.component.spec.ts

@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PageRegisterComponent } from './page-register.component';
+
+describe('PageRegisterComponent', () => {
+  let component: PageRegisterComponent;
+  let fixture: ComponentFixture<PageRegisterComponent>;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      declarations: [PageRegisterComponent]
+    });
+    fixture = TestBed.createComponent(PageRegisterComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 20 - 0
app-angular/src/modules/user/page-register/page-register.component.ts

@@ -0,0 +1,20 @@
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+
+@Component({
+  selector: 'app-page-register',
+  templateUrl: './page-register.component.html',
+  styleUrls: ['./page-register.component.scss']
+})
+export class PageRegisterComponent {
+  constructor(
+    private router: Router,
+  ) { }
+
+
+  goBack() {
+    let path = "/user/login"
+    this.router.navigate([path])
+  }
+
+}

+ 16 - 0
app-angular/src/modules/user/service-user/user.service.spec.ts

@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { UserService } from './user.service';
+
+describe('UserService', () => {
+  let service: UserService;
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+    service = TestBed.inject(UserService);
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+});

+ 32 - 0
app-angular/src/modules/user/service-user/user.service.ts

@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import * as Parse from "parse";
+
+@Injectable({
+  providedIn: 'root'
+})
+export class UserService {
+  get currentUser() {
+    try {
+      let currentUser = JSON.parse(localStorage.getItem("USER_AUTH") || ""); // 从本地存储中获取当前用户信息
+      return currentUser;
+    } catch (err) { }
+    return {};
+  }
+
+  set currentUser(v) {
+    localStorage.setItem("USER_AUTH", JSON.stringify(v)); // 将当前用户信息存储到本地存储中
+  }
+
+  constructor() { }
+
+  async checkUserPassword(user: {
+    username: string;
+    password: string;
+  }) {
+    let exists = await Parse.User.logIn(user?.username, user?.password); // 使用 Parse.User.logIn() 方法验证用户的用户名和密码
+    if (exists?.id) {
+      return true; // 如果验证成功,返回 true
+    }
+    return false; // 如果验证失败,返回 false
+  }
+}

+ 21 - 0
app-angular/src/modules/user/user-routing.module.ts

@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { authGuard } from './guard-auth/auth.guard';
+import { PageInfoComponent } from './page-info/page-info.component';
+import { PageLoginComponent } from './page-login/page-login.component';
+import { PageRegisterComponent } from './page-register/page-register.component';
+
+const routes: Routes = [
+  {path:"login",component:PageLoginComponent},
+  {path:"register",component:PageRegisterComponent},
+  {
+    path:"info",component:PageInfoComponent,
+    canActivate:[authGuard]
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class UserRoutingModule { }

+ 25 - 0
app-angular/src/modules/user/user.module.ts

@@ -0,0 +1,25 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { UserRoutingModule } from './user-routing.module';
+import { PageLoginComponent } from './page-login/page-login.component';
+import { PageRegisterComponent } from './page-register/page-register.component';
+import { PageInfoComponent } from './page-info/page-info.component';
+import { FormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+
+
+@NgModule({
+  declarations: [
+    PageLoginComponent,
+    PageRegisterComponent,
+    PageInfoComponent
+  ],
+  imports: [
+    CommonModule,
+    UserRoutingModule,
+    FormsModule,
+    IonicModule,
+  ]
+})
+export class UserModule { }

+ 1 - 1
docs/product.md

@@ -37,7 +37,7 @@
 -  媒体和赞助商的关注:
    宠物猫产业受到了广泛的媒体关注,尤其是社交媒体平台。猫咪相关的视频、图片和故事在社交媒体上经常引起热议,吸引了大量的粉丝和关注者。这种媒体关注为宠物猫产业带来了更多的曝光度和市场机会。同时,媒体的关注也吸引了赞助商的兴趣,他们愿意在相关的活动、比赛和展览中提供赞助,进一步推动了宠物猫产业的发展。
 
-- 宠物猫市场的增长:宠物猫在许多人的生活中扮演着重要的角色,被视为家庭成员的一部分。随着人们对宠物的情感需求不断增加,宠物猫市场呈现出稳定的增长态势。尤其是年轻人,他们越来越倾向于养宠物猫来陪伴他们的生活。这为喵星球App提供了广阔的市场机会。
+- 宠物猫市场的增长:宠物猫在许多人的生活中扮演着重要的关注,被视为家庭成员的一部分。随着人们对宠物的情感需求不断增加,宠物猫市场呈现出稳定的增长态势。尤其是年轻人,他们越来越倾向于养宠物猫来陪伴他们的生活。这为喵星球App提供了广阔的市场机会。
 
 - 经济效益的增加:
    宠物猫产业不仅仅是宠物猫的销售,还包括宠物用品、医疗服务、宠物食品等相关产业。这些产业的发展带动了宠物猫产业的整体经济效益。例如,宠物用品市场的扩大促进了宠物猫用品的创新和生产,增加了相关企业的收入和就业机会。医疗服务的需求也在增加,为宠物医院和兽医提供了商机。宠物食品市场也在不断扩大,为食品生产商和销售商带来了商机。这些经济效益的增加进一步促进了宠物猫产业的发展。

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor