15949524127 1 سال پیش
والد
کامیت
511305ab80

+ 18 - 0
deploy.ps1

@@ -0,0 +1,18 @@
+# 打包项目,携带应用前缀(index.html中相对路径将自动修复为/dev/jxnu/<学号>前缀)
+# /dev/ 项目测试版上传路径
+# /dev/jxnu/<学号> nova-crm项目预留路径
+set NODE_OPTIONS=–max_old_space_size=16000
+node ./node_modules/@angular/cli/bin/ng build --base-href="/dev/jxnu/202226701020/"
+
+# 清空旧文件目录
+obsutil rm obs://nova-cloud/dev/jxnu/202226701020 -r -f -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com"
+
+# 同步文件目录
+obsutil sync ./www obs://nova-cloud/dev/jxnu/202226701020  -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com" -acl=public-read
+
+
+# 授权公开可读
+obsutil chattri obs://nova-cloud/dev/jxnu/202226701020 -r -f -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com" -acl=public-read
+
+# 列举对象
+obsutil ls obs://nova-cloud/dev/jxnu/202226701020  -i=XSUWJSVMZNHLWFAINRZ1 -k=P4TyfwfDovVNqz08tI1IXoLWXyEOSTKJRVlsGcV6 -e="obs.cn-south-1.myhuaweicloud.com"

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 655 - 19
package-lock.json


+ 1 - 0
package.json

@@ -30,6 +30,7 @@
     "@capacitor/status-bar": "6.0.2",
     "@ionic/angular": "^8.0.0",
     "chart.js": "^4.4.7",
+    "fmode-ng": "^0.0.63",
     "ionicons": "^7.2.1",
     "parse": "^5.3.0",
     "rxjs": "~7.8.0",

+ 39 - 0
src/app/poem-picture/poem-picture.component.html

@@ -0,0 +1,39 @@
+<ion-header [translucent]="true">
+  <ion-toolbar class="custom-toolbar">
+    <ion-title class="custom-title">
+      个性化头像生成
+    </ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <!-- 生成提示词 -->
+  <ion-textarea [value]="userPrompt" (ionInput)="promptInput($event)" placeholder="请输入头像要求(示例:画风采用动漫风,一位长发飘飘的女孩抬头仰望着天空微笑。)" autoGrow="true"></ion-textarea>
+  <ion-button (click)="createImage()" expand="block" color="success">头像生成</ion-button>
+  <!-- 意境画面提示词 -->
+  <div class="desc">
+    {{PictureDescResult}}
+  </div>
+  <!-- 生成结果 -->
+  @if(images.length) {
+    @for(imageUrl of images;track imageUrl){
+      <img [src]="imageUrl || '../../assets/image/logo.png'" alt="" srcset="">
+    }
+
+    <h3>图片地址:
+      <span class="copyable">{{images.join(', ')}}</span>
+    </h3>
+
+  }
+  <!-- 生成状态 -->
+  @if(!images.length){
+    <h2 style="display: grid; place-items: center;">欢迎使用头像生成器</h2>
+    @if(imagineWork.progress!=0){
+      <h1 style="display: grid; place-items: center;">生成中:{{imagineWork.progress}}</h1>
+    }
+    <div style="display: grid; place-items: center;">
+      <img src="https://app.fmode.cn/dev/jxnu/202226701019/头像生成器.png">
+    </div>
+  }
+
+</ion-content>

+ 93 - 0
src/app/poem-picture/poem-picture.component.scss

@@ -0,0 +1,93 @@
+.custom-toolbar {
+    --background: rgba(255, 255, 255, 0.8); /* 使工具栏背景透明 */
+    display: flex; /* 使用 Flexbox 布局 */
+    justify-content: center; /* 水平居中 */
+    align-items: center; /* 垂直居中 */
+    padding: 0; /* 去掉默认内边距 */
+}
+
+.custom-title {
+    font-size: 1.3em; /* 字体大小 */
+    font-weight: bold; /* 加粗 */
+    color: #000000; 
+    text-align: center; /* 文字居中对齐 */
+    margin: 0; /* 去掉默认外边距 */
+    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); /* 添加文字阴影效果 */
+    /* 添加其他美化效果 */
+    font-family: "微软雅黑"; /* 自定义字体 */
+}
+
+/* 全局样式 */
+ion-content {
+    background-color: #7acbd9; /* 背景颜色 */
+    padding: 20px; /* 内边距 */
+    font-family: 'Arial', sans-serif; /* 字体 */
+  }
+  
+  /* 文本区域样式 */
+  ion-textarea {
+    border: 1px solid #55e788; /* ���框颜色 */
+    border-radius: 8px; /* 圆角 */
+    padding: 10px; /* 内边距 */
+    font-size: 16px; /* 字体大小 */
+    color: #333; /* 字体颜色 */
+    background-color: #fff; /* 背景颜色 */
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 阴影效果 */
+  }
+  
+  /* 按钮样式 */
+  ion-button {
+    background-color: #6be4ea; /* 按钮背景颜色 */
+    color: white; /* 按钮文字颜色 */
+    border-radius: 8px; /* 圆角 */
+    font-size: 18px; /* 字体大小 */
+    padding: 10px; /* 内边距 */
+    transition: background-color 0.3s; /* 背景颜色过渡效果 */
+  }
+  
+  ion-button:hover {
+    background-color: #53d888; /* 悬停时的背景颜色 */
+  }
+  
+  /* 图片容器样式 */
+  img {
+    max-width: 100%; /* 最大宽度为100% */
+    height: auto; /* 高度自动 */
+    border-radius: 8px; /* 圆角 */
+    margin-top: 10px; /* 上边距 */
+  }
+  
+  /* 图片地址样式 */
+  h3 {
+    color: #555; /* 字体颜色 */
+    font-size: 14px; /* 字体大小 */
+    margin-top: 10px; /* 上边距 */
+  }
+  
+  /* 生成状态样式 */
+  h1 {
+    color: #333; /* 字体颜色 */
+    font-size: 24px; /* 字体大小 */
+    text-align: center; /* 居中对齐 */
+    margin-top: 20px; /* 上边距 */
+  }
+  
+  /* 意境画面提示词样式 */
+  .desc {
+    background-color: #8ceea6; /* 背景颜色 */
+    border: 1px solid #24e34e; /* 边框颜色 */
+    border-radius: 8px; /* 圆角 */
+    padding: 15px; /* 内边距 */
+    margin-top: 20px; /* 上边距 */
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* 阴影效果 */
+  }
+
+  .copyable {
+    user-select: text; /* 允许文本选择 */
+    background-color: #f9f9f9; /* 背景颜色 */
+    padding: 5px; /* 内边距 */
+    border: 1px solid #ccc; /* 边框 */
+    border-radius: 4px; /* 圆角 */
+    display: inline-block; /* 使其呈现为块级元素 */
+    cursor: text; /* 鼠标悬停时显示文本光标 */
+  }

+ 22 - 0
src/app/poem-picture/poem-picture.component.spec.ts

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

+ 84 - 0
src/app/poem-picture/poem-picture.component.ts

@@ -0,0 +1,84 @@
+import { Component, OnInit } from '@angular/core';
+import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
+import { IonTextarea, IonButton,IonInput } from "@ionic/angular/standalone";
+import { DalleOptions, ImagineWork, FmodeChatCompletion } from 'fmode-ng';
+
+@Component({
+  selector: 'app-poem-picture',
+  templateUrl: './poem-picture.component.html',
+  styleUrls: ['./poem-picture.component.scss'],
+  standalone: true,
+  imports: [
+    IonHeader, IonToolbar, IonTitle, IonContent, 
+    IonButton,
+    IonInput,
+    IonTextarea
+  ],
+})
+
+export class PoemPictureComponent  implements OnInit {
+  /**
+   * 用户输入的文本
+   */
+  userPrompt:string = ""
+  promptInput(ev:any){
+    console.log(ev.detail.value)
+    if (ev.detail.value.length > 0){
+      this.userPrompt = ev.detail.value;
+    }
+  }
+
+  imagineWork:ImagineWork
+  images:Array<string> = []
+  constructor(
+  ){
+    // 示例任务,自己生成图片后请存储新的ID 
+    this.imagineWork = new ImagineWork("");
+    this.imagineWork.fetchTask().then(work=>{
+      if(work){
+        this.imagineWork.id = work.id
+      }
+      this.images = this.imagineWork?.images || '../../assets/image/头像示例.png';
+    })
+  }
+
+  PictureDescResult:string = `` // 画面描述结果
+  async createImage(){
+    this.imagineWork = new ImagineWork();
+    if (this.userPrompt.length > 0){
+    // 文本生成
+    let PromptTemplate = `您是一名专业的图片设计师,擅长设计各类型适合作为头像的唯美图片,请您根据下面提供的需求内容,将其描述的画面、场景、人物、物品等用最简短的语言表达,直接写出画面,并且要贴合描述的画风为主
+    需求如下:
+    ${this.userPrompt}
+    `
+    let completion = new FmodeChatCompletion([
+      {role:"system",content:""},
+      {role:"user",content:PromptTemplate}
+    ])
+    completion.sendCompletion().subscribe((message:any)=>{
+      // 打印消息体
+      console.log(message.content)
+      // 赋值消息内容给组件内属性
+      this.PictureDescResult = message.content
+      if(message?.complete){ // 判断message为完成状态,则设置isComplete为完成
+        // 图片生成
+        let PicturePrompt = `${this.PictureDescResult}\n风格:画面不带任何文字。人物为主体占据整个图片的3/4。正面特写。人物不可呈现怪异形态。不可出现分割。`
+      let options:DalleOptions = {prompt:PicturePrompt}
+      this.imagineWork?.draw(options).subscribe(work=>{
+          console.log("imagineWork",work?.toJSON())
+          console.log("images",work?.get("images"))
+          if(work?.get("images")?.length){
+            this.images = work?.get("images");
+          }
+      })
+      }
+    })
+  }
+  else{
+    this.userPrompt = "请提供您理想头像的组成内容,我将根据其意境为您创作一幅画面的简短描述。"
+  }
+    
+  }
+  ngOnInit() {}
+
+}

+ 2 - 3
src/app/tab4/tab4.page.html

@@ -6,7 +6,6 @@
   </ion-toolbar>
 </ion-header>
 <ion-content [fullscreen]="true">
- 
   <!-- 用户登录状态 -->
   <ion-card>
     <!-- 未登录 -->
@@ -16,10 +15,10 @@
               <ion-card-header>
                   <ion-card-title>请登录</ion-card-title>
                   <ion-card-subtitle>暂无信息</ion-card-subtitle>
-                  <ion-card-content>欢迎来到"生活智伴"!在这里,我们致力于成为您生活中的智慧伙伴。通过科学的生活规划和健康管理,让您的每一天都充满活力与平衡。我们提供个性化的生活建议,帮助您建立健康的生活方式,享受高质量的生活。让我们一起探索智慧生活的美好,开启健康快乐的人生旅程!登录后,您将获得更多贴心的生活建议和个性化服务。现在就加入我们,让生活更有智慧,让每一天都更加美好!</ion-card-content>
+                  <ion-card-content>欢迎来到“智养人生”!在这里,我们为您提供科学、全面的健康管理方案,帮助您实现身心的和谐与平衡。无论是饮食、运动还是心理调适,我们的专业团队将为您量身定制个性化的健康计划。让我们一起探索智慧养生的奥秘,开启健康新生活!登录后,您将踏上智养之旅,发现更好的自己。欢迎您的加入,智养人生,从此刻开始!</ion-card-content>
               </ion-card-header>
               <div class="image-container">
-                <img src="assets/images/lifepartner.jpg" alt="" class="responsive-image">
+                <img src="https://app.fmode.cn/dev/jxnu/202226701019/logo.png" alt="健康主题图片" class="responsive-image">
             </div>
           </ion-card>
       </ion-content>

+ 2 - 2
src/app/tab4/tab4.page.ts

@@ -1,5 +1,5 @@
 import { Component } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, AlertController } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonCard, IonCardContent, IonButton, IonCardHeader, IonCardTitle, IonCardSubtitle, ModalController, AlertController, IonRefresher, IonRefresherContent } from '@ionic/angular/standalone';
 
 import { Router } from '@angular/router';
 import { openUserLoginModal } from '../../lib/user/modal-user-login/modal-user-login.component';
@@ -13,7 +13,7 @@ import { AuthService } from '../services/auth.service';
   templateUrl: 'tab4.page.html',
   styleUrls: ['tab4.page.scss'],
   standalone: true,
-  imports: [
+  imports: [IonRefresherContent, IonRefresher, 
     IonHeader, IonToolbar, IonTitle, IonContent, 
     IonCard, IonCardContent, IonButton, IonCardHeader, 
     IonCardTitle, IonCardSubtitle,

+ 5 - 0
src/app/tabs/tabs.routes.ts

@@ -25,6 +25,11 @@ export const routes: Routes = [
         loadComponent: () =>
           import('../tab4/tab4.page').then((m) => m.Tab4Page),
       },
+      {
+        path: 'picture',
+        loadComponent: () =>
+          import('../poem-picture/poem-picture.component').then((m) => m.PoemPictureComponent),
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 26 - 13
src/main.ts

@@ -1,19 +1,32 @@
-import { enableProdMode } from '@angular/core';
 import { bootstrapApplication } from '@angular/platform-browser';
-import { AppComponent } from './app/app.component';
-import { provideRouter } from '@angular/router';
+import { RouteReuseStrategy, provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
+import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
+
 import { routes } from './app/app.routes';
-import { provideIonicAngular } from '@ionic/angular/standalone';
-import * as Parse from 'parse';
+import { AppComponent } from './app/app.component';
+
+
+// 引用HttpClient方法
+import { provideHttpClient } from '@angular/common/http';
+// 引用移动端授权检测供应器
+// import { Diagnostic } from '@awesome-cordova-plugins/diagnostic/ngx';
+// 设置Parse服务属性
+import Parse from "parse";
+Parse.initialize("ncloudmaster");
+Parse.serverURL = "https://server.fmode.cn/parse";
+localStorage.setItem("NOVA_APIG_SERVER", 'aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG')
 
-// 初始化 Parse
-Parse.initialize('YOUR_APP_ID', 'YOUR_JS_KEY');
-(Parse as any).serverURL = 'http://dev.fmode.cn:1337/parse';
+// 注意:替换Token 根据Token设置Parse服务帐套权限
+Parse.User.become('r:ef31d9ab3a3eef080f4a0920a8e463e6')
 
-// 启动应用
 bootstrapApplication(AppComponent, {
   providers: [
-    provideRouter(routes),
-    provideIonicAngular({})
-  ]
-}).catch(err => console.error(err));
+    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
+    provideIonicAngular(),
+    provideRouter(routes, withPreloading(PreloadAllModules)),
+     // 添加HttpClient供应器
+     provideHttpClient(),
+     // 添加Diagnostic
+    //  Diagnostic,
+  ],
+});

+ 1 - 0
tsconfig.json

@@ -2,6 +2,7 @@
 {
   "compileOnSave": false,
   "compilerOptions": {
+    "allowSyntheticDefaultImports":true,
     "baseUrl": "./src",
     "paths": {
       "src/*": ["*"]

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است