0. 项目目录

  1. 欢迎页的实现
  2. 程序第一次运行实现
  3. 注册的实现
  4. 登陆的实现
  5. 首页的实现
  6. 店铺设置的实现
  7. 商品分类浏览的实现
  8. 编辑商品分类的实现
  9. 新增商品的实现
  10. 商品管理的实现

目录

  • 0. 项目目录
  • 1. 产品需求
    • 1.1 登录页面需求
    • 1.2 找回密码界面详细需求
  • 2. 多种方式登录的设计思路
    • 2.1 表设计
    • 2.2 AJAX请求结果
  • 3. 实现注册
  • 4. 实现登录
    • 4.1 LoginPage组件类的实现
    • 4.2 实现登陆界面
    • 4.3 判断用户名和密码是否正确
  • 5.忘记密码
    • 5.1 忘记密码界面
    • 5.2 忘记界面ts
  • 6. 版权声明

# 写于2020.12.17
# 测试内容包括忘记密码页面跳转,忘记密码手机账号登入,邮箱账号登入,密码更新,注册,手机或邮箱登入
# 有些页面的路由 model打通可能忘记写了,特别注意新页面时候,路由 model都要配好model是为了需要的服务能用,别人能用;路由是为了页面之间通路

1. 产品需求

1.1 登录页面需求

用户场景:程序第一次运行时,用户在欢迎页上点击登录按钮进入登录页面。进入应用程序首页时如果之前用户没有登录过,或者登录时间已经过期,进入登录页面。用户登录成功后,就能够使用应用程序的所有功能。5天之内再使用软件都不需要再次登录。

输入/前置条件:用户已完成注册,用户未登录或者登录时间已过期。

1.2 找回密码界面详细需求

用户场景:用户在登录时忘记了登录密码,可以通过找回密码功能重新设置密码。在登录页上单击忘记密码按
钮,页面跳转到找回密码页面。

输入/前置条件:已注册

2. 多种方式登录的设计思路

2.1 表设计


2.2 AJAX请求结果

统一AJAX请求时从服务器端返回的JSON对象。AjaxResult在其他功能中都需要用到,因此把他放在
SharedModule中

ionic g class shared/class/ajaxResult
export class AjaxResult {constructor(public success: boolean,public data: any,public error?: { message: string; details?: string; },public targetUrl?: string,public unAuthorizedRequest?: boolean) {}
}

3. 实现注册

在PassportService中添加signup(addUser)方法。
src\app\pages\passport\passport.service.ts

async addUser(sign: Signup) {// 验证手机号是否唯一const ajaxResult = this.isUniquePhone(sign.phone);if (!ajaxResult.success) {return ajaxResult;}// 判断邮箱是否已存在const ajaxResult1 = this.isUniqueEmail(sign.email);if (!ajaxResult1.success) {return ajaxResult1;}// 添加用户let users: User[];const userId = Date.now();const user: User = {id: userId,phone: sign.phone,email: sign.email,password: sign.password,createTime: new Date()};users = this.localStorageService.get('TUser', []);users.push(user);this.localStorageService.set('TUser', users);// 添加手机号的账户const account: LoginAccount = {userId: userId,Identifier: sign.phone,credential: sign.password,}this.addAccount(account);// 添加邮箱的账户const account1: LoginAccount = {userId: userId,Identifier: sign.email,credential: sign.password,}this.addAccount(account1);// 添加店铺let shop: Shop = {userId: userId,shopName: '未填写',shopShortName: '未填写',userName: '未填写',shopTel: sign.phone,industryType: '未填写'}this.shopService.addShop(shop);return new AjaxResult(true, null);}
 /*** 判断手机号是否存在* @param sign 注册用户信息*/public isUniquePhone(phone: string) {let users = this.localStorageService.get('TUser', []);for (let i = 0; i < users.length; i++) {if (users[i].phone === phone) {return new AjaxResult(false, null, {message: '您的手机号码已经被注册',details: ''});}}return new AjaxResult(true, null);}
  /*** 判断邮箱是否存在* @param sign 注册用户信息*/public isUniqueEmail(email: string) {let users = this.localStorageService.get('TUser', []);for (let i = 0; i < users.length; i++) {if (users[i].email === email) {return new AjaxResult(false, null, {message: '您的邮箱已经被注册',details: ''});}}return new AjaxResult(true, null);}

4. 实现登录

4.1 LoginPage组件类的实现

为登录组件类添加属性和方法。建议参考之前的任务创建登录页面的视图模型。
src\app\pages\passport\login\login.page.ts

export class LoginPage extends BasePage implements OnInit {constructor(private toastController: ToastController,private passportService:PassportService,private alertController:AlertController,public menuController:MenuController,private router:Router) {super(menuController);}ngOnInit() {}username: string = ''; // 视图模型的属性账号,双向绑定password: string = ''; // 视图模型的属性密码,双向绑定// ...其他省略// 点击登录按钮时调用async onLogin(form: NgForm) {let toast: any;// 判断表单验证是否正确if (form.invalid) {toast = await this.toastController.create({duration: 3000 });}// 判断的代码省略,参考之前的任务自行补上下面代码if (form.controls.username.errors?.required) {toast.message = '请输入您的手机号码或者邮箱';toast.present();return;}if (form.controls.password.errors?.required) {toast.message = '请输入您的密码';toast.present();return;}this.passportService.login(this.username, this.password).then((result) => {if (result.success) {this.router.navigateByUrl('home');// 验证成功,自行完成页面跳转} else {this.alertController.create({header: '警告',buttons: ['确定']}).then((alert) => {alert.message = result.error.message;alert.present();});}});}// 点击忘记密码时调用onForgotPassword() {// 进入找回密码页面}}

async onLogin(form: NgForm):使用toast时,提示内容尽可能简短,长度控制在一行以内。如果提示内容太多,导致用户无法在3秒内读完,建议使用alert

4.2 实现登陆界面

修改登录组件的模板文件
src\app\pages\passport\login\login.page.html

<!--<ion-header><ion-toolbar><ion-title>login</ion-title></ion-toolbar>
</ion-header>--><ion-content class="ion-no-padding"><img src="assets/img/logoin_title.jpg" alt=""><div class="ion-padding-horizontal"><form #loginForm="ngForm"><ion-list class="ion-no-margin ion-no-padding"><ion-item lines="none"></ion-item><ion-item><ion-label position="fixed">账号</ion-label><ion-input name="username" type="string" placeholder="手机号或者电子邮箱" [(ngModel)]="username" required></ion-input></ion-item><ion-item class="ion-margin-top"><ion-label position="fixed">密码</ion-label><ion-input name="password" type="password" placeholder="您的生意专家登录密码" [(ngModel)]="password" required></ion-input></ion-item><ion-item lines="none"></ion-item></ion-list><ion-grid><ion-row><ion-col><ion-button expand="full" color="primary" (click)="onLogin(loginForm)">登录</ion-button></ion-col><ion-col><ion-button expand="full" fill="outline" color="primary" href="/passport/signup">注册新账号</ion-button></ion-col></ion-row><ion-row><ion-col><ion-button fill="clear" size="small" href="/passport/forgot-password">忘记密码?</ion-button></ion-col></ion-row><ion-row class="ion-text-center"><ion-col>查看演示</ion-col></ion-row></ion-grid></form></div><yangGuang-copyright [bottom]="'20px'"></yangGuang-copyright><!--<div style="position: fixed; left: 0; right: 0; bottom: 10px;" class="ion-text-center"><span>&copy;2010-2020 生意专家</span></div>-->
</ion-content>

43行代码yangGuang-copyright换成自己Logo,版权声明,可转6

4.3 判断用户名和密码是否正确

重要的信息使用Alerts给用户提示。

  1. 通过构造函数依赖注入AlertController和PassportService。
  2. 在onLogin方法中创建警告对话框并展现。
    src\app\pages\passport\login\login.page.ts
async onLogin(form: NgForm) {// 判断的代码省略this.passportService.login(this.username, this.password).then((result) => {if (result.success) {// 验证成功,自行完成页面跳转} else {this.alertController.create({header: '警告',buttons: ['确定']}).then((alert) => {alert.message = result.error.message;alert.present();});}});
}

5.忘记密码

根据需求,完成剩余的登录功能。

  1. 点击“忘记密码”,进入找回密码页面。
  2. 登录成功后页面跳转到首页并把相关数据保存在本地存储中。
  3. 在欢迎页组件中调整onSkip代码,如果程序是第一次运行,就跳转到注册页面。判断用户是否已登录,
    已登录过,跳转到首页。未登录过或者登录已经过期,跳转到登录页。

5.1 忘记密码界面

参考之前的任务,在passport目录中创建找回密码组件。参考之前的任务实现找回密码的页面跳转。
找回密码导航栏的实现。
src\app\pages\passport\forgot-password\forgot-password.page.html

<ion-header class="ion-no-border"><ion-toolbar><ion-buttons slot="start"><ion-back-button text="返回"></ion-back-button></ion-buttons><ion-title>找回密码</ion-title></ion-toolbar><ion-toolbar>1、输入邮箱或者手机号>2、输入验证码>3、重置密码</ion-toolbar>
</ion-header><ion-content><div class="ion-text-center"><img class="logo" src="assets/img/logo.png" alt=""></div><ion-grid class="fixed"><ion-row><ion-col class="ion-align-self-center"><img src="assets/img/registered_one.png" alt="" *ngIf="slideIndex!==0"><img src="assets/img/registered_one_one.png" alt="" *ngIf="slideIndex===0"></ion-col><hr/><ion-col class="ion-align-self-center"><img src="assets/img/registered_two.png" alt="" *ngIf="slideIndex!==1"><img src="assets/img/registered_two_two.png" alt="" *ngIf="slideIndex===1"></ion-col><hr/><ion-col class="ion-align-self-center"><img src="assets/img/registered_three.png" alt="" *ngIf="slideIndex!==2"><img src="assets/img/registered_three_three.png" alt="" *ngIf="slideIndex===2"></ion-col><hr/><ion-col class="ion-align-self-center"><img src="assets/img/register_four.png" alt="" *ngIf="slideIndex!==3"><img src="assets/img/register_four_four.png" alt="" *ngIf="slideIndex===3"></ion-col></ion-row></ion-grid><ion-slides  #accountSlides  (ionSlideWillChange)="onSlideWillChange($event)"><ion-slide><form (ngSubmit)="onSubmitAccount(accountForm)" #accountForm="ngForm"><ion-list><ion-item><ion-input name="account" type="string" placeholder="请输入您的手机号码或者邮箱" required  [(ngModel)]="accounts.account" #account="ngModel"></ion-input></ion-item><ion-text class="ion-text-center" color="danger" *ngIf="account.invalid && account.touched"><p [hidden]="!account.errors?.required" class="padding-start">请输入您的手机号码或者邮箱</p></ion-text></ion-list><div class="ion-padding-horizontal"><ion-button *ngIf="slideIndex!==3" type="submit" expand="full" color="primary" [disabled]="accountForm.invalid">下一步</ion-button></div></form></ion-slide><ion-slide><form (ngSubmit)="onSubmitCode(codeForm)" #codeForm="ngForm"><ion-list><ion-item><ion-input name="code" type="ion-text" slot="start" placeholder="输入验证码" required minlength="4" [(ngModel)]="accounts.code" #code="ngModel"></ion-input><ion-button color="primary" expand="full" slot="end" [disabled]="countDown" (click)="onSendSMS()">{{showButtonText}}</ion-button></ion-item><ion-text class="ion-text-center" color="danger" *ngIf="code.invalid && code.touched"><p [hidden]="!code.errors?.required" class="padding-start">请输入验证码</p></ion-text></ion-list><div class="ion-padding-horizontal"><ion-button *ngIf="slideIndex!==3" type="submit" expand="full" color="primary" [disabled]="codeForm.invalid">下一步</ion-button></div></form></ion-slide><ion-slide><form (ngSubmit)="onSubmitUser(userForm)" #userForm="ngForm"><ion-list><ion-item><ion-input name="password" type="password" placeholder="请输入您的密码" required pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$" [(ngModel)]="accounts.password" #password="ngModel"></ion-input></ion-item><ion-text class="ion-text-center" color="danger" *ngIf="password.invalid && password.touched"><p [hidden]="!password.errors?.required" class="padding-start">请输入密码</p><p [hidden]="!password.errors?.pattern" class="padding-start">密码包含大小写字母和数字且长度在8-16位</p></ion-text><ion-item><ion-input name="confirmPassword" type="password" placeholder="请再次输入您的密码" required pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$" [(ngModel)]="accounts.confirmPassword" #confirmPassword="ngModel"></ion-input></ion-item><ion-text class="ion-text-center" color="danger" *ngIf="confirmPassword.invalid && confirmPassword.touched"><p [hidden]="!confirmPassword.errors?.required" class="padding-start">请再次输入密码</p><p [hidden]="!confirmPassword.errors?.pattern" class="padding-start">密码包含大小写字母和数字且长度在8-16位</p></ion-text></ion-list><div class="ion-padding-horizontal"><ion-button type="submit" expand="full" color="primary" [disabled]="userForm.invalid">重置密码</ion-button></div></form></ion-slide><ion-slide><h1>密码修改成功!</h1><div class="ion-padding-horizontal"><ion-button type="submit" expand="full" color="primary" href="/passport/login">登录</ion-button></div></ion-slide></ion-slides>
</ion-content>

5.2 忘记界面ts

src\app\pages\passport\forgot-password\forgot-password.page.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { AlertController, IonSlides, MenuController, ToastController } from '@ionic/angular';
import { LocalStorageService } from 'src/app/shared/services/local-storage.service';
import { AuthenticationCodeService } from '../authentication-code.service';
import { BasePage } from '../basepage';
import { PassportService } from '../passport.service';
import { Account } from './account';
@Component({selector: 'app-forgot-password',templateUrl: './forgot-password.page.html',styleUrls: ['./forgot-password.page.scss'],
})
export class ForgotPasswordPage extends BasePage implements OnInit {@ViewChild('accountSlides', { static: true }) accountSlides: IonSlides;accounts: Account = {account: '',password: '',confirmPassword:'',code: ''};// 按钮切换showButtonText = '发送验证码';countDowmTime = 60;countDown = false;// 显示验证码错误slideIndex = 0;constructor(private authenticationCodeService: AuthenticationCodeService, private localStorageService: LocalStorageService, private toastController: ToastController,private passportService:PassportService,private alertController:AlertController,public menuController:MenuController) {super(menuController);}/*** 验证账户是否存在* @param form */async onSubmitAccount(form: NgForm) {await this.passportService.isUniqueAccount(this.accounts.account).then((result) => {if (result.success) {this.onNext();} else {this.alertController.create({header: '警告',buttons: ['确定']}).then((alert) => {alert.message = result.error.message;alert.present();});}});}/*** * @param form 表单*/onSubmitCode(form: NgForm) {// 验证码验证let result = this.onValidateCode(this.accounts.code);console.log(result);if (result == true) {this.onNext();console.log('验证码验证成功');} else {alert('验证码不一致!');}}/*** * @param code 验证码*/onValidateCode(code: string): boolean {return this.authenticationCodeService.validate(code);}/*** 发送验证码*/onSendSMS() {let codeTime = this.localStorageService.get(this.accounts.account, 0);if (codeTime == 30) {this.showButtonText = '已获取三次';this.countDown = true;return;} else {codeTime++;this.localStorageService.set(this.accounts.account, codeTime);}this.authenticationCodeService.createCode();this.countDown = true;                // 发送验证码后一分钟内,按钮变成不可点击状态 this.showButtonText = '验证码已发送(' + 60 + 's)';           // 验证码发送后的初始状态 const start = setInterval(() => {if (this.countDowmTime >= 0) {this.showButtonText = '验证码已发送(' + this.countDowmTime-- + 's)';} else {clearInterval(start);this.countDowmTime = 60;this.showButtonText = '重新发送';this.countDown = false;}}, 1000)}/*** * @param form 表单 进行更新*/async onSubmitUser(form: NgForm) {if (this.accounts.password !== this.accounts.confirmPassword) {alert('密码不一致!');} else {await this.passportService.updatePassword(this.accounts.account,this.accounts.password).then((result) => {if (result.success) {this.onNext();} else {this.alertController.create({header: '警告',buttons: ['确定']}).then((alert) => {alert.message = result.error.message;alert.present();});}});}}ngOnInit() {this.accountSlides.lockSwipes(true); // 如果时ture那么就锁定 滑动不了页面}onNext() {this.accountSlides.lockSwipes(false); // 没有所页面this.accountSlides.slideNext(); // 当发生滑倒下一页时this.slideIndex++; // slideIndex+1this.accountSlides.lockSwipes(true); // 就划不动了}onPrevious() {this.accountSlides.lockSwipes(false);this.accountSlides.slidePrev();this.slideIndex--;this.accountSlides.lockSwipes(true);}}

6. 版权声明

把版权声明固定在程序的底部。(不用)
src\app\pages\passport\login\login.page.html

<div style="position: fixed; left: 0; right: 0; bottom: 10px;" class="ion-textcenter"><span>&copy;2010-2020 生意专家</span>
</div>

在登录页面和注册页面都有版权的声明,考虑到复用性和可维护性,创建组件。实际上之前用到的页面也是组件的一种。

  1. 创建component。 在app\shared目录下创建components文件夹
ionic g component shared/components/Copyright
  1. 在shared.module.ts文件中,在declarations属性中添加CopyrightComponent,然后在exports属性中添加。
    src\app\shared\components\shared.mudule.ts
import { CopyrightComponent } from './components/copyright/copyright.component';
import { IonicModule } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { LocalStorageService } from './services/local-storage.service';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({declarations: [CopyrightComponent],imports: [CommonModule,FormsModule,IonicModule],providers: [LocalStorageService],exports: [CommonModule,FormsModule,IonicModule,CopyrightComponent]
})
export class SharedModule { }
  1. 修改copyright组件类,能够动态的设定版权距离底部的距离,自动获取当前时间的年份。
    src\app\shared\componets\copyright\copyright.ts
import { Component, Input } from '@angular/core';
@Component({selector: 'app-copyright',templateUrl: 'copyright.html'
})
export class CopyrightComponent {@Input() bottom: string;text: string;constructor() {let year = (new Date()).getFullYear();this.text = `2010-${year} 生意专家`;this.bottom = '10px';}
}

这种字符串是被反引号包围( `),并且以${ expr }这种形式嵌入表达式。

  1. 使用属性绑定组件类的bottom属性。
    src\app\shared\componets\copyright\copyright.hml
<div style="position: fixed;left: 0; right: 0;" [style.bottom]="bottom"
class="ion-text-center"><span>&copy;{{text}}</span>
</div>
  1. 在登录页中使用CopyrightComponent代替之前的div。
    src\app\pages\passport\login\login.page.html
<!-- 其他省略 --><app-copyright [bottom]="'20px'"></app-copyright>
</ion-content>

app-copyright要换成自己的Logo

工程训练:生意专家:04 登陆实现相关推荐

  1. 智能车竞赛接入工程训练竞赛相关事项-建议稿件

    简 介: 对于智能车竞赛与工训竞赛在教指委指导下完成相互结合方面进行初步的规划. 关键词: 智能车竞赛,工训竞赛 §01 背景介绍 一.全国大学生智能车竞赛   全国大学生 智能车竞赛 最初是由教育部 ...

  2. 工程训练大赛物流小车_宁大机械学子在工程训练省赛中斩获佳绩,取得历史性突破...

    2019第六届 浙江省大学生工程训练综合能力竞赛暨第五届浙江创客教育基地联盟创客大赛 圆满落幕 --宁大斩获省一等奖1项,二等奖3项,三等奖1项,获奖率100%,获奖人数15人创历史新高. 赛事介绍 ...

  3. 第七届工程训练比赛之智能垃圾分类

    2021第七届工程训练综合能力竞赛之智能垃圾分类 前言 写在前面:第一次写博客,想把这半年的备赛经历记录下来分享分享给大家,如有错误欢迎大家指正. 比赛成绩:1分23秒(播放宣传片到满载结束) 基本配 ...

  4. 移动平台开发工程训练

    题 目 移动平台开发工程训练 学科部.系: 信息学科部计算机系 专业班级: 学 号: 学生姓名: 指导教师: 起讫日期: 移动平台开发工程训练报告 实验名称: 移动平台开发工程训练 实验目的: 本次工 ...

  5. 【南大科院】高级网络服务工程训练

    密级: 科学技术学院 NANCHANG UNIVERSITY COLLEGE OF SCIENCE AND TECHNOLOGY 计算机系工程训练报告 <高级网络服务工程训练> (2019 ...

  6. 【竞赛总结】第七届工程训练大赛智能搬运赛项心得

    22/9/25更新 最近发现这篇博客被越来越多人收藏,我受宠若惊.为了给大家提供更准确的参考,我在今晚修改了之前的全文内容,并删掉一些没用的废话. 22/4/15更新 发现这篇文章被很多人看到了,潦草 ...

  7. 南开大学工程训练结课报告

    工程训练结课报告 一.焊电路 1.什么是虚焊?虚焊有什么危害? 答:虚焊是指焊锡过少或未很好焊接. 虚焊会导致电路未连接甚至焊锡脱落. 2.通过工程训练课的练习,你认为焊好电路有那些要领? 答:1)要 ...

  8. 工程训练大赛物流小车_我校在全国大学生工程训练综合能力竞赛总决赛中创佳绩...

    6月1日至6月2日,第六届全国大学生工程训练综合能力竞赛总决赛在天津职业技术师范大学隆重举行.我校三名学子在无碳小车"S环形"赛道挑战赛中获一等奖,这是我校首次在该项赛事中摘得重量 ...

  9. 第七届全国大学生工程训练综合能力竞赛(工训赛) 智能配送无人机赛项 省赛心得

    第七届全国大学生工程训练综合能力竞赛(工训赛) 智能配送无人机赛项 省赛心得 第七届全国大学生工程训练综合能力竞赛(工训赛)江西省赛 在华东交通大学落下帷幕.至此,为时四个多月的备赛阶段终于告一段落了 ...

最新文章

  1. 5m 云服务器2核4g_华为云服务器2核4G 5M 248一年
  2. 矩阵奇异值分解简介及C++/OpenCV/Eigen的三种实现
  3. 分享自己整理的《UIT备份容灾解决方案培训稿》
  4. oracle 如何数组变成表,Oracle从零开始19——表的管理09——嵌套表和可变数组
  5. 自监督学习新思路!基于蒸馏(distillation loss)的自监督学习算法
  6. Win11如何更改盘符?Win11更改磁盘驱动器号的方法
  7. shell死循环(whilefor)
  8. 计算机职业规划500字中专,计算机中专生职业规划范文500字中专生职业生涯规划书范文.doc...
  9. 塑胶产品内滑块设计要点,以及注意哪些事项?
  10. 计算机的进制的转换公式,计算机进制转换公式
  11. anaconda安装完怎么打开_录像机怎么样安装在机柜上,看完就明白
  12. 单词首字母大写 (5分)
  13. UIGestureRecognizer触控手势
  14. 运行yolov5-5.0出现AttributeError: Can‘t get attribute ‘SPPF‘ 正确解决方法
  15. e-r数据建模-概念模型 逻辑模型 物理模型-总结
  16. Buffon's Needle
  17. 数据库中的 【行式存储】和【列式存储】
  18. Java学习-07 IO学习
  19. 车载TBOX嵌入式设备软件的功能测试
  20. sqli-labs/Less-52

热门文章

  1. 海拔vs季节,谁决定外生菌根真菌群落的时空分布格局?
  2. UE Lyda项目学习 二、距离匹配 步幅适配 同步组
  3. 一分钟教你如何识别表格文字内容
  4. 论文笔记:Structure-Grounded Pretraining for Text-to-SQL
  5. 小试牛刀--我的快速离散傅里叶变化matlab函数(FFT)
  6. c语言初始化列表,Initialization(初始化)
  7. python试题中连续质数计算,官方答案看不懂,就自己写了个,请大神过目!
  8. 北京筑龙胡婧玥:采购供应链的数字化转型之路
  9. Oracle 实时复制到 PostgreSQL或EnterpriseDB
  10. vs_installer.exe打不开 闪退的解决方法