Browse Source

Merge branch 'master' of http://git.fmode.cn:3000/yuebuzu/s202226701018

yuebuzu-creater 4 tháng trước cách đây
mục cha
commit
f56f20ed0f

+ 21 - 0
wisdom-app/src/app/page/change-key/change-key.component.html

@@ -0,0 +1,21 @@
+<!-- 用户登录状态 -->
+<div class="divback">
+<ion-card>
+  <ion-card-header>
+    <ion-card-title>
+      用户名:{{currentUser?.get("username")}}
+    </ion-card-title>
+    <ion-card-subtitle>您可修改您的密码</ion-card-subtitle>
+   </ion-card-header>
+ <ion-card-content>
+
+   <ion-item>
+     <ion-input [value]="userData['password']" (ionChange)="userDataChange('password',$event)" label="新密码" placeholder="请您输入新的密码"></ion-input>
+   </ion-item>
+
+   <ion-button expand="block" (click)="save()">修改</ion-button>
+   <ion-button expand="block" (click)="cancel()">取消</ion-button>
+ 
+</ion-card-content>
+</ion-card>
+</div>

+ 65 - 0
wisdom-app/src/app/page/change-key/change-key.component.scss

@@ -0,0 +1,65 @@
+    .divback{
+        width: 100%;
+        height: 100%;
+        background-image: url('https://app.fmode.cn/dev/jxnu/202226701019/zhuti1.jpg');
+        background-size: cover;
+        background-position: center;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+    }
+ion-card {
+    opacity: 0.8;
+    margin: 0 auto; /* 使卡片居中 */
+    max-width: 400px; /* 设置卡片的最大宽度 */
+    border-radius: 10px; /* 设置卡片的圆角 */
+    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
+  }
+  
+  ion-card-header {
+    background-color: #f8f9fa; /* 设置卡片头部的背景颜色 */
+    border-top-left-radius: 10px; /* 圆角 */
+    border-top-right-radius: 10px; /* 圆角 */
+    padding: 16px; /* 内边距 */
+  }
+  
+  ion-card-title {
+    font-size: 1.5em; /* 设置标题字体大小 */
+    font-weight: bold; /* 加粗标题 */
+  }
+  
+  ion-card-subtitle {
+    font-size: 1em; /* 设置副标题字体大小 */
+    color: #6c757d; /* 设置副标题颜色 */
+  }
+  
+  ion-card-content {
+    padding: 16px; /* 内边距 */
+    background-color: #ffffff; /* 设置卡片内容的背景颜色 */
+  }
+  
+  ion-item {
+    margin-bottom: 16px; /* 添加底部间距 */
+  }
+  
+  ion-button {
+    margin-top: 8px; /* 添加顶部间距 */
+    --background: #3880ff; /* 设置按钮背景颜色 */
+    --color: white; /* 设置按钮文字颜色 */
+  }
+  
+  ion-button:hover {
+    --background: #3171e0; /* 鼠标悬停时的背景颜色 */
+  }
+  
+  ion-button:active {
+    --background: #2c6bbf; /* 按钮按下时的背景颜色 */
+  }
+  
+  /* 全局样式,确保卡片在页面中居中 */
+  ion-content {
+    display: flex; /* 使用 Flexbox 布局 */
+    justify-content: center; /* 水平居中 */
+    align-items: center; /* 垂直居中 */
+    height: 100%; /* 设置内容高度为 100% */
+  }

+ 22 - 0
wisdom-app/src/app/page/change-key/change-key.component.spec.ts

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

+ 49 - 0
wisdom-app/src/app/page/change-key/change-key.component.ts

@@ -0,0 +1,49 @@
+import {  OnInit } from '@angular/core';
+import { Component } from '@angular/core';
+import { Router } from '@angular/router';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, IonInput, IonItem, IonSegment, IonSegmentButton, IonLabel } from '@ionic/angular/standalone';
+import { CloudUser } from 'src/lib/ncloud';
+
+@Component({
+  selector: 'app-change-key-edit',
+  templateUrl: './change-key.component.html',
+  styleUrls: ['./change-key.component.scss'],
+  standalone: true,
+  imports: [IonHeader, IonToolbar, IonTitle, IonContent, 
+    IonCard,IonCardContent,IonButton,IonCardHeader,IonCardTitle,IonCardSubtitle,
+    IonInput,IonItem,
+    IonSegment,IonSegmentButton,IonLabel
+  ],
+})
+export class ChangeKeyComponent  implements OnInit {
+
+  currentUser:CloudUser|undefined
+  userData:any = {}
+  userDataChange(key:string,ev:any){
+    let value = ev?.detail?.value
+    if(value){
+      this.userData[key] = value
+    }
+  }
+  constructor(
+    private router: Router,
+    private modalCtrl:ModalController) { 
+    this.currentUser = new CloudUser();
+    this.userData = this.currentUser.data;
+  }
+
+  ngOnInit() {}
+
+  async save(){
+  
+    this.currentUser?.set(this.userData)
+    await this.currentUser?.save()
+    this.modalCtrl.dismiss(this.currentUser,"confirm")
+
+    this.router.navigate(['/tabs/tab4'])
+  }
+  cancel(){
+    this.modalCtrl.dismiss(null,"cancel")
+    this.router.navigate(['/tabs/tab4'])
+  }
+}

+ 29 - 0
wisdom-app/src/app/page/feedback-help/feedback-help.component.html

@@ -0,0 +1,29 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>反馈与帮助</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-list>
+    <ion-item *ngFor="let question of questions" (click)="openDetail(question)">
+      {{ question.title }}
+    </ion-item>
+  </ion-list>
+
+  <ion-modal [isOpen]="isModalOpen" (didDismiss)="isModalOpen = false">
+    <ng-template ionModalContent>
+      <ion-header>
+        <ion-toolbar>
+          <ion-title>{{ selectedQuestion?.title }}</ion-title>
+          <ion-buttons slot="end">
+            <ion-button (click)="isModalOpen = false">关闭</ion-button>
+          </ion-buttons>
+        </ion-toolbar>
+      </ion-header>
+      <ion-content>
+        <p>{{ selectedQuestion?.detail }}</p>
+      </ion-content>
+    </ng-template>
+  </ion-modal>
+</ion-content>

+ 7 - 0
wisdom-app/src/app/page/feedback-help/feedback-help.component.scss

@@ -0,0 +1,7 @@
+ion-list {
+  margin: 10px;
+}
+
+ion-item {
+  cursor: pointer;
+}

+ 22 - 0
wisdom-app/src/app/page/feedback-help/feedback-help.component.spec.ts

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

+ 37 - 0
wisdom-app/src/app/page/feedback-help/feedback-help.component.ts

@@ -0,0 +1,37 @@
+import { Component, OnInit } from '@angular/core';
+import { IonicModule } from '@ionic/angular';
+import { CommonModule } from '@angular/common';
+import { Router } from '@angular/router';
+
+@Component({
+  selector: 'feedback-help',
+  templateUrl: './feedback-help.component.html',
+  styleUrls: ['./feedback-help.component.scss'],
+  imports:[IonicModule,
+    CommonModule
+  ],
+  standalone: true,
+})
+export class FeedbackHelpComponent  implements OnInit {
+
+  constructor(
+    private router: Router
+  ) { }
+
+  ngOnInit() {}
+
+  isModalOpen = false;
+  selectedQuestion: any = null;
+
+  questions = [
+    { title: '如何重置密码?', detail: '您可以通过点击“忘记密码”链接来重置您的密码。' },
+    { title: '如何联系客服?', detail: '您可以通过应用内的“联系客服”功能与我们的客服团队联系。' },
+    { title: '如何更新个人信息?', detail: '点击我的信息或者头像,您可以编辑和更新您的个人信息。' },
+    { title: '如何查看订单历史?', detail: '在“我的订单”页面,您可以查看所有的订单历史记录。' },
+  ];
+
+  openDetail(question: any) {
+    this.selectedQuestion = question;
+    this.isModalOpen = true;
+  }
+}

+ 100 - 170
wisdom-app/src/app/tab2/tab2.page.html

@@ -1,173 +1,96 @@
 <ion-header [translucent]="true">
   <ion-toolbar class="custom-toolbar">
-    <div class="search-bar" >
-      <ion-searchbar 
-      placeholder="搜索" 
-      class="custom-searchbar" 
-      (ionInput)="searchProducts($event)">
+    <div class="search-bar">
+      <ion-searchbar
+        placeholder="搜索"
+        class="custom-searchbar"
+        (ionInput)="searchProducts($event)">
       </ion-searchbar>
     </div>
-    @if(!searchTerm){
-      
-    <div class="header">
-      <ion-card-header>
-        
-        <ion-card-title>
-          <ion-segment [(ngModel)]="selectedSegment" (ionChange)="segmentChanged($event)" scrollable>
-            <ion-segment-button *ngFor="let segment of segments" [value]="segment">
-              {{segment}}
-            </ion-segment-button>
-          </ion-segment>
-          <!-- <ion-segment [scrollable]="true" value="HotDot" [value]="type" (ionChange)="typeChange($event)">
-            <ion-segment-button value="HotDot" content-id="HotDot">
-              <ion-label>热点</ion-label>
-            </ion-segment-button>
-            <ion-segment-button value="export" content-id="export">
-              <ion-label>专家科普</ion-label>
-            </ion-segment-button>
-            <ion-segment-button value="sleep" content-id="sleep">
-              <ion-label>睡眠</ion-label>
-            </ion-segment-button>
-            <ion-segment-button value="life" content-id="life">
-              <ion-label>生活</ion-label>
-            </ion-segment-button>
-            <ion-segment-button value="男" content-id="male">
-              <ion-label>男性</ion-label>
-            </ion-segment-button>
-            <ion-segment-button value="女" content-id="female">
-              <ion-label>女性</ion-label>
-            </ion-segment-button>
-          </ion-segment> -->
-        </ion-card-title>
-      </ion-card-header>
-    </div>
-  }
+    <ng-container *ngIf="!searchTerm">
+      <div class="header">
+        <ion-card-header>
+          <ion-card-title>
+            <ion-segment
+              [(ngModel)]="selectedSegment"
+              (ionChange)="segmentChanged($event)"
+              scrollable>
+              <ion-segment-button
+                *ngFor="let segment of segments"
+                [value]="segment">
+                {{ segment }}
+              </ion-segment-button>
+            </ion-segment>
+          </ion-card-title>
+        </ion-card-header>
+      </div>
+    </ng-container>
   </ion-toolbar>
 </ion-header>
 
 <ion-content class="knowledge" [fullscreen]="true">
-  @if(!searchTerm){
+  <ion-loading
+    *ngIf="isLoading"
+    message="加载中...">
+  </ion-loading>
+
+<ion-content class="knowledge" [fullscreen]="true">
+  <ng-container *ngIf="!searchTerm; else searchResults">
     <div class="content">
       <ion-card>
-        <ion-card-header></ion-card-header>
         <ion-card-content>
-          <!-- <ion-segment-view>
-            <ion-segment-content id="HotDot"> -->
-              <!-- 轮播图区域 -->
-              <div class="carousel-container" style="border-radius: 0px; margin: 0px auto;">
-                <div class="carousel" [style.transform]="'translateX(-' + currentSlide * 100 + '%)'">
-                  <div class="slide" *ngFor="let image of images">
-                    <img [src]="image" alt="轮播图" height="100px" >
-                  </div>
-                </div>
-              
-                <button class="prev" (click)="prevSlide()">&#10094;</button>
-                <button class="next" (click)="nextSlide()">&#10095;</button>
-              
-                <div class="dots">
-                  <span class="dot" *ngFor="let image of images; let i = index" 
-                        [class.active]="i === currentSlide" 
-                        (click)="goToSlide(i)"></span>
-                </div>
-              </div>
-              <app-article-card (click)="openDetailModal(card)" *ngFor="let card of cards" [card]="card"></app-article-card>
-            <!-- </ion-segment-content> -->
-  
-            <!-- <ion-segment-content id="export">
-              <app-article-card (click)="openDetailModal(card)" *ngFor="let card of cards" [card]="card"></app-article-card>
-            </ion-segment-content>
-  
-            <ion-segment-content id="sleep"> -->
-              <!-- 轮播图区域 -->
-              <!-- <div class="carousel-container" style="border-radius: 0px; margin: 0px auto;">
-                <div class="carousel" [style.transform]="'translateX(-' + currentSlide * 100 + '%)'">
-                  <div class="slide" *ngFor="let image of images">
-                    <img [src]="image" alt="轮播图" height="100px" >
-                  </div>
-                </div>
-              
-                <button class="prev" (click)="prevSlide()">&#10094;</button>
-                <button class="next" (click)="nextSlide()">&#10095;</button>
-              
-                <div class="dots">
-                  <span class="dot" *ngFor="let image of images; let i = index" 
-                        [class.active]="i === currentSlide" 
-                        (click)="goToSlide(i)"></span>
-                </div>
-              </div>
-              <app-article-card (click)="openDetailModal(card)" *ngFor="let card of cards" [card]="card"></app-article-card>
-            </ion-segment-content>
-  
-            <ion-segment-content id="life">
-              <app-article-card (click)="openDetailModal(card)" *ngFor="let card of cards" [card]="card"></app-article-card>
-            </ion-segment-content>
-            <ion-segment-content id="male"> -->
-              <!-- 轮播图区域 -->
-              <!-- <div class="carousel-container" style="border-radius: 0px; margin: 0px auto;">
-                <div class="carousel" [style.transform]="'translateX(-' + currentSlide * 100 + '%)'">
-                  <div class="slide" *ngFor="let image of images">
-                    <img [src]="image" alt="轮播图" height="100px" >
-                  </div>
-                </div>
-              
-                <button class="prev" (click)="prevSlide()">&#10094;</button>
-                <button class="next" (click)="nextSlide()">&#10095;</button>
-              
-                <div class="dots">
-                  <span class="dot" *ngFor="let image of images; let i = index" 
-                        [class.active]="i === currentSlide" 
-                        (click)="goToSlide(i)"></span>
-                </div>
+          <!-- 轮播图区域 -->
+          <div class="carousel-container">
+            <div class="carousel" [style.transform]="'translateX(-' + currentSlide * 100 + '%)'">
+              <div class="slide" *ngFor="let image of images; trackBy: trackByIndex">
+                <img [src]="image" alt="轮播图" />
               </div>
-              <app-article-card (click)="openDetailModal(card)" *ngFor="let card of cards" [card]="card"></app-article-card>
-            </ion-segment-content>
-            <ion-segment-content id="female"> -->
-              <!-- 轮播图区域 -->
-              <!-- <div class="carousel-container" style="border-radius: 0px; margin: 0px auto;">
-                <div class="carousel" [style.transform]="'translateX(-' + currentSlide * 100 + '%)'">
-                  <div class="slide" *ngFor="let image of images">
-                    <img [src]="image" alt="轮播图" height="100px" >
-                  </div>
-                </div>
-              
-                <button class="prev" (click)="prevSlide()">&#10094;</button>
-                <button class="next" (click)="nextSlide()">&#10095;</button>
-              
-                <div class="dots">
-                  <span class="dot" *ngFor="let image of images; let i = index" 
-                        [class.active]="i === currentSlide" 
-                        (click)="goToSlide(i)"></span>
-                </div>
-              </div>
-              <app-article-card (click)="openDetailModal(card)" *ngFor="let card of cards" [card]="card"></app-article-card>
-            </ion-segment-content>
-          </ion-segment-view> -->
+            </div>
+            <button class="prev" (click)="prevSlide()">&#10094;</button>
+            <button class="next" (click)="nextSlide()">&#10095;</button>
+            <div class="dots">
+              <span
+                class="dot"
+                *ngFor="let image of images; let i = index"
+                [class.active]="i === currentSlide"
+                (click)="goToSlide(i)">
+              </span>
+            </div>
+          </div>
+          <!-- 文章卡片区域 -->
+          <app-article-card
+            *ngFor="let card of cards; trackBy: trackById"
+            [card]="card"
+            (click)="openDetailModal(card)">
+          </app-article-card>
         </ion-card-content>
       </ion-card>
     </div>
-  }
-  @if(searchTerm){
+  </ng-container>
+
+  <!-- 搜索结果 -->
+  <ng-template #searchResults>
     <div>
-      <app-article-card (click)="openDetailModal(product)" *ngFor="let product of products" [card]="product"></app-article-card>
-    </div>
-    @if (products.length == 0) {
-      <div class="no-results" style="margin: 50px auto;">
-        <h2>寻找中···   请耐性等待 ····</h2>
+      <app-article-card
+        *ngFor="let product of products; trackBy: trackById"
+        [card]="product"
+        (click)="openDetailModal(product)">
+      </app-article-card>
+      <div *ngIf="products.length === 0" class="no-results">
+        <h2>寻找中··· 请耐性等待 ····</h2>
       </div>
-    }
-  }
-
+    </div>
+  </ng-template>
 
-  <!-- 底部弹出模态 -->
+  <!-- 详细信息模态 -->
   <ion-modal [isOpen]="isModalOpen" cssClass="bottom-modal">
     <ng-template>
-
       <ion-header>
         <ion-toolbar>
           <ion-buttons slot="start">
             <ion-button (click)="closeDetailModal()">关闭</ion-button>
           </ion-buttons>
-          <ion-title>{{currentProduct.get('category')}}</ion-title>
+          <ion-title>{{ currentProduct?.get('category') }}</ion-title>
           <ion-buttons slot="end">
             <ion-button (click)="shareDetailModal()">分享</ion-button>
           </ion-buttons>
@@ -176,38 +99,43 @@
 
       <ion-content class="ion-padding">
         <div class="modal-content" *ngIf="currentProduct">
-          <h1 class="product-name">{{currentProduct.get('title')}}</h1>
-          <p><strong>作者:</strong>{{currentProduct.get('author')}}</p>
-          <p>{{currentProduct.get('content')[0]}}</p>
+          <h1 class="product-name">{{ currentProduct.get('title') }}</h1>
+          <p><strong>作者:</strong>{{ currentProduct.get('author') }}</p>
+          <p>{{ currentProduct.get('content')[0] }}</p>
           <div class="image-container">
-            <img style="width: 100%; height: auto;" [src]="currentProduct.get('image')[0]" alt="图片" class="medicine-image">
+            <img [src]="currentProduct.get('image')[0]" alt="图片" class="medicine-image" />
           </div>
-          <p>{{currentProduct.get('content')[0]}}</p>  
+          <p>{{ currentProduct.get('content')[1] }}</p>
           <div class="image-container">
-            <img style="width: 100%; height: auto;" [src]="currentProduct.get('image')[0]" alt="图片" class="medicine-image">
+            <img [src]="currentProduct.get('image')[1]" alt="图片" class="medicine-image" />
           </div>
-          <div style="display: flex; height: 30px; width: 100%; justify-content: space-between; align-items: center">
-            <p style="margin-left:30px"><strong>阅读量:</strong>{{currentProduct.get('views')}}</p>
-            <p style="margin-right:30px"><strong>点赞量:</strong>{{currentProduct.get('likes')}}</p>  
+          <div class="stats">
+            <p><strong>阅读量:</strong>{{ currentProduct.get('views') }}</p>
+            <p><strong>点赞量:</strong>{{ currentProduct.get('likes') }}</p>
           </div>
         </div>
       </ion-content>
+
       <ion-footer>
         <ion-item>
-          <!-- <ion-label position="stacked">评论</ion-label> -->
-          <ion-input [value]="comment" (ionInput)="onCommentInput($event)" placeholder="请输入评论"></ion-input>
+          <ion-input
+            [(ngModel)]="comment"
+            (ionInput)="onCommentInput($event)"
+            placeholder="请输入评论">
+          </ion-input>
           <ion-button (click)="postComment()">发布</ion-button>
         </ion-item>
-        
       </ion-footer>
     </ng-template>
   </ion-modal>
 
+  <!-- 分享模态 -->
   <ion-modal class="share-modal" [isOpen]="shareDetail">
+    <ng-template>
       <ion-header>
         <ion-toolbar>
           <ion-buttons slot="end">
-            <ion-button (click)="closeDetailModal()">X</ion-button>
+            <ion-button (click)="closeShareModal()">X</ion-button>
           </ion-buttons>
           <ion-title>分享</ion-title>
         </ion-toolbar>
@@ -215,18 +143,20 @@
       <ion-content>
         <ion-item>
           <ion-label position="stacked">分享链接</ion-label>
-          <!-- <ion-input [(ngModel)]="shareLink" readonly></ion-input> -->
+          <ion-input [value]="shareLink" readonly></ion-input>
         </ion-item>
         <ion-button expand="block" (click)="copyLink()">复制链接</ion-button>
-    </ion-content>
-    <!-- 评论 -->
-    <ion-footer>
-      <ion-item>
-        <!-- <ion-label position="stacked">评论</ion-label> -->
-        <ion-input [value]="comment" (ionInput)="onCommentInput($event)" placeholder="请输入评论"></ion-input>
-        <ion-button (click)="postComment()">发布</ion-button>
-      </ion-item>
-      
-    </ion-footer>
+      </ion-content>
+      <ion-footer>
+        <ion-item>
+          <ion-input
+            [(ngModel)]="comment"
+            (ionInput)="onCommentInput($event)"
+            placeholder="请输入评论">
+          </ion-input>
+          <ion-button (click)="postComment()">发布</ion-button>
+        </ion-item>
+      </ion-footer>
+    </ng-template>
   </ion-modal>
-</ion-content>
+</ion-content>

+ 76 - 129
wisdom-app/src/app/tab2/tab2.page.scss

@@ -1,27 +1,27 @@
 .custom-toolbar {
-  --background: rgba(255, 255, 255, 0.8); /* 使工具栏背景透明 */
-  display: flex; /* 使用 Flexbox 布局 */
-  justify-content: center; /* 水平居中 */
-  align-items: center; /* 垂直居中 */
-  padding: 0; /* 去掉默认内边距 */
+  --background: rgba(255, 255, 255, 0.8);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 0;
 }
 
-
 .search-bar {
-    padding: 10px;
-    text-align: center;
-  }
-  
+  padding: 10px;
+  width: 100%;
+}
+
 .custom-searchbar {
   --background: #ffffff;
   --border-radius: 20px;
-  box-shadow: 0 2px 6px rgba(0,0,0,0.1);
+  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
 }
 
 .header {
   height: 80px;
-  margin-top:-10px
+  margin-top: -10px;
 }
+
 .knowledge {
   height: 100%;
   width: 100%;
@@ -29,13 +29,8 @@
 
 .content {
   margin-top: -5px;
-  -height: 100%;
   width: 100%;
 }
-ion-card-header {
-  font-size: 1.5em;
-  height: auto;
-}
 
 ion-card {
   width: 100%;
@@ -46,117 +41,18 @@ ion-card {
   box-shadow: none;
 }
 
-
 ion-card-content {
   font-size: 1.2em;
   width: 100%;
   height: auto;
 }
 
-ion-segment-view {
-  height: auto;
-  width: 100%;
-}
-
-ion-segment-content {
-  // display: flex;
-  align-items: center;
-  justify-content: center;
-}
-
-// ion-segment-content:nth-of-type(5) {
-//   background: lightpink;
-// }
-// ion-segment-content:nth-of-type(2) {
-//   background: lightblue;
-// }
-// ion-segment-content:nth-of-type(3) {
-//   background: lightgreen;
-// }
-
-.share-modal{
-  --height: 30vh;
-  --width: 100%;
-  --offset-y: 0; /* 确保模态窗口从底部弹出 */
-}
-// 底部弹窗(modal)样式
-.bottom-modal {
-  --height: 100vh;
-  --width: 100%;
-  --offset-y: 0; /* 确保模态窗口从底部弹出 */
-  
-  .modal-content {
-    padding-left: 20px;
-    padding-right: 20px;
-  }
-  
-  .image-container {
-    display: flex;
-    justify-content: center;
-    margin-bottom: 16px;
-  }
-  
-  .medicine-image {
-    object-fit: cover;
-    border-radius: 8px;
-  }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// .tabs {
-//   display: flex;
-//   justify-content: space-around;
-//   padding: 0px 0;
-//   background-color: #f8f8f8;
-// }
-
-// .tabs ion-button {
-//   flex: 1;
-//   text-align: center;
-//   // border: none;
-//   --background: transparent;
-//   --color-checked: #4caf50;
-//   --indicator-color: #4caf50;
-//   --color: #666;
-//   --color-focused: #4caf50;
-//   --color-hover: #4caf50;
-//   --color-activated: #4caf50;
-//   --color-selected: #4caf50;
-// }
-
-// .tab {
-//   cursor: pointer;
-//   padding: 0px 0px;
-// }
-// .tab.active {
-//   color: rgb(81, 255, 0);
-//   background-color: rgb(255, 255, 255);
-// }
-
-//
-
-// 轮播图区域
 .carousel-container {
   position: relative;
   max-width: 800px;
   margin: 0 auto;
   overflow: hidden;
+  border-radius: 8px;
 }
 
 .carousel {
@@ -171,40 +67,42 @@ ion-segment-content {
 .slide img {
   width: 100%;
   height: auto;
+  border-radius: 8px;
 }
 
-.prev, .next {
+.prev,
+.next {
   position: absolute;
   top: 50%;
   transform: translateY(-50%);
   background: rgba(0, 0, 0, 0.5);
   color: white;
-  padding: 16px;
+  padding: 12px;
   border: none;
   cursor: pointer;
+  border-radius: 50%;
 }
 
 .prev {
-  left: 0;
+  left: 10px;
 }
 
 .next {
-  right: 0;
+  right: 10px;
 }
 
 .dots {
   position: absolute;
-  bottom: 20px;
+  bottom: 15px;
   left: 50%;
   transform: translateX(-50%);
-  text-align: center;
+  display: flex;
+  gap: 8px;
 }
 
 .dot {
-  display: inline-block;
-  width: 10px;
-  height: 10px;
-  margin: 0 5px;
+  width: 12px;
+  height: 12px;
   background: #bbb;
   border-radius: 50%;
   cursor: pointer;
@@ -212,5 +110,54 @@ ion-segment-content {
 
 .dot.active {
   background: #717171;
-} 
-//
+}
+
+.no-results {
+  text-align: center;
+  margin: 50px auto;
+}
+
+.bottom-modal {
+  --height: 100vh;
+  --width: 100%;
+  --offset-y: 0;
+}
+
+.share-modal {
+  --height: 30vh;
+  --width: 100%;
+  --offset-y: 0;
+}
+
+.modal-content {
+  padding: 20px;
+}
+
+.image-container {
+  display: flex;
+  justify-content: center;
+  margin-bottom: 16px;
+}
+
+.medicine-image {
+  width: 100%;
+  height: auto;
+  object-fit: cover;
+  border-radius: 8px;
+}
+
+.stats {
+  display: flex;
+  justify-content: space-between;
+  margin: 20px 30px;
+}
+
+ion-footer ion-item {
+  display: flex;
+  align-items: center;
+}
+
+ion-footer ion-input {
+  flex: 1;
+  margin-right: 10px;
+}

+ 162 - 118
wisdom-app/src/app/tab2/tab2.page.ts

@@ -1,84 +1,119 @@
-import { Component } from '@angular/core';
-import { ModalController, IonModal, IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel, IonAvatar, IonButton, IonSegment, IonSegmentButton, IonSegmentContent, IonSegmentView, IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonIcon, IonButtons, IonSearchbar, IonFab, IonFabButton, IonFabList, IonFooter, IonInput } from '@ionic/angular/standalone';
-import { addIcons } from 'ionicons';
-import { airplane, bluetooth, call, wifi } from 'ionicons/icons';
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Router } from '@angular/router';
+import { ModalController } from '@ionic/angular'; // 确保导入 ModalController
 import { ArticleCardComponent } from '../component/article-card/article-card.component';
 import { CommonModule } from '@angular/common';
 import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
-import { Router } from '@angular/router';
+import { NavigationLanComponent } from '../component/navigation-lan/navigation-lan.component';
+import { FormsModule } from '@angular/forms';
 import {
+  airplane,
+  bluetooth,
+  call,
+  wifi,
   chevronDownCircle,
   chevronForwardCircle,
   chevronUpCircle,
   colorPalette,
   document,
-  globe,
+  globe
 } from 'ionicons/icons';
-import { FormsModule } from '@angular/forms';
-addIcons({ airplane, bluetooth, call, wifi });
-addIcons({ chevronDownCircle, chevronForwardCircle, chevronUpCircle, colorPalette, document, globe });
+import { addIcons } from 'ionicons';
+import { IonicModule } from '@ionic/angular'; // 导入 IonicModule
+
+addIcons({
+  airplane,
+  bluetooth,
+  call,
+  wifi,
+  chevronDownCircle,
+  chevronForwardCircle,
+  chevronUpCircle,
+  colorPalette,
+  document,
+  globe
+});
+
 @Component({
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
   styleUrls: ['tab2.page.scss'],
   standalone: true,
   imports: [
-    IonHeader, IonToolbar, IonTitle, IonContent,IonLabel,IonItem,IonList,IonAvatar,ArticleCardComponent,CommonModule,IonButton,
-    IonSegment, IonSegmentButton,IonSegmentContent,IonSegmentView,IonCardContent, IonCardTitle, IonCardHeader,IonCard,
+    IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent,
+    IonLabel,IonItem,IonList,IonAvatar,ArticleCardComponent,CommonModule,IonButton,
+    IonSegment, IonSegmentButton,NavigationLanComponent,
+    IonSegmentContent,IonSegmentView,IonCardContent, IonCardTitle, IonCardHeader,IonCard,
     IonModal,IonIcon, IonButtons, IonSearchbar, IonFab, IonFabButton,IonFabList,IonFooter,
     IonInput,IonSegment,IonSegmentButton,FormsModule
   ]
 })
+export class Tab2Page implements OnInit, OnDestroy {
+  selectedSegment: string = '热点';
+  segments: string[] = ['热点', '专家科普', '睡眠', '生活', '男性', '女性', '两性', '辟谣', '母婴', '美容'];
+
+  images: string[] = [
+    'https://picsum.photos/800/400?random=7',
+    'https://picsum.photos/800/400?random=8',
+    'https://picsum.photos/800/400?random=9',
+    'https://picsum.photos/800/400?random=10',
+    'https://picsum.photos/800/400?random=11',
+    'https://picsum.photos/800/400?random=12',
+  ];
+
+  currentSlide: number = 0;
+  intervalId: any;
+
+  products: CloudObject[] = [];
+  allCards: CloudObject[] = [];
+  cards: CloudObject[] = [];
 
-export class Tab2Page {
-  selectedSegment:string = '热点';
-  segments = [ '热点', '专家科普', '睡眠', '生活', '男性', '女性', '两性', '辟谣', '母婴', '美容'];
-  segmentChanged(event: any) {
-    this.selectedSegment = event.detail.value;
-    console.log(this.selectedSegment);
-    this.loadCards(); // 重新加载卡片
-  }
- /**
-  * 轮播图
-  */
- images = [
-  'https://picsum.photos/800/400?random=7',
-  'https://picsum.photos/800/400?random=8',
-  'https://picsum.photos/800/400?random=9',
-  'https://picsum.photos/800/400?random10',
-  'https://picsum.photos/800/400?random=11',
-  'https://picsum.photos/800/400?random=12',
-];
-
-currentSlide = 0;
-intervalId: any;
-setSlidePosition() {
-  // 这里不需要额外的逻辑,因为在 HTML 中已经通过绑定实现
-}
-
-nextSlide() {
-  this.currentSlide = (this.currentSlide + 1) % this.images.length;
-}
-
-prevSlide() {
-  this.currentSlide = (this.currentSlide - 1 + this.images.length) % this.images.length;
-}
-
-goToSlide(index: number) {
-  this.currentSlide = index;
-}
-
-startAutoSlide() {
-  this.intervalId = setInterval(() => this.nextSlide(), 3000);
-}
-
-
-  products: Array<CloudObject> = []; // 当前显示的科普信息
-  allCards: Array<CloudObject> = []; // 所有科普信息
-
-  //搜索功能
   searchTerm: string = '';
+  comment: string = '';
+  shareLink: string = '';
+
+  isModalOpen: boolean = false;
+  currentProduct: CloudObject | null = null;
+
+  shareDetail: boolean = false;
+
+  isLoading: boolean = false;
+
+  constructor(
+    private modalCtrl: ModalController,
+    private router: Router
+  ) { }
+
+  ngOnInit() {
+    this.loadAllCards();
+    this.loadCards();
+    this.startAutoSlide();
+  }
+
+  ngOnDestroy() {
+    if (this.intervalId) {
+      clearInterval(this.intervalId);
+    }
+  }
+
+  // 轮播图功能
+  nextSlide() {
+    this.currentSlide = (this.currentSlide + 1) % this.images.length;
+  }
+
+  prevSlide() {
+    this.currentSlide = (this.currentSlide - 1 + this.images.length) % this.images.length;
+  }
+
+  goToSlide(index: number) {
+    this.currentSlide = index;
+  }
+
+  startAutoSlide() {
+    this.intervalId = setInterval(() => this.nextSlide(), 3000);
+  }
 
+  // 搜索功能
   async searchProducts(event: any) {
     this.searchTerm = event.detail.value.toLowerCase();
     if (this.searchTerm) {
@@ -89,89 +124,98 @@ startAutoSlide() {
         product.get('content')[0].toLowerCase().includes(this.searchTerm)
       );
     } else {
-      this.products = [...this.allCards]; // 如果搜索词为空,则显示所有科普信息
+      this.products = [...this.allCards];
     }
   }
 
-  isModalOpen = false;
-  currentProduct: any;      // 当前选择的科普信息
+  // 分段控制
+  segmentChanged(event: any) {
+    this.selectedSegment = event.detail.value;
+    this.loadCards();
+  }
 
-  openDetailModal(product?: any) {
-    let user = new CloudUser;
-    if (!user.id){
-      this.router.navigate(['/tabs/tab4'])
-      return
+  // 加载所有卡片
+  async loadAllCards() {
+    this.isLoading = true;
+    const query = new CloudQuery('HotDot');
+    try {
+      this.allCards = await query.find();
+      this.products = [...this.allCards];
+    } catch (error) {
+      console.error('加载所有卡片失败:', error);
+    } finally {
+      this.isLoading = false;
+    }
+  }
+
+  async loadCards() {
+    this.isLoading = true;
+    const query = new CloudQuery('HotDot');
+    query.equalTo('category', this.selectedSegment);
+    try {
+      this.cards = await query.find();
+    } catch (error) {
+      console.error('加载分类卡片失败:', error);
+    } finally {
+      this.isLoading = false;
+    }
+  }
+
+  // 打开详细信息模态
+  openDetailModal(product: CloudObject) {
+    const user = new CloudUser();
+    if (!user.id) {
+      this.router.navigate(['/tabs/tab4']);
+      return;
     }
     this.isModalOpen = true;
     this.currentProduct = product;
   }
+
   closeDetailModal() {
     this.isModalOpen = false;
     this.currentProduct = null;
   }
-  shareDetail = false;
+
+  // 分享功能
   shareDetailModal() {
     this.shareDetail = true;
-    // 在这里确保模态框的aria-hidden属性被正确处理
-    // setTimeout(() => {
-    //   const modalElement = document.querySelector('ion-modal');
-    //   if (modalElement) {
-    //     modalElement.setAttribute('aria-hidden', 'false');
-    //   }
-    // }, 0);
-  }
-  closeShareModal(){
-    this.shareDetail = false;
+    this.shareLink = window.location.href; // 示例分享链接,可以根据需求调整
+  }
 
+  closeShareModal() {
+    this.shareDetail = false;
   }
+
   copyLink() {
-    console.log('复制链接');
+    navigator.clipboard.writeText(this.shareLink).then(() => {
+      console.log('链接已复制');
+      // 可以添加提示用户复制成功的反馈
+    }).catch(err => {
+      console.error('复制失败:', err);
+    });
   }
-  // type:"HotDot"|"export"|"sleep"|"life"|"男"|"女" = "HotDot"
 
-  constructor(
-    private modalCtrl:ModalController,
-    private router:Router,
-  ) { 
-    
-  }
-
-  cards: Array<CloudObject> = []; // 当前显示的分类卡片
-  // async typeChange(ev: any) {
-  //   this.type = ev?.detail?.value || ev?.value || 'HotDot';
-  //   console.log(this.type);
-  //   await this.loadCards(); // 重新加载卡片
-  // }
-  async loadAllCards() {
-    const query = new CloudQuery('HotDot');
-    this.allCards = await query.find();
+  // 评论功能
+  onCommentInput(event: any) {
+    this.comment = event.detail.value;
   }
 
-  async loadCards() {
-    const query = new CloudQuery('HotDot');
-    query.equalTo('category', this.selectedSegment);
-    this.cards = await query.find();
+  postComment() {
+    if (this.comment.trim()) {
+      // 实现发布评论的逻辑,例如调用 API
+      console.log('发布评论:', this.comment);
+      this.comment = '';
+    }
   }
 
-
-  publishHealthInfo() {
-    // 这里可以添加发布求医信息的逻辑
-    console.log('发布求医信息');
+  // 跟踪函数以优化 ngFor
+  trackByIndex(index: number, item: any): number {
+    return index;
   }
 
-  openAiKnowledge(){
-    this.router.navigate(['tabs/ai-knowledge']);
-  }
-  ngOnInit() {
-    this.loadAllCards();
-    this.loadCards(); // 初始化时加载所有科普信息
-  }
-  comment:string = ''
-  onCommentInput(e:any){
-    this.comment = e.detail.value
-    console.log(this.comment);
+  trackById(index: number, item: CloudObject): string {
+    return item.id ?? `no-id-${index}`; // 确保返回 string 类型,避免 null
   }
-  postComment(){
-    console.log('发布评论');
-  }
-}
+
+}

+ 12 - 0
wisdom-app/src/app/tab4/tab4.page.html

@@ -115,6 +115,14 @@
             <ion-icon name="location" slot="start"></ion-icon>
             <ion-label>我的地址</ion-label>
           </ion-item>
+          <ion-item>
+            <ion-icon name="key" slot="start"></ion-icon>
+            <ion-label (click)="goToKey()">修改密码</ion-label>
+          </ion-item>
+          <ion-item>
+            <ion-icon name="bag" slot="start"></ion-icon>
+            <ion-label>我的套餐包</ion-label>
+          </ion-item>
           <ion-item>
             <ion-icon name="chatbox" slot="start"></ion-icon>
             <ion-label>联系客服</ion-label>
@@ -123,6 +131,10 @@
             <ion-icon name="call" slot="start"></ion-icon>
             <ion-label>绑定手机</ion-label>
           </ion-item>
+          <ion-item>
+            <ion-icon name="help-circle" slot="start" ></ion-icon>
+            <ion-label (click)="goToHelp()">帮助</ion-label>
+          </ion-item>
           <ion-item>
             <ion-icon name="folder" slot="start"></ion-icon>
             <ion-label>我的收藏<app-edit-tag (onTagChange)="setTagsValue($event)"></app-edit-tag></ion-label>

+ 9 - 0
wisdom-app/src/app/tab4/tab4.page.ts

@@ -45,6 +45,15 @@ export class Tab4Page {
     this.router.navigate(['/tabs/my-health'])
   }
 
+  goToHelp(){
+    
+    this.router.navigate(['/tabs/help'])
+  }
+  goToKey(){
+    
+    this.router.navigate(['/tabs/password'])
+  }
+
   currentUser:CloudUser|undefined
   constructor(
     private router: Router,

+ 14 - 0
wisdom-app/src/app/tabs/tabs.routes.ts

@@ -74,6 +74,20 @@ export const routes: Routes = [
             (m) => m.PageUserInqueryComponent
           ),
       },
+      {
+        path: 'help',
+        loadComponent: () =>
+          import('../page/feedback-help/feedback-help.component').then(
+            (m) => m.FeedbackHelpComponent
+          ),
+      },
+      {
+        path: 'password',
+        loadComponent: () =>
+          import('../page/change-key/change-key.component').then(
+            (m) => m.ChangeKeyComponent
+          ),
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 125 - 20
wisdom-server/migration/data.js

@@ -887,6 +887,7 @@ module.exports.HotDotList = [
 },
 
 ]
+// data.js
 
 module.exports.DrugList = [
   {
@@ -900,6 +901,9 @@ module.exports.DrugList = [
       "spec": "0.25g*10片/盒",
       "composition": "头孢克肟",
       "taboo": "对头孢菌素过敏者禁用",
+      "treats": [
+          { "__type": "Pointer", "className": "Illness", "objectId": "001" } // 感冒
+      ]
   },
   {
       "objectId": "002",
@@ -912,7 +916,10 @@ module.exports.DrugList = [
       "spec": "200mg*10粒/盒",
       "composition": "布洛芬",
       "taboo": "孕妇、哺乳期妇女慎用",
-      "marketing": "special" 
+      "treats": [
+          { "__type": "Pointer", "className": "Illness", "objectId": "001" }, // 感冒
+          { "__type": "Pointer", "className": "Illness", "objectId": "010" }  // 偏头痛
+      ]
   },
   {
       "objectId": "003",
@@ -925,8 +932,11 @@ module.exports.DrugList = [
       "spec": "10mg*10片/盒",
       "composition": "氯雷他定",
       "taboo": "对本品成分过敏者禁用",
-      "marketing": "special" 
+      "treats": [
+          { "__type": "Pointer", "className": "Illness", "objectId": "005" } // 抑郁症(示例)
+      ]
   },
+  // 其他药品保持不变,添加 'treats' 字段
   {
     "objectId": "004",
     "name": "阿莫西林胶囊",
@@ -938,7 +948,10 @@ module.exports.DrugList = [
     "spec": "500mg*10粒/瓶",
     "composition": "阿莫西林",
     "taboo": "对青霉素类药物过敏者禁用",
-    "marketing": "hot"
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "001" }, // 感冒
+        { "__type": "Pointer", "className": "Illness", "objectId": "007" }  // 胃溃疡
+    ]
   },
   {
     "objectId": "005",
@@ -952,7 +965,9 @@ module.exports.DrugList = [
     "composition": "氯苯那敏、对乙酰氨基酚",
     "taboo": "孕妇、哺乳期妇女慎用",
     "marketing": "hot",
-
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "001" } // 感冒
+    ]
   },
   {
     "objectId": "006",
@@ -964,7 +979,10 @@ module.exports.DrugList = [
     "function": "抗菌消炎,用于泌尿系统感染",
     "spec": "0.2g*20片/盒",
     "composition": "硝呋太尔",
-    "taboo": "孕妇、哺乳期妇女慎用"
+    "taboo": "孕妇、哺乳期妇女慎用",
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "001" } // 感冒(示例)
+    ]
   },
   {
     "objectId": "007",
@@ -976,7 +994,10 @@ module.exports.DrugList = [
     "function": "缓解过敏症状,如鼻炎、皮肤过敏",
     "spec": "5mg+5mg*10片/盒",
     "composition": "氯雷他定、伪麻黄碱",
-    "taboo": "对本品成分过敏者禁用"
+    "taboo": "对本品成分过敏者禁用",
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "005" } // 抑郁症(示例)
+    ]
   },
   {
     "objectId": "008",
@@ -988,7 +1009,11 @@ module.exports.DrugList = [
     "function": "抗酸药,用于治疗胃酸过多、胃溃疡等",
     "spec": "20mg*14片/盒",
     "composition": "泮托拉唑钠",
-    "taboo": "孕妇、哺乳期妇女慎用"
+    "taboo": "孕妇、哺乳期妇女慎用",
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "007" }, // 胃溃疡
+        { "__type": "Pointer", "className": "Illness", "objectId": "009" }  // 抑郁症(示例)
+    ]
   },
   {
     "objectId": "009",
@@ -1001,7 +1026,10 @@ module.exports.DrugList = [
     "spec": "4mg*10片/盒",
     "composition": "马来酸氯苯那敏",
     "taboo": "对本品成分过敏者禁用",
-    "marketing": "hot"
+    "marketing": "hot",
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "005" } // 抑郁症(示例)
+    ]
   },
   {
     "objectId": "010",
@@ -1014,21 +1042,98 @@ module.exports.DrugList = [
     "spec": "10g*20片/盒",
     "composition": "甘草、薄荷、桔梗",
     "taboo": "孕妇、哺乳期妇女慎用",
-    "marketing": "hot"
+    "marketing": "hot",
+    "treats": [
+        { "__type": "Pointer", "className": "Illness", "objectId": "001" }, // 感冒
+        { "__type": "Pointer", "className": "Illness", "objectId": "005" }  // 抑郁症(示例)
+    ]
   },
 
   // parse-dashboard --appId dev --masterKey devmk --serverURL http://dev.fmode.cn:1337/parse --appName DevServer
   // http://127.0.0.1:4040/
 ];
 
-// module.exports.AgentList = [
-//   {
-//     "objectId": "013",
-//     "avatar": '',
-//     "name": "张三",
-//     "desc": "擅长内科疾病治疗",
-//     "User": {
-//         "objectId": "001"
-//       }
-//   }
-// ]
+
+module.exports.IllnessList = [
+  {
+    "objectId": "001",
+    "name": "感冒",
+    "symptoms": "发热、咳嗽、喉咙痛",
+    "description": "一种常见的呼吸道感染疾病。",
+    "treatment": "休息,多喝水,必要时使用退烧药。",
+    "prevention": "勤洗手,避免接触感染源。",
+  },
+  {
+    "objectId": "002",
+    "name": "高血压",
+    "symptoms": "头痛、头晕、心悸",
+    "description": "长期血压升高,增加心脑血管疾病风险。",
+    "treatment": "药物控制血压,健康饮食,适量运动。",
+    "prevention": "保持健康体重,减少盐分摄入,定期监测血压。",
+  },
+  {
+    "objectId": "003",
+    "name": "糖尿病",
+    "symptoms": "频繁口渴、频繁排尿、体重下降",
+    "description": "一种由于胰岛素分泌不足或作用不良导致的慢性代谢疾病。",
+    "treatment": "控制饮食,规律运动,必要时使用胰岛素或口服降糖药。",
+    "prevention": "保持健康体重,均衡饮食,定期体检。",
+  },
+  {
+    "objectId": "004",
+    "name": "哮喘",
+    "symptoms": "喘息、胸闷、咳嗽",
+    "description": "一种慢性呼吸道疾病,特征为气道炎症和气道高反应性。",
+    "treatment": "使用吸入性支气管扩张剂和抗炎药物,避免诱因。",
+    "prevention": "避免过敏原,保持良好的空气质量。",
+  },
+  {
+    "objectId": "005",
+    "name": "抑郁症",
+    "symptoms": "持续的悲伤情绪、兴趣丧失、疲劳",
+    "description": "一种常见的心理健康疾病,影响情绪、思维和行为。",
+    "treatment": "心理治疗、药物治疗、生活方式调整。",
+    "prevention": "保持良好的人际关系,适当运动,寻求专业帮助。",
+  },
+  {
+    "objectId": "006",
+    "name": "关节炎",
+    "symptoms": "关节疼痛、僵硬、肿胀",
+    "description": "一种影响关节的炎症性疾病,常见类型包括类风湿性关节炎和骨关节炎。",
+    "treatment": "药物治疗、物理治疗、手术治疗(严重病例)。",
+    "prevention": "保持健康体重,避免关节过度使用,适度运动。",
+  },
+  {
+    "objectId": "007",
+    "name": "胃溃疡",
+    "symptoms": "上腹部疼痛、恶心、呕吐",
+    "description": "胃黏膜的局部损伤,常由幽门螺杆菌感染或长期使用非甾体抗炎药引起。",
+    "treatment": "抗生素治疗幽门螺杆菌,抑酸药物,饮食调整。",
+    "prevention": "避免过度饮酒,减少使用非甾体抗炎药,保持良好的饮食习惯。",
+  },
+  {
+    "objectId": "008",
+    "name": "慢性阻塞性肺疾病(COPD)",
+    "symptoms": "呼吸急促、咳嗽、咳痰",
+    "description": "一种常见的慢性肺部疾病,主要由长期吸烟或空气污染引起。",
+    "treatment": "戒烟,药物治疗,氧疗,肺康复。",
+    "prevention": "避免吸烟,减少暴露于有害空气污染源。",
+  },
+  {
+    "objectId": "009",
+    "name": "偏头痛",
+    "symptoms": "一侧头痛、恶心、对光和声音敏感",
+    "description": "一种常见的神经系统疾病,特征为反复发作的头痛。",
+    "treatment": "药物缓解疼痛,预防性药物治疗,生活方式调整。",
+    "prevention": "避免已知诱因,保持规律的作息,减少压力。",
+  },
+  {
+    "objectId": "010",
+    "name": "肺炎",
+    "symptoms": "发热、咳嗽、呼吸急促",
+    "description": "肺部感染,导致肺组织炎症。",
+    "treatment": "抗生素治疗,支持疗法,必要时住院治疗。",
+    "prevention": "接种肺炎疫苗,保持良好的卫生习惯,避免吸烟。",
+  },
+  // 可以继续添加更多疾病
+];

+ 97 - 63
wisdom-server/migration/import-data.js

@@ -1,84 +1,118 @@
 // import-data.js
 
 const { CloudQuery, CloudObject } = require("../lib/ncloud");
-const { DepartList, DoctorList, HotDotList, DrugList,RealDoctorList } = require("./data");
-inportDapartAndDoctor();
+const { DepartList, DoctorList, HotDotList, DrugList, RealDoctorList, IllnessList } = require("./data"); // 确保正确导入所有集合
 
-DataMap = {
+// 添加所有集合到 DataMap
+const DataMap = {
     Doctor: {},
     Department: {},
     HotDot: {},
     Drug: {},
     RealDoctor: {},
+    Illness: {},
 };
 
+// 开始导入数据
+inportDapartAndDoctor();
+
 async function inportDapartAndDoctor() {
-    // 导入药品数据
-    // let drugList = DrugList;
-    // for (let index = 0; index < drugList.length; index++) {
-    //     let drug = drugList[index];
-    //     drug = await importObject("Drug", drug);
-    // }
-    // let realDoctorList = RealDoctorList;
-    // for (let index = 0; index < realDoctorList.length; index++) {
-    //     let realDoctor = realDoctorList[index];
-    //     realDoctor = await importObject("RealDoctor", realDoctor);
-    // }
-    //如果需要导入其他数据(科室、医生、热点),可以取消注释以下代码
-   
-    // 导入科室数据
-    // let departList = DepartList;
-    // for (let index = 0; index < departList.length; index++) {
-    //     let depart = departList[index];
-    //     depart = await importObject("Department", depart);
-    // }
-
-    // 导入医生数据
-    // let doctorList = DoctorList;
-    // for (let index = 0; index < doctorList.length; index++) {
-    //     let doctor = doctorList[index];
-    //     doctor = await importObject("Doctor", doctor);
-    // }
-
-    // 导入热点数据
-    let hotDotList = HotDotList;
-    for (let index = 0; index < hotDotList.length; index++) {
-        let hotDot = hotDotList[index];
-        hotDot = await importObject("HotDot", hotDot);
+    try {
+        // 导入药品数据
+        let drugList = DrugList;
+        console.log(`开始导入 Drug 数据,共 ${drugList.length} 条`);
+        for (let index = 0; index < drugList.length; index++) {
+            let drug = drugList[index];
+            drug = await importObject("Drug", drug);
+        }
+
+        // 导入疾病数据
+        let illnessList = IllnessList;
+        console.log(`开始导入 Illness 数据,共 ${illnessList.length} 条`);
+        for (let index = 0; index < illnessList.length; index++) {
+            let illness = illnessList[index];
+            illness = await importObject("Illness", illness);
+        }
+
+        // 如果需要导入其他数据(科室、医生、热点),可以取消注释以下代码
+
+        // 导入科室数据
+        // let departList = DepartList;
+        // console.log(`开始导入 Department 数据,共 ${departList.length} 条`);
+        // for (let index = 0; index < departList.length; index++) {
+        //     let depart = departList[index];
+        //     depart = await importObject("Department", depart);
+        // }
+
+        // 导入医生数据
+        // let doctorList = DoctorList;
+        // console.log(`开始导入 Doctor 数据,共 ${doctorList.length} 条`);
+        // for (let index = 0; index < doctorList.length; index++) {
+        //     let doctor = doctorList[index];
+        //     doctor = await importObject("Doctor", doctor);
+        // }
+
+        // 导入热点数据
+        // let hotDotList = HotDotList;
+        // console.log(`开始导入 HotDot 数据,共 ${hotDotList.length} 条`);
+        // for (let index = 0; index < hotDotList.length; index++) {
+        //     let hotDot = hotDotList[index];
+        //     hotDot = await importObject("HotDot", hotDot);
+        // }
+
+        console.log("数据导入完成");
+    } catch (error) {
+        console.error("导入过程中发生错误:", error);
     }
-    
-    // console.log("药品数据导入完成");
 }
 
 async function importObject(className, data) {
-    // 查重 srcId 数据源列表中的objectId并非数据库生成的唯一ID,因此需要有一个srcId字段进行记录,并查重
-    let query = new CloudQuery(className);
-    let srcId = data.objectId;
-    query.equalTo("srcId", srcId);
-    let importObj = await query.first();
-    console.log(importObj);
-
-    // 导入前批量处理Pointer类型数据,进行重定向
-    Object.keys(data)?.forEach(key => {
-        let field = data[key];
-        let srcId = field?.objectId;
-        if (srcId) { // 是 Pointer 类型字段
-            if (key === "depart") {
-                data[key] = DataMap["Department"]?.[srcId]?.toPointer();
+    try {
+        // 查重 srcId 数据源中的 objectId 并非数据库生成的唯一ID,因此需要有一个 srcId 字段进行记录,并查重
+        let query = new CloudQuery(className);
+        let srcId = data.objectId;
+        query.equalTo("srcId", srcId);
+        let importObj = await query.first();
+        console.log(`查重结果 [${className}]:`, importObj ? `已存在 objectId: ${importObj.id}` : "不存在,准备导入");
+
+        // 导入前批量处理 Pointer 类型数据,进行重定向
+        Object.keys(data)?.forEach(key => {
+            let field = data[key];
+            let fieldObjId = field?.objectId;
+            if (fieldObjId && typeof field === 'object' && field.__type === 'Pointer') { // 是 Pointer 类型字段
+                if (key === "depart") {
+                    data[key] = DataMap["Department"]?.[fieldObjId]?.toPointer();
+                }
+                // 如果有其他 Pointer 类型的字段,可以在这里处理
+                if (key === "doctor") {
+                    data[key] = DataMap["Doctor"]?.[fieldObjId]?.toPointer();
+                }
             }
-            // 如果有其他 Pointer 类型的字段,可以在这里处理
-        }
-    });
 
-    // 若未添加,则创建新对象并保存
-    if (!importObj?.id) {
-        importObj = new CloudObject(className);
-    }
+            // 处理 treats 字段
+            if (key === "treats" && Array.isArray(field)) {
+                data[key] = field.map(item => ({
+                    "__type": "Pointer",
+                    "className": "Illness",
+                    "objectId": item.objectId
+                }));
+            }
+        });
+
+        // 若未添加,则创建新对象并保存
+        if (!importObj?.id) {
+            importObj = new CloudObject(className);
+        }
 
-    // 保存或更新数据
-    data.srcId = srcId;
-    importObj.set(data);
-    importObj = await importObj.save();
+        // 保存或更新数据
+        data.srcId = srcId;
+        importObj.set(data);
+        importObj = await importObj.save();
 
-    DataMap[className][srcId] = importObj;
+        DataMap[className][srcId] = importObj;
+        console.log(`成功导入 ${className} 对象,objectId: ${importObj.id}`);
+        return importObj;
+    } catch (error) {
+        console.error(`导入 ${className} 类别的对象时发生错误:`, error);
+    }
 }