tab1.page.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. import { Component, AfterViewInit } from '@angular/core';
  2. import { Router } from '@angular/router';
  3. import { ModalController, NavController, ToastController } from '@ionic/angular';
  4. import { Observable } from 'rxjs';
  5. import { map, catchError } from 'rxjs/operators';
  6. import { HttpClient, HttpHeaders } from '@angular/common/http';
  7. import { throwError } from 'rxjs';
  8. import { Subscription } from 'rxjs';
  9. import { UserService } from '../services/user.service';
  10. import {ElementRef, OnInit, Renderer2 } from '@angular/core';
  11. interface User {
  12. username: string;
  13. password: string;
  14. }
  15. @Component({
  16. selector: 'app-tab1',
  17. templateUrl: 'tab1.page.html',
  18. styleUrls: ['tab1.page.scss']
  19. })
  20. export class Tab1Page implements AfterViewInit {
  21. doctors = [
  22. {
  23. avatar: '../../assets/images/doctor1.jpg',
  24. name: '张医生',
  25. specialty: '心血管科'
  26. },
  27. {
  28. avatar: '../../assets/images/doctor2.jpg',
  29. name: '李医生',
  30. specialty: '神经科'
  31. },
  32. {
  33. avatar: '../../assets/images/doctor3.jpg',
  34. name: '王医生',
  35. specialty: '儿科'
  36. },
  37. {
  38. avatar: '../../assets/images/doctor4.jpg',
  39. name: '赵医生',
  40. specialty: '外科'
  41. },
  42. {
  43. avatar: '../../assets/images/doctor5.jpg',
  44. name: '陈医生',
  45. specialty: '内科'
  46. }
  47. ];
  48. images = [
  49. '../../assets/images/brackground.jpg',
  50. '../../assets/images/brackground2.jpg',
  51. '../../assets/images/brackground3.jpeg'
  52. ];
  53. // 功能按钮数据
  54. functionItems1 = [
  55. { label: '我的病历', icon: 'document-text', route: '/case' },
  56. { label: '在线问诊', icon: 'chatbubbles', route: '/consultation' },
  57. { label: '健康档案', icon: 'person', route: '/health-record' },
  58. { label: '预约挂号', icon: 'calendar', route: '/appointment' },
  59. ];
  60. functionItems2 = [
  61. { label: '健康资讯', icon: 'newspaper', route: '/health-news' },
  62. { label: '药品购买', icon: 'medkit', route: '/medicine-purchase' },
  63. { label: '专家讲座', icon: 'podium', route: '/expert-lectures' },
  64. { label: '健康社区', icon: 'people', route: '/health-community' }
  65. ];
  66. userAvatar: string = '../../assets/images/user.png'; // 默认头像
  67. private userInfoSubscription!: Subscription;
  68. currentIndex = 0;
  69. startX: number = 0;
  70. endX: number = 0;
  71. isDragging: boolean = false;
  72. currentTranslate: number = 0;
  73. cardWidth = 216; // 每个卡片的宽度加上间距 (200 + 16)
  74. isCyclic: boolean = true;
  75. errorMessage: string = ''; // 错误消息
  76. isLoginModalOpen = false;
  77. user: User = { username: '', password: '' };
  78. fileToUpload: File | null = null;
  79. constructor(
  80. private router: Router,
  81. private modalController: ModalController,
  82. private navCtrl: NavController,
  83. private http: HttpClient,
  84. private toastController: ToastController,// 添加 ToastController 注入
  85. private userService: UserService ,
  86. private el: ElementRef,
  87. private renderer: Renderer2
  88. ) {}
  89. ngOnInit() {
  90. this.subscribeToUserInfo();
  91. this.startImageRotation();
  92. // 初始化时设置第一张图片
  93. this.updateBackgroundImage();
  94. }
  95. ionViewWillEnter() {
  96. this.subscribeToUserInfo();
  97. }
  98. ngOnDestroy() {
  99. if (this.userInfoSubscription) {
  100. this.userInfoSubscription.unsubscribe();
  101. }
  102. }
  103. // 实现 AfterViewInit 接口的 ngAfterViewInit 方法
  104. ngAfterViewInit(): void {
  105. this.ngAfterViewInitLogic();
  106. }
  107. private subscribeToUserInfo() {
  108. // 取消之前的订阅(如果有)
  109. if (this.userInfoSubscription) {
  110. this.userInfoSubscription.unsubscribe();
  111. }
  112. // 订阅最新的用户信息
  113. this.userInfoSubscription = this.userService.getUserInfo().subscribe(userInfo => {
  114. if (userInfo) {
  115. this.userAvatar = userInfo.userAvatar || this.userAvatar;
  116. console.log('Updated user info in Tab1:', userInfo); // 添加日志输出
  117. }
  118. });
  119. }
  120. startImageRotation(): void {
  121. setInterval(() => {
  122. this.currentIndex = (this.currentIndex + 1) % this.images.length;
  123. this.updateBackgroundImage();
  124. }, 5000); // Change image every 5 seconds
  125. }
  126. updateBackgroundImage(): void {
  127. const imageUrl = `url('${this.images[this.currentIndex]}')`;
  128. this.renderer.setStyle(this.el.nativeElement.querySelector('.health-banner'), 'background-image', imageUrl);
  129. }
  130. // 将初始化逻辑移到单独的方法中,以保持代码清晰
  131. private ngAfterViewInitLogic() {
  132. this.updateCarousel();
  133. this.calculateCardWidth();
  134. }
  135. calculateCardWidth() {
  136. const container = document.getElementById('carousel');
  137. if (container && container.children.length > 0) {
  138. const firstCard = container.children[0] as HTMLElement;
  139. this.cardWidth = firstCard.offsetWidth + 16; // 加上间距
  140. }
  141. }
  142. updateCarousel() {
  143. this.currentTranslate = -this.currentIndex * this.cardWidth;
  144. this.updateCarouselPosition();
  145. }
  146. updateCarouselPosition() {
  147. const container = document.getElementById('carousel');
  148. if (container) {
  149. container.style.transform = `translateX(${this.currentTranslate}px)`;
  150. }
  151. }
  152. onTouchStart(event: TouchEvent) {
  153. this.startX = event.touches[0].clientX;
  154. this.isDragging = true;
  155. }
  156. onTouchMove(event: TouchEvent) {
  157. if (this.isDragging) {
  158. const touchX = event.touches[0].clientX;
  159. const deltaX = touchX - this.startX;
  160. this.currentTranslate = -this.currentIndex * this.cardWidth + deltaX;
  161. const maxTranslate = -(this.doctors.length - 1) * this.cardWidth;
  162. this.currentTranslate = Math.max(Math.min(this.currentTranslate, 0), maxTranslate);
  163. this.updateCarouselPosition();
  164. }
  165. }
  166. onTouchEnd(event: TouchEvent) {
  167. this.endX = event.changedTouches[0].clientX;
  168. this.isDragging = false;
  169. const swipeThreshold = 50;
  170. const deltaX = this.startX - this.endX;
  171. if (deltaX > swipeThreshold) {
  172. this.nextSlide();
  173. } else if (deltaX < -swipeThreshold) {
  174. this.prevSlide();
  175. } else {
  176. this.snapToNearestCard();
  177. }
  178. }
  179. prevSlide() {
  180. if (this.isCyclic) {
  181. this.currentIndex = (this.currentIndex - 1 + this.doctors.length) % this.doctors.length;
  182. } else if (this.currentIndex > 0) {
  183. this.currentIndex--;
  184. }
  185. this.updateCarousel();
  186. }
  187. nextSlide() {
  188. if (this.isCyclic) {
  189. this.currentIndex = (this.currentIndex + 1) % this.doctors.length;
  190. } else if (this.currentIndex < this.doctors.length - 1) {
  191. this.currentIndex++;
  192. }
  193. this.updateCarousel();
  194. }
  195. snapToNearestCard() {
  196. const cardIndex = Math.round(-this.currentTranslate / this.cardWidth);
  197. this.currentIndex = Math.max(0, Math.min(cardIndex, this.doctors.length - 1));
  198. this.updateCarousel();
  199. }
  200. onConsultNow() {
  201. console.log(`立即咨询`);
  202. this.router.navigate(['/consultation']);
  203. }
  204. onlineConsultNow(doctor: any) {
  205. console.log(`在线咨询: ${doctor.name}`);
  206. this.router.navigate(['/consultation'], { state: { doctor: doctor } });
  207. }
  208. navigateTo(route: string) {
  209. this.router.navigate([route]);
  210. }
  211. // // 发布求医信息
  212. // handleClick() {
  213. // const fileInput = document.getElementById('fileInput');
  214. // if (fileInput) {
  215. // fileInput.click();
  216. // } else {
  217. // console.error('File input element not found');
  218. // }
  219. // }
  220. // publishHealthInfo(files: FileList) {
  221. // if (files && files.length > 0) {
  222. // const file = files[0];
  223. // const allowedTypes = ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  224. // 'image/jpeg', 'image/png', 'image/gif'];
  225. // if (allowedTypes.includes(file.type)) {
  226. // console.log('Selected file:', file.name);
  227. // // 在这里可以添加上传文件的逻辑
  228. // this.fileToUpload = file;
  229. // // 在这里添加上传文件的逻辑
  230. // this.uploadFile().then(() => this.navCtrl.navigateForward('/tabs/tab2'));
  231. // } else {
  232. // this.presentToast('仅支持 .doc, .docx, .jpg, .jpeg, .png, .gif 文件类型');
  233. // }
  234. // } else {
  235. // console.log('No file selected');
  236. // }
  237. // }
  238. // private async uploadFile(): Promise<void> {
  239. // if (this.fileToUpload) {
  240. // // 这里是模拟文件上传的过程,您可以替换为实际的上传逻辑。
  241. // // 比如调用API进行文件上传,并处理响应。
  242. // // 简单示例:
  243. // // await this.http.post('your-upload-endpoint', this.fileToUpload).toPromise();
  244. // return new Promise((resolve) => setTimeout(resolve, 1000)); // 模拟异步操作
  245. // }
  246. // }
  247. openLoginModal() {
  248. this.isLoginModalOpen = true;
  249. console.log('打开登录/注册模态框');
  250. }
  251. closeLoginModal() {
  252. this.isLoginModalOpen = false;
  253. console.log('关闭登录/注册模态框');
  254. }
  255. onLoginModalDismissed(event: any) {
  256. this.isLoginModalOpen = false;
  257. console.log('登录/注册模态框已关闭');
  258. }
  259. async onLoginFormSubmit(formValue: any) {
  260. console.log('登录表单提交:', formValue);
  261. // 验证用户名和密码长度
  262. if (formValue.username.length < 3) {
  263. await this.presentToast('用户名至少需要3位字符', 'danger');
  264. return;
  265. }
  266. if (formValue.password.length < 6) {
  267. await this.presentToast('密码至少需要6位字符', 'danger');
  268. return;
  269. }
  270. this.loginUser(formValue.username, formValue.password)
  271. .subscribe(
  272. async (response) => {
  273. console.log('登录成功:', response);
  274. await this.presentToast('登录成功', 'success');
  275. this.closeLoginModal();
  276. },
  277. async (error) => {
  278. console.error('登录失败:', error);
  279. await this.presentToast('登录失败,请检查用户名和密码', 'danger');
  280. }
  281. );
  282. }
  283. registerUser() {
  284. if (!this.user.username || !this.user.password) {
  285. console.error('用户名或密码为空');
  286. this.presentToast('用户名和密码不能为空,请输入完整信息', 'danger');
  287. return;
  288. }
  289. // 验证用户名和密码长度
  290. if (this.user.username.length < 3) {
  291. this.presentToast('用户名至少需要3位字符', 'danger');
  292. return;
  293. }
  294. if (this.user.password.length < 6) {
  295. this.presentToast('密码至少需要6位字符', 'danger');
  296. return;
  297. }
  298. console.log('注册用户:', JSON.stringify(this.user, null, 2));
  299. this.registerNewUser(this.user)
  300. .subscribe(
  301. async (response) => {
  302. console.log('注册成功:', response);
  303. await this.presentToast('注册成功', 'success');
  304. this.closeLoginModal();
  305. },
  306. async (error) => {
  307. console.error('注册失败:', error);
  308. if (error.error && error.error.message.includes('cannot be null')) {
  309. await this.presentToast('密码不能为空,请输入密码', 'danger');
  310. } else {
  311. await this.presentToast('注册失败,请稍后再试', 'danger');
  312. }
  313. }
  314. );
  315. }
  316. private loginUser(username: string, password: string): Observable<any> {
  317. const loginUrl = 'http://localhost:8080/api/login'; // 替换为你的登录 API 端点
  318. return this.http.post(loginUrl, { username, password }, {
  319. withCredentials: true,
  320. headers: new HttpHeaders({
  321. 'Content-Type': 'application/json'
  322. })
  323. }).pipe(
  324. map(response => response),
  325. catchError(error => {
  326. console.error('登录请求出错:', error);
  327. return throwError(() => new Error('登录失败'));
  328. })
  329. );
  330. }
  331. private registerNewUser(user: User): Observable<any> {
  332. const registerUrl = 'http://localhost:8080/api/register'; // 替换为你的注册 API 端点
  333. return this.http.post(registerUrl, user)
  334. .pipe(
  335. map(response => response),
  336. catchError(error => {
  337. throw error;
  338. })
  339. );
  340. }
  341. onLearnMore() {
  342. this.navCtrl.navigateForward('/details');
  343. }
  344. async presentToast(message: string, color: string = 'primary') {
  345. const toast = await this.toastController.create({
  346. message: message,
  347. duration: 2000,
  348. color: color,
  349. position: 'top',
  350. });
  351. toast.present();
  352. }
  353. doRefresh(event: any) {
  354. console.log('Begin async operation');
  355. setTimeout(() => {
  356. console.log('Async operations have ended');
  357. event.target.complete();
  358. }, 1000);
  359. }
  360. }