|
@@ -0,0 +1,309 @@
|
|
|
+import { Component, OnInit } from '@angular/core';
|
|
|
+import {
|
|
|
+ IonHeader,
|
|
|
+ IonToolbar,
|
|
|
+ IonTitle,
|
|
|
+ IonContent,
|
|
|
+ IonBackButton,
|
|
|
+ IonButtons,
|
|
|
+ IonList,
|
|
|
+ IonItem,
|
|
|
+ IonLabel,
|
|
|
+ IonInput,
|
|
|
+ IonButton,
|
|
|
+ IonAvatar,
|
|
|
+ IonIcon,
|
|
|
+ AlertController,
|
|
|
+ ActionSheetController,
|
|
|
+ IonSelect,
|
|
|
+ IonSelectOption
|
|
|
+} from '@ionic/angular/standalone';
|
|
|
+import { NgIf, NgFor } from '@angular/common';
|
|
|
+import { FormsModule } from '@angular/forms';
|
|
|
+import { addIcons } from 'ionicons';
|
|
|
+import {
|
|
|
+ cameraOutline,
|
|
|
+ imageOutline,
|
|
|
+ chevronBackOutline
|
|
|
+} from 'ionicons/icons';
|
|
|
+import { CloudUser } from 'src/lib/ncloud';
|
|
|
+import Parse from 'parse';
|
|
|
+
|
|
|
+@Component({
|
|
|
+ selector: 'app-profile',
|
|
|
+ templateUrl: './profile.page.html',
|
|
|
+ styleUrls: ['./profile.page.scss'],
|
|
|
+ standalone: true,
|
|
|
+ imports: [
|
|
|
+ IonHeader,
|
|
|
+ IonToolbar,
|
|
|
+ IonTitle,
|
|
|
+ IonContent,
|
|
|
+ IonBackButton,
|
|
|
+ IonButtons,
|
|
|
+ IonList,
|
|
|
+ IonItem,
|
|
|
+ IonLabel,
|
|
|
+ IonInput,
|
|
|
+ IonButton,
|
|
|
+ IonAvatar,
|
|
|
+ IonIcon,
|
|
|
+ NgIf,
|
|
|
+ NgFor,
|
|
|
+ FormsModule,
|
|
|
+ IonSelect,
|
|
|
+ IonSelectOption
|
|
|
+ ]
|
|
|
+})
|
|
|
+export class ProfilePage implements OnInit {
|
|
|
+ userProfile = {
|
|
|
+ avatar: 'assets/anime-avatar.png',
|
|
|
+ username: '',
|
|
|
+ email: '',
|
|
|
+ bio: '',
|
|
|
+ level: 'LV.1 新手学习者',
|
|
|
+ gender: '',
|
|
|
+ age: null
|
|
|
+ };
|
|
|
+
|
|
|
+ passwordData = {
|
|
|
+ oldPassword: '',
|
|
|
+ newPassword: '',
|
|
|
+ confirmPassword: ''
|
|
|
+ };
|
|
|
+
|
|
|
+ genderOptions = [
|
|
|
+ { value: 'male', label: '男' },
|
|
|
+ { value: 'female', label: '女' },
|
|
|
+ { value: 'other', label: '其他' }
|
|
|
+ ];
|
|
|
+
|
|
|
+ ageOptions = [
|
|
|
+ { value: 1, label: '1岁', group: '18岁以下' },
|
|
|
+ { value: 2, label: '2岁', group: '18岁以下' },
|
|
|
+ // ... 生成1-17岁
|
|
|
+ ...Array.from({ length: 17 }, (_, i) => ({
|
|
|
+ value: i + 1,
|
|
|
+ label: `${i + 1}岁`,
|
|
|
+ group: '18岁以下'
|
|
|
+ })),
|
|
|
+ // ... 生成18-30岁
|
|
|
+ ...Array.from({ length: 13 }, (_, i) => ({
|
|
|
+ value: i + 18,
|
|
|
+ label: `${i + 18}岁`,
|
|
|
+ group: '18-30岁'
|
|
|
+ })),
|
|
|
+ // ... 生成31-50岁
|
|
|
+ ...Array.from({ length: 20 }, (_, i) => ({
|
|
|
+ value: i + 31,
|
|
|
+ label: `${i + 31}岁`,
|
|
|
+ group: '31-50岁'
|
|
|
+ })),
|
|
|
+ // ... 生成51-100岁
|
|
|
+ ...Array.from({ length: 50 }, (_, i) => ({
|
|
|
+ value: i + 51,
|
|
|
+ label: `${i + 51}岁`,
|
|
|
+ group: '50岁以上'
|
|
|
+ }))
|
|
|
+ ];
|
|
|
+
|
|
|
+ constructor(
|
|
|
+ private alertController: AlertController,
|
|
|
+ private actionSheetController: ActionSheetController
|
|
|
+ ) {
|
|
|
+ addIcons({ cameraOutline, imageOutline, chevronBackOutline });
|
|
|
+ }
|
|
|
+
|
|
|
+ ngOnInit() {
|
|
|
+ this.loadUserProfile();
|
|
|
+ }
|
|
|
+
|
|
|
+ async loadUserProfile() {
|
|
|
+ try {
|
|
|
+ const currentUser = new CloudUser();
|
|
|
+ if (currentUser && currentUser.get('username')) {
|
|
|
+ this.userProfile = {
|
|
|
+ avatar: currentUser.get('avatar') || 'assets/anime-avatar.png',
|
|
|
+ username: currentUser.get('username'),
|
|
|
+ email: currentUser.get('email'),
|
|
|
+ bio: currentUser.get('bio') || '',
|
|
|
+ level: currentUser.get('level') || 'LV.1 新手学习者',
|
|
|
+ gender: currentUser.get('gender') || '',
|
|
|
+ age: currentUser.get('age') || null
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载用户资料失败:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async changeAvatar() {
|
|
|
+ const actionSheet = await this.actionSheetController.create({
|
|
|
+ header: '选择头像来源',
|
|
|
+ buttons: [
|
|
|
+ {
|
|
|
+ text: '拍照',
|
|
|
+ icon: 'camera-outline',
|
|
|
+ handler: () => {
|
|
|
+ // TODO: 实现拍照功能
|
|
|
+ this.showNotImplemented();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '从相册选择',
|
|
|
+ icon: 'image-outline',
|
|
|
+ handler: () => {
|
|
|
+ // TODO: 实现相册选择功能
|
|
|
+ this.showNotImplemented();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '取消',
|
|
|
+ role: 'cancel'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ });
|
|
|
+ await actionSheet.present();
|
|
|
+ }
|
|
|
+
|
|
|
+ async saveProfile() {
|
|
|
+ try {
|
|
|
+ const currentUser = new CloudUser();
|
|
|
+ if (currentUser) {
|
|
|
+ // 基本验证
|
|
|
+ if (!this.userProfile.username || !this.userProfile.email) {
|
|
|
+ this.showAlert('错误', '用户名和邮箱不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证邮箱格式
|
|
|
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
+ if (!emailRegex.test(this.userProfile.email)) {
|
|
|
+ this.showAlert('错误', '请输入正确的邮箱格式');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 直接尝试更新用户资料
|
|
|
+ currentUser.set({
|
|
|
+ username: this.userProfile.username,
|
|
|
+ email: this.userProfile.email,
|
|
|
+ bio: this.userProfile.bio,
|
|
|
+ gender: this.userProfile.gender,
|
|
|
+ age: this.userProfile.age
|
|
|
+ });
|
|
|
+
|
|
|
+ await currentUser.save();
|
|
|
+
|
|
|
+ const alert = await this.alertController.create({
|
|
|
+ header: '成功',
|
|
|
+ message: '个人资料已更新',
|
|
|
+ buttons: ['确定']
|
|
|
+ });
|
|
|
+ await alert.present();
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('保存用户资料失败:', error);
|
|
|
+ let errorMessage = '保存失败,请稍后重试';
|
|
|
+
|
|
|
+ // 处理特定错误
|
|
|
+ if (error.code === 202) {
|
|
|
+ errorMessage = '该用户名已被使用';
|
|
|
+ } else if (error.code === 203) {
|
|
|
+ errorMessage = '该邮箱已被使用';
|
|
|
+ }
|
|
|
+
|
|
|
+ const alert = await this.alertController.create({
|
|
|
+ header: '错误',
|
|
|
+ message: errorMessage,
|
|
|
+ buttons: ['确定']
|
|
|
+ });
|
|
|
+ await alert.present();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async changePassword() {
|
|
|
+ const alert = await this.alertController.create({
|
|
|
+ header: '修改密码',
|
|
|
+ inputs: [
|
|
|
+ {
|
|
|
+ name: 'oldPassword',
|
|
|
+ type: 'password',
|
|
|
+ placeholder: '当前密码'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'newPassword',
|
|
|
+ type: 'password',
|
|
|
+ placeholder: '新密码'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'confirmPassword',
|
|
|
+ type: 'password',
|
|
|
+ placeholder: '确认新密码'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ buttons: [
|
|
|
+ {
|
|
|
+ text: '取消',
|
|
|
+ role: 'cancel'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: '确认',
|
|
|
+ handler: async (data) => {
|
|
|
+ if (!data.oldPassword || !data.newPassword || !data.confirmPassword) {
|
|
|
+ this.showAlert('错误', '请填写所有密码字段');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.newPassword !== data.confirmPassword) {
|
|
|
+ this.showAlert('错误', '两次输入的新密码不一致');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.newPassword.length < 6) {
|
|
|
+ this.showAlert('错误', '新密码长度至少为6位');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const currentUser = new CloudUser();
|
|
|
+ // 验证旧密码
|
|
|
+ await currentUser.login(currentUser.get('username'), data.oldPassword);
|
|
|
+ // 更新密码
|
|
|
+ currentUser.set({
|
|
|
+ password: data.newPassword
|
|
|
+ });
|
|
|
+ await currentUser.save();
|
|
|
+
|
|
|
+ this.showAlert('成功', '密码修改成功');
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('修改密码失败:', error);
|
|
|
+ this.showAlert('错误', '当前密码错误或修改失败');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ });
|
|
|
+
|
|
|
+ await alert.present();
|
|
|
+ }
|
|
|
+
|
|
|
+ private async showAlert(header: string, message: string) {
|
|
|
+ const alert = await this.alertController.create({
|
|
|
+ header,
|
|
|
+ message,
|
|
|
+ buttons: ['确定']
|
|
|
+ });
|
|
|
+ await alert.present();
|
|
|
+ }
|
|
|
+
|
|
|
+ private async showNotImplemented() {
|
|
|
+ const alert = await this.alertController.create({
|
|
|
+ header: '提示',
|
|
|
+ message: '该功能正在开发中',
|
|
|
+ buttons: ['确定']
|
|
|
+ });
|
|
|
+ await alert.present();
|
|
|
+ }
|
|
|
+}
|