GZP hace 4 meses
padre
commit
5c0511ff98

+ 23 - 16
README.md

@@ -8,43 +8,44 @@
 - 项目名称:
   - Luck-16th
 - 项目Slogan:
-  - 
+  - Efficiency at Your Fingertips, Building Success Together
 - 项目简介:
-  - 
+  - Luck-16th工地公司管理App是一款专为建筑工地公司设计的全方位管理工具。无论您是项目经理、工程师还是施工队成员,Luck-16th都能帮助您实现工地管理的高效运作。通过该App,您可以轻松查看和更新项目进度、分配任务、跟踪资源使用情况、管理人员和工人的日程安排,甚至进行实时沟通和协作。Luck-16th的直观界面和强大功能使得工地管理变得更加简单和高效,帮助您提升工作效率,减少成本,确保项目按时交付并保持安全性。无论您身在何处,Luck-16th都能让您随时随地管理您的工地项目。赶快体验Luck-16th工地公司管理App,让您的工作变得更加轻松便捷!
 ## 政策背景
-
+- Luck-16th工地公司管理App的诞生源于对建筑工地管理现状的深刻理解和对行业需求的洞察。随着建筑行业的快速发展和工地项目规模的不断扩大,传统的工地管理方式已经无法满足日益复杂的管理需求。项目经理、工程师和施工队成员面临着诸多挑战,如项目进度控制、资源管理、人员协调等问题。为了解决这些问题,Luck-16th团队汇集了一群技术和建筑行业专业人士,共同开发了Luck-16th工地公司管理App。
+Luck-16th旨在为建筑工地公司提供一站式的全方位管理解决方案,通过智能化技术和创新功能,帮助用户实现工地管理的高效运作。该App整合了AI聊天、员工打卡、项目管理等多项功能,为用户提供便捷的工作流程和实时数据支持,助力工地项目顺利进行并保持安全高效。Luck-16th的诞生代表着对建筑工地管理方式的革新和进步,旨在成为建筑行业的领先管理工具,推动行业向更高水平发展。
 ## 行业痛点与解决方案
 
+### 行业痛点:
+当前建筑工地管理存在诸多问题,包括项目进度控制困难、资源分配不均、人员协调不畅等,导致工地管理效率低下、成本增加、项目交付延迟等不利后果。
 
-## 背景现状
+### 解决方案:
+Luck-16th工地公司管理App通过智能化技术和创新功能,提供全方位的管理工具,包括AI聊天、员工打卡、项目管理等功能,帮助用户实现工地管理的高效运作,提升工作效率、降低成本,确保项目按时交付并保持安全性。
 
+## 背景现状
 
 ### 用户分析:相关者
-
+Luck-16th的主要用户包括建筑工地项目经理、工程师、施工队成员等,他们需要一个全面的管理工具来协助他们完成工地管理任务。
 
 ### 技术模型
-
+Luck-16th采用先进的云计算和人工智能技术,实现实时数据处理和智能化管理,为用户提供便捷的工作流程和支持。
 
 ## 商业模型
 
 ### 1. 收入来源
-
+Luck-16th的主要收入来源包括订阅费用、定制化服务费用以及广告推广收入。
 
 ### 2. 成本结构
-
+Luck-16th的成本主要包括技术开发成本、运营维护成本和市场推广成本。
 
 ### 3. 用户增长策略
-
+Luck-16th将通过市场推广、合作伙伴推广和口碑传播等方式来吸引更多用户,扩大用户基数。
 
 ### 4. 用户留存和活跃策略
-
-
+Luck-16th将持续改进产品体验,提升用户满意度,通过定期更新和个性化服务来保持用户的活跃度和忠诚度。
 
 ### 5. 持续发展和扩张策略
-
-
-
-### 融资策略
+Luck-16th将不断优化产品功能,拓展市场领域,寻求合作伙伴,以实现持续发展和扩张。
 
 ## 产品结构
 - 项目概况:显示当前公司正在进行的项目概况,包括项目名称、进度、预算等信息。
@@ -62,8 +63,14 @@
 
 ## 产品优势和特点
 
+- AI聊天功能:Luck-16th拥有智能AI聊天功能,可以为用户提供实时支持和解答问题。用户可以通过与AI聊天进行快速沟通,获取所需信息并解决问题,提高工作效率。
+
+- 员工打卡系统:Luck-16th内置员工打卡系统,员工可以通过App轻松进行签到和签退,实时记录工作时间,提高考勤管理的准确性和便捷性。
+
+- 项目管理工具:Luck-16th提供全面的项目管理功能,用户可以查看和更新项目进度、分配任务、跟踪资源使用情况,管理人员和工人的日程安排,确保项目按时交付并保持高效运作。
 
+- 智能提醒和通知:Luck-16th具备智能提醒和通知功能,及时提醒用户重要事项和任务,帮助用户合理安排时间和资源,确保工作顺利进行。
 
-## 竞品分析对比
+- 数据分析和报告:Luck-16th还提供数据分析和报告功能,用户可以通过App查看工地运营数据、员工表现等关键指标,帮助用户进行决策和优化管理策略。
 
 

+ 2 - 4
src/modules/contacts/add-frends/add-frends.page.html

@@ -24,15 +24,13 @@
 
 <div class="page-color">
 
-    <ion-item *ngIf="!ifSearch">
-      <!-- <ion-avatar slot="start"> -->
+    <!-- <ion-item *ngIf="!ifSearch">
         <ion-card (click)="goAiChatPage()">
           <img style="width: 100px;"src='assets/aichat.png'/>
           <ion-label style="text-align: center;">旅行小助手</ion-label>
         </ion-card>    
-    </ion-item>
+    </ion-item> -->
     <ion-item *ngIf="ifSearch">
-      <!-- <ion-avatar slot="start"> -->
         <ion-card >
           <img style="width: 100px;"src='{{search.userImg}}'/>
           <ion-label style="text-align: center;">{{search.username}}</ion-label>

+ 4 - 4
src/modules/contacts/contacts-routing.module.ts

@@ -7,10 +7,10 @@ const routes: Routes = [
     path: 'add-frends',
     loadChildren: () => import('./add-frends/add-frends.module').then( m => m.AddFrendsPageModule)
   },
-  // {
-  //   path: 'ai-chat',
-  //   loadChildren: () => import('./ai-chat/ai-chat.module').then( m => m.AiChatPageModule)
-  // },
+  {
+    path: 'ai-chat',
+    loadChildren: () => import('../homepage/ai-chat/ai-chat.module').then( m => m.AiChatPageModule)
+  },
   // {path: 'chat-page', loadChildren: () => import('./chat-page/chat-page.component').then(mod => mod.ChatPageComponent)},
 ];
 

+ 1 - 1
src/modules/contacts/friends/friends.page.html

@@ -24,7 +24,7 @@
   </div>
     <ion-item (click)="goAiChatPage()">
       <ion-avatar slot="start">
-        <img [src]="assets/aichat.png" alt="care Avatar">
+        <img src="../../../assets/aichat.png" alt="care Avatar">
       </ion-avatar>
       <ion-grid>
         <ion-row>

+ 2 - 1
src/modules/contacts/friends/friends.page.ts

@@ -86,7 +86,7 @@ export class FriendsPage implements OnInit {
     })
   }
   goAiChatPage(){
-    this.router.navigate(["..//ai-chat-page"],{
+    this.router.navigate(["./homepage/ai-chat"],{
     })
   }
   // public data = [
@@ -126,4 +126,5 @@ export class FriendsPage implements OnInit {
   toggleDropdown(){
     this.showDropdown=true
   }
+  
 }

+ 1 - 0
src/modules/function/boos/boos.page.scss

@@ -1,4 +1,5 @@
 .page-color{
     background: linear-gradient(220.55deg, #B7DCFF 0%, #ffffff 100%);
     height: 100vh;
+    overflow: auto;
 }

+ 1 - 0
src/modules/function/employer/employer.page.scss

@@ -1,6 +1,7 @@
 .page-color{
     background: linear-gradient(220.55deg, #B7DCFF 0%, #ffffff 100%);
     height: 100vh;
+    overflow: auto;
 }
 .sign-img{
     border-radius: 50%;

+ 17 - 0
src/modules/homepage/ai-chat/ai-chat-routing.module.ts

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

+ 20 - 0
src/modules/homepage/ai-chat/ai-chat.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { AiChatPageRoutingModule } from './ai-chat-routing.module';
+
+import { AiChatPage } from './ai-chat.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    AiChatPageRoutingModule
+  ],
+  declarations: [AiChatPage]
+})
+export class AiChatPageModule {}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 24 - 0
src/modules/homepage/ai-chat/ai-chat.page.html


+ 104 - 0
src/modules/homepage/ai-chat/ai-chat.page.scss

@@ -0,0 +1,104 @@
+/* ---历史消息--- */
+#service-list .mobile-page pre{
+    white-space: pre-wrap;
+    word-wrap: break-word;
+}
+.mobile-page{
+    margin-bottom: 2.5rem;
+}
+.mobile-page .admin-img, .mobile-page .user-img{
+ width: 45px;
+ height: 45px;
+}
+i.triangle-admin,i.triangle-user{
+ width: 0;
+     height: 0;
+     position: absolute;
+     top: 10px;
+ display: inline-block;
+     border-top: 10px solid transparent;
+     border-bottom: 10px solid transparent;
+}
+.mobile-page i.triangle-admin{
+ left: 4px;
+ border-right: 12px solid rgb(248, 248, 248);
+}
+.mobile-page i.triangle-user{
+ right: 4px;
+     border-left: 12px solid #9EEA6A;
+}
+.mobile-page .admin-group, .mobile-page .user-group{
+ padding: 6px;
+ display: flex;
+ display: -webkit-flex;
+}
+.mobile-page .admin-group{
+ justify-content: flex-start;
+ -webkit-justify-content: flex-start;
+}
+.mobile-page .user-group{
+ justify-content: flex-end;
+ -webkit-justify-content: flex-end;
+}
+.mobile-page .admin-reply, .mobile-page .user-reply{
+ display: inline-block;
+ padding: 13px;
+ border-radius: 4px;
+ background-color: #fff;
+ margin:0 15px 12px;
+ font-size: .8rem;
+ white-space: pre-wrap;
+}
+.mobile-page .admin-reply{
+ box-shadow: 0px 0px 2px #ddd;
+}
+.mobile-page .user-reply{
+ text-align: left;
+ background-color: #9EEA6A;
+ box-shadow: 0px 0px 2px #bbb;
+}
+.mobile-page .user-msg, .mobile-page .admin-msg{
+ width: 75%;
+ position: relative;
+}
+.mobile-page .user-msg{
+ text-align: right;
+}
+/*--- 消息输入框--- */
+.footer {
+    padding: .5rem;
+    position: fixed;
+    bottom: 60px;
+    left: 0;
+    right: 0;
+  }
+  .chat-container {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 10px;
+    background-color: #f5f5f5;
+  }
+  
+  .chat-input {
+    flex-grow: 1;
+    padding: 8px;
+    border: none;
+    border-radius: 5px;
+    font-size: 16px;
+    background-color: #fff;
+  }
+  
+  .send-button {
+    margin-left: 10px;
+    padding: 8px 16px;
+    border: none;
+    border-radius: 5px;
+    font-size: 16px;
+    color: #fff;
+    background-color: #007bff;
+    cursor: pointer;
+  }
+  
+  /* 可以根据需要自定义样式,例如调整颜色、边框等 */
+  

+ 17 - 0
src/modules/homepage/ai-chat/ai-chat.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { AiChatPage } from './ai-chat.page';
+
+describe('AiChatPage', () => {
+  let component: AiChatPage;
+  let fixture: ComponentFixture<AiChatPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AiChatPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 126 - 0
src/modules/homepage/ai-chat/ai-chat.page.ts

@@ -0,0 +1,126 @@
+import { Component,OnInit } from '@angular/core';
+import { TestChatCompletion, TestChatMessage,oldMessage } from './class-chat-completion';
+import {SharedService} from 'src/modules/user/service-user/Share.service'
+import {NavController } from '@ionic/angular';
+import * as Parse from "parse"
+(Parse as any).serverURL = "https://web2023.fmode.cn/parse"
+Parse.initialize("dev")
+
+
+async function historyMessage(senderId: string,receiverId:string,historyMessages:Array<oldMessage>=[]){
+  await findMessagesByUserName(receiverId,senderId,historyMessages,"assistant")
+  await findMessagesByUserName(senderId,receiverId,historyMessages,"user")
+  historyMessages.sort((a, b) => Number(a.createdAt) - Number(b.createdAt));
+}
+
+async function findMessagesByUserName(senderId: string,receiverId:string,historyMessages:Array<oldMessage>=[],role:string) {
+  const Gzpmessage = Parse.Object.extend('Gzpmessage');
+  const query = new Parse.Query(Gzpmessage);
+  query.equalTo("senderId", senderId);
+  query.equalTo("receiverId", receiverId);
+  try {
+    const messages = await query.find();
+    for (const message of messages) {
+      historyMessages.push({
+        role:role,
+        content:message.get("messageContent"),
+        createdAt:message.get("createdAt").getTime()
+      }) 
+    }
+  } catch (error) {
+    console.error("查询消息时出错:", error);
+  }
+  return historyMessage
+}
+
+export function sendToParse(value:string,senderId:string,receiverId:string){
+  const Gzpmessage = Parse.Object.extend('Gzpmessage');
+    const message = new Gzpmessage();
+    message.set('senderId', senderId);
+    message.set('receiverId', receiverId);
+    message.set('messageContent', value);
+    message.set('createdAt', new Date());
+    // 设置其他字段...
+
+    // 保存对象到数据库
+    message.save().then(
+      (result: any) => {
+        console.log('对话消息已保存到数据库:', result);
+      },
+      (error: any) => {
+        console.error('保存对话消息时出错:', error);
+      }
+    );
+}
+
+@Component({
+  selector: 'app-ai-chat',
+  templateUrl: './ai-chat.page.html',
+  styleUrls: ['./ai-chat.page.scss'],
+})
+export class AiChatPage implements OnInit {
+
+  back(){
+    this.navCtrl.back()
+  }
+
+  oldMessage:boolean=true;
+  title: string ='小助手';
+  userId: string = '';
+  userImg: string = ''
+  public userInput: string = '';
+  messageList: Array<TestChatMessage> = [];
+  historyMessages:Array<oldMessage>=[]
+  completion: TestChatCompletion;
+
+  constructor(private sharedService: SharedService,private navCtrl:NavController) {
+    this.messageList.push({
+      role:'assistant',
+      content:"您好,我是您的小助手,请问现在有什么可以帮到您的。",
+    }
+    )
+    this.completion = new TestChatCompletion(this.messageList,this.sharedService);
+    this.userId = this.sharedService.getUserId();
+    this.userImg = this.sharedService.getUserImg();
+    historyMessage(this.userId,'1',this.historyMessages)
+    // findMessagesByUserName('Aichat',this.userId,this.messageList,"assistant")
+    // findMessagesByUserName(this.userId,'Aichat',this.messageList,"user")
+  }
+  send(value: string) {
+    if (this.sharedService.pdlogin()){
+      this.messageList.push({
+            role: 'user',
+            content: value,
+          });
+      sendToParse(value,this.userId,"1")
+      this.completion.createCompletionByStream();
+    }
+    else{
+      if(value=='开始'){
+        this.messageList.push({
+          role:'assistant',
+          content:"请问",
+        }
+        ) 
+        this.sharedService.isLogin()
+      }
+      else{
+        this.messageList.push({
+          role:'user',
+          content:value,
+        }
+        )
+        this.messageList.push({
+          role:'assistant',
+          content:"对不起,您还没有登入,暂时无法使用此功能",
+        }
+        ) 
+      }    
+    }
+    this.userInput='';
+  }
+
+  ngOnInit() {
+  }
+
+}

+ 95 - 0
src/modules/homepage/ai-chat/class-chat-completion.ts

@@ -0,0 +1,95 @@
+import { sendToParse } from './ai-chat.page';
+import {SharedService} from 'src/modules/user/service-user/Share.service'
+
+export interface TestChatMessage{
+        role:string
+        content:string
+}
+export interface oldMessage{
+  role:string
+  content:string
+  createdAt:any
+}
+export class TestChatCompletion{
+  userId: string = '';
+    messageList:Array<TestChatMessage>
+    constructor(messageList:Array<TestChatMessage>,private sharedService: SharedService){
+      this.userId = this.sharedService.getUserId();
+      this.messageList = messageList
+    }
+  async createCompletionByStream() {
+
+    let token = localStorage.getItem("token");
+    let bodyJson = {
+      "token": `Bearer ${token}`,
+      "messages": this.messageList,
+      "model": "gpt-3.5-turbo",
+      "temperature": 0.5,
+      "presence_penalty": 0,
+      "frequency_penalty": 0,
+      "top_p": 1,
+      "stream":true
+    };
+  
+    let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+      "headers": {
+        "accept": "text/event-stream",
+        "sec-fetch-dest": "empty",
+        "sec-fetch-mode": "cors",
+        "sec-fetch-site": "same-site"
+      },
+      "referrer": "https://ai.fmode.cn/",
+      "referrerPolicy": "strict-origin-when-cross-origin",
+      "body": JSON.stringify(bodyJson),
+      "method": "POST",
+      "mode": "cors",
+      "credentials": "omit"
+    });
+    let messageAiReply = ""
+    let messageIndex = this.messageList.length
+    let reader = response.body?.getReader();
+    if (!reader) {
+      throw new Error("Failed to get the response reader.");
+    }
+  
+    let decoder = new TextDecoder();
+    let buffer = "";
+    while (true) {
+      let { done, value } = await reader.read();
+      if (done) {
+        break;
+      }
+  
+      buffer += decoder.decode(value);
+  
+      // Split the buffer by newlines to get individual messages
+      let messages = buffer.split("\n");
+      // Process each message
+      for (let i = 0; i < messages.length - 1; i++) {
+        let message = messages[i];
+        let dataText = message.replace("data:\ ","")
+        if(dataText.startsWith("{")){
+          try{
+            let dataJson = JSON.parse(dataText)
+            messageAiReply += dataJson?.choices?.[0]?.delta?.content || ""
+            this.messageList[messageIndex] = {
+              role:"assistant",
+              content:messageAiReply,
+            }
+          }catch(err){}
+        }
+        if(dataText.startsWith("[")){
+          this.messageList[messageIndex] = {
+            role:"assistant",
+            content:messageAiReply,
+          }
+          sendToParse(messageAiReply,'1',this.userId)
+          console.log(messageAiReply)
+          messageAiReply = ""
+          // const filteredMessages = this.messageList.filter(message => message.role == "assistant");
+        }
+        buffer = buffer.slice(message.length + 1);
+      }
+    }
+  }
+}

+ 8 - 0
src/modules/homepage/homepage-routing.module.ts

@@ -5,6 +5,14 @@ const routes: Routes = [
   {path: 'homeFirst', loadChildren: () => import('./home-first/home-first.module').then(mod => mod.HomeFirstPageModule)},
   {path: 'boos', loadChildren: () => import('../function/boos/boos.module').then(mod => mod.BoosPageModule)},
   {path: 'employer', loadChildren: () => import('../function/employer/employer.module').then(mod => mod.EmployerPageModule)},
+  {
+    path: 'trave',
+    loadChildren: () => import('./trave/trave.module').then( m => m.TravePageModule)
+  },
+  {
+    path: 'ai-chat',
+    loadChildren: () => import('./ai-chat/ai-chat.module').then( m => m.AiChatPageModule)
+  },
   // {path: 'trave', loadChildren: () => import('../function/trave/trave-routing.module').then(mod => mod.TravePageRoutingModule)},
 ];
 

+ 17 - 0
src/modules/homepage/trave/trave-routing.module.ts

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

+ 20 - 0
src/modules/homepage/trave/trave.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { TravePageRoutingModule } from './trave-routing.module';
+
+import { TravePage } from './trave.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    TravePageRoutingModule
+  ],
+  declarations: [TravePage]
+})
+export class TravePageModule {}

+ 45 - 0
src/modules/homepage/trave/trave.page.html

@@ -0,0 +1,45 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-grid>
+      <ion-row>
+        <ion-col style="display: flex; justify-content: flex-start;">
+          <ion-icon name="chevron-back-outline" (click)="back()"></ion-icon>
+        </ion-col>
+        <ion-col style="display: flex; justify-content: center;">
+          trave
+        </ion-col>
+        <ion-col style="display: flex; justify-content: flex-end;">
+          <ion-icon name="notifications-circle-outline"></ion-icon>
+        </ion-col>
+      </ion-row>
+    </ion-grid>
+  </ion-toolbar>
+</ion-header>
+<ion-grid>
+    <ion-row class="bar-icon">
+      <div class="project-bar-container">
+        <ion-col size="2" class="project-item" *ngFor="let icon of icons">
+          <img src="{{ icon.imageUrl }}" alt="{{ icon.name }}" class="project-icon" />
+          <div class="project-name">{{ icon.name }}</div>
+        </ion-col>
+      </div>    
+    </ion-row>
+  </ion-grid>
+<div class="page-color">
+  <!-- 景点 -->
+  <ion-list>
+    <ion-item *ngFor="let spot of scenicSpots" (click)="goDetailPage(spot)">
+        <ion-card class="grid-with-background" style="background-image: url({{spot.scenicImg}});
+      height: 130px;width: 100%;">
+        <ion-card-header style="padding-inline: 10px;
+        padding-top: 10px;">
+          <ion-card-title style="color: rgb(255, 255, 255);">{{spot.scenicName}}</ion-card-title>
+          <ion-card-subtitle style="color: rgb(255, 255, 255);">Destination</ion-card-subtitle>
+        </ion-card-header>
+      </ion-card>
+    </ion-item>
+  </ion-list>
+  <ion-infinite-scroll>
+    <ion-infinite-scroll-content loadingText="Please wait..." loadingSpinner="bubbles"></ion-infinite-scroll-content>
+  </ion-infinite-scroll>
+</div>

+ 82 - 0
src/modules/homepage/trave/trave.page.scss

@@ -0,0 +1,82 @@
+.page-color{
+    background: linear-gradient(220.55deg, #B7DCFF 0%, #ffffff 100%);
+    height: 100vh;
+    overflow: auto;
+}
+.search-container {
+    display: flex;
+    align-items: center;
+    width: 300px;
+    height: 40px;
+    border-radius: 20px;
+    overflow: hidden;
+    background-color: #f2f2f2;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    transition: width 0.3s;
+  }
+  
+  .search-container.active {
+    width: 400px;
+    border-radius: 4px;
+  }
+  
+  .search-input {
+    flex: 1;
+    height: 100%;
+    padding: 0 10px;
+    border: none;
+    background-color: transparent;
+    font-size: 14px;
+  }
+  
+  .search-button {
+    width: 40px;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #007bff;
+    color: #fff;
+    border: none;
+    cursor: pointer;
+    transition: background-color 0.3s;
+  }
+  
+  .search-button:hover {
+    background-color: #0056b3;
+  }
+  .grid-with-background {
+    background-size: cover;
+    background-position: center;
+  }
+  .bar-icon{
+    padding-inline: 25px;
+    border-radius: 10px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+  }
+  .project-bar-container {
+    display: flex;
+    overflow-x: scroll;
+    width: 100%;
+  }
+  
+  .project-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin: 5px;
+    padding: 10px;
+    border-radius: 20px;
+    background-color: #ffffff;
+    color: #000000;
+  }
+  .project-name {
+    margin-top: 5px;
+  }
+  .capsule-box {
+    border-radius: 20px;
+    background-color: #ffffff;
+    border: 1px solid #000000;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  }
+  

+ 17 - 0
src/modules/homepage/trave/trave.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { TravePage } from './trave.page';
+
+describe('TravePage', () => {
+  let component: TravePage;
+  let fixture: ComponentFixture<TravePage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TravePage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 79 - 0
src/modules/homepage/trave/trave.page.ts

@@ -0,0 +1,79 @@
+import {  OnInit } from '@angular/core';
+import {NavController } from '@ionic/angular';
+import { Component, HostListener , ElementRef, } from '@angular/core';
+import { Router } from '@angular/router';
+
+import * as Parse from "parse"
+(Parse as any).serverURL = "https://web2023.fmode.cn/parse"
+Parse.initialize("dev")
+
+// 获取数据库的内容
+function getScenic() {
+  const GzpScenicSpot = Parse.Object.extend('GzpScenicSpot');
+  const query = new Parse.Query(GzpScenicSpot);
+  return query.find().then(
+    (results) => {
+      return results.map((result) => result.toJSON());
+    },
+    (error) => {
+      console.error('Error:', error);
+      return [];
+    }
+  );
+}
+
+@Component({
+  selector: 'app-trave',
+  templateUrl: './trave.page.html',
+  styleUrls: ['./trave.page.scss'],
+})
+export class TravePage implements OnInit {
+
+  ngOnInit() {
+  }
+
+  back(){
+    this.navCtrl.back()
+  }
+  scenicSpots: any[] = [];
+  isExpanded: boolean = false;
+
+  constructor(private elementRef: ElementRef ,private router:Router,private navCtrl:NavController,) {
+    this.fetchData();
+  }
+
+  fetchData() {
+    getScenic().then((scenicSpots) => {
+      this.scenicSpots=scenicSpots;
+    });
+  }
+  
+// 搜索栏
+  @HostListener('document:click', ['$event.target'])
+  onClick(target: any) {
+    const clickedInside = this.elementRef.nativeElement.contains(target);
+    if (!clickedInside) {
+      this.isExpanded = false;
+    }
+  }
+
+  expandSearch() {
+    this.isExpanded = true;
+  }
+  
+  icons = [
+    { name: '门票', imageUrl: 'assets/门票.png' },
+    { name: '住宿', imageUrl: 'assets/旅游酒店.png' },
+    { name: '公交', imageUrl: 'assets/旅游车.png' },
+    { name: '美食', imageUrl: 'assets/美食.png' },
+    { name: '导航', imageUrl: 'assets/导航.png' },
+    { name: '推荐', imageUrl: 'assets/旅游攻略.png' },
+    { name: '投诉', imageUrl: 'assets/投诉举报.png' },
+    // Add more icons as needed
+  ];
+  goDetailPage(spot:Parse.Object){
+    this.router.navigate(["/pocket-local/homepage/detail-page"],{
+      queryParams:spot
+    })
+  }
+}

+ 20 - 5
src/modules/user/login/login.page.html

@@ -1,7 +1,23 @@
-<body class="主体区" style="background-image: url(assets/register.png);background-size: cover;
-background-position: center;">
+<ion-header [translucent]="true">
+    <ion-toolbar>
+      <ion-grid>
+        <ion-row>
+          <ion-col style="display: flex; justify-content: flex-start;" (click)="goBack()">
+            <ion-icon name="chevron-back-outline"></ion-icon>
+          </ion-col>
+          <ion-col style="display: flex; justify-content: center;">
+            登录
+          </ion-col>
+          <ion-col style="display: flex; justify-content: flex-end;">
+            <ion-icon name="notifications-circle-outline"></ion-icon>
+          </ion-col>
+        </ion-row>
+      </ion-grid>
+    </ion-toolbar>
+  </ion-header>
+
+<div class='page-color'>
   <!-- IonicModule + FormsModule实现,默认好看 -->
-<div class="login-modal">
     <ion-card>
         <ion-card-header>
         <ion-card-title>登录</ion-card-title>
@@ -31,7 +47,6 @@ background-position: center;">
         <ion-button expand="block" routerLink="/user/register">注册</ion-button>
         <ion-button expand="block" fill="clear" (click)="goBack()">返回</ion-button>
     </ion-card>
-</div>
 
 
   <!-- 纯HTML + FormsModule实现,可任意定制样式 -->
@@ -49,4 +64,4 @@ background-position: center;">
     <p style="color: red;">密码错误请确认后点击登入</p>
 
 </ng-container>
-</body>
+</div>

+ 5 - 3
src/modules/user/login/login.page.ts

@@ -2,6 +2,7 @@ import { Component } from '@angular/core';
 import { Router } from '@angular/router';
 import { AlertController, NavController } from '@ionic/angular';
 import { UserService } from '../service-user/user.service';
+
 // 引用Router服务
 @Component({
   selector: 'app-login',
@@ -14,7 +15,7 @@ export class LoginPage {
   constructor(
     private userServ:UserService,
     private router:Router,
-    private alertCtrl:AlertController
+    private alertCtrl:AlertController,private navCtrl:NavController
     ){}
   userData:any = {
     username:"",
@@ -23,10 +24,11 @@ export class LoginPage {
   }
 
   goBack(){
-    localStorage.removeItem("REDIRECT_URL");
-    localStorage.setItem("REDIRECT_URL", "../");
+    // localStorage.removeItem("REDIRECT_URL");
+    localStorage.setItem("REDIRECT_URL", "./user/tabs");
     let path = localStorage.getItem("REDIRECT_URL") || "../"
     this.router.navigate([path])
+    // this.navCtrl.back()
   }
   async login(){
     try{

+ 12 - 4
src/modules/user/mine/mine.page.ts

@@ -1,27 +1,34 @@
-import { Component } from '@angular/core';
+import { Component ,OnInit} from '@angular/core';
 import { ToastController } from '@ionic/angular';
 import { UserService } from 'src/modules/user/service-user/user.service';
-import {SharedService} from 'src/modules/user/service-user/Share.service'
+import {SharedService} from 'src/modules/user/service-user/Share.service';
+
 
 @Component({
   selector: 'app-mine',
   templateUrl: './mine.page.html',
   styleUrls: ['./mine.page.scss'],
 })
-export class MinePage {
+export class MinePage implements OnInit{
 
   currentUser:any
   username: string = '';
   userImg: string = '';
   userId:any=''
+  ngOnInit() {
+    this.userId = this.sharedService.getUserId();
+    this.username = this.sharedService.getUsername();
+    this.userImg = this.sharedService.getUserImg();
+  }
   constructor(
     private toastCtrl:ToastController,
     public userServ:UserService,
     private sharedService: SharedService,
   ){
+    
+    this.userId = this.sharedService.getUserId();
     this.username = this.sharedService.getUsername();
     this.userImg = this.sharedService.getUserImg();
-    this.userId = this.sharedService.getUserId();
     console.log('ok')
   }
   async logout(){
@@ -34,4 +41,5 @@ export class MinePage {
     this.sharedService.outLogin();
     toast.present();
   }
+  
 }

+ 0 - 5
src/modules/user/service-user/user.service.ts

@@ -32,11 +32,6 @@ export class UserService {
       if (results.length > 0) {
         this.sharedService.isLogin()
         this.sharedService.setUsername(userData.username,userData.userId);
-        const userAuth = {
-          username: u,
-          token: 'exampleToken'
-        };
-        localStorage.setItem('USER_AUTH', JSON.stringify(userAuth));
         return true; // 匹配成功
         
       }else{

+ 4 - 0
src/modules/user/user-routing.module.ts

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

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio