浏览代码

Merge branch 'master' of http://git.fmode.cn:3000/19808003398/20222670105

s202226701043 3 月之前
父节点
当前提交
b6a8d0b269
共有 55 个文件被更改,包括 1289 次插入271 次删除
  1. 二进制
      novel-app/obsutil_windows_amd64_5.5.12/obsutil.exe
  2. 19 0
      novel-app/obsutil_windows_amd64_5.5.12/setup.bat
  3. 4 0
      novel-app/src/app/app.routes.ts
  4. 2 1
      novel-app/src/app/atest/atest.page.ts
  5. 23 6
      novel-app/src/app/chapter-generator/chapter-generator.page.ts
  6. 75 31
      novel-app/src/app/character-generator/character-generator.page.html
  7. 56 17
      novel-app/src/app/character-generator/character-generator.page.scss
  8. 32 19
      novel-app/src/app/character-generator/character-generator.page.ts
  9. 2 2
      novel-app/src/app/comp-word-entry/comp-word-entry.component.html
  10. 2 2
      novel-app/src/app/comp-word-entry/comp-word-entry.component.ts
  11. 5 4
      novel-app/src/app/component/article-card/article-card.component.html
  12. 38 11
      novel-app/src/app/home/home.page.html
  13. 200 13
      novel-app/src/app/home/home.page.scss
  14. 110 2
      novel-app/src/app/home/home.page.ts
  15. 1 0
      novel-app/src/app/lib/ncloud.ts
  16. 54 27
      novel-app/src/app/name-generator/name-generator.page.html
  17. 56 17
      novel-app/src/app/name-generator/name-generator.page.scss
  18. 22 6
      novel-app/src/app/name-generator/name-generator.page.ts
  19. 2 2
      novel-app/src/app/short-generator/short-generator.page.html
  20. 78 23
      novel-app/src/app/short-generator/short-generator.page.ts
  21. 2 2
      novel-app/src/app/story-generator/story-generator.page.html
  22. 10 4
      novel-app/src/app/story-generator/story-generator.page.ts
  23. 7 4
      novel-app/src/app/tab1/tab1.page.ts
  24. 3 2
      novel-app/src/app/tab2/tab2.page.html
  25. 5 3
      novel-app/src/app/tab2/tab2.page.ts
  26. 28 0
      novel-app/src/app/tab7/tab7.page.html
  27. 52 0
      novel-app/src/app/tab7/tab7.page.scss
  28. 17 0
      novel-app/src/app/tab7/tab7.page.spec.ts
  29. 186 0
      novel-app/src/app/tab7/tab7.page.ts
  30. 2 2
      novel-app/src/app/toolbox/toolbox.page.html
  31. 84 11
      novel-app/src/app/toolbox/toolbox.page.scss
  32. 33 28
      novel-app/src/app/world-setup/world-setup.page.html
  33. 56 17
      novel-app/src/app/world-setup/world-setup.page.scss
  34. 19 12
      novel-app/src/app/world-setup/world-setup.page.ts
  35. 二进制
      novel-app/src/assets/images/background-image1.jpg
  36. 二进制
      novel-app/src/assets/images/background-image2.jpg
  37. 二进制
      novel-app/src/assets/images/background-image3.jpg
  38. 二进制
      novel-app/src/assets/images/background-image4.jpg
  39. 二进制
      novel-app/src/assets/images/background-image5.jpg
  40. 二进制
      novel-app/src/assets/images/background-image6.jpg
  41. 二进制
      novel-app/src/assets/images/banner1.jpg
  42. 二进制
      novel-app/src/assets/images/banner2.jpg
  43. 二进制
      novel-app/src/assets/images/banner3.jpg
  44. 二进制
      novel-app/src/assets/images/banner4.jpg
  45. 二进制
      novel-app/src/assets/images/banner5.jpg
  46. 二进制
      novel-app/src/assets/images/card1.jpg
  47. 二进制
      novel-app/src/assets/images/card2.jpg
  48. 二进制
      novel-app/src/assets/images/card3.jpg
  49. 二进制
      novel-app/src/assets/images/floating-button.gif
  50. 二进制
      novel-app/src/assets/images/logo1.png
  51. 二进制
      novel-app/src/assets/images/short-generator-icon.png
  52. 二进制
      novel-app/src/assets/images/story-generator-icon.png
  53. 二进制
      novel-app/src/assets/images/toolbox-icon.png
  54. 二进制
      novel-app/src/assets/images/首页顶部图.png
  55. 4 3
      novel-app/src/index.html

二进制
novel-app/obsutil_windows_amd64_5.5.12/obsutil.exe


+ 19 - 0
novel-app/obsutil_windows_amd64_5.5.12/setup.bat

@@ -0,0 +1,19 @@
+@ECHO OFF
+rem Please ensure that this script is in the same directory as obsutil.
+TITLE Add obsutil as custom command for Windows.
+set linkFile=C:\windows\obsutil.exe
+set sourceFile=%~dp0%\obsutil.exe
+if exist %linkFile% (
+    del C:\windows\obsutil.exe
+)
+if exist %sourceFile% (
+    mklink %linkFile% %~dp0%\obsutil.exe
+) else (
+    echo Failed:%sourceFile% is not exist!
+)
+if %errorlevel% == 0 (
+    echo Successfully! %linkFile%
+) else (
+    echo Failed: failed to setup, %linkFile%
+)
+pause

+ 4 - 0
novel-app/src/app/app.routes.ts

@@ -78,6 +78,10 @@ export const routes: Routes = [
   {
     path: 'tab2',
     loadComponent: () => import('./tab2/tab2.page').then( m => m.Tab2Page)
+  },
+  {
+    path: 'tab7',
+    loadComponent: () => import('./tab7/tab7.page').then( m => m.Tab7Page)
   }
 
 

+ 2 - 1
novel-app/src/app/atest/atest.page.ts

@@ -15,7 +15,8 @@ import { AvatarModule, ChatPanelOptions, DalleOptions, FmodeChat, FmodeChatCompl
     IonIcon,IonCard,IonCardHeader,IonCardTitle,
     IonCardSubtitle,IonCardContent, IonThumbnail, IonItem,IonList,CommonModule,IonLabel,
     IonAvatar, IonSelect, IonSelectOption,IonButtons,IonProgressBar,
-    IonText, IonCardHeader, IonCardSubtitle,]
+    IonText, IonCardHeader, IonCardSubtitle,
+  ]
 })
 export class AtestPage implements OnInit {
 

+ 23 - 6
novel-app/src/app/chapter-generator/chapter-generator.page.ts

@@ -9,7 +9,8 @@ import { CommonModule } from '@angular/common';
 import { AiExpandModalComponent } from '../ai-expand-modal/ai-expand-modal.component';
 import { AiPolishModalComponent } from '../ai-polish-modal/ai-polish-modal.component';
 import { AiContinueModalComponent } from '../ai-continue-modal/ai-continue-modal.component';
-
+import { OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
 addIcons({ chevronForward });
 
 @Component({
@@ -18,11 +19,16 @@ addIcons({ chevronForward });
   styleUrls: ['./chapter-generator.page.scss'],
   standalone: true,
   imports: [
-    FormsModule, // 添加 FormsModule
-    IonRouterOutlet, CommonModule, IonicModule, AiExpandModalComponent, AiPolishModalComponent, AiContinueModalComponent
-  ]
+    FormsModule,
+    IonRouterOutlet,
+    CommonModule,
+    IonicModule,
+    AiExpandModalComponent,
+    AiPolishModalComponent,
+    AiContinueModalComponent
+    ]
 })
-export class ChapterGeneratorPage {
+export class ChapterGeneratorPage implements OnInit {
   chapters = [
     { title: 'Chapter 1', content: '这是第一章的内容。' },
     // 其他章节...
@@ -32,8 +38,19 @@ export class ChapterGeneratorPage {
   selectedChapterTitle: string = '';
   selectedChapterContent: string = '';
 
-  constructor(private modalCtrl: ModalController) { }
+  title: string = '';
+  description: string = '';
+
+  constructor(private modalCtrl: ModalController, private route: ActivatedRoute) { }
 
+  ngOnInit() {
+    this.route.queryParams.subscribe(params => {
+      this.title = params['title'];
+      this.description = params['description'];
+      console.log('Received Title:', this.title);
+      console.log('Received Description:', this.description);
+    });
+  }
   async openAiExpandModal() {
     const modal = await this.modalCtrl.create({
       component: AiExpandModalComponent,

+ 75 - 31
novel-app/src/app/character-generator/character-generator.page.html

@@ -7,36 +7,80 @@
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true" class="ion-padding">
-
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>小说类型</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-input [(ngModel)]="type" (ionInput)="typeInput($event)" placeholder="请输入小说类型"></ion-input>
-    </ion-card-content>
-  </ion-card>
-
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>背景</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-textarea [value]="userPrompt" (ionChange)="promptInput($event)" placeholder="请输入小说背景"></ion-textarea>
-    </ion-card-content>
-  </ion-card>
-
-  <ion-button expand="block" (click)="sendMessage()">生成人物设定</ion-button>
-
-  <ion-card *ngIf="responseMsg">
-    <ion-card-header>
-      <ion-card-title>生成的人物设定</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-textarea [value]="responseMsg" readonly class="response-textarea"></ion-textarea>
-      <ion-button expand="block" (click)="copyToClipboard()">复制</ion-button>
-    </ion-card-content>
-  </ion-card>
+<ion-content [fullscreen]="true" class="ion-padding"
+  style="background-image: url('../../assets/images/background-image6.jpg'); background-size: cover; background-position: center; background-repeat: no-repeat;">
 
+  <!-- 使用 ion-grid 包裹所有行,确保布局正确 -->
+  <ion-grid>
+    <ion-row>
+      <ion-label>人物性别</ion-label>
+    </ion-row>
+    <ion-row class="type-buttons">
+      <ion-col size="4">
+        <ion-button (click)="selectGender('男')" [color]="selectedGender === '男' ? 'primary' : 'default'"
+          class="type-button">男</ion-button>
+      </ion-col>
+      <ion-col size="4">
+        <ion-button (click)="selectGender('女')" [color]="selectedGender === '女' ? 'primary' : 'default'"
+          class="type-button">女</ion-button>
+      </ion-col>
+    </ion-row>
+
+    <ion-row>
+      <ion-label>小说类型</ion-label>
+    </ion-row>
+
+    <ion-row class="type-buttons">
+      <ion-col size="4">
+        <ion-button (click)="selectType('重生')" [color]="selectedType === '重生' ? 'primary' : 'default'"
+          class="type-button">重生</ion-button>
+      </ion-col>
+      <ion-col size="4">
+        <ion-button (click)="selectType('都市')" [color]="selectedType === '都市' ? 'primary' : 'default'"
+          class="type-button">都市</ion-button>
+      </ion-col>
+      <ion-col size="4">
+        <ion-button (click)="selectType('穿越')" [color]="selectedType === '穿越' ? 'primary' : 'default'"
+          class="type-button">穿越</ion-button>
+      </ion-col>
+    </ion-row>
+
+    <ion-row class="type-buttons">
+      <ion-col size="4">
+        <ion-button (click)="selectType('玄幻')" [color]="selectedType === '玄幻' ? 'primary' : 'default'"
+          class="type-button">玄幻</ion-button>
+      </ion-col>
+      <ion-col size="4">
+        <ion-button (click)="selectType('系统文')" [color]="selectedType === '系统文' ? 'primary' : 'default'"
+          class="type-button">系统文</ion-button>
+      </ion-col>
+      <ion-col size="4">
+        <ion-button (click)="selectType('搞笑轻松')" [color]="selectedType === '搞笑轻松' ? 'primary' : 'default'"
+          class="type-button">搞笑轻松</ion-button>
+      </ion-col>
+    </ion-row>
+
+    <ion-row>
+      <ion-col size="12">
+        <ion-label>期望描述</ion-label>
+        <ion-textarea [value]="userPrompt" (ionChange)="promptInput($event)" placeholder="请输入期望描述"
+          class="textarea-field" rows="5"></ion-textarea> <!-- 增加 rows 属性 -->
+      </ion-col>
+    </ion-row>
+
+    <ion-row>
+      <ion-col size="12">
+        <ion-button expand="block" (click)="sendMessage()" class="generate-button">生成人物设定</ion-button>
+      </ion-col>
+    </ion-row>
+
+    <ion-row *ngIf="responseMsg">
+      <ion-col size="12">
+        <ion-label>生成的人物设定</ion-label>
+        <ion-textarea [value]="responseMsg" readonly class="response-textarea" rows="10"></ion-textarea>
+        <!-- 增加 rows 属性 -->
+        <ion-button expand="block" (click)="copyToClipboard()" class="copy-button">复制</ion-button>
+      </ion-col>
+    </ion-row>
+  </ion-grid>
 </ion-content>

+ 56 - 17
novel-app/src/app/character-generator/character-generator.page.scss

@@ -1,27 +1,66 @@
-ion-card {
-    margin-bottom: 16px;
-    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-    border-radius: 8px;
+/* 全局样式 */
+
+ion-app {
+    background: url('/assets/images/background-image6.jpg') no-repeat center center fixed;
+    /* 添加背景图片 */
+    background-size: cover;
+    /* 背景图片覆盖整个内容区域 */
+    background-position: center;
+    /* 背景图片居中 */
+    height: 100vh;
+    /* 确保背景覆盖整个视口高度 */
+    margin: 0;
+    /* 移除默认的外边距 */
+    padding: 0;
+    /* 移除默认的内边距 */
 }
 
-ion-card-header {
-    background-color: #f8f9fa;
-    border-bottom: 1px solid #dee2e6;
+ion-content {
+    --background: transparent;
+    /* 设置为透明,以便背景从 ion-app 继承 */
+    padding: 16px;
+    overflow: auto;
+    /* 确保内容可以滚动 */
 }
 
-ion-card-title {
-    font-size: 1.25rem;
-    font-weight: bold;
-    color: #343a40;
+:host {
+    --page-padding: 16px;
+    --primary-color: #003366;
+    /* 深蓝色 */
+    --secondary-color: #336633;
+    /* 墨绿色 */
+    --background-color: #f5f5f5;
+    --text-color: #333333;
+    --highlight-color: #ffcc00;
+    /* 高亮颜色 */
 }
 
-ion-card-content {
-    padding: 16px;
+.input-field {
+    width: 100%;
+}
+
+.reader-group-button {
+    width: 100%;
+    margin-bottom: 10px;
+}
+
+.textarea-field {
+    width: 100%;
+    min-height: 150px;
+    /* 设置最小高度 */
+}
+
+.generate-button {
+    margin-top: 20px;
+}
+
+.copy-button {
+    margin-top: 10px;
 }
 
 ion-button {
     --background: #007bff;
-    --color: #fff;
+    --color: #101010;
     --border-radius: 8px;
     --padding-top: 12px;
     --padding-bottom: 12px;
@@ -71,10 +110,10 @@ ion-input:focus {
     --box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
 }
 
-/* 设置生成的人物设定文本框的高度 */
+/* 设置生成的小说书名文本框的高度 */
 .response-textarea {
-    --min-height: 200px;
-    /* 设置更高的最小高度 */
+    --min-height: 800px;
+    /* 将最小高度增加到 800px */
     border-color: #80bdff;
     /* 可选:设置不同的边框颜色以区分 */
     background-color: #f8f9fa;

+ 32 - 19
novel-app/src/app/character-generator/character-generator.page.ts

@@ -1,7 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons, IonCardContent, IonCardTitle, IonCardHeader, IonCard } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons, IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonCol, IonRow, IonLabel, IonGrid } from '@ionic/angular/standalone';
 import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
 
 @Component({
@@ -13,7 +13,7 @@ import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
     CommonModule, // 确保 CommonModule 已经导入
     FormsModule,
     IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons,
-    IonCardContent, IonCardTitle, IonCardHeader, IonCard,
+    IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonCol, IonRow, IonLabel, IonGrid,
     // 引入fm-markdown-preview组件模块
     MarkdownPreviewModule
   ],
@@ -23,47 +23,60 @@ export class CharacterGeneratorPage implements OnInit {
   constructor() { }
   ngOnInit() { }
 
-  // 用户输入提示词
-  type: string = "东方玄幻";
-  typeInput(ev: any) {
-    this.type = ev.detail.value;
+  types = [
+    '重生', '都市', '穿越', '玄幻', '系统文', '搞笑轻松', '历史古代', '武侠', '奇幻仙侠', '修仙', '末日求生', '东方玄幻', '异能', '科幻末世', '规则怪谈', '悬疑脑洞', '异世大陆', '种田文', '悬疑推理', '无脑爽文', '战神赘婿', '克苏鲁', '穿书'
+  ];
+
+  selectedType: string = '重生';
+
+  selectType(type: string) {
+    this.selectedType = type;
   }
 
-  // 用户输入提示词
-  userPrompt: string = "古代";
+  gender = [
+    '男', '女'
+  ];
+
+  selectedGender: string = '男'; // 修改默认值
+
+  selectGender(gender: string) {
+    this.selectedGender = gender;
+  }
+
+  userPrompt: string = "一个高中生,来自一个神秘的学校。";
   promptInput(ev: any) {
     this.userPrompt = ev.detail.value;
   }
 
-  // 属性:组件内用于展示消息内容的变量
   responseMsg: any = "";
+  isComplete: boolean = false;
 
-  // 方法:实例化completion对象,传入消息数组,并订阅生成的可观察对象。
-  isComplete: boolean = false; // 定义完成状态属性,用来标记是否补全完成
   sendMessage() {
     console.log("create");
 
     let PromptTemplate = `
-    您作为一名专业的${this.type}小说作者,请您根据用户提供的小说背景,给出多个人物设定。
-    以下是用户的口述:${this.userPrompt}
-    `;
+    您作为一名专业的${this.selectedType}小说作者,请您根据用户提供的期望描述,给出一个性别为${this.selectedGender}、符合${this.selectedType}类型特点的人物描述。
+    以下是用户的期望描述:${this.userPrompt}
+  `;
+
+    // 添加系统角色提示
+    let systemPrompt = `
+    你是一名专业的小说作者,擅长各种类型的小说创作。请根据用户提供的信息,生成一个符合特定类型特点的人物描述。
+  `;
 
     let completion = new FmodeChatCompletion([
-      { role: "system", content: "" },
+      { role: "system", content: systemPrompt },
       { role: "user", content: PromptTemplate }
     ]);
     completion.sendCompletion().subscribe((message: any) => {
-      // 打印消息体
       console.log(message.content);
-      // 赋值消息内容给组件内属性
       this.responseMsg = message.content;
-      if (message?.complete) { // 判断message为完成状态,则设置isComplete为完成
+      if (message?.complete) {
         this.isComplete = true;
       }
     });
   }
 
-  // 复制到剪贴板
   copyToClipboard() {
     const textarea = document.createElement('textarea');
     textarea.value = this.responseMsg;

+ 2 - 2
novel-app/src/app/comp-word-entry/comp-word-entry.component.html

@@ -1,7 +1,7 @@
 @for(entry of entryList;let idx = $index;track entry){
   <ion-card>
     <ion-card-header>
-          <ion-card-title>{{entry?.title || "新词条"}}
+          <ion-card-title>{{entry?.name || "新词条"}}
           <ion-button (click)="deleteEntry(idx)" color="danger">删除</ion-button>
 
           </ion-card-title>
@@ -14,7 +14,7 @@
             <ion-select-option value="道具">道具</ion-select-option>
             <ion-select-option value="场景">场景</ion-select-option>
           </ion-select>
-          <ion-input [value]="entry.title" (ionChange)="onIonChange(entry,'title',$event)" placeholder="请输入词条名称"></ion-input>
+          <ion-input [value]="entry.name" (ionChange)="onIonChange(entry,'name',$event)" placeholder="请输入词条名称"></ion-input>
         </ion-item>
         <ion-item>
           <ion-input label="标签" [value]="entry.newTag" (ionChange)="onIonChange(entry,'newTag',$event)"></ion-input>

+ 2 - 2
novel-app/src/app/comp-word-entry/comp-word-entry.component.ts

@@ -3,7 +3,7 @@ import { IonButton, IonCard, IonCardContent, IonCardHeader, IonCardSubtitle, Ion
 
 
 interface WordEntry{
-  title :string // 名称
+  name :string // 名称
   type:"人物"|"道具"|"场景" // 类型
   important:"重要"|"不重要" //  重要程度
   desc:string // 词条简介
@@ -46,7 +46,7 @@ export class CompWordEntryComponent  implements OnInit {
 
   addEntry(){
     this.entryList.push({
-      title:"",
+      name:"",
       type:"人物",
       important:"重要",
       desc:"简介"

+ 5 - 4
novel-app/src/app/component/article-card/article-card.component.html

@@ -1,10 +1,11 @@
 <div class="card">
-  <img [src]="card.get('image')[0]" alt="Image">
+  <!-- <img [src]="card.get('image')[0]" alt="Image"> -->
   <div class="content">
     <h3>{{ card.get('title') }}</h3>
-    <p>{{ card.get('topic') }} &nbsp; {{ card.get('date') }}</p>
-    <p>
+    <p>焚枯食淡荆防颗粒收到了发</p>
+    <!-- <p>{{ card.get('topic') }} &nbsp; {{ card.get('date') }}</p> -->
+    <!-- <p>
       阅读量: {{ card.get('views') }} &nbsp; 赞: {{ card.get('likes') }}
-    </p>
+    </p> -->
   </div>
 </div>

+ 38 - 11
novel-app/src/app/home/home.page.html

@@ -1,12 +1,33 @@
-<ion-header>
+<ion-header [translucent]="true" class="ion-no-border">
   <ion-toolbar>
-    <ion-title>首页</ion-title>
+    <div class="brand-header">
+      <div class="brand-title">
+        <div class="title-container">
+          <span>幻书坊</span>
+          <img src="assets/images/logo1.png" alt="幻书坊">
+        </div>
+      </div>
+    </div>
   </ion-toolbar>
 </ion-header>
-<ion-content [fullscreen]="true">
-  <!-- 顶部图片区域 -->
-  <div class="header-section">
-    <ion-img src="../../assets/images/首页顶部图.png" alt="header"></ion-img>
+
+<ion-content [fullscreen]="true" class="ion-padding"
+  style="background-image: url('../../assets/images/background-image1.jpg'); background-size: cover; background-position: center; background-repeat: no-repeat;">
+
+  <!-- 轮播图 -->
+  <div class="banner-section">
+    <div #bannerContainer class="banner-container" (touchstart)="onTouchStart($event)" (touchmove)="onTouchMove($event)"
+      (touchend)="onTouchEnd($event)">
+      <div class="banner-img-container" [style.transform]="'translateX(' + translateX + 'px)'">
+        <img *ngFor="let slide of slides" [src]="slide.image" [alt]="slide.alt">
+      </div>
+      <div class="banner-indicators">
+        <span class="indicator" *ngFor="let slide of slides; let i = index" [class.active]="currentIndex === i"
+          (click)="goToSlide(i)"></span>
+      </div>
+      <div class="banner-arrows">
+      </div>
+    </div>
   </div>
 
   <!-- 功能按钮区域 -->
@@ -15,7 +36,7 @@
     <ion-button class="feature-button" (click)="navigateTo('/story-generator')" expand="block" fill="clear">
       <div class="button-content">
         <div class="icon-wrapper light-pink">
-          <ion-icon name="book"></ion-icon>
+          <img src="assets/images/story-generator-icon.png" alt="长篇生成">
         </div>
         <span>长篇生成</span>
       </div>
@@ -25,7 +46,7 @@
     <ion-button class="feature-button" (click)="navigateTo('/short-generator')" expand="block" fill="clear">
       <div class="button-content">
         <div class="icon-wrapper light-blue">
-          <ion-icon name="person-outline"></ion-icon>
+          <img src="assets/images/short-generator-icon.png" alt="短篇生成">
         </div>
         <span>短篇生成</span>
       </div>
@@ -35,7 +56,7 @@
     <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>
+          <img src="assets/images/toolbox-icon.png" alt="工具箱">
         </div>
         <span>工具箱</span>
       </div>
@@ -55,7 +76,6 @@
         </div>
       </ion-card-header>
 
-
       <ion-card-content>
         <ion-grid *ngIf="stories.length > 0">
           <ion-row>
@@ -72,11 +92,18 @@
         </ion-grid>
 
         <div class="empty-state" *ngIf="stories.length === 0">
-          <ion-icon name="document-text-outline"></ion-icon>
+          <ion-icon name="document-outline"></ion-icon>
           <h3>暂无作品</h3>
           <p>点击新建作品按钮开始创作</p>
         </div>
       </ion-card-content>
     </ion-card>
   </div>
+
+  <!-- 悬浮按钮 -->
+  <ion-fab vertical="bottom" horizontal="end" slot="fixed">
+    <ion-fab-button (click)="navigateTo('/character')" class="floating-button">
+      <img src="assets/images/floating-button.gif" alt="悬浮按钮">
+    </ion-fab-button>
+  </ion-fab>
 </ion-content>

+ 200 - 13
novel-app/src/app/home/home.page.scss

@@ -1,19 +1,204 @@
+/* 全局样式 */
+ion-app {
+    background: url('/assets/images/background-image1.jpg') no-repeat center center fixed;
+    /* 添加背景图片 */
+    background-size: cover;
+    /* 背景图片覆盖整个内容区域 */
+    background-position: center;
+    /* 背景图片居中 */
+    height: 100vh;
+    /* 确保背景覆盖整个视口高度 */
+    margin: 0;
+    /* 移除默认的外边距 */
+    padding: 0;
+    /* 移除默认的内边距 */
+}
+
+
+ion-content {
+    --background: transparent;
+    /* 设置为透明,以便背景从 ion-app 继承 */
+    padding: 16px;
+}
+
 :host {
-    --ion-background-color: #f4f5f8;
+    --page-padding: 16px;
+    --primary-color: #003366;
+    /* 深蓝色 */
+    --secondary-color: #336633;
+    /* 墨绿色 */
+    --background-color: #f5f5f5;
+    --text-color: #333333;
+    --highlight-color: #ffcc00;
+    /* 高亮颜色 */
 }
 
-.header-section {
-    width: 100%;
-    height: 180px;
-    overflow: hidden;
 
-    ion-img {
+
+.floating-button {
+    --background: transparent !important;
+    --color: inherit !important;
+
+    /* 增大按钮尺寸 */
+    width: 64px;
+    /* 根据需要调整 */
+    height: 64px;
+    /* 根据需要调整 */
+    font-size: 24px;
+    /* 如果有文字内容,可以调整字体大小 */
+    position: relative;
+    /* 添加相对定位以便伪元素定位 */
+    cursor: pointer;
+    /* 添加鼠标悬停效果 */
+
+    img {
         width: 100%;
+        /* 确保图片占满按钮 */
         height: 100%;
-        object-fit: cover;
+        /* 确保图片占满按钮 */
+        object-fit: contain;
+        /* 确保图片不失真 */
+    }
+
+
+    &:hover::after {
+        opacity: 1 !important;
+        /* 使用 !important 来测试 */
+    }
+}
+
+/* 其他样式保持不变 */
+.gradient-background {
+    background: linear-gradient(135deg, #ff7e5f, #feb47b);
+    /* 你可以根据需要调整渐变色 */
+    color: white;
+    /* 确保文字颜色与背景对比明显 */
+    border: none;
+    /* 去掉默认边框 */
+}
+
+// 头部样式
+.brand-header {
+    padding: 8px var(--page-padding);
+    display: flex;
+    justify-content: center;
+
+    .brand-title {
+        display: flex;
+        justify-content: center;
+        width: 100%;
+
+        .title-container {
+            display: flex;
+            align-items: center;
+            gap: 4px;
+            font-family: 'Courier New', Courier, monospace;
+            font-size: 16px;
+            font-weight: 600;
+
+            span {
+                color: var(--primary-color);
+            }
+
+            img {
+                height: 18px;
+                width: 18px;
+                margin-top: 2px;
+            }
+        }
+    }
+}
+
+// 统计信息样式
+.stats-section {
+    display: flex;
+    justify-content: space-around;
+    padding: 10px 0;
+    background-color: var(--primary-color);
+    color: white;
+    border-radius: 8px;
+    margin-bottom: 10px;
+
+    .stat-item {
+        text-align: center;
+        font-size: 1.2em;
+
+        .stat-value {
+            font-size: 2em;
+            margin-bottom: 5px;
+        }
+
+        .stat-label {
+            font-size: 1em;
+        }
+    }
+}
+
+// 轮播图样式
+.banner-section {
+    margin: 16px var(--page-padding);
+
+    .banner-container {
+        position: relative;
+        overflow: hidden;
+        border-radius: 12px;
+        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+        background-color: white;
+
+        .banner-img-container {
+            display: flex;
+            transition: transform 0.5s ease;
+        }
+
+        img {
+            width: 100%;
+            height: auto;
+        }
+
+        .banner-indicators {
+            position: absolute;
+            bottom: 16px;
+            left: 50%;
+            transform: translateX(-50%);
+            display: flex;
+            gap: 8px;
+
+            .indicator {
+                width: 10px;
+                height: 10px;
+                border-radius: 50%;
+                background-color: rgba(0, 0, 0, 0.5);
+                cursor: pointer;
+
+                &.active {
+                    background-color: #ffcc00;
+                }
+            }
+        }
+
+        .banner-arrows {
+            position: absolute;
+            top: 50%;
+            transform: translateY(-50%);
+            display: flex;
+            gap: 16px;
+
+            .arrow-btn {
+                background-color: rgba(0, 0, 0, 0.5);
+                padding: 8px;
+                border-radius: 50%;
+                color: white;
+                cursor: pointer;
+
+                ion-icon {
+                    font-size: 24px;
+                }
+            }
+        }
     }
 }
 
+// 功能按钮区域样式
 .features-section {
     display: flex;
     justify-content: space-between;
@@ -59,13 +244,13 @@
 
             ion-icon {
                 font-size: 24px;
-                color: #333;
+                color: var(--primary-color);
             }
         }
 
         span {
             font-size: 14px;
-            color: #333;
+            color: var(--primary-color);
             font-weight: 500;
         }
     }
@@ -78,6 +263,7 @@
         margin: 0;
         border-radius: 20px;
         box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
+        background-color: rgba(255, 255, 255, 0.5); // 设置背景颜色为白色,透明度为 0.5
 
         .card-header-content {
             display: flex;
@@ -89,6 +275,7 @@
                 font-size: 18px;
                 font-weight: 600;
                 margin: 0;
+                color: var(--primary-color);
             }
         }
     }
@@ -102,13 +289,13 @@
                 margin: 0;
                 font-size: 14px;
                 font-weight: 500;
-                color: #333;
+                color: var(--primary-color);
             }
 
             p {
                 margin: 4px 0 0;
                 font-size: 12px;
-                color: #666;
+                color: var(--text-color);
             }
 
             ion-row {
@@ -130,13 +317,13 @@
         h3 {
             margin: 0 0 8px;
             font-size: 16px;
-            color: #333;
+            color: var(--primary-color);
         }
 
         p {
             margin: 0;
             font-size: 14px;
-            color: #666;
+            color: var(--text-color);
         }
     }
 }

+ 110 - 2
novel-app/src/app/home/home.page.ts

@@ -1,8 +1,10 @@
-import { Component, ViewChild } from '@angular/core';
+// home.page.ts
+import { Component, ViewChild, ElementRef, AfterViewInit } 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;
@@ -17,8 +19,114 @@ interface Story {
   standalone: true,
   imports: [IonicModule, CommonModule]
 })
-export class HomePage {
+export class HomePage implements AfterViewInit {
   stories: Story[] = [];
+  slideWidth: number = 0; // 设置默认值为0
+  autoPlayInterval: NodeJS.Timeout | undefined;
+  currentIndex: number = 0;
+  slides: any[] = []; // 初始化为空数组
+  translateX: number = 0;
+  startX: number = 0;
+  currentTranslateX: number = 0;
+
+  @ViewChild('bannerContainer', { read: ElementRef }) bannerContainer!: ElementRef;
+
+  ngAfterViewInit() {
+    this.startAutoPlay();
+    this.checkSlideWidth();
+  }
+
+  ngAfterViewChecked() {
+    this.checkSlideWidth();
+  }
+
+  private checkSlideWidth() {
+    const container = this.bannerContainer.nativeElement;
+    if (container && container.clientWidth > 0) {
+      this.slideWidth = container.clientWidth;
+      console.log('slideWidth:', this.slideWidth);
+      this.slides = [
+        { image: 'assets/images/banner1.jpg', alt: 'Slide 1' },
+        { image: 'assets/images/banner2.jpg', alt: 'Slide 2' },
+        { image: 'assets/images/banner3.jpg', alt: 'Slide 3' },
+        { image: 'assets/images/banner4.jpg', alt: 'Slide 4' },
+        { image: 'assets/images/banner5.jpg', alt: 'Slide 5' },
+      ];
+      this.updateTranslateX();
+    } else {
+      console.warn('bannerContainer not found or has zero width');
+    }
+  }
+
+
+
+  ngOnDestroy() {
+    this.stopAutoPlay();
+  }
+
+  private startAutoPlay() {
+    this.stopAutoPlay();
+    this.autoPlayInterval = setInterval(() => {
+      this.nextSlide();
+    }, 3000); // 每3秒切换一次
+  }
+
+  private stopAutoPlay() {
+    if (this.autoPlayInterval) {
+      clearInterval(this.autoPlayInterval);
+    }
+  }
+
+  nextSlide() {
+    this.currentIndex = (this.currentIndex + 1) % this.slides.length;
+    this.updateTranslateX();
+  }
+
+  prevSlide() {
+    this.currentIndex = (this.currentIndex - 1 + this.slides.length) % this.slides.length;
+    this.updateTranslateX();
+  }
+
+  goToSlide(index: number) {
+    this.currentIndex = index;
+    this.updateTranslateX();
+  }
+
+  private updateTranslateX() {
+    if (this.slideWidth !== undefined && this.slideWidth > 0) {
+      this.translateX = -this.currentIndex * this.slideWidth;
+      this.currentTranslateX = this.translateX;
+      console.log('translateX:', this.translateX); // 添加调试信息
+    } else {
+      console.warn('slideWidth is not defined or zero');
+    }
+  }
+  onTouchStart(event: TouchEvent) {
+    this.startX = event.touches[0].clientX;
+    this.stopAutoPlay();
+    console.log('Touch Start:', this.startX); // 添加调试信息
+  }
+
+  onTouchMove(event: TouchEvent) {
+    const currentX = event.touches[0].clientX;
+    const diffX = currentX - this.startX;
+    this.currentTranslateX = this.translateX + diffX;
+    console.log('Touch Move:', diffX, this.currentTranslateX); // 添加调试信息
+  }
+
+  onTouchEnd(event: TouchEvent) {
+    const currentX = event.changedTouches[0].clientX;
+    const diffX = currentX - this.startX;
+    if (diffX > 50) {
+      this.prevSlide();
+    } else if (diffX < -50) {
+      this.nextSlide();
+    } else {
+      this.updateTranslateX();
+    }
+    this.startAutoPlay();
+    console.log('Touch End:', diffX, this.currentIndex); // 添加调试信息
+  }
 
   constructor(
     private router: Router,

+ 1 - 0
novel-app/src/app/lib/ncloud.ts

@@ -112,6 +112,7 @@ export class CloudQuery {
   }
 
   equalTo(key: string, value: any) {
+    if (!this.queryParams["where"]) this.queryParams["where"] = {};
       this.queryParams["where"][key] = value;
   }
 

+ 54 - 27
novel-app/src/app/name-generator/name-generator.page.html

@@ -7,36 +7,63 @@
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true" class="ion-padding">
+<ion-content [fullscreen]="true" class="ion-padding"
+  style="background-image: url('../../assets/images/background-image6.jpg'); background-size: cover; background-position: center; background-repeat: no-repeat;">
 
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>小说类型</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-input [(ngModel)]="type" (ionInput)="typeInput($event)" placeholder="请输入小说类型"></ion-input>
-    </ion-card-content>
-  </ion-card>
+  <!-- 使用 ion-grid 包裹所有行,确保布局正确 -->
+  <ion-grid>
+    <ion-row>
+      <ion-col size="12">
+        <ion-label>小说类型</ion-label>
+        <ion-input [(ngModel)]="type" (ionInput)="typeInput($event)" placeholder="请输入小说类型"
+          class="input-field"></ion-input>
+      </ion-col>
+    </ion-row>
 
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>故事梗概</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-textarea [value]="userPrompt" (ionChange)="promptInput($event)" placeholder="请输入小说故事梗概"></ion-textarea>
-    </ion-card-content>
-  </ion-card>
+    <ion-row>
+      <ion-col size="12">
+        <ion-label>读者人群</ion-label>
+        <ion-row>
+          <ion-col size="4">
+            <ion-button (click)="selectReaderGroup('不限人群')"
+              [color]="selectedReaderGroup === '不限人群' ? 'primary' : 'default'"
+              class="reader-group-button">不限人群</ion-button>
+          </ion-col>
+          <ion-col size="4">
+            <ion-button (click)="selectReaderGroup('男频小说')"
+              [color]="selectedReaderGroup === '男频小说' ? 'primary' : 'default'"
+              class="reader-group-button">男频小说</ion-button>
+          </ion-col>
+          <ion-col size="4">
+            <ion-button (click)="selectReaderGroup('女频小说')"
+              [color]="selectedReaderGroup === '女频小说' ? 'primary' : 'default'" color="warning"
+              class="reader-group-button">女频小说</ion-button>
+          </ion-col>
+        </ion-row>
+      </ion-col>
+    </ion-row>
 
-  <ion-button expand="block" (click)="sendMessage()">生成小说书名</ion-button>
+    <ion-row>
+      <ion-col size="12">
+        <ion-label>故事梗概</ion-label>
+        <ion-textarea [value]="userPrompt" (ionChange)="promptInput($event)" placeholder="请输入小说故事梗概"
+          class="textarea-field" rows="5"></ion-textarea> <!-- 增加 rows 属性 -->
+      </ion-col>
+    </ion-row>
 
-  <ion-card *ngIf="responseMsg">
-    <ion-card-header>
-      <ion-card-title>生成的小说书名</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-textarea [value]="responseMsg" readonly class="response-textarea"></ion-textarea>
-      <ion-button expand="block" (click)="copyToClipboard()">复制</ion-button>
-    </ion-card-content>
-  </ion-card>
+    <ion-row>
+      <ion-col size="12">
+        <ion-button expand="block" (click)="sendMessage()" class="generate-button">生成小说书名</ion-button>
+      </ion-col>
+    </ion-row>
 
+    <ion-row *ngIf="responseMsg">
+      <ion-col size="12">
+        <ion-label>生成的小说书名</ion-label>
+        <ion-textarea [value]="responseMsg" readonly class="response-textarea" rows="10"></ion-textarea>
+        <!-- 增加 rows 属性 -->
+        <ion-button expand="block" (click)="copyToClipboard()" class="copy-button">复制</ion-button>
+      </ion-col>
+    </ion-row>
+  </ion-grid>
 </ion-content>

+ 56 - 17
novel-app/src/app/name-generator/name-generator.page.scss

@@ -1,27 +1,66 @@
-ion-card {
-    margin-bottom: 16px;
-    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-    border-radius: 8px;
+/* 全局样式 */
+
+ion-app {
+    background: url('/assets/images/background-image6.jpg') no-repeat center center fixed;
+    /* 添加背景图片 */
+    background-size: cover;
+    /* 背景图片覆盖整个内容区域 */
+    background-position: center;
+    /* 背景图片居中 */
+    height: 100vh;
+    /* 确保背景覆盖整个视口高度 */
+    margin: 0;
+    /* 移除默认的外边距 */
+    padding: 0;
+    /* 移除默认的内边距 */
 }
 
-ion-card-header {
-    background-color: #f8f9fa;
-    border-bottom: 1px solid #dee2e6;
+ion-content {
+    --background: transparent;
+    /* 设置为透明,以便背景从 ion-app 继承 */
+    padding: 16px;
+    overflow: auto;
+    /* 确保内容可以滚动 */
+}
+
+:host {
+    --page-padding: 16px;
+    --primary-color: #003366;
+    /* 深蓝色 */
+    --secondary-color: #336633;
+    /* 墨绿色 */
+    --background-color: #f5f5f5;
+    --text-color: #333333;
+    --highlight-color: #ffcc00;
+    /* 高亮颜色 */
+}
+
+.input-field {
+    width: 100%;
+}
+
+.reader-group-button {
+    width: 100%;
+    margin-bottom: 10px;
+}
+
+.textarea-field {
+    width: 100%;
+    min-height: 150px;
+    /* 设置最小高度 */
 }
 
-ion-card-title {
-    font-size: 1.25rem;
-    font-weight: bold;
-    color: #343a40;
+.generate-button {
+    margin-top: 20px;
 }
 
-ion-card-content {
-    padding: 30px;
+.copy-button {
+    margin-top: 10px;
 }
 
 ion-button {
     --background: #007bff;
-    --color: #fff;
+    --color: #101010;
     --border-radius: 8px;
     --padding-top: 12px;
     --padding-bottom: 12px;
@@ -71,10 +110,10 @@ ion-input:focus {
     --box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
 }
 
-/* 设置生成的人物设定文本框的高度 */
+/* 设置生成的小说书名文本框的高度 */
 .response-textarea {
-    --min-height: 200px;
-    /* 设置更高的最小高度 */
+    --min-height: 800px;
+    /* 将最小高度增加到 800px */
     border-color: #80bdff;
     /* 可选:设置不同的边框颜色以区分 */
     background-color: #f8f9fa;

+ 22 - 6
novel-app/src/app/name-generator/name-generator.page.ts

@@ -1,7 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons, IonCardContent, IonCardTitle, IonCardHeader, IonCard } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons, IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonCol, IonRow, IonLabel, IonGrid } from '@ionic/angular/standalone';
 import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
 
 @Component({
@@ -13,7 +13,7 @@ import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
     CommonModule, // 确保 CommonModule 已经导入
     FormsModule,
     IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons,
-    IonCardContent, IonCardTitle, IonCardHeader, IonCard,
+    IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonCol, IonRow, IonLabel, IonGrid,
     // 引入fm-markdown-preview组件模块
     MarkdownPreviewModule
   ],
@@ -22,6 +22,11 @@ export class NameGeneratorPage implements OnInit {
   constructor() { }
   ngOnInit() { }
 
+  selectedReaderGroup: string = '不限人群';
+
+  selectReaderGroup(group: string) {
+    this.selectedReaderGroup = group;
+  }
   // 用户输入提示词
   type: string = "东方玄幻";
   typeInput(ev: any) {
@@ -43,9 +48,21 @@ export class NameGeneratorPage implements OnInit {
     console.log("create");
 
     let PromptTemplate = `
-    您作为一名专业的${this.type}小说作者,请您根据用户提供的小说故事梗概,给出多个小说书名。
-    以下是用户的口述:${this.userPrompt}
-    `;
+  您作为一名专业的${this.type}小说作者,请您根据用户提供的小说故事梗概和目标读者人群,给出多个小说书名。
+  主要读者人群为:${this.selectedReaderGroup}
+  以下是用户的口述:${this.userPrompt}
+
+  示例:
+  - 读者人群:男频小说
+    - 故事梗概:年轻男子意外获得神秘力量,成为守护世界的英雄。
+    - 书名建议:《英雄崛起》、《神秘力量》、《守护者》
+
+  - 读者人群:女频小说
+    - 故事梗概:年轻女子意外获时光之匙,穿梭古今阻止历史篡改,与时空守护者共斗邪恶势力,守护时间线安全。
+    - 书名建议:《时光守护者》、《穿越时空》、《历史篡改者》
+
+  请根据上述示例,为以下故事梗概和读者人群生成书名:
+  `;
 
     let completion = new FmodeChatCompletion([
       { role: "system", content: "" },
@@ -61,7 +78,6 @@ export class NameGeneratorPage implements OnInit {
       }
     });
   }
-
   // 复制到剪贴板
   copyToClipboard() {
     const textarea = document.createElement('textarea');

+ 2 - 2
novel-app/src/app/short-generator/short-generator.page.html

@@ -10,8 +10,8 @@
 <ion-content class="ion-padding">
 
   <h1>标题</h1>
-  <ion-input [value]="title" (ionInput)="titleInput($event)"></ion-input>
-  <h1>风格</h1>
+  <ion-input [value]="titlel" placeholder="输入标题" (ionInput)="titleInput($event)"></ion-input>
+  <h1>要求</h1>
   <ion-input [value]="style" (ionInput)="styleInput($event)"></ion-input>
 
   <!-- 词条列表编辑区域 -->

+ 78 - 23
novel-app/src/app/short-generator/short-generator.page.ts

@@ -1,10 +1,16 @@
 import { Component, OnInit } from '@angular/core';
-import { IonicModule } from '@ionic/angular';
+import { IonicModule, LoadingController } from '@ionic/angular';
 import { FormsModule } from '@angular/forms';
 import { Router } from '@angular/router';
 import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
 import { CompWordEntryComponent } from '../comp-word-entry/comp-word-entry.component';
 
+
+import { CloudObject, CloudQuery, CloudUser } from '../lib/ncloud';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton,IonIcon, ModalController, IonTextarea, IonInput, IonCard, IonCardHeader, IonCardTitle, IonThumbnail, IonCardContent, IonCardSubtitle, IonItem, IonList, IonLabel, IonAvatar, IonSelect, IonSelectOption, AlertController, IonButtons, IonProgressBar, IonText } from '@ionic/angular/standalone';
+import { CommonModule } from '@angular/common';
+import { AvatarModule, ChatPanelOptions, DalleOptions, FmodeChat, FmodeChatMessage, ImagineWork, openChatPanelModal } from 'fmode-ng';
+
 @Component({
   selector: 'app-short-generator',
   templateUrl: './short-generator.page.html',
@@ -15,6 +21,30 @@ import { CompWordEntryComponent } from '../comp-word-entry/comp-word-entry.compo
     FormsModule,
     MarkdownPreviewModule,
     CompWordEntryComponent,
+    // IonHeader,
+    // IonToolbar,
+    // IonTitle,
+    // IonContent,
+    // IonButton,
+    // IonTextarea,
+    // IonInput,
+    IonIcon,
+    IonCard,
+    IonCardHeader,
+    IonCardTitle,
+    IonCardSubtitle,
+    IonCardContent,
+    IonThumbnail,
+    IonItem,
+    IonList,
+    CommonModule,
+    IonLabel,
+    IonAvatar,
+    IonSelect,
+    IonSelectOption,
+    // IonButtons,
+    IonProgressBar,
+    IonText
   ],
 })
 export class ShortGeneratorPage implements OnInit {
@@ -27,9 +57,10 @@ export class ShortGeneratorPage implements OnInit {
   }
 
   // 用户输入提示词
-  title: string = "时空之旅";
+  titlel: string = "";
   titleInput(ev: any) {
-    this.title = ev.detail.value;
+    console.log(ev.detail.value);
+    this.titlel = ev.detail.value;
   }
 
   style: string = "玄幻";
@@ -40,11 +71,19 @@ export class ShortGeneratorPage implements OnInit {
 
   // 人物词条
   entryList: Array<any> = []
+  list: any = [];
+  entry: string = ''; 
   onEntryListChange(ev: any) {
     this.entryList = ev;
+    let list =JSON.stringify(this.entryList) ;
+    console.log(list);
+    this.entry = JSON.stringify(this.entryList); // 将 entryList 转换为字符串并存储在 entry 中
+  console.log(this.entry); // 输出 entry 的值
   }
+  
   showEntryList() {
     console.log(JSON.stringify(this.entryList))
+    
   }
   // 生成的小说大纲
   generatedOutline: string = "";
@@ -60,12 +99,14 @@ export class ShortGeneratorPage implements OnInit {
 
   sendMessage() {
     console.log("create");
-
+    console.log(JSON.stringify(this.entryList));
+    console.log(this.titlel);
+    console.log(this.entry)
     let PromptTemplate = `
-    您作为一名专业的${this.style}作者,请您根据用户提供的标题${this.title},根据添加的词条${this.entryList},给出短篇小说大纲。
+    您作为一名专业的${this.style}作者,请您根据用户提供的标题${this.titlel},根据这个词条${this.entry}的内容,添加文章信息,并给出短篇小说大纲。
     
     `;
-
+    console.log(PromptTemplate);
     let completion = new FmodeChatCompletion([
       { role: "system", content: "" },
       { role: "user", content: PromptTemplate }
@@ -110,22 +151,36 @@ export class ShortGeneratorPage implements OnInit {
   }
 
   saveNovel() {
-    if (this.generatedContent) {
-      const novelData = {
-        title: this.title,
-        style: this.style,
-        entryList: this.entryList,
-        generatedOutline: this.generatedOutline,
-        generatedContent: this.generatedContent
-      };
-
-      // 保存到本地存储
-      localStorage.setItem('novel', JSON.stringify(novelData));
-      console.log('小说已保存到本地存储');
-
-      // 可以在这里添加其他保存逻辑,例如发送到服务器
-    } else {
-      console.log('没有生成小说内容,无法保存');
-    }
+    let consult = new CloudObject("NovelAriticle")
+    let now = new Date();
+    let dateStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
+    // 对象权限的精确指定
+      let completion = new FmodeChatCompletion([
+        {role:"system",content:""},
+      ])
+      
+      completion.sendCompletion().subscribe((message:any)=>{
+        // 打印消息体
+        console.log(message.content)
+        // 赋值消息内容给组件内属性
+        if (message?.complete  ) {
+         
+          
+          consult.set({
+            // name: `${this.name}`,
+            // age: `${this.age}`,
+            // gender: `${this.gender}`,
+            // desc: `${this.desc}`,
+            // user: this.currentUser.toPointer(),
+            title: `${this.titlel}`,
+            topic: `${this.style}`,
+            content2: `${this.generatedContent}`,
+            date: dateStr,
+            category: `短篇小说` 
+          });
+                  consult.save();
+                  console.log(consult);
+        }
+      })
   }
 }

+ 2 - 2
novel-app/src/app/story-generator/story-generator.page.html

@@ -11,14 +11,14 @@
   <form #storyForm="ngForm" (ngSubmit)="nextStep()">
     <ion-item>
       <ion-label position="stacked">作品名称 *</ion-label>
-      <ion-textarea [(ngModel)]="title" name="title" required placeholder="请输入作品名称"></ion-textarea>
+      <ion-textarea [(ngModel)]="title" name="title" required placeholder="请输入作品名称" (ionInput)="nameInput($event)" ></ion-textarea>
       <div *ngIf="storyForm.submitted && storyForm.controls['title'].invalid" class="error">
         作品名称是必填项。
       </div>
     </ion-item>
     <ion-label position="stacked">作品简介(选填)</ion-label>
     <ion-item>
-      <ion-textarea [(ngModel)]="description" rows="5" placeholder="请输入作品简介"></ion-textarea>
+      <ion-textarea [(ngModel)]="description" name="description" rows="5" placeholder="请输入作品简介" (ionInput)="descripInput($event)" ></ion-textarea>
     </ion-item>
     <ion-button type="submit" expand="block" [disabled]="storyForm.invalid">下一步</ion-button>
   </form>

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

@@ -12,16 +12,22 @@ import { CommonModule } from '@angular/common';
 })
 export class StoryGeneratorPage {
   title: string = '';
+  nameInput(e:any) {
+    this.title = e.detail.value;
+  }
   description: string = '';
+  descripInput(e:any) {
+    this.description = e.detail.value;
+  }
   constructor(
     private router: Router,
   ) { }
 
   nextStep() {
-    // 处理下一步逻辑
-    console.log('Title:', this.title);
+    console.log('Title:', this.title); // 确保这里打印出正确的值
     console.log('Description:', this.description);
-    // 导航到 chapter-generator 页面
-    this.router.navigate(['/chapter-generator']);
+    this.router.navigate(['/chapter-generator'], {
+      queryParams: { title: this.title, description: this.description }
+    });
   }
 }

+ 7 - 4
novel-app/src/app/tab1/tab1.page.ts

@@ -1,3 +1,4 @@
+import { CloudUser } from './../lib/ncloud';
 import { FmodeChat, FmodeChatMessage, openChatPanelModal, ChatPanelOptions } from 'fmode-ng';
 import { Component } from '@angular/core';
 import { IonCardHeader, IonHeader, IonToolbar, IonTitle, IonContent, IonTabButton, IonSearchbar, IonLabel, IonItem, IonList, NavController, IonCard, IonCardTitle, IonCardSubtitle, IonCardContent, IonThumbnail, IonFab, IonFabButton } from '@ionic/angular/standalone';
@@ -42,10 +43,10 @@ export class Tab1Page {
     private router: Router,
      private modalCtrl: ModalController,
     // private navCtrl: NavController,
-    private http: HttpClient// 注入 HttpClient
- 
+    private http: HttpClient// 注入 HttpClient,
+
   ) {
-   
+
     addIcons({ add });
   }
   navigateToPage() {
@@ -64,10 +65,12 @@ export class Tab1Page {
   ngOnInit() {
     this.loadDoctorList()
   }
-
   doctorList:Array<CloudObject> = []
   async loadDoctorList(){
+    let user = new CloudUser();
     let query = new CloudQuery("NovelCharacter");
+    query.equalTo("user",user?.id)
+    console.log("user",user.id)
     this.doctorList = await query.find()
   }
 

+ 3 - 2
novel-app/src/app/tab2/tab2.page.html

@@ -15,10 +15,11 @@
             <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-segment-button value="sleep" content-id="sleep">
               <ion-label>睡眠</ion-label>
             </ion-segment-button>
             <ion-segment-button value="life" content-id="life">
@@ -29,7 +30,7 @@
             </ion-segment-button>
             <ion-segment-button value="女" content-id="female">
               <ion-label>女性</ion-label>
-            </ion-segment-button>
+            </ion-segment-button> -->
           </ion-segment>
         </ion-card-title>
       </ion-card-header>

+ 5 - 3
novel-app/src/app/tab2/tab2.page.ts

@@ -90,7 +90,7 @@ setSlidePosition() {
 
 
 
-  type:"hotdot"|"export"|"sleep"|"life"|"男"|"女" = "hotdot"
+  type:"hotdot"|"export" = "hotdot"
 
   constructor(
     private modalCtrl:ModalController,
@@ -107,9 +107,11 @@ setSlidePosition() {
   }
 
   async loadCards() {
-    const query = new CloudQuery('HotDot');
-    this.allCards = await query.find(); // 执行查询并获取结果
+    const query = new CloudQuery('NovelAriticle');
+    this.allCards = await query.find(); 
+    console.log(this.allCards);
     this.cards = this.allCards.filter((card) => card.get('category').toLowerCase().includes(this.type));
+    console.log(this.cards);
   }
 
 

+ 28 - 0
novel-app/src/app/tab7/tab7.page.html

@@ -0,0 +1,28 @@
+<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 class="ion-padding">
+
+  <h1>标题</h1>
+  <ion-input [value]="titlel" placeholder="输入标题" (ionInput)="titleInput($event)"></ion-input>
+  <h1>要求</h1>
+  <ion-input [value]="style" (ionInput)="styleInput($event)"></ion-input>
+
+ 
+  <!-- 按钮:执行消息生成函数 -->
+  <ion-button (click)="sendMessage()" expand="block">生成大纲</ion-button>
+
+  <ion-textarea [(ngModel)]="generatedOutline" placeholder="生成的小说大纲" autoGrow="true"
+    class="generated-outline"></ion-textarea>
+  
+
+  <!-- 保存按钮 -->
+  <ion-button (click)="saveNovel()" expand="block" color="success">保存小说</ion-button>
+
+</ion-content>

+ 52 - 0
novel-app/src/app/tab7/tab7.page.scss

@@ -0,0 +1,52 @@
+ion-content {
+  --padding-top: 20px;
+  --padding-bottom: 20px;
+}
+
+ion-header {
+  background-color: #488aff;
+  color: white;
+}
+
+ion-title {
+  font-size: 20px;
+  font-weight: bold;
+}
+
+ion-input,
+ion-textarea {
+  margin-bottom: 15px;
+  border-radius: 8px;
+  border: 1px solid #ccc;
+  padding: 10px;
+}
+
+ion-input {
+  height: 40px;
+}
+
+ion-textarea {
+  min-height: 100px;
+}
+
+ion-button {
+  margin-top: 10px;
+  margin-bottom: 15px;
+  --background: #488aff;
+  --color: white;
+  --border-radius: 8px;
+}
+
+.generated-outline {
+  margin-top: 20px;
+  border: 1px solid #ccc;
+  border-radius: 8px;
+  padding: 10px;
+  background-color: #f9f9f9;
+}
+
+h1 {
+  font-size: 18px;
+  font-weight: bold;
+  margin-bottom: 5px;
+}

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

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

+ 186 - 0
novel-app/src/app/tab7/tab7.page.ts

@@ -0,0 +1,186 @@
+import { Component, OnInit } from '@angular/core';
+import { IonicModule, LoadingController } from '@ionic/angular';
+import { FormsModule } from '@angular/forms';
+import { Router } from '@angular/router';
+import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
+import { CompWordEntryComponent } from '../comp-word-entry/comp-word-entry.component';
+
+
+import { CloudObject, CloudQuery, CloudUser } from '../lib/ncloud';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton,IonIcon, ModalController, IonTextarea, IonInput, IonCard, IonCardHeader, IonCardTitle, IonThumbnail, IonCardContent, IonCardSubtitle, IonItem, IonList, IonLabel, IonAvatar, IonSelect, IonSelectOption, AlertController, IonButtons, IonProgressBar, IonText } from '@ionic/angular/standalone';
+import { CommonModule } from '@angular/common';
+import { AvatarModule, ChatPanelOptions, DalleOptions, FmodeChat, FmodeChatMessage, ImagineWork, openChatPanelModal } from 'fmode-ng';
+
+@Component({
+  selector: 'app-tab7',
+  templateUrl: './tab7.page.html',
+  styleUrls: ['./tab7.page.scss'],
+  standalone: true,
+  imports: [
+    IonicModule,
+    FormsModule,
+    MarkdownPreviewModule,
+    CompWordEntryComponent,
+    // IonHeader,
+    // IonToolbar,
+    // IonTitle,
+    // IonContent,
+    // IonButton,
+    // IonTextarea,
+    // IonInput,
+    IonIcon,
+    IonCard,
+    IonCardHeader,
+    IonCardTitle,
+    IonCardSubtitle,
+    IonCardContent,
+    IonThumbnail,
+    IonItem,
+    IonList,
+    CommonModule,
+    IonLabel,
+    IonAvatar,
+    IonSelect,
+    IonSelectOption,
+    // IonButtons,
+    IonProgressBar,
+    IonText
+  ],
+})
+export class Tab7Page implements OnInit {
+  constructor(private router: Router) { }
+
+  ngOnInit() { }
+
+  navigateToContentGenerator() {
+    this.router.navigate(['/content-generator'], { queryParams: { outline: this.generatedOutline } });
+  }
+
+  // 用户输入提示词
+  titlel: string = "";
+  titleInput(ev: any) {
+    console.log(ev.detail.value);
+    this.titlel = ev.detail.value;
+  }
+
+  style: string = "玄幻";
+  styleInput(ev: any) {
+    this.style = ev.detail.value;
+  }
+
+
+  // 人物词条
+  entryList: Array<any> = []
+  list: any = [];
+  entry: string = ''; 
+  onEntryListChange(ev: any) {
+    this.entryList = ev;
+    let list =JSON.stringify(this.entryList) ;
+    console.log(list);
+
+  }
+  
+  showEntryList() {
+    console.log(JSON.stringify(this.entryList))
+    
+  }
+  // 生成的小说大纲
+  generatedOutline: string = "";
+
+  // 生成的小说内容
+  generatedContent: string = "";
+
+  // 属性:组件内用于展示消息内容的变量
+  responseMsg: any = "";
+
+  // 方法:实例化completion对象,传入消息数组,并订阅生成的可观察对象。
+  isComplete: boolean = false; // 定义完成状态属性,用来标记是否补全完成
+
+  sendMessage() {
+    console.log("create");
+    console.log(JSON.stringify(this.entryList));
+    console.log(this.titlel);
+    this.entry = JSON.stringify(this.entryList); // 将 entryList 转换为字符串并存储在 entry 中
+    console.log(this.entry); // 输出 entry 的值
+    let PromptTemplate = `
+    您作为一名专业的${this.style}作者,请您根据用户提供的标题${this.titlel},根据这个词条${this.entry}的内容,添加文章信息,并给出短篇小说大纲。
+    
+    `;
+    console.log(PromptTemplate);
+    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;
+        // 将生成的小说大纲放入文本框中
+        this.generatedOutline = this.responseMsg;
+      }
+    });
+  }
+
+  sendOutline() {
+    console.log("create");
+
+    let PromptTemplate = `
+    根据短篇小说大纲${this.generatedOutline},生成一个短篇小说。
+    `;
+
+    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;
+        // 将生成的小说内容放入文本框中
+        this.generatedContent = this.responseMsg;
+      }
+    });
+  }
+
+  saveNovel() {
+    let consult = new CloudObject("NovelAriticle")
+    let now = new Date();
+    let dateStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
+    // 对象权限的精确指定
+      let completion = new FmodeChatCompletion([
+        {role:"system",content:""},
+      ])
+      
+      completion.sendCompletion().subscribe((message:any)=>{
+        // 打印消息体
+        console.log(message.content)
+        // 赋值消息内容给组件内属性
+        if (message?.complete  ) {
+         
+          
+          consult.set({
+            // name: `${this.name}`,
+            // age: `${this.age}`,
+            // gender: `${this.gender}`,
+            // desc: `${this.desc}`,
+            // user: this.currentUser.toPointer(),
+            title: `${this.titlel}`,
+            topic: `${this.style}`,
+            content2: `${this.generatedContent}`,
+            date: dateStr,
+            category: `工具箱内容` 
+          });
+                  consult.save();
+                  console.log(consult);
+        }
+      })
+  }
+}

+ 2 - 2
novel-app/src/app/toolbox/toolbox.page.html

@@ -7,8 +7,8 @@
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-
+<ion-content [fullscreen]="true" class="ion-padding"
+  style="background-image: url('../../assets/images/background-image6.jpg'); background-size: cover; background-position: center; background-repeat: no-repeat;">
   <!-- 小说书名生成按钮 -->
   <ion-card>
     <ion-card-header>

+ 84 - 11
novel-app/src/app/toolbox/toolbox.page.scss

@@ -1,6 +1,22 @@
 /* 全局样式 */
+ion-app {
+    background: url('/assets/images/background-image6.jpg') no-repeat center center fixed;
+    /* 添加背景图片 */
+    background-size: cover;
+    /* 背景图片覆盖整个内容区域 */
+    background-position: center;
+    /* 背景图片居中 */
+    height: 100vh;
+    /* 确保背景覆盖整个视口高度 */
+    margin: 0;
+    /* 移除默认的外边距 */
+    padding: 0;
+    /* 移除默认的内边距 */
+}
+
 ion-content {
-    --background: #f7f7f7;
+    --background: transparent;
+    /* 设置为透明,以便背景从 ion-app 继承 */
     padding: 16px;
 }
 
@@ -9,11 +25,25 @@ ion-card {
     margin-bottom: 16px;
     border-radius: 8px;
     box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+    /* 默认阴影 */
+    background-size: cover;
+    /* 背景图片覆盖整个卡片 */
+    background-position: center;
+    /* 背景图片居中 */
+    transition: box-shadow 0.3s ease, transform 0.3s ease;
+    /* 添加过渡效果 */
+}
+
+ion-content ion-card:hover {
+    box-shadow: 0 16px 32px rgba(0, 0, 0, 0.3);
+    /* 调整阴影强度和模糊半径 */
+    transform: translateY(-12px);
+    /* 增加提升高度 */
 }
 
 /* 卡片标题样式 */
 ion-card-title {
-    color: #333;
+    color: #ffffff;
     font-size: 1.25rem;
     font-weight: bold;
 }
@@ -25,24 +55,33 @@ ion-card-content {
 
 /* 按钮样式 */
 ion-button {
-    --background: #007bff;
-    --color: #fff;
-    --border-radius: 4px;
-    --padding-top: 10px;
-    --padding-bottom: 10px;
-    --padding-start: 16px;
-    --padding-end: 16px;
+    --background: rgba(255, 255, 255, 0.5);
+    /* 半透明白色背景 */
+    --color: black;
+    /* 按钮文字颜色 */
+    --border-radius: 8px;
+    /* 按钮圆角 */
+    --padding-top: 12px;
+    /* 按钮内边距 */
+    --padding-bottom: 12px;
+    /* 按钮内边距 */
+    --padding-start: 24px;
+    /* 按钮内边距 */
+    --padding-end: 24px;
+    /* 按钮内边距 */
     font-size: 1rem;
     font-weight: 500;
 }
 
 ion-button:hover {
-    --background: #0056b3;
+    --background: rgba(255, 255, 255, 0.7);
+    /* 鼠标悬停时稍微不那么透明 */
 }
 
 /* 工具栏样式 */
 ion-toolbar {
-    --background: #ffffff;
+    --background: transparent;
+    /* 设置为透明,以便背景从 ion-app 继承 */
     --color: #333;
     border-bottom: 1px solid #e0e0e0;
 }
@@ -50,4 +89,38 @@ ion-toolbar {
 /* 返回按钮样式 */
 ion-back-button {
     --color: #007bff;
+}
+
+/* 为每个卡片添加背景图片和不同的渐变背景 */
+ion-card:nth-child(1) {
+    background: linear-gradient(135deg, #fd7a59, #eaf4ba), url('/assets/images/card1.jpg');
+    /* 渐变背景和图片背景 */
+    background-blend-mode: multiply;
+    /* 混合模式 */
+    background-size: cover;
+    /* 背景图片覆盖整个卡片 */
+    background-position: center;
+    /* 背景图片居中 */
+}
+
+ion-card:nth-child(2) {
+    background: linear-gradient(135deg, #39a6f9, hsl(311, 73%, 87%)), url('/assets/images/card2.jpg');
+    /* 渐变背景和图片背景 */
+    background-blend-mode: multiply;
+    /* 混合模式 */
+    background-size: cover;
+    /* 背景图片覆盖整个卡片 */
+    background-position: center;
+    /* 背景图片居中 */
+}
+
+ion-card:nth-child(3) {
+    background: linear-gradient(135deg, #24f919, #e8f5aa), url('/assets/images/card3.jpg');
+    /* 渐变背景和图片背景 */
+    background-blend-mode: multiply;
+    /* 混合模式 */
+    background-size: cover;
+    /* 背景图片覆盖整个卡片 */
+    background-position: center;
+    /* 背景图片居中 */
 }

+ 33 - 28
novel-app/src/app/world-setup/world-setup.page.html

@@ -3,40 +3,45 @@
     <ion-buttons slot="start">
       <ion-back-button defaultHref="/toolbox"></ion-back-button>
     </ion-buttons>
-    <ion-title>人物设定生成</ion-title>
+    <ion-title>世界架构设定</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true" class="ion-padding">
+<ion-content [fullscreen]="true" class="ion-padding"
+  style="background-image: url('../../assets/images/background-image6.jpg'); background-size: cover; background-position: center; background-repeat: no-repeat;">
 
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>小说类型</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-input [(ngModel)]="type" (ionInput)="typeInput($event)" placeholder="请输入小说类型"></ion-input>
-    </ion-card-content>
-  </ion-card>
+  <!-- 使用 ion-grid 包裹所有行,确保布局正确 -->
+  <ion-grid>
 
-  <ion-card>
-    <ion-card-header>
-      <ion-card-title>期望描述</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-textarea [value]="userPrompt" (ionChange)="promptInput($event)" placeholder="请输入小说背景"></ion-textarea>
-    </ion-card-content>
-  </ion-card>
+    <ion-row>
+      <ion-col size="12">
+        <ion-label>小说背景</ion-label>
+        <ion-textarea [value]="novelBackground" (ionChange)="backgroundInput($event)" placeholder="请输入小说背景"
+          class="textarea-field" rows="5"></ion-textarea>
+      </ion-col>
+    </ion-row>
 
-  <ion-button expand="block" (click)="sendMessage()">生成世界架构</ion-button>
+    <ion-row>
+      <ion-col size="12">
+        <ion-label>期望描述</ion-label>
+        <ion-textarea [value]="userPrompt" (ionChange)="promptInput($event)" placeholder="请输入期望描述"
+          class="textarea-field" rows="5"></ion-textarea> <!-- 增加 rows 属性 -->
+      </ion-col>
+    </ion-row>
 
-  <ion-card *ngIf="responseMsg">
-    <ion-card-header>
-      <ion-card-title>生成的世界架构</ion-card-title>
-    </ion-card-header>
-    <ion-card-content>
-      <ion-textarea [value]="responseMsg" readonly class="response-textarea"></ion-textarea>
-      <ion-button expand="block" (click)="copyToClipboard()">复制</ion-button>
-    </ion-card-content>
-  </ion-card>
+    <ion-row>
+      <ion-col size="12">
+        <ion-button expand="block" (click)="sendMessage()" class="generate-button">生成世界架构</ion-button>
+      </ion-col>
+    </ion-row>
 
+    <ion-row *ngIf="responseMsg">
+      <ion-col size="12">
+        <ion-label>生成的世界架构</ion-label>
+        <ion-textarea [value]="responseMsg" readonly class="response-textarea" rows="10"></ion-textarea>
+        <!-- 增加 rows 属性 -->
+        <ion-button expand="block" (click)="copyToClipboard()" class="copy-button">复制</ion-button>
+      </ion-col>
+    </ion-row>
+  </ion-grid>
 </ion-content>

+ 56 - 17
novel-app/src/app/world-setup/world-setup.page.scss

@@ -1,27 +1,66 @@
-ion-card {
-    margin-bottom: 16px;
-    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
-    border-radius: 8px;
+/* 全局样式 */
+
+ion-app {
+    background: url('/assets/images/background-image6.jpg') no-repeat center center fixed;
+    /* 添加背景图片 */
+    background-size: cover;
+    /* 背景图片覆盖整个内容区域 */
+    background-position: center;
+    /* 背景图片居中 */
+    height: 100vh;
+    /* 确保背景覆盖整个视口高度 */
+    margin: 0;
+    /* 移除默认的外边距 */
+    padding: 0;
+    /* 移除默认的内边距 */
 }
 
-ion-card-header {
-    background-color: #f8f9fa;
-    border-bottom: 1px solid #dee2e6;
+ion-content {
+    --background: transparent;
+    /* 设置为透明,以便背景从 ion-app 继承 */
+    padding: 16px;
+    overflow: auto;
+    /* 确保内容可以滚动 */
+}
+
+:host {
+    --page-padding: 16px;
+    --primary-color: #003366;
+    /* 深蓝色 */
+    --secondary-color: #336633;
+    /* 墨绿色 */
+    --background-color: #f5f5f5;
+    --text-color: #333333;
+    --highlight-color: #ffcc00;
+    /* 高亮颜色 */
+}
+
+.input-field {
+    width: 100%;
+}
+
+.reader-group-button {
+    width: 100%;
+    margin-bottom: 10px;
+}
+
+.textarea-field {
+    width: 100%;
+    min-height: 150px;
+    /* 设置最小高度 */
 }
 
-ion-card-title {
-    font-size: 1.25rem;
-    font-weight: bold;
-    color: #343a40;
+.generate-button {
+    margin-top: 20px;
 }
 
-ion-card-content {
-    padding: 30px;
+.copy-button {
+    margin-top: 10px;
 }
 
 ion-button {
     --background: #007bff;
-    --color: #fff;
+    --color: #101010;
     --border-radius: 8px;
     --padding-top: 12px;
     --padding-bottom: 12px;
@@ -71,10 +110,10 @@ ion-input:focus {
     --box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
 }
 
-/* 设置生成的人物设定文本框的高度 */
+/* 设置生成的小说书名文本框的高度 */
 .response-textarea {
-    --min-height: 200px;
-    /* 设置更高的最小高度 */
+    --min-height: 800px;
+    /* 将最小高度增加到 800px */
     border-color: #80bdff;
     /* 可选:设置不同的边框颜色以区分 */
     background-color: #f8f9fa;

+ 19 - 12
novel-app/src/app/world-setup/world-setup.page.ts

@@ -1,7 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons, IonCardContent, IonCardTitle, IonCardHeader, IonCard } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons, IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonCol, IonRow, IonLabel, IonGrid } from '@ionic/angular/standalone';
 import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
 
 @Component({
@@ -13,7 +13,7 @@ import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
     CommonModule, // 确保 CommonModule 已经导入
     FormsModule,
     IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonTextarea, IonInput, IonBackButton, IonButtons,
-    IonCardContent, IonCardTitle, IonCardHeader, IonCard,
+    IonCardContent, IonCardTitle, IonCardHeader, IonCard, IonCol, IonRow, IonLabel, IonGrid,
     // 引入fm-markdown-preview组件模块
     MarkdownPreviewModule
   ],
@@ -22,21 +22,24 @@ export class WorldSetupPage implements OnInit {
 
   constructor() { }
   ngOnInit() { }
+  novelBackground: string = '在一个神秘的星球上,有许多不同的种族,他们都有着自己独特的文化和历史。';
+  responseMsg: string = '';
 
-  // 用户输入提示词
-  type: string = "东方玄幻";
-  typeInput(ev: any) {
-    this.type = ev.detail.value;
+
+
+  backgroundInput(event: any) {
+    this.novelBackground = event.target.value;
   }
 
   // 用户输入提示词
-  userPrompt: string = "古代";
+  userPrompt: string = "我希望这个世界有强大的魔法体系,主角从一个普通少年成长为一代宗师。";
   promptInput(ev: any) {
     this.userPrompt = ev.detail.value;
   }
 
-  // 属性:组件内用于展示消息内容的变量
-  responseMsg: any = "";
+
+
+
 
   // 方法:实例化completion对象,传入消息数组,并订阅生成的可观察对象。
   isComplete: boolean = false; // 定义完成状态属性,用来标记是否补全完成
@@ -44,9 +47,13 @@ export class WorldSetupPage implements OnInit {
     console.log("create");
 
     let PromptTemplate = `
-    您作为一名专业的${this.type}小说作者,请您根据用户提供的期望描述,给出一个世界架构设定。
-    以下是用户的口述:${this.userPrompt}
-    `;
+  您作为一名专业的小说作者,请您根据以下信息生成一个详细的世界架构设定:
+  
+  小说背景:${this.novelBackground}
+  用户期望:${this.userPrompt}
+  
+  请确保生成的世界架构与上述信息紧密相关,并且符合小说的整体风格。
+`;
 
     let completion = new FmodeChatCompletion([
       { role: "system", content: "" },

二进制
novel-app/src/assets/images/background-image1.jpg


二进制
novel-app/src/assets/images/background-image2.jpg


二进制
novel-app/src/assets/images/background-image3.jpg


二进制
novel-app/src/assets/images/background-image4.jpg


二进制
novel-app/src/assets/images/background-image5.jpg


二进制
novel-app/src/assets/images/background-image6.jpg


二进制
novel-app/src/assets/images/banner1.jpg


二进制
novel-app/src/assets/images/banner2.jpg


二进制
novel-app/src/assets/images/banner3.jpg


二进制
novel-app/src/assets/images/banner4.jpg


二进制
novel-app/src/assets/images/banner5.jpg


二进制
novel-app/src/assets/images/card1.jpg


二进制
novel-app/src/assets/images/card2.jpg


二进制
novel-app/src/assets/images/card3.jpg


二进制
novel-app/src/assets/images/floating-button.gif


二进制
novel-app/src/assets/images/logo1.png


二进制
novel-app/src/assets/images/short-generator-icon.png


二进制
novel-app/src/assets/images/story-generator-icon.png


二进制
novel-app/src/assets/images/toolbox-icon.png


二进制
novel-app/src/assets/images/首页顶部图.png


+ 4 - 3
novel-app/src/index.html

@@ -3,12 +3,13 @@
 
 <head>
   <meta charset="utf-8" />
-  <title>Ionic App</title>
+  <title>幻书坊:ai小说app</title>
 
   <base href="/" />
 
   <meta name="color-scheme" content="light dark" />
-  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
+  <meta name="viewport"
+    content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
   <meta name="format-detection" content="telephone=no" />
   <meta name="msapplication-tap-highlight" content="no" />
 
@@ -23,4 +24,4 @@
   <app-root></app-root>
 </body>
 
-</html>
+</html>