shishuangxi

提交登录模块

Showing 45 changed files with 1029 additions and 3 deletions
... ... @@ -54,7 +54,7 @@ export class HttpUrlUtils {
*/
static readonly E_NEWSPAPER_LIST_PATH: string = "/api/rmrb-bff-display-zh/display/zh/c/paperApi/paperList";
private static hostUrl: string = HttpUrlUtils.HOST_PRODUCT;
private static hostUrl: string = HttpUrlUtils.HOST_UAT;
static getCommonHeaders(): HashMap<string, string> {
let headers: HashMap<string, string> = new HashMap<string, string>()
... ... @@ -67,7 +67,7 @@ export class HttpUrlUtils {
headers.set('timestamp', HttpUrlUtils.getTimestamp())
headers.set('RMRB-X-TOKEN', HttpUrlUtils.getXToken())
headers.set('device_id', HttpUrlUtils.getDeviceId())
headers.set('cookie', 'RMRB-X-TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc')
// headers.set('cookie', 'RMRB-X-TOKEN=eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcwMzY0OTYwNiwidXNlcklkIjo0NTk3NzYyOTc0NzQ5NDksInVzZXJWZXJzaW9uIjoiNDU5Nzc2Mjk3NDc0OTQ5XzIiLCJ1c2VyTmFtZSI6IkJ1bGlraWtpMTgxIiwidXNlclR5cGUiOjIsImNyZWF0b3JJZCI6NDI2NTM5MH0.jhQ9kylcm3FxWf0-lBMZuLkdtIQ6XpFnAi0AFZJNwfc')
headers.set('build_version', HttpUrlUtils.getVersion())
headers.set('adcode', HttpUrlUtils.getAdCode())
headers.set('os_version', HttpUrlUtils.getOsVersion())
... ... @@ -214,4 +214,19 @@ export class HttpUrlUtils {
private static getUserType() {
return '2';
}
static getVerifyCodeUrl() {
let url = HttpUrlUtils.hostUrl + "/api/rmrb-user-center/auth/zh/c/sendVerifyCode";
return url;
}
static getAppLoginUrl() :string{
let url = HttpUrlUtils.getHost() + "/api/rmrb-user-center/auth/zh/c/appLogin";
return url;
}
static getCheckVerifyCodeUrl() {
let url = HttpUrlUtils.hostUrl + "/api/rmrb-user-center/auth/zh/c/checkVerifyCode";
return url;
}
}
\ No newline at end of file
... ...
... ... @@ -32,4 +32,8 @@ export class WDRouterPage {
static detailPlayVodPage = new WDRouterPage("wdDetailPlayVod", "ets/pages/DetailPlayVodPage");
// 直播详情页
static detailPlayLivePage = new WDRouterPage("wdDetailPlayLive", "ets/pages/DetailPlayLivePage");
static loginPage = new WDRouterPage("wdLogin", "ets/pages/login/LoginPage");
static forgetPasswordPage = new WDRouterPage("wdLogin", "ets/pages/login/ForgetPasswordPage");
}
... ...
... ... @@ -14,7 +14,7 @@ export class WDRouterRule {
WDRouterRule.jumpWithPage(page, action)
}
private static jumpWithPage(page?: WDRouterPage, params?: object) {
static jumpWithPage(page?: WDRouterPage, params?: object) {
if (page) {
if (params) {
// router.pushUrl({ url: 'pages/routerpage2', , params: params })
... ...
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test
\ No newline at end of file
... ...
export { add } from "./src/main/ets/utils/Calc"
\ No newline at end of file
... ...
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
}
]
}
\ No newline at end of file
... ...
import { hspTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hspTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}
... ...
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope
\ No newline at end of file
... ...
{
"name": "wdlogin",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "Index.ets",
"author": "",
"license": "Apache-2.0",
"dependencies": {
"wdConstant": "file:../../commons/wdConstant",
"wdKit": "file:../../commons/wdKit",
"wdWebComponent": "file:../../commons/wdWebComponent",
"wdBean": "file:../../features/wdBean",
"wdRouter": "file:../../commons/wdRouter",
"wdNetwork": "file:../../commons/wdNetwork"
}
}
\ No newline at end of file
... ...
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
\ No newline at end of file
... ...
export interface CheckVerifyBean{
temToken: string
jwtToken: string
}
\ No newline at end of file
... ...
@CustomDialog
export struct CustomProtocolDialog {
cancel: () => void=()=>{}
confirm: () => void=()=>{}
controller: CustomDialogController
build() {
Column() {
Text("温馨提示")
.fontColor("#222222")
.fontSize(23)
.width("100%")
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.margin({ top: 26 })
Text() {
Span("为保障您的合法权益,请阅读并同意").fontSize(18).fontColor("#666666")
Span("《用户协议》").fontSize(18).fontColor("#ED2800")
Span("及").fontSize(18).fontColor("#666666")
Span("《隐私政策》").fontSize(18).fontColor("#ED2800")
Span("后进行登录").fontSize(18).fontColor("#666666")
}.margin({ top: 15, left: 20, right: 20 })
Divider().color("#999999").width("100%").margin({ top: 18 }).height('0.5vp')
Row() {
Text('放弃登录')
.fontSize(20)
.fontColor("#999999")
.layoutWeight(1)
.fontWeight(FontWeight.Medium)
.textAlign(TextAlign.Center)
.onClick(() => {
this.controller.close()
if (this.cancel) {
this.cancel()
}
}).height('100%')
// Divider().color("#999999").height('100%').width('0.5vp')
Text('同意并登录')
.fontSize(20)
.fontColor("#ED2800")
.layoutWeight(1)
.fontWeight(FontWeight.Medium)
.textAlign(TextAlign.Center)
.border({
width:{left:1},
color:"#999999",
style:{left:BorderStyle.Solid}
})
.onClick(() => {
this.controller.close()
if (this.confirm) {
this.confirm()
}
}).height('100%')
}.layoutWeight(1).justifyContent(FlexAlign.Center)
}.height(206).backgroundColor(Color.White).borderRadius(8)
}
}
\ No newline at end of file
... ...
import { Logger } from 'wdKit/src/main/ets/utils/Logger'
import { LoginInputComponent } from './LoginInputComponent'
import { LoginViewModel } from './LoginViewModel'
import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
const TAG = 'ForgetPasswordPage'
/**
* 找回密码页面
* */
@Entry
@Component
struct ForgetPasswordPage {
@State phoneContent: string = ''
@State codeContent: string = ''
@State isSubmit: boolean = false //是否可以提交 默认不可以
loginViewModel: LoginViewModel = new LoginViewModel()
@State @Watch('onCodeSend') isCodeSend: boolean = false //验证码点击发送事件
onCodeSend() {
if (this.isCodeSend) {
this.sendVerifyCode()
}
}
build() {
Column() {
Image($r('app.media.login_back_icon')).width(24).height(24).margin({ left: 15, top: 10 }).onClick(() => {
router.back()
})
Text('找回密码').fontSize(22).fontColor('#333333').fontWeight(FontWeight.Bold).margin({ left: 25, top: 112 })
LoginInputComponent({
phoneContent: $phoneContent,
codeContent: $codeContent,
isSubmit: $isSubmit,
isCodeSend: $isCodeSend
})
Row() {
Button("确认", { type: ButtonType.Normal })
.layoutWeight(1)
.borderRadius(4)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ top: 26 })
.height(44)
.backgroundColor("#ED2800")
.opacity(this.isSubmit ? 1 : 0.6)
.onClick(() => {
this.checkVerifyCode()
})
}.padding({ left: 25, right: 25 }).width('100%')
}.width('100%').height('100%').alignItems(HorizontalAlign.Start)
}
aboutToAppear() {
if (this.isCodeSend) {
this.sendVerifyCode()
}
}
//发送验证码
sendVerifyCode() {
if (this.isEmpty(this.phoneContent)) {
return
}
this.loginViewModel.sendVerifyCode(this.phoneContent).then((verifyCode) => {
promptAction.showToast({ message: "验证码已发送成功" })
Logger.debug(TAG, "sendVerifyCode: " + verifyCode)
})
}
//校验验证码
checkVerifyCode() {
if (!this.isSubmit) {
return
}
if (this.isEmpty(this.phoneContent)) {
return
}
if (this.isEmpty(this.codeContent)) {
return
}
this.loginViewModel.checkVerifyCode(this.phoneContent, this.codeContent).then(() => {
//todo 跳转密码设置页面
promptAction.showToast({message:"校验成功,准备跳转设置页面"})
Logger.debug(TAG,"校验成功")
}).catch((error:string)=>{
promptAction.showToast({message:error})
Logger.debug(TAG,"校验失败")
})
}
isEmpty(obj: undefined|null|string): boolean {
return (obj == undefined || obj == null || obj == '');
}
}
\ No newline at end of file
... ...
export interface LoginBean {
// {"code":"0","data":{"firstMark":1,"id":569350079889669,"jwtToken":"eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcxMDY0NzE0MiwidXNlcklkIjo1NjkzNTAwNzk4ODk2NjksInVzZXJWZXJzaW9uIjoiNTY5MzUwMDc5ODg5NjY5XzAiLCJ1c2VyTmFtZSI6IiVFNCVCQSVCQSVFNiVCMCU5MSVFNiU5NyVBNSVFNiU4QSVBNSVFNyVCRCU5MSVFNSU4RiU4QjJrRDJ4VyIsInVzZXJUeXBlIjoxLCJjcmVhdG9ySWQiOm51bGx9.1M0E_6V60opL7AxamGzINpieTHP11fRbiXKDPc-ywWg","longTimeNoLoginMark":0,"refreshToken":"83fe2f1a-77af-4f73-8490-1cebed037f73","status":1,"userName":"人民日报网友2kD2xW","userType":1},"message":"Success","success":true,"timestamp":1710467142214}
firstMark: number
id: number
jwtToken: string
longTimeNoLoginMark: number
refreshToken: string
status: number
userName: string
userType: number
temToken: string
}
\ No newline at end of file
... ...
import { Logger } from 'wdKit'
@Component
export struct LoginInputComponent {
@State timeCount: number = 60
@Link phoneContent: string
@Link codeContent: string
@State codeBtnState: boolean = false //发送验证码控件是否可以 默认不可用
@Link isCodeSend: boolean //验证码控件是否点击 默认没有 发送接口
@Link isSubmit: boolean //是否可以提交
build() {
Column() {
this.addCodeLayout()
}.width('100%').padding({ left: 25, right: 25 })
}
@Builder
addCodeLayout() {
TextInput({ placeholder: "请输入手机号" })
.fontSize(16)
.height(48)
.margin({ top: 36 })
.backgroundColor("#F5F5F5")
.borderRadius(4)
.type(InputType.PhoneNumber)
.onChange((content) => {
this.phoneContent = content
this.isSubmit = (this.phoneContent.length >= 11 && this.codeContent.length >= 6)
if (content.length >= 11) {
this.codeBtnState = true
} else {
this.codeBtnState = false
}
})
Row() {
TextInput({ placeholder: "验证码" })
.layoutWeight(1)
.fontSize(16)
.height(48)
.type(InputType.Number)
.fontColor("#222222")
.backgroundColor("#00000000")
.borderRadius({ topLeft: 4, bottomLeft: 4 })
.backgroundImage($r('app.media.login_code_bg_one'), ImageRepeat.NoRepeat)
.backgroundImageSize(ImageSize.Contain)
.onChange((value) => {
this.codeContent = value
this.isSubmit = (this.phoneContent.length >= 11 && this.codeContent.length >= 6)
})
Text(this.isCodeSend ? this.timeCount + "s" : "发送验证码")
.backgroundImage($r('app.media.login_code_bg'), ImageRepeat.NoRepeat)
.backgroundImageSize(ImageSize.Cover)
.fontColor('#ED2800')
.width(110)
.fontSize(14)
.fontWeight(this.codeBtnState ? FontWeight.Bold : FontWeight.Normal)
.height(48)
.enabled(this.codeBtnState)// .align(Alignment.End)
.textAlign(TextAlign.Center)
.onClick(() => {
if (this.phoneContent.length < 11) {
return
}
this.isCodeSend = true
let time = setInterval(() => {
Logger.debug("倒计时:" + this.timeCount)
this.timeCount--
if (this.timeCount < 1) {
this.isCodeSend = false
this.timeCount = 60
clearInterval(time)
}
}, 1000)
})
}.margin({ top: 15 }).height(61).alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Start)
}
}
\ No newline at end of file
... ...
import HashMap from '@ohos.util.HashMap';
import { HttpUrlUtils, ResponseDTO } from 'wdNetwork';
import { Logger } from 'wdKit';
import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
import { LoginBean } from './LoginBean';
import { CheckVerifyBean } from './CheckVerifyBean';
const TAG = 'LoginModel'
export class LoginModel {
//获取验证码
sendVerifyCode(number: string) {
let bean: Record<string, string> = {};
bean['phoneNum'] = number
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<string>((success, fail) => {
HttpRequest.post<ResponseDTO<string>>(HttpUrlUtils.getVerifyCodeUrl(), bean, headers).then((data: ResponseDTO<string>) => {
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
success(data.data)
}, (error: Error) => {
fail(error.message)
Logger.debug("LoginViewModel:error ", error.toString())
})
})
}
//{"phone":"13625644528","loginType":2,"deviceId":"60da5af6-9c59-3566-8622-8c6c00710994","verificationCode":"644528"}
appLogin(phone: string, loginType: number, verificationCode: string) {
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
let bean: Record<string, Object> = {};
bean['phone'] = phone
bean['loginType'] = loginType
bean['deviceId'] = '60da5af6-9c59-3566-8622-8c6c00710994'
bean['verificationCode'] = verificationCode
return new Promise<LoginBean>((success, fail) => {
HttpRequest.post<ResponseDTO<LoginBean>>(HttpUrlUtils.getAppLoginUrl(), bean, headers).then((data: ResponseDTO<LoginBean>) => {
Logger.debug("LoginViewModel:success2 ", data.message)
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
success(data.data)
}, (error: Error) => {
fail(error.message)
Logger.debug("LoginViewModel:error2 ", error.toString())
})
})
}
// {"password":"523acd319228efde34e8a30268ee8ca5e4fc421d72affa531676e1765940d22c","phone":"13625644528","loginType":0,"oldPassword":"BA5FD74F827AF9B271FE17CADC489C36","deviceId":"60da5af6-9c59-3566-8622-8c6c00710994"}
appLoginByPassword(phone: string, loginType: number, password: string, oldPassword: string) {
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
let bean: Record<string, string | number> = {};
bean['phone'] = phone
bean['loginType'] = loginType
bean['deviceId'] = '60da5af6-9c59-3566-8622-8c6c00710994'
bean['password'] = password
bean['oldPassword'] = oldPassword
return new Promise<LoginBean>((success, fail) => {
HttpRequest.post<ResponseDTO<LoginBean>>(HttpUrlUtils.getAppLoginUrl(), bean, headers).then((data: ResponseDTO<LoginBean>) => {
Logger.debug("LoginViewModel:success2 ", data.message)
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
success(data.data)
}, (error: Error) => {
Logger.debug("LoginViewModel:error2 ", error.toString())
fail(error.message)
})
})
}
//忘记密码 校验验证码 {"verifyCode":"644528","phone":"13625644528"} 去除头部cookie 可以正常访问
checkVerifyCode(phone: string, verifyCode: string) {
let bean: Record<string, Object> = {};
bean['verifyCode'] = verifyCode
bean['phone'] = phone
let headers: HashMap<string, string> = HttpUrlUtils.getCommonHeaders();
return new Promise<CheckVerifyBean>((success, fail) => {
HttpRequest.post<ResponseDTO<CheckVerifyBean>>(HttpUrlUtils.getCheckVerifyCodeUrl(), bean, headers).then((data: ResponseDTO<CheckVerifyBean>) => {
Logger.debug("LoginViewModel:success2 ", data.message)
if (!data || !data.data) {
fail("数据为空")
return
}
if (data.code != 0) {
fail(data.message)
return
}
success(data.data)
}, (error: Error) => {
Logger.debug("LoginViewModel:error2 ", error.toString())
fail(error.message)
})
})
}
}
... ...
import { Logger } from 'wdKit/src/main/ets/utils/Logger'
import { CustomProtocolDialog } from './CustomProtocolDialog'
import router from '@ohos.router'
import { LoginViewModel } from './LoginViewModel'
import { LoginInputComponent } from './LoginInputComponent'
import promptAction from '@ohos.promptAction'
import { SPHelper } from 'wdKit'
import { WDRouterPage } from 'wdRouter/src/main/ets/router/WDRouterPage';
import { WDRouterRule } from 'wdRouter/src/main/ets/router/WDRouterRule';
@Extend(Row)
function otherStyle() {
.backgroundImageSize(ImageSize.Cover)
.layoutWeight(1)
.height("100%")
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Center)
}
function isEmpty(obj: undefined | string | null): boolean {
return (obj == undefined || obj == null || obj == '');
}
const TAG = "LoginPage"
@Preview
@Entry
@Component
struct LoginPage {
@State codeBtnState: boolean = false
@State timeCount: number = 60
phoneController: TextInputController = new TextInputController()
codeSendText = ""
@State @Watch('onCodeSend') isCodeSend: boolean = false //验证码是否发送
@State phoneContent: string = "" //手机号
@State codeContent: string = "" //验证码
@State protocolState: boolean = false //协议勾选状态
accountContent = '' //账号
passwordContent = ''
@State isSubmit: boolean = false
@State checkCodePage: boolean = true //判断是否是验证码页面 默认验证码登录
@State passwordSwitch: boolean = true //密码显示
// @State isPasswordSubmit: boolean = false //账户密码状态 是否出发登录
dialogController: CustomDialogController = new CustomDialogController({
builder: CustomProtocolDialog({
cancel: () => {
},
confirm: () => {
this.requestLogin()
}
}),
// alignment:DialogAlignment.Center
})
loginViewModel = new LoginViewModel()
onCodeSend() {
Logger.debug(TAG, "isCodeSend:" + this.isCodeSend + "")
if (this.isCodeSend) {
this.sendVerifyCode()
}
}
aboutToAppear() {
Logger.debug(TAG, "aboutToAppear:" + this.isCodeSend + "")
}
onPageShow() {
Logger.debug(TAG, "onPageShow:" + this.isCodeSend + "")
}
build() {
RelativeContainer() {
//注册内容
Column() {
Image($r("app.media.login_logo"))
.width(120)
.height(66)
.margin({ top: 78 })
.align(Alignment.Center)
if (this.checkCodePage) {
LoginInputComponent({
phoneContent: $phoneContent,
codeContent: $codeContent,
isSubmit: $isSubmit,
isCodeSend: $isCodeSend
})
} else {
this.addPassword()
}
Row() {
// Checkbox().selectedColor("#ED2800").onChange((value) => {
// this.protocolState = value
// })
Image(this.protocolState ? $r('app.media.login_checkbox_select') : $r('app.media.login_checkbox_unselected'))
.width(15)
.height(15)
.onClick(() => {
this.protocolState = !this.protocolState
})
Text() {
Span("我已阅读并同意").fontColor("#999999").fontSize(12)
Span("《用户协议》").fontColor("#ED2800").fontSize(12).onClick(() => {
//todo 协议
})
Span("及").fontColor("#999999").fontSize(12)
Span("《隐私政策》").fontColor("#ED2800").fontSize(12).onClick(() => {
//todo 协议
})
}
}.margin({ top: 28 }).alignItems(VerticalAlign.Center)
Row() {
Button("登录", { type: ButtonType.Normal })
.borderRadius(4)
.fontSize(20)
.fontWeight(FontWeight.Medium)
.margin({ top: 20 })
.height(44)
.opacity(this.isSubmit ? 1 : 0.6)
.enabled(this.isSubmit ? true : false)
.width("100%")
.backgroundColor("#ED2800")
.onClick(() => {
//todo 登录
this.loginSubmit()
})
}.padding({ left: 25, right: 25 }).width('100%')
if (!this.checkCodePage) {
Text('忘记密码').fontColor('#666666').fontSize(14).margin({ top: 16 })
.onClick(() => {
// router.pushUrl({ url: 'pages/login/ForgetPasswordPage' })
WDRouterRule.jumpWithPage(WDRouterPage.forgetPasswordPage)
})
}
}.width("100%")
.alignRules({
top: { anchor: "__container__", align: VerticalAlign.Top },
}).id("register")
//其他登录方式
Column() {
this.addOtherLogin()
}.width('100%')
.alignRules({
bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
}).id("other")
//关闭按钮
Image($r('app.media.login_closed'))
.width(24)
.height(24)
.margin({ top: 10, right: 15 })
.alignRules({
top: { anchor: "__container__", align: VerticalAlign.Top },
right: { anchor: "__container__", align: HorizontalAlign.End }
})
.onClick(() => {
router.back()
})
.id('id_close')
}.width('100%').height('100%')
}
@Builder
addPassword() {
Column() {
TextInput({ placeholder: "请输入账号", controller: this.phoneController })
.fontSize(16)
.height(48)
.backgroundColor("#F5F5F5")
.borderRadius(4)
.type(InputType.PhoneNumber)
.onChange((content) => {
this.accountContent = content
this.isSubmit = (this.accountContent.length >= 11 && this.passwordContent.length >= 6)
})
RelativeContainer() {
if (this.passwordSwitch) {
this.addPasswordInputLayout()
} else {
this.addPasswordInputLayout()
}
Image(this.passwordSwitch ? $r('app.media.login_password_off') : $r('app.media.login_password_on'))
.onClick(() => {
this.passwordSwitch = !this.passwordSwitch
})
.width(24)
.height(24)
.alignRules({
right: { anchor: "__container__", align: HorizontalAlign.End },
center: { anchor: '__container__', align: VerticalAlign.Center }
})
.margin({ right: 12 })
.id("password_icon")
}.margin({ top: 12 })
.height(61)
.width('100%')
}.padding({ left: 32, right: 32 }).width('100%').margin({ top: 46 })
}
@Builder
addPasswordInputLayout() {
TextInput({ placeholder: "请输入密码", text: this.passwordContent })
.layoutWeight(1)
.fontSize(16)
.height(48)
.fontColor("#222222")
.backgroundColor("#F5F5F5")
.type(this.passwordSwitch ? InputType.Password : InputType.Normal)
.showPasswordIcon(false)
.borderRadius({ topLeft: 4, bottomLeft: 4 })
.alignRules({
// top:{anchor:"__container__",align:VerticalAlign.Top} ,
left: { anchor: "__container__", align: HorizontalAlign.Start },
})
.onChange((value) => {
// Logger.debug(TAG, "onChange" + value + "/" + this.passwordContent)
this.passwordContent = value
this.isSubmit = (this.accountContent.length >= 11 && this.passwordContent.length >= 6)
})
.id("password")
}
@Builder
addOtherLogin() {
Column() {
Row() {
Divider().layoutWeight(1).margin({ left: 25 })
Text('其他登录方式').margin({ left: 16, right: 16 }).fontSize(14).fontColor("#666666")
Divider().layoutWeight(1).margin({ right: 25 })
}.width('100%')
Row() {
Row() {
Image($r('app.media.login_wx'))
.width(20).height(20)
}.backgroundImage($r('app.media.login_other_left'), ImageRepeat.NoRepeat)
.otherStyle()
Row() {
Image($r('app.media.login_qq')).size({ width: 20, height: 20 })
}.backgroundImage($r('app.media.login_other_middle'), ImageRepeat.NoRepeat)
.otherStyle()
Row() {
Image($r('app.media.login_wb')).size({ width: 20, height: 20 })
}.backgroundImage($r('app.media.login_other_middle'), ImageRepeat.NoRepeat)
.otherStyle()
Row() {
Image(this.checkCodePage ? $r('app.media.login_qt') : $r('app.media.login_other_password'))
.size({ width: 20, height: 20 })
}.backgroundImage($r('app.media.login_other_right'), ImageRepeat.NoRepeat)
.otherStyle().onClick(() => {
this.checkCodePage = !this.checkCodePage;
this.passwordContent = ''
this.passwordSwitch = true
this.isSubmit = false
})
}.height(36)
.width('100%')
.padding({ left: 25, right: 25 })
// .justifyContent(FlexAlign.SpaceEvenly)
.margin({ top: 24 })
}.width('100%').margin({ bottom: 40 })
}
//发送验证码
sendVerifyCode() {
this.loginViewModel.sendVerifyCode(this.phoneContent).then((verifyCode) => {
promptAction.showToast({ message: "验证码已发送成功" })
Logger.debug(TAG, "sendVerifyCode: " + verifyCode)
}).catch((message:string)=>{
Logger.debug(TAG, "sendVerifyCode: " + message)
})
}
requestLogin() {
Logger.debug('LoginViewModel', "requestLogin")
if (this.checkCodePage) {
this.loginViewModel.appLogin(this.phoneContent, 2, this.codeContent).then((data) => {
Logger.debug(TAG, "requestLogin: " + data.jwtToken)
let dd = SPHelper.default.get('userName', 'dd').then((value) => {
Logger.debug(TAG, 'SP:' + value)
})
router.back()
})
} else {
this.loginViewModel.appLoginByPassword(this.accountContent, 0, this.passwordContent, "").then((data) => {
Logger.debug(TAG, "requestLogin: " + data.jwtToken)
let dd = SPHelper.default.get('userName', 'dd').then((value) => {
Logger.debug(TAG, 'SP:' + value)
})
promptAction.showToast({ message: '登录成功' })
router.back()
}).catch((value: string) => {
promptAction.showToast({ message: value })
})
}
}
//登录
loginSubmit() {
Logger.debug(TAG, "loginSubmit " + this.checkCodePage)
//todo 判断是验证码登录还是密码登录
if (this.checkCodePage) {
if (isEmpty(this.phoneContent)) {
Logger.debug(TAG, "手机号为空")
return
}
if (isEmpty(this.codeContent)) {
Logger.debug(TAG, "验证码为空")
return
}
} else {
if (isEmpty(this.accountContent)) {
Logger.debug(TAG, "账号为空")
return
}
if (isEmpty(this.passwordContent)) {
Logger.debug(TAG, "密码为空")
return
}
}
if (this.protocolState) {
this.requestLogin()
} else {
this.dialogController.open()
}
}
}
\ No newline at end of file
... ...
import { Logger } from 'wdKit/src/main/ets/utils/Logger'
import { LoginModel } from './LoginModel'
import { LoginBean } from './LoginBean'
import { SPHelper } from 'wdKit'
import { CheckVerifyBean } from './CheckVerifyBean'
import cryptoFramework from '@ohos.security.cryptoFramework'
import buffer from '@ohos.buffer'
const TAG = "LoginViewModel"
export class LoginViewModel {
loginModel: LoginModel
constructor() {
this.loginModel = new LoginModel()
}
//发送验证码
sendVerifyCode(number: string) {
return new Promise<string>((success, fail) => {
this.loginModel.sendVerifyCode(number).then((data) => {
success(data)
}).catch((message: string) => {
fail(message)
})
})
}
appLogin(phone: string, loginType: number, verificationCode: string) {
return new Promise<LoginBean>((success, fail) => {
this.loginModel.appLogin(phone, loginType, verificationCode).then((data: LoginBean) => {
//todo 保存登录数据
SPHelper.default.save("firstMark", data.firstMark)
SPHelper.default.save("id", data.id)
SPHelper.default.save("jwtToken", data.jwtToken)
SPHelper.default.save("longTimeNoLoginMark", data.longTimeNoLoginMark)
SPHelper.default.save("refreshToken", data.refreshToken)
SPHelper.default.save("status", data.status)
SPHelper.default.save("userType", data.userType)
SPHelper.default.save("userName", data.userName)
success(data)
}).catch(() => {
fail()
})
})
}
async appLoginByPassword(phone: string, loginType: number, password: string, oldPassword: string) {
return new Promise<LoginBean>(async (success, fail) => {
let passwordNew = await this.doMd(password)
Logger.debug(TAG, "PASSWORD:" + passwordNew)
this.loginModel.appLoginByPassword(phone, loginType, passwordNew, oldPassword).then((data: LoginBean) => {
//todo 保存登录数据
SPHelper.default.save("userName", data.userName)
success(data)
}).catch((value: string) => {
fail(value)
})
})
}
//{"code":"0","data":{"tempToken":"eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcxMDQ2ODE5NCwidXNlcklkIjpudWxsLCJ1c2VyVmVyc2lvbiI6Im51bGxfbnVsbCIsInVzZXJOYW1lIjpudWxsLCJ1c2VyVHlwZSI6bnVsbCwiY3JlYXRvcklkIjpudWxsLCJ1c2VySWRaaCI6bnVsbH0.R5gv44Gyni3QTxtWvSxYn0eMuUD5_bI1hh9TaThq25g","jwtToken":"eyJhbGciOiJIUzI1NiIsImtpZCI6ImQ4WkI2QkhxSEZrdjJ2U25BNlRwZEdKRjBHcjItVzBvS2FaYzdLOUUycmcifQ.eyJpc3MiOiJwZW9wbGVzLWRhaWx5LWZvdXJhIiwic3ViIjoicGVvcGxlcy1kYWlseS1mb3VyYSIsImV4cCI6MTcxMDY0NzU5NCwidXNlcklkIjo1NjkzNTAwNzk4ODk2NjksInVzZXJWZXJzaW9uIjoiNTY5MzUwMDc5ODg5NjY5XzAiLCJ1c2VyTmFtZSI6IiVFNCVCQSVCQSVFNiVCMCU5MSVFNiU5NyVBNSVFNiU4QSVBNSVFNyVCRCU5MSVFNSU4RiU4QjJrRDJ4VyIsInVzZXJUeXBlIjoxLCJjcmVhdG9ySWQiOm51bGwsInVzZXJJZFpoIjpudWxsfQ.Ai19vg8-rhJNXt2nwFTfir7s01eLfTtOCKcptIpeyG0"},"message":"Success","success":true,"timestamp":1710467595186}
checkVerifyCode(phone: string, verifyCode: string) {
return new Promise<CheckVerifyBean>((success, reject) => {
this.loginModel.checkVerifyCode(phone, verifyCode).then((data: CheckVerifyBean) => {
//todo 保存数据
SPHelper.default.save("tempToken", data.temToken)
SPHelper.default.save("jwtToken", data.jwtToken)
success(data)
}, (value: string) => {
reject(value)
})
})
}
async doMd(content: string): Promise<string> {
let mdAlgName = 'SHA256'; // 摘要算法名
let message = content; // 待摘要的数据
let md = cryptoFramework.createMd(mdAlgName);
// 数据量较少时,可以只做一次update,将数据全部传入,接口未对入参长度做限制
await md.update({ data: new Uint8Array(buffer.from(message, 'utf-8').buffer) });
let mdResult = await md.digest();
console.info('Md result:' + mdResult.data);
return this.byte2Hex(mdResult.data)
}
byte2Hex(data: Uint8Array): string {
let bufferStr = ''
for (let i = 0; i < data.length; i++) {
let temp = data[i].toString(16)
if (temp.length == 1) {
temp += "0"
}
bufferStr += temp
}
console.info('Md result2:' + bufferStr);
return bufferStr;
}
}
\ No newline at end of file
... ...
export function add(a:number, b:number) {
return a + b;
}
\ No newline at end of file
... ...
{
"module": {
"name": "wdLogin",
"type": "shared",
"description": "$string:shared_desc",
"deviceTypes": [
"phone",
"tablet",
"2in1"
],
"deliveryWithInstall": true,
"pages": "$profile:main_pages"
}
}
\ No newline at end of file
... ...
{
"color": [
{
"name": "white",
"value": "#FFFFFF"
}
]
}
\ No newline at end of file
... ...
{
"string": [
{
"name": "shared_desc",
"value": "description"
}
]
}
\ No newline at end of file
... ...
{
"src": [
"pages/Index",
"pages/login/LoginPage",
"pages/login/ForgetPasswordPage"
]
}
... ...
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}
\ No newline at end of file
... ...
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest',() => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}
\ No newline at end of file
... ...