فهرست منبع

feat:book beautify

Midnight 5 روز پیش
والد
کامیت
d0c9d7f2a6

+ 26 - 4
myapp/src/app/tab2/tab2.page.ts

@@ -12,6 +12,20 @@ import { CloudObject, CloudQuery } from 'src/lib/ncloud';
 })
 export class Tab2Page {
 
+  ionViewWillEnter() {
+  if (Parse.User.current()) {
+    this.loadConsult(); // 👈 加载当前用户的咨询记录
+  } else {
+    this.consultList = []; // 👈 未登录时清空
+  }
+
+  // 如果是刚登出,确保清空页面
+  if (localStorage.getItem("userLoggedOut") === "true") {
+    this.consultList = [];
+    localStorage.removeItem("userLoggedOut");
+  }
+}
+
   constructor(
     private modalCtrl: ModalController,
     private alertCtrl: AlertController
@@ -173,7 +187,8 @@ export class Tab2Page {
           "chatId": chatId,
           "messageList": chat.messageList,
           "name": chat.role.get("name"),
-          "avatar": chat.role.get("avatar")
+          "avatar": chat.role.get("avatar"),
+          "user": Parse.User.current()  // 👈 新增用户字段
         })
         console.log("lawConsult", lawConsult)
         lawConsult.save();
@@ -186,9 +201,16 @@ export class Tab2Page {
   consultList: Array<CloudObject> = []
 
   async loadConsult() {
-    let query = new CloudQuery("LawConsult");
-    this.consultList = await query.find()
-    console.log(this.consultList)
+    let currentUser = Parse.User.current();
+  if (!currentUser) {
+    this.consultList = [];
+    return;
+  }
+
+  const query = new CloudQuery("LawConsult");
+  query.equalTo("user", currentUser);  // 👈 只查当前用户的数据
+  this.consultList = await query.find();
+  console.log("当前用户咨询记录", this.consultList);
   }
 
   // 新增的删除咨询记录方法

+ 43 - 15
myapp/src/modules/demo/book/page-book-display/page-book-display.component.html

@@ -1,12 +1,19 @@
 <ion-header>
-  <ion-toolbar color="primary">
-    <ion-buttons slot="start">
+  <ion-toolbar class="custom-header">
+    <ion-buttons slot="start" style="color: white;">
       <ion-back-button (click)="back()"></ion-back-button>
     </ion-buttons>
-    <ion-title>法律文书详情</ion-title>
+    <ion-title class="header-title">法律文书详情</ion-title>
+    <ion-buttons slot="end">
+      <ion-button class="search-button">
+        <ion-icon slot="icon-only" name="search-outline"></ion-icon>
+      </ion-button>
+    </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
+
+
 <ion-content class="ion-padding">
   <div *ngIf="book" class="document-detail-container">
     <!-- 头部卡片 -->
@@ -19,26 +26,43 @@
         <ion-card-subtitle *ngIf="book?.get('isFeatured')" class="featured-badge">
           <ion-chip color="warning">
             <ion-icon name="star"></ion-icon>
-            <ion-label>精选</ion-label>
+            <ion-label>精选文书</ion-label>
           </ion-chip>
         </ion-card-subtitle>
       </ion-card-header>
     </ion-card>
 
     <!-- 描述部分 -->
-    <ion-card class="description-card">
+    <ion-card class="info-card">
       <ion-card-content>
-        <h2 class="section-title">文书描述</h2>
-        <p class="document-description">{{book?.get('description')}}</p>
+        <h2 class="section-title">
+          <ion-icon name="document-text-outline" class="title-icon"></ion-icon>
+          文书描述
+        </h2>
+        <p class="document-description">{{book?.get('description') || '暂无详细描述'}}</p>
+        
+        <div class="meta-info">
+          <div class="meta-item">
+            <ion-icon name="time-outline"></ion-icon>
+            <span>更新日期: {{book?.get('updateDate') | date:'yyyy-MM-dd'}}</span>
+          </div>
+          <div class="meta-item">
+            <ion-icon name="file-tray-outline"></ion-icon>
+            <span>分类: {{book?.get('category')}}</span>
+          </div>
+        </div>
       </ion-card-content>
     </ion-card>
 
     <!-- 标签部分 -->
-    <ion-card class="tags-card" *ngIf="book?.get('tags')?.length > 0">
+    <ion-card class="info-card" *ngIf="book?.get('tags')?.length > 0">
       <ion-card-content>
-        <h2 class="section-title">相关标签</h2>
+        <h2 class="section-title">
+          <ion-icon name="pricetags-outline" class="title-icon"></ion-icon>
+          相关标签
+        </h2>
         <div class="tags-container">
-          <ion-chip *ngFor="let tag of book?.get('tags')" color="medium" outline>
+          <ion-chip *ngFor="let tag of book?.get('tags')" [color]="getTagColor(tag)" outline>
             {{tag}}
           </ion-chip>
         </div>
@@ -47,20 +71,24 @@
 
     <!-- 操作按钮 -->
     <div class="action-buttons">
-      <ion-button expand="block" color="primary" shape="round">
-        <ion-icon slot="start" name="download"></ion-icon>
+      <ion-button expand="block" color="primary" shape="round" class="action-button">
+        <ion-icon slot="start" name="download-outline"></ion-icon>
         下载模板
       </ion-button>
-      <ion-button expand="block" color="secondary" fill="outline" shape="round">
-        <ion-icon slot="start" name="create"></ion-icon>
+      <ion-button expand="block" color="secondary" fill="outline" shape="round" class="action-button">
+        <ion-icon slot="start" name="create-outline"></ion-icon>
         在线编辑
       </ion-button>
+      <ion-button expand="block" color="tertiary" fill="clear" class="action-button">
+        <ion-icon slot="start" name="bookmark-outline"></ion-icon>
+        收藏文书
+      </ion-button>
     </div>
   </div>
 
   <!-- 加载状态 -->
   <div *ngIf="!book" class="loading-container">
-    <ion-spinner name="crescent"></ion-spinner>
+    <ion-spinner name="crescent" color="primary"></ion-spinner>
     <p>正在加载文书详情...</p>
   </div>
 </ion-content>

+ 115 - 14
myapp/src/modules/demo/book/page-book-display/page-book-display.component.scss

@@ -1,51 +1,139 @@
+/* 头部标题 */
+.custom-header {
+  --background: linear-gradient(135deg, #3A5FE5 0%, #6A8EFF 100%);
+  --border-width: 0;
+  --box-shadow: 0 2px 10px rgba(58, 95, 229, 0.3);
+  padding: 0 16px;
+  
+  .header-title {
+    color: white;
+    font-size: 1.2rem;
+    font-weight: 600;
+    letter-spacing: 0.5px;
+    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+    padding: 0 12px;
+  }
+
+  .search-button {
+    --color: white;
+    --background-hover: rgba(255, 255, 255, 0.1);
+    --background-activated: rgba(255, 255, 255, 0.2);
+    --border-radius: 50%;
+    --padding-start: 8px;
+    --padding-end: 8px;
+    
+    ion-icon {
+      font-size: 1.4rem;
+    }
+  }
+
+  
+  /* 添加底部细线 */
+  &:after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 1px;
+    background: rgba(255, 255, 255, 0.2);
+  }
+}
+
+//
 .document-detail-container {
   max-width: 800px;
   margin: 0 auto;
+  padding-bottom: 20px;
 }
 
 .document-header-card {
   text-align: center;
+  border-radius: 16px;
   box-shadow: 0 4px 16px rgba(var(--ion-color-primary-rgb), 0.1);
   margin-bottom: 24px;
+  background: linear-gradient(135deg, rgba(var(--ion-color-primary-rgb), 0.05) 0%, rgba(var(--ion-color-secondary-rgb), 0.05) 100%);
+  border: 1px solid rgba(var(--ion-color-primary-rgb), 0.1);
 
   .icon-container {
     display: flex;
     justify-content: center;
     margin-bottom: 16px;
+    padding-top: 16px;
   }
 
   .document-icon {
     width: 80px;
     height: 80px;
     object-fit: contain;
+    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
   }
 
   .document-title {
     font-size: 1.5rem;
-    font-weight: bold;
+    font-weight: 600;
     color: var(--ion-color-primary);
     margin-bottom: 8px;
+    padding: 0 16px;
   }
 
   .featured-badge {
     margin-top: 8px;
+    margin-bottom: 16px;
+    
+    ion-chip {
+      font-weight: 500;
+      ion-icon {
+        color: var(--ion-color-warning-contrast);
+      }
+    }
   }
 }
 
-.description-card, .tags-card {
+.info-card {
+  border-radius: 16px;
   margin-bottom: 20px;
-  border-radius: 12px;
-  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
-
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  border: 1px solid rgba(var(--ion-color-medium-rgb), 0.1);
+  
   .section-title {
-    font-size: 1.2rem;
+    display: flex;
+    align-items: center;
+    font-size: 1.1rem;
+    font-weight: 600;
     color: var(--ion-color-primary);
-    margin-bottom: 12px;
+    margin-bottom: 16px;
+    
+    .title-icon {
+      margin-right: 8px;
+      font-size: 1.2rem;
+    }
   }
 
   .document-description {
     line-height: 1.6;
-    color: var(--ion-color-medium);
+    color: var(--ion-color-dark);
+    margin-bottom: 16px;
+    font-size: 0.95rem;
+  }
+
+  .meta-info {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12px;
+    margin-top: 16px;
+    
+    .meta-item {
+      display: flex;
+      align-items: center;
+      font-size: 0.85rem;
+      color: var(--ion-color-medium);
+      
+      ion-icon {
+        margin-right: 6px;
+        font-size: 1rem;
+      }
+    }
   }
 }
 
@@ -53,6 +141,13 @@
   display: flex;
   flex-wrap: wrap;
   gap: 8px;
+  margin-top: 8px;
+  
+  ion-chip {
+    font-weight: 500;
+    --background: rgba(var(--ion-color-primary-rgb), 0.1);
+    --color: var(--ion-color-primary);
+  }
 }
 
 .action-buttons {
@@ -60,11 +155,16 @@
   flex-direction: column;
   gap: 12px;
   margin-top: 24px;
-
-  ion-button {
-    --border-radius: 50px;
+  
+  .action-button {
+    --border-radius: 12px;
     height: 48px;
     font-weight: 500;
+    font-size: 1rem;
+    
+    ion-icon {
+      font-size: 1.2rem;
+    }
   }
 }
 
@@ -73,15 +173,16 @@
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  height: 200px;
-
+  height: 60vh;
+  
   ion-spinner {
     width: 48px;
     height: 48px;
   }
-
+  
   p {
     margin-top: 16px;
     color: var(--ion-color-medium);
+    font-size: 0.95rem;
   }
 }

+ 40 - 42
myapp/src/modules/demo/book/page-book-display/page-book-display.component.ts

@@ -3,27 +3,17 @@ import { Component, OnInit } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
 import { 
-  IonHeader, 
-  IonToolbar, 
-  IonTitle, 
-  IonContent, 
-  IonButtons, 
-  IonBackButton, 
-  IonCard, 
-  IonCardHeader, 
-  IonCardTitle, 
-  IonCardSubtitle, 
-  IonCardContent, 
-  IonChip, 
-  IonLabel, 
-  IonIcon, 
-  IonButton, 
-  IonImg, 
-  IonSpinner, 
-  NavController
+  IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, 
+  IonBackButton, IonCard, IonCardHeader, IonCardTitle, 
+  IonCardSubtitle, IonCardContent, IonChip, IonLabel, 
+  IonIcon, IonButton, IonImg, IonSpinner, NavController
 } from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { star, download, create } from 'ionicons/icons';
+import { 
+  star, downloadOutline, createOutline, bookmarkOutline,
+  documentTextOutline, timeOutline, fileTrayOutline, 
+  pricetagsOutline, shareSocialOutline
+} from 'ionicons/icons';
 
 @Component({
   selector: 'app-page-book-display',
@@ -32,50 +22,58 @@ import { star, download, create } from 'ionicons/icons';
   standalone: true,
   imports: [
     CommonModule,
-    IonHeader, 
-    IonToolbar, 
-    IonTitle, 
-    IonContent, 
-    IonButtons, 
-    IonBackButton, 
-    IonCard, 
-    IonCardHeader, 
-    IonCardTitle, 
-    IonCardSubtitle, 
-    IonCardContent, 
-    IonChip, 
-    IonLabel, 
-    IonIcon, 
-    IonButton, 
-    IonImg, 
-    IonSpinner
+    IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, 
+    IonBackButton, IonCard, IonCardHeader, IonCardTitle, 
+    IonCardSubtitle, IonCardContent, IonChip, IonLabel, 
+    IonIcon, IonButton, IonImg, IonSpinner
   ]
 })
 export class PageBookDisplayComponent  implements OnInit {
 
    book: CloudObject | undefined | null;
 
-  back(){
-    this.navCtrl.back()
-  }
-
   constructor(
     private route: ActivatedRoute,
     private navCtrl: NavController
   ) {
-    addIcons({ star, download, create });
+    addIcons({ 
+      star, downloadOutline, createOutline, bookmarkOutline,
+      documentTextOutline, timeOutline, fileTrayOutline,
+      pricetagsOutline, shareSocialOutline
+    });
     
     this.route.params.subscribe(params => {
-      console.log(params);
       this.loadBook(params['bookId']);
     });
   }
 
+  back() {
+    this.navCtrl.back();
+  }
+
   async loadBook(bookId: string) {
     let query = new CloudQuery("DocumentCategory");
     this.book = await query.get(bookId);
   }
 
+  // 为标签生成随机颜色
+  getTagColor(tag: string): string {
+    const colors = ['primary', 'secondary', 'tertiary', 'success', 'warning', 'danger'];
+    const index = Math.abs(this.hashCode(tag)) % colors.length;
+    return colors[index];
+  }
+
+  // 简单的字符串hash函数
+  private hashCode(str: string): number {
+    let hash = 0;
+    for (let i = 0; i < str.length; i++) {
+      const char = str.charCodeAt(i);
+      hash = ((hash << 5) - hash) + char;
+      hash |= 0; // Convert to 32bit integer
+    }
+    return hash;
+  }
+
   ngOnInit() {}
 
 }

+ 54 - 27
myapp/src/modules/demo/book/page-book-list/page-book-list.component.html

@@ -1,23 +1,33 @@
-  
 <ion-header>
-  <ion-toolbar color="primary">
-    <ion-title>法律文书库</ion-title>
+  <ion-toolbar class="custom-header">
+    <ion-title class="header-title">法律文书库</ion-title>
+    <ion-buttons slot="end">
+      <ion-button class="search-button">
+        <ion-icon slot="icon-only" name="search-outline"></ion-icon>
+      </ion-button>
+    </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content class="ion-padding">
+<ion-content class="ion-padding" [fullscreen]="true">
+  <!-- 搜索栏 -->
+  <ion-searchbar placeholder="搜索法律文书..." animated class="custom-searchbar"></ion-searchbar>
+
   <!-- 分类卡片 -->
-  <ion-list>
+  <ion-list lines="none" class="category-list">
     <ion-list-header>
       <ion-label>文书分类</ion-label>
+      <ion-button fill="clear" size="small">查看全部</ion-button>
     </ion-list-header>
     
     <ion-grid>
       <ion-row>
         @for(documentCategory of categorieList; track documentCategory){
           <ion-col size="6" size-md="4" size-lg="3">
-            <ion-card (click)="goBook(documentCategory)" class="category-card">
-              <ion-icon name="document-text-outline" class="category-icon"></ion-icon>
+            <ion-card (click)="goBook(documentCategory)" class="category-card" [style.--card-color]="getCategoryColor($index)">
+              <div class="card-icon-wrapper">
+                <ion-icon name="document-text-outline" class="category-icon"></ion-icon>
+              </div>
               <ion-card-header>
                 <ion-card-title>{{documentCategory.get('name')}}</ion-card-title>
               </ion-card-header>
@@ -31,36 +41,53 @@
     </ion-grid>
   </ion-list>
 
-  <!-- 精选法律文书 -->
-  <ion-list>
+  <!-- 精选法律文书 - 改为网格布局 -->
+  <ion-list lines="none" class="featured-list">
     <ion-list-header>
       <ion-label>精选法律文书</ion-label>
+      <ion-button fill="clear" size="small">更多</ion-button>
     </ion-list-header>
     
-    @for(legalDocument of documentList; track legalDocument){
-      <ion-item detail="true" lines="full">
-        <ion-icon name="document-outline" slot="start" color="primary"></ion-icon>
-        <ion-label>
-          <h3>{{legalDocument.get('title')}}</h3>
-          <p>{{legalDocument.get('description') || '暂无描述'}}</p>
-          <p class="meta-info">
-            <ion-badge color="light">{{legalDocument.get('docType')}}</ion-badge>
-            <span>适用: {{legalDocument.get('applicableScope')}}</span>
-          </p>
-        </ion-label>
-      </ion-item>
-    }
+    <ion-grid>
+      <ion-row>
+        @for(legalDocument of documentList; track legalDocument; let i = $index){
+          <ion-col size="12" size-md="6" size-lg="4">
+            <ion-card class="document-card">
+              <ion-card-header>
+                <ion-card-title>{{legalDocument.get('title')}}</ion-card-title>
+                <ion-card-subtitle>
+                  <ion-badge [color]="getDocTypeColor(legalDocument.get('docType'))">
+                    {{legalDocument.get('docType')}}
+                  </ion-badge>
+                </ion-card-subtitle>
+              </ion-card-header>
+              <ion-card-content>
+                <p>{{legalDocument.get('description') || '暂无描述'}}</p>
+                <div class="meta-info">
+                  <span>适用: {{legalDocument.get('applicableScope')}}</span>
+                  <ion-button fill="clear" size="small" (click)="viewDocument(legalDocument)">
+                    查看详情
+                    <ion-icon slot="end" name="chevron-forward-outline"></ion-icon>
+                  </ion-button>
+                </div>
+              </ion-card-content>
+            </ion-card>
+          </ion-col>
+        }
+      </ion-row>
+    </ion-grid>
   </ion-list>
 
   <!-- 法律知识 -->
-  <ion-list>
+  <ion-list lines="none" class="knowledge-list">
     <ion-list-header>
       <ion-label>法律知识</ion-label>
+      <ion-button fill="clear" size="small">更多</ion-button>
     </ion-list-header>
     
     @for(legalKnowledge of knowledgeList; track legalKnowledge){
-      <ion-item detail="true" lines="full">
-        <ion-icon name="book-outline" slot="start" color="secondary"></ion-icon>
+      <ion-item detail="true" lines="full" class="knowledge-item" (click)="viewKnowledge(legalKnowledge)">
+        <ion-icon name="book-outline" slot="start" class="knowledge-icon"></ion-icon>
         <ion-label>
           <h3>{{legalKnowledge.get('title')}}</h3>
           <p>{{legalKnowledge.get('summary') || '暂无摘要'}}</p>
@@ -74,8 +101,8 @@
   </ion-list>
 
   <ion-fab vertical="bottom" horizontal="end" slot="fixed">
-    <ion-fab-button color="danger">
+    <ion-fab-button color="primary">
       <ion-icon name="cloud-download-outline"></ion-icon>
     </ion-fab-button>
   </ion-fab>
-</ion-content>
+</ion-content>

+ 268 - 25
myapp/src/modules/demo/book/page-book-list/page-book-list.component.scss

@@ -1,47 +1,290 @@
+/* 头部标题 */
+.custom-header {
+  --background: linear-gradient(135deg, #3A5FE5 0%, #6A8EFF 100%);
+  --border-width: 0;
+  --box-shadow: 0 2px 10px rgba(58, 95, 229, 0.3);
+  padding: 0 16px;
+  
+  .header-title {
+    color: white;
+    font-size: 1.2rem;
+    font-weight: 600;
+    letter-spacing: 0.5px;
+    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+    padding: 0 12px;
+  }
+  
+  .search-button {
+    --color: white;
+    --background-hover: rgba(255, 255, 255, 0.1);
+    --background-activated: rgba(255, 255, 255, 0.2);
+    --border-radius: 50%;
+    --padding-start: 8px;
+    --padding-end: 8px;
+    
+    ion-icon {
+      font-size: 1.4rem;
+    }
+  }
+  
+  /* 添加底部细线 */
+  &:after {
+    content: '';
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    height: 1px;
+    background: rgba(255, 255, 255, 0.2);
+  }
+}
+
+/* 全局变量 */
+:root {
+  --primary: #3A5FE5;
+  --secondary: #00C4A1;
+  --danger: #FF4D4F;
+  --light: #F5F7FA;
+  --dark: #2D3748;
+  --medium: #A0AEC0;
+  --card-bg: #FFFFFF;
+  --card-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+}
+
+/* 搜索栏样式 */
+.custom-searchbar {
+  padding: 8px 0;
+  --background: var(--light);
+  --border-radius: 12px;
+  --box-shadow: none;
+}
+
+/* 分类卡片样式 */
+.category-list {
+  background: transparent;
+  
+  ion-list-header {
+    padding-left: 0;
+    
+    ion-label {
+      font-size: 1.2rem;
+      font-weight: 600;
+      color: #2D3748;
+    }
+    
+    ion-button {
+      --color: #3A5FE5;
+      font-size: 0.9rem;
+    }
+  }
+}
+
 .category-card {
   height: 100%;
   display: flex;
   flex-direction: column;
-  transition: transform 0.3s ease;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
+  border-radius: 12px;
+  background: #FFFFFF;
+  box-shadow:  0 4px 12px rgba(0, 0, 0, 0.08);
+  margin: 0;
+  overflow: visible;
   
   &:active {
-    transform: scale(0.98);
+    transform: translateY(2px);
+  }
+  
+  .card-icon-wrapper {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 60px;
+    height: 60px;
+    margin: 16px auto 8px;
+    border-radius: 50%;
+    background: rgba(var(--card-color-rgb), 0.1);
+  }
+  
+  .category-icon {
+    font-size: 2rem;
+    color: var(--card-color);
+  }
+  
+  ion-card-header {
+    padding-bottom: 0;
+    
+    ion-card-title {
+      font-size: 1rem;
+      font-weight: 600;
+      color: #2D3748;
+      text-align: center;
+    }
+  }
+  
+  ion-card-content {
+    flex-grow: 1;
+    padding-top: 0;
+    font-size: 0.85rem;
+    color: var(--medium);
+    text-align: center;
   }
 }
 
-.category-icon {
-  font-size: 2.5rem;
-  margin: 16px auto;
-  color: var(--ion-color-primary);
+/* 精选法律文书样式 */
+.featured-list {
+  background: transparent;
+  
+  ion-list-header {
+    padding-left: 0;
+    
+    ion-label {
+      font-size: 1.2rem;
+      font-weight: 600;
+      color: #2D3748;
+    }
+    
+    ion-button {
+      --color: #3A5FE5;
+      font-size: 0.9rem;
+    }
+  }
 }
 
-ion-card-header {
-  padding-bottom: 0;
+.document-card {
+  height: 100%;
+  border-radius: 12px;
+  background: #FFFFFF;
+  box-shadow:  0 4px 12px rgba(0, 0, 0, 0.08);
+  margin: 0;
+  
+  ion-card-header {
+    padding-bottom: 0;
+    
+    ion-card-title {
+      font-size: 1rem;
+      font-weight: 600;
+      color: #000000;
+    }
+    
+    ion-card-subtitle {
+      padding-top: 8px;
+      
+      ion-badge {
+        font-weight: 500;
+        font-size: 0.7rem;
+      }
+    }
+  }
+  
+  ion-card-content {
+    padding-top: 0;
+    font-size: 0.85rem;
+    color: var(--medium);
+    
+    .meta-info {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 12px;
+      font-size: 0.8rem;
+      color: var(--medium);
+      
+      ion-button {
+        --padding-start: 0;
+        --padding-end: 0;
+        --color: #3A5FE5;
+        font-size: 0.8rem;
+      }
+    }
+  }
 }
 
-ion-card-content {
-  flex-grow: 1;
-  padding-top: 0;
+/* 法律知识样式 */
+.knowledge-list {
+  background: transparent;
+  
+  ion-list-header {
+    padding-left: 0;
+    
+    ion-label {
+      font-size: 1.2rem;
+      font-weight: 600;
+      color: #2D3748;
+    }
+    
+    ion-button {
+      --color: #3A5FE5;
+      font-size: 0.9rem;
+    }
+  }
 }
 
-.meta-info {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  margin-top: 8px;
-  font-size: 0.8rem;
-  color: var(--ion-color-medium);
+.knowledge-item {
+  --padding-start: 0;
+  --inner-padding-end: 0;
+  --border-radius: 12px;
+  --background: #FFFFFF;
+  margin-bottom: 12px;
+  border-radius: 12px;
+  box-shadow:  0 4px 12px rgba(0, 0, 0, 0.08);
+  
+  .knowledge-icon {
+    color: var(--secondary);
+    font-size: 1.5rem;
+    margin-right: 12px;
+  }
+  
+  ion-label {
+    h3 {
+      font-weight: 600;
+      color: #2D3748;
+      margin-bottom: 6px;
+    }
+    
+    p {
+      font-size: 0.9rem;
+      color: var(--medium);
+      margin-bottom: 8px;
+    }
+    
+    .meta-info {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      font-size: 0.8rem;
+      color: var(--medium);
+      
+      ion-badge {
+        font-weight: 500;
+      }
+    }
+  }
 }
 
-ion-badge {
-  margin-right: 8px;
+/* FAB按钮样式 */
+ion-fab-button {
+  --box-shadow: 0 4px 12px rgba(58, 95, 229, 0.3);
 }
 
-ion-list {
-  margin-bottom: 24px;
+/* 动画效果 */
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(10px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
 }
 
-ion-list-header ion-label {
-  font-size: 1.2rem;
-  font-weight: bold;
+.category-card, .document-card, .knowledge-item {
+  animation: fadeIn 0.4s ease-out forwards;
+  opacity: 0;
+  
+  @for $i from 1 through 20 {
+    &:nth-child(#{$i}) {
+      animation-delay: $i * 0.1s;
+    }
+  }
 }

+ 66 - 7
myapp/src/modules/demo/book/page-book-list/page-book-list.component.ts

@@ -1,11 +1,19 @@
 import { Component, OnInit } from '@angular/core';
 import { DataImporter } from '../import-book-data';
 import { CloudObject, CloudQuery } from 'src/lib/ncloud';
-import { NavController } from '@ionic/angular/standalone';
+import { IonCardSubtitle, NavController } from '@ionic/angular/standalone';
 import { DatePipe } from '@angular/common';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonListHeader, IonLabel, IonItem, IonIcon, IonCard, IonCardHeader, IonCardTitle, IonCardContent, IonGrid, IonRow, IonCol, IonBadge, IonFab, IonFabButton } from '@ionic/angular/standalone';
+import { 
+  IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonListHeader, 
+  IonLabel, IonItem, IonIcon, IonCard, IonCardHeader, IonCardTitle, 
+  IonCardContent, IonGrid, IonRow, IonCol, IonBadge, IonFab, IonFabButton,
+  IonButtons, IonBackButton, IonButton, IonSearchbar
+} from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { documentTextOutline, documentOutline, bookOutline, cloudDownloadOutline } from 'ionicons/icons';
+import { 
+  documentTextOutline, documentOutline, bookOutline, cloudDownloadOutline,
+  searchOutline, chevronForwardOutline
+} from 'ionicons/icons';
 
 
 @Component({
@@ -13,17 +21,41 @@ import { documentTextOutline, documentOutline, bookOutline, cloudDownloadOutline
   templateUrl: './page-book-list.component.html',
   styleUrls: ['./page-book-list.component.scss'],
   standalone: true,
-  imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonListHeader, IonLabel, IonItem, IonIcon, IonCard, IonCardHeader, IonCardTitle, IonCardContent, IonGrid, IonRow, IonCol, IonBadge, IonFab, IonFabButton, DatePipe]
-})
+  imports: [
+    IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonListHeader, 
+    IonLabel, IonItem, IonIcon, IonCard, IonCardHeader, IonCardTitle, 
+    IonCardContent, IonGrid, IonRow, IonCol, IonBadge, IonFab, IonFabButton,
+    IonButtons, IonCardSubtitle, IonBackButton, IonButton, IonSearchbar,
+    DatePipe
+  ]})
 export class PageBookListComponent  implements OnInit {
 
+  // 分类颜色数组
+  categoryColors = [
+    '#3A5FE5', // 蓝色
+    '#00C4A1', // 青色
+    '#FF7043', // 橙色
+    '#9C27B0', // 紫色
+    '#FF4D4F', // 红色
+    '#4CAF50', // 绿色
+    '#607D8B', // 灰色
+    '#FFC107'  // 黄色
+  ];
+
   constructor(
     private navCtrl: NavController
   ) {
-    addIcons({ documentTextOutline, documentOutline, bookOutline, cloudDownloadOutline });
+    addIcons({ 
+      documentTextOutline, 
+      documentOutline, 
+      bookOutline, 
+      cloudDownloadOutline,
+      searchOutline,
+      chevronForwardOutline
+    });
   }
 
-  ngOnInit() {
+   ngOnInit() {
     this.loadBookData();
   }
 
@@ -54,4 +86,31 @@ export class PageBookListComponent  implements OnInit {
     DataImporter.executeFullImport();
   }
 
+  // 获取分类颜色
+  getCategoryColor(index: number): string {
+    return this.categoryColors[index % this.categoryColors.length];
+  }
+
+  // 根据文档类型获取颜色
+  getDocTypeColor(docType: string): string {
+    const typeMap: Record<string, string> = {
+      '合同': 'secondary',
+      '诉讼': 'danger',
+      '协议': 'success',
+      '通知': 'warning',
+      '申请': 'tertiary'
+    };
+    return typeMap[docType] || 'primary';
+  }
+
+  // 查看文书详情
+  viewDocument(document: CloudObject) {
+    this.navCtrl.navigateForward(['/document-detail', document.id]);
+  }
+
+  // 查看法律知识详情
+  viewKnowledge(knowledge: CloudObject) {
+    this.navCtrl.navigateForward(['/knowledge-detail', knowledge.id]);
+  }
+
 }