0225263 4 bulan lalu
induk
melakukan
fb722e1883

+ 31 - 0
package-lock.json

@@ -16,6 +16,9 @@
         "@angular/platform-browser": "^18.0.0",
         "@angular/platform-browser-dynamic": "^18.0.0",
         "@angular/router": "^18.0.0",
+        "@babylonjs/core": "^7.14.0",
+        "@babylonjs/loaders": "^7.14.0",
+        "@babylonjs/materials": "^7.14.0",
         "@capacitor/app": "6.0.0",
         "@capacitor/core": "6.1.0",
         "@capacitor/haptics": "6.0.0",
@@ -2614,6 +2617,28 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babylonjs/core": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmmirror.com/@babylonjs/core/-/core-7.14.0.tgz",
+      "integrity": "sha512-1yTDyd+5W3GuarFoEYKtEr3dBE7/4N/a/2kwsz3DzBu7cPPjJgG0elRgfCkUm/bZ+9zHxUNfgip7sDF7elhYzQ=="
+    },
+    "node_modules/@babylonjs/loaders": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmmirror.com/@babylonjs/loaders/-/loaders-7.14.0.tgz",
+      "integrity": "sha512-TzxXXabwQ3qbUlSZUASU6AljPCtt0rQmlRQfsVvUp4TKBz8zYWNhTcWbO4hhBhwB2yWtuUwZAT04h2W8aKV5Wg==",
+      "peerDependencies": {
+        "@babylonjs/core": "^7.0.0",
+        "babylonjs-gltf2interface": "^7.0.0"
+      }
+    },
+    "node_modules/@babylonjs/materials": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmmirror.com/@babylonjs/materials/-/materials-7.14.0.tgz",
+      "integrity": "sha512-cqg4knLEDl3EinfYsrqcfG9QXMn+8OcFel0kbys5wvi4w38kx7/PvoEd5zLor0PivfHQdpK7gF77jeyZaZChRg==",
+      "peerDependencies": {
+        "@babylonjs/core": "^7.0.0"
+      }
+    },
     "node_modules/@capacitor/app": {
       "version": "6.0.0",
       "resolved": "https://registry.npmmirror.com/@capacitor/app/-/app-6.0.0.tgz",
@@ -7189,6 +7214,12 @@
         "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
       }
     },
+    "node_modules/babylonjs-gltf2interface": {
+      "version": "7.14.0",
+      "resolved": "https://registry.npmmirror.com/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.14.0.tgz",
+      "integrity": "sha512-yfoU8HA7k/qStdyFFCK3CXzUpyN/pksnPXj0I9kEf76XOospRm5VdLFvweombIyQQtMNV+aDAB8STqgECU3LDA==",
+      "peer": true
+    },
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz",

+ 3 - 0
package.json

@@ -21,6 +21,9 @@
     "@angular/platform-browser": "^18.0.0",
     "@angular/platform-browser-dynamic": "^18.0.0",
     "@angular/router": "^18.0.0",
+    "@babylonjs/core": "^7.14.0",
+    "@babylonjs/loaders": "^7.14.0",
+    "@babylonjs/materials": "^7.14.0",
     "@capacitor/app": "6.0.0",
     "@capacitor/core": "6.1.0",
     "@capacitor/haptics": "6.0.0",

+ 17 - 18
src/app/creator/creator.page.html

@@ -25,6 +25,7 @@
       <ion-label class="nickname">{{user?.get("username")}}</ion-label> <!-- 昵称 -->
     </div>
     <div class="stats">
+      <ion-label class="label-icon">上月作品数据:</ion-label>
       <ion-label class="label-icon"><ion-icon name="thumbs-up-outline"></ion-icon> 点赞数:300</ion-label>
       <ion-label class="label-icon"><ion-icon name="eye-outline"></ion-icon> 浏览量:6000</ion-label>
       <ion-label class="label-icon"><ion-icon name="star-outline"></ion-icon> 最佳作品点赞数:150</ion-label>
@@ -32,29 +33,27 @@
     </div>
 </div>
 
-  <div class="best-works">
-    <ion-card>
-      <ion-card-header>
-        <ion-card-title>最佳作品</ion-card-title>
-      </ion-card-header>
-      <ion-card-content>
-        <!-- 最佳作品列表 -->
-      </ion-card-content>
-    </ion-card>
-  </div>
-
-  <div class="exclusive-services">
-    <ion-card>
+<div class="animate-card animate-card-84">
+  <div class="animate-card__layer">
+   <ion-card>
       <ion-card-header>
         <ion-card-title>专属服务</ion-card-title>
       </ion-card-header>
-      <ion-card-content>
-        <ion-label>专属服务内容:</ion-label>
-        <ion-label>1. 学创作</ion-label>
-        <ion-label>2. 任务中心</ion-label>
+     </ion-card>
+      </div>
+    <div class="animate-card__sublayer">
+      <ion-card-content class="content-position">
+        <ion-button>
+          <ion-icon name="create-outline" ></ion-icon> 学创作
+        </ion-button>
+        <ion-button>
+          <ion-icon name="list-outline"></ion-icon> 
+          任务中心
+        </ion-button>
       </ion-card-content>
-    </ion-card>
   </div>
+</div>
+  
 
   <div class="tools-resources">
     <ion-card>

+ 132 - 1
src/app/creator/creator.page.scss

@@ -21,4 +21,135 @@
 
 .label-icon {
   color: black; /* 图标和文字颜色 */
-}
+}
+
+.content-position{
+  padding-top:0px;
+}
+
+.animate-card {
+  position: relative;
+   width: 100%; /* 设置卡片宽度 */
+  height: 100px; /* 设置卡片高度 */
+  overflow: hidden;
+}
+.animate-card-84 {
+
+  &::before, &::after {
+    content: '';
+    position: absolute;
+    height: 4px;
+    left: 5px;
+    right: 5px;
+    z-index: 2;
+    transform: scaleX(0);
+    transform-origin: 0 0;
+    transition: all 0.35s ease;
+    background-color: #000;
+  }
+
+  &::before {
+    top: 5px;
+    transition-delay: 0.28s;
+  }
+
+  &::after {
+    bottom: 5px;
+    transition-delay: 0s;
+  }
+
+  .animate-card {
+    &__layer {
+      width: 100%;
+      height: 100%;
+      transition: 0.5s;
+
+      & > img {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    &__sublayer {
+      position: absolute;
+      top: 0;
+      bottom: 0;
+      left: 0;
+      right: 0;
+      z-index: 1;
+      width: 100%;
+      height: 100%;
+      padding: 30px;
+      text-align: center;
+      color: #000;
+      background-color: #fff;
+      opacity: 0;
+      transition: all 0.5s ease;
+
+      &::before, &::after {
+        content: '';
+        position: absolute;
+        top: 5px;
+        bottom: 5px;
+        z-index: -1;
+        width: 4px;
+        transform: scaleY(0);
+        transform-origin: 0 0;
+        background-color: #000;
+        transition: all 0.35s ease;
+      }
+
+      &::before {
+        left: 5px;
+        transition-delay: 0.28s;
+      }
+
+      &::after {
+        right: 5px;
+        transition-delay: 0s;
+      }
+    }
+  }
+
+  &:hover {
+    &::before {
+      transition-delay: 0s;
+    }
+
+    &::after {
+      transition-delay: 0.28s;
+    }
+
+    &::before, &::after {
+      transform: scale(1);
+    }
+
+    .animate-card {
+      &__layer {
+
+      }
+
+      &__sublayer {
+        opacity: 1;
+
+        &::before {
+          transition-delay: 0s;
+        }
+
+        &::after {
+          transition-delay: 0.28s;
+        }
+
+        &::before, &::after {
+          transform: scale(1);
+        }
+      }
+    }
+  }
+}
+
+ion-button{
+  margin-top:0px;
+}
+
+

+ 69 - 3
src/app/feedback/feedback.page.html

@@ -1,13 +1,13 @@
 <ion-header [translucent]="true">
   <ion-toolbar style="height: 60px">
-    <ion-buttons slot="start">
+    <!-- <ion-buttons slot="start">
       <ion-back-button defaultHref="/tabs/tab4"></ion-back-button>
-    </ion-buttons>
+    </ion-buttons> -->
     <ion-title style="font-size:25px" >反馈</ion-title>
   </ion-toolbar>
 </ion-header>
 
-<ion-content>
+<!-- <ion-content>
   <ion-list lines="none">
     <ion-item *ngFor="let message of chatMessages" [class.sender]="message.sender === 'customer'">
       <ion-avatar slot="start">
@@ -23,4 +23,70 @@
     <ion-input placeholder="输入消息..." [(ngModel)]="newMessage"></ion-input>
     <ion-button expand="block" (click)="sendMessage()">发送</ion-button>
   </ion-footer>
+</ion-content> -->
+
+<ion-header>
+  <ion-toolbar color="primary">
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab4"></ion-back-button>
+    </ion-buttons>
+    <ion-title>{{ contact?.get('name') || contact?.get('to')?.get("nickname") ||contact?.get('to')?.get('username') }}</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content class="chat-content">
+  <ion-list lines="none">
+    <ion-item *ngFor="let message of messageList" class="message-item">
+      <ion-label class="message-container"
+                 [class.sent-message-container]="message?.get('sendUser')?.id === user?.id"
+                 [class.received-message-container]="message?.get('receiveUser')?.id === targetId">
+        <div class="message-details">
+          <p [class.sent-message]="message?.get('sendUser')?.id === user?.id"
+             [class.received-message]="message?.get('receiveUser')?.id === targetId"
+             class="message-text">{{ message?.get("contentJson")?.content }}</p>
+          <div class="message-time">
+            <p>{{ message.createdAt|date:'HH:mm:ss' }}</p>
+          </div>
+        </div>
+      </ion-label>
+      <ion-avatar slot="end" *ngIf="message?.get('sendUser')?.id === user?.id" class="message-avatar sent-avatar">
+        <img [src]="'/assets/img/a.png'">
+      </ion-avatar>
+      <ion-avatar slot="start" *ngIf="message?.get('receiveUser')?.id === targetId" class="message-avatar received-avatar">
+        <img [src]="'/assets/img/b.png'">
+      </ion-avatar>
+    </ion-item>
+  </ion-list>
+
+  <ion-list lines="none">
+    <ion-item *ngFor="let message of messages" class="message-item">
+      <ion-label class="message-container"
+                 [class.sent-message-container]="message.type === 'sent'"
+                 [class.received-message-container]="message.type === 'received'">
+        <div class="message-details">
+          <p [class.sent-message]="message.type === 'sent'"
+             [class.received-message]="message.type === 'received'"
+             class="message-text">{{ message.text }}</p>
+          <div class="message-time">
+            <p>{{ message.time }}</p>
+          </div>
+        </div>
+      </ion-label>
+      <ion-avatar slot="end" *ngIf="message.type === 'sent'" class="message-avatar sent-avatar">
+        <img [src]="message.avatar">
+      </ion-avatar>
+      <ion-avatar slot="start" *ngIf="message.type === 'received'" class="message-avatar received-avatar">
+        <img [src]="message.avatar">
+      </ion-avatar>
+    </ion-item>
+  </ion-list>
 </ion-content>
+
+<ion-footer>
+  <ion-toolbar>
+    <ion-input placeholder="Type your message..." [(ngModel)]="newMessage" clearInput></ion-input>
+    <ion-buttons slot="end">
+      <ion-button (click)="sendMessage()" color="primary" [disabled]="!newMessage">Send</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-footer>

+ 83 - 1
src/app/feedback/feedback.page.scss

@@ -1,3 +1,85 @@
 // ion-header {
 //   --min-height: 80px !important; /* 设置 header 的最小高度为 80px,你可以根据需要调整高度 */
-// }
+// }
+
+.chat-content {
+    padding: 10px;
+  }
+  
+  ion-item.message-item {
+    
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    margin-bottom: 10px;
+    max-width: 80%; /* 控制消息框的最大宽度 */
+  }
+  
+  .message-container {
+    padding: 8px 12px;
+    display: inline-block;
+    max-width: 80%; /* 控制消息内容的最大宽度 */
+  }
+  
+  .sent {
+    justify-content: flex-end; /* 将发送的消息右对齐 */
+  }
+  
+  .received {
+    justify-content: flex-start; /* 将接收的消息左对齐 */
+  }
+  
+  .sent-message-container {
+    background-color: #dcf8c6; /* 发送消息的背景颜色 */
+    align-self: flex-end;
+    border-radius: 10px;
+    padding: 10px;
+    margin-bottom: 4px;
+    max-width: 70%; /* 适当调整最大宽度 */
+    text-align: right; /* 文本右对齐 */
+  }
+  
+  .received-message-container {
+    background-color: #f0f0f0; /* 接收消息的背景颜色 */
+    align-self: flex-start;
+    border-radius: 10px;
+    padding: 10px;
+    margin-bottom: 4px;
+    max-width: 70%; /* 适当调整最大宽度 */
+    text-align: left; /* 文本左对齐 */
+  }
+  .sent-message-container[_ngcontent-ng-c914708361]{
+    max-width: 100%;
+  }
+  ion-avatar[_ngcontent-ng-c914708361]{
+    margin-top:28px;
+  }
+  .list-md{
+    width: 123%;
+  }
+  .received-message-container[_ngcontent-ng-c914708361]{
+    max-width: 100%;
+  }
+  
+  .sent-message, .received-message {
+    color: #333; /* 消息文本颜色 */
+  }
+  
+  .message-time {
+    font-size: 12px;
+    color: #888; /* 时间文本颜色 */
+    margin-top: 4px;
+  }
+  
+  .message-details {
+    display: flex;
+    flex-direction: column;
+  }
+  
+  ion-avatar {
+    width: 32px;
+    height: 32px;
+    margin-left: 8px;
+    margin-right: 8px;
+  }
+  

+ 135 - 14
src/app/feedback/feedback.page.ts

@@ -1,4 +1,41 @@
+// import { Component, OnInit } from '@angular/core';
+
+// @Component({
+//   selector: 'app-feedback',
+//   templateUrl: './feedback.page.html',
+//   styleUrls: ['./feedback.page.scss'],
+// })
+// export class FeedbackPage implements OnInit {
+
+//   chatMessages: { text: string, sender: string, avatar: string }[] = [];
+//   newMessage: string = '';
+
+//   constructor() {}
+
+//   ngOnInit() {
+//     // 模拟一些聊天消息
+//     this.chatMessages = [
+//       { text: '你好,请问有什么可以帮助您的吗?', sender: 'customer', avatar: 'https://img-bsy.txrpic.com/preview/Element/00/00/89/11/E-891182-2418FE26A.png?imageMogr2/quality/90/thumbnail/320x%3E' },
+//       { text: '您好,我想咨询一下关于产品的信息。', sender: 'support', avatar: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.c43kVbudRWN3-pJYtmfugAAAAA?rs=1&pid=ImgDetMain' }
+//     ];
+//   }
+
+//   sendMessage() {
+//     if (this.newMessage.trim() !== '') {
+//       this.chatMessages.push({ text: this.newMessage, sender: 'customer', avatar: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.c43kVbudRWN3-pJYtmfugAAAAA?rs=1&pid=ImgDetMain' });
+//       // 在这里可以添加客服回复的逻辑
+//       this.newMessage = '';
+//     }
+//   }
+
+// }
+
 import { Component, OnInit } from '@angular/core';
+import { NavController } from '@ionic/angular';
+import { Router } from '@angular/router';
+import { ActivatedRoute } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import Parse from "parse";
 
 @Component({
   selector: 'app-feedback',
@@ -6,26 +43,110 @@ import { Component, OnInit } from '@angular/core';
   styleUrls: ['./feedback.page.scss'],
 })
 export class FeedbackPage implements OnInit {
-
-  chatMessages: { text: string, sender: string, avatar: string }[] = [];
+  userid: string;
+  messageList:any = []
+  messages = [
+    { type: 'received', avatar: '/assets/img/support-avatar.png', time: '10:30 AM', text: 'Hi there!' },
+    { type: 'sent', avatar: '/assets/img/b.png', time: '10:31 AM', text: 'Hey! How are you?' },
+    // Add more messages as needed
+  ];
+  
   newMessage: string = '';
 
-  constructor() {}
+  constructor(private route: ActivatedRoute) {
+    this.userid = this.route.snapshot.paramMap.get('userid') as string;
+    this.targetId = this.userid
+  }
 
-  ngOnInit() {
-    // 模拟一些聊天消息
-    this.chatMessages = [
-      { text: '你好,请问有什么可以帮助您的吗?', sender: 'customer', avatar: 'https://img-bsy.txrpic.com/preview/Element/00/00/89/11/E-891182-2418FE26A.png?imageMogr2/quality/90/thumbnail/320x%3E' },
-      { text: '您好,我想咨询一下关于产品的信息。', sender: 'support', avatar: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.c43kVbudRWN3-pJYtmfugAAAAA?rs=1&pid=ImgDetMain' }
-    ];
+  contact:Parse.Object|undefined
+  user:Parse.User|undefined
+  targetId:string |undefined
+  async ngOnInit() {
+    this.user =  Parse.User.current()
+    let fromId = Parse.User.current()?.id
+    if(this.userid && fromId){
+      let query = new Parse.Query("Contact");
+      query.include("to")
+      query.equalTo("from",fromId);
+      query.equalTo("to",this.userid);
+      this.contact = await query.first();
+    }
+    this.loadHistory();
+    return
   }
+  async sendMessage() {
+    if (this.newMessage.trim() === '') {
+      return;
+    }
+    let sendUser = Parse.User?.current()?.toPointer()
+    let receiveUser = {__type:"Pointer",className:"_User",objectId:this.userid}
+    let Message = Parse.Object.extend("Message");
+    let message = new Message();
+    message.set("sendUser",sendUser)
+    message.set("receiveUser",receiveUser)
+    message.set("contentJson",{
+      role:"user",
+      content: this.newMessage
+    })
+    message = await message.save()
+    if(message?.id){
+      this.messageList.push(message)
+      this.syncSession(message,sendUser,receiveUser);
+    }
+    this.newMessage = '';
 
-  sendMessage() {
-    if (this.newMessage.trim() !== '') {
-      this.chatMessages.push({ text: this.newMessage, sender: 'customer', avatar: 'https://tse3-mm.cn.bing.net/th/id/OIP-C.c43kVbudRWN3-pJYtmfugAAAAA?rs=1&pid=ImgDetMain' });
-      // 在这里可以添加客服回复的逻辑
-      this.newMessage = '';
+    this.loadHistory();
+  }
+  async syncSession(message:any,sendUser:any,receiveUser:any){
+    // 根据当前聊天,更新最新的会话状态表 MessageSession 记录最新的会话
+    let session = await this.checkSessionExists();
+    if(!session?.id){
+      let MessageSession = Parse.Object.extend("MessageSession")
+      session = new MessageSession()
     }
+    session?.set("message",message?.toPointer())
+    session?.set("sendUser",sendUser)
+    session?.set("receiveUser",receiveUser)
+    session?.save();
+  }
+  async checkSessionExists(){
+    let query = Parse.Query.fromJSON('MessageSession',{where: {
+      $or: [
+        {
+          sendUser: this.user?.id,
+          receiveUser: this.targetId
+        },
+        {
+          sendUser: this.targetId,
+          receiveUser: this.user?.id
+        }
+      ]
+    }})
+    return await query.first()
   }
 
+  getCurrentTime() {
+    const now = new Date();
+    return now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
+  }
+
+  async loadHistory(){
+    let query = Parse.Query.fromJSON('Message',{where: {
+      $or: [
+        {
+          sendUser: this.user?.id,
+          receiveUser: this.targetId
+        },
+        {
+          sendUser: this.targetId,
+          receiveUser: this.user?.id
+        }
+      ]
+    }})
+
+    let list = await query.find();
+    if(list?.length){
+      this.messageList = list
+    }
+  }
 }