Quellcode durchsuchen

add: add story-generator

祝雨婧 vor 2 Monaten
Ursprung
Commit
7dd3e220f1

+ 28 - 9
novel-app/package-lock.json

@@ -9,10 +9,12 @@
       "version": "0.0.1",
       "dependencies": {
         "@angular/animations": "^18.0.0",
+        "@angular/cdk": "^18.2.14",
         "@angular/common": "^18.0.0",
         "@angular/compiler": "^18.0.0",
         "@angular/core": "^18.0.0",
         "@angular/forms": "^18.0.0",
+        "@angular/material": "^18.2.14",
         "@angular/platform-browser": "^18.0.0",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/router": "^18.0.0",
@@ -22,7 +24,7 @@
         "@capacitor/haptics": "6.0.2",
         "@capacitor/keyboard": "6.0.3",
         "@capacitor/status-bar": "6.0.2",
-        "@ionic/angular": "^8.0.0",
+        "@ionic/angular": "^8.4.1",
         "fmode-ng": "^0.0.63",
         "ionicons": "^7.2.1",
         "rxjs": "~7.8.0",
@@ -488,7 +490,6 @@
       "resolved": "https://registry.npmmirror.com/@angular/cdk/-/cdk-18.2.14.tgz",
       "integrity": "sha512-vDyOh1lwjfVk9OqoroZAP8pf3xxKUvyl+TVR8nJxL4c5fOfUFkD7l94HaanqKSRwJcI2xiztuu92IVoHn8T33Q==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "tslib": "^2.3.0"
       },
@@ -674,6 +675,24 @@
         "node": "^18.19.1 || ^20.11.1 || >=22.0.0"
       }
     },
+    "node_modules/@angular/material": {
+      "version": "18.2.14",
+      "resolved": "https://registry.npmmirror.com/@angular/material/-/material-18.2.14.tgz",
+      "integrity": "sha512-28pxzJP49Mymt664WnCtPkKeg7kXUsQKTKGf/Kl95rNTEdTJLbnlcc8wV0rT0yQNR7kXgpfBnG7h0ETLv/iu5Q==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/animations": "^18.0.0 || ^19.0.0",
+        "@angular/cdk": "18.2.14",
+        "@angular/common": "^18.0.0 || ^19.0.0",
+        "@angular/core": "^18.0.0 || ^19.0.0",
+        "@angular/forms": "^18.0.0 || ^19.0.0",
+        "@angular/platform-browser": "^18.0.0 || ^19.0.0",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
     "node_modules/@angular/platform-browser": {
       "version": "18.2.12",
       "resolved": "https://registry.npmmirror.com/@angular/platform-browser/-/platform-browser-18.2.12.tgz",
@@ -3907,12 +3926,12 @@
       }
     },
     "node_modules/@ionic/angular": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmmirror.com/@ionic/angular/-/angular-8.4.0.tgz",
-      "integrity": "sha512-ivgHk76zpu6EZZlxXj5+FUqGwFKotWhDDA9YRltd2QCnQN+7kwacQk7KFInQ5Sd8RJT98mKFG3oOpyx5gFrBdA==",
+      "version": "8.4.1",
+      "resolved": "https://registry.npmmirror.com/@ionic/angular/-/angular-8.4.1.tgz",
+      "integrity": "sha512-22ghlHeIJjHDizns/huYp1sQ3Y9qYyUY9hEueIB0e8jsNhCOwhRijMIoOCZ/sfMKTbNaKX7EJ25NpVetF7mZXQ==",
       "license": "MIT",
       "dependencies": {
-        "@ionic/core": "8.4.0",
+        "@ionic/core": "8.4.1",
         "ionicons": "^7.0.0",
         "jsonc-parser": "^3.0.0",
         "tslib": "^2.3.0"
@@ -4085,9 +4104,9 @@
       }
     },
     "node_modules/@ionic/core": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmmirror.com/@ionic/core/-/core-8.4.0.tgz",
-      "integrity": "sha512-mZ2Ni9QByFGWBNr5W/F/nyPV+cXLhK+6W5BRziy7QPX6YIS57KH8FpY+CjE7BEcpE78anyY49bZt3eOWcES02g==",
+      "version": "8.4.1",
+      "resolved": "https://registry.npmmirror.com/@ionic/core/-/core-8.4.1.tgz",
+      "integrity": "sha512-D5xpw5TF2wldpAWE0rHq3L+5T79EjR6d++QFpprjp+q+cFjjhOnfGD+2k7gLlWepAod9LUUigeL0JF02C2wgRQ==",
       "license": "MIT",
       "dependencies": {
         "@stencil/core": "4.20.0",

+ 3 - 1
novel-app/package.json

@@ -14,10 +14,12 @@
   "private": true,
   "dependencies": {
     "@angular/animations": "^18.0.0",
+    "@angular/cdk": "^18.2.14",
     "@angular/common": "^18.0.0",
     "@angular/compiler": "^18.0.0",
     "@angular/core": "^18.0.0",
     "@angular/forms": "^18.0.0",
+    "@angular/material": "^18.2.14",
     "@angular/platform-browser": "^18.0.0",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/router": "^18.0.0",
@@ -27,7 +29,7 @@
     "@capacitor/haptics": "6.0.2",
     "@capacitor/keyboard": "6.0.3",
     "@capacitor/status-bar": "6.0.2",
-    "@ionic/angular": "^8.0.0",
+    "@ionic/angular": "^8.4.1",
     "fmode-ng": "^0.0.63",
     "ionicons": "^7.2.1",
     "rxjs": "~7.8.0",

+ 61 - 57
novel-app/src/app/app.routes.ts

@@ -1,59 +1,63 @@
-import { HttpClientModule } from '@angular/common/http';
-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: '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)
-  },
-  {
-    path: 'login',
-    loadComponent: () => import('./login/login.page').then(m => m.LoginPage)
-  },
-  {
-    path: 'short-generator',
-    loadComponent: () => import('./short-generator/short-generator.page').then(m => m.ShortGeneratorPage)
-  },
-  {
-    path: 'character',
-    loadComponent: () => import('./character/character.page').then(m => m.CharacterPage)
-  },
-  {
-    path: 'character-creator',
-    loadComponent: () => import('./character-creator/character-creator.page').then(m => m.CharacterCreatorPage)
+import { HttpClientModule } from '@angular/common/http';
+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: '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)
+  },
+  {
+    path: 'login',
+    loadComponent: () => import('./login/login.page').then(m => m.LoginPage)
+  },
+  {
+    path: 'short-generator',
+    loadComponent: () => import('./short-generator/short-generator.page').then(m => m.ShortGeneratorPage)
+  },
+  {
+    path: 'character',
+    loadComponent: () => import('./character/character.page').then(m => m.CharacterPage)
+  },
+  {
+    path: 'character-creator',
+    loadComponent: () => import('./character-creator/character-creator.page').then(m => m.CharacterCreatorPage)
+  },
  {
+    path: 'chapter-generator',
+    loadComponent: () => import('./chapter-generator/chapter-generator.page').then( m => m.ChapterGeneratorPage)
   }
 
-
-
-];
-
-
-
-
-
-@NgModule({
-  imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }), HttpClientModule],
-  exports: [RouterModule],
-  providers: [
-    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
-  ],
-})
-export class AppRoutingModule { }
+
+
+
+];
+
+
+
+
+
+@NgModule({
+  imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }), HttpClientModule],
+  exports: [RouterModule],
+  providers: [
+    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
+  ],
+})
+export class AppRoutingModule { }

+ 70 - 0
novel-app/src/app/chapter-generator/chapter-generator.page.html

@@ -0,0 +1,70 @@
+<!-- chapter-generator.page.html -->
+<ion-header>
+  <ion-toolbar>
+    <!-- 返回箭头 -->
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/"></ion-back-button>
+    </ion-buttons>
+
+    <!-- 页面标题 -->
+    <ion-title>章节编辑</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <!-- 遮罩层 -->
+  <div class="overlay" [style.display]="isSideShow ? 'block' : 'none'"></div>
+
+  <!-- 主要内容区域 -->
+  <div class="content-container">
+
+    <!-- 侧边栏 -->
+    <div [style.display]="isSideShow ? 'flex' : 'none'"
+      style="display: flex; width: 200px; flex-direction: column; z-index: 1000;">
+      <ion-list>
+        <ion-item *ngFor="let chapter of chapters; let i = index;" (click)="selectChapter(i)">
+          <ion-label>{{ chapter.title }}</ion-label>
+          <ion-buttons slot="end">
+            <ion-button (click)="deleteChapter(i)">
+              <ion-icon name="trash"></ion-icon>
+            </ion-button>
+          </ion-buttons>
+        </ion-item>
+      </ion-list>
+      <ion-button (click)="addChapter()">
+        <ion-icon name="add"></ion-icon>添加章节
+      </ion-button>
+
+      <ion-button color="light" (click)="toggleSide()">
+        <ion-icon name="add"></ion-icon>{{isSideShow ? '折叠' : '展开'}}
+      </ion-button>
+    </div>
+
+    <!-- 内容区域 -->
+    <div class="chapter-edit-container">
+      <ion-button>AI续写</ion-button>
+      <ion-button>AI润色</ion-button>
+      <ion-button>AI扩写</ion-button>
+      @if(selectedChapterIndex !== null){
+      <ion-item>
+        <ion-label position="floating">章节标题</ion-label>
+        <ion-input [(ngModel)]="selectedChapterTitle"></ion-input>
+      </ion-item>
+      <ion-label position="floating">章节内容</ion-label>
+      <ion-item>
+        <textarea [(ngModel)]="selectedChapterContent" style="width: 100%; height: 300px;"></textarea>
+      </ion-item>
+      <ion-button (click)="saveChapter()" expand="block" color="success">保存章节</ion-button>
+      } @else {
+      <p>请选择一个章节进行编辑。</p>
+      }
+    </div>
+  </div>
+
+  <!-- 悬浮球 -->
+  <ion-fab vertical="bottom" horizontal="start" slot="fixed">
+    <ion-fab-button (click)="toggleSide()">
+      <ion-icon name="chevron-forward"></ion-icon>
+    </ion-fab-button>
+  </ion-fab>
+</ion-content>

+ 45 - 0
novel-app/src/app/chapter-generator/chapter-generator.page.scss

@@ -0,0 +1,45 @@
+/* chapter-generator.page.scss */
+ion-menu {
+    --width: 80%;
+}
+
+ion-list {
+    margin-top: 16px;
+}
+
+.overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: calc(100% - 200px);
+    /* 200px 是侧边栏的宽度 */
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.5);
+    /* 半透明黑色背景 */
+    z-index: 999;
+    /* 确保遮罩层在主要内容之上 */
+    margin-left: 200px;
+    /* 与侧边栏对齐 */
+}
+
+.content-container {
+    display: flex;
+    width: 100%;
+    height: 100%;
+    position: relative;
+    z-index: 100;
+    /* 设置一个比侧边栏低的 z-index */
+}
+
+.chapter-edit-container {
+    flex: 1;
+    padding: 16px;
+    position: relative;
+    z-index: 100;
+    /* 设置与 AI 功能按钮相同的 z-index */
+}
+
+ion-fab {
+    z-index: 1000;
+    /* 确保悬浮球在最上层 */
+}

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

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

+ 77 - 0
novel-app/src/app/chapter-generator/chapter-generator.page.ts

@@ -0,0 +1,77 @@
+// chapter-generator.page.ts
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { FormsModule } from '@angular/forms'; // 导入 FormsModule
+import { IonBackButton, IonButton, IonButtons, IonContent, IonFab, IonFabButton, IonHeader, IonIcon, IonInput, IonItem, IonLabel, IonList, IonMenu, IonMenuButton, IonRouterOutlet, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
+import { chevronForward } from 'ionicons/icons';
+
+addIcons({ chevronForward });
+
+@Component({
+  selector: 'app-chapter-generator',
+  templateUrl: './chapter-generator.page.html',
+  styleUrls: ['./chapter-generator.page.scss'],
+  standalone: true,
+  imports: [
+    FormsModule, // 添加 FormsModule
+    IonIcon, IonRouterOutlet,
+    IonList, IonFab, IonBackButton,
+    IonFabButton, CommonModule,
+    IonTitle, IonMenuButton, IonMenu,
+    IonContent, IonItem, IonInput, IonLabel, IonButton, IonButtons, IonHeader, IonToolbar
+  ]
+})
+export class ChapterGeneratorPage {
+  chapters = [
+    { title: 'Chapter 1', content: '这是第一章的内容。' },
+    // 其他章节...
+  ];
+  isSideShow: boolean = true;
+
+  toggleSide() {
+    this.isSideShow = !this.isSideShow;
+  }
+
+  addChapter() {
+    const newChapter = { title: `Chapter ${this.chapters.length + 1}`, content: '' };
+    this.chapters.push(newChapter);
+    this.selectChapter(this.chapters.length - 1); // 自动编辑新添加的章节
+  }
+
+  deleteChapter(index: number) {
+    if (index === this.selectedChapterIndex) {
+      this.selectedChapterIndex = null;
+      this.selectedChapterTitle = '';
+      this.selectedChapterContent = '';
+    }
+    this.chapters.splice(index, 1);
+  }
+
+  selectedChapterIndex: number | null = null;
+  selectedChapterTitle: string = '';
+  selectedChapterContent: string = '';
+
+  selectChapter(index: number) {
+    this.editChapter(index);
+    this.isSideShow = false; // 隐藏侧边栏
+  }
+
+  editChapter(index: number) {
+    this.selectedChapterIndex = index;
+    this.selectedChapterTitle = this.chapters[index].title;
+    this.selectedChapterContent = this.chapters[index].content; // 初始化内容为当前章节的内容
+  }
+
+  saveChapter() {
+    if (this.selectedChapterIndex !== null) {
+      this.chapters[this.selectedChapterIndex].title = this.selectedChapterTitle;
+      this.chapters[this.selectedChapterIndex].content = this.selectedChapterContent;
+      console.log('章节内容已保存:', this.selectedChapterContent);
+      this.selectedChapterIndex = null;
+      this.selectedChapterTitle = '';
+      this.selectedChapterContent = '';
+      this.isSideShow = true; // 显示侧边栏
+    }
+  }
+}

+ 5 - 0
novel-app/src/app/home/home.page.html

@@ -1,3 +1,8 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>首页</ion-title>
+  </ion-toolbar>
+</ion-header>
 <ion-content [fullscreen]="true">
   <!-- 顶部图片区域 -->
   <div class="header-section">

+ 1 - 1
novel-app/src/app/person/person.page.ts

@@ -7,7 +7,7 @@ import {
   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 { ActionSheetController } from '@ionic/angular/standalone';
 import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
 
 interface User {

+ 21 - 8
novel-app/src/app/story-generator/story-generator.page.html

@@ -1,13 +1,26 @@
-<ion-header [translucent]="true">
+<ion-header>
   <ion-toolbar>
-    <ion-title>story-generator</ion-title>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/"></ion-back-button>
+    </ion-buttons>
+    <ion-title>创建长篇小说</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">story-generator</ion-title>
-    </ion-toolbar>
-  </ion-header>
+<ion-content class="ion-padding">
+  <ion-label position="stacked">作品名称 *</ion-label>
+  <ion-item>
+    <ion-textarea [(ngModel)]="title" placeholder="请输入作品名称"></ion-textarea>
+  </ion-item>
+
+  <ion-label position="stacked">作品简介(选填)</ion-label>
+  <ion-item>
+    <ion-textarea [(ngModel)]="description" rows="5" placeholder="请输入作品简介"></ion-textarea>
+  </ion-item>
+
+  <div class="button-container">
+    <ion-button (click)="nextStep()" expand="block" color="primary">
+      下一步
+    </ion-button>
+  </div>
 </ion-content>

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

@@ -0,0 +1,44 @@
+ion-header {
+    ion-toolbar {
+        ion-title {
+            font-size: 20px;
+        }
+    }
+}
+
+ion-content {
+    .ion-padding {
+        ion-label {
+            margin-bottom: 10px;
+            /* 增加标签和文本框之间的间距 */
+        }
+
+        ion-item {
+            margin-bottom: 20px;
+        }
+
+        ion-input,
+        ion-textarea {
+            padding: 15px;
+            border-radius: 8px;
+            border: 1px solid #ccc;
+            /* 添加边框 */
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            font-size: 16px;
+            color: #333;
+        }
+
+        ion-button {
+            font-size: 18px;
+            background-color: #007bff;
+            color: white;
+            border-radius: 8px;
+            padding: 15px 30px;
+            transition: background-color 0.3s ease;
+        }
+
+        ion-button:hover {
+            background-color: #0056b3;
+        }
+    }
+}

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

@@ -1,20 +1,27 @@
-import { Component, OnInit } from '@angular/core';
-import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+import { IonicModule } from '@ionic/angular';
 import { FormsModule } from '@angular/forms';
-import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { Router } from '@angular/router';
 
 @Component({
   selector: 'app-story-generator',
   templateUrl: './story-generator.page.html',
   styleUrls: ['./story-generator.page.scss'],
   standalone: true,
-  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+  imports: [IonicModule, FormsModule],
 })
-export class StoryGeneratorPage implements OnInit {
+export class StoryGeneratorPage {
+  title: string = '';
+  description: string = '';
+  constructor(
+    private router: Router,
+  ) { }
 
-  constructor() { }
-
-  ngOnInit() {
+  nextStep() {
+    // 处理下一步逻辑
+    console.log('Title:', this.title);
+    console.log('Description:', this.description);
+    // 导航到 chapter-generator 页面
+    this.router.navigate(['/chapter-generator']);
   }
-
-}
+}