warrior 2 months ago
parent
commit
b9314766ae

+ 7 - 1
projects/live-app/src/modules/account/account.modules.routes.ts

@@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
 import { AccountLogComponent } from './account-log/account-log.component';
 import { BankcardComponent } from './bankcard/bankcard.component';
+import { NoticeLogComponent } from './notice-log/notice-log.component';
 import { DetailComponent } from './order/detail/detail.component';
 import { OrderComponent } from './order/order.component';
 import { RechargeComponent } from './recharge/recharge.component';
@@ -35,7 +36,12 @@ const routes: Routes = [
   {
     path: 'order/detail/:id',
     component: DetailComponent,
-  }
+  },
+  {
+    path: 'noticelog',
+    component: NoticeLogComponent,
+  },
+  
 ]
 @NgModule({
   imports: [RouterModule.forChild(routes)],

+ 34 - 0
projects/live-app/src/modules/account/notice-log/notice-log.component.html

@@ -0,0 +1,34 @@
+<nav title="系统通知"></nav>
+<ion-content class="content">
+  @for (item of list; track $index) {
+  <div class="log-item">
+    <img
+      [src]="item.avatar"
+      alt=""
+      class="avatar"
+      (click)="toUrl('user/profile/' + item.tuid)"
+    />
+    <div class="item-col-right">
+      <div class="row">
+        <div class="name">{{ item.title }}</div>
+        <div class="time">{{ item.createdAt | date : "yyyy-MM-dd HH:ss" }}</div>
+      </div>
+      <div class="row-btns">
+        @switch (item.status) { @case ('100') { @if (item.friend == user.id) {
+        <div class="tg" (click)="onApply(item.fid,$index, true)">通过</div>
+        <div class="tg jj" (click)="onApply(item.fid,$index, false)">拒绝</div>
+        }@else {
+        <div class="tg other">等待验证</div>
+        } } @case ('200') {
+        <div class="tg other">已通过</div>
+        } @case ('101') {
+        <div class="tg other">已拒绝</div>
+        } }
+      </div>
+    </div>
+  </div>
+  }
+  <ion-infinite-scroll (ionInfinite)="onIonInfinite($event)">
+    <ion-infinite-scroll-content></ion-infinite-scroll-content>
+  </ion-infinite-scroll>
+</ion-content>

+ 43 - 0
projects/live-app/src/modules/account/notice-log/notice-log.component.scss

@@ -0,0 +1,43 @@
+.log-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 6px 10px;
+  border-bottom: 1px solid #f3f3f3;
+  font-size: 14px;
+  .avatar {
+    width: 36px;
+    height: 36px;
+    border-radius: 50%;
+    margin-right: 6px;
+  }
+  .item-col-right {
+    display: flex;
+    justify-content: space-between;
+    flex: 1;
+    .time {
+      color: #676767;
+      margin-top: 4px;
+    }
+    .row-btns {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+    }
+    .tg {
+      border: 1px solid;
+      padding: 0px 6px;
+      // background: #0054e9;
+      color: #0054e9;
+      border-radius: 4px;
+    }
+    .jj {
+      color: #c5000f;
+      margin-top: 4px;
+    }
+    .other {
+      color: #676767;
+    }
+  }
+}

+ 28 - 0
projects/live-app/src/modules/account/notice-log/notice-log.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 { NoticeLogComponent } from './notice-log.component';
+
+describe('NoticeLogComponent', () => {
+  let component: NoticeLogComponent;
+  let fixture: ComponentFixture<NoticeLogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ NoticeLogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(NoticeLogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 81 - 0
projects/live-app/src/modules/account/notice-log/notice-log.component.ts

@@ -0,0 +1,81 @@
+import { CommonModule, DatePipe } from '@angular/common';
+import { Component, OnInit } from '@angular/core';
+import { NavComponent } from '../../../app/components/nav/nav.component';
+import { AiChatService } from '../../../services/aichart.service';
+import {
+  ionicStandaloneModules,
+  LoadingController,
+  ToastController,
+} from '../../ionic-standalone.modules';
+import * as Parse from 'parse';
+import { InfiniteScrollCustomEvent } from '@ionic/core';
+import { Router } from '@angular/router';
+import { MessageService } from '../../../services/message.service';
+
+@Component({
+  selector: 'app-notice-log',
+  templateUrl: './notice-log.component.html',
+  styleUrls: ['./notice-log.component.scss'],
+  standalone: true,
+  imports: [...ionicStandaloneModules, NavComponent, CommonModule],
+  providers: [DatePipe],
+})
+export class NoticeLogComponent implements OnInit {
+  list: Array<any> = [];
+  user: Parse.Object = Parse.User.current()!;
+
+  constructor(
+    public toastController: ToastController,
+    private loadingCtrl: LoadingController,
+    private router: Router,
+    private msgSer: MessageService,
+    private aiSer: AiChatService
+  ) {}
+
+  ngOnInit() {
+    this.getLog();
+  }
+  async getLog() {
+    let uid: any = Parse.User.current()?.id;
+    let r = await this.aiSer.getSysNotice(uid, 20, this.list.length);
+    this.list.push(...r?.data);
+    return r?.data;
+  }
+  async onIonInfinite(ev: any) {
+    let uid: any = Parse.User.current()?.id;
+    let result = await this.aiSer.getSysNotice(uid, 20, this.list.length);
+    if (result.data.length == 0) {
+      (ev as InfiniteScrollCustomEvent).target.disabled = true;
+    }
+    setTimeout(() => {
+      (ev as InfiniteScrollCustomEvent).target.complete();
+    }, 500);
+  }
+  toUrl(url: string) {
+    this.router.navigate([url]);
+  }
+  async onApply(id: string, index: number, pass: boolean) {
+    let isAnthor = this.aiSer.identity
+    const loading = await this.loadingCtrl.create({
+      message: '加载中',
+    });
+    loading.present();
+    this.list[index].status = pass ? '200' : '101';
+    let query = new Parse.Query('Friends');
+    let res = await query.get(id);
+    res.set('isPass', pass);
+    if(pass){
+      let channel = isAnthor ? `${this.user.id}-${this.list[index].tuid}` : `${this.list[index].tuid}-${this.user.id}`
+      res.set('channel', channel)
+      this.msgSer.subscribeMessage(channel); //同意好友邀请并且订阅频道
+    }
+    await res.save();
+    loading.dismiss();
+    const toast = await this.toastController.create({
+      message: `已${pass ? '通过' : '拒绝'}申请`,
+      color: 'success',
+      duration: 1000,
+    });
+    toast.present();
+  }
+}

+ 17 - 7
projects/live-app/src/modules/live/chat/chat.component.html

@@ -34,13 +34,20 @@
   >
     <ng-template>
       <ion-list>
-        <ion-item class="clear" [button]="true" [detail]="false">
-          <ion-icon name="person-remove-outline"></ion-icon>加入黑名单</ion-item
+        @if (uid) {
+        <ion-item (click)="onRjects()" class="clear" [button]="true" [detail]="false">
+          <ion-icon name="person-remove-outline"></ion-icon
+          >{{ this.isRet?.id ? "移除黑名单" : "加入黑名单" }}</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-item
+          class="clear"
+          [button]="true"
+          [detail]="false"
+          (click)="deleteChatLog()"
           ><ion-icon name="trash-outline"></ion-icon>删除聊天记录</ion-item
         >
       </ion-list>
@@ -48,10 +55,10 @@
   </ion-popover>
 
   <div #scrollMsg id="scrollMsg" class="scroll">
-    @for (item of msgServe.messageMapList[channle]; track $index) {
+    @for (item of msgServe.messageMapList[channel]; track $index) {
     <div class="clearfix message-box">
       @if ($index == 0 || item.timestamp -
-      msgServe.messageMapList[channle][$index-1].timestamp > 600) {
+      msgServe.messageMapList[channel][$index-1].timestamp > 600) {
       <div class="time-box">
         @if (item.istoday) {
         <div class="time">{{ item.timestamp | showDate }}</div>
@@ -75,7 +82,7 @@
         <!-- 文字消息 msg_type == 1 || text -->
         @if (item.msg_type == 1 || item.msg_type == 'text') {
         <div class="msg-card">
-          @if(channle == 'global_room'){
+          @if(channel == 'global_room'){
           <span class="text-item_status">{{
             item.name || "用户" + item.publisher
           }}</span>
@@ -147,7 +154,10 @@
     >
       <ion-icon name="happy-outline" (click)="changeShowEmoji()"></ion-icon>
       @if (uid && profile?.get("identyType") === 'anchor') {
-      <ion-icon name="videocam-outline" (click)="call.toLiveContact()"></ion-icon>
+      <ion-icon
+        name="videocam-outline"
+        (click)="call.toLiveContact()"
+      ></ion-icon>
       } @if (uid && profile?.get("identyType") === 'anchor') {
       <ion-icon name="gift-outline" (click)="gift.openModal()"></ion-icon>
       }

+ 95 - 13
projects/live-app/src/modules/live/chat/chat.component.ts

@@ -12,6 +12,7 @@ import * as Parse from 'parse';
 import { GiftModalComponent } from '../../../app/components/gift-modal/gift-modal.component';
 import { MessageService } from '../../../services/message.service';
 import {
+  AlertController,
   ionicStandaloneModules,
   LoadingController,
   ScrollDetail,
@@ -33,14 +34,14 @@ import { CallModalComponent } from '../../../app/components/call-modal/call-moda
     GiftModalComponent,
     CommonModule,
     SharedModule,
-    CallModalComponent
+    CallModalComponent,
   ],
   // providers: [DatePipe],
 })
 export class ChatComponent implements OnInit {
   @ViewChild('call') call!: CallModalComponent;
 
-  channle: string = '';
+  channel: string = '';
   uid: string = '';
   profile?: Parse.Object; // 对方身份
   targetUser?: Parse.Object; // 对方用户
@@ -52,18 +53,22 @@ export class ChatComponent implements OnInit {
   timer: any;
   currentScroll: number = 0; //滚动条位置
   disabled: boolean = false;
-  level:any //权益
+  friend?: Parse.Object; //好友
+  isRet?: Parse.Object; //黑名单
+
+  level: any; //权益
   constructor(
     private router: Router,
     private http: HttpClient,
     // public datePipe: DatePipe,
     public toastController: ToastController,
+    private alertController: AlertController,
     private loadingCtrl: LoadingController,
     private activateRoute: ActivatedRoute,
     public msgServe: MessageService,
     public aiServ: AiChatService,
     public accServ: AccountService
-    ) {
+  ) {
     msgServe.pageFun = this.updatePage;
     msgServe.pageFun();
   }
@@ -71,13 +76,13 @@ export class ChatComponent implements OnInit {
   ngOnInit() {
     this.activateRoute.paramMap.subscribe(async (params) => {
       let id: any = params.get('id');
-      this.channle = id;
+      this.channel = id;
       if (id !== 'global_room') {
         const us = id.split('-');
         const current = Parse.User.current()?.id!;
         this.uid = us.find((item: string) => item !== current);
       }
-      if (!this.channle) {
+      if (!this.channel) {
         history.back();
         return;
       }
@@ -102,11 +107,19 @@ export class ChatComponent implements OnInit {
     });
     loading.present();
     await this.getProfile();
+    await this.getFriend();
     await this.msgServe.initRTM();
-    await this.msgServe.subscribeMessage(this.channle, {
-      message: true,
-      // presence: true,
-    }); //订阅消息
+    await this.msgServe.subscribeMessage(
+      this.channel,
+      {
+        message: true,
+        // presence: true,
+      },
+      this.friend?.get('config')?.[Parse.User.current()?.id!]
+    ); //订阅消息
+    if (this.uid) {
+      this.isRet = await this.aiServ.getRetFriends(this.uid);
+    }
     loading.dismiss();
   }
   /* 获取用户信息 */
@@ -128,10 +141,19 @@ export class ChatComponent implements OnInit {
       this.targetUser = await queryUser.first();
     }
   }
+  async getFriend() {
+    if (!this.uid) return;
+    let query = new Parse.Query('Friends');
+    query.equalTo('channel', this.channel);
+    query.equalTo('company', this.msgServe.company);
+    query.equalTo('isPass', true);
+    query.notEqualTo('isDeleted', true);
+    this.friend = await query.first();
+  }
   ngOnDestroy(): void {
     this.msgServe.pageFun = () => {};
     if (!this.uid) {
-      this.msgServe.unsubscribeMessage(this.channle);
+      this.msgServe.unsubscribeMessage(this.channel);
     }
   }
   /* 开始滑动 */
@@ -158,7 +180,7 @@ export class ChatComponent implements OnInit {
   }
   //调起表情
   changeShowEmoji(isClose?: boolean) {
-    if(!this.uid && !this.accServ.userVip?.rights?.['all-chat']) return
+    if (!this.uid && !this.accServ.userVip?.rights?.['all-chat']) return;
     this.showEmoji = isClose ? false : !this.showEmoji;
     this.height = 0;
   }
@@ -188,7 +210,7 @@ export class ChatComponent implements OnInit {
     });
   }
   async send(param: { msg_type: string; content: string }) {
-    await this.msgServe.publishMessage(param.content, this.channle);
+    await this.msgServe.publishMessage(param.content, this.channel);
     this.text = '';
     this.disabled = false;
   }
@@ -214,4 +236,64 @@ export class ChatComponent implements OnInit {
   toUrl(url: string) {
     this.router.navigateByUrl(url);
   }
+
+  async deleteChatLog() {
+    const alert = await this.alertController.create({
+      cssClass: 'my-custom-class',
+      header: '',
+      message: '你确定删除聊天记录吗?',
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel',
+          handler: () => {},
+        },
+        {
+          text: '确定',
+          cssClass: 'secondary',
+          handler: async (blah) => {
+            console.log('Confirm Cancel: blah');
+            if (this.uid && this.friend?.id) {
+              let uid = Parse.User.current()?.id!;
+              let config = this.friend?.get('config') || {};
+              config[uid] = new Date()?.getTime();
+              this.friend.set('config', config);
+              await this.friend.save();
+            }
+            this.msgServe.delMsg(this.channel);
+          },
+        },
+      ],
+    });
+    await alert.present();
+  }
+
+  async onRjects() {
+    const alert = await this.alertController.create({
+      cssClass: 'my-custom-class',
+      header: '',
+      message: `你确定${this.isRet?.get('isAward') ? '移除对方为黑名单列表' : '加入对方为黑名单列表'}吗?`,
+      buttons: [
+        {
+          text: '取消',
+          role: 'cancel',
+          handler: () => {},
+        },
+        {
+          text: '确定',
+          cssClass: 'secondary',
+          handler: async (blah) => {
+            if (!this.isRet?.id) {
+              let obj = Parse.Object.extend('EventLog');
+              this.isRet = new obj();
+              this.isRet?.set('isAward', !this.isRet?.get('isAward'));
+              await this.isRet?.save();
+            }
+            this.msgServe.delMsg(this.channel);
+          },
+        },
+      ],
+    });
+    await alert.present();
+  }
 }

+ 1 - 1
projects/live-app/src/modules/login/agreement/agreement.component.html

@@ -1,7 +1,7 @@
 <ion-header>
   <ion-toolbar>
     <ion-buttons slot="end" (click)="dismiss()">
-      <div style="margin-right: 20px">已了解</div>
+      <div style="margin-right: 20px">已知晓</div>
     </ion-buttons>
   </ion-toolbar>
 </ion-header>

+ 1 - 1
projects/live-app/src/modules/login/login.component.html

@@ -245,7 +245,7 @@
     <div class="agreement">
       <ion-checkbox color="primary" [(ngModel)]="agreement"></ion-checkbox>
       <div class="content">
-        注册即代表同意<span (click)="showAgreement()"
+        我已阅读且同意<span (click)="showAgreement()"
           >《{{registerAgreement?.get('title')}}》</span
         >
       </div>

+ 3 - 3
projects/live-app/src/modules/login/login.component.scss

@@ -165,11 +165,11 @@ ion-content {
       width: 84vw;
       height: 13.333vw;
       display: flex;
-      align-items: flex-start;
+      align-items: center;
       justify-content: center;
       font-size: 4vw;
       font-weight: 400;
-      color: #9f9f9f;
+      color: #2e2e2e;
       margin-top: 6.667vw;
       margin-bottom: 6.667vw;
       span {
@@ -177,7 +177,7 @@ ion-content {
       }
       .content {
         margin-left: 2.667vw;
-        width: 90%;
+        // width: 90%;
       }
       ion-checkbox {
         --background: #108ee9;

+ 2 - 2
projects/live-app/src/modules/login/login.component.ts

@@ -354,7 +354,7 @@ export class LoginComponent implements OnInit {
     headers.set('Access-Control-Allow-Origin', '*');
     this.http
       .post(
-        `https://server.fmode.cn/api/reset_password`,
+        `https://server.fmode.cn/api/auth/reset_password`,
         {
           company: this.company,
           code: this.reset.code,
@@ -367,7 +367,7 @@ export class LoginComponent implements OnInit {
         catchError(async (e) => {
           // 显示报错
           const toast = await this.toastController.create({
-            message: e.message,
+            message: e.error?.mess || '服务器错误',
             color: 'danger',
             duration: 1000,
           });

+ 1 - 1
projects/live-app/src/modules/tabs/home/home.component.html

@@ -75,7 +75,7 @@
       </div>
       <ion-icon
         (click)="isColumn = !isColumn"
-        [name]="isColumn ? 'grid' : 'list'"
+        [name]="!isColumn ? 'grid' : 'list'"
         style="font-size: 24px; color: #fe4d53"
       ></ion-icon>
     </div>

+ 2 - 2
projects/live-app/src/modules/tabs/notice/notice.component.html

@@ -41,7 +41,7 @@
     <ion-segment-content id="notice">
       <div class="notice-list" (touchmove)="onMousemove($event)">
         <ion-list>
-          <ion-item class="li" (click)="toUrl('/live/chat')">
+          <ion-item class="li" (click)="toUrl('/account/noticelog')">
             <img
               src="img/notice.png"
               class="avatar"
@@ -53,7 +53,7 @@
                 系统消息
                 <!-- <span class="time">{{ item.createdAt | showDate }}</span> -->
               </div>
-              <div class="message-content">{{ "暂无" }}</div>
+              <!-- <div class="message-content">{{ "暂无" }}</div> -->
             </div>
             <ion-icon
               style="color: #afafaf"

+ 1 - 1
projects/live-app/src/modules/tabs/notice/notice.component.ts

@@ -58,7 +58,7 @@ export class NoticeComponent implements OnInit {
     // let resChat = await this.aiSer.getLinkUsers(uid);
     // resChat?.data && this.noticeList.push(...resChat.data);
     this.getSetting();
-    this.getSysNotice()
+    // this.getSysNotice()
   }
   async getSetting() {
     let query = new Parse.Query('SiteConfig');

+ 67 - 36
projects/live-app/src/services/aichart.service.ts

@@ -9,31 +9,14 @@ export class AiChatService {
   isLoggedIn = false;
   company: string = 'Qje9D4bqol';
   emojis: Array<any> = [];
-
+  get identity(): boolean {
+    let profile = JSON.parse(localStorage.getItem('profile') || '{}');
+    return profile?.identyType === 'anchor';
+  }
   constructor(private http: HttpService) {
     this.initEmoji();
   }
-  async getAccountLog(): Promise<any> {
-    const uid = Parse.User.current()?.id;
-    let query = new Parse.Query('Account');
-    query.equalTo('user', uid);
-    query.notEqualTo('isDeleted', true);
-    query.select('objectId');
-    let account = await query.first();
-    if (!account?.id) {
-      return;
-    }
-    let sql = `SELECT alog."assetCount",TO_CHAR(alog."createdAt", 'YYYY-MM-DD HH24:MI:SS') AS time,
-    (CASE WHEN alog."targetAccount" = '${account.id}' THEN 'recharge' ELSE 'used' END) cate,
-    "assetType","orderNumber","desc"
-    FROM "AccountLog" AS alog
-    WHERE (alog."targetAccount" = '${account.id}' OR alog."fromAccount" = '${account.id}')
-    AND alog."isVerified" IS TRUE
-    AND alog."isDeleted" IS NOT TRUE
-    ORDER BY alog."createdAt" DESC`;
-    let data: any = await this.http.customSQL(sql);
-    return data?.data;
-  }
+
   initEmoji() {
     let emojiChar =
       '☺-😋-😌-😍-😏-😜-😝-😞-😔-😪-😁-😂-😃-😅-😆-👿-😒-😓-😔-😏-😖-😘-😚-😒-😡-😢-😣-😤-😢-😨-😳-😵-😷-😸-😻-😼-😽-😾-😿-🙊-🙋-🙏-✈-🚇-🚃-🚌-🍄-🍅-🍆-🍇-🍈-🍉-🍑-🍒-🍓-🐔-🐶-🐷-👦-👧-👱-👩-👰-👨-👲-👳-💃-💄-💅-💆-💇-🌹-💑-💓-💘-🚲';
@@ -126,6 +109,27 @@ export class AiChatService {
     }
     this.emojis = emojis;
   }
+  async getAccountLog(): Promise<any> {
+    const uid = Parse.User.current()?.id;
+    let query = new Parse.Query('Account');
+    query.equalTo('user', uid);
+    query.notEqualTo('isDeleted', true);
+    query.select('objectId');
+    let account = await query.first();
+    if (!account?.id) {
+      return;
+    }
+    let sql = `SELECT alog."assetCount",TO_CHAR(alog."createdAt", 'YYYY-MM-DD HH24:MI:SS') AS time,
+    (CASE WHEN alog."targetAccount" = '${account.id}' THEN 'recharge' ELSE 'used' END) cate,
+    "assetType","orderNumber","desc"
+    FROM "AccountLog" AS alog
+    WHERE (alog."targetAccount" = '${account.id}' OR alog."fromAccount" = '${account.id}')
+    AND alog."isVerified" IS TRUE
+    AND alog."isDeleted" IS NOT TRUE
+    ORDER BY alog."createdAt" DESC`;
+    let data: any = await this.http.customSQL(sql);
+    return data?.data;
+  }
   async getWallet(uid: string): Promise<any> {
     const data = await this.http.httpRequst(
       'https://server.fmode.cn/api/ailiao/wallet',
@@ -175,36 +179,64 @@ export class AiChatService {
     const data: any = await this.http.customSQL(sql);
     return data.data;
   }
-  getFriends(uid: string): Promise<any> {
-    let sql = `SELECT u.avatar,u.nickname,u."objectId" AS uid,f."channel"
+  /* 获取好友列表 */
+  async getFriends(uid: string): Promise<any> {
+    let rejectsSql = `SELECT invited FROM "EventLog" WHERE "isDeleted" IS NOT TRUE AND "user" = '${uid}' AND "isAward" = TRUE `;
+    let data: any = await this.http.customSQL(rejectsSql);
+    let list = data.data;
+    let notInclude = list?.map((item: any) => {
+      return `'${item.invited}'`;
+    });
+    let sql = `SELECT u.avatar,u.nickname,u."objectId" AS uid,f."channel",
+    f.deadline
      FROM 
-      (SELECT (CASE WHEN "friend" = '${uid}' THEN "user" ELSE "friend" END) fid,"channel"
+      (SELECT (CASE WHEN "friend" = '${uid}' THEN "user" ELSE "friend" END) fid,"channel",
+	     "Friends".config->'l0gF95BPLB' AS deadline --被删除的聊天记录时间
       FROM "Friends"
       WHERE "isDeleted" IS NOT TRUE
       AND "isPass" = TRUE
       AND ("friend" = '${uid}'
       OR "user" = '${uid}')
-      GROUP BY fid,"channel") AS f
+      GROUP BY fid,"channel",deadline) AS f
     LEFT JOIN "_User" AS u
     ON u."objectId" = f.fid
+    ${notInclude.length > 0 ? `WHERE u."objectId" NOT IN (${notInclude})` : ''}
     `;
     return this.http.customSQL(sql);
   }
 
-
+  async getRetFriends(uid: string): Promise<Parse.Object | undefined> {
+    let query = new Parse.Query('EventLog');
+    query.equalTo('user', Parse.User.current()?.id);
+    query.equalTo('invited', uid);
+    query.notEqualTo('isDeleted', false);
+    query.equalTo('isAward', true);
+    query.select('objectId');
+    return await query.first();
+  }
   /* 获取系统通知 */
-  getSysNotice(uid: string): Promise<any> {
+  getSysNotice(uid: string, limit?: number, skip?: number): Promise<any> {
     let sql = `SELECT
-    (CASE WHEN "user" = 'l0gF95BPLB' THEN '请求添加'+u.name+'为好友'
-	ELSE '收到'+u.name+'的好友申请' END) title,
+    "Friends"."objectId" fid,"friend","Friends"."user",
+    (CASE WHEN "user" = '${uid}' THEN '请求添加' || u.name ||'为好友'
+	  ELSE '收到'||us.name||'的好友申请' END) title,
+    (CASE WHEN "user" = '${uid}' THEN us.avatar
+	  ELSE u.avatar END) avatar,
+    (CASE WHEN "user" = '${uid}' THEN us."objectId"
+	  ELSE u."objectId" END) tuid,
     (CASE WHEN "isPass" = TRUE THEN '200'
-     WHEN "isPass" = FALSE THEN '101'
-    ELSE '100' END) status
+    WHEN "isPass" = FALSE THEN '101'
+    ELSE '100' END) status,
+    "Friends"."createdAt"
     FROM "Friends"
-    WHERE "company" = '${this.company}'
+	  LEFT JOIN "_User" AS u
+    ON u."objectId" = "Friends"."user"
+	  LEFT JOIN "_User" AS us
+    ON us."objectId" = "Friends"."friend"
+    WHERE "Friends"."company" = '${this.company}'
     AND (friend = '${uid}' OR "user" = '${uid}')
-    ORDER BY "createdAt" DESC`;
-    console.log(sql);
+    ORDER BY "Friends"."createdAt" DESC
+    OFFSET ${skip || 0} LIMIT ${limit || 20}`;
     return this.http.customSQL(sql);
   }
 
@@ -274,7 +306,6 @@ export class AiChatService {
     let res: any = await this.http.customSQL(sql);
     return res.data[0]?.sum;
   }
-  
 
   async get_duration(rid: string, uid: string) {
     let url = 'https://server.fmode.cn/api/ailiao/remain_second';

+ 71 - 33
projects/live-app/src/services/auth.service.ts

@@ -3,6 +3,8 @@ import * as Parse from 'parse';
 import { Router } from '@angular/router';
 import { MessageService } from './message.service';
 import { ConnectTaskService } from './connectTask.service';
+import { HttpClient } from '@angular/common/http';
+import { catchError } from 'rxjs/operators';
 @Injectable({
   providedIn: 'root',
 })
@@ -12,7 +14,8 @@ export class AuthService {
   constructor(
     private connectTask: ConnectTaskService,
     private router: Router,
-    private msgSer: MessageService
+    private msgSer: MessageService,
+    private http: HttpClient
   ) {}
   authMobile(
     mobile: string,
@@ -22,39 +25,74 @@ export class AuthService {
     register?: boolean
   ) {
     return new Promise((resolve, reject) => {
-      Parse.Cloud.run('auth_mobile', {
-        c: this.company,
-        mobile: mobile,
-        password: password,
-        code: code,
-        register: register,
-        nickname: nickname,
-      })
-        .then((authData) => {
-          // console.log(authData);
-          if (authData) {
-            // let sessionToken = authData.get('sessionToken');
-            Parse.User.become(authData)
-              .then(async (data) => {
-                // console.log(data);
-                await this.getProfile()
-                await this.connectTask.init();
-                this.redirectUrl = this.redirectUrl ? this.redirectUrl : 'tabs';
-                this.router.navigate([this.redirectUrl]);
-                resolve(data);
-              })
-              .catch((err) => {
-                console.error(err);
-                reject('登录失败,token已过期');
-              });
-          } else {
-            reject(authData.message);
-          }
+      if (password) {
+        Parse.Cloud.run('auth_mobile', {
+          c: this.company,
+          mobile: mobile,
+          password: password,
+          code: code,
+          register: register,
+          nickname: nickname,
         })
-        .catch((err) => {
-          console.error(err.message);
-          reject(err.message);
-        });
+          .then((authData) => {
+            // console.log(authData);
+            if (authData) {
+              // let sessionToken = authData.get('sessionToken');
+              Parse.User.become(authData)
+                .then(async (data) => {
+                  // console.log(data);
+                  await this.getProfile();
+                  await this.connectTask.init();
+                  this.redirectUrl = this.redirectUrl
+                    ? this.redirectUrl
+                    : 'tabs';
+                  this.router.navigate([this.redirectUrl]);
+                  resolve(data);
+                })
+                .catch((err) => {
+                  console.error(err);
+                  reject('登录失败,token已过期');
+                });
+            } else {
+              reject(authData.message);
+            }
+          })
+          .catch((err) => {
+            // console.error(err.message);
+            reject(err.message);
+          });
+      } else {
+        this.http
+          .get(
+            `https://server.fmode.cn/api/auth/mobile?company=${this.company}&mobile=${mobile}&code=${code}`
+          )
+          .pipe(catchError(async (e) => {
+            console.log(e);
+            reject(e?.error.mess || '登录失败,服务器错误');
+          }))
+          .subscribe((res: any) => {
+            console.log(res);
+            if (res.code == 200) {
+              Parse.User.become(res.data.token)
+                .then(async (data) => {
+                  console.log(data);
+                  await this.getProfile();
+                  await this.connectTask.init();
+                  this.redirectUrl = this.redirectUrl
+                    ? this.redirectUrl
+                    : 'tabs';
+                  this.router.navigate([this.redirectUrl]);
+                  resolve(data);
+                })
+                .catch((err) => {
+                  // console.error(err);
+                  reject('登录失败,token已过期');
+                });
+            } else {
+              reject(res?.mess);
+            }
+          });
+      }
     });
   }
   async getProfile() {

+ 2 - 1
projects/live-app/src/services/connectTask.service.ts

@@ -10,6 +10,7 @@ export class ConnectTaskService {
   msChannelName: string = 'user_connect_room'; // 主播在线上报频道
   onlineUserList = new Set(); // 在线用户列表
   isSubscribe: boolean = false;
+
   constructor(private msgSer: MessageService, private aiSer: AiChatService) {}
 
   async init() {
@@ -60,7 +61,7 @@ export class ConnectTaskService {
       let channelName = item.channel;
       await this.msgSer.subscribeMessage(channelName, {
         message: true,
-      });
+      },item.deadline);
     });
   }
   /* 获取用户当前所在频道 */

+ 11 - 5
projects/live-app/src/services/message.service.ts

@@ -296,7 +296,7 @@ export class MessageService {
     });
   }
   /* 订阅消息 */
-  subscribeMessage(channelName: string, param?: any, callback?: any) {
+  subscribeMessage(channelName: string, param?: any,deadline?: number) {
     if (this.channelNameList[channelName]) return;
     return new Promise((resolve, reject) => {
       const options = {
@@ -307,7 +307,7 @@ export class MessageService {
         withLock: false, // lock 事件
       };
       this.rtmClient
-        .subscribe(channelName, options)
+        ?.subscribe(channelName, options)
         .then((res: any) => {
           console.log('subscribeMessage', res);
           //订阅成功
@@ -315,7 +315,7 @@ export class MessageService {
           if (!this.messageMapList[channelName]) {
             this.messageMapList[channelName] = [];
             if(channelName.indexOf('-') > -1 || channelName == 'global_room'){
-              this.getHistoryMessage(channelName);
+              this.getHistoryMessage(channelName,deadline);
             }
           }
           this.pageFun?.();
@@ -328,13 +328,14 @@ export class MessageService {
     });
   }
 
-  async getHistoryMessage(channelName: string) {
+  async getHistoryMessage(channelName: string,deadline?:number) {
     let query = new Parse.Query('MessageLog');
     query.equalTo('channel', channelName);
     query.descending('createdAt');
     query.skip(this.messageMapList[channelName].length);
     query.limit(50);
     query.select('content', 'from_id');
+    deadline && query.greaterThanOrEqualTo('createdAt', new Date(deadline));
     let msgList = await query.find();
     console.log('历史消息:', msgList);
     msgList.forEach((item: any) => {
@@ -350,7 +351,7 @@ export class MessageService {
   /* 取消订阅 */
   unsubscribeMessage(channelName: string) {
     this.rtmClient
-      .unsubscribe(channelName)
+      ?.unsubscribe(channelName)
       .then((res: any) => {
         console.log('unsubscribeMessage', res);
         //订阅成功
@@ -458,4 +459,9 @@ export class MessageService {
       console.log('发出消息失败:', status);
     }
   }
+
+  delMsg(channelName: string, index?: number,limit?: number) {
+    this.messageMapList[channelName].splice(index ?? 0, limit ?? this.messageMapList[channelName].length);
+    console.log(this.messageMapList[channelName]);
+  }
 }