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/sdk.js b/api/sdk.js
index c4dc3f4..210c5a4 100644
--- a/api/sdk.js
+++ b/api/sdk.js
@@ -28,3 +28,21 @@ export function deleteVideo(data) {
data
})
}
+
+// 获取套餐地址
+export function getPackageUrl(data) {
+ return request({
+ url: '/v2/service/getPackageUrl',
+ method: 'POST',
+ data
+ })
+}
+
+// 上报增值服务购买请求
+export function reportBuyRequest(data) {
+ return request({
+ url: '/service/reportBuyRequest',
+ method: 'POST',
+ data
+ })
+}
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..c927885 100644
--- a/api/user.js
+++ b/api/user.js
@@ -65,6 +65,33 @@ export function loginRequest(data) {
})
}
+// 密码登录
+export function passwordLoginRequest(data) {
+ return request({
+ url: '/user/login',
+ method: 'POST',
+ data
+ })
+}
+
+// 注册
+export function registerRequest(data) {
+ return request({
+ url: '/user/register',
+ method: 'POST',
+ data
+ })
+}
+
+// 重置密码
+export function resetPasswordRequest(data) {
+ return request({
+ url: '/user/resetPassword',
+ 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..3752ffb
--- /dev/null
+++ b/components/verify/verifySlider/verifySlider.vue
@@ -0,0 +1,784 @@
+
+
+
+
+
+
+
+
+ {{ tipWords }}
+
+
+
+
+
+
+ {{ text }}
+
+ {{ finishText }}
+
+
+
+
+
+
+
+
+
+
+
+
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/p2p/authorizeWechat.vue b/pages/p2p/authorizeWechat.vue
index 6d3c9bd..a87155f 100644
--- a/pages/p2p/authorizeWechat.vue
+++ b/pages/p2p/authorizeWechat.vue
@@ -11,15 +11,27 @@
您已授权
- 您已拒绝授权,请去设置中
-
- 打开语音、视频通话提醒开关
+
+ 授权失败
+ 请保证设备一直处于在线状态
+
+ 重试
+
-
- 打开设置
+
+ 您已拒绝授权,请去设置中
+
+ 打开语音、视频通话提醒开关
+
+
+ 打开设置
+
@@ -52,57 +64,76 @@
const pending = ref(false)
- onShow(() => {
+ const weChatTicketsFlag = ref(false)
+
+ onShow(async () => {
uni.showLoading({
title: '加载中...'
})
- wx.getDeviceVoIPList({
- async success(res) {
- list.value = res.list
- if (res.list.length > 0) {
- const result = await getInfo()
- if (result.code === 0) {
- const data = list.value.find(item => item.sn === result.data.WXIoTDeviceInfo.SN)
- if (data) {
- if (data.status === 1) {
- if (reject.value) {
- passthrough({
- request_method: 'POST',
- request_uri: '/api/v1/tencentYun/reportWechatAuthSuccess',
- post_args: {
- lockId: $bluetooth.currentLockInfo.lockId,
- wxOpenid: getStorage('openid'),
- wxDeviceSn: result.data.WXIoTDeviceInfo.SNTicket
- }
- })
- }
- reject.value = false
- } else if (data.status === 0) {
- reject.value = true
- }
- isAuthorized.value = true
- requestFinish.value = true
- uni.hideLoading()
- } else {
- requestFinish.value = true
- uni.hideLoading()
- }
- } else {
- uni.showToast({
- title: result.message,
- icon: 'none'
- })
- requestFinish.value = true
- uni.hideLoading()
- }
- } else {
- requestFinish.value = true
- uni.hideLoading()
- }
+
+ const resultList = await Promise.all([getDeviceVoIPList(), getAuthResult()])
+
+ list.value = resultList[0]
+ const authResult = resultList[1]
+
+ const data = list.value.find(item => item.sn === authResult.data.wxDeviceSn)
+
+ if (authResult?.code === 0 && authResult?.data?.wxOpenid === getStorage('openid') && data) {
+ isAuthorized.value = true
+ requestFinish.value = true
+ if (data.status === 1) {
+ reject.value = false
+ } else if (data.status === 0) {
+ reject.value = true
+ weChatTicketsFlag.value = true
}
- })
+ uni.hideLoading()
+ } else {
+ requestFinish.value = true
+ uni.hideLoading()
+ }
})
+ const getDeviceVoIPList = async () => {
+ return new Promise(resolve => {
+ wx.getDeviceVoIPList({
+ success: res => {
+ resolve(res.list)
+ }
+ })
+ })
+ }
+
+ const retry = async () => {
+ if (pending.value) return
+ uni.showLoading({
+ title: '授权中...'
+ })
+ pending.value = true
+ const ticketsResult = await weChatTickets()
+
+ pending.value = false
+ if (ticketsResult?.code === 0) {
+ passthrough({
+ request_method: 'POST',
+ request_uri: '/api/v1/tencentYun/reportWechatAuthSuccess',
+ post_args: {
+ lockId: $bluetooth.currentLockInfo.lockId,
+ wxOpenid: getStorage('openid'),
+ wxDeviceSn: ticketsResult.data.wxDeviceSn
+ }
+ })
+ uni.hideLoading()
+ isAuthorized.value = true
+ } else {
+ uni.hideLoading()
+ uni.showToast({
+ title: '授权失败',
+ icon: 'none'
+ })
+ }
+ }
+
const openSetting = () => {
uni.openSetting({
success: res => {
@@ -111,6 +142,18 @@
})
}
+ const getAuthResult = async () => {
+ const result = await passthrough({
+ request_method: 'GET',
+ request_uri: '/api/v1/tencentYun/checkWechatAuth',
+ post_args: {
+ lockId: $bluetooth.currentLockInfo.lockId,
+ wxOpenid: getStorage('openid')
+ }
+ })
+ return result
+ }
+
const getInfo = async () => {
const result = await passthrough({
request_method: 'GET',
@@ -122,6 +165,29 @@
return result
}
+ const weChatTickets = async (snTicket, sn) => {
+ let ticket = snTicket
+ let snResult = sn
+ if (!snTicket) {
+ const result = await getInfo()
+ ticket = result.data.WXIoTDeviceInfo.SNTicket
+ snResult = result.data.WXIoTDeviceInfo.SN
+ }
+ const result = await $bluetooth.weChatTickets({
+ keyId: $bluetooth.currentLockInfo.keyId.toString(),
+ uid: $bluetooth.currentLockInfo.uid.toString(),
+ openId: getStorage('openid'),
+ snTicket: ticket
+ })
+
+ return {
+ code: result.code,
+ data: {
+ wxDeviceSn: snResult
+ }
+ }
+ }
+
const handleAuthorize = async () => {
if (pending.value) return
pending.value = true
@@ -136,22 +202,39 @@
modelId: result.data.WXIoTDeviceInfo.ModelId,
deviceName: await env[await getApp().globalData.getEnvConfig()].appName,
async success() {
- isAuthorized.value = true
- uni.hideLoading()
- pending.value = false
- passthrough({
- request_method: 'POST',
- request_uri: '/api/v1/tencentYun/reportWechatAuthSuccess',
- post_args: {
- lockId: $bluetooth.currentLockInfo.lockId,
- wxOpenid: getStorage('openid'),
- wxDeviceSn: result.data.WXIoTDeviceInfo.SNTicket
- }
- })
- uni.showToast({
- title: '授权成功',
- icon: 'none'
- })
+ const ticketsResult = await weChatTickets(
+ result.data.WXIoTDeviceInfo.SNTicket,
+ result.data.WXIoTDeviceInfo.SN
+ )
+
+ if (ticketsResult?.code === 0) {
+ isAuthorized.value = true
+ uni.hideLoading()
+ pending.value = false
+ passthrough({
+ request_method: 'POST',
+ request_uri: '/api/v1/tencentYun/reportWechatAuthSuccess',
+ post_args: {
+ lockId: $bluetooth.currentLockInfo.lockId,
+ wxOpenid: getStorage('openid'),
+ wxDeviceSn: result.data.WXIoTDeviceInfo.SN
+ }
+ })
+ uni.showToast({
+ title: '授权成功',
+ icon: 'none'
+ })
+ } else {
+ isAuthorized.value = true
+ uni.hideLoading()
+ pending.value = false
+ reject.value = true
+ weChatTicketsFlag.value = true
+ uni.showToast({
+ title: '授权失败',
+ icon: 'none'
+ })
+ }
},
fail() {
isAuthorized.value = true
diff --git a/pages/p2p/videoLog.vue b/pages/p2p/videoLog.vue
index 4cff9e5..c004a54 100644
--- a/pages/p2p/videoLog.vue
+++ b/pages/p2p/videoLog.vue
@@ -113,7 +113,7 @@
import { onMounted, ref, computed } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { useBluetoothStore } from '@/stores/bluetooth'
- import { passthrough } from '@/api/sdk'
+ import { passthrough, getPackageUrl, reportBuyRequest } from '@/api/sdk'
import { useBasicStore } from '@/stores/basic'
const $bluetooth = useBluetoothStore()
@@ -157,13 +157,22 @@
})
}
- const toWebview = () => {
- $basic.routeJump({
- name: 'webview',
- params: {
- url: encodeURIComponent('https://www.baidu.com')
- }
- })
+ const toWebview = async () => {
+ const result = await Promise.all([
+ getPackageUrl({}),
+ reportBuyRequest({ type: 'cloud_storage', lockId: $bluetooth.currentLockInfo.lockId })
+ ])
+
+ const urls = result[0].data
+
+ if (urls?.cloud_storage) {
+ $basic.routeJump({
+ name: 'webview',
+ params: {
+ url: encodeURIComponent(urls.cloud_storage)
+ }
+ })
+ }
}
const resetLog = async () => {
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..5ee60d9
--- /dev/null
+++ b/pages/user/forgotPassword.vue
@@ -0,0 +1,239 @@
+
+
+
+
+ 国家/地区
+
+ {{ country.name }}
+ +{{ country.code }}
+
+
+
+
+
+
+
+
+ 密码必须是8-20位,至少包括数字/字母/符号中的2种
+
+
+
+
+
+
+
+
+
+ {{ tips }}
+
+
+
+
+
+ 重置密码
+
+
+
+
+
+
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..cd0aff3
--- /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/bluetooth.js b/stores/bluetooth.js
index 4484d7a..dad8566 100644
--- a/stores/bluetooth.js
+++ b/stores/bluetooth.js
@@ -116,7 +116,9 @@ const subCmdIds = {
// 修改设置
updateSetting: 70,
// 修改设置带参数
- updateSettingWithParams: 72
+ updateSettingWithParams: 72,
+ // 微信票据
+ weChatTickets: 55
}
export const useBluetoothStore = defineStore('ble', {
@@ -482,6 +484,21 @@ export const useBluetoothStore = defineStore('ble', {
}
})
break
+ case subCmdIds.weChatTickets:
+ that.updateCurrentLockInfo({
+ ...that.currentLockInfo,
+ token: decrypted.slice(5, 9)
+ })
+ if (decrypted[2] === 0) {
+ characteristicValueCallback({
+ code: decrypted[9]
+ })
+ } else {
+ characteristicValueCallback({
+ code: decrypted[2]
+ })
+ }
+ break
case subCmdIds.registerCard:
case subCmdIds.registerRemote:
case subCmdIds.registerPalmVein:
@@ -2861,6 +2878,107 @@ export const useBluetoothStore = defineStore('ble', {
return this.getResult(this.setLockPassword, data)
},
+ // 微信票据
+ async weChatTickets(data) {
+ // 确认蓝牙状态正常
+ if (
+ this.bluetoothStatus !== 0 &&
+ this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN
+ ) {
+ console.log('写入未执行', this.bluetoothStatus)
+ this.getBluetoothStatus()
+ return {
+ code: -1
+ }
+ }
+
+ // 确认设备连接正常
+ if (
+ !this.currentLockInfo.connected &&
+ this.currentLockInfo.transportType !== transportType.TRANSPORT_TENCENT_YUN
+ ) {
+ const searchResult = await this.searchAndConnectDevice()
+ if (searchResult.code !== 0) {
+ return searchResult
+ }
+ this.updateCurrentLockInfo({
+ ...this.currentLockInfo,
+ deviceId: searchResult.data.deviceId
+ })
+ console.log('设备ID:', this.currentLockInfo.deviceId)
+ const result = await this.connectBluetoothDevice()
+ console.log('连接结果', result)
+ if (!result) {
+ return {
+ code: -1
+ }
+ }
+ }
+
+ // 检查是否已添加为用户
+ const checkResult = await this.checkLockUser()
+ if (!checkResult) {
+ return {
+ code: -1
+ }
+ }
+
+ const { keyId, uid, openId, snTicket } = data
+ const length = 2 + 1 + 1 + 40 + 20 + 4 + 2 + openId.length + 2 + snTicket.length + 1 + 16
+ const headArray = this.createPackageHeader(3, length)
+ const contentArray = new Uint8Array(length)
+
+ contentArray[0] = cmdIds.expandCmd / 256
+ contentArray[1] = cmdIds.expandCmd % 256
+
+ contentArray[2] = subCmdIds.weChatTickets
+
+ contentArray[3] = length - 3
+
+ for (let i = 0; i < keyId.length; i++) {
+ contentArray[i + 4] = keyId.charCodeAt(i)
+ }
+ for (let i = 0; i < uid.length; i++) {
+ contentArray[i + 44] = uid.charCodeAt(i)
+ }
+
+ contentArray.set(this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]), 64)
+
+ contentArray[68] = openId.length / 256
+ contentArray[69] = openId.length % 256
+
+ for (let i = 0; i < openId.length; i++) {
+ contentArray[i + 70] = openId.charCodeAt(i)
+ }
+
+ contentArray[70 + openId.length] = snTicket.length / 256
+ contentArray[71 + openId.length] = snTicket.length % 256
+
+ for (let i = 0; i < snTicket.length; i++) {
+ contentArray[i + 72 + openId.length] = snTicket.charCodeAt(i)
+ }
+
+ contentArray[72 + openId.length + snTicket.length] = 16
+
+ const md5Array = this.md5Encrypte(
+ keyId + uid,
+ this.currentLockInfo.token || new Uint8Array([0, 0, 0, 0]),
+ this.currentLockInfo.signKey
+ )
+
+ contentArray.set(md5Array, 73 + openId.length + snTicket.length)
+
+ const cebArray = sm4.encrypt(contentArray, this.currentLockInfo.commKey, {
+ mode: 'ecb',
+ output: 'array'
+ })
+
+ const packageArray = this.createPackageEnd(headArray, cebArray)
+
+ this.transportMessage(packageArray)
+
+ return this.getResult(this.weChatTickets, data)
+ },
parseTimeToList(timeString) {
let timeList = [0, 0, 0, 0]
diff --git a/stores/user.js b/stores/user.js
index 8675e85..20ec8d2 100644
--- a/stores/user.js
+++ b/stores/user.js
@@ -2,10 +2,18 @@
* @description 用户信息数据持久化
*/
import { defineStore } from 'pinia'
-import { getUserInfoRequest, getWebUrlRequest, loginRequest, phoneLoginRequest } from '@/api/user'
+import {
+ getUserInfoRequest,
+ getWebUrlRequest,
+ loginRequest,
+ phoneLoginRequest,
+ registerRequest,
+ passwordLoginRequest
+} 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 +42,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 passwordLoginRequest({
+ 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')