warrior 3 months ago
parent
commit
5483ba0d7f

+ 5 - 0
projects/live-app/src/app/app.routes.ts

@@ -29,5 +29,10 @@ export const routes: Routes = [
     canActivate: mapToCanActivate([AuthGuard]),
     loadChildren: () =>import('../moduls/goods/goods.modules.routes').then((mod) => mod.GoodsRoutingModule),
   },
+  {
+    path: 'live', 
+    canActivate: mapToCanActivate([AuthGuard]),
+    loadChildren: () =>import('../moduls/live/live.modules.routes').then((mod) => mod.LiveRoutingModule),
+  },
   
 ];

+ 158 - 0
projects/live-app/src/moduls/live/chat/chat.component.html

@@ -0,0 +1,158 @@
+<ion-header [translucent]="true" class="header">
+  <ion-toolbar class="toolbar">
+    <ion-buttons slot="start" (click)="onBack()">
+      <ion-icon
+        name="chevron-back-outline"
+        style="width: 6.4vw; height: 6.4vw; color: #000000"
+      ></ion-icon>
+    </ion-buttons>
+    <ion-title class="title">{{ targetUser.name }}</ion-title>
+    <ion-buttons slot="end" id="click-trigger">
+      <ion-icon name="ellipsis-horizontal-outline"></ion-icon>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content
+  [scrollEvents]="true"
+  [fullscreen]="true"
+  (ionScrollStart)="handleScrollStart()"
+  (ionScroll)="handleScroll($any($event))"
+  (ionScrollEnd)="handleScrollEnd()"
+  class="ion-padding"
+>
+  <ion-popover
+    trigger="click-trigger"
+    [dismissOnSelect]="true"
+    triggerAction="click"
+  >
+    <ng-template>
+      <ion-list>
+        <ion-item class="clear" [button]="true" [detail]="false">
+          <ion-icon name="person-remove-outline"></ion-icon>加入黑名单</ion-item
+        >
+        <ion-item class="clear" [button]="true" [detail]="false"
+          ><ion-icon name="star-outline"></ion-icon>添加关注</ion-item
+        >
+        <ion-item class="clear" [button]="true" [detail]="false"
+          ><ion-icon name="trash-outline"></ion-icon>删除聊天记录</ion-item
+        >
+      </ion-list>
+    </ng-template>
+  </ion-popover>
+
+  <div id="container" style="overflow: hidden">
+    @for (item of list.data; track $index) {
+    <div class="clearfix message-box">
+      @if ($index == 0 || item.create_time - list.data[$index-1].create_time >
+      60) {
+      <div class="time-box">
+        @if (item.istoday) {
+        <div class="time">{{ item.timeStamp | date : "HH:mm" }}</div>
+        }@else {
+        <div class="time">
+          {{ item.timeStamp | date : "yyyy年MM月dd日 HH:mm" }}
+        </div>
+        }
+      </div>
+      }
+
+      <!-- 他人信息 -->
+      @if (!item.is_self) {
+      <div class="msg-bloak no_self">
+        <img class="avatar fl" mode="widthFix" src="{{ item.avatar }}" />
+        <!-- 文字消息 msg_type == 1 || text -->
+        @if (item.msg_type == 1 || item.msg_type == 'text') {
+        <div class="text-item fl text-item_left">
+          <p>{{ item.content }}</p>
+        </div>
+        }
+        <!-- 图片消息 msg_type == 2 || img -->
+        @else if(item.msg_type == 2 || item.msg_type == 'img' || item.msg_type
+        == 'image') {
+        <img
+          class="img-item fl"
+          [src]="item.content"
+          (click)="predivimg(item.content)"
+        />
+        } @else if (item.msg_type == 3) {
+        <div class="text-item fl text-item_left">
+          <p>{{ item.content }}</p>
+        </div>
+        }
+      </div>
+      } @else {
+      <div class="msg-bloak self">
+        <!-- 自己信息 -->
+        @if (item.msg_type == 1 || item.msg_type == 'text') {
+        <div class="text-item fr text-item_right">
+          <p>{{ item.content }}</p>
+        </div>
+        } @if (item.msg_type == 2 || item.msg_type == 'img' || item.msg_type ==
+        'image') {
+        <img
+          class="img-item fr"
+          src="{{ item.content }}"
+          (click)="predivimg(item.content)"
+          bindtap="predivimg"
+          data-src="{{ item.content }}"
+        />
+        } @if (item.msg_type == 3) {
+        <div class="text-item fr text-item_right">
+          <p>{{ item.content }}</p>
+        </div>
+        }
+        <img class="avatar fr" [src]="item.avatar" />
+      </div>
+      }
+    </div>
+    }
+  </div>
+</ion-content>
+<ion-footer>
+  <ion-toolbar class="footer-tool">
+    <ion-input
+      slot="start"
+      labelPlacement="stacked"
+      [clearInput]="true"
+      placeholder="和ta说点什么"
+      [(ngModel)]="msg"
+    >
+    </ion-input>
+    <div class="tools" slot="end">
+      <ion-icon name="happy-outline"></ion-icon>
+      <ion-icon name="videocam-outline"></ion-icon>
+      <ion-icon name="gift-outline"></ion-icon>
+      <span class="splice">|</span>
+      <!-- <div class="send">发送</div> -->
+      <ion-button
+        class="send"
+        fill="outline"
+        size="small"
+        [disabled]="msg.length == 0"
+        >发送</ion-button
+      >
+    </div>
+  </ion-toolbar>
+  <div [style.height]="height + 'px'"></div>
+  @if (showEmoji ||showMore) {
+  <div class="b-1px-b"></div>
+  } @if (showEmoji) {
+  <div class="emoji-content">
+    <div class="emoji-box">
+      @for (item of emojis; track $index) {
+      <div class="emoji-item">
+        <div class="emoji-img" (click)="emojiChoose(item)">
+          {{ item?.char }}
+        </div>
+      </div>
+      }
+      <div class="emoji-item__del" (click)="delEmoji()">
+        <img
+          class="emoji-img"
+          src="https://common.file.futurestack.cn/images/wxapp/card_multi/images//chat/del.svg"
+        />
+      </div>
+    </div>
+  </div>
+  }
+</ion-footer>

+ 115 - 0
projects/live-app/src/moduls/live/chat/chat.component.scss

@@ -0,0 +1,115 @@
+.ion-padding {
+  padding-bottom: 50px;
+  .avatar {
+    width: 40px;
+    height: 40px;
+  }
+  .message-box {
+    margin-bottom: 30px;
+    .time-box {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      height: 50px;
+      font-size: 12px;
+      color: #fff;
+      .time {
+        background: rgba(0, 0, 0, 0.2);
+        border-radius: 4px;
+        padding: 0 10px;
+      }
+    }
+    .text-item {
+      position: relative;
+      line-height: 1.5;
+      font-size: 16px;
+      padding: 10px;
+      max-width: 220px;
+      border-radius: 4px;
+      word-wrap: break-word;
+      min-height: 40px;
+      min-width: 40px;
+    }
+    .msg-bloak {
+      display: flex;
+      .text-item_left {
+        background: #f1f1f1;
+      }
+      .text-item_left::before {
+        content: "";
+        position: absolute;
+        left: -11px;
+        top: calc(20px - 6px);
+        border: 6px solid transparent;
+        border-right-color: #f1f1f1;
+        z-index: 20;
+      }
+      .text-item_right {
+        background: #a2e65b;
+      }
+      .text-item_right::before {
+        content: "";
+        position: absolute;
+        left: calc(100% - 1px);
+        top: calc(20px - 6px);
+        border: 6px solid transparent;
+        border-left-color: #a2e65b;
+      }
+    }
+    .self{
+      justify-content: end;
+    }
+    .no_self{
+      justify-content: start;
+    }
+    .text-item_status {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      margin-right: 12px;
+      font-size: 12px;
+      color: #888;
+    }
+
+    .text-item_status--fail {
+      color: red;
+    }
+
+    .text-item_status--success {
+      color: #28bf39;
+    }
+  }
+  .img-item {
+    width: 140px;
+    height: 100px;
+    object-fit: contain;
+  }
+}
+.footer-tool {
+  .tools {
+    width: 160px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    flex-shrink: 0;
+    ion-icon {
+      font-size: 30px;
+    }
+  }
+}
+
+ion-popover {
+  --width: 150px;
+}
+.clear {
+  font-size: 14px;
+}
+.fl {
+  margin-right: 10px;
+  float: left;
+}
+
+.fr {
+  float: right;
+  margin-left: 10px;
+}

+ 28 - 0
projects/live-app/src/moduls/live/chat/chat.component.spec.ts

@@ -0,0 +1,28 @@
+/* tslint:disable:no-unused-variable */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { DebugElement } from '@angular/core';
+
+import { ChatComponent } from './chat.component';
+
+describe('ChatComponent', () => {
+  let component: ChatComponent;
+  let fixture: ComponentFixture<ChatComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ChatComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ChatComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 209 - 0
projects/live-app/src/moduls/live/chat/chat.component.ts

@@ -0,0 +1,209 @@
+import { DatePipe } from '@angular/common';
+import { HttpClient } from '@angular/common/http';
+import { Component, OnInit } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { IonicModule, ScrollDetail } from '@ionic/angular';
+import * as Parse from 'parse';
+
+@Component({
+  selector: 'app-chat',
+  templateUrl: './chat.component.html',
+  styleUrls: ['./chat.component.scss'],
+  standalone: true,
+  imports: [IonicModule, FormsModule, DatePipe],
+  providers: [DatePipe],
+})
+export class ChatComponent implements OnInit {
+  targetUser: any = {
+    name: '小兰花',
+    avatar: '',
+  };
+  msg: string = '';
+  list: any = {
+    data: [
+      {
+        is_self: true,
+        avatar:
+          'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+        msg_type: 1,
+        content: 'nihao',
+        create_time: new Date(),
+        istoday: true,
+        timeStamp: new Date(),
+        data: [
+          {
+            create_time: new Date(),
+          },
+        ],
+      },
+      {
+        is_self: true,
+        avatar:
+          'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+        msg_type: 1,
+        content: `Use the pipe name to trace where the pipe is declared and used. To resolve this error: If the pipe is local to the NgModule, give it a unique name in the pipe's decorator and declared it in the NgModule. If the pipe is standalone or is declared in another NgModule, add it to the imports field of the standalone component or the current NgModule.`,
+        create_time: new Date(),
+        istoday: true,
+        timeStamp: new Date(),
+        data: [
+          {
+            create_time: new Date(),
+          },
+        ],
+      },
+      {
+        is_self: false,
+        avatar:
+          'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+        msg_type: 1,
+        content: 'nihao',
+        create_time: new Date(),
+        istoday: true,
+        timeStamp: new Date(),
+        data: [
+          {
+            create_time: new Date(),
+          },
+        ],
+      },
+    ],
+  };
+
+  showPreView: boolean = false; //预览图片
+  viewImg: string = '';
+  height: number = 0;
+  showEmoji: boolean = false;
+  showMore: boolean = false;
+  emojis: Array<any> = []
+
+  constructor(private http: HttpClient, public datePipe: DatePipe) {}
+
+  ngOnInit() {}
+  initEmoji() {
+    let emojiChar =
+      "☺-😋-😌-😍-😏-😜-😝-😞-😔-😪-😁-😂-😃-😅-😆-👿-😒-😓-😔-😏-😖-😘-😚-😒-😡-😢-😣-😤-😢-😨-😳-😵-😷-😸-😻-😼-😽-😾-😿-🙊-🙋-🙏-✈-🚇-🚃-🚌-🍄-🍅-🍆-🍇-🍈-🍉-🍑-🍒-🍓-🐔-🐶-🐷-👦-👧-👱-👩-👰-👨-👲-👳-💃-💄-💅-💆-💇-🌹-💑-💓-💘-🚲";
+
+    let emojiKey = [
+      "60a",
+      "60b",
+      "60c",
+      "60d",
+      "60f",
+      "61b",
+      "61d",
+      "61e",
+      "61f",
+      "62a",
+      "62c",
+      "602",
+      "603",
+      "605",
+      "606",
+      "608",
+      "612",
+      "613",
+      "614",
+      "615",
+      "616",
+      "618",
+      "619",
+      "620",
+      "621",
+      "623",
+      "624",
+      "625",
+      "627",
+      "629",
+      "633",
+      "635",
+      "637",
+      "63a",
+      "63b",
+      "63c",
+      "63d",
+      "63e",
+      "63f",
+      "64a",
+      "64b",
+      "64f",
+      "681",
+      "68a",
+      "68b",
+      "68c",
+      "344",
+      "345",
+      "346",
+      "347",
+      "348",
+      "349",
+      "351",
+      "352",
+      "353",
+      "414",
+      "415",
+      "416",
+      "466",
+      "467",
+      "468",
+      "469",
+      "470",
+      "471",
+      "472",
+      "473",
+      "483",
+      "484",
+      "485",
+      "486",
+      "487",
+      "490",
+      "491",
+      "493",
+      "498",
+      "6b4",
+    ];
+    let emojis = []
+    let emojiCharArr = emojiChar.split("-");
+    for (let i in emojiKey) {
+      let em = {
+        char: emojiCharArr[i],
+        emoji: "0x1f" + emojiKey[i],
+      };
+      emojis.push(em);
+    }
+    this.emojis = emojis
+  }
+  handleScrollStart() {
+    console.log('scroll start');
+  }
+
+  handleScroll(ev: CustomEvent<ScrollDetail>) {
+    console.log('scroll', ev.detail);
+    let srcollop = ev.detail.startY;
+    console.log(srcollop);
+  }
+
+  handleScrollEnd() {
+    console.log('scroll end');
+  }
+  //调起表情
+  changeShowEmoji() {
+    this.showEmoji = !this.showEmoji;
+    this.height = 0;
+    this.showMore = false;
+  }
+  //添加表情
+  emojiChoose(value: any) {
+    this.msg = this.msg + value.char;
+  }
+  //删除表情
+  delEmoji() {
+    this.msg = this.msg.substring(0, this.msg.length - 2);
+  }
+  predivimg<T>(value: string) {
+    this.showPreView = true;
+    this.viewImg = value;
+  }
+  onBack() {
+    history.back();
+  }
+}

+ 14 - 0
projects/live-app/src/moduls/live/live.modules.routes.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { ChatComponent } from './chat/chat.component';
+const routes: Routes = [
+  {
+    path: 'chat',//聊天
+    component: ChatComponent,
+  },
+]
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class LiveRoutingModule { }

+ 1 - 0
projects/live-app/src/moduls/tabs/notice/notice.component.html

@@ -44,6 +44,7 @@
           @for (item of noticeList; track $index) {
           <ion-item
             class="li"
+            (click)="toUrl('/live/chat')"
             (touchstart)="startPress()"
             (mousemove)="stopPress()"
           >

+ 18 - 7
projects/live-app/src/moduls/tabs/notice/notice.component.ts

@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
 import { IonicModule } from '@ionic/angular';
 import * as Parse from 'parse';
 import { InfiniteScrollCustomEvent } from '@ionic/angular';
+import { Router } from '@angular/router';
 @Component({
   selector: 'app-notice',
   templateUrl: './notice.component.html',
@@ -32,38 +33,48 @@ export class NoticeComponent implements OnInit {
     },
   ];
   friends: Array<Object> = [];
-  constructor() {}
+  times: number = 0;
+  timer: any;
+  showModal: boolean = false; //是否长按弹窗
+  currentObject: any; //当前选择对象
+  constructor(private router: Router) {}
 
   ngOnInit() {}
   segmentChanged(e: any) {
     let { value } = e.detail;
     this.active = value;
   }
-  times: number = 0;
-  timer: any;
+
   startPress() {
-    this.times += 100;
+    this.showModal = false;
     if (this.times >= 500) {
       console.log(this.times);
       this.times = 0;
+      this.showModal = true;
       return;
     }
     this.timer = setTimeout(() => {
+      this.times += 500;
       this.startPress();
-    }, 100);
+    }, 500);
   }
-  onMousemove(e:any){
+  onMousemove(e: any) {
     clearTimeout(this.timer);
+    this.showModal = false;
     this.times = 0;
   }
   stopPress() {
     clearTimeout(this.timer);
     this.times = 0;
   }
-  onIonInfinite(ev:any) {
+  onIonInfinite(ev: any) {
     console.log(ev);
     setTimeout(() => {
       (ev as InfiniteScrollCustomEvent).target.complete();
     }, 500);
   }
+  toUrl(url: string) {
+    if (this.showModal) return;
+    this.router.navigate([url]);
+  }
 }