GZP 2 tháng trước cách đây
mục cha
commit
0dff0bf81e
45 tập tin đã thay đổi với 961 bổ sung64 xóa
  1. 109 5
      package-lock.json
  2. 2 0
      package.json
  3. 4 0
      src/app/app-routing.module.ts
  4. 15 16
      src/app/tab1/tab1.page.html
  5. 1 1
      src/app/tabs/tabs-routing.module.ts
  6. 3 0
      src/global.scss
  7. 2 1
      src/index.html
  8. 0 3
      src/luck-16th/login-page/login-page.component.html
  9. 0 24
      src/luck-16th/login-page/login-page.component.spec.ts
  10. 0 14
      src/luck-16th/login-page/login-page.component.ts
  11. 17 0
      src/modules/function/boos/boos-routing.module.ts
  12. 20 0
      src/modules/function/boos/boos.module.ts
  13. 13 0
      src/modules/function/boos/boos.page.html
  14. 0 0
      src/modules/function/boos/boos.page.scss
  15. 17 0
      src/modules/function/boos/boos.page.spec.ts
  16. 15 0
      src/modules/function/boos/boos.page.ts
  17. 17 0
      src/modules/function/employer/employer-routing.module.ts
  18. 20 0
      src/modules/function/employer/employer.module.ts
  19. 13 0
      src/modules/function/employer/employer.page.html
  20. 0 0
      src/modules/function/employer/employer.page.scss
  21. 17 0
      src/modules/function/employer/employer.page.spec.ts
  22. 15 0
      src/modules/function/employer/employer.page.ts
  23. 10 0
      src/modules/function/function-routing.module.ts
  24. 14 0
      src/modules/function/function.module.ts
  25. 17 0
      src/modules/user/edit-info/edit-info-routing.module.ts
  26. 20 0
      src/modules/user/edit-info/edit-info.module.ts
  27. 47 0
      src/modules/user/edit-info/edit-info.page.html
  28. 0 0
      src/modules/user/edit-info/edit-info.page.scss
  29. 17 0
      src/modules/user/edit-info/edit-info.page.spec.ts
  30. 56 0
      src/modules/user/edit-info/edit-info.page.ts
  31. 17 0
      src/modules/user/login/login-routing.module.ts
  32. 20 0
      src/modules/user/login/login.module.ts
  33. 47 0
      src/modules/user/login/login.page.html
  34. 0 0
      src/modules/user/login/login.page.scss
  35. 17 0
      src/modules/user/login/login.page.spec.ts
  36. 93 0
      src/modules/user/login/login.page.ts
  37. 17 0
      src/modules/user/mine/mine-routing.module.ts
  38. 20 0
      src/modules/user/mine/mine.module.ts
  39. 84 0
      src/modules/user/mine/mine.page.html
  40. 3 0
      src/modules/user/mine/mine.page.scss
  41. 17 0
      src/modules/user/mine/mine.page.spec.ts
  42. 27 0
      src/modules/user/mine/mine.page.ts
  43. 14 0
      src/modules/user/user-routing.module.ts
  44. 14 0
      src/modules/user/user.module.ts
  45. 90 0
      src/test.html

+ 109 - 5
package-lock.json

@@ -22,7 +22,9 @@
         "@capacitor/keyboard": "6.0.0",
         "@capacitor/status-bar": "6.0.0",
         "@ionic/angular": "^8.0.0",
+        "@types/parse": "^3.0.9",
         "ionicons": "^7.0.0",
+        "parse": "^5.1.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.14.2"
@@ -2407,6 +2409,18 @@
         "node": ">=6.9.0"
       }
     },
+    "node_modules/@babel/runtime-corejs3": {
+      "version": "7.23.2",
+      "resolved": "https://registry.npmmirror.com/@babel/runtime-corejs3/-/runtime-corejs3-7.23.2.tgz",
+      "integrity": "sha512-54cIh74Z1rp4oIjsHjqN+WM4fMyCBYe+LpZ9jWm51CZ1fbH3SkAzQD/3XLoNkjbJ7YEmjobLXyvQrFypRHOrXw==",
+      "dependencies": {
+        "core-js-pure": "^3.30.2",
+        "regenerator-runtime": "^0.14.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
     "node_modules/@babel/template": {
       "version": "7.24.6",
       "resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.24.6.tgz",
@@ -4866,7 +4880,6 @@
       "version": "20.12.12",
       "resolved": "https://registry.npmmirror.com/@types/node/-/node-20.12.12.tgz",
       "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==",
-      "dev": true,
       "dependencies": {
         "undici-types": "~5.26.4"
       }
@@ -4880,6 +4893,14 @@
         "@types/node": "*"
       }
     },
+    "node_modules/@types/parse": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmmirror.com/@types/parse/-/parse-3.0.9.tgz",
+      "integrity": "sha512-DGTHygc7krgmNAK8h42giwmAofCd9uv2++RD+zw6OmWI7AEnlTYZwEuWsx22SA2CSMQrZW8P2INHLpQbnQFUng==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/qs": {
       "version": "6.9.15",
       "resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.15.tgz",
@@ -7053,6 +7074,16 @@
         "url": "https://opencollective.com/core-js"
       }
     },
+    "node_modules/core-js-pure": {
+      "version": "3.37.1",
+      "resolved": "https://registry.npmmirror.com/core-js-pure/-/core-js-pure-3.37.1.tgz",
+      "integrity": "sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==",
+      "hasInstallScript": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
     "node_modules/core-util-is": {
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -7215,6 +7246,12 @@
         "node": ">= 8"
       }
     },
+    "node_modules/crypto-js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
+      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+      "optional": true
+    },
     "node_modules/css-loader": {
       "version": "6.10.0",
       "resolved": "https://registry.npmmirror.com/css-loader/-/css-loader-6.10.0.tgz",
@@ -9806,6 +9843,11 @@
         "postcss": "^8.1.0"
       }
     },
+    "node_modules/idb-keyval": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmmirror.com/idb-keyval/-/idb-keyval-6.2.1.tgz",
+      "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
+    },
     "node_modules/ieee754": {
       "version": "1.2.1",
       "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz",
@@ -12978,6 +13020,25 @@
         "node": ">=6"
       }
     },
+    "node_modules/parse": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmmirror.com/parse/-/parse-5.1.0.tgz",
+      "integrity": "sha512-46gVRe1JHsh21Ht0/Ko6PeMDl6wELLMYxnZPFD6iZm2EWsWnzi2txNGE6PvnIv+G7yOufZIOD0BCZLYOFl3toA==",
+      "dependencies": {
+        "@babel/runtime-corejs3": "7.23.2",
+        "idb-keyval": "6.2.1",
+        "react-native-crypto-js": "1.0.0",
+        "uuid": "9.0.1",
+        "ws": "8.16.0",
+        "xmlhttprequest": "1.8.0"
+      },
+      "engines": {
+        "node": ">=18 <21"
+      },
+      "optionalDependencies": {
+        "crypto-js": "4.2.0"
+      }
+    },
     "node_modules/parse-json": {
       "version": "5.2.0",
       "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
@@ -13017,6 +13078,38 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/parse/node_modules/uuid": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz",
+      "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+      "funding": [
+        "https://github.com/sponsors/broofa",
+        "https://github.com/sponsors/ctavan"
+      ],
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/parse/node_modules/ws": {
+      "version": "8.16.0",
+      "resolved": "https://registry.npmmirror.com/ws/-/ws-8.16.0.tgz",
+      "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/parse5": {
       "version": "7.1.2",
       "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.1.2.tgz",
@@ -13661,6 +13754,11 @@
       "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
       "dev": true
     },
+    "node_modules/react-native-crypto-js": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/react-native-crypto-js/-/react-native-crypto-js-1.0.0.tgz",
+      "integrity": "sha512-FNbLuG/HAdapQoybeZSoes1PWdOj0w242gb+e1R0hicf3Gyj/Mf8M9NaED2AnXVOX01b2FXomwUiw1xP1K+8sA=="
+    },
     "node_modules/read-package-json": {
       "version": "7.0.1",
       "resolved": "https://registry.npmmirror.com/read-package-json/-/read-package-json-7.0.1.tgz",
@@ -13791,8 +13889,7 @@
     "node_modules/regenerator-runtime": {
       "version": "0.14.1",
       "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
-      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
-      "dev": true
+      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
     },
     "node_modules/regenerator-transform": {
       "version": "0.15.2",
@@ -15666,8 +15763,7 @@
     "node_modules/undici-types": {
       "version": "5.26.5",
       "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz",
-      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
-      "dev": true
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
     },
     "node_modules/unicode-canonical-property-names-ecmascript": {
       "version": "2.0.0",
@@ -16905,6 +17001,14 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/xmlhttprequest": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmmirror.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
+      "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/y18n": {
       "version": "5.0.8",
       "resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",

+ 2 - 0
package.json

@@ -27,7 +27,9 @@
     "@capacitor/keyboard": "6.0.0",
     "@capacitor/status-bar": "6.0.0",
     "@ionic/angular": "^8.0.0",
+    "@types/parse": "^3.0.9",
     "ionicons": "^7.0.0",
+    "parse": "^5.1.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.14.2"

+ 4 - 0
src/app/app-routing.module.ts

@@ -9,6 +9,10 @@ const routes: Routes = [
   {
     path: 'tab-mine',
     loadChildren: () => import('./tab-mine/tab-mine.module').then( m => m.TabMinePageModule)
+  },
+  {
+    path: 'user',
+        loadChildren: () => import('../modules/user/user.module').then(m => m.UserModule)
   }
 ];
 @NgModule({

+ 15 - 16
src/app/tab1/tab1.page.html

@@ -1,16 +1,15 @@
-<!-- <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>
+<ion-card style="background-image: url(assets/mypage.png);">
+  <ion-card-header>
+    <ion-item>
+      <ion-avatar slot="start">
+        <img src='{{"https://ionicframework.com/docs/img/demos/avatar.svg"}}' />
+      </ion-avatar>
+      <ion-label>
+        <ion-card-content>
+          <p>{{'请登入~'}}</p>
+          <p>登入查看更多哦</p>
+      </ion-card-content>
+      </ion-label>
+    </ion-item>
+  </ion-card-header>
+</ion-card>

+ 1 - 1
src/app/tabs/tabs-routing.module.ts

@@ -17,7 +17,7 @@ const routes: Routes = [
       },
       {
         path: 'tab3',
-        loadChildren: () => import('../tab3/tab3.module').then(m => m.Tab3PageModule)
+        loadChildren: () => import('../../modules/user/mine/mine.module').then(mod => mod.MinePageModule)
       },
       {
         path: '',

+ 3 - 0
src/global.scss

@@ -35,3 +35,6 @@
 /* @import "@ionic/angular/css/palettes/dark.always.css"; */
 /* @import "@ionic/angular/css/palettes/dark.class.css"; */
 @import "@ionic/angular/css/palettes/dark.system.css";
+
+$background: linear-gradient(220.55deg, #B7DCFF 0%, #ffffff 100%);
+

+ 2 - 1
src/index.html

@@ -17,9 +17,10 @@
   <!-- add to homescreen for ios -->
   <meta name="apple-mobile-web-app-capable" content="yes" />
   <meta name="apple-mobile-web-app-status-bar-style" content="black" />
+  <link rel="icon" type="image/x-icon" href="favicon.ico">
 </head>
 
-<body>
+<body style="background: linear-gradient(220.55deg, #DDE4FF 0%, #8DA2EE 100%);">
   <app-root></app-root>
 </body>
 

+ 0 - 3
src/luck-16th/login-page/login-page.component.html

@@ -1,3 +0,0 @@
-<p>
-  login-page works!
-</p>

+ 0 - 24
src/luck-16th/login-page/login-page.component.spec.ts

@@ -1,24 +0,0 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-import { IonicModule } from '@ionic/angular';
-
-import { LoginPageComponent } from './login-page.component';
-
-describe('LoginPageComponent', () => {
-  let component: LoginPageComponent;
-  let fixture: ComponentFixture<LoginPageComponent>;
-
-  beforeEach(waitForAsync(() => {
-    TestBed.configureTestingModule({
-      declarations: [ LoginPageComponent ],
-      imports: [IonicModule.forRoot()]
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(LoginPageComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  }));
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 14
src/luck-16th/login-page/login-page.component.ts

@@ -1,14 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-@Component({
-  selector: 'app-login-page',
-  templateUrl: './login-page.component.html',
-  styleUrls: ['./login-page.component.scss'],
-})
-export class LoginPageComponent  implements OnInit {
-
-  constructor() { }
-
-  ngOnInit() {}
-
-}

+ 17 - 0
src/modules/function/boos/boos-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { BoosPage } from './boos.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: BoosPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class BoosPageRoutingModule {}

+ 20 - 0
src/modules/function/boos/boos.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { BoosPageRoutingModule } from './boos-routing.module';
+
+import { BoosPage } from './boos.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    BoosPageRoutingModule
+  ],
+  declarations: [BoosPage]
+})
+export class BoosPageModule {}

+ 13 - 0
src/modules/function/boos/boos.page.html

@@ -0,0 +1,13 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>boos</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">boos</ion-title>
+    </ion-toolbar>
+  </ion-header>
+</ion-content>

+ 0 - 0
src/luck-16th/login-page/login-page.component.scss → src/modules/function/boos/boos.page.scss


+ 17 - 0
src/modules/function/boos/boos.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { BoosPage } from './boos.page';
+
+describe('BoosPage', () => {
+  let component: BoosPage;
+  let fixture: ComponentFixture<BoosPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(BoosPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 15 - 0
src/modules/function/boos/boos.page.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-boos',
+  templateUrl: './boos.page.html',
+  styleUrls: ['./boos.page.scss'],
+})
+export class BoosPage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 17 - 0
src/modules/function/employer/employer-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { EmployerPage } from './employer.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: EmployerPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class EmployerPageRoutingModule {}

+ 20 - 0
src/modules/function/employer/employer.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { EmployerPageRoutingModule } from './employer-routing.module';
+
+import { EmployerPage } from './employer.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    EmployerPageRoutingModule
+  ],
+  declarations: [EmployerPage]
+})
+export class EmployerPageModule {}

+ 13 - 0
src/modules/function/employer/employer.page.html

@@ -0,0 +1,13 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>employer</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">employer</ion-title>
+    </ion-toolbar>
+  </ion-header>
+</ion-content>

+ 0 - 0
src/modules/function/employer/employer.page.scss


+ 17 - 0
src/modules/function/employer/employer.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { EmployerPage } from './employer.page';
+
+describe('EmployerPage', () => {
+  let component: EmployerPage;
+  let fixture: ComponentFixture<EmployerPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(EmployerPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 15 - 0
src/modules/function/employer/employer.page.ts

@@ -0,0 +1,15 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-employer',
+  templateUrl: './employer.page.html',
+  styleUrls: ['./employer.page.scss'],
+})
+export class EmployerPage implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 10 - 0
src/modules/function/function-routing.module.ts

@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class FunctionRoutingModule { }

+ 14 - 0
src/modules/function/function.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { FunctionRoutingModule } from './function-routing.module';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    FunctionRoutingModule
+  ]
+})
+export class FunctionModule { }

+ 17 - 0
src/modules/user/edit-info/edit-info-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { EditInfoPage } from './edit-info.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: EditInfoPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class EditInfoPageRoutingModule {}

+ 20 - 0
src/modules/user/edit-info/edit-info.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { EditInfoPageRoutingModule } from './edit-info-routing.module';
+
+import { EditInfoPage } from './edit-info.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    EditInfoPageRoutingModule
+  ],
+  declarations: [EditInfoPage]
+})
+export class EditInfoPageModule {}

+ 47 - 0
src/modules/user/edit-info/edit-info.page.html

@@ -0,0 +1,47 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>资料编辑</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">资料编辑</ion-title>
+    </ion-toolbar>
+  </ion-header>
+
+  <ion-card>
+    <ion-card-header>
+      <ion-card-title>{{currentUser?.get('username')}} - {{currentUser?.id}}</ion-card-title>
+    </ion-card-header>
+    <ion-card-content>
+      <ion-list>
+        <ion-item>
+          <ion-input label="姓名" type="text" [(ngModel)]="userInfo.name"></ion-input>
+        </ion-item>
+        <ion-item>
+          <ion-input label="手机" type="tel" [(ngModel)]="userInfo.mobile"></ion-input>
+        </ion-item>
+        <ion-item>
+          <ion-select label="性别" [(ngModel)]="userInfo.gender">
+            <ion-select-option value="男">男</ion-select-option>
+            <ion-select-option value="女">女</ion-select-option>
+          </ion-select>
+        </ion-item>
+        <ion-item>
+          <ion-label>生日</ion-label>
+          <ion-datetime-button datetime="birthday"></ion-datetime-button>
+          <ion-modal [keepContentsMounted]="true">
+            <ng-template>
+              <ion-datetime id="birthday" displayFormat="MM/DD/YYYY" [(ngModel)]="userInfo.birthday"></ion-datetime>
+            </ng-template>
+          </ion-modal>
+        </ion-item>
+      </ion-list>
+    </ion-card-content>
+  </ion-card>
+
+  <ion-button expand="block" (click)="save()">保存</ion-button>
+  <ion-button expand="block" (click)="cancel()">取消</ion-button>
+</ion-content>

+ 0 - 0
src/modules/user/edit-info/edit-info.page.scss


+ 17 - 0
src/modules/user/edit-info/edit-info.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { EditInfoPage } from './edit-info.page';
+
+describe('EditInfoPage', () => {
+  let component: EditInfoPage;
+  let fixture: ComponentFixture<EditInfoPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(EditInfoPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 56 - 0
src/modules/user/edit-info/edit-info.page.ts

@@ -0,0 +1,56 @@
+import { Component, OnInit } from '@angular/core';
+import { NavController } from '@ionic/angular';
+import * as Parse from 'parse';
+
+@Component({
+  selector: 'app-edit-info',
+  templateUrl: './edit-info.page.html',
+  styleUrls: ['./edit-info.page.scss'],
+})
+export class EditInfoPage implements OnInit {
+
+  userInfo: any = {
+    name: '',
+    mobile: '',
+    gender: '',
+    birthday: ''
+  };
+  currentUser:Parse.User|undefined
+  constructor(private navController: NavController) {}
+
+  ngOnInit() {
+    this.currentUser = Parse.User.current();
+    if (this.currentUser) {
+      // 修改uesrInfo赋值逻辑,仅加载被编辑的字段属性值
+      let json = this.currentUser.toJSON();
+      for (const key in json) {
+        if (this.userInfo.hasOwnProperty(key)) {
+          this.userInfo[key] = json[key]
+        }
+      }
+    }
+    console.log(this.userInfo)
+  }
+
+  save() {
+    this.currentUser = Parse.User.current();
+    if (this.currentUser) {
+      console.log(this.userInfo)
+      for (const key in this.userInfo) {
+        if (this.userInfo.hasOwnProperty(key)) {
+          this.currentUser.set(key, this.userInfo[key]);
+        }
+      }
+      this.currentUser.save().then(() => {
+        this.navController.back();
+      }).catch((error) => {
+        console.error('Error saving user data: ', error);
+      });
+    }
+  }
+
+  cancel() {
+    this.navController.back();
+  }
+
+}

+ 17 - 0
src/modules/user/login/login-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { LoginPage } from './login.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: LoginPage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class LoginPageRoutingModule {}

+ 20 - 0
src/modules/user/login/login.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { LoginPageRoutingModule } from './login-routing.module';
+
+import { LoginPage } from './login.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    LoginPageRoutingModule
+  ],
+  declarations: [LoginPage]
+})
+export class LoginPageModule {}

+ 47 - 0
src/modules/user/login/login.page.html

@@ -0,0 +1,47 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-grid>
+      <ion-row>
+        <ion-col style="display: flex; justify-content: flex-start;">
+          <ion-icon name="chevron-back-outline"></ion-icon>
+        </ion-col>
+        <ion-col style="display: flex; justify-content: center;">
+          登入/注册
+        </ion-col>
+        <ion-col style="display: flex; justify-content: flex-end;">
+          <ion-icon name="notifications-circle-outline"></ion-icon>
+        </ion-col>
+      </ion-row>
+    </ion-grid>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-card>
+    <ion-card-header>
+      <ion-card-title>登录/注册</ion-card-title>
+    </ion-card-header>
+  
+    <ion-card-content>
+
+      <ion-list [inset]="true">
+        <ion-item>
+          <ion-input [(ngModel)]="username" label="账号" placeholder="请输入用户名"></ion-input>
+        </ion-item>
+        <ion-item>
+          <ion-input [(ngModel)]="password" label="密码" type="password" placeholder="请输入密码"></ion-input>
+        </ion-item>
+      </ion-list>
+      
+      <ion-row>
+        <ion-col></ion-col>
+        <ion-col><ion-button (click)="login()" fill="clear">登录</ion-button></ion-col>
+        <ion-col><ion-button (click)="register()" fill="clear">注册</ion-button></ion-col>
+        <ion-col></ion-col>
+      </ion-row>
+    </ion-card-content>
+  </ion-card>
+
+  <!-- 新增路由返回逻辑,执行back函数 -->
+  <ion-button expand="block" (click)="back()">返回</ion-button>
+</ion-content>

+ 0 - 0
src/modules/user/login/login.page.scss


+ 17 - 0
src/modules/user/login/login.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { LoginPage } from './login.page';
+
+describe('LoginPage', () => {
+  let component: LoginPage;
+  let fixture: ComponentFixture<LoginPage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(LoginPage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 93 - 0
src/modules/user/login/login.page.ts

@@ -0,0 +1,93 @@
+import { Component, OnInit } from '@angular/core';
+import { AlertController, NavController } from '@ionic/angular';
+import * as Parse from "parse"
+// 引用Router服务
+@Component({
+  selector: 'app-login',
+  templateUrl: './login.page.html',
+  styleUrls: ['./login.page.scss'],
+})
+export class LoginPage implements OnInit {
+
+  username:string = ""
+  password:string = ""
+  constructor(
+    // 新增:Router服务,用于路由跳转
+    private navCtrl:NavController,
+    private alertController:AlertController
+  ) { }
+
+  ngOnInit() {
+  }
+
+  async login(){
+    let user
+    try {
+      user = await Parse.User.logIn(this.username,this.password)
+    } catch (error:any) {
+      let message:string = ""
+      // 新增提示词详情,根据Parse.User.login方法返回的不同英文提示词,增加对应的中文内容转换
+      if(error?.message.indexOf("is required")>-1){
+        message = "必须输入账号或邮箱"
+      }
+      if(error?.message.indexOf("Invalid username")>-1){
+        message = "账号或密码错误,请检查"
+      }
+      this.presentAlert({
+        header:"登录失败",
+        subHeader:"状态码:"+error.code,
+        message:message || error.message
+      })
+    }
+    console.log(user)
+    if(user?.id){
+      this.navCtrl.back()
+    }
+  }
+  async register(){
+    let user = new Parse.User()
+    user.set("username",this.username)
+    user.set("password",this.password)
+    try {
+        let result = await user.signUp();
+        console.log(result)
+        if(result?.id){
+          this.navCtrl.back()
+        }
+        // Hooray! Let them use the app now.
+    } catch (error:any) {
+        // 新增提示词详情,根据Parse.User.signUp方法返回的不同英文提示词,增加对应的中文内容转换
+        let message:string = ""
+        if(error?.message.indexOf("already exists")>-1){
+          message = "该账号已存在请修改后重试"
+        }
+        if(error?.message.indexOf("empty")>-1){
+          message = "账号不能为空请输入后重试"
+        }
+        this.presentAlert({
+          header:"注册失败",
+          subHeader:"状态码:"+error.code,
+          message:message || error.message
+        })
+    }
+  }
+
+  async presentAlert(options:{header:string,subHeader:string,message:string}) {
+    const alert = await this.alertController.create({
+      header: options?.header,
+      subHeader: options?.subHeader,
+      message: options?.message,
+      buttons: ['好的'],
+    });
+
+    await alert.present();
+  }
+
+  /**
+   * 返回上级页面函数
+   * @desc
+   */
+  back(){
+    this.navCtrl.back()
+  }
+}

+ 17 - 0
src/modules/user/mine/mine-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { MinePage } from './mine.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: MinePage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class MinePageRoutingModule {}

+ 20 - 0
src/modules/user/mine/mine.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { MinePageRoutingModule } from './mine-routing.module';
+
+import { MinePage } from './mine.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    MinePageRoutingModule
+  ],
+  declarations: [MinePage]
+})
+export class MinePageModule {}

+ 84 - 0
src/modules/user/mine/mine.page.html

@@ -0,0 +1,84 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-grid>
+      <ion-row>
+        <ion-col style="display: flex; justify-content: flex-start;">
+          <ion-icon name="chevron-back-outline"></ion-icon>
+        </ion-col>
+        <ion-col style="display: flex; justify-content: center;">
+          我的
+        </ion-col>
+        <ion-col style="display: flex; justify-content: flex-end;">
+          <ion-icon name="notifications-circle-outline"></ion-icon>
+        </ion-col>
+      </ion-row>
+    </ion-grid>
+  </ion-toolbar>
+</ion-header>
+<div class="page-color">
+    <ion-card>
+      <ion-card-header>
+        <ion-item>
+          <ion-avatar slot="start">
+            <img src='{{"https://ionicframework.com/docs/img/demos/avatar.svg"}}' />
+          </ion-avatar>
+          <ion-label>
+            <ion-card-content>
+              <ion-card-title>{{user?.get("username") || '未登录'}}</ion-card-title>
+              <ion-card-subtitle *ngIf="!user?.id">请您登陆后继续使用</ion-card-subtitle>
+              <ion-card-subtitle *ngIf="user?.id">{{user?.get("name")}}-{{user?.get("gender")}}</ion-card-subtitle>
+          </ion-card-content>
+          </ion-label>
+        </ion-item>
+      </ion-card-header>
+    </ion-card>
+  
+    <ion-card>
+      <ion-card-header>
+        <ion-card-title style="font-size: 20px;">个人资料</ion-card-title>
+        <ion-button *ngIf="user?.id" fill="clear" routerLink="/user/edit/info">编辑资料</ion-button>
+      </ion-card-header>
+    
+      <ion-card-content>
+        <ion-label>
+          <b>联系方式</b>
+          <p>13679842345</p>
+        </ion-label>
+        <br>
+        <ion-label>
+          <b>公司信息</b>
+          <p>建筑公司</p>
+        </ion-label>
+      </ion-card-content>
+    </ion-card>
+  
+    <ion-card>
+      <ion-card-header>
+        <ion-card-title style="font-size: 20px;">设置</ion-card-title>
+        <ion-button *ngIf="user?.id" fill="clear" routerLink="/user/edit/info">编辑资料</ion-button>
+      </ion-card-header>
+    
+      <ion-card-content>
+        <ion-label>
+          <b>修改密码</b>
+        </ion-label>
+        <br>
+        <ion-label>
+          <b>消息通知设置</b>
+        </ion-label>
+      </ion-card-content>
+    </ion-card>
+  
+  
+    <ion-card>
+      <ion-row>
+        <ion-col></ion-col>
+        <ion-col size="6">
+          <ion-button style="display: flex; justify-content: center;" *ngIf="!user?.id" routerLink="/user/login">登录</ion-button>
+          <ion-button style="display: flex; justify-content: center;" *ngIf="user?.id" (click)="logout()">登出</ion-button>
+        </ion-col>
+        <ion-col></ion-col>
+      </ion-row>
+    </ion-card>
+    <ion-button *ngIf="user?.id" fill="clear" (click)="logout()">登出</ion-button>
+</div>

+ 3 - 0
src/modules/user/mine/mine.page.scss

@@ -0,0 +1,3 @@
+.page-color{
+    background: linear-gradient(220.55deg, #B7DCFF 0%, #ffffff 100%);
+}

+ 17 - 0
src/modules/user/mine/mine.page.spec.ts

@@ -0,0 +1,17 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MinePage } from './mine.page';
+
+describe('MinePage', () => {
+  let component: MinePage;
+  let fixture: ComponentFixture<MinePage>;
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MinePage);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 27 - 0
src/modules/user/mine/mine.page.ts

@@ -0,0 +1,27 @@
+import { Component, OnInit } from '@angular/core';
+// 由于Parse本身是js库,在ts中加载需要通过 * as Parse转换一下
+import * as Parse from "parse"
+@Component({
+  selector: 'app-mine',
+  templateUrl: './mine.page.html',
+  styleUrls: ['./mine.page.scss'],
+})
+export class MinePage implements OnInit {
+
+  constructor() {
+   
+  }
+
+  // 由于Parse.User.current()是随着localStorage变化的属性
+  // 为了避免首次复制后用户状态变化,页面不同步,通过get方法实现实时获取
+  user:Parse.User|undefined
+  async ngOnInit() {
+      this.user = await Parse.User.current()
+      setInterval(async ()=>{
+      this.user = await Parse.User.current()
+    },1000)
+  }
+  logout(){
+    Parse.User.logOut();
+  }
+}

+ 14 - 0
src/modules/user/user-routing.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+const routes: Routes = [
+    {path: 'login', loadChildren: () => import('./login/login.module').then(mod => mod.LoginPageModule)},
+    {path: 'mine', loadChildren: () => import('./mine/mine.module').then(mod => mod.MinePageModule)},
+    {path: 'edit/info', loadChildren: () => import('./edit-info/edit-info.module').then(mod => mod.EditInfoPageModule)},
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class UserRoutingModule { }

+ 14 - 0
src/modules/user/user.module.ts

@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { UserRoutingModule } from './user-routing.module';
+
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    UserRoutingModule
+  ]
+})
+export class UserModule { }

+ 90 - 0
src/test.html

@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>个人资料</title>
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            margin: 0;
+            padding: 0;
+        }
+        .header {
+            background-color: #f1f1f1;
+            padding: 20px;
+            text-align: center;
+        }
+        .content {
+            padding: 20px;
+        }
+        .section {
+            margin-bottom: 20px;
+        }
+        .section-title {
+            font-weight: bold;
+            margin-bottom: 10px;
+        }
+        .form-control {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 10px;
+        }
+        .form-control label {
+            font-weight: bold;
+        }
+        .form-control input[type="text"],
+        .form-control input[type="password"] {
+            flex-grow: 1;
+            margin-left: 10px;
+        }
+        .button {
+            background-color: #4CAF50;
+            border: none;
+            color: white;
+            padding: 10px 20px;
+            text-align: center;
+            text-decoration: none;
+            display: inline-block;
+            font-size: 16px;
+            margin: 4px 2px;
+            cursor: pointer;
+        }
+    </style>
+</head>
+<body>
+    <div class="header">
+        <h1>个人资料</h1>
+    </div>
+    <div class="content">
+        <div class="section">
+            <div class="section-title">基本信息</div>
+            <div class="form-control">
+                <label>姓名:</label>
+                <input type="text" value="张伟" readonly>
+            </div>
+            <div class="form-control">
+                <label>职位:</label>
+                <input type="text" value="项目经理" readonly>
+            </div>
+        </div>
+        <div class="section">
+            <div class="section-title">联系方式</div>
+            <div class="form-control">
+                <label>手机号:</label>
+                <input type="text" value="13912345678" readonly>
+            </div>
+        </div>
+        <div class="section">
+            <div class="section-title">公司信息</div>
+            <div class="form-control">
+                <label>公司名称:</label>
+                <input type="text" value="建筑公司" readonly>
+            </div>
+        </div>
+        <div class="section">
+            <a href="#" class="button">编辑资料</a>
+        </div>
+    </div>
+</body>
+</html>