Browse Source

提交代码1

pqy 3 months ago
parent
commit
b65bbca8df

+ 15 - 0
.hintrc

@@ -0,0 +1,15 @@
+{
+  "extends": [
+    "development"
+  ],
+  "hints": {
+    "compat-api/css": [
+      "default",
+      {
+        "ignore": [
+          "background-position: center"
+        ]
+      }
+    ]
+  }
+}

+ 5 - 0
src/app/app.component.scss

@@ -0,0 +1,5 @@
+.header-title {
+    font-family: "FangSong", serif; /* 使用仿宋体 */
+    font-weight: bold; /* 加粗 */
+    text-align: center; /* 居中 */
+  }

+ 3 - 2
src/app/app.component.ts

@@ -1,5 +1,6 @@
-import { Component } from '@angular/core';
-
+import { Component,EnvironmentInjector, inject } from '@angular/core';
+import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
 @Component({
   selector: 'app-root',
   templateUrl: 'app.component.html',

+ 3 - 11
src/app/tab1/tab1.page.html

@@ -1,17 +1,9 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
-    <ion-title>
-      Tab 1
-    </ion-title>
+    <ion-title class="header-title">窑忆</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">Tab 1</ion-title>
-    </ion-toolbar>
-  </ion-header>
-
-  <app-explore-container name="Tab 1 page"></app-explore-container>
+<ion-content [fullscreen]="true" style="--background: url('/assets/images/background.jpg') no-repeat center/cover;">
 </ion-content>
+

+ 5 - 0
src/app/tab1/tab1.page.scss

@@ -0,0 +1,5 @@
+.header-title {
+    font-family: "FangSong", serif; /* 使用仿宋体 */
+    font-weight: bold; /* 加粗 */
+    text-align: center; /* 居中 */
+  }

+ 33 - 2
src/app/tab1/tab1.page.ts

@@ -2,11 +2,42 @@ import { Component } from '@angular/core';
 
 @Component({
   selector: 'app-tab1',
-  templateUrl: 'tab1.page.html',
-  styleUrls: ['tab1.page.scss']
+  templateUrl: './tab1.page.html',
+  styleUrls: ['./tab1.page.scss'],
 })
 export class Tab1Page {
+  userQuery: string = ''; // 用户输入的文本
+  agentAnswer: string = ''; // 智能体的回答
+  recommendedQuestion: string = '吉州窑的典型纹饰是什么?'; // 每日推荐问题
 
   constructor() {}
 
+  // 处理用户输入变化
+  onInputChange(event: any) {
+    this.userQuery = event.target.value;
+  }
+
+  // 提交问题并获取答案
+  fetchAnswer() {
+    if (this.userQuery.trim() === '') {
+      this.agentAnswer = '请输入有效的问题!';
+      return;
+    }
+
+    // 模拟调用智能体接口
+    this.agentAnswer = `这是关于 "${this.userQuery}" 的回答。`;
+  }
+
+  // 启动语音识别
+  startVoiceRecognition() {
+    // 模拟语音识别逻辑
+    this.userQuery = '模拟语音输入内容';
+    this.fetchAnswer();
+  }
+
+  // 设置推荐问题为查询内容
+  setQuery(question: string) {
+    this.userQuery = question;
+    this.fetchAnswer();
+  }
 }

+ 60 - 12
src/app/tab2/tab2.page.html

@@ -1,17 +1,65 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
-    <ion-title>
-      Tab 2
-    </ion-title>
+    <ion-title class="header-title">窑忆</ion-title>
   </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>
-
-  <app-explore-container name="Tab 2 page"></app-explore-container>
-</ion-content>
+<ion-content [fullscreen]="true" style="--background: url('/assets/images/background.jpg') no-repeat center/cover;">
+  <!-- 左上角图标:控制左边栏 -->
+  <div class="icon top_left" (click)="toggleSidebar()">
+    <ion-icon [name]="isSidebarVisible ? 'chevron-back-outline' : 'menu-outline'"></ion-icon>
+  </div>
+  <!-- 左边栏 -->
+  <div class="left_sidebar" [ngClass]="{ hidden: !isSidebarVisible }">
+    <!-- 右上角图标:创建新对话 -->
+    <div class="icon top_right" (click)="createNewChat()">
+    <ion-icon name="add-circle-outline"></ion-icon>
+  </div>
+    <div class="sidebar_box">
+    <!-- 左边栏内容 -->
+      <div class="left_sidebar_content" *ngIf="isSidebarVisible">
+        <p>这里是左边栏内容</p>
+      </div>
+    </div>
+    <!-- 导出当前对话 -->
+      <div class="transparent_box">
+        <!-- 左侧图标 -->
+        <div class="export_icon">
+          <ion-icon name="download-outline"></ion-icon>
+        </div>
+        <!-- 右侧文字 -->
+        <div class="export_text">
+          导出当前对话
+        </div>
+      </div>
+  </div>
+  <!-- 右侧对话区域 -->
+  <div class="chat_area" [ngStyle]="{'margin-left': isSidebarVisible ? '30%' : '0'}">
+    <!-- 对话内容显示框 -->
+    <div class="chat-container">
+      <div *ngFor="let message of chatMessages" class="message-container" [ngClass]="{'user-message': message.sender === 'user', 'other-message': message.sender === 'other'}">
+        <!-- 用户消息内容 -->
+        <div class="message-bubble">
+          {{ message.text }}
+        </div>
+        <!-- 用户头像 -->
+        <div *ngIf="message.sender === 'user'" class="avatar-container">
+          <img src="/assets/images/user.jpg" class="avatar" alt="用户头像">
+        </div>
+      </div>
+    </div>
+    <!-- 问题输入框 -->
+    <div class="input_box">
+      <!-- 语音输入图标 -->
+      <ion-button (click)="startSpeechRecognition()" class="voice_button">
+        <ion-icon name="mic-outline"></ion-icon>
+      </ion-button>
+      <!-- 输入框 -->
+      <ion-input [(ngModel)]="userMessage" placeholder="输入问题..." clearInput></ion-input>
+      <!-- 发送按钮 -->
+      <ion-button (click)="sendMessage()" class="send_button">
+        <ion-icon name="arrow-forward-circle-outline"></ion-icon>
+      </ion-button>
+    </div>
+  </div>
+</ion-content>

+ 209 - 0
src/app/tab2/tab2.page.scss

@@ -0,0 +1,209 @@
+.header-title {
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  font-weight: bold; /* 加粗 */
+  text-align: center; /* 居中 */
+}
+/* 左边栏样式 */
+.left_sidebar {
+  width: 30%;
+  height: 100%;
+  background-color: #f0f0f0;
+  border-right: 1px solid #ccc;
+  position: absolute;
+  top: 0;
+  left: 0;
+  transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out; /* 动画效果 */
+}
+/* 左边栏隐藏时样式 */
+.left_sidebar.hidden {
+  transform: translateX(-100%); /* 左移隐藏 */
+  opacity: 0; /* 渐隐效果 */
+}
+/* 图标样式 */
+.icon {
+  position: absolute; /* 图标相对于窗口位置 */
+  font-size: calc(2vw + 10px);
+  color: gray;
+  cursor: pointer;
+  padding: 1vw; /* 动态调整内边距 */
+  background-color: transparent;
+  border-radius: 10%;
+  z-index: 100; /* 确保图标显示在最上层 */
+}
+/* 左上角图标 */
+.top_left {
+  top: calc(7vh); /* 距离页面顶部2% */
+  left: calc(3vw); /* 距离页面左侧2% */
+}
+/* 右上角图标 */
+.top_right {
+  top: calc(7vh); /* 距离页面顶部2% */
+  left: calc(20vw); /* 距离页面右侧10% */
+}
+/* 白色盒子样式 */
+.sidebar_box {
+  background-color: #ffffff; /* 盒子背景为纯白 */
+  margin: 5px; /* 盒子内部与边栏之间的间距 */
+  padding: 2px; /* 内边距增加视觉空间 */
+  border-radius: 10px; /* 圆角 */
+  box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; /* 轻微阴影增强视觉层次感 */
+  height: calc(75%); /* 减去上下间距的高度 */
+  margin-top: 100px; /* 盒子与顶部的距离 */
+  overflow-y: scroll; /* 滚动支持 */
+}
+/* 左边栏内容样式 */
+.left_sidebar_content {
+  font-size: 16px;
+  color: #333; /* 深灰色字体 */
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  line-height: 1.5; /* 增加行高,提升可读性 */
+}
+/* 新增的透明盒子 */
+.transparent_box {
+  display: flex;
+  align-items: center;
+  background-color: transparent;
+  margin-top: 10px;
+  margin: 5px; /* 盒子内部与边栏之间的间距 */
+  padding: 10px;
+  border-radius: 10px;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+}
+.transparent_box:hover {
+  background-color: rgba(0, 0, 0, 0.1);
+}
+/* 左侧图标样式 */
+.export_icon {
+  margin-right: 10px;
+  font-size: calc(2vw + 10px);
+  color: gray;
+}
+/* 右侧文字样式 */
+.export_text {
+  color: gray;
+  font-size: 9px;
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  font-weight: bold;
+}
+/* 右侧对话区域 */
+.chat_area {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  transition: margin-left 0.3s ease; /* 动画过渡 */
+}
+/* 对话内容显示框 */
+.chat-container{
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;  /* 默认左对齐 */
+  flex-grow: 1;
+  overflow-y: auto;
+  margin-bottom: 10px;
+  background-color: rgba(249, 249, 249, 0.7); 
+  padding: 10px;
+  height: calc(80% - 15px); /* 让它占据大部分空间 */
+}
+/* 单条消息容器 */
+.message-container {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;  /* 使内容右对齐,头像和气泡分别在左右 */
+  margin: 5px;
+  width: 100%;  /* 占满宽度 */
+}
+/* 消息气泡 */
+.message-bubble {
+  max-width: 80%;
+  padding: 10px;
+  border-radius: 20px;
+  font-size: 16px;
+  line-height: 1.4;
+  word-wrap: break-word;
+  white-space: pre-line; /* 保留换行 */
+  display: inline-block;
+  background: url('/assets/images/bubble-background.png') no-repeat center/cover;
+  color: white;
+  margin-right: 5px; /* 留出空间给头像 */
+  border-radius: 20px 20px 0 20px;  /* 气泡形状 */
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  
+  /* 添加阴影效果 */
+  box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.2), /* 外阴影 */
+              inset -2px -2px 5px rgba(255, 255, 255, 0.5), /* 内阴影高光 */
+              inset 2px 2px 5px rgba(0, 0, 0, 0.1); /* 内阴影暗部 */
+}
+
+/* 用户消息右对齐 */
+.user-message {
+  flex-direction: row;  /* 保证头像和气泡从左到右排列 */
+}
+/* 头像容器 */
+.avatar-container {
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
+/* 头像样式 */
+.avatar {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;  /* 圆形头像 */
+  object-fit: cover;
+}
+/* 输入框盒子的样式 */
+.input_box {
+  display: flex;
+  align-items: center;           /* 垂直居中对齐 */
+  justify-content: center; 
+  justify-content: space-between; /* 左右对齐 */
+  width: 100%;                   /* 让输入框区域宽度充满父容器 */
+  padding: 5px;                 /* 内边距 */
+  margin-bottom: 10px;           /* 距离底部 5px */
+  background: url('/assets/images/button-background2.png') no-repeat center/cover;
+  border-radius: 30px;            /* 圆角 */
+  box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 12px; /* 阴影效果 */
+  position: relative;
+}
+/* 语音输入按钮 */
+.voice_button {
+  color: gray;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: none;  /* 去掉默认边框 */
+  --background: transparent;
+  cursor: pointer;
+  margin-right: 0px; /* 与输入框之间的小间隙 */
+}
+/* 输入框样式 */
+ion-input {
+  flex-grow: 1;  /* 使输入框占据剩余空间 */
+  max-width: calc(100%); /* 设置输入框的最大宽度,留出空间给发送按钮 */
+  --padding-start: 10px;
+  --padding-end: 10px;
+  --border-radius: 30px;
+  --background: #f9f9f9;
+  box-sizing: border-box;
+  font-family: "FangSong", serif;
+  font-weight: bold;
+  margin-right: 0px; /* 确保输入框与发送按钮之间有小间隙 */
+}
+/* 输入框在获得焦点时的样式 */
+ion-input:focus {
+  --background: #fff;  /* 获取焦点时背景变为白色 */
+  --box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);  /* 聚焦时显示阴影 */
+}
+/* 发送按钮 */
+.send_button{
+  color: gray;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  --background: transparent;
+  border: none;  /* 去掉默认边框 */
+  cursor: pointer;
+  margin-left: 0px; /* 与输入框之间的小间隙 */
+}

+ 58 - 4
src/app/tab2/tab2.page.ts

@@ -2,11 +2,65 @@ import { Component } from '@angular/core';
 
 @Component({
   selector: 'app-tab2',
-  templateUrl: 'tab2.page.html',
-  styleUrls: ['tab2.page.scss']
+  templateUrl: './tab2.page.html',
+  styleUrls: ['./tab2.page.scss'],
 })
 export class Tab2Page {
-
+  isSidebarVisible: boolean = true; // 左边栏显示状态
+  chatMessages: { text: string, sender: string }[] = [];  // 存储所有聊天消息,包含文本和发送者
+  userMessage: string = '';  // 用户输入的消息,初始化为空字符串
   constructor() {}
-
+  // 切换左边栏显示和隐藏
+  toggleSidebar() {
+    this.isSidebarVisible = !this.isSidebarVisible;
+    console.log(`左边栏 ${this.isSidebarVisible ? '显示' : '隐藏'}`);
+  }
+  // 创建新对话
+  createNewChat() {
+    console.log('创建新对话');
+    // 实现新对话逻辑
+  }
+  // 导出当前对话
+  exportConversation() {
+    console.log('导出当前对话');
+  }
+  // 发送消息
+  sendMessage() {
+    if (this.userMessage.trim()) {  // 如果输入的消息不为空
+      console.log('发送消息:', this.userMessage);
+      this.chatMessages.push({ text: this.userMessage, sender: 'user' });
+      this.userMessage = '';  // 清空输入框
+    }
+  }
+  // 开始语音识别
+  startSpeechRecognition() {
+    // 检查浏览器是否支持 SpeechRecognition
+    if (!('webkitSpeechRecognition' in window)) {
+      alert('抱歉,您的浏览器不支持语音输入功能');
+      return;
+    }
+    const recognition = new (window as any).webkitSpeechRecognition();
+    recognition.lang = 'zh-CN';  // 设置语言为中文
+    recognition.interimResults = true; // 支持实时识别结果
+    let finalTranscript = ''; // 用于存储最终结果
+    recognition.start();
+    recognition.onresult = (event: any) => {
+      let interimTranscript = '';
+      for (let i = event.resultIndex; i < event.results.length; i++) {
+        if (event.results[i].isFinal) {
+          // 如果结果是最终结果,则存储到 finalTranscript 中
+          finalTranscript += event.results[i][0].transcript;
+        } else {
+          // 如果是临时结果,存储到 interimTranscript 中
+          interimTranscript += event.results[i][0].transcript;
+        }
+        console.log('识别结果:', interimTranscript);
+      }
+      this.userMessage = `${finalTranscript}${interimTranscript}`.trim();
+    };
+    recognition.onerror = (event: any) => {
+      console.error('语音识别错误:', event.error);
+      alert('语音识别失败,请重试!');
+    };
+  }
 }

+ 56 - 11
src/app/tab3/tab3.page.html

@@ -1,17 +1,62 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
-    <ion-title>
-      Tab 3
-    </ion-title>
+    <ion-title class="header-title">窑忆</ion-title>
   </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>
-
-  <app-explore-container name="Tab 3 page"></app-explore-container>
+<ion-content [fullscreen]="true" style="--background: url('/assets/images/background.jpg') no-repeat center/cover;">
+  <div class="image-container">
+    <!-- 背景框 -->
+    <div class="background-frame">
+      <!-- 图片显示区域 -->
+      <img [src]="imageSrc" alt="Selected Image" class="image" *ngIf="!isCameraMode && imageSrc" />
+      <!-- 视频流显示 -->
+      <video #video *ngIf="isCameraMode && !imageCaptured && cameraAvailable" autoplay muted></video>
+      <!-- 占位文本 -->
+      <p class="placeholder-text" *ngIf="!imageSrc && !isCameraMode">No Image Selected</p>
+      <p class="placeholder-text" *ngIf="isCameraMode && (!cameraAvailable || imageCaptured)">Camera not available</p>
+    </div>
+    <!-- 切换图标 -->
+    <ion-button fill="clear" class="toggle-button" (click)="toggleMode()">
+      <ion-icon [name]="isCameraMode ? 'image' : 'camera'"></ion-icon>
+    </ion-button>
+  </div>
+  <!-- 上传图片按钮 -->
+  <div *ngIf="!isCameraMode" class="upload-container">
+    <ion-button class="primary-button" (click)="selectImage()">上传图片</ion-button>
+    <ion-button class="secondary-button" (click)="startDetection()">开始检测</ion-button>
+    <input type="file" hidden #fileInput (change)="onFileSelected($event)" />
+  </div>
+  <!-- 调用摄像头按钮 -->
+  <div *ngIf="isCameraMode" class="camera-container">
+    <ion-button class="primary-button" (click)="startCamera()">打开摄像头</ion-button>
+    <ion-button class="secondary-button" (click)="startDetection()">开始检测</ion-button>
+  </div>
+  <!-- Canvas 用于捕获图像 -->
+  <canvas #canvas hidden></canvas>
+  <!-- 分隔线 -->
+  <hr class="divider" />
+  <!-- 动态填充表格 -->
+  <div class="table-container">
+    <table>
+      <thead>
+        <tr>
+          <th>序号</th>
+          <th>识别结果</th>
+          <th>识别置信度</th>
+          <th>详情</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr *ngFor="let item of recognitionResults; let i = index">
+          <td>{{ i + 1 }}</td>
+          <td>{{ item.result }}</td>
+          <td>{{ item.confidence }}</td>
+          <td>
+            <ion-button size="small" fill="outline" (click)="viewDetails(item)">查看</ion-button>
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
 </ion-content>

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

@@ -0,0 +1,146 @@
+.header-title {
+    font-family: "FangSong", serif; /* 使用仿宋体 */
+    font-weight: bold; /* 加粗 */
+    text-align: center; /* 居中 */
+  }
+.image-container {
+  position: relative;
+  width: 100%;
+  height: 50%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  border-radius: 10px;
+  overflow: hidden;
+  margin-top: 0px;
+  background: url('/assets/images/recognition-background.png') no-repeat center/cover;
+}
+.background-frame {
+  position: relative;
+  width: 81%; /* 内容框宽度 */
+  height: 93%; /* 内容框高度 */
+  background: rgb(196, 191, 191 ,0.9); /* 半透明灰色背景 */
+  border-radius: 10px; /* 圆角与外框一致 */
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  overflow: hidden; /* 确保内容不会溢出 */
+}
+.placeholder-text {
+  color: white;
+  font-size: 16px;
+  text-align: center;
+}
+.image {
+  width: 100%; /* 图片自适应内容框 */
+  height: 100%;
+  object-fit: cover; /* 确保图片完整覆盖框 */
+  border-radius: 10px; /* 圆角与框一致 */
+}
+video {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  border-radius: 10px;
+}
+.toggle-button {
+  position: absolute;
+  top: 20px;
+  right: 40px;
+  z-index: 10;
+  color: black;
+}
+.button-group {
+  display: flex;
+  flex-direction: column; /* 垂直排列 */
+  justify-content: center; /* 垂直居中 */
+  align-items: center; /* 水平居中 */
+  height: 100vh; /* 页面高度,按钮垂直居中 */
+}
+.upload-container {
+  display: flex;
+  justify-content: space-between; /* 按钮之间均匀分布 */
+  width: 100%; /* 按钮组整体宽度占页面100% */
+  margin-bottom: 10px; /* 按钮组之间的间距 */
+  margin-top: 10px;
+  margin-right: 10px;
+}
+.camera-container {
+  display: flex;
+  justify-content: space-between; /* 按钮之间均匀分布 */
+  width: 100%; /* 按钮组整体宽度占页面80% */
+  margin-bottom: 10px; /* 按钮组之间的间距 */
+  margin-top: 10px;
+  margin-right: 10px;
+}
+.primary-button {
+  --background: none;
+  flex: 0 0 42.5%;
+  height: 48px;
+  font-size: 16px;
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  font-weight: bold; /* 加粗 */
+  text-align: center;
+  border-radius: 10px;
+  color: black;
+  background: url('/assets/images/button-background1.png') no-repeat center/cover;
+  margin-left: 15px;
+  margin-right: 15px;
+  box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 12px; /* 阴影效果 */
+}
+.secondary-button {
+  --background: none;
+  flex: 0 0 42.5%;;
+  height: 48px;
+  font-size: 16px;
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  font-weight: bold; /* 加粗 */
+  text-align: center;
+  border-radius: 10px;
+  color: black;
+  background: url('/assets/images/button-background1.png') no-repeat center/cover;
+  margin-left: 15px;
+  margin-right: 15px;
+  box-shadow: rgba(0, 0, 0, 0.2) 0px 4px 12px; /* 阴影效果 */
+}
+.divider {
+  border: none; /* 去掉默认边框 */
+  height: 40px; /* 分割线高度 */
+  width: calc 100%; /* 总宽度减去左右空出20px */
+  margin: 16px auto; /* 自动居中 */
+  background: url('/assets/images/divider.png') repeat-x center; /* 设置图片作为分割线 */
+  background-size: contain; /* 确保图片在水平方向完整显示 */
+}
+.table-container {
+  width: 90%;
+  margin: 16px auto;
+  max-height: 500px; /* 限制表格高度 */
+  overflow-y: auto; /* 添加垂直滚动条 */
+  border: 1px solid #ccc; /* 添加边框方便视觉分割 */
+  border-radius: 10px; /* 圆角 */
+  background: url('/assets/images/table-background.png') no-repeat center/cover;
+}
+table {
+  width: 100%;
+  border-collapse: collapse;
+  font-family: "FangSong", serif; /* 使用仿宋体 */
+  font-weight: bold; /* 加粗 */
+  text-align: center; /* 居中 */
+}
+thead {
+  position: sticky; /* 表头固定 */
+  top: 0;
+  background-color: #f4f4f4;
+  z-index: 1;
+}
+th,
+td {
+  padding: 12px;
+  border: 1px solid #ccc;
+}
+th {
+  font-weight: bold;
+}
+tbody tr:hover {
+  background-color: #f9f9f9;
+}

+ 0 - 3
src/app/tab3/tab3.page.spec.ts

@@ -8,18 +8,15 @@ import { Tab3Page } from './tab3.page';
 describe('Tab3Page', () => {
   let component: Tab3Page;
   let fixture: ComponentFixture<Tab3Page>;
-
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [Tab3Page],
       imports: [IonicModule.forRoot(), ExploreContainerComponentModule]
     }).compileComponents();
-
     fixture = TestBed.createComponent(Tab3Page);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });
-
   it('should create', () => {
     expect(component).toBeTruthy();
   });

+ 126 - 6
src/app/tab3/tab3.page.ts

@@ -1,12 +1,132 @@
-import { Component } from '@angular/core';
+import { Component, ElementRef, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core';
 
 @Component({
   selector: 'app-tab3',
   templateUrl: 'tab3.page.html',
   styleUrls: ['tab3.page.scss']
 })
-export class Tab3Page {
-
-  constructor() {}
-
-}
+export class Tab3Page implements AfterViewInit{
+  @ViewChild('video',{ static: false }) videoElement!: ElementRef<HTMLVideoElement>;
+  @ViewChild('canvas',{ static: false }) canvasElement!: ElementRef<HTMLCanvasElement>;
+  @ViewChild('fileInput',{ static: false }) fileInput!: ElementRef<HTMLInputElement>;
+  isCameraMode: boolean = false; // 是否为摄像头模式
+  imageCaptured: boolean = false; // 是否已捕获图像
+  cameraAvailable: boolean = false; // 摄像头是否可用
+  imageSrc: string | null = null; // 保存图片数据
+  videoStream: MediaStream | null = null; // 保存视频流
+  showAlert: boolean = false; // 是否显示弹窗
+  recognitionResults: { result: string; confidence: string; details: string }[] = []; // 动态识别结果
+  constructor() {
+    this.checkCameraAvailability();
+  }
+  checkCameraAvailability() {
+    navigator.mediaDevices
+      .getUserMedia({ video: true })
+      .then(() => {
+        this.cameraAvailable = true; // 摄像头可用
+      })
+      .catch(() => {
+        this.cameraAvailable = false; // 摄像头不可用
+      });
+  }
+  // 确保视图加载完成后 ViewChild 初始化
+  ngAfterViewInit() {
+    console.log('Video Element:', this.videoElement);
+    console.log('Canvas Element:', this.canvasElement);
+    console.log('File Input Element:', this.fileInput);
+  }
+  // 切换模式
+  toggleMode() {
+    this.isCameraMode = !this.isCameraMode;
+    this.imageSrc = null; // 切换模式时清除图片
+    if (!this.isCameraMode) {
+      this.stopCamera();
+    }
+  }
+  // 选择图片
+  selectImage() {
+    if (this.fileInput) {
+      this.fileInput.nativeElement.click();
+    } else {
+      console.error('File input is not available');
+    }
+  }
+  // 处理选择的图片
+  onFileSelected(event: any) {
+    const file = event.target.files[0];
+    if (file) {
+      const reader = new FileReader();
+      reader.onload = (e: any) => {
+        this.imageSrc = e.target.result;
+      };
+      reader.readAsDataURL(file);
+    }
+  }
+  // 启动摄像头
+  async startCamera() {
+    try {
+      this.isCameraMode = true;
+      this.imageCaptured = false;
+      this.videoStream = await navigator.mediaDevices.getUserMedia({ video: true });
+      const video = this.videoElement.nativeElement;
+      video.srcObject = this.videoStream;
+      video.play();
+      // 自动捕获图像逻辑:5秒后捕获最后一帧
+      setTimeout(() => {
+        if (this.isCameraMode && this.videoStream) {
+          this.captureImage();
+        }
+      }, 5000);
+    } catch (error) {
+      console.error('Error accessing camera:', error);
+    }
+  }
+  // 停止摄像头
+  stopCamera() {
+    if (this.videoStream) {
+      const tracks = this.videoStream.getTracks();
+      tracks.forEach(track => track.stop());
+      this.videoStream = null;
+    }
+    this.isCameraMode = false;
+  }
+  // 捕获图像
+  captureImage() {
+    if (!this.videoElement || !this.canvasElement) {
+      console.error('Video or Canvas element is not available');
+      return;
+    }
+    const video = this.videoElement.nativeElement;
+    const canvas = this.canvasElement.nativeElement;
+    const context = canvas.getContext('2d');
+    if (context) {
+      // 设置 Canvas 大小与视频相同
+      canvas.width = video.videoWidth;
+      canvas.height = video.videoHeight;
+      // 绘制当前视频帧到 Canvas
+      context.drawImage(video, 0, 0, canvas.width, canvas.height);
+      // 获取图片数据并保存到 imageSrc
+      this.imageSrc = canvas.toDataURL('image/png');
+      this.imageCaptured = true;
+      // 停止摄像头
+      this.stopCamera();
+    }
+  }
+  startDetection() {
+    console.log('开始检测事件触发');
+    // 模拟数据
+    const newResult = {
+      result: '识别结果 ' + (this.recognitionResults.length + 1),
+      confidence: (Math.random() * 100).toFixed(2) + '%',
+      details: '详情内容 ' + (this.recognitionResults.length + 1),
+    };
+    // 将数据添加到识别结果中
+    this.recognitionResults.push(newResult);
+  }
+  // 查看详情事件
+  viewDetails(item: { result: string; confidence: string; details: string }) {
+    console.log('查看详情:', item);
+    // 在此实现查看详情的逻辑
+    alert(`结果: ${item.result}\n置信度: ${item.confidence}\n详情: ${item.details}`);
+  }
+}

+ 16 - 0
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 Tab4PageRoutingModule {}

+ 20 - 0
src/app/tab4/tab4.module.ts

@@ -0,0 +1,20 @@
+import { IonicModule } from '@ionic/angular';
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { Tab4Page } from './tab4.page';
+import { ExploreContainerComponentModule } from '../explore-container/explore-container.module';
+
+import { Tab4PageRoutingModule } from './tab4-routing.module';
+
+@NgModule({
+  imports: [
+    IonicModule,
+    CommonModule,
+    FormsModule,
+    ExploreContainerComponentModule,
+    Tab4PageRoutingModule
+  ],
+  declarations: [Tab4Page]
+})
+export class Tab4PageModule {}

+ 27 - 0
src/app/tab4/tab4.page.html

@@ -0,0 +1,27 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title class="header-title">窑忆</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true" style="--background: url('/assets/images/background.jpg') no-repeat center/cover;">
+  <div class="box"></div>
+  <div class="user">
+    <div class="face">
+      <img src="assets/images/user.jpg" class="img" alt="User Avatar">
+    </div>
+    <div class="username">
+      pqyyyyy
+    </div>
+    <div class="id">
+      ID:14945
+    </div>
+  </div>
+  <ion-list>
+    <ion-item *ngFor="let item of list" (click)="onItemClick(item)" lines="none">
+      <ion-icon [name]="item.icon" slot="start" class="setfont"></ion-icon>
+      <ion-label>{{ item.title }}</ion-label>
+      <ion-icon name="chevron-forward" slot="end"></ion-icon>
+    </ion-item>
+  </ion-list>
+</ion-content>

+ 72 - 0
src/app/tab4/tab4.page.scss

@@ -0,0 +1,72 @@
+.header-title {
+    font-family: "FangSong", serif; /* 使用仿宋体 */
+    font-weight: bold; /* 加粗 */
+    text-align: center; /* 居中 */
+  } 
+  .box {
+    position: absolute;
+    width: 100%;
+    height: 750px;
+    top: -400px;
+    z-index: -1;
+    border-radius: 50%;
+    background:
+      radial-gradient(circle, rgba(255, 255, 255, 0.8) 60%, rgba(255, 255, 255, 0) 100%) ,
+      url('/assets/images/1.jpg') no-repeat center/cover;
+  }
+  
+  .user {
+    height: 300px;
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    margin: 10px;
+    margin-bottom: 100px;
+  }
+  
+  .face {
+    position: relative;
+    width: 120px;
+    height: 120px;
+    background: url('/assets/images/2.jpg') no-repeat center/cover;
+    border-radius: 50%;
+    margin: 0px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    overflow: hidden;
+  }
+  
+  .username, .id {
+    color: white;
+    text-align: center;
+  }
+  
+  .img {
+    width: 80px; /* 头像大小 */
+    height: 80px;
+    object-fit: cover;
+    border-radius: 50%;
+  }
+  
+  ion-list {
+    margin-top: 20px;
+    font-family: "FangSong", serif; /* 使用仿宋体 */
+    font-weight: bold; /* 加粗 */
+    text-align: center; /* 居中 */
+  }
+  
+  ion-item {
+    --background: white;
+    --color: black;
+    padding: 10px;
+  }
+  
+  ion-icon.setfont {
+    color: gray;
+    font-size: 1.5rem;
+    font-family: "FangSong", serif; /* 使用仿宋体 */
+    font-weight: bold; /* 加粗 */
+  }
+  

+ 26 - 0
src/app/tab4/tab4.page.spec.ts

@@ -0,0 +1,26 @@
+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('Tab4Page', () => {
+  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();
+  });
+});

+ 21 - 0
src/app/tab4/tab4.page.ts

@@ -0,0 +1,21 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-tab4',
+  templateUrl: 'tab4.page.html',
+  styleUrls: ['tab4.page.scss']
+})
+export class Tab4Page {
+  list = [
+    { id: '1', icon: 'time-outline', title: '我的陶记' },
+    { id: '2', icon: 'chatbubbles-outline', title: '意见反馈' },
+    { id: '3', icon: 'settings-outline', title: '设置' },
+    { id: '4', icon: 'information-circle-outline', title: '关于我们' },
+  ];
+  onItemClick(item: any) {
+    console.log('Clicked item:', item);
+    // Handle the click action for the item
+  }
+  constructor() {}
+
+}

+ 4 - 0
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.Tab4PageModule)
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 11 - 8
src/app/tabs/tabs.page.html

@@ -1,20 +1,23 @@
 <ion-tabs>
-
   <ion-tab-bar slot="bottom">
     <ion-tab-button tab="tab1" href="/tabs/tab1">
-      <ion-icon aria-hidden="true" name="triangle"></ion-icon>
-      <ion-label>Tab 1</ion-label>
+      <ion-icon 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="ellipse"></ion-icon>
-      <ion-label>Tab 2</ion-label>
+      <ion-icon name="sparkles-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="square"></ion-icon>
-      <ion-label>Tab 3</ion-label>
+      <ion-icon name="eye-outline"></ion-icon>
+      <ion-label>陶瓷识别</ion-label>
     </ion-tab-button>
-  </ion-tab-bar>
 
+  <ion-tab-button tab="tab4" href="/tabs/tab4">
+      <ion-icon name="person-outline"></ion-icon>
+      <ion-label>我的</ion-label>
+    </ion-tab-button>
+  </ion-tab-bar>
 </ion-tabs>

BIN
src/assets/images/1.jpg


BIN
src/assets/images/2.jpg


BIN
src/assets/images/background.jpg


BIN
src/assets/images/bubble-background.png


BIN
src/assets/images/button-background1.png


BIN
src/assets/images/button-background2(1).png


BIN
src/assets/images/button-background2.png


BIN
src/assets/images/divider.png


BIN
src/assets/images/recognition-background.png


BIN
src/assets/images/table-background.png


BIN
src/assets/images/user.jpg