diff --git a/angular.json b/angular.json index 8753b78..7fee45f 100644 --- a/angular.json +++ b/angular.json @@ -64,6 +64,14 @@ "maximumError": "10kb" } ] + }, + "rap2": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.rap2.ts" + } + ] } } }, @@ -75,6 +83,9 @@ "configurations": { "production": { "browserTarget": "PocketCommunityWeb:build:production" + }, + "rap2": { + "browserTarget": "PocketCommunityWeb:build:rap2" } } }, diff --git a/src/app/account/account/account.module.ts b/src/app/account/account/account.module.ts index 09f9c52..e59873c 100644 --- a/src/app/account/account/account.module.ts +++ b/src/app/account/account/account.module.ts @@ -6,15 +6,24 @@ import {LoginComponent} from '../login/login.component'; import {RegisterComponent} from '../register/register.component'; // 重置密码组件 import {ResetpwdComponent} from '../resetpwd/resetpwd.component'; +import {TranslateModule} from '@ngx-translate/core'; +import {RouterModule} from '@angular/router'; +import {ReactiveFormsModule} from '@angular/forms'; +// 提示框组件 +import {MessageComponent} from '../../message/message.component'; +import {InputComponent} from '../../input/input.component'; /** * 账号管理模块 */ @NgModule({ - declarations: [LoginComponent, RegisterComponent, ResetpwdComponent], + declarations: [LoginComponent, RegisterComponent, ResetpwdComponent, MessageComponent, InputComponent], imports: [ - CommonModule + CommonModule, + TranslateModule, + RouterModule, + ReactiveFormsModule, ] }) export class AccountModule { } diff --git a/src/app/account/login/login.component.html b/src/app/account/login/login.component.html index df5a7b5..0cb64d3 100644 --- a/src/app/account/login/login.component.html +++ b/src/app/account/login/login.component.html @@ -8,7 +8,7 @@ {{ 'login.manager_name' | translate }} + [placeholder]="'tip.input' | translate:{value:'login.manager_name'|translate}" formControlName="managerName"> @@ -17,7 +17,7 @@ {{ 'login.password' | translate }} + [placeholder]="'tip.input' | translate:{value:'login.manager_name'|translate}" formControlName="password">
diff --git a/src/app/account/login/login.service.ts b/src/app/account/login/login.service.ts index 9a5a259..5d7850d 100644 --- a/src/app/account/login/login.service.ts +++ b/src/app/account/login/login.service.ts @@ -1,19 +1,20 @@ import {Injectable} from '@angular/core'; import {CookieService} from 'ngx-cookie-service'; import {Router} from '@angular/router'; -import {HttpInterface} from '../../interface/Http'; import {MessageService} from '../../message/message.service'; +import {JSONRequest} from '../../interface/JSONRequest'; @Injectable({ providedIn: 'root' }) -export class LoginService implements HttpInterface { +export class LoginService extends JSONRequest { constructor( private cookieService: CookieService, private router: Router, private messageService: MessageService ) { + super(); } /** @@ -52,8 +53,4 @@ export class LoginService implements HttpInterface { this.messageService.danger('登陆失败'); return false; } - - url(): string { - return '/api/manager/login'; - } } diff --git a/src/app/account/register/register.component.html b/src/app/account/register/register.component.html index 6b23b3d..390051d 100644 --- a/src/app/account/register/register.component.html +++ b/src/app/account/register/register.component.html @@ -7,8 +7,12 @@
{{ 'login.manager_name' | translate }}
- + +
+ {{'tip.notnull' | translate:{value:'login.manager_name'|translate} }} +
@@ -17,7 +21,12 @@ {{ 'login.password' | translate }} + [class.is-invalid]="checkValue('password')" + [placeholder]="'tip.input' | translate:{value:'login.password'|translate}" formControlName="password"/> + +
+ {{'tip.notnull' | translate:{value:'login.password'|translate} }} +
@@ -27,8 +36,14 @@ {{ 'register.confirm_pwd' | translate }} + [class.is-invalid]="(checkPwd()|async) !==''" + [placeholder]="'tip.input' | translate:{value:'register.confirm_pwd'|translate}" + formControlName="confirmPassword"/> + +
+ {{ checkPwd()|async }} + +
@@ -36,29 +51,41 @@
{{ 'register.mobile' | translate }}
- + + +
+ {{ checkMobile()|async }} +
-
+
{{ 'register.email' | translate }}
+ [placeholder]="'tip.input' | translate:{value:'register.email'|translate}" formControlName="email" [class.is-invalid]="checkValue('email')" /> + + +
+ {{'tip.notnull' | translate:{value:'register.email'|translate} }} +
- +
-
diff --git a/src/app/account/register/register.component.ts b/src/app/account/register/register.component.ts index 86c6285..093f66c 100644 --- a/src/app/account/register/register.component.ts +++ b/src/app/account/register/register.component.ts @@ -1,37 +1,123 @@ import {Component, OnInit} from '@angular/core'; import {FormBuilder} from '@angular/forms'; import {Commons} from '../../commons'; -import {Router} from '@angular/router'; import {RegisterService} from './register.service'; +import {TranslateService} from '@ngx-translate/core'; +import {Observable, of} from 'rxjs'; @Component({ selector: 'app-register', templateUrl: './register.component.html', styleUrls: ['./register.component.scss'] }) + + // 注册模块 export class RegisterComponent extends Commons implements OnInit { + + // 注册表单 registerForm = this.fb.group({ + // 管理员名 managerName: [], + // 密码 password: [], + // 确认密码 confirmPassword: [], + // 手机号 mobile: [], - email: [] + // 邮箱 + email: [], + // 邮箱类型 + emailType: this.fb.control('-1') }); + /** + * 邮箱类型 + */ + emailType$ = this.registerService.getEmailType(); + + // 表单验证 + validForm = { + confirmPassword: { + flag: false + }, + mobile: { + flag: false + } + }; + constructor( private fb: FormBuilder, - private router: Router, - private registerService: RegisterService + private registerService: RegisterService, + private translateService: TranslateService ) { super(); } + /** + * 检查单个表单值 + * @param name formControlName + */ + checkValue(name): boolean { + if (!this.validForm.hasOwnProperty(name)) { + this.validForm[name] = {}; + } + this.validForm[name].flag = this.registerForm.value[name]; + return !this.validForm[name].flag; + } + + /** + * 检查表单所有值 + */ + checkForm(): boolean { + for (const key in this.validForm) { + if (!this.validForm[key].flag) { + return true; + } + } + return this.registerForm.value.emailType === '-1'; + } + + /** + * 检查确认密码 + */ + checkPwd(): Observable { + + if (!this.registerForm.value.confirmPassword) { + this.validForm.confirmPassword.flag = false; + return this.translateService.get('tip.password_null'); + } else if (this.registerForm.value.password !== this.registerForm.value.confirmPassword) { + this.validForm.confirmPassword.flag = false; + return this.translateService.get('tip.password_diff'); + } else { + this.validForm.confirmPassword.flag = true; + return of(''); + } + } + + /** + * 检查手机 + */ + checkMobile(): Observable { + if (!this.registerForm.value.mobile) { + this.validForm.mobile.flag = false; + return this.translateService.get('tip.mobile_null'); + } else if (!/^1[3456789]\d{9}$/.test(this.registerForm.value.mobile)) { + this.validForm.mobile.flag = false; + return this.translateService.get('tip.mobile_error'); + } else { + this.validForm.mobile.flag = true; + return of(''); + } + } + ngOnInit(): void { + } register() { - this.registerService.register(JSON.stringify(this.registerForm.value)); + this.registerService.register(this.registerForm.value); } } + diff --git a/src/app/account/register/register.service.ts b/src/app/account/register/register.service.ts index bae472c..cacafda 100644 --- a/src/app/account/register/register.service.ts +++ b/src/app/account/register/register.service.ts @@ -1,22 +1,66 @@ -import { Injectable } from '@angular/core'; -import {HttpInterface} from '../../interface/Http'; +import {Injectable} from '@angular/core'; +import {JSONRequest} from '../../interface/JSONRequest'; +import {HttpClient} from '@angular/common/http'; +import {catchError, tap} from 'rxjs/operators'; +import {JSONResponse} from '../../interface/JSONResponse'; +import {HttpInterface} from '../../interface/HttpInterface'; +import {Observable} from 'rxjs'; +import {Result} from '../../interface/Result'; +import {Router} from '@angular/router'; +import {MessageService} from '../../message/message.service'; @Injectable({ providedIn: 'root' }) -export class RegisterService implements HttpInterface { +export class RegisterService extends JSONRequest { - constructor() { } + constructor( + private http: HttpClient, + private router: Router, + private messageService: MessageService + ) { + super(); + + this.httpError.result = Result.FAIL; + this.httpError.message = '注册失败'; + } /** * * @param body 注册表单 */ - register(body: string) { + register(body) { + this.http.post>(HttpInterface.register, body, this.httpOptions) + .pipe( + catchError(this.handleError('注册', this.httpError)) + ).subscribe(r => { + if (r.result === Result.OK) { + this.messageService.info('注册成功'); + this.router.navigateByUrl('/login'); + } else { + this.messageService.danger('注册失败'); + } + }); + } + + /** + * 获取邮箱类型 + */ + getEmailType(): Observable { + return this.http.get>(HttpInterface.getEmailType) + .pipe( + catchError(this.handleError('获取邮箱类型')) + ); } - url(): string { - return '/api/manager/register'; + /** + * 发送验证码 + */ + sendEmail(sender): Observable { + return this.http.post>(HttpInterface.sendCode, {email: 'sender'}) + .pipe( + catchError(this.handleError('发送邮件验证码')) + ); } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 88e0fd9..4cff0c0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -7,18 +7,18 @@ import {AppComponent} from './app.component'; // 响应式表单 import {ReactiveFormsModule} from '@angular/forms'; // 国际化支持 -import {HttpClient, HttpClientModule} from '@angular/common/http'; import {TranslateLoader, TranslateModule} from '@ngx-translate/core'; import {TranslateHttpLoader} from '@ngx-translate/http-loader'; // cookie import {CookieService} from 'ngx-cookie-service'; -// 提示框组件 -import {MessageComponent} from './message/message.component' // 异常处理组件 import {ErrorComponent} from './error/error.component'; // 账号管理模块 import {AccountModule} from './account/account/account.module'; +// 论坛模块 import {ForumModule} from './forum/forum/forum.module'; +// Http请求模块 +import {HttpClient, HttpClientModule} from '@angular/common/http'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http); @@ -30,7 +30,6 @@ export function HttpLoaderFactory(http: HttpClient) { @NgModule({ declarations: [ AppComponent, - MessageComponent, ErrorComponent ], imports: [ diff --git a/src/app/commons.ts b/src/app/commons.ts index ef320b2..f663454 100644 --- a/src/app/commons.ts +++ b/src/app/commons.ts @@ -1,24 +1,5 @@ -import {environment} from './../environments/environment'; - // 组件通用配置 export class Commons { // 页面高度=屏幕的高度/2 height = 'height:' + screen.height / 2 + 'px'; - - // post请求 - request(url, b, res) { - const header = new Headers(); - header.append('Content-Type', 'application/json'); - const req = new Request(environment.apiServer + url, - {method: 'POST', body: b, headers: header}); - fetch(req).then(r => { - if (r.status === 200) { - return r.json(); - } else { - throw new Error('666'); - } - }).then(res).catch(err => { - console.error(err); - }); - } } diff --git a/src/app/forum/forum/forum.module.ts b/src/app/forum/forum/forum.module.ts index f19a7f4..bf94313 100644 --- a/src/app/forum/forum/forum.module.ts +++ b/src/app/forum/forum/forum.module.ts @@ -2,6 +2,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; // 论坛组件 import {ForumComponent} from '../forum.component'; +import {TranslateModule} from '@ngx-translate/core'; /** @@ -9,8 +10,12 @@ import {ForumComponent} from '../forum.component'; */ @NgModule({ declarations: [ForumComponent], + exports: [ + ForumComponent + ], imports: [ - CommonModule + CommonModule, + TranslateModule ] }) export class ForumModule { } diff --git a/src/app/interface/Http.ts b/src/app/interface/Http.ts deleted file mode 100644 index 0518c20..0000000 --- a/src/app/interface/Http.ts +++ /dev/null @@ -1,5 +0,0 @@ -// 请求接口 -export interface HttpInterface { - // 接口地址 - url(): string; -} diff --git a/src/app/interface/HttpInterface.ts b/src/app/interface/HttpInterface.ts new file mode 100644 index 0000000..cedfdb4 --- /dev/null +++ b/src/app/interface/HttpInterface.ts @@ -0,0 +1,20 @@ +// 环境变量 +import {environment} from '../../environments/environment'; +// 请求接口 +const HttpInterface = { + // 注册接口 + register: '/api/manager/register', + // 获取邮箱类型接口 + getEmailType: '/api/manager/emailType', + // 登陆接口 + login: '/api/manager/login', + // 发送验证码接口 + sendCode: '/api/manager/sendcode' +}; + +// tslint:disable-next-line:forin +for (const key in HttpInterface) { + HttpInterface[key] = environment.apiServer + HttpInterface[key]; +} +console.debug(HttpInterface); +export {HttpInterface}; diff --git a/src/app/interface/JSONRequest.ts b/src/app/interface/JSONRequest.ts new file mode 100644 index 0000000..da80746 --- /dev/null +++ b/src/app/interface/JSONRequest.ts @@ -0,0 +1,30 @@ +import {HttpInterface} from './HttpInterface'; +import {Observable, of} from 'rxjs'; +import {HttpHeaders} from '@angular/common/http'; +import {JSONResponse} from './JSONResponse'; + +export abstract class JSONRequest { + + protected httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }) + }; + + protected httpError = new JSONResponse(); + + /** + * Handle Http operation that failed. + * Let the app continue. + * @param operation - name of the operation that failed + * @param result - optional value to return as the observable result + */ + protected handleError(operation = 'operation', result?: T) { + return (error: any): Observable => { + + // TODO: send the error to remote logging infrastructure + console.error(error); // log to console instead + + // Let the app keep running by returning an empty result. + return of(result as T); + }; + } +} diff --git a/src/app/interface/JSONResponse.ts b/src/app/interface/JSONResponse.ts new file mode 100644 index 0000000..f8a3534 --- /dev/null +++ b/src/app/interface/JSONResponse.ts @@ -0,0 +1,38 @@ +import {Result} from './Result'; + + +export class JSONResponse { + // 响应结果 + // tslint:disable-next-line:variable-name + private _result: Result; +// 响应详细结果 + // tslint:disable-next-line:variable-name + private _message: string; +// 自定义其他响应信息 + // tslint:disable-next-line:variable-name + private _body: T; + + get result(): Result { + return this._result; + } + + set result(value: Result) { + this._result = value; + } + + get message(): string { + return this._message; + } + + set message(value: string) { + this._message = value; + } + + get body(): T { + return this._body; + } + + set body(value: T) { + this._body = value; + } +} diff --git a/src/app/interface/Result.ts b/src/app/interface/Result.ts new file mode 100644 index 0000000..30f4e6c --- /dev/null +++ b/src/app/interface/Result.ts @@ -0,0 +1,4 @@ +export enum Result { + OK = 'OK', + FAIL = 'FAIL' +} diff --git a/src/assets/i18n/en-US.json b/src/assets/i18n/en-US.json index 406a7d3..bdab3eb 100644 --- a/src/assets/i18n/en-US.json +++ b/src/assets/i18n/en-US.json @@ -10,7 +10,8 @@ "register": { "confirm_pwd": "confrim password", "mobile": "mobile", - "email": "email" + "email": "email", + "emailType": "email type" }, "reset_pwd": { "code": "verification code" @@ -28,8 +29,14 @@ "complaint": "time:{{time}}" }, "tip":{ - "input": "please input ", - "HELLO": "Hello {{value}} welcome to you" + "input": "please input {{value}}", + "HELLO": "Hello {{value}} welcome to you", + "notnull": "The {{value}} cannot be empty", + "password_null": "the password cannot be empty", + "password_diff": "The passwords do not match", + "mobile_null": "The phone number cannot be empty", + "mobile_error": "The phone number is illegal", + "select": "please choose an {{value}}" }, "button": { "login": "login", diff --git a/src/assets/i18n/zh-CN.json b/src/assets/i18n/zh-CN.json index f4afc12..192d479 100644 --- a/src/assets/i18n/zh-CN.json +++ b/src/assets/i18n/zh-CN.json @@ -10,7 +10,8 @@ "register": { "confirm_pwd": "确认密码", "mobile": "手机", - "email": "邮箱" + "email": "邮箱", + "email_type": "邮箱类型" }, "reset_pwd": { "code": "验证码" @@ -28,8 +29,14 @@ "complaint_time": "投诉时间:{{time}}" }, "tip":{ - "input": "请输入", - "HELLO": "欢迎管理员{{value}}登陆" + "input": "请输入{{value}}", + "HELLO": "欢迎管理员{{value}}登陆", + "notnull": "{{value}}不能为空", + "password_null": "确认密码不能为空", + "password_diff": "密码和确认密码不一致", + "mobile_null": "手机号不能为空", + "mobile_error": "手机号不合法", + "select": "请选择{{value}}" }, "button": { "login": "登陆", diff --git a/src/environments/environment.rap2.ts b/src/environments/environment.rap2.ts new file mode 100644 index 0000000..71ef8d1 --- /dev/null +++ b/src/environments/environment.rap2.ts @@ -0,0 +1,21 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false, + // 服务端地址 + apiServer: 'http://rap2.taobao.org:38080/app/mock/245830', + // token key + tokenKey: 'token' + +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI.