siyana 1 天之前
父节点
当前提交
cd338ef7a7

+ 2 - 1
angular.json

@@ -136,7 +136,8 @@
   "cli": {
   "cli": {
     "schematicCollections": [
     "schematicCollections": [
       "@ionic/angular-toolkit"
       "@ionic/angular-toolkit"
-    ]
+    ],
+    "analytics": "abe9b1bf-56fc-40c6-ab96-03076de3eccb"
   },
   },
   "schematics": {
   "schematics": {
     "@ionic/angular-toolkit:component": {
     "@ionic/angular-toolkit:component": {

文件差异内容过多而无法显示
+ 645 - 14
package-lock.json


+ 1 - 0
package.json

@@ -27,6 +27,7 @@
     "@capacitor/keyboard": "7.0.1",
     "@capacitor/keyboard": "7.0.1",
     "@capacitor/status-bar": "7.0.1",
     "@capacitor/status-bar": "7.0.1",
     "@ionic/angular": "^8.0.0",
     "@ionic/angular": "^8.0.0",
+    "fmode-ng": "^0.0.83",
     "ionicons": "^7.0.0",
     "ionicons": "^7.0.0",
     "rxjs": "~7.8.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "tslib": "^2.3.0",

+ 1 - 0
src/app/app-routing.module.ts

@@ -5,6 +5,7 @@ const routes: Routes = [
   {
   {
     path: '',
     path: '',
     loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
     loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
+    
   }
   }
 ];
 ];
 @NgModule({
 @NgModule({

+ 18 - 2
src/app/app.module.ts

@@ -7,10 +7,26 @@ import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
 import { AppRoutingModule } from './app-routing.module';
 import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
 import { AppComponent } from './app.component';
 
 
+// fmode-ng依赖的服务
+import { HttpClientModule } 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')
+
 @NgModule({
 @NgModule({
   declarations: [AppComponent],
   declarations: [AppComponent],
-  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
-  providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
+  imports: [
+    HttpClientModule,
+    BrowserModule, 
+    IonicModule.forRoot(),
+    AppRoutingModule],
+  providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
+    //fmode-ng 依赖服务注入
+    Diagnostic,
+  ],
   bootstrap: [AppComponent],
   bootstrap: [AppComponent],
 })
 })
 export class AppModule {}
 export class AppModule {}

+ 167 - 110
src/app/tab1/tab1.page.html

@@ -1,5 +1,6 @@
 
 
 
 
+
 <ion-content [fullscreen]="true">
 <ion-content [fullscreen]="true">
   <header class="header">
   <header class="header">
     <div class="container header-container">
     <div class="container header-container">
@@ -13,126 +14,182 @@
         </div>
         </div>
     </div>
     </div>
 </header>
 </header>
-  <div id="home-page" class="page active">
-    <div class="container">
-        <!-- 轮播广告区 -->
-        <div class="section">
-            <div class="banner">
-                
-                <div class="banner-dots">
-                    <div class="banner-dot active"></div>
-                    <div class="banner-dot"></div>
-                    <div class="banner-dot"></div>
-                </div>
-            </div>
-        </div>
-
-        <!-- 分类快捷入口 -->
-        <div class="section">
-            <div class="category-grid">
-                <div class="category-item">
-                    <div class="category-icon">
-                        <i class="iconfont icon-hot"></i>
-                    </div>
-                    <div class="category-name">热血</div>
-                </div>
-                <div class="category-item">
-                    <div class="category-icon">
-                        <i class="iconfont icon-love"></i>
-                    </div>
-                    <div class="category-name">恋爱</div>
-                </div>
-                <div class="category-item">
-                    <div class="category-icon">
-                        <i class="iconfont icon-fantasy"></i>
+          <div id="home-page" class="page active">
+            <div class="container">
+                <!-- 轮播广告区 -->
+                <div class="section">
+                    <div class="banner">
+                        <img src="assets/icon/doupo.jpeg">
+                        <div class="banner-dots">
+                            <div class="banner-dot active"></div>
+                            <div class="banner-dot"></div>
+                            <div class="banner-dot"></div>
+                        </div>
                     </div>
                     </div>
-                    <div class="category-name">玄幻</div>
                 </div>
                 </div>
-                <div class="category-item">
-                    <div class="category-icon">
-                        <i class="iconfont icon-school"></i>
-                    </div>
-                    <div class="category-name">校园</div>
-                </div>
-            </div>
-        </div>
 
 
-        <!-- 每日更新 -->
-        <div class="section">
-            <div class="section-header">
-                <h2 class="section-title">每日更新</h2>
-                <a href="#" class="section-more">更多 ></a>
-            </div>
-            <div class="comic-list">
-                <div class="comic-item" data-comic-id="1">
-                    <div class="comic-cover">
-                        
-                        <div class="comic-vip">VIP</div>
-                    </div>
-                    <div class="comic-info">
-                        <div class="comic-title">斗破苍穹</div>
-                        <div class="comic-author">作者: 天蚕土豆</div>
+                <!-- 分类快捷入口 -->
+                <div class="section">
+                    <div class="category-grid">
+                        <div class="category-item">
+                            <div class="category-icon">
+                                <i class="iconfont icon-hot"></i>
+                            </div>
+                            <div class="category-name">热血</div>
+                        </div>
+                        <div class="category-item">
+                            <div class="category-icon">
+                                <i class="iconfont icon-love"></i>
+                            </div>
+                            <div class="category-name">恋爱</div>
+                        </div>
+                        <div class="category-item">
+                            <div class="category-icon">
+                                <i class="iconfont icon-fantasy"></i>
+                            </div>
+                            <div class="category-name">玄幻</div>
+                        </div>
+                        <div class="category-item">
+                            <div class="category-icon">
+                                <i class="iconfont icon-school"></i>
+                            </div>
+                            <div class="category-name">校园</div>
+                        </div>
                     </div>
                     </div>
                 </div>
                 </div>
-                <div class="comic-item" data-comic-id="2">
-                    <div class="comic-cover">
-                       
-                    </div>
-                    <div class="comic-info">
-                        <div class="comic-title">一人之下</div>
-                        <div class="comic-author">作者: 米二</div>
-                    </div>
-                </div>
-                <div class="comic-item" data-comic-id="3">
-                    <div class="comic-cover">
-                        
-                        <div class="comic-vip">VIP</div>
-                    </div>
-                    <div class="comic-info">
-                        <div class="comic-title">狐妖小红娘</div>
-                        <div class="comic-author">作者: 小新</div>
-                    </div>
-                </div>
-            </div>
-        </div>
 
 
-        <!-- 热门推荐 -->
-        <div class="section">
-            <div class="section-header">
-                <h2 class="section-title">热门推荐</h2>
-                <a href="#" class="section-more">更多 ></a>
-            </div>
-            <div class="comic-list">
-                <div class="comic-item" data-comic-id="4">
-                    <div class="comic-cover">
+                <!-- 每日更新 -->
+                <div class="section">
+                    <div class="section-header">
+                        <h2 class="section-title">每日更新</h2>
+                        <a href="#" class="section-more">更多 ></a>
+                    </div>
+                    <div class="comic-list">
+                        <div class="comic-item" data-comic-id="1">
+                            <div class="comic-cover">
+                                <img src="assets/icon/doupo.jpeg" alt="漫画封面">
+                                <div class="comic-vip">VIP</div>
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">斗破苍穹</div>
+                                <div class="comic-author">作者: 天蚕土豆</div>
+                            </div>
+                        </div>
                         
                         
-                    </div>
-                    <div class="comic-info">
-                        <div class="comic-title">全职高手</div>
-                        <div class="comic-author">作者: 蝴蝶蓝</div>
+                        <div class="comic-item" data-comic-id="2">
+                            <div class="comic-cover">
+                                <img src="assets/icon/yiren.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">一人之下</div>
+                                <div class="comic-author">作者: 米二</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="3">
+                            <div class="comic-cover">
+                                <img src="assets/icon/huyao.jpeg" alt="漫画封面">
+                                <div class="comic-vip">VIP</div>
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">狐妖小红娘</div>
+                                <div class="comic-author">作者: 小新</div>
+                            </div>
+                        </div>
                     </div>
                     </div>
                 </div>
                 </div>
-                <div class="comic-item" data-comic-id="5">
-                    <div class="comic-cover">
-                        
-                        <div class="comic-vip">VIP</div>
-                    </div>
-                    <div class="comic-info">
-                        <div class="comic-title">斗罗大陆</div>
-                        <div class="comic-author">作者: 唐家三少</div>
-                    </div>
-                </div>
-                <div class="comic-item" data-comic-id="6">
-                    <div class="comic-cover">
-                        
-                    </div>
-                    <div class="comic-info">
-                        <div class="comic-title">镇魂街</div>
-                        <div class="comic-author">作者: 许辰</div>
+
+                <!-- 热门推荐 -->
+                <div class="section">
+                    <div class="section-header">
+                        <h2 class="section-title">热门推荐</h2>
+                        <a href="#" class="section-more">更多 ></a>
+                    </div>
+                    <div class="comic-list">
+                        <div class="comic-item" data-comic-id="4">
+                            <div class="comic-cover">
+                                <img src="assets/icon/quanzhi.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">全职高手</div>
+                                <div class="comic-author">作者: 蝴蝶蓝</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="5">
+                            <div class="comic-cover">
+                                <img src="assets/icon/douluo.jpeg" alt="漫画封面">
+                                <div class="comic-vip">VIP</div>
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">斗罗大陆</div>
+                                <div class="comic-author">作者: 唐家三少</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="6">
+                            <div class="comic-cover">
+                                <img src="assets/icon/zhenhun.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">镇魂街</div>
+                                <div class="comic-author">作者: 许辰</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="7">
+                            <div class="comic-cover">
+                                <img src="assets/icon/riyue.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">日月同错</div>
+                                <div class="comic-author">作者: 第年秒</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="8">
+                            <div class="comic-cover">
+                                <img src="assets/icon/xiedi.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">我为邪帝</div>
+                                <div class="comic-author">作者: 时代漫王</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="9">
+                            <div class="comic-cover">
+                                <img src="assets/icon/shaoson.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">绍宋</div>
+                                <div class="comic-author">作者: 李晓楠</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="10">
+                            <div class="comic-cover">
+                                <img src="assets/icon/mohuang.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">魔皇大管家</div>
+                                <div class="comic-author">作者: 夜枭</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="11">
+                            <div class="comic-cover">
+                                <img src="assets/icon/fanpai.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">我!天命大反派</div>
+                                <div class="comic-author">作者: 天命反派</div>
+                            </div>
+                        </div>
+                        <div class="comic-item" data-comic-id="12">
+                            <div class="comic-cover">
+                                <img src="assets/icon/dianju.jpeg" alt="漫画封面">
+                            </div>
+                            <div class="comic-info">
+                                <div class="comic-title">电锯人</div>
+                                <div class="comic-author">作者: 藤本树</div>
+                            </div>
+                        </div>
                     </div>
                     </div>
                 </div>
                 </div>
             </div>
             </div>
         </div>
         </div>
-    </div>
-</div>
-</ion-content>
+        
+</ion-content>

+ 33 - 114
src/app/tab2/tab2.page.html

@@ -1,117 +1,36 @@
 
 
 <ion-content [fullscreen]="true">
 <ion-content [fullscreen]="true">
-  <div class="container">
-    <!-- 顶部导航栏 -->
-    <div class="top-nav">
-        <button class="back-btn">
-            <i class="vant-icon vant-icon-arrow-left"></i>
-        </button>
-        <div class="nav-title">排行榜</div>
-        <button class="search-btn">
-            <i class="vant-icon vant-icon-search"></i>
-        </button>
-    </div>
-    
-    <!-- 榜单分类区 -->
-    <div class="category-tabs">
-        <div class="tab-item active">热门动漫</div>
-        <div class="tab-item">最新更新</div>
-        <div class="tab-item">热血漫画</div>
-        <div class="tab-item">恋爱漫画</div>
-        <div class="tab-item">玄幻奇幻</div>
-        <div class="tab-item">悬疑推理</div>
-        <div class="tab-item">搞笑日常</div>
-    </div>
-    
-    <!-- 漫画展示区 -->
-    <div class="comic-list">
-        <!-- 漫画卡片1 -->
-        <div class="comic-card">
-            <div class="rank-badge top1">1</div>
-            <img src="https://via.placeholder.com/100x130/ff9999/ffffff?text=漫画1" alt="漫画封面" class="comic-cover">
-            <div class="comic-info">
-                <div>
-                    <h3 class="comic-title">斗罗大陆</h3>
-                    <p class="comic-author">作者:唐家三少</p>
-                    <p class="comic-update">更新至第320章</p>
-                </div>
-                <div class="comic-popularity">
-                    <i class="vant-icon vant-icon-fire-o popularity-icon"></i>
-                    <span>月平均热度 20546</span>
-                </div>
-            </div>
-        </div>
-        
-        <!-- 漫画卡片2 -->
-        <div class="comic-card">
-            <div class="rank-badge top3">2</div>
-            <img src="https://via.placeholder.com/100x130/99ccff/ffffff?text=漫画2" alt="漫画封面" class="comic-cover">
-            <div class="comic-info">
-                <div>
-                    <h3 class="comic-title">一人之下</h3>
-                    <p class="comic-author">作者:米二</p>
-                    <p class="comic-update">更新至第568章</p>
-                </div>
-                <div class="comic-popularity">
-                    <i class="vant-icon vant-icon-fire-o popularity-icon"></i>
-                    <span>月平均热度 19872</span>
-                </div>
-            </div>
-        </div>
-        
-        <!-- 漫画卡片3 -->
-        <div class="comic-card">
-            <div class="rank-badge top3">3</div>
-            <img src="https://via.placeholder.com/100x130/99ff99/ffffff?text=漫画3" alt="漫画封面" class="comic-cover">
-            <div class="comic-info">
-                <div>
-                    <h3 class="comic-title">狐妖小红娘</h3>
-                    <p class="comic-author">作者:小新</p>
-                    <p class="comic-update">更新至第112章</p>
-                </div>
-                <div class="comic-popularity">
-                    <i class="vant-icon vant-icon-fire-o popularity-icon"></i>
-                    <span>月平均热度 18765</span>
-                </div>
-            </div>
-        </div>
-        
-        <!-- 漫画卡片4 -->
-        <div class="comic-card">
-            <div class="rank-badge">4</div>
-            <img src="https://via.placeholder.com/100x130/ffcc99/ffffff?text=漫画4" alt="漫画封面" class="comic-cover">
-            <div class="comic-info">
-                <div>
-                    <h3 class="comic-title">全职高手</h3>
-                    <p class="comic-author">作者:蝴蝶蓝</p>
-                    <p class="comic-update">更新至第176章</p>
-                </div>
-                <div class="comic-popularity">
-                    <i class="vant-icon vant-icon-fire-o popularity-icon"></i>
-                    <span>月平均热度 17614</span>
-                </div>
-            </div>
-        </div>
-        
-        <!-- 漫画卡片5 -->
-        <div class="comic-card">
-            <div class="rank-badge">5</div>
-            <img src="https://via.placeholder.com/100x130/ccccff/ffffff?text=漫画5" alt="漫画封面" class="comic-cover">
-            <div class="comic-info">
-                <div>
-                    <h3 class="comic-title">镇魂街</h3>
-                    <p class="comic-author">作者:许辰</p>
-                    <p class="comic-update">更新至第309章</p>
-                </div>
-                <div class="comic-popularity">
-                    <i class="vant-icon vant-icon-fire-o popularity-icon"></i>
-                    <span>月平均热度 16543</span>
-                </div>
-            </div>
-        </div>
-    </div>
-    
-    <!-- 底部导航栏 -->
-    
-</div>
+  <ion-card class="artist-card">
+  <!-- 卡片头部(头像 + 名称) -->
+  <div class="card-header">
+    <img 
+      src="assets/icon/hoshino.jpeg" 
+      alt="星野 荐" 
+      class="artist-avatar"
+      (error)="handleImageError($event)"
+    />
+    <h2>星野 荐</h2>
+    <p class="subtitle">漫画推荐师 · 治愈系作者</p>
+  </div>
+
+  <!-- 描述内容 -->
+  <ion-card-content>
+    <p>
+      擅长挖掘冷门神作,能用「漫画处方」精准匹配你的灵魂需求。
+      代表作《星辰图书咖啡馆》隐藏无数彩蛋!
+    </p>
+  </ion-card-content>
+
+  <!-- 底部按钮 -->
+  <ion-button 
+    expand="block" 
+    fill="solid" 
+    color="primary" 
+    class="info-button"
+    (click)="openConsult()"
+  >
+    <ion-icon name="newspaper-outline" slot="start"></ion-icon>
+    查看资讯
+  </ion-button>
+</ion-card>
 </ion-content>
 </ion-content>

+ 44 - 204
src/app/tab2/tab2.page.scss

@@ -1,205 +1,45 @@
-* {
-    margin: 0;
-    padding: 0;
-    box-sizing: border-box;
-    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-}
-
-body {
-    background-color: #f5f5f5;
-    color: #333;
-    font-size: 14px;
-    line-height: 1.5;
-}
-
-.container {
-    max-width: 100%;
-    margin: 0 auto;
-    padding-bottom: 60px;
-}
-
-/* 顶部导航栏 */
-.top-nav {
-    position: sticky;
-    top: 0;
-    z-index: 100;
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-    padding: 10px 15px;
-    background-color: #fff;
-    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
-}
-
-.nav-title {
-    font-size: 18px;
-    font-weight: 600;
-    position: absolute;
-    left: 50%;
-    transform: translateX(-50%);
-}
-
-.back-btn {
-    font-size: 20px;
-    color: #666;
-    background: none;
-    border: none;
-    padding: 5px;
-}
-
-.search-btn {
-    font-size: 20px;
-    color: #666;
-    background: none;
-    border: none;
-    padding: 5px;
-}
-
-/* 榜单分类区 */
-.category-tabs {
-    display: flex;
-    overflow-x: auto;
-    padding: 10px 15px;
-    background-color: #fff;
-    white-space: nowrap;
-    scrollbar-width: none;
-}
-
-.category-tabs::-webkit-scrollbar {
-    display: none;
-}
-
-.tab-item {
-    padding: 8px 15px;
-    margin-right: 10px;
-    border-radius: 15px;
-    font-size: 14px;
-    background-color: #f5f5f5;
-    color: #666;
-    flex-shrink: 0;
-}
-
-.tab-item.active {
-    background-color: #ff4e4e;
-    color: #fff;
-}
-
-/* 漫画展示区 */
-.comic-list {
-    padding: 15px;
-}
-
-.comic-card {
-    display: flex;
-    margin-bottom: 15px;
-    background-color: #fff;
-    border-radius: 8px;
-    overflow: hidden;
-    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
-    position: relative;
-}
-
-.rank-badge {
-    position: absolute;
-    left: 0;
-    top: 0;
-    width: 30px;
-    height: 30px;
-    background-color: #ff4e4e;
-    color: #fff;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    font-weight: bold;
-    border-bottom-right-radius: 8px;
-    z-index: 1;
-}
-
-.rank-badge.top3 {
-    background-color: #ff9e00;
-}
-
-.rank-badge.top1 {
-    background-color: #ff4e4e;
-}
-
-.comic-cover {
-    width: 100px;
-    height: 130px;
-    object-fit: cover;
-    flex-shrink: 0;
-}
-
-.comic-info {
-    flex: 1;
-    padding: 12px;
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-}
-
-.comic-title {
-    font-size: 16px;
-    font-weight: 600;
-    margin-bottom: 5px;
-    display: -webkit-box;
-    -webkit-line-clamp: 1;
-    -webkit-box-orient: vertical;
-    overflow: hidden;
-}
-
-.comic-author {
-    font-size: 12px;
-    color: #999;
-    margin-bottom: 8px;
-}
-
-.comic-update {
-    font-size: 12px;
-    color: #ff4e4e;
-    margin-bottom: 8px;
-}
-
-.comic-popularity {
-    display: flex;
-    align-items: center;
-    font-size: 12px;
-    color: #999;
-}
-
-.popularity-icon {
-    margin-right: 5px;
-    color: #ff9e00;
-}
-
-/* 底部导航栏 */
-.bottom-nav {
-    position: fixed;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    display: flex;
-    justify-content: space-around;
-    padding: 10px 0;
-    background-color: #fff;
-    box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.1);
-    z-index: 100;
-}
-
-.nav-item {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    color: #666;
-    text-decoration: none;
-    font-size: 12px;
-}
-
-.nav-item.active {
-    color: #ff4e4e;
-}
-
-.nav-icon {
-    font-size: 20px;
-    margin-bottom: 3px;
+/* hoshino-card.component.scss */
+.artist-card {
+  border-radius: 16px;
+  overflow: hidden;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  margin: 16px;
+  text-align: center;
+
+  .card-header {
+    padding: 20px 0 10px;
+    background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
+
+    .artist-avatar {
+      width: 300px;
+      height: 300px;
+      border-radius: 50%;
+      object-fit: cover;
+      border: 3px solid white;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    }
+
+    h2 {
+      margin: 8px 0 0;
+      color: #2c3e50;
+      font-weight: bold;
+    }
+
+    .subtitle {
+      margin: 4px 0;
+      color: #7f8c8d;
+      font-size: 14px;
+    }
+  }
+
+  ion-card-content {
+    color: #34495e;
+    line-height: 1.6;
+    padding: 16px 20px;
+  }
+
+  .info-button {
+    --border-radius: 0 0 16px 16px;
+    margin-top: 0;
+  }
 }
 }

+ 172 - 2
src/app/tab2/tab2.page.ts

@@ -1,5 +1,9 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
-
+import { ModalController } from '@ionic/angular/standalone';
+// 引用fmode-ng智能体组件
+import { ChatPanelOptions, FmodeChat, FmodeChatMessage, openChatPanelModal } from 'fmode-ng';
+import Parse from "parse";
+import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
 @Component({
 @Component({
   selector: 'app-tab2',
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
   templateUrl: 'tab2.page.html',
@@ -7,7 +11,173 @@ import { Component } from '@angular/core';
   standalone: false,
   standalone: false,
 })
 })
 export class Tab2Page {
 export class Tab2Page {
+  // 处理图片加载失败
+  handleImageError(event: Event) {
+    const img = event.target as HTMLImageElement;
+    img.src = 'assets/icon/hoshino.jpeg'; // 备用图片
+  }
+
+  // 处理按钮点击
+  openDetails() {
+    console.log('查看资讯按钮被点击');
+    // 实际项目中可以跳转页面:
+    // this.router.navigate(['/details']);
+  }
+  openConsult(chatId?:string){
+    localStorage.setItem("company","E4KpGvTEto")
+    let options:ChatPanelOptions = {
+      roleId:"2DXJkRsjXK", // 预设,无需更改
+      // chatId:chatId, // 若存在,则恢复会话。若不存在,则开启新会话
+      onChatInit:(chat:FmodeChat)=>{
+        console.log("onChatInit");
+        console.log("Chat类",chat);
+        console.log("预设角色",chat.role);
+        // 角色名称
+        chat.role.set("name","星野荐");
+        // 角色称号
+        chat.role.set("title","漫画家");
+        // 角色描述
+        chat.role.set("desc","个人作品画风清新,但隐藏“推荐彩蛋”,星野荐,年龄26岁");
+        // 角色标签
+        chat.role.set("tags",['跑步', '动感单车']);
+        // 角色头像
+        chat.role.set("avatar","assets/icon/hoshino.jpeg")
+        // 角色提示词
+        chat.role.set("prompt",`
+# 角色设定
+性别:男
+
+年龄:32岁
+
+国籍:日本(活跃于国际漫画平台)
+
+职业:
+
+漫画家(创作小众治愈系作品)
+
+“漫画考古学家”(专注挖掘冷门神作)
+
+线上漫画推荐专栏主理人
+发型:微卷的深棕色短发,总有一撮呆毛翘起。
+
+服饰:爱穿宽松的条纹衬衫+工装裤,胸前挂着一副老式放大镜(用来“鉴定漫画细节”)。
+
+标志性道具:
+
+手捧一本封面夸张的漫画,书脊贴满彩色标签。
+
+背包上别满各国漫画角色的徽章。
+
+表情:热情洋溢的笑容,眼神专注时会在镜片后反光。
+
+
+`);
+        // 对话灵感分类
+        let promptCates = [
+          {
+            "img": "assets/icon/leixing.jpeg",
+            "name": "类型"
+          },
+          {
+            "img": "assets/icon/fengge.jpeg",
+            "name": "风格"
+          },
+          {
+            "img": "assets/icon/zhuti.jpeg",
+            "name": "主题"
+          }
+        ]
+        setTimeout(() => {
+          chat.role.set("promptCates",promptCates)
+        }, 500);
+        // 对话灵感列表
+        let promptList = [
+          {
+            cate:"类型",img:"/assets/icon/leixing.jpg",
+            messageList:[
+            "我喜欢热血战斗类的漫画,比如《龙珠》《火影忍者》,有什么类似的推荐吗?",
+            "有没有好看的悬疑推理漫画,剧情烧脑的那种?",
+            "最近想看看轻松搞笑的日常漫画,能推荐一些吗?",
+            "对科幻机甲类的漫画感兴趣,类似《高达》或者《攻壳机动队》这样的有推荐吗?",
+            "有没有黑暗奇幻风格的漫画,比如《剑风传奇》这种?"
+          ]
+          },
+          {
+            cate:"风格",img:"/assets/icon/fengge.jpg",
+            messageList:[
+              "我喜欢画风细腻、人物美型的漫画,比如《CLAMP》的作品,有类似的推荐吗?",
+              "有没有画风独特、辨识度高的漫画,比如《JOJO的奇妙冒险》那种?",
+              "喜欢复古手绘风格的漫画,类似《浪客行》这样的,能推荐一些吗?",
+              "有没有色彩鲜艳、视觉冲击力强的漫画,比如《死神》早期的风格?",
+              "偏好写实画风的漫画,类似《寄生兽》这样的,有什么推荐?"
+            ]
+          },
+          {
+            cate:"主题",img:"/assets/icon/zhuti.jpg",
+            messageList: [
+            "有没有主角成长线很精彩的漫画,比如从弱小变强的那种?",
+            "想看看关于‘复仇’主题的漫画,剧情要够狠够刺激的!",
+            "有没有讲述友情、团队合作的漫画,类似《海贼王》这种?",
+            "对‘时间循环’或者‘平行世界’设定的漫画感兴趣,有什么推荐?",
+            "有没有探讨人性、社会问题的深刻漫画,类似《死亡笔记》或《怪物》?"
+          ]
+          },
+        ]
+        let ChatPrompt = Parse.Object.extend("ChatPrompt");
+        setTimeout(() => {
+          chat.promptList = promptList.map(item=>{
+            let prompt = new ChatPrompt();
+            prompt.set(item);
+            prompt.img = item.img;
+            return prompt;
+          })
+        }, 500);
+
+        // 功能按钮区域预设
+        chat.leftButtons = [
+          { // 提示 当角色配置预设提示词时 显示
+           title:"话题灵感", // 按钮标题
+           showTitle:true, // 是否显示标题文字
+           icon:"color-wand-outline", // 标题icon图标
+           onClick:()=>{ // 按钮点击事件
+               chat.isPromptModalOpen = true
+           },
+           show:()=>{ // 按钮显示条件
+             return chat?.promptList?.length // 存在话题提示词时显示
+           }
+         },
+      ]
+
+      },
+      onMessage:(chat:FmodeChat,message:FmodeChatMessage)=>{
+        console.log("onMessage",message)
+        let content:any = message?.content
+        if(typeof content == "string"){
+          // 根据阶段标记判断下一步处理过程
+          if (content.includes('[导诊完成]')) {
+            // 进入问诊环节
+            console.log('进入问诊环节');
+          } else if (content.includes('[问诊完成]')) {
+            // 进入检查环节
+            console.log('进入检查环节');
+          } else if (content.includes('[检查完成]')) {
+            // 进入诊断与处方环节
+            console.log('进入诊断与处方环节');
+          } else if (content.includes('[处方完成]')) {
+            // 结束会话或其他逻辑
+            console.log('结束会话');
+          }
+        }
+      },
+      onChatSaved:(chat:FmodeChat)=>{
+        // chat?.chatSession?.id 本次会话的 chatId
+        console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
+      }
+    }
+    openChatPanelModal(this.modalCtrl,options)
+  }
+
+  constructor(private modalCtrl:ModalController,) {}
 
 
-  constructor() {}
 
 
 }
 }

+ 39 - 37
src/app/tab3/tab3.page.html

@@ -105,45 +105,47 @@
 
 
 <body>
 <body>
     <!-- 顶部信息展示区 -->
     <!-- 顶部信息展示区 -->
-    <div class="top-info">
-        <div class="avatar" onclick="changeAvatar()"></div>
-        <div class="user-info">
-            <div class="username">用户昵称</div>
-            <div class="user-level">VIP 会员</div>
-        </div>
-    </div>
+    
 
 
     <!-- 功能模块区 -->
     <!-- 功能模块区 -->
-    <div class="function-module">
-        <div class="module-item">
-            <i class="fa-solid fa-coins"></i>
-            <span>点券、阅点</span>
-        </div>
-        <div class="module-item">
-            <i class="fa-solid fa-history"></i>
-            <span>阅读记录</span>
-        </div>
-        <div class="module-item">
-            <i class="fa-solid fa-book"></i>
-            <span>书架</span>
-        </div>
-        <div class="module-item">
-            <i class="fa-solid fa-bell"></i>
-            <span>消息中心</span>
+    <div id="profile-page" class="page">
+            <div class="container">
+                <div class="section" style="text-align: center; padding: 20px 0;">
+                    <div style="width: 80px; height: 80px; border-radius: 50%; background-color: #f0f0f0; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 15px;">
+                        <i class="iconfont icon-user" style="font-size: 40px; color: #999;"></i>
+                    </div>
+                    <h2 style="font-size: 18px; margin-bottom: 10px;">点击登录</h2>
+                    <p style="font-size: 14px; color: #999; margin-bottom: 20px;">登录后查看我的收藏、历史记录等</p>
+                    <a href="#" style="display: inline-block; background-color: #ff4e33; color: white; padding: 8px 20px; border-radius: 20px; font-weight: bold;">立即登录</a>
+                </div>
+                
+                <div class="section">
+                    <div style="background-color: white; border-radius: 8px; overflow: hidden;">
+                        <div style="padding: 15px; border-bottom: 1px solid #f0f0f0; display: flex; align-items: center; justify-content: space-between;">
+                            <div style="display: flex; align-items: center;">
+                                <i class="iconfont icon-collect" style="font-size: 20px; color: #ff4e33; margin-right: 10px;"></i>
+                                <span>我的收藏</span>
+                            </div>
+                            <i class="iconfont icon-arrow-right" style="font-size: 16px; color: #999;"></i>
+                        </div>
+                        <div style="padding: 15px; border-bottom: 1px solid #f0f0f0; display: flex; align-items: center; justify-content: space-between;">
+                            <div style="display: flex; align-items: center;">
+                                <i class="iconfont icon-history" style="font-size: 20px; color: #ff4e33; margin-right: 10px;"></i>
+                                <span>浏览历史</span>
+                            </div>
+                            <i class="iconfont icon-arrow-right" style="font-size: 16px; color: #999;"></i>
+                        </div>
+                        <div style="padding: 15px; display: flex; align-items: center; justify-content: space-between;">
+                            <div style="display: flex; align-items: center;">
+                                <i class="iconfont icon-setting" style="font-size: 20px; color: #ff4e33; margin-right: 10px;"></i>
+                                <span>设置</span>
+                            </div>
+                            <i class="iconfont icon-arrow-right" style="font-size: 16px; color: #999;"></i>
+                        </div>
+                    </div>
+                </div>
+            </div>
         </div>
         </div>
-        <div class="module-item">
-            <i class="fa-solid fa-gift"></i>
-            <span>兑换中心</span>
-        </div>
-        <div class="module-item">
-            <i class="fa-solid fa-gear"></i>
-            <span>设置</span>
-        </div>
-        <div class="module-item">
-            <i class="fa-solid fa-download"></i>
-            <span>离线下载</span>
-        </div>
-    </div>
 
 
     <!-- 其他信息展示区 -->
     <!-- 其他信息展示区 -->
     <div class="other-info">
     <div class="other-info">
@@ -158,4 +160,4 @@
         }
         }
     </script>
     </script>
 </body>
 </body>
-</ion-content>
+

+ 45 - 0
src/app/tab3/tab3.page.scss

@@ -0,0 +1,45 @@
+/* hoshino-card.component.scss */
+.artist-card {
+  border-radius: 16px;
+  overflow: hidden;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  margin: 16px;
+  text-align: center;
+
+  .card-header {
+    padding: 20px 0 10px;
+    background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
+
+    .artist-avatar {
+      width: 100px;
+      height: 100px;
+      border-radius: 50%;
+      object-fit: cover;
+      border: 3px solid white;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    }
+
+    h2 {
+      margin: 8px 0 0;
+      color: #2c3e50;
+      font-weight: bold;
+    }
+
+    .subtitle {
+      margin: 4px 0;
+      color: #7f8c8d;
+      font-size: 14px;
+    }
+  }
+
+  ion-card-content {
+    color: #34495e;
+    line-height: 1.6;
+    padding: 16px 20px;
+  }
+
+  .info-button {
+    --border-radius: 0 0 16px 16px;
+    margin-top: 0;
+  }
+}

+ 25 - 0
src/app/tab3/tab3.page.ts

@@ -7,6 +7,31 @@ import { Component } from '@angular/core';
   standalone: false,
   standalone: false,
 })
 })
 export class Tab3Page {
 export class Tab3Page {
+  // ... 现有代码 ...
+
+  // 添加图片错误处理方法
+  handleImageError(event: Event) {
+    const imgElement = event.target as HTMLImageElement;
+    console.error('图片加载失败:', imgElement.src);
+    
+    // 可选:设置默认图片
+    // imgElement.src = 'assets/images/default.png';
+    
+    // 可选:隐藏图片
+    // imgElement.style.display = 'none';
+  }
+
+  // 添加打开详情方法
+  openDetails() {
+    // 根据您的实际功能实现:
+    console.log('打开详情');
+    
+    // 示例:导航到详情页
+    // this.router.navigate(['/details']);
+    
+    // 示例:打开模态框
+    // this.modalController.create({...}).present();
+  }
 
 
   constructor() {}
   constructor() {}
 
 

+ 6 - 1
src/app/tabs/tabs.module.ts

@@ -6,14 +6,19 @@ import { FormsModule } from '@angular/forms';
 import { TabsPageRoutingModule } from './tabs-routing.module';
 import { TabsPageRoutingModule } from './tabs-routing.module';
 
 
 import { TabsPage } from './tabs.page';
 import { TabsPage } from './tabs.page';
+import { ModalController } from '@ionic/angular/standalone';
 
 
 @NgModule({
 @NgModule({
+   
   imports: [
   imports: [
     IonicModule,
     IonicModule,
     CommonModule,
     CommonModule,
     FormsModule,
     FormsModule,
     TabsPageRoutingModule
     TabsPageRoutingModule
   ],
   ],
-  declarations: [TabsPage]
+  declarations: [TabsPage],
+  providers:[
+      ModalController,
+    ]
 })
 })
 export class TabsPageModule {}
 export class TabsPageModule {}

+ 37 - 16
src/app/tabs/tabs.page.html

@@ -1,20 +1,41 @@
 <ion-tabs>
 <ion-tabs>
 
 
-  <ion-tab-bar slot="bottom">
-    <ion-tab-button tab="tab1" href="/tabs/tab1">
-      <ion-icon aria-hidden="true" name="home-outline"></ion-icon>
-      <ion-label>首页</ion-label>
-    </ion-tab-button>
-
-    <ion-tab-button tab="tab2" href="/tabs/tab2">
-      <ion-icon aria-hidden="true" name="podium-outline"></ion-icon>
-      <ion-label>排行榜</ion-label>
-    </ion-tab-button>
-
-    <ion-tab-button tab="tab3" href="/tabs/tab3">
-      <ion-icon aria-hidden="true" name="person-outline"></ion-icon>
-      <ion-label>我的</ion-label>
-    </ion-tab-button>
-  </ion-tab-bar>
+  <ion-tab-bar slot="bottom">
+    <ion-tab-button tab="tab1" href="/tabs/tab1">
+      <ion-icon aria-hidden="true" name="home-outline"></ion-icon>
+      <ion-label>首页</ion-label>
+    </ion-tab-button>
+
+    <ion-tab-button tab="tab2" href="/tabs/tab2">
+      <ion-icon aria-hidden="true" name="podium-outline"></ion-icon>
+      <ion-label>AI问答</ion-label>
+    </ion-tab-button>
+
+    <ion-tab-button tab="tab3" href="/tabs/tab3">
+      <ion-icon aria-hidden="true" name="person-outline"></ion-icon>
+      <ion-label>我的</ion-label>
+    </ion-tab-button>
+  </ion-tab-bar>
 
 
 </ion-tabs>
 </ion-tabs>
+
+<ion-tabs>
+
+  <ion-tab-bar slot="bottom">
+    <ion-tab-button tab="tab1" href="/tabs/tab1">
+      <ion-icon aria-hidden="true" name="home-outline"></ion-icon>
+      <ion-label>首页</ion-label>
+    </ion-tab-button>
+
+    <ion-tab-button tab="tab2" href="/tabs/tab2">
+      <ion-icon aria-hidden="true" name="podium-outline"></ion-icon>
+      <ion-label>AI问答</ion-label>
+    </ion-tab-button>
+
+    <ion-tab-button tab="tab3" href="/tabs/tab3">
+      <ion-icon aria-hidden="true" name="person-outline"></ion-icon>
+      <ion-label>我的</ion-label>
+    </ion-tab-button>
+  </ion-tab-bar>
+
+</ion-tabs>

二进制
src/assets/icon/dianju.jpeg


二进制
src/assets/icon/douluo.jpeg


二进制
src/assets/icon/doupo.jpeg


二进制
src/assets/icon/fanpai.jpeg


二进制
src/assets/icon/fengge.jpeg


二进制
src/assets/icon/hoshino.jpeg


二进制
src/assets/icon/huyao.jpeg


二进制
src/assets/icon/leixing.jpeg


二进制
src/assets/icon/mohuang.jpeg


二进制
src/assets/icon/quanzhi.jpeg


二进制
src/assets/icon/riyue.jpeg


二进制
src/assets/icon/shaoson.jpeg


二进制
src/assets/icon/xiedi.jpeg


二进制
src/assets/icon/yiren.jpeg


二进制
src/assets/icon/zhenhun.jpeg


二进制
src/assets/icon/zhuti.jpeg


+ 152 - 0
src/lib/import.data.ts

@@ -0,0 +1,152 @@
+import Parse from 'parse';
+
+// 定义玄幻漫画分类计划数据
+async function importFantasyComicPlan() {
+  try {
+    await Parse.Cloud.run('testConnection');
+    console.log('Parse server connected!');
+    // 初始化Parse
+    Parse.initialize("YOUR_APP_ID", "YOUR_JS_KEY");
+    Parse.serverURL = 'https://your.parse-server.com/parse';
+
+    // 1. 创建用户 (如果不存在)
+    const User = Parse.Object.extend("_User");
+    const creator = new User();
+    creator.set("username", "fantasy_artist");
+    creator.set("email", "fantasy@example.com");
+    creator.set("password", "fantasy123");
+    creator.set("emailVerified", true);
+    
+    const savedCreator = await creator.save(null, { useMasterKey: true });
+    console.log("创作者用户创建成功:", savedCreator.id);
+
+    // 2. 创建玄幻漫画计划
+    const ComicPlan = Parse.Object.extend("ComicPlan");
+    const fantasyPlan = new ComicPlan();
+    
+    fantasyPlan.set("planName", "玄幻修仙系列漫画");
+    fantasyPlan.set("description", "创作一部关于修仙世界的长篇玄幻漫画,包含修真体系、法宝、灵兽等元素");
+    fantasyPlan.set("coverImage", new Parse.File("cover.jpg", { base64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" }));
+    fantasyPlan.set("totalTasks", 6);
+    fantasyPlan.set("completedTasks", 0);
+    fantasyPlan.set("status", "active");
+    fantasyPlan.set("difficulty", "advanced");
+    fantasyPlan.set("tags", ["fantasy", "cultivation", "action", "long-term"]);
+    fantasyPlan.set("creator", savedCreator);
+    fantasyPlan.set("dueDate", new Date(Date.now() + 90 * 24 * 60 * 60 * 1000)); // 90天后
+    
+    const savedPlan = await fantasyPlan.save();
+    console.log("玄幻漫画计划创建成功:", savedPlan.id);
+
+    // 3. 创建玄幻漫画任务
+    const ComicTask = Parse.Object.extend("ComicTask");
+    
+    // 任务1: 世界观设定
+    const task1 = new ComicTask();
+    task1.set("taskName", "世界观与修真体系设定");
+    task1.set("description", "设计修真等级体系(炼气、筑基、金丹等)、各大门派势力分布、主要地图");
+    task1.set("step", 1);
+    task1.set("type", "storyboard");
+    task1.set("isCompleted", false);
+    task1.set("priority", 5);
+    task1.set("estimatedHours", 20);
+    task1.set("plan", savedPlan);
+    task1.set("assignee", savedCreator);
+    task1.set("startDate", new Date());
+    task1.set("endDate", new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)); // 7天后
+    await task1.save();
+    
+    // 任务2: 主角设计
+    const task2 = new ComicTask();
+    task2.set("taskName", "主角与主要角色设计");
+    task2.set("description", "设计主角形象、性格、成长路线,以及3-5个重要配角");
+    task2.set("step", 2);
+    task2.set("type", "sketch");
+    task2.set("referenceImages", [
+      new Parse.File("ref1.jpg", { base64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" }),
+      new Parse.File("ref2.jpg", { base64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==" })
+    ]);
+    task2.set("isCompleted", false);
+    task2.set("priority", 4);
+    task2.set("estimatedHours", 15);
+    task2.set("plan", savedPlan);
+    task2.set("assignee", savedCreator);
+    task2.set("startDate", new Date(Date.now() + 5 * 24 * 60 * 60 * 1000));
+    task2.set("endDate", new Date(Date.now() + 12 * 24 * 60 * 60 * 1000));
+    await task2.save();
+    
+    // 任务3: 第一话分镜
+    const task3 = new ComicTask();
+    task3.set("taskName", "第一话分镜设计");
+    task3.set("description", "完成第一话(主角觉醒灵根,加入门派)的完整分镜");
+    task3.set("step", 3);
+    task3.set("type", "storyboard");
+    task3.set("isCompleted", false);
+    task3.set("priority", 5);
+    task3.set("estimatedHours", 25);
+    task3.set("plan", savedPlan);
+    task3.set("assignee", savedCreator);
+    task3.set("startDate", new Date(Date.now() + 10 * 24 * 60 * 60 * 1000));
+    task3.set("endDate", new Date(Date.now() + 20 * 24 * 60 * 60 * 1000));
+    await task3.save();
+    
+    // 任务4: 法宝与灵兽设计
+    const task4 = new ComicTask();
+    task4.set("taskName", "法宝与灵兽设计");
+    task4.set("description", "设计主角的初始法宝和伴生灵兽,以及3-5种常见法宝");
+    task4.set("step", 4);
+    task4.set("type", "sketch");
+    task4.set("isCompleted", false);
+    task4.set("priority", 3);
+    task4.set("estimatedHours", 12);
+    task4.set("plan", savedPlan);
+    task4.set("assignee", savedCreator);
+    task4.set("startDate", new Date(Date.now() + 15 * 24 * 60 * 60 * 1000));
+    task4.set("endDate", new Date(Date.now() + 22 * 24 * 60 * 60 * 1000));
+    await task4.save();
+    
+    // 任务5: 第一话线稿
+    const task5 = new ComicTask();
+    task5.set("taskName", "第一话线稿绘制");
+    task5.set("description", "根据分镜完成第一话的完整线稿");
+    task5.set("step", 5);
+    task5.set("type", "lineart");
+    task5.set("isCompleted", false);
+    task5.set("priority", 4);
+    task5.set("estimatedHours", 30);
+    task5.set("plan", savedPlan);
+    task5.set("assignee", savedCreator);
+    task5.set("startDate", new Date(Date.now() + 20 * 24 * 60 * 60 * 1000));
+    task5.set("endDate", new Date(Date.now() + 35 * 24 * 60 * 60 * 1000));
+    await task5.save();
+    
+    // 任务6: 第一话上色
+    const task6 = new ComicTask();
+    task6.set("taskName", "第一话上色与特效");
+    task6.set("description", "完成第一话的上色工作,添加修真特效(灵气、法宝光效等)");
+    task6.set("step", 6);
+    task6.set("type", "coloring");
+    task6.set("isCompleted", false);
+    task6.set("priority", 4);
+    task6.set("estimatedHours", 25);
+    task6.set("plan", savedPlan);
+    task6.set("assignee", savedCreator);
+    task6.set("startDate", new Date(Date.now() + 35 * 24 * 60 * 60 * 1000));
+    task6.set("endDate", new Date(Date.now() + 50 * 24 * 60 * 60 * 1000));
+    await task6.save();
+    
+    console.log("6个玄幻漫画任务已成功创建");
+    
+    // 更新计划的任务总数
+    savedPlan.set("totalTasks", 6);
+    await savedPlan.save();
+    
+    console.log("玄幻漫画分类计划导入完成!");
+    
+  } catch (error) {
+    console.error('Failed to connect to Parse server:', error);
+  }
+}
+
+// 执行导入
+importFantasyComicPlan();

+ 431 - 0
src/lib/ncloud.ts

@@ -0,0 +1,431 @@
+// CloudObject.ts
+
+let serverURL = `https://dev.fmode.cn/parse`;
+if(location.protocol=="http:"){
+   serverURL = `http://dev.fmode.cn:1337/parse`;
+}
+
+export class CloudObject {
+    className: string;
+    id: string | null = null;
+    createdAt:any;
+    updatedAt:any;
+    data: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    toPointer() {
+        return { "__type": "Pointer", "className": this.className, "objectId": this.id };
+    }
+
+    set(json: Record<string, any>) {
+        Object.keys(json).forEach(key => {
+            if (["objectId", "id", "createdAt", "updatedAt"].indexOf(key) > -1) {
+                return;
+            }
+            this.data[key] = json[key];
+        });
+    }
+
+    get(key: string) {
+        return this.data[key] || null;
+    }
+
+    async save() {
+        let method = "POST";
+        let url = serverURL + `/classes/${this.className}`;
+
+        // 更新
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+
+        const body = JSON.stringify(this.data);
+        const response = await fetch(url, {
+            headers: {
+                "content-type": "application/json;charset=UTF-8",
+                "x-parse-application-id": "dev"
+            },
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        return this;
+    }
+
+    async destroy() {
+        if (!this.id) return;
+        const response = await fetch(serverURL + `/classes/${this.className}/${this.id}`, {
+            headers: {
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "DELETE",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result) {
+            this.id = null;
+        }
+        return true;
+    }
+}
+
+// CloudQuery.ts
+export class CloudQuery {
+    className: string;
+    queryParams: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    include(...fileds:string[]) {
+        this.queryParams["include"] = fileds;
+    }
+    greaterThan(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$gt"] = value;
+    }
+
+    greaterThanAndEqualTo(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$gte"] = value;
+    }
+
+    lessThan(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$lt"] = value;
+    }
+
+    lessThanAndEqualTo(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$lte"] = value;
+    }
+
+    equalTo(key: string, value: any) {
+        if (!this.queryParams["where"]) this.queryParams["where"] = {};
+        this.queryParams["where"][key] = value;
+    }
+
+    async get(id: string) {
+        const url = serverURL + `/classes/${this.className}/${id}?`;
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        if (json) {
+            let existsObject = this.dataToObj(json)
+            return existsObject;
+        }
+        return null
+    }
+
+    async find():Promise<Array<CloudObject>> {
+        let url = serverURL + `/classes/${this.className}?`;
+
+        let queryStr = ``
+        Object.keys(this.queryParams).forEach(key=>{
+            let paramStr = JSON.stringify(this.queryParams[key]);
+            if(key=="include"){
+                paramStr = this.queryParams[key]?.join(",")
+            }
+            if(queryStr) {
+                url += `${key}=${paramStr}`;
+            }else{
+                url += `&${key}=${paramStr}`;
+            }
+        })
+        // if (Object.keys(this.queryParams["where"]).length) {
+
+        // }
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        let list = json?.results || []
+        let objList = list.map((item:any)=>this.dataToObj(item))
+        return objList || [];
+    }
+
+
+    async first() {
+        let url = serverURL + `/classes/${this.className}?`;
+
+        if (Object.keys(this.queryParams["where"]).length) {
+            const whereStr = JSON.stringify(this.queryParams["where"]);
+            url += `where=${whereStr}&limit=1`;
+        }
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        const exists = json?.results?.[0] || null;
+        if (exists) {
+            let existsObject = this.dataToObj(exists)
+            return existsObject;
+        }
+        return null
+    }
+
+    dataToObj(exists:any):CloudObject{
+        let existsObject = new CloudObject(this.className);
+        Object.keys(exists).forEach(key=>{
+          if(exists[key]?.__type =="Object"){
+            exists[key] = this.dataToObj(exists[key])
+          }
+        })
+        existsObject.set(exists);
+        existsObject.id = exists.objectId;
+        existsObject.createdAt = exists.createdAt;
+        existsObject.updatedAt = exists.updatedAt;
+        return existsObject;
+    }
+}
+
+// CloudUser.ts
+export class CloudUser extends CloudObject {
+    constructor() {
+        super("_User"); // 假设用户类在Parse中是"_User"
+        // 读取用户缓存信息
+        let userCacheStr = localStorage.getItem("NCloud/dev/User")
+        if(userCacheStr){
+            let userData = JSON.parse(userCacheStr)
+            // 设置用户信息
+            this.id = userData?.objectId;
+            this.sessionToken = userData?.sessionToken;
+            this.data = userData; // 保存用户数据
+        }
+    }
+
+    sessionToken:string|null = ""
+    /** 获取当前用户信息 */
+    async current() {
+        if (!this.sessionToken) {
+            console.error("用户未登录");
+            return null;
+        }
+        return this;
+        // const response = await fetch(serverURL + `/users/me`, {
+        //     headers: {
+        //         "x-parse-application-id": "dev",
+        //         "x-parse-session-token": this.sessionToken // 使用sessionToken进行身份验证
+        //     },
+        //     method: "GET"
+        // });
+
+        // const result = await response?.json();
+        // if (result?.error) {
+        //     console.error(result?.error);
+        //     return null;
+        // }
+        // return result;
+    }
+
+    /** 登录 */
+    async login(username: string, password: string):Promise<CloudUser|null> {
+        const response = await fetch(serverURL + `/login`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify({ username, password }),
+            method: "POST"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        // 设置用户信息
+        this.id = result?.objectId;
+        this.sessionToken = result?.sessionToken;
+        this.data = result; // 保存用户数据
+        // 缓存用户信息
+        console.log(result)
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
+        return this;
+    }
+
+    /** 登出 */
+    async logout() {
+        if (!this.sessionToken) {
+            console.error("用户未登录");
+            return;
+        }
+
+        const response = await fetch(serverURL + `/logout`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "x-parse-session-token": this.sessionToken
+            },
+            method: "POST"
+        });
+
+        let result = await response?.json();
+
+        if (result?.error) {
+            console.error(result?.error);
+            if(result?.error=="Invalid session token"){
+                this.clearUserCache()
+                return true;
+            }
+            return false;
+        }
+
+        this.clearUserCache()
+        return true;
+    }
+    clearUserCache(){
+        // 清除用户信息
+        localStorage.removeItem("NCloud/dev/User")
+        this.id = null;
+        this.sessionToken = null;
+        this.data = {};
+    }
+
+    /** 注册 */
+    async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
+        const userData = {
+            username,
+            password,
+            ...additionalData // 合并额外的用户数据
+        };
+
+        const response = await fetch(serverURL + `/users`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify(userData),
+            method: "POST"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        // 设置用户信息
+        // 缓存用户信息
+        console.log(result)
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(result))
+        this.id = result?.objectId;
+        this.sessionToken = result?.sessionToken;
+        this.data = result; // 保存用户数据
+        return this;
+    }
+
+    override async save() {
+        let method = "POST";
+        let url = serverURL + `/users`;
+
+        // 更新用户信息
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+
+        let data:any = JSON.parse(JSON.stringify(this.data))
+        delete data.createdAt
+        delete data.updatedAt
+        delete data.ACL
+        delete data.objectId
+        const body = JSON.stringify(data);
+        let headersOptions:any = {
+            "content-type": "application/json;charset=UTF-8",
+            "x-parse-application-id": "dev",
+            "x-parse-session-token": this.sessionToken, // 添加sessionToken以进行身份验证
+        }
+        const response = await fetch(url, {
+            headers: headersOptions,
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        localStorage.setItem("NCloud/dev/User",JSON.stringify(this.data))
+        return this;
+    }
+}
+
+export class CloudApi{
+    async fetch(path:string,body:any,options?:{
+        method:string
+        body:any
+    }){
+
+        let reqOpts:any =  {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            method: options?.method || "POST",
+            mode: "cors",
+            credentials: "omit"
+        }
+        if(body||options?.body){
+            reqOpts.body = JSON.stringify(body || options?.body);
+            reqOpts.json = true;
+        }
+        let host = `https://dev.fmode.cn`
+        // host = `http://127.0.0.1:1337`
+        let url = `${host}/api/`+path
+        console.log(url,reqOpts)
+        const response = await fetch(url,reqOpts);
+        let json = await response.json();
+        return json
+    }
+}

+ 3 - 1
tsconfig.json

@@ -6,10 +6,12 @@
     "outDir": "./dist/out-tsc",
     "outDir": "./dist/out-tsc",
     "forceConsistentCasingInFileNames": true,
     "forceConsistentCasingInFileNames": true,
     "strict": true,
     "strict": true,
+    "skipLibCheck": true,
     "noImplicitOverride": true,
     "noImplicitOverride": true,
     "noPropertyAccessFromIndexSignature": true,
     "noPropertyAccessFromIndexSignature": true,
     "noImplicitReturns": true,
     "noImplicitReturns": true,
     "noFallthroughCasesInSwitch": true,
     "noFallthroughCasesInSwitch": true,
+    "allowSyntheticDefaultImports":true,
     "sourceMap": true,
     "sourceMap": true,
     "declaration": false,
     "declaration": false,
     "downlevelIteration": true,
     "downlevelIteration": true,
@@ -20,7 +22,7 @@
     "module": "es2020",
     "module": "es2020",
     "lib": [
     "lib": [
       "es2018", 
       "es2018", 
-      "dom"
+      "dom","dom.iterable"
     ],
     ],
     "useDefineForClassFields": false
     "useDefineForClassFields": false
   },
   },

部分文件因为文件数量过多而无法显示