3 Комити 0e0ea27d44 ... 535c7863b3

Аутор SHA1 Порука Датум
  祝雨婧 535c7863b3 fix:add home forum person пре 3 месеци
  祝雨婧 dc045aa0e5 Merge branch 'master' of http://git.fmode.cn:3000/19808003398/20222670105 пре 3 месеци
  祝雨婧 b8809ac0a7 fix:full home forum пре 3 месеци
34 измењених фајлова са 523 додато и 376 уклоњено
  1. 28 11
      novel-app/src/app/app.routes.ts
  2. 2 6
      novel-app/src/app/character-creator/character-creator.page.html
  3. 0 0
      novel-app/src/app/character-creator/character-creator.page.scss
  4. 17 0
      novel-app/src/app/character-creator/character-creator.page.spec.ts
  5. 20 0
      novel-app/src/app/character-creator/character-creator.page.ts
  6. 4 4
      novel-app/src/app/forum/forum.page.html
  7. 0 0
      novel-app/src/app/forum/forum.page.scss
  8. 6 5
      novel-app/src/app/forum/forum.page.spec.ts
  9. 5 5
      novel-app/src/app/forum/forum.page.ts
  10. 68 94
      novel-app/src/app/home/home.page.html
  11. 169 0
      novel-app/src/app/home/home.page.scss
  12. 59 66
      novel-app/src/app/home/home.page.ts
  13. 0 24
      novel-app/src/app/page-novel/page-novel.component.html
  14. 0 22
      novel-app/src/app/page-novel/page-novel.component.spec.ts
  15. 0 55
      novel-app/src/app/page-novel/page-novel.component.ts
  16. 4 9
      novel-app/src/app/person/person.page.html
  17. 0 0
      novel-app/src/app/person/person.page.scss
  18. 5 5
      novel-app/src/app/person/person.page.spec.ts
  19. 18 16
      novel-app/src/app/person/person.page.ts
  20. 13 0
      novel-app/src/app/story-generator/story-generator.page.html
  21. 0 0
      novel-app/src/app/story-generator/story-generator.page.scss
  22. 17 0
      novel-app/src/app/story-generator/story-generator.page.spec.ts
  23. 20 0
      novel-app/src/app/story-generator/story-generator.page.ts
  24. 0 18
      novel-app/src/app/tab2/tab2.page.spec.ts
  25. 0 16
      novel-app/src/app/tab2/tab2.page.ts
  26. 2 7
      novel-app/src/app/tabs/tabs.page.html
  27. 2 2
      novel-app/src/app/tabs/tabs.page.ts
  28. 13 10
      novel-app/src/app/tabs/tabs.routes.ts
  29. 13 0
      novel-app/src/app/toolbox/toolbox.page.html
  30. 0 0
      novel-app/src/app/toolbox/toolbox.page.scss
  31. 17 0
      novel-app/src/app/toolbox/toolbox.page.spec.ts
  32. 20 0
      novel-app/src/app/toolbox/toolbox.page.ts
  33. BIN
      novel-app/src/assets/images/首页顶部图.png
  34. 1 1
      novel-app/src/theme/variables.scss

+ 28 - 11
novel-app/src/app/app.routes.ts

@@ -1,33 +1,50 @@
-import { NgModule } from '@angular/core';
-import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
-import { RouteReuseStrategy } from '@angular/router';
 import { HttpClientModule } from '@angular/common/http';
-import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
-
-
+import { NgModule } from '@angular/core';
+import { PreloadAllModules, RouteReuseStrategy, RouterModule, Routes } from '@angular/router';
+import { IonicRouteStrategy } from '@ionic/angular';
 
 export const routes: Routes = [
+  {
+    path: '',
+    loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
+  },
+  {
+    path: 'character-creator',
+    loadComponent: () => import('./character-creator/character-creator.page').then(m => m.CharacterCreatorPage)
+  },
+  {
+    path: 'story-generator',
+    loadComponent: () => import('./story-generator/story-generator.page').then(m => m.StoryGeneratorPage)
+  },
+  {
+    path: 'toolbox',
+    loadComponent: () => import('./toolbox/toolbox.page').then(m => m.ToolboxPage)
+  },
   {
     path: '',
     loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
   },
   {
     path: 'register',
-    loadComponent: () => import('./register/register.page').then( m => m.RegisterPage)
+    loadComponent: () => import('./register/register.page').then(m => m.RegisterPage)
   },
   {
     path: 'login',
-    loadComponent: () => import('./login/login.page').then( m => m.LoginPage)
-  },
+    loadComponent: () => import('./login/login.page').then(m => m.LoginPage)
+  }
 
 
 ];
 
+
+
+
+
 @NgModule({
-  imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }),HttpClientModule],
+  imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }), HttpClientModule],
   exports: [RouterModule],
   providers: [
     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
   ],
 })
-export class AppRoutingModule {}
+export class AppRoutingModule { }

+ 2 - 6
novel-app/src/app/tab3/tab3.page.html → novel-app/src/app/character-creator/character-creator.page.html

@@ -1,17 +1,13 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
-    <ion-title>
-      Tab 3
-    </ion-title>
+    <ion-title>character-creator</ion-title>
   </ion-toolbar>
 </ion-header>
 
 <ion-content [fullscreen]="true">
   <ion-header collapse="condense">
     <ion-toolbar>
-      <ion-title size="large">Tab 3</ion-title>
+      <ion-title size="large">character-creator</ion-title>
     </ion-toolbar>
   </ion-header>
-
-  <app-explore-container name="Tab 3 page"></app-explore-container>
 </ion-content>

+ 0 - 0
novel-app/src/app/page-novel/page-novel.component.scss → novel-app/src/app/character-creator/character-creator.page.scss


+ 17 - 0
novel-app/src/app/character-creator/character-creator.page.spec.ts

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

+ 20 - 0
novel-app/src/app/character-creator/character-creator.page.ts

@@ -0,0 +1,20 @@
+import { Component, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+
+@Component({
+  selector: 'app-character-creator',
+  templateUrl: './character-creator.page.html',
+  styleUrls: ['./character-creator.page.scss'],
+  standalone: true,
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+})
+export class CharacterCreatorPage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 4 - 4
novel-app/src/app/tab2/tab2.page.html → novel-app/src/app/forum/forum.page.html

@@ -1,7 +1,7 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
     <ion-title>
-      Tab 2
+      forum
     </ion-title>
   </ion-toolbar>
 </ion-header>
@@ -9,9 +9,9 @@
 <ion-content [fullscreen]="true">
   <ion-header collapse="condense">
     <ion-toolbar>
-      <ion-title size="large">Tab 2</ion-title>
+      <ion-title size="large">forum</ion-title>
     </ion-toolbar>
   </ion-header>
 
-  <app-explore-container name="Tab 2 page"></app-explore-container>
-</ion-content>
+  <app-explore-container name="forum page"></app-explore-container>
+</ion-content>

+ 0 - 0
novel-app/src/app/tab2/tab2.page.scss → novel-app/src/app/forum/forum.page.scss


+ 6 - 5
novel-app/src/app/tab4/tab4.page.spec.ts → novel-app/src/app/forum/forum.page.spec.ts

@@ -1,13 +1,13 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { Tab4Page } from './tab4.page';
+import { ForumPage } from './forum.page';
 
-describe('Tab4Page', () => {
-  let component: Tab4Page;
-  let fixture: ComponentFixture<Tab4Page>;
+describe('ForumPage', () => {
+  let component: ForumPage;
+  let fixture: ComponentFixture<ForumPage>;
 
   beforeEach(async () => {
-    fixture = TestBed.createComponent(Tab4Page);
+    fixture = TestBed.createComponent(ForumPage);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });
@@ -16,3 +16,4 @@ describe('Tab4Page', () => {
     expect(component).toBeTruthy();
   });
 });
+

+ 5 - 5
novel-app/src/app/tab3/tab3.page.ts → novel-app/src/app/forum/forum.page.ts

@@ -3,12 +3,12 @@ import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/stan
 import { ExploreContainerComponent } from '../explore-container/explore-container.component';
 
 @Component({
-  selector: 'app-tab3',
-  templateUrl: 'tab3.page.html',
-  styleUrls: ['tab3.page.scss'],
+  selector: 'app-forum',
+  templateUrl: 'forum.page.html',
+  styleUrls: ['forum.page.scss'],
   standalone: true,
   imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent],
 })
-export class Tab3Page {
-  constructor() {}
+export class ForumPage {
+  constructor() { }
 }

+ 68 - 94
novel-app/src/app/home/home.page.html

@@ -1,102 +1,76 @@
-<ion-header>
-  <ion-toolbar>
-    <ion-buttons slot="start">
-      <ion-button (click)="goToHome()">
-        <ion-icon name="home-outline"></ion-icon>
-      </ion-button>
-    </ion-buttons>
-    <ion-searchbar [(ngModel)]="searchQuery" (ionInput)="onSearchInput($event)"
-      placeholder="搜索小说、角色或创意内容"></ion-searchbar>
-    <ion-buttons slot="end">
-      <ion-menu-button></ion-menu-button>
-      <ion-button (click)="openUserMenu($event)">
-        <ion-avatar>
-          <img [src]="userAvatar" *ngIf="userAvatar; else defaultAvatar">
-          <ng-template #defaultAvatar>
-            <ion-icon name="person-outline"></ion-icon>
-          </ng-template>
-        </ion-avatar>
-      </ion-button>
-    </ion-buttons>
-  </ion-toolbar>
-</ion-header>
-
-<!--轮播图/推荐位-->
 <ion-content [fullscreen]="true">
-  <ion-slides pager="true" autoplay="3000">
-    <ion-slide *ngFor="let item of recommendedItems; let i = index">
-      <img [src]="item.image" />
-      <div class="carousel-caption">
-        <h3>{{ item.title }}</h3>
-        <p>{{ item.description }}</p>
-        <button (click)="goToItem(item)">阅读更多</button>
-      </div>
-    </ion-slide>
-  </ion-slides>
-
+  <!-- 顶部图片区域 -->
+  <div class="header-section">
+    <ion-img src="../../assets/images/首页顶部图.png" alt="header"></ion-img>
+  </div>
 
-  <!-- 功能亮点介绍 -->
-  <ion-grid>
-    <ion-row>
-      <ion-col size="6">
-        <ion-card>
-          <ion-card-header>
-            <ion-card-title>小说生成</ion-card-title>
-          </ion-card-header>
-          <ion-card-content>
-            <ion-button expand="full" (click)="navigateToNovelGeneration()">
-              <ion-icon name="book" slot="start"></ion-icon>
-              定制你的小说世界
-            </ion-button>
-          </ion-card-content>
-        </ion-card>
-      </ion-col>
-      <ion-col size="6">
-        <ion-card>
-          <ion-card-header>
-            <ion-card-title>智能体创建</ion-card-title>
-          </ion-card-header>
-          <ion-card-content>
-            <ion-button expand="full" (click)="navigateToCharacterCreation()">
-              <ion-icon name="person" slot="start"></ion-icon>
-              创建你的智能体
-            </ion-button>
-          </ion-card-content>
-        </ion-card>
-      </ion-col>
-    </ion-row>
-  </ion-grid>
+  <!-- 功能按钮区域 -->
+  <div class="features-section">
+    <!-- 生成小说按钮 -->
+    <ion-button class="feature-button" (click)="navigateTo('/story-generator')" expand="block" fill="clear">
+      <div class="button-content">
+        <div class="icon-wrapper light-blue">
+          <ion-icon name="book"></ion-icon>
+        </div>
+        <span>生成小说</span>
+      </div>
+    </ion-button>
 
-  <!-- 社区互动板块 -->
-  <ion-list>
-    <ion-item-group>
-      <ion-item-divider>
-        <ion-label>最新动态</ion-label>
-      </ion-item-divider>
-      <ion-item *ngFor="let post of latestPosts">
-        <ion-avatar slot="start">
-          <img [src]="post.avatarUrl" alt="Avatar">
-        </ion-avatar>
-        <ion-label>
-          <h2>{{ post.title }}</h2>
-          <p>{{ post.content }}</p>
-        </ion-label>
-      </ion-item>
-    </ion-item-group>
+    <!-- 创建角色按钮 -->
+    <ion-button class="feature-button" (click)="navigateTo('/character-creator')" expand="block" fill="clear">
+      <div class="button-content">
+        <div class="icon-wrapper light-pink">
+          <ion-icon name="person-outline"></ion-icon>
+        </div>
+        <span>创建角色</span>
+      </div>
+    </ion-button>
 
-    <ion-item-group>
-      <ion-item-divider>
-        <ion-label>热门话题</ion-label>
-      </ion-item-divider>
-      <ion-item *ngFor="let topic of popularTopics">
-        <ion-label>
-          <h2>{{ topic.name }}</h2>
-          <p>{{ topic.description }}</p>
-        </ion-label>
-      </ion-item>
-    </ion-item-group>
-  </ion-list>
+    <!-- 工具箱按钮 -->
+    <ion-button class="feature-button" (click)="navigateTo('/toolbox')" expand="block" fill="clear">
+      <div class="button-content">
+        <div class="icon-wrapper light-purple">
+          <ion-icon name="build-outline"></ion-icon>
+        </div>
+        <span>工具箱</span>
+      </div>
+    </ion-button>
+  </div>
 
+  <!-- 作品区域 -->
+  <div class="stories-section">
+    <ion-card>
+      <ion-card-header>
+        <div class="card-header-content">
+          <ion-card-title>我的作品</ion-card-title>
+          <ion-button fill="clear" size="small" (click)="presentCreateOptions($event)">
+            <ion-icon slot="start" name="add-outline"></ion-icon>
+            新建作品
+          </ion-button>
+        </div>
+      </ion-card-header>
 
+      <ion-card-content>
+        <ion-grid *ngIf="stories.length > 0">
+          <ion-row>
+            <ion-col size="6" *ngFor="let story of stories">
+              <div class="story-card">
+                <ion-img [src]="story.cover" alt="story cover"></ion-img>
+                <div class="story-info">
+                  <h3>{{story.title}}</h3>
+                  <p>{{formatDate(story.createTime)}}</p>
+                </div>
+              </div>
+            </ion-col>
+          </ion-row>
+        </ion-grid>
 
+        <div class="empty-state" *ngIf="stories.length === 0">
+          <ion-icon name="document-text-outline"></ion-icon>
+          <h3>暂无作品</h3>
+          <p>点击新建作品按钮开始创作</p>
+        </div>
+      </ion-card-content>
+    </ion-card>
+  </div>
 </ion-content>

+ 169 - 0
novel-app/src/app/home/home.page.scss

@@ -0,0 +1,169 @@
+:host {
+    --ion-background-color: #f4f5f8;
+}
+
+.header-section {
+    width: 100%;
+    height: 180px;
+    overflow: hidden;
+
+    ion-img {
+        width: 100%;
+        height: 100%;
+        object-fit: cover;
+    }
+}
+
+.features-section {
+    display: flex;
+    justify-content: space-between;
+    padding: 16px;
+    gap: 12px;
+
+    .feature-button {
+        flex: 1;
+        height: 100px;
+        margin: 0;
+        --background: #ffffff;
+        --background-activated: #f5f5f5;
+        --border-radius: 20px;
+        --box-shadow: none;
+
+        .button-content {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            width: 100%;
+            gap: 8px;
+        }
+
+        .icon-wrapper {
+            width: 48px;
+            height: 48px;
+            border-radius: 16px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+
+            &.light-blue {
+                background: #e3f2fd;
+            }
+
+            &.light-pink {
+                background: #fce4ec;
+            }
+
+            &.light-purple {
+                background: #f3e5f5;
+            }
+
+            ion-icon {
+                font-size: 24px;
+                color: #333;
+            }
+        }
+
+        span {
+            font-size: 14px;
+            color: #333;
+            font-weight: 500;
+        }
+    }
+}
+
+.stories-section {
+    padding: 0 16px 16px;
+
+    ion-card {
+        margin: 0;
+        border-radius: 20px;
+        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+
+        .card-header-content {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 16px;
+
+            ion-card-title {
+                font-size: 18px;
+                font-weight: 600;
+                margin: 0;
+            }
+        }
+    }
+
+    .story-card {
+        background: white;
+        border-radius: 16px;
+        overflow: hidden;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+
+        ion-img {
+            aspect-ratio: 3/4;
+            object-fit: cover;
+        }
+
+        .story-info {
+            padding: 12px;
+
+            h3 {
+                margin: 0;
+                font-size: 14px;
+                font-weight: 500;
+                color: #333;
+            }
+
+            p {
+                margin: 4px 0 0;
+                font-size: 12px;
+                color: #666;
+            }
+        }
+    }
+
+    .empty-state {
+        text-align: center;
+        padding: 32px 16px;
+
+        ion-icon {
+            font-size: 48px;
+            color: #999;
+            margin-bottom: 16px;
+        }
+
+        h3 {
+            margin: 0 0 8px;
+            font-size: 16px;
+            color: #333;
+        }
+
+        p {
+            margin: 0;
+            font-size: 14px;
+            color: #666;
+        }
+    }
+}
+
+// 响应式调整
+@media (max-width: 320px) {
+    .features-section {
+        .feature-button {
+            height: 90px;
+
+            .icon-wrapper {
+                width: 40px;
+                height: 40px;
+
+                ion-icon {
+                    font-size: 20px;
+                }
+            }
+
+            span {
+                font-size: 12px;
+            }
+        }
+    }
+}

+ 59 - 66
novel-app/src/app/home/home.page.ts

@@ -1,88 +1,81 @@
-import { Component, OnInit, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import {
-  IonHeader, IonToolbar, IonTitle, IonContent, IonSearchbar, IonButtons, IonButton, IonIcon, IonMenuButton, IonAvatar,
-  IonGrid, IonRow, IonCol, IonCard, IonCardHeader, IonCardContent, IonList, IonItem, IonLabel
-} from '@ionic/angular/standalone';
-
+import { Component, ViewChild } from '@angular/core';
 import { CommonModule } from '@angular/common';
+import { IonicModule, PopoverController } from '@ionic/angular';
 import { Router } from '@angular/router';
 
+interface Story {
+  id: string;
+  cover: string;
+  title: string;
+  createTime: Date;
+}
+
 @Component({
   selector: 'app-home',
   templateUrl: 'home.page.html',
   styleUrls: ['home.page.scss'],
   standalone: true,
-  imports: [
-    IonHeader, IonToolbar, IonContent,
-    IonSearchbar, IonButtons, IonButton, IonIcon, IonMenuButton, IonAvatar, IonGrid, IonRow,
-    IonCol, IonCard, IonCardHeader, IonCardContent, IonList, IonItem, IonLabel, IonLabel, CommonModule
-  ],
-  schemas: [CUSTOM_ELEMENTS_SCHEMA]
+  imports: [IonicModule, CommonModule]
 })
-export class HomePage implements OnInit {
-  // 属性
-  searchQuery: string = ''; // 搜索查询字符串
-  recommendedItems: any[] = []; // 推荐位数据
-
-  userAvatar: string | null = null; // 用户头像
-
+export class HomePage {
+  stories: Story[] = [];
 
+  constructor(
+    private router: Router,
+    private popoverController: PopoverController
+  ) { }
 
-  constructor(private router: Router) { }
-  ngOnInit(): void {
-    throw new Error('Method not implemented.');
+  navigateTo(path: string) {
+    this.router.navigate([path]);
   }
-  // 导航到首页
-  goToHome() {
-    // 实现导航逻辑,例如使用Angular Router
-  }
-
-  // 处理搜索输入
-  onSearchInput(event: any) {
-    // 处理搜索输入的逻辑,例如过滤显示结果
-    console.log(this.searchQuery);
-  }
-
-  latestPosts = [
-    { title: '新小说发布', content: '用户XX发布了一部新小说《XX传》', avatarUrl: 'assets/images/avatar1.jpg' },
-    { title: '热门讨论', content: '关于小说创作的技巧讨论火热进行中', avatarUrl: 'assets/images/avatar2.jpg' },
-  ];
 
-  popularTopics = [
-    { name: '小说创作大赛', description: '参与大赛,赢取丰厚奖品!' },
-    { name: '智能体互动体验', description: '分享你与智能体的互动故事。' },
-  ];
+  async presentCreateOptions(ev: any) {
+    const popover = await this.popoverController.create({
+      component: CreateOptionsComponent,
+      event: ev,
+      translucent: true,
+      size: 'auto'
+    });
 
+    await popover.present();
 
-
-  openUserProfile() {
-    // 跳转到用户个人中心页面
-    this.router.navigate(['/profile']);
+    const { data } = await popover.onDidDismiss();
+    if (data) {
+      this.createStory(data.type);
+    }
   }
 
-  openSettings() {
-    // 跳转到设置页面
-    this.router.navigate(['/settings']);
+  createStory(type: 'long' | 'short') {
+    this.router.navigate(['/create-story', { type }]);
   }
 
-  navigateToNovelGeneration() {
-    // 跳转到小说生成页面
-    this.router.navigate(['/tabs/novel']);
+  formatDate(date: Date): string {
+    return date.toLocaleDateString('zh-CN');
   }
+}
 
-  navigateToCharacterCreation() {
-    // 跳转到智能体创建页面
-    this.router.navigate(['/character-creation']);
-  }
-  goToItem(item: any): void {
-    // 假设item有一个属性可以用来导航,比如item.id
-    // 这里你需要根据你的应用逻辑来调整
-    this.router.navigate(['/some-route', item.id]);
-  }
-  openUserMenu($event: Event): void {
-    // 在这里添加打开用户菜单的逻辑
-    // 例如,你可以切换一个布尔值来控制菜单的显示状态
-    console.log('User menu button clicked', $event);
-  }
+@Component({
+  template: `
+    <ion-list>
+      <ion-item button (click)="select('long')">
+        <ion-icon name="book-outline" slot="start"></ion-icon>
+        <ion-label>创建长篇</ion-label>
+      </ion-item>
+      <ion-item button (click)="select('short')">
+        <ion-icon name="document-text-outline" slot="start"></ion-icon>
+        <ion-label>创建短篇</ion-label>
+      </ion-item>
+    </ion-list>
+  `,
+  standalone: true,
+  imports: [IonicModule]
+})
+export class CreateOptionsComponent {
+  constructor(private popoverController: PopoverController) { }
 
-}
+  select(type: 'long' | 'short') {
+    this.popoverController.dismiss({
+      type: type
+    });
+  }
+}

+ 0 - 24
novel-app/src/app/page-novel/page-novel.component.html

@@ -1,24 +0,0 @@
-<ion-content>
-
-  <h1>风格</h1>
-  <ion-input [value]="fengge" (ionInput)="fenggeInput($event)"></ion-input>
-
-  <!-- 文本域:生成提示词 -->
-  <h1>剧情大纲的描述</h1>
-  <ion-textarea [value]="userPrompt" (ionInput)="promptInput($event)" placeholder="文本提示词"
-    autoGrow="true"></ion-textarea>
-
-  <!-- 按钮:执行消息生成函数 -->
-  <ion-button (click)="sendMessage()" expand="block">生成小说</ion-button>
-
-  <!-- 展示:返回消息内容 -->
-  <!-- 消息传输过程中,实时预览 -->
-  @if(!isComplete){
-  <div>{{responseMsg}}</div>
-  }
-  <!-- 消息传输完成后,实时预览Markdown格式 -->
-  @if(isComplete){
-  <fm-markdown-preview class="content-style" [content]="responseMsg"></fm-markdown-preview>
-  }
-
-</ion-content>

+ 0 - 22
novel-app/src/app/page-novel/page-novel.component.spec.ts

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

+ 0 - 55
novel-app/src/app/page-novel/page-novel.component.ts

@@ -1,55 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { IonContent, IonHeader, IonTitle, IonToolbar, 
-  IonLabel,IonItem,IonInput,IonButton,IonBackButton,IonIcon,
-  IonTextarea} from '@ionic/angular/standalone';
-import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
-
-@Component({
-  selector: 'app-page-novel',
-  templateUrl: './page-novel.component.html',
-  styleUrls: ['./page-novel.component.scss'],
-  imports: [IonTextarea, IonContent,IonInput,IonButton,MarkdownPreviewModule
-  ],
-  standalone: true,
-})
-export class PageNovelComponent implements OnInit {
-  constructor() { }
-  ngOnInit() { }
-  // 用户输入提示词
-  fengge: string = "科幻"
-  fenggeInput(ev: any) {
-    this.fengge = ev.detail.value;
-  }
-  // 用户输入提示词
-  userPrompt: string = "请描述基本大纲"
-  promptInput(ev: any) {
-    this.userPrompt = ev.detail.value;
-  }
-  // 属性:组件内用于展示消息内容的变量
-  responseMsg: any = ""
-  // 方法:实例化completion对象,传入消息数组,并订阅生成的可观察对象。
-  isComplete: boolean = false; // 定义完成状态属性,用来标记是否补全完成
-  sendMessage() {
-    console.log("create")
-
-    let PromptTemplate = `
-    您作为一名专业的${this.fengge}小说作家,请您根据用户输入的小说大纲,写一篇小说。
-    以下是小说大纲:${this.userPrompt}
-    `
-
-    let completion = new FmodeChatCompletion([
-      { role: "system", content: "" },
-      { role: "user", content: PromptTemplate }
-    ])
-    completion.sendCompletion().subscribe((message: any) => {
-      // 打印消息体
-      console.log(message.content)
-      // 赋值消息内容给组件内属性
-      this.responseMsg = message.content
-      if (message?.complete) { // 判断message为完成状态,则设置isComplete为完成
-        this.isComplete = true
-      }
-    })
-  }
-
-}

+ 4 - 9
novel-app/src/app/tab4/tab4.page.html → novel-app/src/app/person/person.page.html

@@ -14,12 +14,12 @@
 
 <ion-content [fullscreen]="true" class="ion-padding">
   <div class="background-pattern"></div>
-  
+
   <!-- 用户信息卡片 -->
   <ion-card class="user-card">
     <div class="avatar-container">
       <ion-avatar>
-        <img [src]="user.avatar" alt="avatar"/>
+        <img [src]="user.avatar" alt="avatar" />
       </ion-avatar>
     </div>
     <ion-card-header>
@@ -42,12 +42,7 @@
       <ion-item (click)="changeAvatar()">
         <ion-icon name="image-outline" slot="start"></ion-icon>
         <ion-label>更换头像</ion-label>
-        <input 
-          type="file" 
-          #fileInput 
-          (change)="uploadAvatarFromFile($event)" 
-          accept="image/*" 
-          style="display: none">
+        <input type="file" #fileInput (change)="uploadAvatarFromFile($event)" accept="image/*" style="display: none">
       </ion-item>
 
       <ion-item (click)="changePassword()">
@@ -66,4 +61,4 @@
       </ion-item>
     </ion-list>
   </ion-card>
-</ion-content> 
+</ion-content>

+ 0 - 0
novel-app/src/app/tab4/tab4.page.scss → novel-app/src/app/person/person.page.scss


+ 5 - 5
novel-app/src/app/tab3/tab3.page.spec.ts → novel-app/src/app/person/person.page.spec.ts

@@ -1,13 +1,13 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { Tab3Page } from './tab3.page';
+import { PersonPage } from './person.page';
 
-describe('Tab3Page', () => {
-  let component: Tab3Page;
-  let fixture: ComponentFixture<Tab3Page>;
+describe('PersonPage', () => {
+  let component: PersonPage;
+  let fixture: ComponentFixture<PersonPage>;
 
   beforeEach(async () => {
-    fixture = TestBed.createComponent(Tab3Page);
+    fixture = TestBed.createComponent(PersonPage);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });

+ 18 - 16
novel-app/src/app/tab4/tab4.page.ts → novel-app/src/app/person/person.page.ts

@@ -1,27 +1,29 @@
 import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { FormsModule,ReactiveFormsModule } from '@angular/forms';
-import{Router} from '@angular/router';
-import { IonAvatar, IonBackButton, IonButton, IonButtons, IonContent, IonHeader, IonIcon, 
-  IonItem, IonLabel, IonList, IonTitle, IonToolbar,ToastController, AlertController,IonCard, IonCardHeader, IonCardTitle} from '@ionic/angular/standalone';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { Router } from '@angular/router';
+import {
+  IonAvatar, IonBackButton, IonButton, IonButtons, IonContent, IonHeader, IonIcon,
+  IonItem, IonLabel, IonList, IonTitle, IonToolbar, ToastController, AlertController, IonCard, IonCardHeader, IonCardTitle
+} from '@ionic/angular/standalone';
 import { UserService } from '../services/user.service';
 import { ActionSheetController } from '@ionic/angular';
 import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
- 
+
 interface User {
   username: string;
   avatar: string;
 }
 
 @Component({
-  selector: 'app-tab4',
-  templateUrl: './tab4.page.html',
-  styleUrls: ['./tab4.page.scss'],
+  selector: 'app-person',
+  templateUrl: './person.page.html',
+  styleUrls: ['./person.page.scss'],
   standalone: true,
-  imports: [IonContent, IonHeader,  IonToolbar, CommonModule, FormsModule,
-    IonAvatar,IonList,IonItem,IonLabel,IonButtons,IonCard,IonIcon,IonTitle,IonButton,IonCardHeader,IonCardTitle]
+  imports: [IonContent, IonHeader, IonToolbar, CommonModule, FormsModule,
+    IonAvatar, IonList, IonItem, IonLabel, IonButtons, IonCard, IonIcon, IonTitle, IonButton, IonCardHeader, IonCardTitle]
 })
-export class Tab4Page implements OnInit {
+export class PersonPage implements OnInit {
   isLoggedIn: boolean = false;
   user: User = {
     username: 'User_123456',
@@ -35,7 +37,7 @@ export class Tab4Page implements OnInit {
     private alertController: AlertController,
     private actionSheetController: ActionSheetController,
     private userService: UserService
-  ) {}
+  ) { }
 
   ngOnInit() {
     this.checkLoginStatus();
@@ -114,11 +116,11 @@ export class Tab4Page implements OnInit {
         resultType: CameraResultType.DataUrl,
         source: sourceType === 'camera' ? CameraSource.Camera : CameraSource.Photos
       });
-      
+
       if (image && image.dataUrl) {
         // 先更新本地显示
         this.user.avatar = image.dataUrl;
-        
+
         // 然后保存到服务
         this.userService.updateAvatar(image.dataUrl).subscribe(
           response => {
@@ -262,7 +264,7 @@ export class Tab4Page implements OnInit {
   }
 
   goToCreativeCenter() {
-    this.router.navigate(['/tabs/tab1']);
+    this.router.navigate(['/tabs/home']);
   }
 
   goToLogin() {
@@ -282,7 +284,7 @@ export class Tab4Page implements OnInit {
           const imageData = e.target.result;
           // 先更新本地显示
           this.user.avatar = imageData;
-          
+
           // 然后保存到服务
           this.userService.updateAvatar(imageData).subscribe(
             response => {

+ 13 - 0
novel-app/src/app/story-generator/story-generator.page.html

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

+ 0 - 0
novel-app/src/app/tab3/tab3.page.scss → novel-app/src/app/story-generator/story-generator.page.scss


+ 17 - 0
novel-app/src/app/story-generator/story-generator.page.spec.ts

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

+ 20 - 0
novel-app/src/app/story-generator/story-generator.page.ts

@@ -0,0 +1,20 @@
+import { Component, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+
+@Component({
+  selector: 'app-story-generator',
+  templateUrl: './story-generator.page.html',
+  styleUrls: ['./story-generator.page.scss'],
+  standalone: true,
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+})
+export class StoryGeneratorPage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 0 - 18
novel-app/src/app/tab2/tab2.page.spec.ts

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

+ 0 - 16
novel-app/src/app/tab2/tab2.page.ts

@@ -1,16 +0,0 @@
-import { Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
-import { ExploreContainerComponent } from '../explore-container/explore-container.component';
-
-@Component({
-  selector: 'app-tab2',
-  templateUrl: 'tab2.page.html',
-  styleUrls: ['tab2.page.scss'],
-  standalone: true,
-  imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent]
-})
-export class Tab2Page {
-
-  constructor() {}
-
-}

+ 2 - 7
novel-app/src/app/tabs/tabs.page.html

@@ -5,17 +5,12 @@
       <ion-label>首页</ion-label>
     </ion-tab-button>
 
-    <ion-tab-button tab="tab2" (click)="goPage('/tabs/tab2')">
-      <ion-icon aria-hidden="true" name="reader"></ion-icon>
-      <ion-label>创作</ion-label>
-    </ion-tab-button>
-
-    <ion-tab-button tab="tab3" (click)="goPage('/tabs/tab3')">
+    <ion-tab-button tab="forum" (click)="goPage('/tabs/forum')">
       <ion-icon aria-hidden="true" name="chatbox"></ion-icon>
       <ion-label>论坛</ion-label>
     </ion-tab-button>
 
-    <ion-tab-button tab="tab4" (click)="goPage('/tabs/tab4')">
+    <ion-tab-button tab="person" (click)="goPage('/tabs/person')">
       <ion-icon aria-hidden="true" name="person"></ion-icon>
       <ion-label>个人</ion-label>
     </ion-tab-button>

+ 2 - 2
novel-app/src/app/tabs/tabs.page.ts

@@ -2,7 +2,7 @@ import { Component, EnvironmentInjector, inject } from '@angular/core';
 import { Router } from '@angular/router';
 import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, NavController } from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { home, reader, chatbox, person } from 'ionicons/icons';
+import { home, chatbox, person } from 'ionicons/icons';
 
 @Component({
   selector: 'app-tabs',
@@ -18,7 +18,7 @@ export class TabsPage {
     private navCtrl: NavController,
     private router: Router
   ) {
-    addIcons({ home, reader, chatbox, person });
+    addIcons({ home, chatbox, person });
   }
   goPage(page: string) {
     this.router.navigateByUrl(page)

+ 13 - 10
novel-app/src/app/tabs/tabs.routes.ts

@@ -12,24 +12,27 @@ export const routes: Routes = [
           import('../home/home.page').then((m) => m.HomePage),
       },
       {
-        path: 'tab2',
+        path: 'forum',
         loadComponent: () =>
-          import('../tab2/tab2.page').then((m) => m.Tab2Page),
+          import('../forum/forum.page').then((m) => m.ForumPage),
       },
       {
-        path: 'tab3',
+        path: 'person',
         loadComponent: () =>
-          import('../tab3/tab3.page').then((m) => m.Tab3Page),
+          import('../person/person.page').then((m) => m.PersonPage),
       },
+
       {
-        path: 'tab4',
-        loadComponent: () =>
-          import('../tab4/tab4.page').then((m) => m.Tab4Page),
+        path: 'character-creator',
+        loadComponent: () => import('../character-creator/character-creator.page').then(m => m.CharacterCreatorPage)
       },
       {
-        path: 'novel',
-        loadComponent: () =>
-          import('../page-novel/page-novel.component').then((m) => m.PageNovelComponent),
+        path: 'story-generator',
+        loadComponent: () => import('../story-generator/story-generator.page').then(m => m.StoryGeneratorPage)
+      },
+      {
+        path: 'toolbox',
+        loadComponent: () => import('../toolbox/toolbox.page').then(m => m.ToolboxPage)
       },
       {
         path: '',

+ 13 - 0
novel-app/src/app/toolbox/toolbox.page.html

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

+ 0 - 0
novel-app/src/app/toolbox/toolbox.page.scss


+ 17 - 0
novel-app/src/app/toolbox/toolbox.page.spec.ts

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

+ 20 - 0
novel-app/src/app/toolbox/toolbox.page.ts

@@ -0,0 +1,20 @@
+import { Component, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+
+@Component({
+  selector: 'app-toolbox',
+  templateUrl: './toolbox.page.html',
+  styleUrls: ['./toolbox.page.scss'],
+  standalone: true,
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+})
+export class ToolboxPage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

BIN
novel-app/src/assets/images/首页顶部图.png


+ 1 - 1
novel-app/src/theme/variables.scss

@@ -1,2 +1,2 @@
 // For information on how to create your own theme, please see:
-// http://ionicframework.com/docs/theming/
+// http://ionicframework.com/docs/theming/