|
@@ -1,9 +1,15 @@
|
|
import { Component, AfterViewInit } from '@angular/core';
|
|
import { Component, AfterViewInit } from '@angular/core';
|
|
import { Router } from '@angular/router';
|
|
import { Router } from '@angular/router';
|
|
-import { ModalController, NavController } from '@ionic/angular';
|
|
|
|
-import { HttpClient } from '@angular/common/http';
|
|
|
|
|
|
+import { ModalController, NavController, ToastController } from '@ionic/angular';
|
|
import { Observable } from 'rxjs';
|
|
import { Observable } from 'rxjs';
|
|
import { map, catchError } from 'rxjs/operators';
|
|
import { map, catchError } from 'rxjs/operators';
|
|
|
|
+import { HttpClient, HttpHeaders } from '@angular/common/http';
|
|
|
|
+import { throwError } from 'rxjs';
|
|
|
|
+
|
|
|
|
+interface User {
|
|
|
|
+ username: string;
|
|
|
|
+ password: string;
|
|
|
|
+}
|
|
|
|
|
|
@Component({
|
|
@Component({
|
|
selector: 'app-tab1',
|
|
selector: 'app-tab1',
|
|
@@ -58,19 +64,35 @@ export class Tab1Page implements AfterViewInit {
|
|
];
|
|
];
|
|
|
|
|
|
currentIndex = 0;
|
|
currentIndex = 0;
|
|
- startX: number = 0; // 初始化 startX
|
|
|
|
- endX: number = 0; // 初始化 endX
|
|
|
|
- isDragging: boolean = false; // 标记是否正在拖动
|
|
|
|
- currentTranslate: number = 0; // 当前的平移值
|
|
|
|
|
|
+ startX: number = 0;
|
|
|
|
+ endX: number = 0;
|
|
|
|
+ isDragging: boolean = false;
|
|
|
|
+ currentTranslate: number = 0;
|
|
cardWidth = 216; // 每个卡片的宽度加上间距 (200 + 16)
|
|
cardWidth = 216; // 每个卡片的宽度加上间距 (200 + 16)
|
|
- isCyclic: boolean = true; // 是否启用循环滑动
|
|
|
|
|
|
+ isCyclic: boolean = true;
|
|
|
|
+ errorMessage: string = ''; // 错误消息
|
|
|
|
+ isLoginModalOpen = false;
|
|
|
|
+ user: User = { username: '', password: '' };
|
|
|
|
|
|
- ngAfterViewInit() {
|
|
|
|
- this.updateCarousel(); // 确保初始状态正确
|
|
|
|
- this.calculateCardWidth(); // 动态计算卡片宽度
|
|
|
|
|
|
+ constructor(
|
|
|
|
+ private router: Router,
|
|
|
|
+ private modalController: ModalController,
|
|
|
|
+ private navCtrl: NavController,
|
|
|
|
+ private http: HttpClient,
|
|
|
|
+ private toastController: ToastController // 添加 ToastController 注入
|
|
|
|
+ ) {}
|
|
|
|
+
|
|
|
|
+ // 实现 AfterViewInit 接口的 ngAfterViewInit 方法
|
|
|
|
+ ngAfterViewInit(): void {
|
|
|
|
+ this.ngAfterViewInitLogic();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 将初始化逻辑移到单独的方法中,以保持代码清晰
|
|
|
|
+ private ngAfterViewInitLogic() {
|
|
|
|
+ this.updateCarousel();
|
|
|
|
+ this.calculateCardWidth();
|
|
}
|
|
}
|
|
|
|
|
|
- // 计算卡片宽度
|
|
|
|
calculateCardWidth() {
|
|
calculateCardWidth() {
|
|
const container = document.getElementById('carousel');
|
|
const container = document.getElementById('carousel');
|
|
if (container && container.children.length > 0) {
|
|
if (container && container.children.length > 0) {
|
|
@@ -79,13 +101,11 @@ export class Tab1Page implements AfterViewInit {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // 更新轮播位置
|
|
|
|
updateCarousel() {
|
|
updateCarousel() {
|
|
this.currentTranslate = -this.currentIndex * this.cardWidth;
|
|
this.currentTranslate = -this.currentIndex * this.cardWidth;
|
|
this.updateCarouselPosition();
|
|
this.updateCarouselPosition();
|
|
}
|
|
}
|
|
|
|
|
|
- // 更新轮播位置
|
|
|
|
updateCarouselPosition() {
|
|
updateCarouselPosition() {
|
|
const container = document.getElementById('carousel');
|
|
const container = document.getElementById('carousel');
|
|
if (container) {
|
|
if (container) {
|
|
@@ -93,20 +113,17 @@ export class Tab1Page implements AfterViewInit {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // 触摸开始
|
|
|
|
onTouchStart(event: TouchEvent) {
|
|
onTouchStart(event: TouchEvent) {
|
|
this.startX = event.touches[0].clientX;
|
|
this.startX = event.touches[0].clientX;
|
|
this.isDragging = true;
|
|
this.isDragging = true;
|
|
}
|
|
}
|
|
|
|
|
|
- // 触摸移动
|
|
|
|
onTouchMove(event: TouchEvent) {
|
|
onTouchMove(event: TouchEvent) {
|
|
if (this.isDragging) {
|
|
if (this.isDragging) {
|
|
const touchX = event.touches[0].clientX;
|
|
const touchX = event.touches[0].clientX;
|
|
const deltaX = touchX - this.startX;
|
|
const deltaX = touchX - this.startX;
|
|
- this.currentTranslate = -this.currentIndex * this.cardWidth + deltaX; // 动态更新平移值
|
|
|
|
|
|
+ this.currentTranslate = -this.currentIndex * this.cardWidth + deltaX;
|
|
|
|
|
|
- // 限制 currentTranslate 的值
|
|
|
|
const maxTranslate = -(this.doctors.length - 1) * this.cardWidth;
|
|
const maxTranslate = -(this.doctors.length - 1) * this.cardWidth;
|
|
this.currentTranslate = Math.max(Math.min(this.currentTranslate, 0), maxTranslate);
|
|
this.currentTranslate = Math.max(Math.min(this.currentTranslate, 0), maxTranslate);
|
|
|
|
|
|
@@ -114,101 +131,64 @@ export class Tab1Page implements AfterViewInit {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // 触摸结束
|
|
|
|
onTouchEnd(event: TouchEvent) {
|
|
onTouchEnd(event: TouchEvent) {
|
|
this.endX = event.changedTouches[0].clientX;
|
|
this.endX = event.changedTouches[0].clientX;
|
|
this.isDragging = false;
|
|
this.isDragging = false;
|
|
|
|
|
|
- const swipeThreshold = 50; // 滑动阈值
|
|
|
|
|
|
+ const swipeThreshold = 50;
|
|
const deltaX = this.startX - this.endX;
|
|
const deltaX = this.startX - this.endX;
|
|
|
|
|
|
if (deltaX > swipeThreshold) {
|
|
if (deltaX > swipeThreshold) {
|
|
- // 向左滑动
|
|
|
|
this.nextSlide();
|
|
this.nextSlide();
|
|
} else if (deltaX < -swipeThreshold) {
|
|
} else if (deltaX < -swipeThreshold) {
|
|
- // 向右滑动
|
|
|
|
this.prevSlide();
|
|
this.prevSlide();
|
|
} else {
|
|
} else {
|
|
- // 如果滑动距离不够,则恢复到原来的位置
|
|
|
|
this.snapToNearestCard();
|
|
this.snapToNearestCard();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // 上一张
|
|
|
|
prevSlide() {
|
|
prevSlide() {
|
|
if (this.isCyclic) {
|
|
if (this.isCyclic) {
|
|
- if (this.currentIndex === 0) {
|
|
|
|
- this.currentIndex = this.doctors.length - 1;
|
|
|
|
- } else {
|
|
|
|
- this.currentIndex--;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- if (this.currentIndex > 0) {
|
|
|
|
- this.currentIndex--;
|
|
|
|
- }
|
|
|
|
|
|
+ this.currentIndex = (this.currentIndex - 1 + this.doctors.length) % this.doctors.length;
|
|
|
|
+ } else if (this.currentIndex > 0) {
|
|
|
|
+ this.currentIndex--;
|
|
}
|
|
}
|
|
this.updateCarousel();
|
|
this.updateCarousel();
|
|
}
|
|
}
|
|
|
|
|
|
- // 下一张
|
|
|
|
nextSlide() {
|
|
nextSlide() {
|
|
if (this.isCyclic) {
|
|
if (this.isCyclic) {
|
|
- if (this.currentIndex === this.doctors.length - 1) {
|
|
|
|
- this.currentIndex = 0;
|
|
|
|
- } else {
|
|
|
|
- this.currentIndex++;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- if (this.currentIndex < this.doctors.length - 1) {
|
|
|
|
- this.currentIndex++;
|
|
|
|
- }
|
|
|
|
|
|
+ this.currentIndex = (this.currentIndex + 1) % this.doctors.length;
|
|
|
|
+ } else if (this.currentIndex < this.doctors.length - 1) {
|
|
|
|
+ this.currentIndex++;
|
|
}
|
|
}
|
|
this.updateCarousel();
|
|
this.updateCarousel();
|
|
}
|
|
}
|
|
|
|
|
|
- // 快照到最近的卡片
|
|
|
|
snapToNearestCard() {
|
|
snapToNearestCard() {
|
|
const cardIndex = Math.round(-this.currentTranslate / this.cardWidth);
|
|
const cardIndex = Math.round(-this.currentTranslate / this.cardWidth);
|
|
this.currentIndex = Math.max(0, Math.min(cardIndex, this.doctors.length - 1));
|
|
this.currentIndex = Math.max(0, Math.min(cardIndex, this.doctors.length - 1));
|
|
this.updateCarousel();
|
|
this.updateCarousel();
|
|
}
|
|
}
|
|
- // 在线咨询按钮点击事件
|
|
|
|
|
|
+
|
|
onConsultNow() {
|
|
onConsultNow() {
|
|
console.log(`立即咨询`);
|
|
console.log(`立即咨询`);
|
|
this.router.navigate(['/consultation']);
|
|
this.router.navigate(['/consultation']);
|
|
}
|
|
}
|
|
|
|
|
|
- // 在线咨询按钮点击事件
|
|
|
|
onlineConsultNow(doctor: any) {
|
|
onlineConsultNow(doctor: any) {
|
|
console.log(`在线咨询: ${doctor.name}`);
|
|
console.log(`在线咨询: ${doctor.name}`);
|
|
- // 跳转到 ConsultationPage 并传递医生信息
|
|
|
|
this.router.navigate(['/consultation'], { state: { doctor: doctor } });
|
|
this.router.navigate(['/consultation'], { state: { doctor: doctor } });
|
|
}
|
|
}
|
|
|
|
|
|
- // 导航到指定路由
|
|
|
|
navigateTo(route: string) {
|
|
navigateTo(route: string) {
|
|
this.router.navigate([route]);
|
|
this.router.navigate([route]);
|
|
}
|
|
}
|
|
|
|
|
|
- // 发布求医信息
|
|
|
|
publishHealthInfo() {
|
|
publishHealthInfo() {
|
|
- // 这里可以添加发布求医信息的逻辑
|
|
|
|
console.log('发布求医信息');
|
|
console.log('发布求医信息');
|
|
}
|
|
}
|
|
|
|
|
|
- isLoginModalOpen = false; // 声明 isLoginModalOpen 属性
|
|
|
|
- user = {
|
|
|
|
- username: '',
|
|
|
|
- password: ''
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- constructor(
|
|
|
|
- private router: Router,
|
|
|
|
- private modalController: ModalController,
|
|
|
|
- private navCtrl: NavController,
|
|
|
|
- private http: HttpClient // 注入 HttpClient
|
|
|
|
- ) {}
|
|
|
|
-
|
|
|
|
openLoginModal() {
|
|
openLoginModal() {
|
|
this.isLoginModalOpen = true;
|
|
this.isLoginModalOpen = true;
|
|
console.log('打开登录/注册模态框');
|
|
console.log('打开登录/注册模态框');
|
|
@@ -224,60 +204,91 @@ export class Tab1Page implements AfterViewInit {
|
|
console.log('登录/注册模态框已关闭');
|
|
console.log('登录/注册模态框已关闭');
|
|
}
|
|
}
|
|
|
|
|
|
- onLoginFormSubmit(formValue: any) {
|
|
|
|
- // 处理登录逻辑
|
|
|
|
|
|
+ async onLoginFormSubmit(formValue: any) {
|
|
console.log('登录表单提交:', formValue);
|
|
console.log('登录表单提交:', formValue);
|
|
|
|
|
|
- // 发送登录请求
|
|
|
|
|
|
+ // 验证用户名和密码长度
|
|
|
|
+ if (formValue.username.length < 3) {
|
|
|
|
+ await this.presentToast('用户名至少需要3位字符', 'danger');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (formValue.password.length < 6) {
|
|
|
|
+ await this.presentToast('密码至少需要6位字符', 'danger');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
this.loginUser(formValue.username, formValue.password)
|
|
this.loginUser(formValue.username, formValue.password)
|
|
.subscribe(
|
|
.subscribe(
|
|
- (response) => {
|
|
|
|
|
|
+ async (response) => {
|
|
console.log('登录成功:', response);
|
|
console.log('登录成功:', response);
|
|
- // 这里可以处理登录成功的逻辑,例如跳转到主页
|
|
|
|
|
|
+ await this.presentToast('登录成功', 'success');
|
|
this.closeLoginModal();
|
|
this.closeLoginModal();
|
|
},
|
|
},
|
|
- (error) => {
|
|
|
|
|
|
+ async (error) => {
|
|
console.error('登录失败:', error);
|
|
console.error('登录失败:', error);
|
|
- // 这里可以处理登录失败的逻辑,例如显示错误消息
|
|
|
|
- this.closeLoginModal();
|
|
|
|
|
|
+ await this.presentToast('登录失败,请检查用户名和密码', 'danger');
|
|
}
|
|
}
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
registerUser() {
|
|
registerUser() {
|
|
- // 处理注册逻辑
|
|
|
|
- console.log('注册用户:', this.user);
|
|
|
|
|
|
+ if (!this.user.username || !this.user.password) {
|
|
|
|
+ console.error('用户名或密码为空');
|
|
|
|
+ this.presentToast('用户名和密码不能为空,请输入完整信息', 'danger');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 验证用户名和密码长度
|
|
|
|
+ if (this.user.username.length < 3) {
|
|
|
|
+ this.presentToast('用户名至少需要3位字符', 'danger');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- // 发送注册请求
|
|
|
|
- this.registerNewUser(this.user.username, this.user.password)
|
|
|
|
|
|
+ if (this.user.password.length < 6) {
|
|
|
|
+ this.presentToast('密码至少需要6位字符', 'danger');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ console.log('注册用户:', JSON.stringify(this.user, null, 2));
|
|
|
|
+
|
|
|
|
+ this.registerNewUser(this.user)
|
|
.subscribe(
|
|
.subscribe(
|
|
- (response) => {
|
|
|
|
|
|
+ async (response) => {
|
|
console.log('注册成功:', response);
|
|
console.log('注册成功:', response);
|
|
- // 这里可以处理注册成功的逻辑,例如跳转到登录页面
|
|
|
|
|
|
+ await this.presentToast('注册成功', 'success');
|
|
this.closeLoginModal();
|
|
this.closeLoginModal();
|
|
},
|
|
},
|
|
- (error) => {
|
|
|
|
|
|
+ async (error) => {
|
|
console.error('注册失败:', error);
|
|
console.error('注册失败:', error);
|
|
- // 这里可以处理注册失败的逻辑,例如显示错误消息
|
|
|
|
- this.closeLoginModal();
|
|
|
|
|
|
+ if (error.error && error.error.message.includes('cannot be null')) {
|
|
|
|
+ await this.presentToast('密码不能为空,请输入密码', 'danger');
|
|
|
|
+ } else {
|
|
|
|
+ await this.presentToast('注册失败,请稍后再试', 'danger');
|
|
|
|
+ }
|
|
}
|
|
}
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
private loginUser(username: string, password: string): Observable<any> {
|
|
private loginUser(username: string, password: string): Observable<any> {
|
|
- const loginUrl = 'YOUR_API_ENDPOINT/login'; // 替换为你的登录 API 端点
|
|
|
|
- return this.http.post(loginUrl, { username, password })
|
|
|
|
- .pipe(
|
|
|
|
- map(response => response),
|
|
|
|
- catchError(error => {
|
|
|
|
- throw error;
|
|
|
|
- })
|
|
|
|
- );
|
|
|
|
|
|
+ const loginUrl = 'http://localhost:8080/api/login'; // 替换为你的登录 API 端点
|
|
|
|
+ return this.http.post(loginUrl, { username, password }, {
|
|
|
|
+ withCredentials: true,
|
|
|
|
+ headers: new HttpHeaders({
|
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
|
+ })
|
|
|
|
+ }).pipe(
|
|
|
|
+ map(response => response),
|
|
|
|
+ catchError(error => {
|
|
|
|
+ console.error('登录请求出错:', error);
|
|
|
|
+ return throwError(() => new Error('登录失败'));
|
|
|
|
+ })
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
|
|
- private registerNewUser(username: string, password: string): Observable<any> {
|
|
|
|
- const registerUrl = 'YOUR_API_ENDPOINT/register'; // 替换为你的注册 API 端点
|
|
|
|
- return this.http.post(registerUrl, { username, password })
|
|
|
|
|
|
+ private registerNewUser(user: User): Observable<any> {
|
|
|
|
+ const registerUrl = 'http://localhost:8080/api/register'; // 替换为你的注册 API 端点
|
|
|
|
+ return this.http.post(registerUrl, user)
|
|
.pipe(
|
|
.pipe(
|
|
map(response => response),
|
|
map(response => response),
|
|
catchError(error => {
|
|
catchError(error => {
|
|
@@ -286,9 +297,20 @@ export class Tab1Page implements AfterViewInit {
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
- // 新增方法:处理“点击了解更多”按钮点击事件
|
|
|
|
onLearnMore() {
|
|
onLearnMore() {
|
|
- // 跳转到详情页面
|
|
|
|
this.navCtrl.navigateForward('/details');
|
|
this.navCtrl.navigateForward('/details');
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
+
|
|
|
|
+ async presentToast(message: string, color: string) {
|
|
|
|
+ const toast = await this.toastController.create({
|
|
|
|
+ message: message,
|
|
|
|
+ duration: 2000,
|
|
|
|
+ color: color,
|
|
|
|
+ position: 'top',
|
|
|
|
+ });
|
|
|
|
+ toast.present();
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|