warrior 6 dní pred
rodič
commit
5d7bdd4a72

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

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

+ 13 - 0
projects/live-app/src/app/components/nav/nav.component.html

@@ -0,0 +1,13 @@
+<ion-header [translucent]="true" class="header">
+  <ion-toolbar class="toolbar">
+    @if (type == 'back') {
+      <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">{{title}}</ion-title>
+  </ion-toolbar>
+</ion-header>

+ 0 - 0
projects/live-app/src/app/components/nav/nav.component.scss


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

+ 22 - 0
projects/live-app/src/app/components/nav/nav.component.ts

@@ -0,0 +1,22 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { IonicModule } from '@ionic/angular';
+
+@Component({
+  selector: 'nav',
+  templateUrl: './nav.component.html',
+  styleUrls: ['./nav.component.scss'],
+  standalone: true,
+  imports: [IonicModule],
+})
+export class NavComponent implements OnInit {
+  @Input('type') type: string = 'back';
+  @Input('title') title: string = '';
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+  onBack(){
+    history.back()
+  }
+}

+ 1 - 11
projects/live-app/src/moduls/account/bankcard/bankcard.component.html

@@ -1,14 +1,4 @@
-<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">我的银行卡</ion-title>
-  </ion-toolbar>
-</ion-header>
+<nav title="我的银行卡"></nav>
 
 <div class="notice_list">
   <div class="card_list">

+ 2 - 4
projects/live-app/src/moduls/account/bankcard/bankcard.component.ts

@@ -1,4 +1,5 @@
 import { Component, OnInit } from '@angular/core';
+import { NavComponent } from '../../../app/components/nav/nav.component';
 
 import * as Parse from 'parse';
 import { HttpClient } from '@angular/common/http';
@@ -8,7 +9,7 @@ import { IonicModule, ToastController } from '@ionic/angular';
   templateUrl: './bankcard.component.html',
   styleUrls: ['./bankcard.component.scss'],
 	standalone: true,
-  imports: [IonicModule],
+  imports: [IonicModule,NavComponent],
 })
 export class BankcardComponent implements OnInit {
   constructor(
@@ -157,7 +158,4 @@ export class BankcardComponent implements OnInit {
   addCard() {
     this.isModalOpen = true;
   }
-  onBack(){
-    history.back()
-  }
 }

+ 1 - 11
projects/live-app/src/moduls/account/wattle/wattle.component.html

@@ -1,14 +1,4 @@
-<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">我的钱包</ion-title>
-  </ion-toolbar>
-</ion-header>
+<nav title="我的钱包"></nav>
 <ion-content class="content">
   <div class="top">
     <div class="box">

+ 2 - 4
projects/live-app/src/moduls/account/wattle/wattle.component.ts

@@ -2,13 +2,14 @@ import { Component, OnInit } from '@angular/core';
 import { IonicModule } from '@ionic/angular';
 import * as Parse from 'parse';
 import { Router, ActivatedRoute } from '@angular/router';
+import { NavComponent } from '../../../app/components/nav/nav.component';
 
 @Component({
   selector: 'app-wattle',
   templateUrl: './wattle.component.html',
   styleUrls: ['./wattle.component.scss'],
   standalone: true,
-  imports: [IonicModule],
+  imports: [IonicModule,NavComponent],
 })
 export class WattleComponent implements OnInit {
   company: any = localStorage.getItem('company');
@@ -56,7 +57,4 @@ export class WattleComponent implements OnInit {
   toBank() {
     this.router.navigate(['account/bankcard'])
   }
-  onBack(){
-    history.back()
-  }
 }

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

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { VipComponent } from './vip/vip.component';
+const routes: Routes = [
+  {
+    path: '',
+    redirectTo:'idcard',
+    pathMatch: "full",
+  },
+  {
+    path: 'vip',//实名
+    component: VipComponent,
+  },
+
+]
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class GoodsRoutingModule { }

+ 82 - 0
projects/live-app/src/moduls/goods/vip/vip.component.html

@@ -0,0 +1,82 @@
+<nav title="会员购买"></nav>
+<ion-content class="content">
+  @if (vips.length > 0) {
+  <div class="combo_index">
+    <div class="combo-info">
+      <img class="img" [src]="user?.get('avatar')" mode="aspectFill" />
+      <div class="name">{{ user.name ? user.name : user.nickname }}</div>
+      <div class="text-info">
+        <div class="text-top">
+          @if (myVip) {
+          <div class="text1">
+            {{ myVip.validity ? myVip.grade : "会员已过期" }}
+          </div>
+          } @else{
+          <div class="text1">未开通</div>
+          }
+          <!-- <div class="text2">
+            钥匙:{{ account.seeKeys ? account.seeKeys : 0 }}
+          </div>
+          <div class="text3">
+            牵线次数:{{ account.together ? account.together : 0 }}
+          </div>
+          <div class="text3">
+            金币余额:{{ account.credit ? account.credit : 0 }}
+          </div> -->
+        </div>
+        <div class="text-bot">
+          @if (myVip) {
+          <div class="date">有效期至:{{ myVip.expiredAt }}</div>
+          }
+        </div>
+      </div>
+    </div>
+    @for (item of vips; track $index) {
+    <div
+      class="combo_box1 {{
+        item.id == currentGoods?.id ? 'combo_box1-currentGoods' : ''
+      }}"
+      (click)="onchang(item)"
+    >
+      <div class="title">
+        <div class="title-top">{{ item?.get("name") }}</div>
+        <div class="price">¥{{ item?.get("price") }}</div>
+      </div>
+      <div class="title-info">
+        <div style="width: 100%" [innerHTML]="item?.get('details')"></div>
+      </div>
+    </div>
+    }
+
+    <div class="member-title">会员服务说明</div>
+    <div class="member-text">
+      让找对象更轻松,找缘来有你来办会员吧,可以帮你快速脱单哦~
+    </div>
+    <div class="time-limit">会员购买期限</div>
+    <div class="limit-text">
+      :请务必在有效期内使用完钥匙、金币、牵线,过期后所有服务都将清零,钥匙可以用来查看嘉宾的联系方式、金币可以用来置顶资料以及给嘉宾赠送虚拟礼物、牵线可以用来让红娘帮你联系嘉宾。
+    </div>
+    <div class="refund">关于退款说明</div>
+    <div class="refund-text">
+      :会员服务为虚拟产品,因此购买之后无法进行退换货,因此购买前请慎重。
+    </div>
+    <div class="violation">会员违规说明</div>
+    @if (vips && vips.length > 0) {
+      <div class="violation-text">
+        {{ tips[0] }}
+        <div>
+          {{ tips[1] }}
+        </div>
+      </div>
+    }
+
+    <div class="price-info">
+      <div class="price-tab">
+        <div class="text">总计</div>
+        <div class="price">¥{{ currentGoods?.get('price') }}</div>
+      </div>
+      <div class="comfirm" bind:tap="openPay">确认支付</div>
+    </div>
+  </div>
+  }
+</ion-content>

+ 190 - 0
projects/live-app/src/moduls/goods/vip/vip.component.scss

@@ -0,0 +1,190 @@
+.content {
+  .combo_index {
+    background-color: #f6f6f6;
+    padding-bottom: 100px;
+    .combo-info {
+      width: 100%;
+      height: 180px;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      padding: 10px;
+      background: linear-gradient(#ffffff, #f96464);
+      .img {
+        width: 70px;
+        height: 70px;
+      }
+
+      .name {
+        font-size: 14px;
+        color: #ffffff;
+        text-align: center;
+        margin-top: 10px;
+      }
+
+      .text-info {
+        width: 300px;
+        display: flex;
+        flex-wrap: inherit;
+        color: white;
+        flex-direction: column;
+        font-size: 12px;
+        margin: 10px auto 5px;
+        .text-top {
+          display: flex;
+          justify-content: space-evenly;
+        }
+        .text-bot {
+          font-size: 12px;
+          display: flex;
+          justify-content: center;
+          color: #e6e6e6;
+        }
+      }
+    }
+
+    .combo_box1 {
+      width: 345px;
+      // height: 380px;
+      border: 1px solid #ff5c64;
+      border-radius: 12px;
+      margin: 10px auto;
+      padding: 10px;
+
+      .title {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+
+        .title-top {
+          font-size: 18px;
+          color: #222222;
+          font-weight: 700;
+          // margin: 22px;
+        }
+
+        .price {
+          font-size: 24px;
+          color: #ff5c64;
+          font-weight: 700;
+        }
+      }
+    }
+
+    .combo_box1-active {
+      background-color: #ffe5e7;
+    }
+
+    .member-title {
+      font-size: 18px;
+      color: #222222;
+      font-weight: bold;
+      width: 345px;
+      margin: 0px auto 10px;
+    }
+
+    .member-text {
+      width: 345px;
+      margin: 0px auto 10px;
+      color: #222222;
+      line-height: 18px;
+      font-size: 12x;
+    }
+
+    .member-tab1 {
+      padding: 10px;
+
+      .member-title1 {
+        font-size: 14px;
+        color: #ff5c64;
+      }
+    }
+
+    .time-limit {
+      width: 345px;
+      background-color: #ff5c64;
+      margin: 10px auto;
+      font-size: 14px;
+      padding: 10px;
+    }
+
+    .limit-text {
+      width: 345px;
+      margin: 1px auto;
+      color: #222222;
+      line-height: 18px;
+      font-size: 12px;
+    }
+
+    .refund {
+      width: 345px;
+      background-color: #ff5c64;
+      margin: 10px auto;
+      font-size: 14px;
+      padding: 8px 10px;
+    }
+
+    .refund-text {
+      width: 345px;
+      margin: 10px auto;
+      color: #222222;
+      line-height: 18px;
+      font-size: 12px;
+    }
+
+    .violation {
+      width: 345px;
+      background-color: #ff5c64;
+      margin: 10px auto;
+      font-size: 14px;
+      padding: 8px 10px;
+    }
+
+    .violation-text {
+      width: 345px;
+      margin: 10px auto;
+      color: #222222;
+      line-height: 18px;
+      font-size: 12px;
+    }
+  }
+  .price-info {
+    position: fixed;
+    bottom: 0;
+    display: flex;
+    width: 100%;
+    height: 48px;
+    margin-top: 50px;
+
+    .price-tab {
+      width: 250px;
+      height: 48px;
+      display: flex;
+      background-color: #ffffff;
+      flex: 1;
+      .text {
+        font-size: 18px;
+        padding: 16px;
+        color: #222222;
+        font-weight: 500;
+      }
+
+      .price {
+        font-size: 18px;
+        color: #ff5c64;
+        padding-top: 18px;
+      }
+    }
+
+    .comfirm {
+      width: 120px;
+      height: 48px;
+      background-color: #ff5c64;
+      font-size: 18px;
+      color: #ffffff;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+    }
+  }
+}

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

+ 75 - 0
projects/live-app/src/moduls/goods/vip/vip.component.ts

@@ -0,0 +1,75 @@
+import { Component, OnInit } from '@angular/core';
+import { IonicModule } from '@ionic/angular';
+import { NavComponent } from '../../../app/components/nav/nav.component';
+import * as Parse from 'parse';
+import { AuthService } from '../../../services/auth.service';
+import { DatePipe } from '@angular/common';
+
+@Component({
+  selector: 'app-vip',
+  templateUrl: './vip.component.html',
+  styleUrls: ['./vip.component.scss'],
+  standalone: true,
+  imports: [IonicModule, NavComponent],
+  providers: [DatePipe],
+})
+export class VipComponent implements OnInit {
+  user: any = Parse.User.current();
+  vips: Array<Parse.Object> = [];
+  profile?: Parse.Object;
+  account?: Parse.Object;
+  myVip: any;
+  currentGoods?: Parse.Object; //当前选择的会员
+  tips: Array<string> = [
+    ' :会员承诺书本人自愿参加“心上人”线上高端单身俱乐部活动。遵守言责自负、文责自负的原则,另本人自愿做出如下承诺:一、严格遵守国家法律法规,遵守社会公德,承诺本人无违法犯罪行为。若有隐瞒,后果自负。二、恪守诚信,保证我所提供的报名内容真实、准确、无欺诈成份。否则,愿意接受法律的制裁。',
+  ];
+  constructor(private authSer: AuthService, private datePipe: DatePipe) {}
+
+  ngOnInit() {
+    this.refresh()
+  }
+  refresh() {
+    this.getGoods();
+    this.getUserVip();
+  }
+  //获取当前VIP等级
+  async getUserVip() {
+    let vip = new Parse.Query('UserVip');
+    vip.equalTo('user', Parse.User.current()?.id);
+    vip.equalTo('company', this.authSer.company);
+    let reqVip = await vip.first();
+    if (reqVip && reqVip.id) {
+      let myVip = reqVip.toJSON();
+      let now = new Date().getTime();
+      let lastDate = new Date(myVip?.['expiredAt'].iso).getTime();
+      myVip['expiredAt'] = this.datePipe.transform(
+        myVip?.['expiredAt'].iso,
+        'yyyy-MM-dd'
+      );
+      if (lastDate >= now) {
+        myVip['validity'] = true;
+      }
+      this.myVip;
+    }
+  }
+  async getGoods() {
+    let goods = new Parse.Query('ShopGoods');
+    goods.equalTo('company', this.authSer.company);
+    goods.equalTo('type', 'vip');
+    goods.equalTo('status', true);
+    goods.ascending('top');
+    let res = await goods.find();
+    this.vips = res;
+    this.currentGoods = this.vips[0];
+  }
+  //获取用户账户信息
+  async getAccount() {
+    let queryAccount = new Parse.Query('Account');
+    queryAccount.equalTo('user', Parse.User.current()?.id);
+    let res = await queryAccount.first();
+    this.account = res;
+  }
+  onchang(data: Parse.Object) {
+    this.currentGoods = data;
+  }
+}

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

@@ -52,7 +52,7 @@
       <div class="text">爱聊 <span>VIP</span></div>
       <p>开通爱聊VIP,解锁海量专属主播聊天。</p>
     </div>
-    <div class="btn">立即开通</div>
+    <div class="btn" (click)="toUrl('goods/vip')">立即开通</div>
   </div>
   <div class="tool">
     @for (item of tools; track $index) {

+ 1 - 11
projects/live-app/src/moduls/user/album/album.component.html

@@ -1,14 +1,4 @@
-<ion-header [translucent]="true" class="header">
-  <ion-toolbar class="toolbar">
-    <ion-buttons slot="start" (click)="back()">
-      <ion-icon
-        name="chevron-back-outline"
-        style="width: 6.4vw; height: 6.4vw; color: #000000"
-      ></ion-icon>
-    </ion-buttons>
-    <ion-title class="title">我的相册</ion-title>
-  </ion-toolbar>
-</ion-header>
+<nav title="我的相册"></nav>
 <ion-content class="content">
   @if (loading) {
   <div class="upload">

+ 2 - 4
projects/live-app/src/moduls/user/album/album.component.ts

@@ -5,6 +5,7 @@ import {
   ToastController,
 } from '@ionic/angular';
 import * as Parse from 'parse';
+import { NavComponent } from '../../../app/components/nav/nav.component';
 import { UploadComponent } from '../../../app/components/upload/upload.component';
 import { AuthService } from '../../../services/auth.service';
 
@@ -13,7 +14,7 @@ import { AuthService } from '../../../services/auth.service';
   templateUrl: './album.component.html',
   styleUrls: ['./album.component.scss'],
   standalone: true,
-  imports: [IonicModule, UploadComponent],
+  imports: [IonicModule, UploadComponent,NavComponent],
 })
 export class AlbumComponent implements OnInit {
   files: any = [];
@@ -62,7 +63,4 @@ export class AlbumComponent implements OnInit {
     });
     toast.present();
   }
-  back() {
-    history.back();
-  }
 }

+ 1 - 11
projects/live-app/src/moduls/user/certification/certification.component.html

@@ -1,14 +1,4 @@
-<ion-header [translucent]="true" class="header">
-  <ion-toolbar class="toolbar">
-    <ion-buttons slot="start" (click)="back()">
-      <ion-icon
-        name="chevron-back-outline"
-        style="width: 6.4vw; height: 6.4vw; color: #000000"
-      ></ion-icon>
-    </ion-buttons>
-    <ion-title class="title">实名认证</ion-title>
-  </ion-toolbar>
-</ion-header>
+<nav title="实名认证"></nav>
 <ion-content class="content">
   <div class="hred">
     <div class="hred-left">

+ 3 - 5
projects/live-app/src/moduls/user/certification/certification.component.ts

@@ -5,13 +5,14 @@ import { HttpService } from '../../../services/http.service';
 import * as utils from '../../../services/utils'
 import { AgreementComponent } from '../../login/agreement/agreement.component';
 import * as Parse from 'parse';
+import { NavComponent } from '../../../app/components/nav/nav.component';
 
 @Component({
   selector: 'app-certification',
   templateUrl: './certification.component.html',
   styleUrls: ['./certification.component.scss'],
   standalone: true,
-  imports: [IonicModule,FormsModule],
+  imports: [IonicModule,FormsModule,NavComponent],
 })
 export class CertificationComponent implements OnInit {
 
@@ -69,9 +70,6 @@ export class CertificationComponent implements OnInit {
     });
     return await modal.present();
   }
-  back() {
-    history.back()
-  }
 
   async presentToast(title:string, time:number, color:string) {
     const toast = await this.toastController.create({
@@ -157,7 +155,7 @@ export class CertificationComponent implements OnInit {
       this.isReal = true
       await this.presentToast('认证成功', 1500, 'primary')
       setTimeout(() => {
-        this.back()
+        history.back()
       }, 1800);
     }
   }