Przeglądaj źródła

feat: new tab2 with home

lfgldr 1 miesiąc temu
rodzic
commit
b0236a426c

+ 2 - 1
myapp/angular.json

@@ -136,7 +136,8 @@
   "cli": {
     "schematicCollections": [
       "@ionic/angular-toolkit"
-    ]
+    ],
+    "analytics": false
   },
   "schematics": {
     "@ionic/angular-toolkit:component": {

+ 0 - 2
myapp/src/app/tab1/tab1.page.spec.ts

@@ -1,8 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { IonicModule } from '@ionic/angular';
-
 import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
-
 import { Tab1Page } from './tab1.page';
 
 describe('Tab1Page', () => {

+ 1 - 2
myapp/src/app/tab2/tab2.module.ts

@@ -4,7 +4,6 @@ import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { Tab2Page } from './tab2.page';
 import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
-
 import { Tab2PageRoutingModule } from './tab2-routing.module';
 
 @NgModule({
@@ -13,7 +12,7 @@ import { Tab2PageRoutingModule } from './tab2-routing.module';
     CommonModule,
     FormsModule,
     ExploreContainerComponentModule,
-    Tab2PageRoutingModule
+    Tab2PageRoutingModule,
   ],
   declarations: [Tab2Page]
 })

+ 97 - 13
myapp/src/app/tab2/tab2.page.html

@@ -1,17 +1,101 @@
-<ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title>
-      Tab 2
-    </ion-title>
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-title>农业知识库</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="toggleFontSize()">
+        <ion-icon [name]="isLargeFont ? 'text' : 'text-outline'"></ion-icon>
+      </ion-button>
+      <ion-button (click)="refreshData()">
+        <ion-icon name="refresh"></ion-icon>
+      </ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+
+  <!-- 搜索栏 -->
+  <ion-toolbar class="search-toolbar">
+    <ion-searchbar 
+      [(ngModel)]="searchQuery" 
+      placeholder="搜索病虫害或种植技术..."
+      (ionChange)="onSearch()"
+      animated>
+    </ion-searchbar>
+    <ion-button fill="clear" slot="end" (click)="startVoiceSearch()">
+      <ion-icon name="mic"></ion-icon>
+    </ion-button>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">Tab 2</ion-title>
-    </ion-toolbar>
-  </ion-header>
+<ion-content [class.large-font]="isLargeFont">
+  <!-- 分类导航 -->
+  <div class="category-container">
+    <ion-segment [(ngModel)]="currentCategory" (ionChange)="filterByCategory()">
+      <ion-segment-button *ngFor="let cat of categories" [value]="cat.id">
+        <ion-icon [name]="cat.icon"></ion-icon>
+        <ion-label>{{ cat.name }}</ion-label>
+      </ion-segment-button>
+    </ion-segment>
+  </div>
+
+  <!-- 专家在线 -->
+  <ion-card class="expert-card">
+    <ion-card-header>
+      <ion-card-title>👨🌾 专家在线咨询</ion-card-title>
+      <ion-card-subtitle>立即连线农业专家解答疑难</ion-card-subtitle>
+    </ion-card-header>
+    <ion-card-content>
+      <div class="expert-list">
+        <div class="expert-item" *ngFor="let expert of onlineExperts" (click)="connectExpert(expert)">
+          <ion-avatar>
+            <img [src]="expert.avatar">
+          </ion-avatar>
+          <div class="expert-info">
+            <h3>{{ expert.name }}</h3>
+            <p>{{ expert.specialty }}</p>
+            <ion-badge [color]="expert.isOnline ? 'success' : 'medium'">
+              {{ expert.isOnline ? '在线' : '离线' }}
+            </ion-badge>
+          </div>
+          <ion-button fill="clear" size="small">
+            <ion-icon name="chatbubble-ellipses"></ion-icon>
+          </ion-button>
+        </div>
+      </div>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 知识卡片列表 -->
+  <div class="knowledge-grid">
+    <ion-card *ngFor="let item of filteredKnowledge" 
+              [class.emergency]="item.isEmergency"
+              (click)="navigateToDetail(item)">
+      <ion-badge *ngIf="item.tag" [color]="getTagColor(item.tag)">
+        {{ getTagLabel(item.tag) }}
+      </ion-badge>
+      <ion-img [src]="item.image"></ion-img>
+      <ion-card-header>
+        <ion-card-title>{{ item.title }}</ion-card-title>
+        <ion-card-subtitle>
+          <ion-icon name="time"></ion-icon>
+          {{ item.duration || '2分钟阅读' }}
+        </ion-card-subtitle>
+      </ion-card-header>
+      <ion-card-content>
+        {{ item.summary }}
+      </ion-card-content>
+      <ion-footer *ngIf="item.type === 'video'">
+        <ion-button fill="clear">
+          <ion-icon name="play" slot="start"></ion-icon>
+          播放视频
+        </ion-button>
+      </ion-footer>
+    </ion-card>
+  </div>
 
-  <app-explore-container name="Tab 2 page"></app-explore-container>
-</ion-content>
+  <!-- 空状态 -->
+  <div class="empty-state" *ngIf="filteredKnowledge.length === 0">
+    <ion-icon name="book"></ion-icon>
+    <h3>未找到相关知识点</h3>
+    <p>尝试更换筛选条件或搜索其他关键词</p>
+    <ion-button fill="outline" (click)="resetFilters()">重置筛选</ion-button>
+  </div>
+</ion-content>

+ 188 - 0
myapp/src/app/tab2/tab2.page.scss

@@ -0,0 +1,188 @@
+/* 全局样式变量 */
+:host {
+    --knowledge-card-width: calc(100% - 20px);
+  }
+  
+  /* 大字体模式 */
+  ion-content.large-font {
+    font-size: 1.2rem;
+  
+    ion-card-title {
+      font-size: 1.4rem;
+    }
+  }
+  
+  /* 搜索工具栏 */
+  .search-toolbar {
+    --background: var(--ion-color-light);
+    padding: 0 10px;
+  
+    ion-searchbar {
+      padding: 0;
+      --background: var(--ion-color-light-shade);
+      --border-radius: 20px;
+    }
+  }
+  
+  /* 分类导航 */
+  .category-container {
+    display: flex;
+    padding: 10px;
+    background: var(--ion-color-light);
+    overflow-x: auto;
+  
+    ion-segment {
+      flex: 1;
+      min-width: max-content;
+  
+      ion-segment-button {
+        --padding-top: 8px;
+        --padding-bottom: 8px;
+        min-width: 80px;
+  
+        ion-icon {
+          font-size: 1.8rem;
+          margin-bottom: 5px;
+        }
+      }
+    }
+  }
+  
+  /* 专家卡片 */
+  .expert-card {
+    margin: 10px;
+  
+    .expert-list {
+      .expert-item {
+        display: flex;
+        align-items: center;
+        padding: 10px 0;
+        border-bottom: 1px solid var(--ion-color-light-shade);
+  
+        ion-avatar {
+          width: 50px;
+          height: 50px;
+          margin-right: 12px;
+        }
+  
+        .expert-info {
+          flex: 1;
+          
+          h3 {
+            margin: 0 0 4px;
+            font-weight: 500;
+          }
+          
+          p {
+            margin: 0;
+            font-size: 0.8rem;
+            color: var(--ion-color-medium);
+          }
+          
+          ion-badge {
+            margin-top: 4px;
+          }
+        }
+        
+        &:last-child {
+          border-bottom: none;
+        }
+      }
+    }
+  }
+  
+  /* 知识网格布局 */
+  .knowledge-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(var(--knowledge-card-width), 1fr));
+    gap: 15px;
+    padding: 10px;
+  
+    @media (min-width: 576px) {
+      --knowledge-card-width: calc(50% - 15px);
+    }
+  
+    @media (min-width: 992px) {
+      --knowledge-card-width: calc(33.33% - 15px);
+    }
+  }
+  
+  /* 知识卡片 */
+  ion-card {
+    margin: 0;
+    border-radius: 12px;
+    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
+    transition: transform 0.3s ease;
+  
+    &:active {
+      transform: scale(0.98);
+    }
+  
+    &.emergency {
+      border-left: 4px solid var(--ion-color-danger);
+    }
+  
+    ion-badge {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      z-index: 2;
+    }
+  
+    ion-img {
+      height: 120px;
+      object-fit: cover;
+    }
+  
+    ion-card-header {
+      padding: 16px 16px 0;
+    }
+  
+    ion-card-content {
+      padding: 0 16px 16px;
+      font-size: 0.9rem;
+      color: var(--ion-color-medium-shade);
+    }
+  
+    ion-footer {
+      padding: 0 16px 16px;
+    }
+  }
+  
+  /* 空状态 */
+  .empty-state {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    height: 50vh;
+    text-align: center;
+    padding: 20px;
+    color: var(--ion-color-medium);
+  
+    ion-icon {
+      font-size: 3rem;
+      margin-bottom: 15px;
+      opacity: 0.5;
+    }
+  
+    h3 {
+      margin: 0 0 10px;
+      font-weight: bold;
+    }
+  }
+  
+  /* 动画效果 */
+  @keyframes fadeIn {
+    from { opacity: 0; transform: translateY(10px); }
+    to { opacity: 1; transform: translateY(0); }
+  }
+  
+  ion-card {
+    animation: fadeIn 0.5s ease forwards;
+    @for $i from 1 through 10 {
+      &:nth-child(#{$i}) {
+        animation-delay: $i * 0.1s;
+      }
+    }
+  }

+ 0 - 2
myapp/src/app/tab2/tab2.page.spec.ts

@@ -1,8 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { IonicModule } from '@ionic/angular';
-
 import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
-
 import { Tab2Page } from './tab2.page';
 
 describe('Tab2Page', () => {

+ 204 - 6
myapp/src/app/tab2/tab2.page.ts

@@ -1,13 +1,211 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { AlertController } from '@ionic/angular';
+
+interface KnowledgeItem {
+  id: string;
+  title: string;
+  summary: string;
+  image: string;
+  type: 'article' | 'video';
+  category: string;
+  tag?: 'emergency' | 'prevention' | 'expert';
+  duration?: string;
+  isEmergency?: boolean;
+}
+
+interface Expert {
+  id: string;
+  name: string;
+  avatar: string;
+  specialty: string;
+  isOnline: boolean;
+  rating: number;
+}
 
 @Component({
   selector: 'app-tab2',
-  templateUrl: 'tab2.page.html',
-  styleUrls: ['tab2.page.scss'],
+  templateUrl: './tab2.page.html',
+  styleUrls: ['./tab2.page.scss'],
   standalone: false,
 })
-export class Tab2Page {
+export class Tab2Page implements OnInit {
+  searchQuery = '';
+  isLargeFont = false;
+  currentCategory = 'all';
 
-  constructor() {}
+  categories = [
+    { id: 'all', name: '全部', icon: 'apps' },
+    { id: 'wheat', name: '小麦', icon: 'leaf' },
+    { id: 'rice', name: '水稻', icon: 'water' },
+    { id: 'corn', name: '玉米', icon: 'ear' },
+    { id: 'fruit', name: '果树', icon: 'nutrition' },
+  ];
 
-}
+  onlineExperts: Expert[] = [
+    {
+      id: '1',
+      name: '张农艺师',
+      avatar: 'assets/images/expert1.jpg',
+      specialty: '水稻种植专家',
+      isOnline: true,
+      rating: 4.8
+    },
+    {
+      id: '2',
+      name: '李研究员',
+      avatar: 'assets/images/expert2.jpg',
+      specialty: '果树病虫害防治',
+      isOnline: true,
+      rating: 4.9
+    },
+    {
+      id: '3',
+      name: '王技术员',
+      avatar: 'assets/images/expert3.jpg',
+      specialty: '土壤改良',
+      isOnline: false,
+      rating: 4.7
+    }
+  ];
+
+  knowledgeList: KnowledgeItem[] = [
+    {
+      id: '1',
+      title: '小麦赤霉病防治',
+      summary: '识别赤霉病早期症状及防治方案',
+      image: 'assets/images/wheat-disease.jpg',
+      type: 'article',
+      category: 'wheat',
+      tag: 'emergency',
+      isEmergency: true
+    },
+    {
+      id: '2',
+      title: '水稻科学灌溉技巧',
+      summary: '不同生长阶段的水分管理要点',
+      image: 'assets/images/rice-irrigation.jpg',
+      type: 'article',
+      category: 'rice',
+      tag: 'expert',
+      duration: '5分钟阅读'
+    },
+    {
+      id: '3',
+      title: '果树修剪实操指南',
+      summary: '视频演示冬季修剪的正确方法',
+      image: 'assets/images/fruit-pruning.jpg',
+      type: 'video',
+      category: 'fruit',
+      duration: '12分钟'
+    },
+    {
+      id: '4',
+      title: '玉米螟虫预防措施',
+      summary: '生物防治与化学防治结合方案',
+      image: 'assets/images/corn-pest.jpg',
+      type: 'article',
+      category: 'corn',
+      tag: 'prevention'
+    },
+    {
+      id: '5',
+      title: '土壤改良方法',
+      summary: '酸性土壤改良的7种有效方式',
+      image: 'assets/images/soil-improve.jpg',
+      type: 'article',
+      category: 'all',
+      duration: '8分钟阅读'
+    }
+  ];
+
+  filteredKnowledge: KnowledgeItem[] = [];
+
+  constructor(
+    private router: Router,
+    private alertCtrl: AlertController
+  ) {}
+
+  ngOnInit() {
+    this.filteredKnowledge = [...this.knowledgeList];
+  }
+
+  toggleFontSize() {
+    this.isLargeFont = !this.isLargeFont;
+  }
+
+  refreshData() {
+    // 模拟刷新数据
+    this.filteredKnowledge = [...this.knowledgeList];
+    this.searchQuery = '';
+    this.currentCategory = 'all';
+  }
+
+  resetFilters() {
+    this.refreshData();
+  }
+
+  onSearch() {
+    if (!this.searchQuery) {
+      this.filteredKnowledge = [...this.knowledgeList];
+      return;
+    }
+
+    const query = this.searchQuery.toLowerCase();
+    this.filteredKnowledge = this.knowledgeList.filter(item => 
+      item.title.toLowerCase().includes(query) || 
+      item.summary.toLowerCase().includes(query)
+    );
+  }
+
+  startVoiceSearch() {
+    console.log('启动语音搜索');
+    // 实际应集成语音识别API
+  }
+
+  filterByCategory() {
+    if (this.currentCategory === 'all') {
+      this.filteredKnowledge = [...this.knowledgeList];
+    } else {
+      this.filteredKnowledge = this.knowledgeList.filter(
+        item => item.category === this.currentCategory
+      );
+    }
+  }
+
+  async connectExpert(expert: Expert) {
+    if (!expert.isOnline) {
+      const alert = await this.alertCtrl.create({
+        header: '专家离线',
+        message: `${expert.name}专家当前不在线,请选择其他在线专家`,
+        buttons: ['确定']
+      });
+      await alert.present();
+      return;
+    }
+
+    this.router.navigate(['/expert-chat', expert.id]);
+  }
+
+  navigateToDetail(item: KnowledgeItem) {
+    this.router.navigate(['/knowledge-detail', item.id]);
+  }
+
+  getTagColor(tag: string): string {
+    switch (tag) {
+      case 'emergency': return 'danger';
+      case 'prevention': return 'warning';
+      case 'expert': return 'success';
+      default: return 'primary';
+    }
+  }
+
+  getTagLabel(tag: string): string {
+    switch (tag) {
+      case 'emergency': return '紧急';
+      case 'prevention': return '预防';
+      case 'expert': return '专家推荐';
+      default: return '';
+    }
+  }
+}

+ 1 - 1
myapp/src/app/tab3/tab3-routing.module.ts

@@ -13,4 +13,4 @@ const routes: Routes = [
   imports: [RouterModule.forChild(routes)],
   exports: [RouterModule]
 })
-export class Tab3PageRoutingModule {}
+export class Tab3PageRoutingModule {}

+ 5 - 7
myapp/src/app/tab3/tab3.module.ts

@@ -1,20 +1,18 @@
-import { IonicModule } from '@ionic/angular';
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { Tab3Page } from './tab3.page';
-import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
-
 import { Tab3PageRoutingModule } from './tab3-routing.module';
 
 @NgModule({
   imports: [
-    IonicModule,
     CommonModule,
     FormsModule,
-    ExploreContainerComponentModule,
+    ReactiveFormsModule,
+    IonicModule,
     Tab3PageRoutingModule
   ],
   declarations: [Tab3Page]
 })
-export class Tab3PageModule {}
+export class Tab3PageModule {}

+ 165 - 13
myapp/src/app/tab3/tab3.page.html

@@ -1,17 +1,169 @@
-<ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title>
-      Tab 3
-    </ion-title>
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-title>我的农场</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="toggleFieldForm()">
+        <ion-icon [name]="showFieldForm ? 'close' : 'add'" slot="icon-only"></ion-icon>
+      </ion-button>
+    </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">Tab 3</ion-title>
-    </ion-toolbar>
-  </ion-header>
+<ion-content>
+  <!-- 添加/编辑农田表单 -->
+  <ion-card *ngIf="showFieldForm" class="form-card">
+    <ion-card-header>
+      <ion-card-title>{{ editingField ? '编辑农田' : '添加新农田' }}</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <form [formGroup]="fieldForm" (ngSubmit)="saveField()">
+        <ion-item>
+          <ion-label position="floating">农田名称</ion-label>
+          <ion-input formControlName="name" type="text"></ion-input>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label position="floating">面积(亩)</ion-label>
+          <ion-input formControlName="area" type="number"></ion-input>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label position="floating">位置</ion-label>
+          <ion-input formControlName="location" type="text"></ion-input>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label>当前作物</ion-label>
+          <ion-select formControlName="currentCrop">
+            <ion-select-option value="冬小麦">冬小麦</ion-select-option>
+            <ion-select-option value="春玉米">春玉米</ion-select-option>
+            <ion-select-option value="水稻">水稻</ion-select-option>
+            <ion-select-option value="大豆">大豆</ion-select-option>
+          </ion-select>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label>土壤类型</ion-label>
+          <ion-select formControlName="soilType">
+            <ion-select-option value="粘壤土">粘壤土</ion-select-option>
+            <ion-select-option value="砂壤土">砂壤土</ion-select-option>
+            <ion-select-option value="壤土">壤土</ion-select-option>
+            <ion-select-option value="粘土">粘土</ion-select-option>
+          </ion-select>
+        </ion-item>
+        
+        <div class="form-buttons">
+          <ion-button type="button" fill="outline" (click)="cancelEdit()">取消</ion-button>
+          <ion-button type="submit" [disabled]="!fieldForm.valid">保存</ion-button>
+        </div>
+      </form>
+    </ion-card-content>
+  </ion-card>
 
-  <app-explore-container name="Tab 3 page"></app-explore-container>
-</ion-content>
+  <!-- 农场概览 -->
+  <ion-card class="summary-card">
+    <ion-card-header>
+      <ion-card-title>农场概览</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <div class="summary-grid">
+        <div class="summary-item">
+          <ion-icon name="map" color="primary"></ion-icon>
+          <h3>{{ fields.length }}</h3>
+          <p>地块数量</p>
+        </div>
+        <div class="summary-item">
+          <ion-icon name="leaf" color="success"></ion-icon>
+          <h3>{{ totalArea }}亩</h3>
+          <p>种植面积</p>
+        </div>
+        <div class="summary-item">
+          <ion-icon name="alarm" color="warning"></ion-icon>
+          <h3>{{ pendingTasks }}</h3>
+          <p>待办农事</p>
+        </div>
+      </div>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 农田地块列表 -->
+  <ion-list>
+    <ion-item-sliding *ngFor="let field of fields">
+      <ion-item (click)="editField(field)">
+        <ion-avatar slot="start">
+          <img [src]="getCropImage(field.currentCrop)">
+        </ion-avatar>
+        <ion-label>
+          <h2>{{ field.name }}</h2>
+          <p>{{ field.area }}亩 • {{ field.currentCrop }}</p>
+          <p class="field-status">
+            <ion-badge *ngIf="field.status" [color]="getStatusColor(field.status)">
+              {{ field.status }}
+            </ion-badge>
+            <span>种植 {{ field.daysPlanted }}天</span>
+          </p>
+        </ion-label>
+        <ion-note slot="end">
+          {{ field.nextTask || '暂无农事' }}
+        </ion-note>
+      </ion-item>
+      <ion-item-options side="end">
+        <ion-item-option color="danger" (click)="deleteField(field.id)">
+          <ion-icon name="trash" slot="icon-only"></ion-icon>
+        </ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+  </ion-list>
+
+  <!-- 无地块提示 -->
+  <div class="empty-tip" *ngIf="fields.length === 0 && !showFieldForm">
+    <ion-icon name="earth"></ion-icon>
+    <p>您还没有添加农田地块</p>
+    <ion-button fill="outline" (click)="toggleFieldForm()">添加第一块地</ion-button>
+  </div>
+
+  <!-- 农事提醒 -->
+  <ion-card class="task-card" *ngIf="fields.length > 0">
+    <ion-card-header>
+      <ion-card-title>
+        <ion-icon name="notifications" color="warning"></ion-icon>
+        近期农事提醒
+      </ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <ion-list>
+        <ion-item *ngFor="let task of recentTasks" (click)="viewTaskDetail(task)">
+          <ion-icon [name]="getTaskIcon(task.type)" slot="start" [color]="getTaskColor(task.type)"></ion-icon>
+          <ion-label>
+            <h3>{{ task.fieldName }}:{{ task.name }}</h3>
+            <p>{{ task.dueDate | date:'MM月dd日' }} • {{ task.notes || '暂无备注' }}</p>
+          </ion-label>
+          <ion-badge slot="end" [color]="task.urgent ? 'danger' : 'medium'">
+            {{ task.urgent ? '紧急' : '常规' }}
+          </ion-badge>
+        </ion-item>
+      </ion-list>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 生长记录 -->
+  <ion-card *ngIf="fields.length > 0">
+    <ion-card-header>
+      <ion-card-title>
+        <ion-icon name="calendar" color="primary"></ion-icon>
+        近期生长记录
+      </ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <div class="record-timeline">
+        <div class="record-item" *ngFor="let record of recentRecords">
+          <div class="record-date">{{ record.date | date:'MM.dd' }}</div>
+          <div class="record-content">
+            <h4>{{ record.fieldName }} {{ record.activity }}</h4>
+            <p>{{ record.notes }}</p>
+          </div>
+        </div>
+      </div>
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 212 - 0
myapp/src/app/tab3/tab3.page.scss

@@ -0,0 +1,212 @@
+/* 表单卡片 */
+.form-card {
+  margin: 10px;
+  border-radius: 12px;
+
+  ion-item {
+    --padding-start: 0;
+    --inner-padding-end: 0;
+    margin-bottom: 15px;
+  }
+
+  .form-buttons {
+    display: flex;
+    justify-content: space-between;
+    margin-top: 20px;
+
+    ion-button {
+      width: 48%;
+    }
+  }
+}
+
+/* 农场概览卡片 */
+.summary-card {
+  margin: 10px;
+  border-radius: 12px;
+
+  .summary-grid {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    gap: 10px;
+    text-align: center;
+
+    .summary-item {
+      ion-icon {
+        font-size: 2rem;
+      }
+
+      h3 {
+        margin: 5px 0 0;
+        font-size: 1.4rem;
+        font-weight: bold;
+      }
+
+      p {
+        margin: 2px 0;
+        font-size: 0.8rem;
+        color: var(--ion-color-medium);
+      }
+    }
+  }
+}
+
+/* 地块列表 */
+ion-list {
+  background: transparent;
+  padding-top: 0;
+
+  ion-item {
+    --padding-start: 10px;
+    --inner-padding-end: 10px;
+    margin-bottom: 8px;
+    border-radius: 10px;
+    --background: var(--ion-color-light);
+
+    ion-avatar {
+      width: 50px;
+      height: 50px;
+      background: var(--ion-color-light-shade);
+    }
+
+    h2 {
+      font-weight: 600;
+    }
+
+    .field-status {
+      display: flex;
+      align-items: center;
+      margin-top: 5px;
+
+      ion-badge {
+        margin-right: 8px;
+      }
+
+      span {
+        font-size: 0.8rem;
+        color: var(--ion-color-medium);
+      }
+    }
+
+    ion-note {
+      font-size: 0.8rem;
+      color: var(--ion-color-primary);
+    }
+  }
+}
+
+/* 空状态提示 */
+.empty-tip {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 60vh;
+  text-align: center;
+  padding: 20px;
+
+  ion-icon {
+    font-size: 3rem;
+    color: var(--ion-color-medium);
+    margin-bottom: 15px;
+  }
+
+  p {
+    color: var(--ion-color-medium);
+    margin-bottom: 20px;
+  }
+}
+
+/* 农事提醒卡片 */
+.task-card {
+  margin: 15px 10px;
+
+  ion-item {
+    --padding-start: 0;
+    --inner-padding-end: 0;
+    --border-radius: 8px;
+    margin-bottom: 8px;
+
+    ion-icon {
+      font-size: 1.5rem;
+    }
+
+    h3 {
+      font-size: 0.95rem;
+      margin-bottom: 3px;
+    }
+
+    p {
+      font-size: 0.8rem;
+      color: var(--ion-color-medium);
+    }
+  }
+}
+
+/* 生长记录时间线 */
+.record-timeline {
+  padding-left: 20px;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    left: 6px;
+    top: 0;
+    bottom: 0;
+    width: 2px;
+    background: var(--ion-color-light-shade);
+  }
+
+  .record-item {
+    position: relative;
+    padding-bottom: 15px;
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: -20px;
+      top: 5px;
+      width: 10px;
+      height: 10px;
+      border-radius: 50%;
+      background: var(--ion-color-primary);
+    }
+
+    .record-date {
+      font-weight: bold;
+      color: var(--ion-color-primary);
+      margin-bottom: 5px;
+    }
+
+    .record-content {
+      background: var(--ion-color-light);
+      padding: 10px;
+      border-radius: 8px;
+
+      h4 {
+        margin: 0 0 5px;
+        font-size: 0.9rem;
+      }
+
+      p {
+        margin: 0 0 8px;
+        font-size: 0.8rem;
+        color: var(--ion-color-medium);
+      }
+
+      .record-images {
+        display: flex;
+        gap: 5px;
+        overflow-x: auto;
+
+        ion-thumbnail {
+          width: 60px;
+          height: 60px;
+          border-radius: 5px;
+          overflow: hidden;
+        }
+      }
+    }
+  }
+}

+ 1 - 3
myapp/src/app/tab3/tab3.page.spec.ts

@@ -1,8 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { IonicModule } from '@ionic/angular';
-
 import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
-
 import { Tab3Page } from './tab3.page';
 
 describe('Tab3Page', () => {
@@ -23,4 +21,4 @@ describe('Tab3Page', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
-});
+});

+ 276 - 6
myapp/src/app/tab3/tab3.page.ts

@@ -1,13 +1,283 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { AlertController } from '@ionic/angular';
+
+interface FarmField {
+  id: string;
+  name: string;
+  area: number;
+  location: string;
+  currentCrop: string;
+  daysPlanted: number;
+  status?: '需灌溉' | '需施肥' | '需防治' | '正常';
+  nextTask?: string;
+  soilType?: string;
+}
+
+interface FarmTask {
+  id: string;
+  fieldId: string;
+  fieldName: string;
+  name: string;
+  type: 'irrigation' | 'fertilization' | 'pestControl' | 'harvest';
+  dueDate: Date;
+  notes?: string;
+  urgent: boolean;
+  completed: boolean;
+}
+
+interface GrowthRecord {
+  id: string;
+  fieldId: string;
+  fieldName: string;
+  date: Date;
+  activity: string;
+  notes: string;
+  images?: string[];
+}
 
 @Component({
   selector: 'app-tab3',
-  templateUrl: 'tab3.page.html',
-  styleUrls: ['tab3.page.scss'],
+  templateUrl: './tab3.page.html',
+  styleUrls: ['./tab3.page.scss'],
   standalone: false,
 })
-export class Tab3Page {
+export class Tab3Page implements OnInit {
+  fields: FarmField[] = [
+    {
+      id: '1',
+      name: '北区小麦田',
+      area: 5.2,
+      location: '农场北侧',
+      currentCrop: '冬小麦',
+      daysPlanted: 45,
+      status: '需施肥',
+      nextTask: '明日追肥',
+      soilType: '粘壤土'
+    },
+    {
+      id: '2',
+      name: '南区玉米地',
+      area: 3.8,
+      location: '农场南侧',
+      currentCrop: '春玉米',
+      daysPlanted: 22,
+      status: '正常',
+      nextTask: '下周除草',
+      soilType: '砂壤土'
+    }
+  ];
 
-  constructor() {}
+  tasks: FarmTask[] = [
+    {
+      id: '1',
+      fieldId: '1',
+      fieldName: '北区小麦田',
+      name: '追施氮肥',
+      type: 'fertilization',
+      dueDate: new Date(new Date().setDate(new Date().getDate() + 1)),
+      urgent: true,
+      completed: false
+    },
+    {
+      id: '2',
+      fieldId: '2',
+      fieldName: '南区玉米地',
+      name: '除草作业',
+      type: 'pestControl',
+      dueDate: new Date(new Date().setDate(new Date().getDate() + 7)),
+      urgent: false,
+      completed: false
+    }
+  ];
 
-}
+  records: GrowthRecord[] = [
+    {
+      id: '1',
+      fieldId: '1',
+      fieldName: '北区小麦田',
+      date: new Date(new Date().setDate(new Date().getDate() - 3)),
+      activity: '病虫害检查',
+      notes: '发现少量蚜虫,已喷施防治',
+      images: [
+        'assets/images/wheat-pest1.jpg',
+        'assets/images/wheat-pest2.jpg'
+      ]
+    },
+    {
+      id: '2',
+      fieldId: '2',
+      fieldName: '南区玉米地',
+      date: new Date(new Date().setDate(new Date().getDate() - 5)),
+      activity: '追肥',
+      notes: '施用复合肥20kg/亩'
+    }
+  ];
+
+  showFieldForm = false;
+  editingField: FarmField | null = null;
+  fieldForm: FormGroup;
+
+  constructor(
+    private fb: FormBuilder,
+    private alertCtrl: AlertController
+  ) {
+    this.fieldForm = this.fb.group({
+      name: ['', Validators.required],
+      area: ['', [Validators.required, Validators.min(0.1)]],
+      location: [''],
+      currentCrop: ['冬小麦', Validators.required],
+      soilType: ['粘壤土']
+    });
+  }
+
+  ngOnInit() {}
+
+  get totalArea(): number {
+    return this.fields.reduce((sum, field) => sum + field.area, 0);
+  }
+
+  get pendingTasks(): number {
+    return this.tasks.filter(t => !t.completed).length;
+  }
+
+  get recentTasks(): FarmTask[] {
+    return this.tasks
+      .filter(t => !t.completed)
+      .sort((a, b) => a.dueDate.getTime() - b.dueDate.getTime())
+      .slice(0, 3);
+  }
+
+  get recentRecords(): GrowthRecord[] {
+    return [...this.records]
+      .sort((a, b) => b.date.getTime() - a.date.getTime())
+      .slice(0, 4);
+  }
+
+  getCropImage(crop: string): string {
+    const cropImages: {[key: string]: string} = {
+      '冬小麦': 'assets/images/wheat-icon.png',
+      '春玉米': 'assets/images/corn-icon.png',
+      '水稻': 'assets/images/rice-icon.png',
+      '大豆': 'assets/images/soybean-icon.png'
+    };
+    return cropImages[crop] || 'assets/images/crop-default.png';
+  }
+
+  getStatusColor(status: string): string {
+    const statusColors: {[key: string]: string} = {
+      '需灌溉': 'primary',
+      '需施肥': 'warning',
+      '需防治': 'danger',
+      '正常': 'success'
+    };
+    return statusColors[status] || 'medium';
+  }
+
+  getTaskIcon(type: string): string {
+    const taskIcons: {[key: string]: string} = {
+      'irrigation': 'water',
+      'fertilization': 'nutrition',
+      'pestControl': 'bug',
+      'harvest': 'leaf'
+    };
+    return taskIcons[type] || 'alert-circle';
+  }
+
+  getTaskColor(type: string): string {
+    const taskColors: {[key: string]: string} = {
+      'irrigation': 'primary',
+      'fertilization': 'warning',
+      'pestControl': 'danger',
+      'harvest': 'success'
+    };
+    return taskColors[type] || 'medium';
+  }
+
+  toggleFieldForm() {
+    this.showFieldForm = !this.showFieldForm;
+    if (!this.showFieldForm) {
+      this.editingField = null;
+      this.fieldForm.reset({
+        currentCrop: '冬小麦',
+        soilType: '粘壤土'
+      });
+    }
+  }
+
+  editField(field: FarmField) {
+    this.editingField = field;
+    this.fieldForm.patchValue({
+      name: field.name,
+      area: field.area,
+      location: field.location,
+      currentCrop: field.currentCrop,
+      soilType: field.soilType
+    });
+    this.showFieldForm = true;
+  }
+
+  saveField() {
+    if (this.fieldForm.invalid) return;
+
+    const fieldData = this.fieldForm.value;
+    
+    if (this.editingField) {
+      // 更新现有农田
+      const index = this.fields.findIndex(f => f.id === this.editingField?.id);
+      if (index >= 0) {
+        this.fields[index] = {
+          ...this.fields[index],
+          ...fieldData
+        };
+      }
+    } else {
+      // 添加新农田
+      this.fields.push({
+        id: Date.now().toString(),
+        daysPlanted: 0,
+        status: '正常',
+        ...fieldData
+      });
+    }
+
+    this.cancelEdit();
+  }
+
+  cancelEdit() {
+    this.showFieldForm = false;
+    this.editingField = null;
+    this.fieldForm.reset({
+      currentCrop: '冬小麦',
+      soilType: '粘壤土'
+    });
+  }
+
+  async deleteField(fieldId: string) {
+    const alert = await this.alertCtrl.create({
+      header: '确认删除',
+      message: '确定要删除这个农田地块吗?相关记录也将被删除',
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel'
+        },
+        {
+          text: '删除',
+          handler: () => {
+            this.fields = this.fields.filter(f => f.id !== fieldId);
+            this.tasks = this.tasks.filter(t => t.fieldId !== fieldId);
+            this.records = this.records.filter(r => r.fieldId !== fieldId);
+          }
+        }
+      ]
+    });
+
+    await alert.present();
+  }
+
+  viewTaskDetail(task: FarmTask) {
+    console.log('查看任务详情:', task);
+    // 实际应导航到任务详情页
+  }
+}

+ 16 - 0
myapp/src/app/tab4/tab4-routing.module.ts

@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { Tab4Page } from './tab4.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: Tab4Page,
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class Tab3PageRoutingModule {}

+ 18 - 0
myapp/src/app/tab4/tab4.module.ts

@@ -0,0 +1,18 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { IonicModule } from '@ionic/angular';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { Tab4Page } from './tab4.page';
+import { Tab3PageRoutingModule } from './tab4-routing.module';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    ReactiveFormsModule,
+    IonicModule,
+    Tab3PageRoutingModule
+  ],
+  declarations: [Tab4Page]
+})
+export class Tab3PageModule {}

+ 169 - 0
myapp/src/app/tab4/tab4.page.html

@@ -0,0 +1,169 @@
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-title>我的农场</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="toggleFieldForm()">
+        <ion-icon [name]="showFieldForm ? 'close' : 'add'" slot="icon-only"></ion-icon>
+      </ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <!-- 添加/编辑农田表单 -->
+  <ion-card *ngIf="showFieldForm" class="form-card">
+    <ion-card-header>
+      <ion-card-title>{{ editingField ? '编辑农田' : '添加新农田' }}</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <form [formGroup]="fieldForm" (ngSubmit)="saveField()">
+        <ion-item>
+          <ion-label position="floating">农田名称</ion-label>
+          <ion-input formControlName="name" type="text"></ion-input>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label position="floating">面积(亩)</ion-label>
+          <ion-input formControlName="area" type="number"></ion-input>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label position="floating">位置</ion-label>
+          <ion-input formControlName="location" type="text"></ion-input>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label>当前作物</ion-label>
+          <ion-select formControlName="currentCrop">
+            <ion-select-option value="冬小麦">冬小麦</ion-select-option>
+            <ion-select-option value="春玉米">春玉米</ion-select-option>
+            <ion-select-option value="水稻">水稻</ion-select-option>
+            <ion-select-option value="大豆">大豆</ion-select-option>
+          </ion-select>
+        </ion-item>
+        
+        <ion-item>
+          <ion-label>土壤类型</ion-label>
+          <ion-select formControlName="soilType">
+            <ion-select-option value="粘壤土">粘壤土</ion-select-option>
+            <ion-select-option value="砂壤土">砂壤土</ion-select-option>
+            <ion-select-option value="壤土">壤土</ion-select-option>
+            <ion-select-option value="粘土">粘土</ion-select-option>
+          </ion-select>
+        </ion-item>
+        
+        <div class="form-buttons">
+          <ion-button type="button" fill="outline" (click)="cancelEdit()">取消</ion-button>
+          <ion-button type="submit" [disabled]="!fieldForm.valid">保存</ion-button>
+        </div>
+      </form>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 农场概览 -->
+  <ion-card class="summary-card">
+    <ion-card-header>
+      <ion-card-title>农场概览</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <div class="summary-grid">
+        <div class="summary-item">
+          <ion-icon name="map" color="primary"></ion-icon>
+          <h3>{{ fields.length }}</h3>
+          <p>地块数量</p>
+        </div>
+        <div class="summary-item">
+          <ion-icon name="leaf" color="success"></ion-icon>
+          <h3>{{ totalArea }}亩</h3>
+          <p>种植面积</p>
+        </div>
+        <div class="summary-item">
+          <ion-icon name="alarm" color="warning"></ion-icon>
+          <h3>{{ pendingTasks }}</h3>
+          <p>待办农事</p>
+        </div>
+      </div>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 农田地块列表 -->
+  <ion-list>
+    <ion-item-sliding *ngFor="let field of fields">
+      <ion-item (click)="editField(field)">
+        <ion-avatar slot="start">
+          <img [src]="getCropImage(field.currentCrop)">
+        </ion-avatar>
+        <ion-label>
+          <h2>{{ field.name }}</h2>
+          <p>{{ field.area }}亩 • {{ field.currentCrop }}</p>
+          <p class="field-status">
+            <ion-badge *ngIf="field.status" [color]="getStatusColor(field.status)">
+              {{ field.status }}
+            </ion-badge>
+            <span>种植 {{ field.daysPlanted }}天</span>
+          </p>
+        </ion-label>
+        <ion-note slot="end">
+          {{ field.nextTask || '暂无农事' }}
+        </ion-note>
+      </ion-item>
+      <ion-item-options side="end">
+        <ion-item-option color="danger" (click)="deleteField(field.id)">
+          <ion-icon name="trash" slot="icon-only"></ion-icon>
+        </ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+  </ion-list>
+
+  <!-- 无地块提示 -->
+  <div class="empty-tip" *ngIf="fields.length === 0 && !showFieldForm">
+    <ion-icon name="earth"></ion-icon>
+    <p>您还没有添加农田地块</p>
+    <ion-button fill="outline" (click)="toggleFieldForm()">添加第一块地</ion-button>
+  </div>
+
+  <!-- 农事提醒 -->
+  <ion-card class="task-card" *ngIf="fields.length > 0">
+    <ion-card-header>
+      <ion-card-title>
+        <ion-icon name="notifications" color="warning"></ion-icon>
+        近期农事提醒
+      </ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <ion-list>
+        <ion-item *ngFor="let task of recentTasks" (click)="viewTaskDetail(task)">
+          <ion-icon [name]="getTaskIcon(task.type)" slot="start" [color]="getTaskColor(task.type)"></ion-icon>
+          <ion-label>
+            <h3>{{ task.fieldName }}:{{ task.name }}</h3>
+            <p>{{ task.dueDate | date:'MM月dd日' }} • {{ task.notes || '暂无备注' }}</p>
+          </ion-label>
+          <ion-badge slot="end" [color]="task.urgent ? 'danger' : 'medium'">
+            {{ task.urgent ? '紧急' : '常规' }}
+          </ion-badge>
+        </ion-item>
+      </ion-list>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 生长记录 -->
+  <ion-card *ngIf="fields.length > 0">
+    <ion-card-header>
+      <ion-card-title>
+        <ion-icon name="calendar" color="primary"></ion-icon>
+        近期生长记录
+      </ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <div class="record-timeline">
+        <div class="record-item" *ngFor="let record of recentRecords">
+          <div class="record-date">{{ record.date | date:'MM.dd' }}</div>
+          <div class="record-content">
+            <h4>{{ record.fieldName }} {{ record.activity }}</h4>
+            <p>{{ record.notes }}</p>
+          </div>
+        </div>
+      </div>
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 212 - 0
myapp/src/app/tab4/tab4.page.scss

@@ -0,0 +1,212 @@
+/* 表单卡片 */
+.form-card {
+  margin: 10px;
+  border-radius: 12px;
+
+  ion-item {
+    --padding-start: 0;
+    --inner-padding-end: 0;
+    margin-bottom: 15px;
+  }
+
+  .form-buttons {
+    display: flex;
+    justify-content: space-between;
+    margin-top: 20px;
+
+    ion-button {
+      width: 48%;
+    }
+  }
+}
+
+/* 农场概览卡片 */
+.summary-card {
+  margin: 10px;
+  border-radius: 12px;
+
+  .summary-grid {
+    display: grid;
+    grid-template-columns: repeat(3, 1fr);
+    gap: 10px;
+    text-align: center;
+
+    .summary-item {
+      ion-icon {
+        font-size: 2rem;
+      }
+
+      h3 {
+        margin: 5px 0 0;
+        font-size: 1.4rem;
+        font-weight: bold;
+      }
+
+      p {
+        margin: 2px 0;
+        font-size: 0.8rem;
+        color: var(--ion-color-medium);
+      }
+    }
+  }
+}
+
+/* 地块列表 */
+ion-list {
+  background: transparent;
+  padding-top: 0;
+
+  ion-item {
+    --padding-start: 10px;
+    --inner-padding-end: 10px;
+    margin-bottom: 8px;
+    border-radius: 10px;
+    --background: var(--ion-color-light);
+
+    ion-avatar {
+      width: 50px;
+      height: 50px;
+      background: var(--ion-color-light-shade);
+    }
+
+    h2 {
+      font-weight: 600;
+    }
+
+    .field-status {
+      display: flex;
+      align-items: center;
+      margin-top: 5px;
+
+      ion-badge {
+        margin-right: 8px;
+      }
+
+      span {
+        font-size: 0.8rem;
+        color: var(--ion-color-medium);
+      }
+    }
+
+    ion-note {
+      font-size: 0.8rem;
+      color: var(--ion-color-primary);
+    }
+  }
+}
+
+/* 空状态提示 */
+.empty-tip {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 60vh;
+  text-align: center;
+  padding: 20px;
+
+  ion-icon {
+    font-size: 3rem;
+    color: var(--ion-color-medium);
+    margin-bottom: 15px;
+  }
+
+  p {
+    color: var(--ion-color-medium);
+    margin-bottom: 20px;
+  }
+}
+
+/* 农事提醒卡片 */
+.task-card {
+  margin: 15px 10px;
+
+  ion-item {
+    --padding-start: 0;
+    --inner-padding-end: 0;
+    --border-radius: 8px;
+    margin-bottom: 8px;
+
+    ion-icon {
+      font-size: 1.5rem;
+    }
+
+    h3 {
+      font-size: 0.95rem;
+      margin-bottom: 3px;
+    }
+
+    p {
+      font-size: 0.8rem;
+      color: var(--ion-color-medium);
+    }
+  }
+}
+
+/* 生长记录时间线 */
+.record-timeline {
+  padding-left: 20px;
+  position: relative;
+
+  &::before {
+    content: '';
+    position: absolute;
+    left: 6px;
+    top: 0;
+    bottom: 0;
+    width: 2px;
+    background: var(--ion-color-light-shade);
+  }
+
+  .record-item {
+    position: relative;
+    padding-bottom: 15px;
+
+    &::before {
+      content: '';
+      position: absolute;
+      left: -20px;
+      top: 5px;
+      width: 10px;
+      height: 10px;
+      border-radius: 50%;
+      background: var(--ion-color-primary);
+    }
+
+    .record-date {
+      font-weight: bold;
+      color: var(--ion-color-primary);
+      margin-bottom: 5px;
+    }
+
+    .record-content {
+      background: var(--ion-color-light);
+      padding: 10px;
+      border-radius: 8px;
+
+      h4 {
+        margin: 0 0 5px;
+        font-size: 0.9rem;
+      }
+
+      p {
+        margin: 0 0 8px;
+        font-size: 0.8rem;
+        color: var(--ion-color-medium);
+      }
+
+      .record-images {
+        display: flex;
+        gap: 5px;
+        overflow-x: auto;
+
+        ion-thumbnail {
+          width: 60px;
+          height: 60px;
+          border-radius: 5px;
+          overflow: hidden;
+        }
+      }
+    }
+  }
+}

+ 24 - 0
myapp/src/app/tab4/tab4.page.spec.ts

@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
+import { Tab4Page } from './tab4.page';
+
+describe('Tab3Page', () => {
+  let component: Tab4Page;
+  let fixture: ComponentFixture<Tab4Page>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [Tab4Page],
+      imports: [IonicModule.forRoot(), ExploreContainerComponentModule]
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(Tab4Page);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 283 - 0
myapp/src/app/tab4/tab4.page.ts

@@ -0,0 +1,283 @@
+import { Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { AlertController } from '@ionic/angular';
+
+interface FarmField {
+  id: string;
+  name: string;
+  area: number;
+  location: string;
+  currentCrop: string;
+  daysPlanted: number;
+  status?: '需灌溉' | '需施肥' | '需防治' | '正常';
+  nextTask?: string;
+  soilType?: string;
+}
+
+interface FarmTask {
+  id: string;
+  fieldId: string;
+  fieldName: string;
+  name: string;
+  type: 'irrigation' | 'fertilization' | 'pestControl' | 'harvest';
+  dueDate: Date;
+  notes?: string;
+  urgent: boolean;
+  completed: boolean;
+}
+
+interface GrowthRecord {
+  id: string;
+  fieldId: string;
+  fieldName: string;
+  date: Date;
+  activity: string;
+  notes: string;
+  images?: string[];
+}
+
+@Component({
+  selector: 'app-tab4',
+  templateUrl: './tab4.page.html',
+  styleUrls: ['./tab4.page.scss'],
+  standalone: false,
+})
+export class Tab4Page implements OnInit {
+  fields: FarmField[] = [
+    {
+      id: '1',
+      name: '北区小麦田',
+      area: 5.2,
+      location: '农场北侧',
+      currentCrop: '冬小麦',
+      daysPlanted: 45,
+      status: '需施肥',
+      nextTask: '明日追肥',
+      soilType: '粘壤土'
+    },
+    {
+      id: '2',
+      name: '南区玉米地',
+      area: 3.8,
+      location: '农场南侧',
+      currentCrop: '春玉米',
+      daysPlanted: 22,
+      status: '正常',
+      nextTask: '下周除草',
+      soilType: '砂壤土'
+    }
+  ];
+
+  tasks: FarmTask[] = [
+    {
+      id: '1',
+      fieldId: '1',
+      fieldName: '北区小麦田',
+      name: '追施氮肥',
+      type: 'fertilization',
+      dueDate: new Date(new Date().setDate(new Date().getDate() + 1)),
+      urgent: true,
+      completed: false
+    },
+    {
+      id: '2',
+      fieldId: '2',
+      fieldName: '南区玉米地',
+      name: '除草作业',
+      type: 'pestControl',
+      dueDate: new Date(new Date().setDate(new Date().getDate() + 7)),
+      urgent: false,
+      completed: false
+    }
+  ];
+
+  records: GrowthRecord[] = [
+    {
+      id: '1',
+      fieldId: '1',
+      fieldName: '北区小麦田',
+      date: new Date(new Date().setDate(new Date().getDate() - 3)),
+      activity: '病虫害检查',
+      notes: '发现少量蚜虫,已喷施防治',
+      images: [
+        'assets/images/wheat-pest1.jpg',
+        'assets/images/wheat-pest2.jpg'
+      ]
+    },
+    {
+      id: '2',
+      fieldId: '2',
+      fieldName: '南区玉米地',
+      date: new Date(new Date().setDate(new Date().getDate() - 5)),
+      activity: '追肥',
+      notes: '施用复合肥20kg/亩'
+    }
+  ];
+
+  showFieldForm = false;
+  editingField: FarmField | null = null;
+  fieldForm: FormGroup;
+
+  constructor(
+    private fb: FormBuilder,
+    private alertCtrl: AlertController
+  ) {
+    this.fieldForm = this.fb.group({
+      name: ['', Validators.required],
+      area: ['', [Validators.required, Validators.min(0.1)]],
+      location: [''],
+      currentCrop: ['冬小麦', Validators.required],
+      soilType: ['粘壤土']
+    });
+  }
+
+  ngOnInit() {}
+
+  get totalArea(): number {
+    return this.fields.reduce((sum, field) => sum + field.area, 0);
+  }
+
+  get pendingTasks(): number {
+    return this.tasks.filter(t => !t.completed).length;
+  }
+
+  get recentTasks(): FarmTask[] {
+    return this.tasks
+      .filter(t => !t.completed)
+      .sort((a, b) => a.dueDate.getTime() - b.dueDate.getTime())
+      .slice(0, 3);
+  }
+
+  get recentRecords(): GrowthRecord[] {
+    return [...this.records]
+      .sort((a, b) => b.date.getTime() - a.date.getTime())
+      .slice(0, 4);
+  }
+
+  getCropImage(crop: string): string {
+    const cropImages: {[key: string]: string} = {
+      '冬小麦': 'assets/images/wheat-icon.png',
+      '春玉米': 'assets/images/corn-icon.png',
+      '水稻': 'assets/images/rice-icon.png',
+      '大豆': 'assets/images/soybean-icon.png'
+    };
+    return cropImages[crop] || 'assets/images/crop-default.png';
+  }
+
+  getStatusColor(status: string): string {
+    const statusColors: {[key: string]: string} = {
+      '需灌溉': 'primary',
+      '需施肥': 'warning',
+      '需防治': 'danger',
+      '正常': 'success'
+    };
+    return statusColors[status] || 'medium';
+  }
+
+  getTaskIcon(type: string): string {
+    const taskIcons: {[key: string]: string} = {
+      'irrigation': 'water',
+      'fertilization': 'nutrition',
+      'pestControl': 'bug',
+      'harvest': 'leaf'
+    };
+    return taskIcons[type] || 'alert-circle';
+  }
+
+  getTaskColor(type: string): string {
+    const taskColors: {[key: string]: string} = {
+      'irrigation': 'primary',
+      'fertilization': 'warning',
+      'pestControl': 'danger',
+      'harvest': 'success'
+    };
+    return taskColors[type] || 'medium';
+  }
+
+  toggleFieldForm() {
+    this.showFieldForm = !this.showFieldForm;
+    if (!this.showFieldForm) {
+      this.editingField = null;
+      this.fieldForm.reset({
+        currentCrop: '冬小麦',
+        soilType: '粘壤土'
+      });
+    }
+  }
+
+  editField(field: FarmField) {
+    this.editingField = field;
+    this.fieldForm.patchValue({
+      name: field.name,
+      area: field.area,
+      location: field.location,
+      currentCrop: field.currentCrop,
+      soilType: field.soilType
+    });
+    this.showFieldForm = true;
+  }
+
+  saveField() {
+    if (this.fieldForm.invalid) return;
+
+    const fieldData = this.fieldForm.value;
+    
+    if (this.editingField) {
+      // 更新现有农田
+      const index = this.fields.findIndex(f => f.id === this.editingField?.id);
+      if (index >= 0) {
+        this.fields[index] = {
+          ...this.fields[index],
+          ...fieldData
+        };
+      }
+    } else {
+      // 添加新农田
+      this.fields.push({
+        id: Date.now().toString(),
+        daysPlanted: 0,
+        status: '正常',
+        ...fieldData
+      });
+    }
+
+    this.cancelEdit();
+  }
+
+  cancelEdit() {
+    this.showFieldForm = false;
+    this.editingField = null;
+    this.fieldForm.reset({
+      currentCrop: '冬小麦',
+      soilType: '粘壤土'
+    });
+  }
+
+  async deleteField(fieldId: string) {
+    const alert = await this.alertCtrl.create({
+      header: '确认删除',
+      message: '确定要删除这个农田地块吗?相关记录也将被删除',
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel'
+        },
+        {
+          text: '删除',
+          handler: () => {
+            this.fields = this.fields.filter(f => f.id !== fieldId);
+            this.tasks = this.tasks.filter(t => t.fieldId !== fieldId);
+            this.records = this.records.filter(r => r.fieldId !== fieldId);
+          }
+        }
+      ]
+    });
+
+    await alert.present();
+  }
+
+  viewTaskDetail(task: FarmTask) {
+    console.log('查看任务详情:', task);
+    // 实际应导航到任务详情页
+  }
+}

+ 4 - 0
myapp/src/app/tabs/tabs-routing.module.ts

@@ -19,6 +19,10 @@ const routes: Routes = [
         path: 'tab3',
         loadChildren: () => import('../tab3/tab3.module').then(m => m.Tab3PageModule)
       },
+      {
+        path: 'tab4',
+        loadChildren: () => import('../tab4/tab4.module').then(m => m.Tab3PageModule)
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 6 - 1
myapp/src/app/tabs/tabs.page.html

@@ -12,9 +12,14 @@
     </ion-tab-button>
 
     <ion-tab-button tab="tab3" href="/tabs/tab3">
-      <ion-icon aria-hidden="true" name="square"></ion-icon>
+      <ion-icon aria-hidden="true" name="hexagon"></ion-icon>
       <ion-label>Tab 3</ion-label>
     </ion-tab-button>
+
+    <ion-tab-button tab="tab4" href="/tabs/tab4">
+      <ion-icon aria-hidden="true" name="square"></ion-icon>
+      <ion-label>Tab 4</ion-label>
+    </ion-tab-button>
   </ion-tab-bar>
 
 </ion-tabs>