Jelajahi Sumber

add account

warrior 1 Minggu lalu
induk
melakukan
784525455d
32 mengubah file dengan 1632 tambahan dan 76 penghapusan
  1. TEMPAT SAMPAH
      projects/live-app/public/img/Alogo.png
  2. TEMPAT SAMPAH
      projects/live-app/public/img/bg.png
  3. TEMPAT SAMPAH
      projects/live-app/public/img/用户榜底.png
  4. 2 1
      projects/live-app/src/app/app.config.ts
  5. 6 1
      projects/live-app/src/app/app.routes.ts
  6. 30 0
      projects/live-app/src/moduls/account/account.modules.routes.ts
  7. 61 0
      projects/live-app/src/moduls/account/bankcard/bankcard.component.html
  8. 116 0
      projects/live-app/src/moduls/account/bankcard/bankcard.component.scss
  9. 28 0
      projects/live-app/src/moduls/account/bankcard/bankcard.component.spec.ts
  10. 163 0
      projects/live-app/src/moduls/account/bankcard/bankcard.component.ts
  11. 70 0
      projects/live-app/src/moduls/account/certification/certification.component.html
  12. 160 0
      projects/live-app/src/moduls/account/certification/certification.component.scss
  13. 28 0
      projects/live-app/src/moduls/account/certification/certification.component.spec.ts
  14. 165 0
      projects/live-app/src/moduls/account/certification/certification.component.ts
  15. 54 0
      projects/live-app/src/moduls/account/wattle/wattle.component.html
  16. 108 0
      projects/live-app/src/moduls/account/wattle/wattle.component.scss
  17. 28 0
      projects/live-app/src/moduls/account/wattle/wattle.component.spec.ts
  18. 62 0
      projects/live-app/src/moduls/account/wattle/wattle.component.ts
  19. 6 5
      projects/live-app/src/moduls/tabs/home/home.component.scss
  20. 12 3
      projects/live-app/src/moduls/tabs/live-review/live-review.component.html
  21. 40 0
      projects/live-app/src/moduls/tabs/live-review/live-review.component.scss
  22. 3 3
      projects/live-app/src/moduls/tabs/my/my.component.html
  23. 6 5
      projects/live-app/src/moduls/tabs/my/my.component.scss
  24. 28 1
      projects/live-app/src/moduls/tabs/my/my.component.ts
  25. 51 31
      projects/live-app/src/moduls/tabs/notice/notice.component.html
  26. 26 13
      projects/live-app/src/moduls/tabs/notice/notice.component.scss
  27. 16 5
      projects/live-app/src/moduls/tabs/notice/notice.component.ts
  28. 78 3
      projects/live-app/src/moduls/tabs/ranking/ranking.component.html
  29. 117 0
      projects/live-app/src/moduls/tabs/ranking/ranking.component.scss
  30. 65 5
      projects/live-app/src/moduls/tabs/ranking/ranking.component.ts
  31. 49 0
      projects/live-app/src/services/http.service.ts
  32. 54 0
      projects/live-app/src/services/utils.ts

TEMPAT SAMPAH
projects/live-app/public/img/Alogo.png


TEMPAT SAMPAH
projects/live-app/public/img/bg.png


TEMPAT SAMPAH
projects/live-app/public/img/用户榜底.png


+ 2 - 1
projects/live-app/src/app/app.config.ts

@@ -3,7 +3,8 @@ import { FormsModule } from '@angular/forms';
 import { provideRouter } from '@angular/router';
 import { provideIonicAngular, IonicRouteStrategy } from '@ionic/angular/standalone';
 import { routes } from './app.routes';
+import { provideHttpClient } from '@angular/common/http';
 
 export const appConfig: ApplicationConfig = {
-  providers: [provideZoneChangeDetection({ eventCoalescing: true }),provideIonicAngular({ mode: 'ios' }), provideRouter(routes),importProvidersFrom(FormsModule),]
+  providers: [provideZoneChangeDetection({ eventCoalescing: true }),provideIonicAngular({ mode: 'ios' }), provideRouter(routes),importProvidersFrom(FormsModule),provideHttpClient()]
 };

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

@@ -9,9 +9,14 @@ export const routes: Routes = [
     loadComponent:()=> import('../moduls/login/login.component').then((mod) => mod.LoginComponent),
   },
   {
-    path: 'tabs', //教材评审组成员
+    path: 'tabs', //首页tabs
     component: TabsComponent,
     canActivate: mapToCanActivate([AuthGuard]),
     loadChildren: () =>import('../moduls/tabs/tabs.modules.routes').then((mod) => mod.TabsRoutingModule),
   },
+  {
+    path: 'account', 
+    canActivate: mapToCanActivate([AuthGuard]),
+    loadChildren: () =>import('../moduls/account/account.modules.routes').then((mod) => mod.AccountRoutingModule),
+  },
 ];

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

@@ -0,0 +1,30 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { BankcardComponent } from './bankcard/bankcard.component';
+import { CertificationComponent } from './certification/certification.component';
+import { WattleComponent } from './wattle/wattle.component';
+const routes: Routes = [
+  {
+    path: '',
+    redirectTo:'wattle',
+    pathMatch: "full",
+  },
+  {
+    path: 'wattle', //钱包
+    component: WattleComponent,
+  },
+  {
+    path: 'bankcard',
+    component: BankcardComponent,
+  },
+  {
+    path: 'idcard',//实名
+    component: CertificationComponent,
+  },
+  
+]
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class AccountRoutingModule { }

+ 61 - 0
projects/live-app/src/moduls/account/bankcard/bankcard.component.html

@@ -0,0 +1,61 @@
+<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>
+
+<div class="notice_list">
+  <div class="card_list">
+    @if (account && account.bank && account.bank.length == 0 ) {
+    <div>
+      <img
+        class="image"
+        src="https://file-cloud.fmode.cn/uiZD6NisQm/20220810/1dgb16090145.png"
+      />
+      <div class="txt">暂无绑定银行卡</div>
+    </div>
+    } @if (account && account.bank && account.bank.length > 0 ) { @for (card of
+    account.bank; track $index) {
+    <div class="card">
+      <div class="top">
+        <img class="logo" src="{{ card.logo }}" alt="" />
+      </div>
+      <div class="info">
+        <div class="card_no">{{ card.bankcard }}</div>
+        <div class="bank_name">{{ card.bankname }}</div>
+      </div>
+    </div>
+    } }
+  </div>
+  <ion-button class="add_btn" (click)="addCard()">添加银行卡</ion-button>
+
+  <!-- <Modal [(ngModel)]="isModalOpen" [transparent]="true" [title]="'银行卡信息'" [footer]="footer">
+		<div class="model">
+
+			<input type="text" [(ngModel)]='bankinfo.bankcard' autocomplete="off" placeholder="请填写银行卡号"
+				autocomplete="new-password">
+
+			<div class="line"></div>
+
+			<input type="text" [(ngModel)]='bankinfo.idcard' maxlength="18" autocomplete="off" placeholder="请填写身份证号"
+				autocomplete="new-password">
+
+			<div class="line"></div>
+
+			<input type="text" [(ngModel)]='bankinfo.name' maxlength="18" autocomplete="off" placeholder="请填写真实姓名"
+				autocomplete="new-password">
+
+			<div class="line"></div>
+
+			<input type="text" [(ngModel)]='bankinfo.mobile' maxlength="18" autocomplete="off" placeholder="请填写银行预留手机号"
+				autocomplete="new-password">
+
+		</div>
+	</Modal> -->
+</div>

+ 116 - 0
projects/live-app/src/moduls/account/bankcard/bankcard.component.scss

@@ -0,0 +1,116 @@
+.notice_list {
+	height: 100vh;
+	width: 100%;
+	background-image: url("https://file-cloud.fmode.cn/uiZD6NisQm/20220831/g1bkbm102855.png");
+	background-repeat: no-repeat;
+	background-position: center top;
+	background-size: 100% 100%;
+
+	.nav {
+		width: 100%;
+		height: 6vh;
+		line-height: 5vh;
+		color: #000000;
+		background: #dbe5fd;
+		z-index: 100;
+	}
+
+	.card_list {
+		margin-top: 16px;
+		width: 100%;
+		height: 94vh;
+		margin-bottom: 100px;
+		overflow-y: auto;
+
+		.image {
+			margin: 50px 100px;
+			width: 175px;
+			height: 175px;
+			text-align: center;
+		}
+
+		.txt {
+			color: #fff;
+			text-align: center;
+		}
+
+		.card {
+			height: 22vh;
+			width: 94%;
+			margin: 0 auto;
+			// background-color: #292B2A;
+			border-radius: 10px;
+			margin-bottom: 10px;
+			color: 000000;
+			border: 1px solid #000000;
+
+			.top {
+				width: 100%;
+				height: 60%;
+				padding: 10px;
+
+				.logo {
+					width: 60px;
+					height: 60px;
+					border-radius: 50%;
+				}
+			}
+
+			.info {
+				width: 100%;
+				height: 40%;
+				// background-color: #fff;
+				padding: 10px;
+				border-radius: 0 0 10px 10px;
+
+				.card_no {
+					color: #000;
+					font-size: 16px;
+					margin-bottom: 4px;
+					font-weight: 600;
+				}
+
+				.bank_name {
+					color: #444;
+					font-size: 12px;
+					margin-bottom: 4px;
+				}
+			}
+		}
+
+	}
+
+	.add_btn {
+		position: fixed;
+		bottom: 1vh;
+		width: 80%;
+		left: 10vw;
+		background: #92a1ff;
+		border-radius: 18px;
+	}
+
+	.model {
+		height: 30vh;
+		width: 100%;
+		border: 1px solid #000000;
+
+		input {
+			width: 100%;
+			height: 6vh;
+			height: 1;
+			border-radius: 6px;
+			border: none;
+			padding: 0 10px;
+			font-size: 14px;
+			flex: 1;
+
+		}
+
+		.line {
+			margin: 4px 0;
+			width: 100%;
+			height: 1px;
+			background-color: #a2a2a2;
+		}
+	}
+}

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

+ 163 - 0
projects/live-app/src/moduls/account/bankcard/bankcard.component.ts

@@ -0,0 +1,163 @@
+import { Component, OnInit } from '@angular/core';
+
+import * as Parse from 'parse';
+import { HttpClient } from '@angular/common/http';
+import { IonicModule, ToastController } from '@ionic/angular';
+@Component({
+  selector: 'app-bankcard',
+  templateUrl: './bankcard.component.html',
+  styleUrls: ['./bankcard.component.scss'],
+	standalone: true,
+  imports: [IonicModule],
+})
+export class BankcardComponent implements OnInit {
+  constructor(
+    private http: HttpClient,
+    public toastController: ToastController
+  ) {}
+  company: string = localStorage.getItem('company') || '';
+  account: any = null;
+  bankinfo: any = {
+    bankcard: '',
+    name: '',
+    idcard: '',
+    mobile: '',
+  };
+  adding: boolean = false;
+  isModalOpen: boolean = false;
+  setOpen(isOpen: boolean) {
+    this.isModalOpen = isOpen;
+  }
+  async ngOnInit() {
+    await this.getAccountInfo();
+  }
+  async getAccountInfo() {
+    let user = Parse.User.current();
+    let Account = new Parse.Query('Account');
+    Account.equalTo('user', user?.id);
+    Account.equalTo('company', this.company);
+    let account = await Account.first();
+    if (account && account.id) {
+      this.account = account.toJSON();
+      console.log(this.account);
+    }
+  }
+
+  footer = [
+    {
+      text: '取消',
+      onPress: () => {
+        console.log('ok');
+        this.onClose();
+      },
+    },
+    {
+      text: '确定',
+      onPress: () => {
+        console.log('ok');
+        if (this.adding) {
+          return;
+        }
+        this.adding = true;
+        this.confirm();
+      },
+    },
+  ];
+
+  onClose() {
+    this.isModalOpen = false;
+  }
+
+  async confirm() {
+    let cardInfo = this.bankinfo;
+    for (const key in cardInfo) {
+      if (!cardInfo[key]) {
+        const toast = await this.toastController.create({
+          message: '请将信息填写完整',
+          color: 'warning',
+          duration: 100000,
+        });
+        toast.present();
+        this.adding = false;
+        return;
+      }
+    }
+    this.verifyCard().then(async (res: any) => {
+      if (res.data.code == 200) {
+        if (res.data.data.result == 0 || res.data.data.result == 1) {
+          this.bankinfo.bankname = res.data.data.bank_info.bank;
+          this.bankinfo.logo = res.data.data.bank_info.logo;
+          if (this.account.bank && this.account.bank.length > 0) {
+            this.account.bank.push(this.bankinfo);
+          } else {
+            this.account.bank = [this.bankinfo];
+          }
+          this.updateAccount();
+          this.isModalOpen = false;
+          setTimeout(() => {
+            this.adding = false;
+          }, 800);
+        } else {
+          const toast = await this.toastController.create({
+            message: '卡状态异常,请更换卡',
+            color: 'warning',
+            duration: 100000,
+          });
+          toast.present();
+          this.adding = false;
+          return;
+        }
+      } else if (res.data.code == 400) {
+        const toast = await this.toastController.create({
+          message: res.data.msg,
+          color: 'warning',
+          duration: 100000,
+        });
+        toast.present();
+        this.adding = false;
+        return;
+      } else {
+        const toast = await this.toastController.create({
+          message: '服务错误请稍后重试',
+          color: 'warning',
+          duration: 100000,
+        });
+        toast.present();
+        this.adding = false;
+        return;
+      }
+    });
+  }
+  async verifyCard() {
+    return new Promise((resolve, reject) => {
+      this.http
+        .post('https://test.fmode.cn/api/apig/bankcard', {
+          company: this.company,
+          bankcard: this.bankinfo.bankcard,
+          name: this.bankinfo.name,
+          idcard: this.bankinfo.idcard,
+          mobile: this.bankinfo.mobile,
+        })
+        .subscribe((res: any) => {
+          console.log(res);
+          resolve(res);
+        });
+    });
+  }
+
+  async updateAccount() {
+    let Account = new Parse.Query('Account');
+    let account = await Account.get(this.account.objectId);
+    if (account) {
+      account.set('bank', this.account.bank);
+      await account.save();
+    }
+  }
+
+  addCard() {
+    this.isModalOpen = true;
+  }
+  onBack(){
+    history.back()
+  }
+}

+ 70 - 0
projects/live-app/src/moduls/account/certification/certification.component.html

@@ -0,0 +1,70 @@
+<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>
+<ion-content class="content">
+  <div class="hred">
+    <div class="hred-left">
+      {{ title }}
+    </div>
+    <img
+      src="http://cloud.file.futurestack.cn/real-idcard.png"
+      class="hred-img"
+    />
+  </div>
+  @if (isReal) {
+  <div class="tips">
+    <img
+      class="tips-img"
+      src="https://cloud.file.futurestack.cn/game-auth.png"
+      alt=""
+    />
+    <div class="text">您已完成认证</div>
+  </div>
+  <div class="pf">
+    <div style="margin-right: 10px">{{ secretName }}*</div>
+    <div class="">{{ secretIdCard }}********</div>
+  </div>
+  } @else{
+  <div class="h3">填写身份信息认证</div>
+  <div class="li">
+    真实姓名
+    <input
+      type="text"
+      [(ngModel)]="name"
+      name="name"
+      autocomplete="off"
+      placeholder="请填写真实姓名"
+      autocomplete="new-password"
+    />
+  </div>
+  <div class="li">
+    身份证号
+    <input
+      type="text"
+      [(ngModel)]="idCard"
+      maxlength="18"
+      name="idCard"
+      autocomplete="off"
+      placeholder="请填写身份证号"
+      autocomplete="new-password"
+    />
+  </div>
+  <div class="footer" (click)="check()">提交</div>
+  }
+  <div class="agreement">
+    <ion-checkbox color="primary" [(ngModel)]="agreement"></ion-checkbox>
+    <div class="content">
+      注册即代表同意<span (click)="showAgreement()"
+        >《爱聊直播平台隐私协议》</span
+      >
+    </div>
+  </div>
+</ion-content>

+ 160 - 0
projects/live-app/src/moduls/account/certification/certification.component.scss

@@ -0,0 +1,160 @@
+// .header {
+//   .toolbar{
+//     --background: #171b24;
+//     --opacity: 1;
+//     --min-height: 13.3333vw;
+//   }
+//   .title{
+//     --color : #FFFFFF;
+//     text-align: left;
+//     font-size: 4.2667vw;
+//     font-family: Source Han Sans CN;
+//     font-weight: 500;
+//     color: #FFFFFF;
+//     padding-left: 8vw;
+//   }
+// }
+.content {
+  --background: #f8f8f8;
+  --padding-bottom: 5.3333vw;
+
+  .hred {
+    width: 350px;
+    height: 42.6667vw;
+    padding: 2.6667vw;
+    background: #FFFFFF;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin: 10px auto;
+    .hred-left {
+      font-size: 14px;
+      font-family: Source Han Sans CN;
+      font-weight: 400;
+      color: #bbbbbb;
+    }
+    .hred-img {
+      width: 49.0667vw;
+      height: 37.3333vw;
+    }
+  }
+  .tips {
+    display: flex;
+    margin: 10.6667vw auto;
+    font-size: 4.2667vw;
+    font-family: Source Han Sans CN;
+    font-weight: 500;
+    color: #ffffff;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    margin-top: 26.6667vw;
+    .tips-img {
+      width: 10.6667vw;
+      height: 10.6667vw;
+    }
+  }
+  .pf {
+    font-size: 3.7333vw;
+    font-family: Source Han Sans CN;
+    font-weight: 500;
+    color: #727272;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .h3 {
+    margin: 10.6667vw auto 0.5333vw;
+    font-size: 4.2667vw;
+    font-family: Source Han Sans CN;
+    font-weight: 500;
+    // color: #ffffff;
+    width: 93.3333vw;
+    padding: 3.2vw;
+    border-radius: 2.6667vw;
+    // background: #353C4D;
+    text-align: center;
+  }
+  .li {
+    margin: 2.6667vw auto;
+    font-size: 4.2667vw;
+    font-family: Source Han Sans CN;
+    font-weight: 500;
+    // color: #ffffff;
+    width: 350px;
+    padding: 2.6667vw;
+    border-radius: 2.6667vw;
+    background: #fff;
+    display: flex;
+    align-items: center;
+    input {
+      // width: 64vw;
+      margin-left: 1.6vw;
+      height: 8.5333vw;
+      border-radius: 1.6vw;
+      border: none;
+      // background: #353c4d;
+      // color: #ffffff;
+      padding: 0 5.3333vw;
+      font-size: 16px;
+      flex: 1;
+    }
+  }
+
+  .footer {
+    margin: 26.6667vw auto 5.3333vw;
+    width: 69.3333vw;
+    background: #0054e9;
+    border-radius: 10px;
+    padding: 2.6667vw 0;
+    text-align: center;
+    font-size: 4.2667vw;
+    color: #ffffff;
+  }
+  .agreement {
+    width: 84vw;
+    height: 13.333vw;
+    display: flex;
+    align-items: flex-start;
+    justify-content: center;
+    font-size: 14px;
+    font-weight: 400;
+    color: #9f9f9f;
+    margin: auto;
+    margin-top: 6.667vw;
+    span {
+      color: #3f51b5;
+    }
+    .content {
+      margin-left: 2.667vw;
+      // width: 90%;
+    }
+    ion-checkbox {
+      --background: #108ee9;
+      // --border-color: #fff;
+      // --border-color-checked: #fff;
+      --background-checked: #108ee9;
+    }
+  }
+}
+
+input:-internal-autofill-previewed,
+input:-internal-autofill-selected {
+  -webkit-text-fill-color: #ffffff;
+  transition: background-color 5000s ease-out 0.5s;
+}
+input::-webkit-input-placeholder {
+  color: #999999;
+}
+input::-moz-placeholder {
+  /* Mozilla Firefox 19+ */
+  color: #999999;
+}
+input:-moz-placeholder {
+  /* Mozilla Firefox 4 to 18 */
+  color: #999999;
+}
+input:-ms-input-placeholder {
+  /* Internet Explorer 10-11 */
+  color: #999999;
+}

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

+ 165 - 0
projects/live-app/src/moduls/account/certification/certification.component.ts

@@ -0,0 +1,165 @@
+import { Component, OnInit } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { IonicModule, LoadingController, ModalController, ToastController } from '@ionic/angular';
+import { HttpService } from '../../../services/http.service';
+import * as utils from '../../../services/utils'
+import { AgreementComponent } from '../../login/agreement/agreement.component';
+import * as Parse from 'parse';
+
+@Component({
+  selector: 'app-certification',
+  templateUrl: './certification.component.html',
+  styleUrls: ['./certification.component.scss'],
+  standalone: true,
+  imports: [IonicModule,FormsModule],
+})
+export class CertificationComponent implements OnInit {
+
+  name: string = ''
+  idCard: string = ''
+  title: string = '根据相关法律法规要求,用户需先进行实名认证,方可使用本平台。请尽快完成下方实名认证,本平台将对您的信息严格保密。'
+  company:any = window.localStorage.getItem("company")
+  isReal: boolean = false
+  loading: any
+  time: any //节流
+  secretName: any
+  secretIdCard:any
+  agreement: boolean = false;
+  registerAgreement: any;
+
+  constructor(
+    private service: HttpService,
+    public loadCtrl: LoadingController,
+    private modalController: ModalController,
+    public toastController: ToastController,
+  ) { }
+
+  ngOnInit() {
+    this.getAgreement()
+    this.getProfile()
+  }
+  getAgreement() {
+    let Agreement = new Parse.Query('ContractAgreement');
+    Agreement.equalTo('company', this.company);
+    Agreement.equalTo('type', 'register');
+    Agreement.first().then((res) => {
+      console.log(res);
+      this.registerAgreement = res;
+    });
+  }
+  async getProfile() {
+    let uid = Parse.User.current()?.id
+    let query = new Parse.Query("Profile")
+    query.equalTo("user", uid)
+    query.equalTo("isCross", true)
+    let res = await query.first()
+    if (res && res.id) {
+      this.isReal = true
+      this.secretIdCard = res.get('idcard').slice(0,6)
+      this.secretName = res.get('name').slice(0,1)
+    }
+  }
+  async showAgreement() {
+    const modal = await this.modalController.create({
+      component: AgreementComponent,
+      cssClass: 'my-custom-class',
+      componentProps: {
+        agreement: this.registerAgreement,
+      },
+    });
+    return await modal.present();
+  }
+  back() {
+    history.back()
+  }
+
+  async presentToast(title:string, time:number, color:string) {
+    const toast = await this.toastController.create({
+      message: title,
+      duration: time,
+      color: color
+    });
+    toast.present();
+  }
+
+  async check() {
+    this.loading = await this.loadCtrl.create()
+    this.loading.present()
+
+    this.time && clearTimeout(this.time)
+
+    this.time = setTimeout(async () => {
+      console.log(this.name, this.idCard);
+      if (!this.idCard || this.idCard.length != 18 || !this.name) {
+        this.loading.dismiss()
+        await this.presentToast('格式错误', 1500, 'danger')
+        return
+      }
+      let pass = utils.fun.IdentityCodeValid(this.idCard)
+      console.log(pass);
+      if (!pass) {
+        this.loading.dismiss()
+        await this.presentToast('认证失败,请填写真实的身份信息', 1500, 'danger')
+        return
+      }
+
+      let res: any = await this.service.postAuth(this.company, this.idCard, this.name)
+      if (res.code == 1) {
+        let { isok } = res.data.result
+        console.log(isok);
+        if (isok) {
+          let { sex } = res.data.result.IdCardInfor
+          this.anthProfile(sex)
+          return
+        }
+        this.loading.dismiss()
+        await this.presentToast('认证失败,请填写真实的身份信息', 1500, 'danger')
+      } else {
+        this.loading.dismiss()
+        await this.presentToast('认证失败', 1500, 'danger')
+      }
+    }, 500);
+  }
+
+  async anthProfile(sex: string) {
+    let uid = Parse.User.current()?.id
+    let query = new Parse.Query("Profile")
+    query.equalTo("idcard", this.idCard)
+    query.equalTo("company", this.company)
+    let res = await query.first()
+    if (res && res.id) {
+      this.loading.dismiss()
+      await this.presentToast('认证失败,该身份已被认证', 1500, 'danger')
+      return
+    }
+
+    let obj = Parse.Object.extend("Profile")
+    let profile = new obj()
+    profile.set("company", {
+      __type: "Pointer",
+      className: "Company",
+      objectId: this.company,
+    })
+    profile.set("user", {
+      __type: "Pointer",
+      className: "_User",
+      objectId: uid,
+    })
+    profile.set("idcard", this.idCard)
+    profile.set("name", this.name)
+    profile.set("isCross", true)
+    profile.set("sex", sex)
+    let r = await profile.save()
+    if (r && r.id) {
+      console.log(r.id);
+      localStorage.setItem("profile", r.id)
+      this.loading.dismiss()
+      this.isReal = true
+      await this.presentToast('认证成功', 1500, 'primary')
+      setTimeout(() => {
+        this.back()
+      }, 1800);
+    }
+  }
+
+}

+ 54 - 0
projects/live-app/src/moduls/account/wattle/wattle.component.html

@@ -0,0 +1,54 @@
+<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>
+<ion-content class="content">
+  <div class="top">
+    <div class="box">
+      <div class="account_info">
+        <div class="balance">
+          <div class="count">{{ account?.balance?.toFixed(2) || 0}}</div>
+          <div class="title">我的余额</div>
+        </div>
+      </div>
+      <div class="figure">
+        <div class="recharge" (click)="recharge()">充值</div>
+        <div class="recharges" (click)="withdrawal()">提现</div>
+      </div>
+    </div>
+
+    <div class="install" (click)="toBank()">
+      <div class="install-to">
+        <div class="name">我的银行卡</div>
+      </div>
+      <img
+        class="img"
+        src="https://file-cloud.fmode.cn/uiZD6NisQm/20220808/9sq3d1093746.png"
+      />
+    </div>
+    <div class="install" (click)="record()">
+      <div class="install-to">
+        <div class="name">充值记录</div>
+      </div>
+      <img
+        class="img"
+        src="https://file-cloud.fmode.cn/uiZD6NisQm/20220808/9sq3d1093746.png"
+      />
+    </div>
+    <div class="install" (click)="records()">
+      <div class="install-to">
+        <div class="name">提现记录</div>
+      </div>
+      <img
+        class="img"
+        src="https://file-cloud.fmode.cn/uiZD6NisQm/20220808/9sq3d1093746.png"
+      />
+    </div></div
+></ion-content>

+ 108 - 0
projects/live-app/src/moduls/account/wattle/wattle.component.scss

@@ -0,0 +1,108 @@
+.top {
+  background-image: url("https://file-cloud.fmode.cn/uiZD6NisQm/20220831/g1bkbm102855.png");
+  background-repeat: no-repeat;
+  background-position: center top;
+  background-size: 100% 100%;
+  height: 100%;
+  padding: 40px 0;
+  width: 100%;
+
+  .head {
+    padding: 15px 5px;
+    // background: #292B2A;
+
+    .name {
+      color: #000000;
+      text-align: center;
+    }
+  }
+
+  .box {
+    text-align: center;
+    margin: 0 auto 16px ;
+    // background: #292B2A;
+    border-radius: 9px;
+    color: #000000;
+    padding: 20px;
+    width: 92%;
+    height: 28vh;
+    // margin-top: 20px;
+    border: 1px solid #000000;
+
+    .account_info {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      width: 100%;
+      height: 14vh;
+
+      .balance {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-direction: column;
+        width: 40%;
+        height: 100%;
+
+        .title {
+          font-size: 14px;
+        }
+
+        .count {
+          font-size: 16px;
+          font-weight: 600;
+          margin-bottom: 6px;
+        }
+      }
+    }
+
+    .figure {
+      display: flex;
+
+      .recharge {
+        width: 150px;
+        background: #92a1ff;
+        border-radius: 18px;
+        padding: 10px 0 10px 0;
+        margin: 0 auto;
+        color: #ffffff;
+      }
+
+      .recharges {
+        width: 150px;
+        border: 1px solid #000000;
+        border-radius: 18px;
+        padding: 10px 0 10px 0;
+        margin: 0 auto;
+        color: #000000;
+        margin-left: 20px;
+      }
+    }
+  }
+
+  .install {
+    width: 92%;
+    margin: 10px auto;
+    border-radius: 9px;
+    padding: 10px 0;
+    display: flex;
+    justify-content: space-between;
+    border: 1px solid #000000;
+
+    .install-to {
+      display: flex;
+      padding-left: 10px;
+
+      .name {
+        color: #000000;
+        margin: auto 5px;
+      }
+    }
+
+    .img {
+      width: 20px;
+      height: 20px;
+      margin: auto 10px;
+    }
+  }
+}

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

+ 62 - 0
projects/live-app/src/moduls/account/wattle/wattle.component.ts

@@ -0,0 +1,62 @@
+import { Component, OnInit } from '@angular/core';
+import { IonicModule } from '@ionic/angular';
+import * as Parse from 'parse';
+import { Router, ActivatedRoute } from '@angular/router';
+
+@Component({
+  selector: 'app-wattle',
+  templateUrl: './wattle.component.html',
+  styleUrls: ['./wattle.component.scss'],
+  standalone: true,
+  imports: [IonicModule],
+})
+export class WattleComponent implements OnInit {
+  company: any = localStorage.getItem('company');
+  constructor(private activatRoute: ActivatedRoute,
+    private router: Router,) { }
+  account: any = {}
+
+  ngOnInit() {
+    this.activatRoute.paramMap.subscribe(parms => {
+      this.getAccount()
+    })
+
+  }
+  back() {
+    this.router.navigate(['metayoung/tabs/my'])
+  }
+  async getAccount() {
+    let id = Parse.User.current()?.id
+    let Account = new Parse.Query("Account")
+    Account.equalTo("user", id)
+    Account.equalTo("company", this.company)
+    let account = await Account.first()
+    this.account = account?.toJSON()
+  }
+
+  // showBalance(balance:number) {
+  //   if (balance) {
+  //     return Number(balance.toFixed(2))
+  //   } else {
+  //     return 0
+  //   }
+  // }
+  record() {
+    this.router.navigate(['metayoung/record'])
+  }
+  records() {
+    this.router.navigate(['metayoung/records'])
+  }
+  recharge() {
+    this.router.navigate(['metayoung/recharge'])
+  }
+  withdrawal() {
+    this.router.navigate(['metayoung/withdrawal'])
+  }
+  toBank() {
+    this.router.navigate(['account/bankcard'])
+  }
+  onBack(){
+    history.back()
+  }
+}

+ 6 - 5
projects/live-app/src/moduls/tabs/home/home.component.scss

@@ -2,10 +2,11 @@
   --padding-bottom: 100px;
   --background: #f8f8f8;
   .header {
-    padding: 10px;
-    background: #fd6f6a;
-    height: 150px;
-    border-radius: 0 0 50px 50px;
+    padding:20px 10px 10px;
+    height: 160px;
+    // border-radius: 0 0 50px 50px;
+    background-image: url(/img/bg.png);
+    background-size: 100% 100%;
     .top {
       display: flex;
       .search {
@@ -18,7 +19,7 @@
         padding: 0 3.2vw;
         position: sticky;
         top: 0;
-        background: #fd6f6a;
+        background: #fd6f6a00;
       }
       ion-segment-button {
         color: white;

+ 12 - 3
projects/live-app/src/moduls/tabs/live-review/live-review.component.html

@@ -1,3 +1,12 @@
-<p>
-  live-review works!
-</p>
+<div class="live-page">
+  <div class="post-footer">
+    <div class="btn">点击进入直播间</div>
+    <div class="block">
+      <div class="tag">直播中
+        <img src="/img/live.gif" alt="">
+      </div>
+      <div class="live-room">这个女孩叫小美</div>
+      <div class="tips">这个女孩叫小美正在直播</div>
+    </div>
+  </div>
+</div>

+ 40 - 0
projects/live-app/src/moduls/tabs/live-review/live-review.component.scss

@@ -0,0 +1,40 @@
+.live-page{
+  height: 100%;
+  background-color: #fff;
+  position: relative;
+  .post-footer{
+    position: absolute;
+    bottom: 0;
+    height: 350px;
+    color: white;
+    padding: 50px 10px 120px;
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    align-items: center;
+    background: linear-gradient(to top, #000000, rgba(255, 255, 255, 0));
+    .btn{
+      padding: 10px;
+      border-radius: 20px;
+      border: 1px solid;
+      // margin:auto;
+    }
+    .block{
+      width: 100%;
+      .tag{
+        background: #fc4942;
+        padding: 4px 6px;
+        border-radius: 4px;
+        display: inline-flex;
+        align-items: center;
+        img{
+          width: 20px;
+        }
+      }
+      .live-room{
+        margin: 6px auto;
+      }
+    }
+  }
+}

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

@@ -56,7 +56,7 @@
   </div>
   <div class="tool">
     @for (item of tools; track $index) {
-    <div class="tool-li">
+    <div class="tool-li" (click)="toUrl(item.path)">
       <div class="icon">
         <img [src]="item.icon" alt="" />
       </div>
@@ -141,7 +141,7 @@
       </div>
     </div>
     <div class="list">
-      <div class="li">
+      <div class="li" (click)="toUrl('/account/idcard')">
         <div class="li-lable">
           <img src="/img/成为主播.png" alt="" class="icon" />
           成为主播
@@ -176,7 +176,7 @@
         </div>
         <ion-icon name="chevron-forward-outline"></ion-icon>
       </div>
-      <div class="li">
+      <div class="li" (click)="onLogout()">
         <div class="li-lable">
           <img src="/img/退出登录.png" alt="" class="icon" />
           退出登录

+ 6 - 5
projects/live-app/src/moduls/tabs/my/my.component.scss

@@ -2,10 +2,11 @@
   --padding-bottom: 100px;
   --background: #f8f8f8;
   .header {
-    padding: 10px;
-    background: #fd6f6a;
-    height: 130px;
-    border-radius: 0 0 50px 50px;
+    padding:20px 10px 10px;
+    background-image: url(/img/bg.png);
+    background-size: 100% 100%;
+    height: 140px;
+    // border-radius: 0 0 50px 50px;
     .user-dateil {
       display: flex;
       align-items: center;
@@ -298,7 +299,7 @@
     .list{
       background: white;
       border-radius: 10px;
-      padding: 4px 10px;
+      padding: 4px 10px 10px;
       margin: 10px auto;
       .li{
         display: flex;

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

@@ -5,6 +5,7 @@ import * as Parse from 'parse';
 import { AgreementComponent } from '../../login/agreement/agreement.component';
 import { AlertController, ModalController } from '@ionic/angular';
 import { Router } from '@angular/router';
+import { AuthService } from '../../../services/auth.service';
 @Component({
   selector: 'app-my',
   templateUrl: './my.component.html',
@@ -17,13 +18,14 @@ export class MyComponent implements OnInit {
   constructor(
     private modalController: ModalController,
     private alertController: AlertController,
+    public authServ: AuthService,
     private router: Router
   ) {}
   tools: Array<{ icon: string; title: string; path: string }> = [
     {
       icon: '/img/钱包.png',
       title: '钱包',
-      path: '',
+      path: 'account/wattle',
     },
     {
       icon: '/img/相册.png',
@@ -64,6 +66,7 @@ export class MyComponent implements OnInit {
     });
   }
   toUrl(url: string, params?: Object) {
+    console.log(url);
     if (params) {
       this.router.navigate([url, Object]);
     } else {
@@ -82,4 +85,28 @@ export class MyComponent implements OnInit {
       return await modal.present();
     }
   }
+  async onLogout(){
+      const alert = await this.alertController.create({
+      cssClass: 'my-custom-class',
+      header: '',
+      message: '你确定退出登录吗?',
+      buttons: [
+        {
+          text: '确定',
+          role: 'cancel',
+          cssClass: 'secondary',
+          handler: (blah) => {
+            console.log('Confirm Cancel: blah');
+            this.authServ.logout()
+          },
+        },
+        {
+          text: '取消',
+          handler: () => {
+          },
+        },
+      ],
+    });
+    await alert.present();
+  }
 }

+ 51 - 31
projects/live-app/src/moduls/tabs/notice/notice.component.html

@@ -16,7 +16,6 @@
       </ion-segment-button>
     </ion-segment>
     <div class="more">
-      <!-- <img src="/img/more.png" alt="" /> -->
       <ion-button id="click-trigger"
         ><ion-icon name="ellipsis-horizontal-outline"></ion-icon
       ></ion-button>
@@ -25,42 +24,63 @@
 </ion-header>
 <ion-content class="content">
   <ion-searchbar animated="true" placeholder="搜索"></ion-searchbar>
-
-  <ion-popover trigger="click-trigger" triggerAction="click">
+  <ion-popover
+    trigger="click-trigger"
+    [dismissOnSelect]="true"
+    triggerAction="click"
+  >
     <ng-template>
-      <div class="pro">123</div>
+      <ion-list>
+        <ion-item class="clear" [button]="true" [detail]="false"
+          >已读所有消息</ion-item
+        >
+      </ion-list>
     </ng-template>
   </ion-popover>
   <ion-segment-view>
     <ion-segment-content id="notice">
-      <div class="notice-list">
-        @for (item of noticeList; track $index) {
-        <div
-          class="li"
-          (touchstart)="startPress()"
-          (mousemove)="stopPress()"
-        >
-          <ion-avatar>
-            <img
-              alt="Silhouette of a person's head"
-              src="https://ionicframework.com/docs/img/demos/avatar.svg"
-            />
-          </ion-avatar>
-          <div class="li-right">
-            <div class="name">
-              系统消息
-              <span class="time">20:20:18</span>
-            </div>
-            <div class="message-content">
-              12554444444
+      <div class="notice-list" (touchmove)="onMousemove($event)">
+        <ion-list>
+          @for (item of noticeList; track $index) {
+          <ion-item
+            class="li"
+            (touchstart)="startPress()"
+            (mousemove)="stopPress()"
+          >
+            <!-- <div class="li" (touchstart)="startPress()" (mousemove)="stopPress()"> -->
+            <ion-avatar slot="start">
+              <img [src]="item.avatar" alt="avatar" />
+            </ion-avatar>
+            <div class="li-right">
+              <div class="name">
+                系统消息
+                <span class="time">20:20:18</span>
+              </div>
+              <div class="message-content">12554444444</div>
             </div>
-          </div>
-        </div>
-      }
+            <!-- </div> -->
+          </ion-item>
+
+          }
+        </ion-list>
       </div>
     </ion-segment-content>
-    <ion-segment-content id="friends"
-      >Second</ion-segment-content
-    ></ion-segment-view
-  >
+    <ion-segment-content id="friends">
+      <div class="notice-list" (touchmove)="onMousemove($event)">
+        <ion-list>
+          @for (item of noticeList; track $index) {
+          <ion-item>
+            <ion-avatar slot="start">
+              <img
+                [src]="'https://picsum.photos/80/80?random=' + $index"
+                alt="avatar"
+              />
+            </ion-avatar>
+            <ion-label>{{ item.name }}</ion-label>
+          </ion-item>
+          }
+        </ion-list>
+      </div>
+    </ion-segment-content>
+  </ion-segment-view>
 </ion-content>

+ 26 - 13
projects/live-app/src/moduls/tabs/notice/notice.component.scss

@@ -26,8 +26,8 @@
         width: 20px;
         height: 20px;
       }
-      ion-button{
-        --background:white;
+      ion-button {
+        --background: white;
         --background-hover: white;
         --background-activated: white;
         --background-focused: white;
@@ -36,7 +36,7 @@
     }
   }
 }
-.content{
+.content {
   --padding-bottom: 100px;
   --background: #f8f8f8;
   ion-segment-content {
@@ -44,38 +44,51 @@
     align-items: center;
     justify-content: center;
   }
-  .notice-list{
+  .notice-list {
     width: 100%;
     height: 100%;
     display: flex;
     flex-direction: column;
     padding: 10px;
-    .li{
+    .li {
       display: flex;
       margin-bottom: 10px;
-      ion-avatar{
+      ion-avatar {
         margin-right: 10px;
         flex-shrink: 0;
       }
-      .li-right{
+      .li-right {
         flex: 1;
         display: flex;
         flex-direction: column;
-        border-bottom: 1px solid #e5e5e5;
-        padding-bottom: 6px;
-        .name{
+        // border-bottom: 1px solid #e5e5e5;
+        // padding-bottom: 6px;
+        .name {
           display: flex;
           justify-content: space-between;
-          .time{
+          .time {
             color: #676767;
             font-size: 12px;
           }
         }
-        .message-content{
+        .message-content {
           color: #676767;
           margin-top: 6px;
         }
       }
     }
+    ion-avatar {
+      margin-right: 10px;
+      flex-shrink: 0;
+    }
   }
-}
+}
+ion-popover {
+  --width: 120px;
+}
+.clear {
+  // padding: 4px 10px;
+  // text-align: center;
+  font-size: 14px;
+  color: #676767;
+}

+ 16 - 5
projects/live-app/src/moduls/tabs/notice/notice.component.ts

@@ -1,7 +1,7 @@
 import { Component, OnInit } from '@angular/core';
 import { IonicModule } from '@ionic/angular';
 import * as Parse from 'parse';
-
+import { InfiniteScrollCustomEvent } from '@ionic/angular';
 @Component({
   selector: 'app-notice',
   templateUrl: './notice.component.html',
@@ -11,21 +11,21 @@ import * as Parse from 'parse';
 })
 export class NoticeComponent implements OnInit {
   active: string = 'notice';
-  noticeList: Array<Object> = [
+  noticeList: Array<any> = [
     {
-      avatar: '',
+      avatar: Parse.User.current()?.get('avatar'),
       name: '系统消息',
       content: '',
       createdAt: new Date(),
     },
     {
-      avatar: '',
+      avatar: Parse.User.current()?.get('avatar'),
       name: '系统消息',
       content: '',
       createdAt: new Date(),
     },
     {
-      avatar: '',
+      avatar: Parse.User.current()?.get('avatar'),
       name: '系统消息',
       content: '',
       createdAt: new Date(),
@@ -45,14 +45,25 @@ export class NoticeComponent implements OnInit {
     this.times += 100;
     if (this.times >= 500) {
       console.log(this.times);
+      this.times = 0;
       return;
     }
     this.timer = setTimeout(() => {
       this.startPress();
     }, 100);
   }
+  onMousemove(e:any){
+    clearTimeout(this.timer);
+    this.times = 0;
+  }
   stopPress() {
     clearTimeout(this.timer);
     this.times = 0;
   }
+  onIonInfinite(ev:any) {
+    console.log(ev);
+    setTimeout(() => {
+      (ev as InfiniteScrollCustomEvent).target.complete();
+    }, 500);
+  }
 }

+ 78 - 3
projects/live-app/src/moduls/tabs/ranking/ranking.component.html

@@ -1,3 +1,78 @@
-<p>
-  ranking works!
-</p>
+<ion-header [translucent]="true" class="header">
+  <ion-toolbar class="toolbar">
+    <!-- <ion-buttons slot="start">
+      <ion-icon
+        name="chevron-back-outline"
+        style="width: 6.4vw; height: 6.4vw; color: #ffffff"
+      ></ion-icon>
+    </ion-buttons> -->
+    <ion-title class="title">排名</ion-title>
+  </ion-toolbar>
+</ion-header>
+<ion-content class="content"> 
+
+  <div class="order">
+    <div class="ladder">
+      <div class="top-block">
+        <div class="top2">
+          <div class="user-block">
+            <div class="user-avatar">
+              <img src="/img/2.png" alt="" class="tag" />
+              <img [src]="orderList[1].avatar" class="avatar" alt="" />
+            </div>
+            <div class="user-name">
+              {{ orderList[1].name }}
+            </div>
+          </div>
+          <div class="user-detail">
+            <div class="num">{{orderList[1].num}}</div>
+            <div class="pm">TOP2</div>
+          </div>
+        </div>
+        <div class="top1">
+          <div class="user-block">
+            <div class="user-avatar">
+              <img src="/img/2.png" alt="" class="tag" />
+              <img [src]="orderList[0].avatar" class="avatar" alt="" />
+            </div>
+            <div class="user-name">
+              {{ orderList[0].name }}
+            </div>
+          </div>
+          <div class="user-detail">
+            <div class="num">{{orderList[0].num}}</div>
+            <div class="pm">TOP1</div>
+          </div>
+        </div>
+        <div class="top3">
+          <div class="user-block">
+            <div class="user-avatar">
+              <img src="/img/2.png" alt="" class="tag" />
+              <img [src]="orderList[2].avatar" class="avatar" alt="" />
+            </div>
+            <div class="user-name">
+              {{ orderList[2].name }}
+            </div>
+          </div>
+          <div class="user-detail">
+            <div class="num">{{orderList[2].num}}</div>
+            <div class="pm">TOP2</div>
+          </div>
+        </div>
+      </div>
+    </div>
+    @for (item of orderList.slice(2); track $index) {
+    <div class="row">
+      <div class="row-left">
+        <span class="row-index">{{$index}}</span>
+        <img [src]="item.avatar" alt="" class="row-avatar" />
+        <div class="row-name">{{ item.name }}</div>
+      </div>
+      <div class="row-right">
+        <div class="row-tpis">距离第一名</div>
+        <div class="row-tpis-num">{{item.num}} <span></span></div>
+      </div>
+    </div>
+    }
+  </div>
+</ion-content>

+ 117 - 0
projects/live-app/src/moduls/tabs/ranking/ranking.component.scss

@@ -0,0 +1,117 @@
+.content{
+  .order {
+    width: 360px;
+    margin: 10px auto;
+    background-image: url(/img/用户榜底.png);
+    background-size: 100% 100%;
+    height: 220px;
+    padding: 6px 30px;
+    border-radius: 20px;
+    .ladder {
+      position: relative;
+      height: 120px;
+      width: 200px;
+      margin: 10px auto;
+      .top-block {
+        display: flex;
+        justify-content: space-evenly;
+        width: 100%;
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        z-index: 9;
+        align-items: self-end;
+        .top1,
+        .top2,
+        .top3 {
+          width: 60px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          flex-direction: column;
+          .user-detail {
+            font-size: 12px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+          }
+          .pm {
+            font-weight: 600;
+            color: white;
+          }
+          .num {
+            color: #ffb63f;
+          }
+          .user-block {
+            font-size: 10px;
+            margin-bottom: 10px;
+            .user-avatar {
+              width: 40px;
+              height: 40px;
+              position: relative;
+              .tag {
+                position: absolute;
+                right: -7px;
+                top: -6px;
+                width: 20px;
+              }
+              .avatar {
+                width: 100%;
+                height: 100%;
+              }
+            }
+          }
+        }
+        .top1 {
+          margin-bottom: 20px;
+          .num {
+            color: #ffffb9;
+          }
+        }
+      }
+    }
+    .ladder::after {
+      content: "";
+      position: absolute;
+      bottom: 0;
+      left: 0;
+      width: 100%;
+      height: 70px;
+      background-image: url(/img/top.png);
+      background-size: 100% 100%;
+    }
+    .row {
+      font-size: 12px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin-top: 6px;
+      color: #999999;
+      .row-left {
+        display: flex;
+        align-items: center;
+        .row-avatar {
+          width: 30px;
+          height: 30px;
+          margin: 0 4px;
+        }
+      }
+      .row-right {
+        display: flex;
+        .row-tpis-num {
+          color: #f7931e;
+          display: flex;
+          align-items: center;
+          span {
+            width: 6px;
+            height: 6px;
+            border-radius: 50%;
+            background-color: #f7931e;
+            margin-left: 4px;
+          }
+        }
+      }
+    }
+  }
+}

+ 65 - 5
projects/live-app/src/moduls/tabs/ranking/ranking.component.ts

@@ -10,10 +10,70 @@ import * as Parse from 'parse';
   imports: [IonicModule],
 })
 export class RankingComponent implements OnInit {
+  user?: Parse.Object = Parse.User.current();
+  orderList: Array<any> = [
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+    {
+      name: '甜心宝贝',
+      avatar: 'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
+      num: 94.5,
+    },
+  ];
+  constructor() {}
 
-  constructor() { }
-
-  ngOnInit() {
-  }
-
+  ngOnInit() {}
 }

+ 49 - 0
projects/live-app/src/services/http.service.ts

@@ -0,0 +1,49 @@
+import { Injectable } from '@angular/core';
+import { HttpClient,HttpHeaders } from '@angular/common/http';
+import { Observable, throwError } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class HttpService {
+
+  constructor(public http: HttpClient) { }
+
+  customSQL(sql:string){
+    return new Promise((resolve,reason)=>{
+      this.http.post('https://server.fmode.cn/api/novaql/select',{
+        sql
+      }).subscribe(data=> {
+        resolve (data)
+      })
+    })
+  }
+
+  // 定义get请求方法
+  getMsg(url: string, params: any) {
+    return this.http.get(url, {
+      params
+    });
+  }
+
+  postAuth(company:string,idCard:string,name:string){
+    return new Promise((resolve,reason)=>{
+      this.http.post('https://server.fmode.cn/api/apig/idcard',{
+        company:company,
+        cardNo:idCard,
+        realName:name
+      }).subscribe(data=> {
+        resolve (data)
+      })
+    })
+  }
+
+
+  // 定义jsonp的方法
+  getJsonpMsg(url: string, cb: string) {
+    return this.http.jsonp(url, cb);
+  }
+
+
+}

+ 54 - 0
projects/live-app/src/services/utils.ts

@@ -0,0 +1,54 @@
+//身份证校验
+function IdentityCodeValid(code:string) {
+  let m = /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/
+  return m.test(code)
+}
+
+// 手机号校验
+function isPoneAvailable(poneInput:string) {
+  var myreg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/;
+  if (!myreg.test(poneInput)) {
+    return false;
+  } else {
+    return true;
+  }
+}
+// 身份证号获取出生年月日
+function getBirthdatByIdNo(iIdNo:string) {
+  var tmpStr = "";
+  iIdNo = iIdNo.replace(/^\s+|\s+$/g, "");
+
+  if (iIdNo.length == 15) {
+    tmpStr = iIdNo.substring(6, 12);
+    tmpStr = "19" + tmpStr;
+    tmpStr = tmpStr.substring(0, 4) + "/" + tmpStr.substring(4, 6) + "/" + tmpStr.substring(6)
+  } else {
+    tmpStr = iIdNo.substring(6, 14);
+    tmpStr = tmpStr.substring(0, 4) + "/" + tmpStr.substring(4, 6) + "/" + tmpStr.substring(6)
+  }
+  return tmpStr;
+}
+
+// 获取性别
+function getSex(idcard:string) {
+  let sex = ''
+  if (parseInt(idcard.substr(16, 1)) % 2 == 1) {
+    sex = '男'
+  } else {
+    sex = '女'
+  }
+  return sex
+}
+
+// 微信号校验
+function authCode(str:string){
+  let length = str.replace(/\s/g,"").length
+  return length
+}
+export const fun = {
+  IdentityCodeValid,
+  isPoneAvailable,
+  getBirthdatByIdNo,
+  getSex,
+  authCode
+}