diff --git a/App.vue b/App.vue
index 092e580..830976a 100644
--- a/App.vue
+++ b/App.vue
@@ -29,7 +29,7 @@
if (this.envVersion === 'trial') {
return 'XHJ'
}
- return 'XHJ'
+ return 'DEV'
}
},
computed: {
diff --git a/api/system.js b/api/system.js
new file mode 100644
index 0000000..c350145
--- /dev/null
+++ b/api/system.js
@@ -0,0 +1,12 @@
+import request from '../utils/request'
+
+// system 系统模块
+
+// 获取国家列表
+export function getCountryListRequest(data) {
+ return request({
+ url: '/system/listCountry',
+ method: 'POST',
+ data
+ })
+}
diff --git a/api/user.js b/api/user.js
index 2ea0a3e..c7ed31e 100644
--- a/api/user.js
+++ b/api/user.js
@@ -65,6 +65,24 @@ export function loginRequest(data) {
})
}
+// 密码登录
+export function passwordLoginRequest(data) {
+ return request({
+ url: '/user/register',
+ method: 'POST',
+ data
+ })
+}
+
+// 注册
+export function registerRequest(data) {
+ return request({
+ url: '/user/login',
+ method: 'POST',
+ data
+ })
+}
+
// 注册
export function phoneLoginRequest(data) {
return request({
diff --git a/components/verify/utils/ase.js b/components/verify/utils/ase.js
new file mode 100644
index 0000000..aee9d8f
--- /dev/null
+++ b/components/verify/utils/ase.js
@@ -0,0 +1,15 @@
+import CryptoJS from 'crypto-js'
+
+/**
+ * @word 要加密的内容
+ * @keyWord String 服务器随机返回的关键字
+ * */
+export function aesEncrypt(word, keyWord = 'XwKsGlMcdPMEhR1B') {
+ let key = CryptoJS.enc.Utf8.parse(keyWord)
+ let src = CryptoJS.enc.Utf8.parse(word)
+ let encrypted = CryptoJS.AES.encrypt(src, key, {
+ mode: CryptoJS.mode.ECB,
+ padding: CryptoJS.pad.Pkcs7
+ })
+ return encrypted.toString()
+}
diff --git a/components/verify/utils/request.js b/components/verify/utils/request.js
new file mode 100644
index 0000000..c6c6f88
--- /dev/null
+++ b/components/verify/utils/request.js
@@ -0,0 +1,43 @@
+import env from '@/config/env'
+
+export const myRequest = async (option = {}) => {
+ const envConfig = getApp().globalData.getEnvConfig()
+ const baseConfig = env[envConfig]
+
+ console.log('=== 请求入参 ===')
+ console.log('URL:', baseConfig.baseUrl + option.url)
+ console.log('Data:', JSON.stringify(option.data || {}, null, 2))
+ console.log('Method:', option.method || 'GET')
+ console.log('================')
+
+ return new Promise((resolve, reject) => {
+ uni.request({
+ url: baseConfig.baseUrl + option.url,
+ data: option.data || {},
+ method: option.method || 'GET',
+ timeout: 30000,
+ header: {
+ 'content-type': 'application/json',
+ ...option.header
+ },
+ success: result => {
+ console.log('=== 请求出参 ===')
+ console.log('StatusCode:', result.statusCode)
+ console.log('Response:', JSON.stringify(result.data, null, 2))
+ console.log('================')
+
+ if (result.statusCode === 200) {
+ resolve(result)
+ } else {
+ reject(new Error(`HTTP ${result.statusCode}: ${result.errMsg || 'Request failed'}`))
+ }
+ },
+ fail: error => {
+ console.log('=== 请求失败 ===')
+ console.log('Error:', error)
+ console.log('================')
+ reject(new Error(error.errMsg || 'Network request failed'))
+ }
+ })
+ })
+}
diff --git a/components/verify/verify.vue b/components/verify/verify.vue
new file mode 100644
index 0000000..f9d33b4
--- /dev/null
+++ b/components/verify/verify.vue
@@ -0,0 +1,476 @@
+
+
+
+
+ 请完成安全验证
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/verify/verifySlider/verifySlider.vue b/components/verify/verifySlider/verifySlider.vue
new file mode 100644
index 0000000..f1e9332
--- /dev/null
+++ b/components/verify/verifySlider/verifySlider.vue
@@ -0,0 +1,781 @@
+
+
+
+
+
+
+
+
+ {{ tipWords }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/constant/reg.js b/constant/reg.js
new file mode 100644
index 0000000..9b2424c
--- /dev/null
+++ b/constant/reg.js
@@ -0,0 +1,3 @@
+export const PHONE_REG = /^\d{7,12}$/
+export const EMAIL_REG = /^[\w.-]+@([\w-]+\.)+[\w-]{2,4}$/
+export const PASSWORD_REG = /^(?!\d+$)(?![a-z]+$)(?![^0-9a-z]+$).{8,20}$/i
diff --git a/package-lock.json b/package-lock.json
index 3e19e4e..c5dbe72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,6 +5,7 @@
"packages": {
"": {
"dependencies": {
+ "crypto-js": "^4.2.0",
"pinia": "^2.2.0",
"pinia-plugin-unistorage": "^0.1.2",
"uview-plus": "^3.3.12"
@@ -3106,6 +3107,12 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+ "license": "MIT"
+ },
"node_modules/css-functions-list": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
diff --git a/package.json b/package.json
index f7c9d92..e055ba6 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,6 @@
{
"dependencies": {
+ "crypto-js": "^4.2.0",
"pinia": "^2.2.0",
"pinia-plugin-unistorage": "^0.1.2",
"uview-plus": "^3.3.12"
diff --git a/pages.json b/pages.json
index 81ff30f..b06cfb4 100644
--- a/pages.json
+++ b/pages.json
@@ -112,6 +112,36 @@
"style": {
"navigationBarTitleText": "验证邮箱"
}
+ },
+ {
+ "path": "login",
+ "style": {
+ "navigationBarTitleText": "登录"
+ }
+ },
+ {
+ "path": "register",
+ "style": {
+ "navigationBarTitleText": "注册"
+ }
+ },
+ {
+ "path": "forgotPassword",
+ "style": {
+ "navigationBarTitleText": "忘记密码"
+ }
+ },
+ {
+ "path": "countryList",
+ "style": {
+ "navigationBarTitleText": "你所在的国家/地区"
+ }
+ },
+ {
+ "path": "safeVerify",
+ "style": {
+ "navigationBarTitleText": "安全验证"
+ }
}
]
},
@@ -593,22 +623,13 @@
],
"preloadRule": {
"pages/main/home": {
- "packages": [
- "pages/others",
- "pages/addDevice",
- "pages/p2p"
- ]
+ "packages": ["pages/others", "pages/addDevice", "pages/p2p"]
},
"pages/main/lockDetail": {
- "packages": [
- "pages/feature",
- "pages/setting"
- ]
+ "packages": ["pages/feature", "pages/setting"]
},
"pages/main/mine": {
- "packages": [
- "pages/user"
- ]
+ "packages": ["pages/user"]
}
},
"globalStyle": {
diff --git a/pages/main/home.vue b/pages/main/home.vue
index 9fe1cd9..7f5777d 100644
--- a/pages/main/home.vue
+++ b/pages/main/home.vue
@@ -408,6 +408,12 @@
homeLogin() {
const that = this
return new Promise(resolve => {
+ // #ifdef APP-PLUS
+ that.routeJump({
+ name: 'login',
+ type: 'reLaunch'
+ })
+ // #endif
// #ifdef MP-WEIXIN
uni.login({
provider: 'weixin',
diff --git a/pages/user/countryList.vue b/pages/user/countryList.vue
new file mode 100644
index 0000000..b01e087
--- /dev/null
+++ b/pages/user/countryList.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ country.name }}
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/forgotPassword.vue b/pages/user/forgotPassword.vue
new file mode 100644
index 0000000..1e8e1a1
--- /dev/null
+++ b/pages/user/forgotPassword.vue
@@ -0,0 +1,5 @@
+
+ 忘记密码
+
+
+
diff --git a/pages/user/login.vue b/pages/user/login.vue
new file mode 100644
index 0000000..7d1838d
--- /dev/null
+++ b/pages/user/login.vue
@@ -0,0 +1,170 @@
+
+
+
+ 欢迎使用星星锁
+
+ 国家/地区
+ {{ country.name }} +{{ country.code }}
+
+
+
+
+
+
+
+
+
+
+
+ 我已阅读并同意
+ 《用户协议》
+ 《隐私协议》
+
+
+
+ 登录
+
+
+ 忘记密码
+ 注册
+
+
+
+
+
+
diff --git a/pages/user/register.vue b/pages/user/register.vue
new file mode 100644
index 0000000..741e8ee
--- /dev/null
+++ b/pages/user/register.vue
@@ -0,0 +1,317 @@
+
+
+
+
+
+ 国家/地区
+
+ {{ country.name }}
+ +{{ country.code }}
+
+
+
+
+
+
+
+
+ 密码必须是8-20位,至少包括数字/字母/符号中的2种
+
+
+
+
+
+
+
+
+
+ {{ tips }}
+
+
+
+
+
+
+
+
+
+ 我已阅读并同意
+ 《用户协议》
+ 《隐私协议》
+
+
+
+ 注册
+
+
+
+
+
+
diff --git a/pages/user/safeVerify.vue b/pages/user/safeVerify.vue
new file mode 100644
index 0000000..8c95797
--- /dev/null
+++ b/pages/user/safeVerify.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pages/user/userInfo.vue b/pages/user/userInfo.vue
index ac35d08..d69cfe3 100644
--- a/pages/user/userInfo.vue
+++ b/pages/user/userInfo.vue
@@ -246,47 +246,47 @@
diff --git a/stores/basic.js b/stores/basic.js
index 552a78a..300a5a0 100644
--- a/stores/basic.js
+++ b/stores/basic.js
@@ -406,11 +406,36 @@ const pages = [
name: 'videoEdit',
path: '/pages/p2p/videoEdit',
tabBar: false
+ },
+ {
+ name: 'login',
+ path: '/pages/user/login',
+ tabBar: false
+ },
+ {
+ name: 'register',
+ path: '/pages/user/register',
+ tabBar: false
+ },
+ {
+ name: 'forgotPassword',
+ path: '/pages/user/forgotPassword',
+ tabBar: false
+ },
+ {
+ name: 'countryList',
+ path: '/pages/user/countryList',
+ tabBar: false
+ },
+ {
+ name: 'safeVerify',
+ path: '/pages/user/safeVerify',
+ tabBar: false
}
]
export const useBasicStore = defineStore('basic', {
- state () {
+ state() {
return {
// 设备信息
deviceInfo: null,
@@ -424,7 +449,7 @@ export const useBasicStore = defineStore('basic', {
// 路由跳转
/* data 入参 name string页面名称 type string跳转方式 params object传递参数 delta number返回页面数
* 具体入参查看文档 https://www.uviewui.com/js/route.html */
- routeJump (data) {
+ routeJump(data) {
const page = pages.find(page => {
return page.name === data.name
})
@@ -453,10 +478,10 @@ export const useBasicStore = defineStore('basic', {
}
},
// 获取当前网络状态
- getNetworkType () {
+ getNetworkType() {
return new Promise(resolve => {
uni.getNetworkType({
- success (res) {
+ success(res) {
if (res.networkType === 'none') {
uni.showToast({
title: '网络访问失败,请检查网络是否正常',
@@ -467,14 +492,14 @@ export const useBasicStore = defineStore('basic', {
}
resolve(true)
},
- fail () {
+ fail() {
resolve(false)
}
})
})
},
// 获取设备信息
- getDeviceInfo () {
+ getDeviceInfo() {
const that = this
return new Promise(resolve => {
if (that.deviceInfo?.model) {
@@ -482,29 +507,31 @@ export const useBasicStore = defineStore('basic', {
return
}
uni.getSystemInfo({
- success (res) {
+ success(res) {
that.deviceInfo = res
resolve(that.deviceInfo)
},
- fail () {
+ fail() {
resolve({})
}
})
})
},
// 获取胶囊信息
- getButtonInfo () {
+ getButtonInfo() {
return new Promise(resolve => {
+ // #ifdef MP-WEIXIN
if (this.buttonInfo?.top) {
resolve(this.buttonInfo)
return
}
this.buttonInfo = uni.getMenuButtonBoundingClientRect()
+ // #endif
resolve(this.buttonInfo)
})
},
// 计算字符串长度
- calculateStringTotalWidth (str) {
+ calculateStringTotalWidth(str) {
let totalWidth = 0
// 遍历字符串中的每一个字符
for (let i = 0; i < str.length; i++) {
@@ -521,10 +548,10 @@ export const useBasicStore = defineStore('basic', {
return totalWidth
},
// 回退页面并弹出toast提示
- backAndToast (message, delta = 1) {
+ backAndToast(message, delta = 1) {
uni.navigateBack({
delta,
- complete () {
+ complete() {
setTimeout(() => {
uni.showToast({
title: message,
@@ -535,7 +562,7 @@ export const useBasicStore = defineStore('basic', {
})
},
// 分享跳转
- shareJump (data = this.shareConfig) {
+ shareJump(data = this.shareConfig) {
if (data.path) {
const target = data.path.split('/')
if (target.length > 1) {
@@ -563,7 +590,7 @@ export const useBasicStore = defineStore('basic', {
}
this.shareConfig = data
- function getParams (params) {
+ function getParams(params) {
let paramStr = ''
Object.keys(params).forEach(item => {
if (paramStr === '') {
diff --git a/stores/user.js b/stores/user.js
index 8675e85..7fd0131 100644
--- a/stores/user.js
+++ b/stores/user.js
@@ -2,10 +2,17 @@
* @description 用户信息数据持久化
*/
import { defineStore } from 'pinia'
-import { getUserInfoRequest, getWebUrlRequest, loginRequest, phoneLoginRequest } from '@/api/user'
+import {
+ getUserInfoRequest,
+ getWebUrlRequest,
+ loginRequest,
+ phoneLoginRequest,
+ registerRequest
+} from '@/api/user'
import { useLockStore } from '@/stores/lock'
import { setStorage, getStorage } from '@/utils/storage'
import { useNotificationStore } from '@/stores/notification'
+import { useBasicStore } from '@/stores/basic'
export const useUserStore = defineStore('user', {
state() {
@@ -34,6 +41,65 @@ export const useUserStore = defineStore('user', {
}
return code
},
+ async register(params) {
+ const { account, password, receiverType, countryCode, verificationCode } = params
+ const $basic = useBasicStore()
+ const deviceInfo = await $basic.getDeviceInfo()
+ const info = {
+ deviceBrand: deviceInfo.deviceBrand,
+ deviceId: deviceInfo.deviceId,
+ deviceModel: deviceInfo.deviceModel,
+ model: deviceInfo.model,
+ system: deviceInfo.system
+ }
+ const { code, data, message } = await registerRequest({
+ receiverType,
+ countryCode,
+ account,
+ password,
+ verificationCode,
+ platId: 2,
+ deviceInfo: info
+ })
+ if (code === 0) {
+ setStorage('token', data.accessToken)
+ return true
+ }
+ uni.showToast({
+ title: message,
+ icon: 'none'
+ })
+ return false
+ },
+ async passwordLogin(params) {
+ const { username, password, countryCode } = params
+ const $basic = useBasicStore()
+ const deviceInfo = await $basic.getDeviceInfo()
+ const info = {
+ deviceBrand: deviceInfo.deviceBrand,
+ deviceId: deviceInfo.deviceId,
+ deviceModel: deviceInfo.deviceModel,
+ model: deviceInfo.model,
+ system: deviceInfo.system
+ }
+ const { code, data, message } = await registerRequest({
+ username,
+ password,
+ countryCode,
+ loginType: 1,
+ platId: 2,
+ deviceInfo: info
+ })
+ if (code === 0) {
+ setStorage('token', data.accessToken)
+ return true
+ }
+ uni.showToast({
+ title: message,
+ icon: 'none'
+ })
+ return false
+ },
async phoneLogin(params) {
const { iv, encryptedData, code: js_code } = params
const openid = await getStorage('openid')