添加页面文件
This commit is contained in:
parent
d2c89b4f02
commit
560bd306ee
@ -129,7 +129,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cli": {
|
"cli": {
|
||||||
"schematicCollections": ["@ionic/angular-toolkit"]
|
"schematicCollections": [
|
||||||
|
"@ionic/angular-toolkit"
|
||||||
|
],
|
||||||
|
"analytics": false
|
||||||
},
|
},
|
||||||
"schematics": {
|
"schematics": {
|
||||||
"@ionic/angular-toolkit:component": {
|
"@ionic/angular-toolkit:component": {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { CapacitorConfig } from '@capacitor/cli';
|
import type { CapacitorConfig } from '@capacitor/cli';
|
||||||
|
|
||||||
const config: CapacitorConfig = {
|
const config: CapacitorConfig = {
|
||||||
appId: 'io.ionic.starter',
|
appId: 'com.milimoe.fungame',
|
||||||
appName: 'FunGame.Web',
|
appName: 'FunGame',
|
||||||
webDir: 'www'
|
webDir: 'www'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "FunGame.Web",
|
"name": "FunGame",
|
||||||
"integrations": {
|
"integrations": {
|
||||||
"capacitor": {}
|
"capacitor": {}
|
||||||
},
|
},
|
||||||
|
|||||||
32
package-lock.json
generated
32
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "FunGame.Web",
|
"name": "com.milimoe.fungame",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "FunGame.Web",
|
"name": "com.milimoe.fungame",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^19.0.0",
|
"@angular/animations": "^19.0.0",
|
||||||
"@angular/common": "^19.0.0",
|
"@angular/common": "^19.0.0",
|
||||||
@ -16,13 +16,15 @@
|
|||||||
"@angular/platform-browser": "^19.0.0",
|
"@angular/platform-browser": "^19.0.0",
|
||||||
"@angular/platform-browser-dynamic": "^19.0.0",
|
"@angular/platform-browser-dynamic": "^19.0.0",
|
||||||
"@angular/router": "^19.0.0",
|
"@angular/router": "^19.0.0",
|
||||||
|
"@capacitor/android": "7.2.0",
|
||||||
"@capacitor/app": "7.0.1",
|
"@capacitor/app": "7.0.1",
|
||||||
"@capacitor/core": "7.2.0",
|
"@capacitor/core": "7.2.0",
|
||||||
"@capacitor/haptics": "7.0.1",
|
"@capacitor/haptics": "7.0.1",
|
||||||
"@capacitor/keyboard": "7.0.1",
|
"@capacitor/keyboard": "7.0.1",
|
||||||
"@capacitor/status-bar": "7.0.1",
|
"@capacitor/status-bar": "7.0.1",
|
||||||
"@ionic/angular": "^8.0.0",
|
"@ionic/angular": "^8.5.7",
|
||||||
"ionicons": "^7.0.0",
|
"ionicons": "^7.4.0",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.15.0"
|
||||||
@ -2556,6 +2558,15 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@capacitor/android": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@capacitor/android/-/android-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-zdhEy3jZPG5Toe/pGzKtDgIiBGywjaoEuQWnGVjBYPlSAEUtAhpZ2At7V0SCb26yluAuzrAUV0Ue+LQeEtHwFQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@capacitor/core": "^7.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@capacitor/app": {
|
"node_modules/@capacitor/app": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@capacitor/app/-/app-7.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@capacitor/app/-/app-7.0.1.tgz",
|
||||||
@ -13173,6 +13184,15 @@
|
|||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moment": {
|
||||||
|
"version": "2.30.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz",
|
||||||
|
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mrmime": {
|
"node_modules/mrmime": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz",
|
||||||
|
|||||||
16
package.json
16
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "FunGame.Web",
|
"name": "com.milimoe.fungame",
|
||||||
"version": "0.0.1",
|
"version": "1.0.0",
|
||||||
"author": "Ionic Framework",
|
"author": "Milimoe",
|
||||||
"homepage": "https://ionicframework.com/",
|
"homepage": "https://milimoe.com/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
@ -21,13 +21,15 @@
|
|||||||
"@angular/platform-browser": "^19.0.0",
|
"@angular/platform-browser": "^19.0.0",
|
||||||
"@angular/platform-browser-dynamic": "^19.0.0",
|
"@angular/platform-browser-dynamic": "^19.0.0",
|
||||||
"@angular/router": "^19.0.0",
|
"@angular/router": "^19.0.0",
|
||||||
|
"@capacitor/android": "7.2.0",
|
||||||
"@capacitor/app": "7.0.1",
|
"@capacitor/app": "7.0.1",
|
||||||
"@capacitor/core": "7.2.0",
|
"@capacitor/core": "7.2.0",
|
||||||
"@capacitor/haptics": "7.0.1",
|
"@capacitor/haptics": "7.0.1",
|
||||||
"@capacitor/keyboard": "7.0.1",
|
"@capacitor/keyboard": "7.0.1",
|
||||||
"@capacitor/status-bar": "7.0.1",
|
"@capacitor/status-bar": "7.0.1",
|
||||||
"@ionic/angular": "^8.0.0",
|
"@ionic/angular": "^8.5.7",
|
||||||
"ionicons": "^7.0.0",
|
"ionicons": "^7.4.0",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.15.0"
|
||||||
@ -60,5 +62,5 @@
|
|||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"typescript": "~5.6.3"
|
"typescript": "~5.6.3"
|
||||||
},
|
},
|
||||||
"description": "An Ionic project"
|
"description": "FunGame Web Version"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { IonApp, IonRouterOutlet } from '@ionic/angular/standalone';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: 'app.component.html',
|
templateUrl: 'app.component.html',
|
||||||
imports: [IonApp, IonRouterOutlet],
|
imports: [IonApp, IonRouterOutlet]
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|||||||
@ -1,8 +1,43 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
|
import { TabsPage } from './tabs/tabs.page';
|
||||||
|
import { authGuard } from './guards/auth.guard';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
|
component: TabsPage,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'home',
|
||||||
|
loadComponent: () => import('./pages/home/home.page').then((m) => m.HomePage)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'feed',
|
||||||
|
loadComponent: () => import('./pages/feed/feed.page').then((m) => m.FeedPage)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'profile',
|
||||||
|
loadComponent: () => import('./pages/profile/profile.page').then((m) => m.ProfilePage),
|
||||||
|
canActivate: [authGuard]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'login',
|
||||||
|
loadComponent: () => import('./pages/login/login.page').then((m) => m.LoginPage)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'register',
|
||||||
|
loadComponent: () => import('./pages/register/register.page').then((m) => m.RegisterPage)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirectTo: 'home',
|
||||||
|
pathMatch: 'full',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirectTo: 'home',
|
||||||
|
pathMatch: 'full'
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
37
src/app/components/feed-card/feed-card.component.html
Normal file
37
src/app/components/feed-card/feed-card.component.html
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<ion-card>
|
||||||
|
<ion-card-header>
|
||||||
|
<ion-card-title>{{ card.title }}</ion-card-title>
|
||||||
|
<ion-card-subtitle>{{ card.author }}</ion-card-subtitle>
|
||||||
|
</ion-card-header>
|
||||||
|
<ion-card-content>
|
||||||
|
发布于:{{ card.date }}
|
||||||
|
</ion-card-content>
|
||||||
|
<ion-card-content>
|
||||||
|
<p style="white-space: pre-wrap;">{{ card.content }}</p>
|
||||||
|
</ion-card-content>
|
||||||
|
<ion-card-content style="display: flex; justify-content: space-between; align-items: center; padding: 0 10px; gap: 10px;">
|
||||||
|
<div style="display: flex; justify-content: flex-start; align-items: center; flex-grow: 1; min-width: 0;">
|
||||||
|
Likes: {{ card.likes }}
|
||||||
|
<ion-button>
|
||||||
|
<ion-icon name="thumbs-up-sharp"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center; flex-grow: 1; min-width: 0;">
|
||||||
|
Forwards: {{ card.forwards }}
|
||||||
|
<ion-button>
|
||||||
|
<ion-icon name="share-social-sharp"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: center; align-items: center; flex-grow: 1; min-width: 0;">
|
||||||
|
Comments: {{ card.comments }}
|
||||||
|
<ion-button>
|
||||||
|
<ion-icon name="chatbubble-ellipses-sharp"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: flex-end; align-items: center; flex-grow: 1; min-width: 0;">
|
||||||
|
<ion-button (click)="triggerScrollToTop()">
|
||||||
|
<ion-icon name="chevron-up-circle-sharp"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
24
src/app/components/feed-card/feed-card.component.spec.ts
Normal file
24
src/app/components/feed-card/feed-card.component.spec.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
|
import { IonicModule } from '@ionic/angular';
|
||||||
|
|
||||||
|
import { FeedCardComponent } from './feed-card.component';
|
||||||
|
|
||||||
|
describe('FeedCardComponent', () => {
|
||||||
|
let component: FeedCardComponent;
|
||||||
|
let fixture: ComponentFixture<FeedCardComponent>;
|
||||||
|
|
||||||
|
beforeEach(waitForAsync(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ FeedCardComponent ],
|
||||||
|
imports: [IonicModule.forRoot()]
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FeedCardComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
30
src/app/components/feed-card/feed-card.component.ts
Normal file
30
src/app/components/feed-card/feed-card.component.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCardContent, IonButton, IonIcon } from '@ionic/angular/standalone';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
import { thumbsUpSharp, shareSocialSharp, chatbubbleEllipsesSharp, chevronUpCircleSharp } from 'ionicons/icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-feed-card',
|
||||||
|
templateUrl: './feed-card.component.html',
|
||||||
|
styleUrls: ['./feed-card.component.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCardContent, IonButton, IonIcon, CommonModule]
|
||||||
|
})
|
||||||
|
export class FeedCardComponent {
|
||||||
|
@Input() card: any;
|
||||||
|
@Output() scrollToTop = new EventEmitter<void>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
addIcons({
|
||||||
|
'thumbs-up-sharp': thumbsUpSharp,
|
||||||
|
'share-social-sharp': shareSocialSharp,
|
||||||
|
'chatbubble-ellipses-sharp': chatbubbleEllipsesSharp,
|
||||||
|
'chevron-up-circle-sharp': chevronUpCircleSharp
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerScrollToTop() {
|
||||||
|
this.scrollToTop.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/app/guards/auth.guard.spec.ts
Normal file
17
src/app/guards/auth.guard.spec.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { CanActivateFn } from '@angular/router';
|
||||||
|
|
||||||
|
import { authGuard } from './auth.guard';
|
||||||
|
|
||||||
|
describe('authGuard', () => {
|
||||||
|
const executeGuard: CanActivateFn = (...guardParameters) =>
|
||||||
|
TestBed.runInInjectionContext(() => authGuard(...guardParameters));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(executeGuard).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
15
src/app/guards/auth.guard.ts
Normal file
15
src/app/guards/auth.guard.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { inject } from '@angular/core';
|
||||||
|
import { CanActivateFn, Router } from '@angular/router';
|
||||||
|
import { AuthService } from '../services/auth.service';
|
||||||
|
|
||||||
|
export const authGuard: CanActivateFn = (route, state) => {
|
||||||
|
const authService = inject(AuthService);
|
||||||
|
const router = inject(Router);
|
||||||
|
|
||||||
|
if (authService.isLoggedIn()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
router.navigateByUrl('/login');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
40
src/app/pages/feed/feed.page.html
Normal file
40
src/app/pages/feed/feed.page.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar color="primary">
|
||||||
|
<ion-title>动态</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding" [fullscreen]="true">
|
||||||
|
<ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
|
||||||
|
<ion-refresher-content></ion-refresher-content>
|
||||||
|
</ion-refresher>
|
||||||
|
|
||||||
|
<ion-radio-group [(ngModel)]="isTeam">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>个人竞技模式(12人混战)</ion-label>
|
||||||
|
<ion-radio slot="start" [value]="false"></ion-radio>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>团队死亡竞赛(12人2队30分胜)</ion-label>
|
||||||
|
<ion-radio slot="start" [value]="true"></ion-radio>
|
||||||
|
</ion-item>
|
||||||
|
</ion-radio-group>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>显示完整回合日志</ion-label>
|
||||||
|
<ion-checkbox slot="start" [(ngModel)]="showAll"></ion-checkbox>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<div style="display: flex; justify-content: flex-end; align-items: center;">
|
||||||
|
立即开始一局 FunGame 模拟 >>>
|
||||||
|
<ion-button (click)="fetchPosts()">
|
||||||
|
<ion-icon name="rocket-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-loading
|
||||||
|
[isOpen]="loading"
|
||||||
|
message="加载中..."
|
||||||
|
(didDismiss)="loading = false"
|
||||||
|
></ion-loading>
|
||||||
|
|
||||||
|
<app-feed-card *ngFor="let post of posts" [card]="post" (scrollToTop)="scrollToTop()"></app-feed-card>
|
||||||
|
</ion-content>
|
||||||
@ -1,13 +1,12 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { FeedPage } from './feed.page';
|
||||||
|
|
||||||
import { Tab1Page } from './tab1.page';
|
describe('FeedPage', () => {
|
||||||
|
let component: FeedPage;
|
||||||
|
let fixture: ComponentFixture<FeedPage>;
|
||||||
|
|
||||||
describe('Tab1Page', () => {
|
beforeEach(() => {
|
||||||
let component: Tab1Page;
|
fixture = TestBed.createComponent(FeedPage);
|
||||||
let fixture: ComponentFixture<Tab1Page>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
fixture = TestBed.createComponent(Tab1Page);
|
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
56
src/app/pages/feed/feed.page.ts
Normal file
56
src/app/pages/feed/feed.page.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Component, ViewChild } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { IonContent, IonHeader, IonTitle, IonToolbar, IonRadioGroup, IonItem, IonLabel, IonRadio, IonCheckbox, IonButton, IonIcon, IonRefresher, IonRefresherContent, IonLoading } from '@ionic/angular/standalone';
|
||||||
|
import { FeedService } from '../../services/feed.service';
|
||||||
|
import { FeedCardComponent } from '../../components/feed-card/feed-card.component';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
import { rocketOutline } from 'ionicons/icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-feed',
|
||||||
|
templateUrl: './feed.page.html',
|
||||||
|
styleUrls: ['./feed.page.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonContent, IonHeader, IonTitle, IonToolbar, IonRadioGroup, IonItem, IonLabel, IonRadio, IonCheckbox, IonButton, IonIcon, IonRefresher, IonRefresherContent, IonLoading, CommonModule, FormsModule, FeedCardComponent]
|
||||||
|
})
|
||||||
|
export class FeedPage {
|
||||||
|
@ViewChild(IonContent) content!: IonContent;
|
||||||
|
posts: any[] = [];
|
||||||
|
isTeam: boolean = false;
|
||||||
|
showAll: boolean = false;
|
||||||
|
loading: boolean = false;
|
||||||
|
|
||||||
|
constructor(private feedService: FeedService) {
|
||||||
|
addIcons({ 'rocket-outline': rocketOutline });
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchPosts() {
|
||||||
|
this.loading = true;
|
||||||
|
this.feedService.fetchPosts(this.isTeam, this.showAll).subscribe({
|
||||||
|
next: (posts) => {
|
||||||
|
this.posts = posts;
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
doRefresh(event: any) {
|
||||||
|
this.feedService.fetchPosts(this.isTeam, this.showAll).subscribe({
|
||||||
|
next: (posts) => {
|
||||||
|
this.posts = posts;
|
||||||
|
event.target.complete();
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
event.target.complete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToTop() {
|
||||||
|
this.content.scrollToTop(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/app/pages/home/home.page.html
Normal file
9
src/app/pages/home/home.page.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar color="primary">
|
||||||
|
<ion-title>首页</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<h1>欢迎来到首页</h1>
|
||||||
|
<p>这是应用的首页内容。</p>
|
||||||
|
</ion-content>
|
||||||
@ -1,13 +1,12 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { HomePage } from './home.page';
|
||||||
|
|
||||||
import { Tab2Page } from './tab2.page';
|
describe('HomePage', () => {
|
||||||
|
let component: HomePage;
|
||||||
|
let fixture: ComponentFixture<HomePage>;
|
||||||
|
|
||||||
describe('Tab2Page', () => {
|
beforeEach(() => {
|
||||||
let component: Tab2Page;
|
fixture = TestBed.createComponent(HomePage);
|
||||||
let fixture: ComponentFixture<Tab2Page>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
fixture = TestBed.createComponent(Tab2Page);
|
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
23
src/app/pages/home/home.page.ts
Normal file
23
src/app/pages/home/home.page.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home',
|
||||||
|
templateUrl: './home.page.html',
|
||||||
|
styleUrls: ['./home.page.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
|
||||||
|
})
|
||||||
|
export class HomePage implements OnInit {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
addIcons({ });
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
23
src/app/pages/login/login.page.html
Normal file
23
src/app/pages/login/login.page.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar color="primary">
|
||||||
|
<ion-title>登录</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-grid>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label position="floating">邮箱</ion-label>
|
||||||
|
<ion-input [(ngModel)]="email" type="email"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label position="floating">密码</ion-label>
|
||||||
|
<ion-input [(ngModel)]="password" type="password"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
<ion-button expand="block" (click)="login()" class="ion-margin-top">登录</ion-button>
|
||||||
|
<ion-button expand="block" fill="outline" [routerLink]="['/register']" class="ion-margin-top">去注册</ion-button>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
</ion-content>
|
||||||
0
src/app/pages/login/login.page.scss
Normal file
0
src/app/pages/login/login.page.scss
Normal file
@ -1,13 +1,12 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { LoginPage } from './login.page';
|
||||||
|
|
||||||
import { Tab3Page } from './tab3.page';
|
describe('LoginPage', () => {
|
||||||
|
let component: LoginPage;
|
||||||
|
let fixture: ComponentFixture<LoginPage>;
|
||||||
|
|
||||||
describe('Tab3Page', () => {
|
beforeEach(() => {
|
||||||
let component: Tab3Page;
|
fixture = TestBed.createComponent(LoginPage);
|
||||||
let fixture: ComponentFixture<Tab3Page>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
fixture = TestBed.createComponent(Tab3Page);
|
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
29
src/app/pages/login/login.page.ts
Normal file
29
src/app/pages/login/login.page.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { Router, RouterModule } from '@angular/router';
|
||||||
|
import { IonContent, IonHeader, IonTitle, IonToolbar, IonGrid, IonRow, IonCol, IonItem, IonLabel, IonInput, IonButton } from '@ionic/angular/standalone';
|
||||||
|
import { AuthService } from '../../services/auth.service';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login',
|
||||||
|
templateUrl: './login.page.html',
|
||||||
|
styleUrls: ['./login.page.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonContent, IonHeader, IonTitle, IonToolbar, IonGrid, IonRow, IonCol, IonItem, IonLabel, IonInput, IonButton, CommonModule, FormsModule, RouterModule]
|
||||||
|
})
|
||||||
|
export class LoginPage {
|
||||||
|
email: string = '';
|
||||||
|
password: string = '';
|
||||||
|
|
||||||
|
constructor(private authService: AuthService, private router: Router) {
|
||||||
|
addIcons({ });
|
||||||
|
}
|
||||||
|
|
||||||
|
login() {
|
||||||
|
if (this.authService.login(this.email, this.password)) {
|
||||||
|
this.router.navigateByUrl('/profile');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
src/app/pages/profile/profile.page.html
Normal file
130
src/app/pages/profile/profile.page.html
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<ion-header class="ion-no-border">
|
||||||
|
<ion-toolbar color="transparent">
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-button>
|
||||||
|
<ion-icon slot="icon-only" name="menu-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<ion-button>
|
||||||
|
<ion-icon slot="icon-only" name="share-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="profile-page-content">
|
||||||
|
<!-- 页面背景图容器 -->
|
||||||
|
<div class="profile-background-image">
|
||||||
|
<img src="assets/images/bg.jpg" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="authService.isLoggedIn(); else notLoggedIn" class="profile-container">
|
||||||
|
<!-- 用户信息区 -->
|
||||||
|
<div class="user-info-section">
|
||||||
|
<ion-avatar class="user-avatar">
|
||||||
|
<img [src]="user?.avatar ? user.avatar : 'assets/images/noavar.gif'" />
|
||||||
|
</ion-avatar>
|
||||||
|
|
||||||
|
<div class="user-details">
|
||||||
|
<h2 class="user-name">{{ user?.name || '用户昵称' }}</h2>
|
||||||
|
<div class="user-tags">
|
||||||
|
<!-- 根据性别动态显示图标 -->
|
||||||
|
<ion-icon *ngIf="user?.gender === 'female'" name="female-outline" class="gender-icon female"></ion-icon>
|
||||||
|
<!-- 认证标签 -->
|
||||||
|
<span *ngIf="user?.isVerified" class="verified-tag">
|
||||||
|
<ion-icon name="checkmark-circle-outline"></ion-icon> 困困薯
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p class="user-bio">{{ user?.bio || '这个人很懒,什么都没留下。' }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据统计区 -->
|
||||||
|
<ion-grid class="stats-grid">
|
||||||
|
<ion-row>
|
||||||
|
<ion-col size="4" class="stat-item">
|
||||||
|
<div class="stat-number">{{ user?.following || 0 }}</div>
|
||||||
|
<div class="stat-label">关注</div>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="4" class="stat-item">
|
||||||
|
<div class="stat-number">{{ user?.followers || 0 }}</div>
|
||||||
|
<div class="stat-label">粉丝</div>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="4" class="stat-item">
|
||||||
|
<div class="stat-number">{{ user?.likesCollections || 0 }}</div>
|
||||||
|
<div class="stat-label">获赞与收藏</div>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
|
||||||
|
<!-- 操作区域:包含分享瞬间、编辑资料和设置 -->
|
||||||
|
<div class="profile-actions-main-row">
|
||||||
|
<!-- 左侧:分享瞬间 -->
|
||||||
|
<div class="moment-section">
|
||||||
|
<div class="moment-action-item">
|
||||||
|
<ion-button fill="clear" class="add-moment-button">
|
||||||
|
<ion-icon slot="icon-only" name="add-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<div class="moment-action-label">分享瞬间</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:编辑资料 & 设置 -->
|
||||||
|
<div class="edit-settings-buttons">
|
||||||
|
<ion-button fill="outline" shape="round" class="edit-profile-button">编辑资料</ion-button>
|
||||||
|
<ion-button fill="outline" shape="round" class="settings-button">
|
||||||
|
<ion-icon slot="icon-only" name="settings-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容切换标签 -->
|
||||||
|
<ion-segment [(ngModel)]="selectedSegment" mode="md" class="profile-segment">
|
||||||
|
<ion-segment-button value="notes">
|
||||||
|
<p>笔记</p> <!-- 移除 style="color: white;" -->
|
||||||
|
</ion-segment-button>
|
||||||
|
<ion-segment-button value="collections">
|
||||||
|
<p>收藏</p> <!-- 移除 style="color: white;" -->
|
||||||
|
</ion-segment-button>
|
||||||
|
<ion-segment-button value="liked">
|
||||||
|
<p>赞过</p> <!-- 移除 style="color: white;" -->
|
||||||
|
</ion-segment-button>
|
||||||
|
</ion-segment>
|
||||||
|
|
||||||
|
<!-- 内容展示区 (瀑布流布局) -->
|
||||||
|
<div class="content-grid">
|
||||||
|
<ion-grid>
|
||||||
|
<ion-row class="ion-align-items-start">
|
||||||
|
<!-- 左列 -->
|
||||||
|
<ion-col size="6">
|
||||||
|
<div *ngFor="let post of getPostsBySegment(); let i = index">
|
||||||
|
<div class="post-item" *ngIf="i % 2 === 0">
|
||||||
|
<img [src]="post.imageUrl" alt="Post Image" class="post-image" />
|
||||||
|
<!-- 可以添加帖子标题、点赞数等 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-col>
|
||||||
|
<!-- 右列 -->
|
||||||
|
<ion-col size="6">
|
||||||
|
<div *ngFor="let post of getPostsBySegment(); let i = index">
|
||||||
|
<div class="post-item" *ngIf="i % 2 !== 0">
|
||||||
|
<img [src]="post.imageUrl" alt="Post Image" class="post-image" />
|
||||||
|
<!-- 可以添加帖子标题、点赞数等 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #notLoggedIn>
|
||||||
|
<div class="not-logged-in-container">
|
||||||
|
<p>请登录以查看您的个人资料。</p>
|
||||||
|
<ion-button expand="block" [routerLink]="['/login']">登录</ion-button>
|
||||||
|
<ion-button expand="block" fill="outline" [routerLink]="['/register']">注册</ion-button>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ion-content>
|
||||||
288
src/app/pages/profile/profile.page.scss
Normal file
288
src/app/pages/profile/profile.page.scss
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
// 确保 ion-header 和 ion-content 的背景透明,以便背景图显示
|
||||||
|
ion-header {
|
||||||
|
--background: transparent;
|
||||||
|
--border-width: 0; // 移除默认边框
|
||||||
|
position: absolute; // 让头部浮动在内容之上
|
||||||
|
width: 100%;
|
||||||
|
z-index: 10; // 确保头部在最上层
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-toolbar {
|
||||||
|
--background: transparent;
|
||||||
|
--border-width: 0;
|
||||||
|
color: white; // 头部图标和文字颜色
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-button {
|
||||||
|
--color: white; // 头部按钮图标颜色
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-page-content {
|
||||||
|
--background: var(--ion-color-light);
|
||||||
|
--padding-top: 0;
|
||||||
|
--padding-bottom: 0;
|
||||||
|
--padding-start: 0;
|
||||||
|
--padding-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面背景图容器
|
||||||
|
.profile-background-image {
|
||||||
|
position: absolute; // 保持绝对定位,使其不影响文档流
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 425px; // 调整背景图高度以覆盖更多区域
|
||||||
|
overflow: hidden; // 隐藏超出容器的部分
|
||||||
|
z-index: 1; // 确保在内容下方
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内部的 img 标签样式
|
||||||
|
.profile-background-image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover; // 关键:图片会覆盖整个容器,保持宽高比,裁剪多余部分
|
||||||
|
object-position: center; // 关键:图片在容器中居中显示
|
||||||
|
filter: brightness(0.8); // 调整亮度,让文字更清晰
|
||||||
|
display: block; // 移除图片底部可能存在的空白
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-container {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2; // 确保内容在背景图上方
|
||||||
|
padding: 20px;
|
||||||
|
padding-top: 120px; // 增加顶部内边距,给头部和背景图留出更多空间
|
||||||
|
color: white; // 默认文字颜色为白色
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户信息区
|
||||||
|
.user-info-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
margin-right: 15px;
|
||||||
|
border: 2px solid white; // 头像白色边框
|
||||||
|
flex-shrink: 0; // 防止头像被压缩
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-details {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 1.8em;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-tags {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gender-icon {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-right: 5px;
|
||||||
|
&.female {
|
||||||
|
color: #ff69b4; // 粉色
|
||||||
|
}
|
||||||
|
&.male {
|
||||||
|
color: #00bfff; // 蓝色
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.verified-tag {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 3px 8px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
ion-icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
font-size: 1em;
|
||||||
|
color: #4CAF50; // 绿色勾
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-bio {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据统计区
|
||||||
|
.stats-grid {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
.stat-number {
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.stat-label {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合后的操作区域
|
||||||
|
.profile-actions-main-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* 将左右两部分推开 */
|
||||||
|
align-items: flex-end; /* 底部对齐 */
|
||||||
|
margin: 20px;
|
||||||
|
margin-top: -30px; /* 向上微调,使其与统计数据行对齐 */
|
||||||
|
position: relative; /* 确保 z-index 作用 */
|
||||||
|
z-index: 5; /* 确保在背景图和内容上方 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.moment-section {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px; /* 分享瞬间和我的瞬间之间的间距 (现在只有一个,但保留) */
|
||||||
|
}
|
||||||
|
|
||||||
|
.moment-action-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: #ff69b4; /* 确保文字颜色可见 */
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-moment-button {
|
||||||
|
--background: transparent;
|
||||||
|
--color: white;
|
||||||
|
font-size: 2em;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none; /* 移除阴影 */
|
||||||
|
margin-bottom: 5px; /* 文字的间距 */
|
||||||
|
--padding-start: 0;
|
||||||
|
--padding-end: 0;
|
||||||
|
--padding-top: 0;
|
||||||
|
--padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除我的瞬间相关样式
|
||||||
|
.moment-action-item.my-moments {
|
||||||
|
display: none; // 隐藏,或者直接删除这部分样式
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-moments-thumbnail {
|
||||||
|
display: none; // 隐藏,或者直接删除这部分样式
|
||||||
|
}
|
||||||
|
|
||||||
|
.moment-action-label {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: white;
|
||||||
|
white-space: nowrap; /* 防止文字换行 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-settings-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复编辑资料和设置按钮样式
|
||||||
|
.edit-profile-button, .settings-button {
|
||||||
|
--background: rgba(255, 255, 255, 0.2);
|
||||||
|
--background-activated: rgba(255, 255, 255, 0.3);
|
||||||
|
--color: white;
|
||||||
|
--border-color: rgba(255, 255, 255, 0.5);
|
||||||
|
--border-width: 1px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
height: 35px;
|
||||||
|
box-shadow: none; /* 移除阴影 */
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-button {
|
||||||
|
width: 35px; /* 使其成为正方形按钮 */
|
||||||
|
--padding-start: 0;
|
||||||
|
--padding-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容切换标签
|
||||||
|
.profile-segment {
|
||||||
|
--background: white; /* segment 背景改为白色 */
|
||||||
|
--background-checked: white;
|
||||||
|
--color: #999; /* 未选中文字颜色 */
|
||||||
|
--color-checked: black; /* 选中文字颜色 */
|
||||||
|
margin-top: 20px;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0 20px;
|
||||||
|
height: 50px;
|
||||||
|
border-bottom: 1px solid #eee; /* 添加底部边框 */
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-segment-button {
|
||||||
|
--indicator-color: black; // 下划线颜色
|
||||||
|
--indicator-height: 2px;
|
||||||
|
--padding-start: 0;
|
||||||
|
--padding-end: 0;
|
||||||
|
--padding-top: 15px;
|
||||||
|
--padding-bottom: 15px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-transform: none; // 防止大写
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保 segment 内部的文字颜色是黑色的
|
||||||
|
.profile-segment ion-segment-button p {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-segment ion-segment-button.segment-button-checked p {
|
||||||
|
font-weight: bold; // 选中时加粗
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 内容展示区 (瀑布流布局)
|
||||||
|
.content-grid {
|
||||||
|
background-color: var(--ion-color-light); // 浅色背景,与顶部深色背景区分
|
||||||
|
padding: 10px;
|
||||||
|
min-height: 400px; // 确保有足够高度
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-item {
|
||||||
|
margin-bottom: 10px; // 帖子之间的间距
|
||||||
|
background-color: white; /* 帖子背景改为白色 */
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden; // 确保图片圆角
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-image {
|
||||||
|
width: 100%;
|
||||||
|
height: auto; // 保持图片比例
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未登录状态
|
||||||
|
.not-logged-in-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
color: gray;
|
||||||
|
p {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/app/pages/profile/profile.page.spec.ts
Normal file
17
src/app/pages/profile/profile.page.spec.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ProfilePage } from './profile.page';
|
||||||
|
|
||||||
|
describe('ProfilePage', () => {
|
||||||
|
let component: ProfilePage;
|
||||||
|
let fixture: ComponentFixture<ProfilePage>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProfilePage);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
82
src/app/pages/profile/profile.page.ts
Normal file
82
src/app/pages/profile/profile.page.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { Router, RouterModule } from '@angular/router';
|
||||||
|
import {
|
||||||
|
IonContent, IonHeader, IonTitle, IonToolbar, IonCard, IonCardHeader, IonCardTitle,
|
||||||
|
IonCardContent, IonItem, IonAvatar, IonLabel, IonButton, IonButtons, IonIcon,
|
||||||
|
IonGrid, IonRow, IonCol, IonSegment, IonSegmentButton // 引入新的组件
|
||||||
|
} from '@ionic/angular/standalone';
|
||||||
|
import { AuthService } from '../../services/auth.service';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
// 导入所有需要的图标
|
||||||
|
import { menuOutline, shareOutline, addOutline, settingsOutline, femaleOutline, checkmarkCircleOutline } from 'ionicons/icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-profile',
|
||||||
|
templateUrl: './profile.page.html',
|
||||||
|
styleUrls: ['./profile.page.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
IonContent, IonHeader, IonTitle, IonToolbar, IonCard, IonCardHeader, IonCardTitle,
|
||||||
|
IonCardContent, IonItem, IonAvatar, IonLabel, IonButton, IonButtons, IonIcon,
|
||||||
|
IonGrid, IonRow, IonCol, IonSegment, IonSegmentButton, // 添加到 imports
|
||||||
|
CommonModule, FormsModule, RouterModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class ProfilePage implements OnInit {
|
||||||
|
user: any;
|
||||||
|
selectedSegment: string = 'notes'; // 默认选中笔记
|
||||||
|
|
||||||
|
// 模拟帖子数据,用于瀑布流布局
|
||||||
|
posts: any[] = [
|
||||||
|
{ segment: 'notes', imageUrl: 'assets/images/test/9.png', title: '我的第一篇笔记', likes: 10 },
|
||||||
|
{ segment: 'notes', imageUrl: 'assets/images/test/ar.png', title: '生活小记', likes: 25 },
|
||||||
|
{ segment: 'notes', imageUrl: 'assets/images/test/986.jpg', title: '旅行日记', likes: 8 },
|
||||||
|
{ segment: 'notes', imageUrl: 'assets/images/test/ar.png', title: '学习心得', likes: 15 },
|
||||||
|
{ segment: 'notes', imageUrl: 'assets/images/test/9.png', title: '美食分享', likes: 30 },
|
||||||
|
{ segment: 'collections', imageUrl: 'assets/images/test/986.jpg', title: '收藏夹1', likes: 5 },
|
||||||
|
{ segment: 'collections', imageUrl: 'assets/images/test/ar.png', title: '灵感收集', likes: 12 },
|
||||||
|
{ segment: 'liked', imageUrl: 'assets/images/test/ar.png', title: '赞过的作品', likes: 50 },
|
||||||
|
{ segment: 'liked', imageUrl: 'assets/images/test/986.jpg', title: '精彩瞬间', likes: 40 },
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(public authService: AuthService, private router: Router) {
|
||||||
|
// 添加所有需要的图标
|
||||||
|
addIcons({
|
||||||
|
menuOutline,
|
||||||
|
shareOutline,
|
||||||
|
addOutline,
|
||||||
|
settingsOutline,
|
||||||
|
femaleOutline,
|
||||||
|
checkmarkCircleOutline
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.authService.user$.subscribe(user => {
|
||||||
|
// 模拟用户数据,包含更多字段以填充 UI
|
||||||
|
this.user = {
|
||||||
|
...user, // 合并现有用户数据
|
||||||
|
name: user?.name || '测试用户',
|
||||||
|
bio: user?.bio || '这个人很懒,什么都没留下。',
|
||||||
|
gender: user?.gender || 'female', // 模拟性别,可以是 'male' 或 'female'
|
||||||
|
isVerified: user?.isVerified || true, // 模拟是否认证
|
||||||
|
following: user?.following || 11, // 关注数
|
||||||
|
followers: user?.followers || 49, // 粉丝数
|
||||||
|
likesCollections: user?.likesCollections || 362, // 获赞与收藏数
|
||||||
|
// 已删除:myMomentsThumbnail
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.authService.logout();
|
||||||
|
this.router.navigateByUrl('/login'); // 或者 '/tabs/profile' 根据你的路由设置
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据选中的 segment 过滤帖子数据
|
||||||
|
getPostsBySegment(): any[] {
|
||||||
|
return this.posts.filter(post => post.segment === this.selectedSegment);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/app/pages/register/register.page.html
Normal file
23
src/app/pages/register/register.page.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar color="primary">
|
||||||
|
<ion-title>注册</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-grid>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label position="floating">邮箱</ion-label>
|
||||||
|
<ion-input [(ngModel)]="email" type="email"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label position="floating">密码</ion-label>
|
||||||
|
<ion-input [(ngModel)]="password" type="password"></ion-input>
|
||||||
|
</ion-item>
|
||||||
|
<ion-button expand="block" (click)="register()" class="ion-margin-top">注册</ion-button>
|
||||||
|
<ion-button expand="block" fill="outline" [routerLink]="['/login']" class="ion-margin-top">去登录</ion-button>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
</ion-content>
|
||||||
0
src/app/pages/register/register.page.scss
Normal file
0
src/app/pages/register/register.page.scss
Normal file
17
src/app/pages/register/register.page.spec.ts
Normal file
17
src/app/pages/register/register.page.spec.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { RegisterPage } from './register.page';
|
||||||
|
|
||||||
|
describe('RegisterPage', () => {
|
||||||
|
let component: RegisterPage;
|
||||||
|
let fixture: ComponentFixture<RegisterPage>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(RegisterPage);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
29
src/app/pages/register/register.page.ts
Normal file
29
src/app/pages/register/register.page.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { Router, RouterModule } from '@angular/router';
|
||||||
|
import { IonContent, IonHeader, IonTitle, IonToolbar, IonGrid, IonRow, IonCol, IonItem, IonLabel, IonInput, IonButton } from '@ionic/angular/standalone';
|
||||||
|
import { AuthService } from '../../services/auth.service';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-register',
|
||||||
|
templateUrl: './register.page.html',
|
||||||
|
styleUrls: ['./register.page.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonContent, IonHeader, IonTitle, IonToolbar, IonGrid, IonRow, IonCol, IonItem, IonLabel, IonInput, IonButton, CommonModule, FormsModule, RouterModule]
|
||||||
|
})
|
||||||
|
export class RegisterPage {
|
||||||
|
email: string = '';
|
||||||
|
password: string = '';
|
||||||
|
|
||||||
|
constructor(private authService: AuthService, private router: Router) {
|
||||||
|
addIcons({ });
|
||||||
|
}
|
||||||
|
|
||||||
|
register() {
|
||||||
|
if (this.authService.login(this.email, this.password)) {
|
||||||
|
this.router.navigateByUrl('/profile');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/app/services/auth.service.spec.ts
Normal file
16
src/app/services/auth.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
|
describe('AuthService', () => {
|
||||||
|
let service: AuthService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(AuthService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
34
src/app/services/auth.service.ts
Normal file
34
src/app/services/auth.service.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AuthService {
|
||||||
|
private userSubject = new BehaviorSubject<any>(null);
|
||||||
|
user$ = this.userSubject.asObservable();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
const storedUser = localStorage.getItem('user');
|
||||||
|
if (storedUser) {
|
||||||
|
this.userSubject.next(JSON.parse(storedUser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
login(email: string, password: string): boolean {
|
||||||
|
// 模拟登录逻辑
|
||||||
|
const user = { email, name: '测试用户', avatar: '' };
|
||||||
|
localStorage.setItem('user', JSON.stringify(user));
|
||||||
|
this.userSubject.next(user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
localStorage.removeItem('user');
|
||||||
|
this.userSubject.next(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoggedIn(): boolean {
|
||||||
|
return !!this.userSubject.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/app/services/feed.service.spec.ts
Normal file
16
src/app/services/feed.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { FeedService } from './feed.service';
|
||||||
|
|
||||||
|
describe('FeedService', () => {
|
||||||
|
let service: FeedService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(FeedService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
74
src/app/services/feed.service.ts
Normal file
74
src/app/services/feed.service.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Observable, throwError } from 'rxjs';
|
||||||
|
import { catchError, map } from 'rxjs/operators';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { environment } from 'src/environments/environment';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class FeedService {
|
||||||
|
private apiUrl = environment.apiUrl;
|
||||||
|
private authToken = environment.authToken;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {}
|
||||||
|
|
||||||
|
fetchPosts(isTeam: boolean, showAll: boolean): Observable<any[]> {
|
||||||
|
const url = `${this.apiUrl}?isweb=true&isteam=${isTeam}&showall=${showAll}`;
|
||||||
|
return this.http.get<string[]>(url, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': this.authToken,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).pipe(
|
||||||
|
map(results => {
|
||||||
|
let rank = 0;
|
||||||
|
return results.map(result => {
|
||||||
|
let title = '';
|
||||||
|
const strs = result.includes('===') ? result.split('===') : result.split('==');
|
||||||
|
|
||||||
|
if (strs.length > 1) {
|
||||||
|
const content = strs[1].trim();
|
||||||
|
if (content.startsWith('Round')) {
|
||||||
|
title = `第 ${content.replace('Round', '').trim()} 回合`;
|
||||||
|
} else if (content.startsWith('终局审判')) {
|
||||||
|
title = '终局审判';
|
||||||
|
} else if (content.startsWith('排名')) {
|
||||||
|
title = '排名';
|
||||||
|
} else if (content.startsWith('伤害排行榜')) {
|
||||||
|
title = '伤害排行榜';
|
||||||
|
} else if (content.startsWith('空投')) {
|
||||||
|
title = '空投';
|
||||||
|
} else if (content.startsWith('技术得分排行榜')) {
|
||||||
|
title = '技术得分排行榜';
|
||||||
|
} else if (content.startsWith('本场比赛最佳角色')) {
|
||||||
|
title = '本场比赛最佳角色';
|
||||||
|
} else if (content.startsWith('团队模式随机分组')) {
|
||||||
|
title = '团队模式随机分组';
|
||||||
|
} else if (content.startsWith('角色')) {
|
||||||
|
rank++;
|
||||||
|
title = `第 ${rank} 名:${content.replace('角色', '').trim()}`;
|
||||||
|
}
|
||||||
|
} else if (strs.length > 3) {
|
||||||
|
title = `${strs[1].trim()} ${strs[3].replace('角色', '').trim()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
author: 'FunGame 模拟',
|
||||||
|
title: title || '',
|
||||||
|
date: moment().format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
content: result,
|
||||||
|
likes: 999,
|
||||||
|
forwards: 999,
|
||||||
|
comments: 233
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
catchError(error => {
|
||||||
|
console.error('Fetch error:', error);
|
||||||
|
return throwError(() => new Error('Failed to fetch posts'));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
<ion-header [translucent]="true">
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title>
|
|
||||||
Tab 1
|
|
||||||
</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<ion-content [fullscreen]="true">
|
|
||||||
<ion-header collapse="condense">
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title size="large">Tab 1</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<app-explore-container name="Tab 1 page"></app-explore-container>
|
|
||||||
</ion-content>
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
|
|
||||||
import { ExploreContainerComponent } from '../explore-container/explore-container.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-tab1',
|
|
||||||
templateUrl: 'tab1.page.html',
|
|
||||||
styleUrls: ['tab1.page.scss'],
|
|
||||||
imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent],
|
|
||||||
})
|
|
||||||
export class Tab1Page {
|
|
||||||
constructor() {}
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
<ion-header [translucent]="true">
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title>
|
|
||||||
Tab 2
|
|
||||||
</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<ion-content [fullscreen]="true">
|
|
||||||
<ion-header collapse="condense">
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title size="large">Tab 2</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<app-explore-container name="Tab 2 page"></app-explore-container>
|
|
||||||
</ion-content>
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
|
|
||||||
import { ExploreContainerComponent } from '../explore-container/explore-container.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-tab2',
|
|
||||||
templateUrl: 'tab2.page.html',
|
|
||||||
styleUrls: ['tab2.page.scss'],
|
|
||||||
imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent]
|
|
||||||
})
|
|
||||||
export class Tab2Page {
|
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
<ion-header [translucent]="true">
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title>
|
|
||||||
Tab 3
|
|
||||||
</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<ion-content [fullscreen]="true">
|
|
||||||
<ion-header collapse="condense">
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-title size="large">Tab 3</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<app-explore-container name="Tab 3 page"></app-explore-container>
|
|
||||||
</ion-content>
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
import { Component } from '@angular/core';
|
|
||||||
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
|
|
||||||
import { ExploreContainerComponent } from '../explore-container/explore-container.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-tab3',
|
|
||||||
templateUrl: 'tab3.page.html',
|
|
||||||
styleUrls: ['tab3.page.scss'],
|
|
||||||
imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent],
|
|
||||||
})
|
|
||||||
export class Tab3Page {
|
|
||||||
constructor() {}
|
|
||||||
}
|
|
||||||
@ -1,18 +1,18 @@
|
|||||||
<ion-tabs>
|
<ion-tabs>
|
||||||
<ion-tab-bar slot="bottom">
|
<ion-tab-bar slot="bottom">
|
||||||
<ion-tab-button tab="tab1" href="/tabs/tab1">
|
<ion-tab-button tab="home">
|
||||||
<ion-icon aria-hidden="true" name="triangle"></ion-icon>
|
<ion-icon name="home-outline"></ion-icon>
|
||||||
<ion-label>Tab 1</ion-label>
|
<ion-label>首页</ion-label>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
|
|
||||||
<ion-tab-button tab="tab2" href="/tabs/tab2">
|
<ion-tab-button tab="feed">
|
||||||
<ion-icon aria-hidden="true" name="ellipse"></ion-icon>
|
<ion-icon name="chatbubbles-outline"></ion-icon>
|
||||||
<ion-label>Tab 2</ion-label>
|
<ion-label>动态</ion-label>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
|
|
||||||
<ion-tab-button tab="tab3" href="/tabs/tab3">
|
<ion-tab-button tab="profile">
|
||||||
<ion-icon aria-hidden="true" name="square"></ion-icon>
|
<ion-icon name="person-outline"></ion-icon>
|
||||||
<ion-label>Tab 3</ion-label>
|
<ion-label>我的</ion-label>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
</ion-tab-bar>
|
</ion-tab-bar>
|
||||||
</ion-tabs>
|
</ion-tabs>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Component, EnvironmentInjector, inject } from '@angular/core';
|
import { Component, EnvironmentInjector, inject } from '@angular/core';
|
||||||
import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';
|
import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';
|
||||||
import { addIcons } from 'ionicons';
|
import { addIcons } from 'ionicons';
|
||||||
import { triangle, ellipse, square } from 'ionicons/icons';
|
import { homeOutline, chatbubblesOutline, personOutline } from 'ionicons/icons';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tabs',
|
selector: 'app-tabs',
|
||||||
@ -13,6 +13,6 @@ export class TabsPage {
|
|||||||
public environmentInjector = inject(EnvironmentInjector);
|
public environmentInjector = inject(EnvironmentInjector);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
addIcons({ triangle, ellipse, square });
|
addIcons({ homeOutline, chatbubblesOutline, personOutline });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
import { Routes } from '@angular/router';
|
|
||||||
import { TabsPage } from './tabs.page';
|
|
||||||
|
|
||||||
export const routes: Routes = [
|
|
||||||
{
|
|
||||||
path: 'tabs',
|
|
||||||
component: TabsPage,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'tab1',
|
|
||||||
loadComponent: () =>
|
|
||||||
import('../tab1/tab1.page').then((m) => m.Tab1Page),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tab2',
|
|
||||||
loadComponent: () =>
|
|
||||||
import('../tab2/tab2.page').then((m) => m.Tab2Page),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tab3',
|
|
||||||
loadComponent: () =>
|
|
||||||
import('../tab3/tab3.page').then((m) => m.Tab3Page),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
redirectTo: '/tabs/tab1',
|
|
||||||
pathMatch: 'full',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
redirectTo: '/tabs/tab1',
|
|
||||||
pathMatch: 'full',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
BIN
src/assets/images/bg.jpg
Normal file
BIN
src/assets/images/bg.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 769 KiB |
BIN
src/assets/images/input.png
Normal file
BIN
src/assets/images/input.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/images/noavar.gif
Normal file
BIN
src/assets/images/noavar.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/images/test/9.png
Normal file
BIN
src/assets/images/test/9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
BIN
src/assets/images/test/986.jpg
Normal file
BIN
src/assets/images/test/986.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 665 KiB |
BIN
src/assets/images/test/ar.png
Normal file
BIN
src/assets/images/test/ar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 686 KiB |
@ -1,3 +1,5 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: true
|
production: true,
|
||||||
|
apiUrl: 'https://api.redbud.fun/fungame/test',
|
||||||
|
authToken: 'Bearer askjrf2139ryf9'
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,9 @@
|
|||||||
// The list of file replacements can be found in `angular.json`.
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false,
|
||||||
|
apiUrl: 'https://api.redbud.fun/fungame/test',
|
||||||
|
authToken: 'Bearer askjrf2139ryf9'
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -4,11 +4,13 @@ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalo
|
|||||||
|
|
||||||
import { routes } from './app/app.routes';
|
import { routes } from './app/app.routes';
|
||||||
import { AppComponent } from './app/app.component';
|
import { AppComponent } from './app/app.component';
|
||||||
|
import { provideHttpClient, withFetch } from '@angular/common/http';
|
||||||
|
|
||||||
bootstrapApplication(AppComponent, {
|
bootstrapApplication(AppComponent, {
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
provideIonicAngular(),
|
provideIonicAngular(),
|
||||||
provideRouter(routes, withPreloading(PreloadAllModules)),
|
provideRouter(routes, withPreloading(PreloadAllModules)),
|
||||||
|
provideHttpClient(withFetch())
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user