Merge branch 'fanpeng' into 'master'
demo添加获取私钥功能 See merge request StarlockTeam/wx-starlock!1
39
App.vue
@ -1,16 +1,41 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
import { mapState, mapActions } from 'pinia'
|
||||||
|
let firstCheckSetting = true
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onLaunch: function() {
|
globalData: {
|
||||||
console.log('App Launch')
|
// 更新登录状态
|
||||||
|
updateIsLogin(isLogin) {
|
||||||
|
useUserStore().updateLoginStatus(isLogin)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useBluetoothStore, ['bluetoothStatus']),
|
||||||
|
},
|
||||||
|
onLaunch: async function() {
|
||||||
|
// 检查强制升级
|
||||||
this.updateMiniProgram()
|
this.updateMiniProgram()
|
||||||
|
// 检查蓝牙权限
|
||||||
|
const checkResult = await this.checkSetting()
|
||||||
|
console.log(checkResult)
|
||||||
|
if(checkResult === true) {
|
||||||
|
this.initAndListenBluetooth()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onShow: function() {
|
onShow() {
|
||||||
console.log('App Show')
|
if(firstCheckSetting) {
|
||||||
},
|
firstCheckSetting = false
|
||||||
onHide: function() {
|
} else {
|
||||||
console.log('App Hide')
|
this.checkSetting()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapActions(useBluetoothStore, ['initBluetooth', 'onBluetoothState', 'updateBluetoothStatus', 'checkSetting',
|
||||||
|
'onBluetoothConnectStatus', 'onBluetoothCharacteristicValueChange', 'updateInitBluetooth', 'initAndListenBluetooth']),
|
||||||
|
...mapActions(useUserStore, ['updateLoginStatus']),
|
||||||
// 强制升级
|
// 强制升级
|
||||||
updateMiniProgram() {
|
updateMiniProgram() {
|
||||||
const updateManager = uni.getUpdateManager()
|
const updateManager = uni.getUpdateManager()
|
||||||
|
|||||||
26
README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# 项目说明
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
#### 功能与星锁app相同,在其基础上简化
|
||||||
|
|
||||||
|
## 使用工具
|
||||||
|
#### HBuilderX + 微信开发者工具(推荐使用IntelliJ工具编写,HBuilderX代码提示等功能做的较差)
|
||||||
|
|
||||||
|
## 技术栈 + 运行方式
|
||||||
|
#### [uni-app](https://uniapp.dcloud.net.cn/)创建的vue3项目,目前并未使用uni-app x和uniCloud,主要使用vue3 + pinia + uview-plus
|
||||||
|
#### 在HBuilderX中点击 文件 -> 导入 -> 从本地目录导入,选择项目目录即可导入项目
|
||||||
|
#### 运行只需执行`npm i` 安装依赖(node版本 v20.16),然后在HBuilderX中点击运行 -> 运行到微信开发者工具即可(运行前勾选运行时压缩代码)
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
1. api 项目接口
|
||||||
|
2. config 项目不同环境配置
|
||||||
|
3. pages 项目页面
|
||||||
|
4. static 项目静态资源
|
||||||
|
5. stores 项目全局状态管理
|
||||||
|
6. utils 项目公共方法
|
||||||
|
|
||||||
|
## 公共方法
|
||||||
|
#### 示例在index页面中,后续添加公共方法会在文档中说明
|
||||||
|
1. utils/request 请求方法
|
||||||
|
2. pinia 全局状态管理
|
||||||
|
3. [uview-plus](https://uiadmin.net/uview-plus/components/intro.html) Uni-app常用UI组件库,且提供很多常用api
|
||||||
12
api/file.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import request from '../utils/request'
|
||||||
|
|
||||||
|
// file 用户模块
|
||||||
|
|
||||||
|
// 获取文件上传参数
|
||||||
|
export function getUploadParamsRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/file/getUploadParams',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
12
api/lock.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import request from '../utils/request'
|
||||||
|
|
||||||
|
// lock 锁模块
|
||||||
|
|
||||||
|
// 获取锁列表
|
||||||
|
export function getLockListRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/lock/list',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
30
api/safeAnswer.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import request from '../utils/request'
|
||||||
|
|
||||||
|
// safeAnswer 安全问题模块
|
||||||
|
|
||||||
|
// 获取安全问题列表
|
||||||
|
export function getQuestionListRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/safeAnswer/getQuestionList',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取安全问题答案
|
||||||
|
export function getQuestionAnswerRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/safeAnswer/getOwnQuestionList',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新安全问题答案
|
||||||
|
export function updateQuestionAnswerRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/safeAnswer/set',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
51
api/user.js
@ -2,10 +2,55 @@ import request from '../utils/request'
|
|||||||
|
|
||||||
// user 用户模块
|
// user 用户模块
|
||||||
|
|
||||||
// 登录
|
// 获取用户信息
|
||||||
export function login(data) {
|
export function getUserInfoRequest(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/login',
|
url: '/user/getUserInfo',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新用户信息
|
||||||
|
export function updateUserInfoRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/updateUserInfo',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改密码
|
||||||
|
export function updatePasswordRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/changePassword',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取解绑邮箱token
|
||||||
|
export function unbindEmailTokenRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/unbindEmailToken',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改绑定邮箱
|
||||||
|
export function updateEmailRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/bindEmail',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取邮箱验证码
|
||||||
|
export function getEmailCodeRequest(data) {
|
||||||
|
return request({
|
||||||
|
url: '/user/sendValidationCodeAuth',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
|||||||
@ -4,12 +4,14 @@ const version = '1.0.0.0'
|
|||||||
|
|
||||||
const DEV = {
|
const DEV = {
|
||||||
name: '开发',
|
name: '开发',
|
||||||
baseUrl: 'https://www.baidu.com',
|
baseUrl: 'https://dev.lock.star-lock.cn/api',
|
||||||
|
webviewBaseUrl: 'https://dev.lock.star-lock.cn',
|
||||||
version: version
|
version: version
|
||||||
}
|
}
|
||||||
const PRE = {
|
const PRE = {
|
||||||
name: '预发',
|
name: '预发',
|
||||||
baseUrl: '',
|
baseUrl: 'https://pre.lock.star-lock.cn/api',
|
||||||
|
webviewBaseUrl: 'https://pre.lock.star-lock.cn',
|
||||||
version: version
|
version: version
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,4 +22,4 @@ const PROD = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更换环境的时候 切换导出就行
|
// 更换环境的时候 切换导出就行
|
||||||
export default DEV
|
export default PRE
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name" : "wx-starlock",
|
"name" : "wx-starlock",
|
||||||
"appid" : "",
|
"appid" : "__UNI__933D519",
|
||||||
"description" : "",
|
"description" : "",
|
||||||
"versionName" : "1.0.0",
|
"versionName" : "1.0.0",
|
||||||
"versionCode" : "100",
|
"versionCode" : "100",
|
||||||
@ -50,11 +50,13 @@
|
|||||||
"quickapp" : {},
|
"quickapp" : {},
|
||||||
/* 小程序特有相关 */
|
/* 小程序特有相关 */
|
||||||
"mp-weixin" : {
|
"mp-weixin" : {
|
||||||
"appid" : "",
|
"appid" : "wx9829a39e65550757",
|
||||||
"setting" : {
|
"setting" : {
|
||||||
"urlCheck" : false
|
"urlCheck" : true,
|
||||||
|
"minified" : true
|
||||||
},
|
},
|
||||||
"usingComponents" : true
|
"usingComponents" : true,
|
||||||
|
"lazyCodeLoading" : "requiredComponents"
|
||||||
},
|
},
|
||||||
"mp-alipay" : {
|
"mp-alipay" : {
|
||||||
"usingComponents" : true
|
"usingComponents" : true
|
||||||
|
|||||||
23
package-lock.json
generated
@ -6,8 +6,10 @@
|
|||||||
"": {
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crc": "^4.3.2",
|
"crc": "^4.3.2",
|
||||||
|
"js-md5": "^0.8.3",
|
||||||
"pinia": "^2.2.0",
|
"pinia": "^2.2.0",
|
||||||
"pinia-plugin-unistorage": "^0.1.2",
|
"pinia-plugin-unistorage": "^0.1.2",
|
||||||
|
"sm-crypto": "^0.3.13",
|
||||||
"uview-plus": "^3.3.12"
|
"uview-plus": "^3.3.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -134,6 +136,18 @@
|
|||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/js-md5": {
|
||||||
|
"version": "0.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz",
|
||||||
|
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/jsbn": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/pinia": {
|
"node_modules/pinia": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/pinia/-/pinia-2.2.0.tgz",
|
||||||
@ -172,6 +186,15 @@
|
|||||||
"integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==",
|
"integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/sm-crypto": {
|
||||||
|
"version": "0.3.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/sm-crypto/-/sm-crypto-0.3.13.tgz",
|
||||||
|
"integrity": "sha512-ztNF+pZq6viCPMA1A6KKu3bgpkmYti5avykRHbcFIdSipFdkVmfUw2CnpM2kBJyppIalqvczLNM3wR8OQ0pT5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tiny-emitter": {
|
"node_modules/tiny-emitter": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"crc": "^4.3.2",
|
"crc": "^4.3.2",
|
||||||
|
"js-md5": "^0.8.3",
|
||||||
"pinia": "^2.2.0",
|
"pinia": "^2.2.0",
|
||||||
"pinia-plugin-unistorage": "^0.1.2",
|
"pinia-plugin-unistorage": "^0.1.2",
|
||||||
|
"sm-crypto": "^0.3.13",
|
||||||
"uview-plus": "^3.3.12"
|
"uview-plus": "^3.3.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
136
pages.json
@ -9,23 +9,143 @@
|
|||||||
},
|
},
|
||||||
"pages": [
|
"pages": [
|
||||||
{
|
{
|
||||||
"path": "pages/demo/demo",
|
"path": "pages/home/home",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "uni-app"
|
"navigationBarTitleText": "星星锁",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/index/index",
|
"path": "pages/mine/mine",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "uni-app"
|
"navigationBarTitleText": "星星锁",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/index/index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/userInfo/userInfo",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "个人信息",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/updateName/updateName",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "修改昵称",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/updatePassword/updatePassword",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "重置密码",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/updateEmail/updateEmail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "修改邮箱",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/verifyEmail/verifyEmail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "验证邮箱",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/safeQuestion/safeQuestion",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "安全问题",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/updateSafeQuestion/updateSafeQuestion",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "修改安全问题",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/webview/webview",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "介绍",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/lockDetail/lockDetail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "星星锁",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/searchDevice/searchDevice",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "搜索",
|
||||||
|
"navigationBarTextStyle": "white",
|
||||||
|
"navigationBarBackgroundColor": "#63b8af",
|
||||||
|
"navigationStyle": "default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
"navigationBarTitleText": "uni-app",
|
"navigationBarTitleText": "星星锁",
|
||||||
"navigationBarBackgroundColor": "#F8F8F8",
|
"navigationBarBackgroundColor": "#F3F3F3",
|
||||||
"backgroundColor": "#F8F8F8"
|
"backgroundColor": "#F3F3F3",
|
||||||
|
"navigationStyle": "custom"
|
||||||
},
|
},
|
||||||
"uniIdRouter": {}
|
"tabBar": {
|
||||||
|
"color": "#a3a3a3",
|
||||||
|
"selectedColor": "#63b8af",
|
||||||
|
"borderStyle": "white",
|
||||||
|
"backgroundColor": "#FFFFFF",
|
||||||
|
"position": "bottom",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"pagePath": "pages/home/home",
|
||||||
|
"iconPath": "static/images/tabbar_key_no_select.png",
|
||||||
|
"selectedIconPath": "static/images/tabbar_key_select.png",
|
||||||
|
"text": "设备"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pagePath": "pages/mine/mine",
|
||||||
|
"iconPath": "static/images/tabbar_mine_no_select.png",
|
||||||
|
"selectedIconPath": "static/images/tabbar_mine_select.png",
|
||||||
|
"text": "我的"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,317 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view>
|
|
||||||
<button @click="getList">获取设备列表</button>
|
|
||||||
<button @click="stopGetList">停止获取</button>
|
|
||||||
<view v-if="showList">
|
|
||||||
<button class="device" v-for="item in list"
|
|
||||||
:key="item.deviceId" @click="connect(item)">{{item.name}}
|
|
||||||
- {{item.pair ? '已配对' : '未配对'}}-{{item.sleep ? '休眠中' :
|
|
||||||
'已唤醒'}}</button>
|
|
||||||
</view>
|
|
||||||
<view v-else>
|
|
||||||
<button @click="getPublicKey">获取锁公钥</button>
|
|
||||||
<button @click="getTest">获取锁私钥</button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import crc from 'crc'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
list: [],
|
|
||||||
getting: false,
|
|
||||||
// deviceId: '6C3CD148-F456-1C61-F35E-C176B0CC644A',
|
|
||||||
// serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',
|
|
||||||
// characteristicId1: '0000FFF1-0000-1000-8000-00805F9B34FB',
|
|
||||||
// characteristicId2: '0000FFF2-0000-1000-8000-00805F9B34FB',
|
|
||||||
deviceId: '',
|
|
||||||
serviceId: '',
|
|
||||||
characteristicId1: '',
|
|
||||||
characteristicId2: '',
|
|
||||||
lockId: '',
|
|
||||||
showList: true,
|
|
||||||
number: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLoad() {
|
|
||||||
uni.openBluetoothAdapter({
|
|
||||||
success(res) {
|
|
||||||
console.log('初始化成功')
|
|
||||||
console.log(res)
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('初始化失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onUnload() {
|
|
||||||
uni.closeBluetoothAdapter({
|
|
||||||
success(res) {
|
|
||||||
console.log('关闭蓝牙成功')
|
|
||||||
console.log(res)
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('关闭蓝牙失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
GetCommKey() {
|
|
||||||
const userId = 294
|
|
||||||
|
|
||||||
let buffer = new ArrayBuffer(54)
|
|
||||||
let binaryData = new Uint8Array(buffer)
|
|
||||||
|
|
||||||
// 固定包头
|
|
||||||
binaryData[0] = 0xEF
|
|
||||||
binaryData[1] = 0x01
|
|
||||||
binaryData[2] = 0xEE
|
|
||||||
binaryData[3] = 0x02
|
|
||||||
|
|
||||||
// 包类型 发送
|
|
||||||
binaryData[4] = 0x01
|
|
||||||
|
|
||||||
// 包序号
|
|
||||||
binaryData[5] = this.number / 256
|
|
||||||
binaryData[6] = this.number % 256
|
|
||||||
this.number++
|
|
||||||
|
|
||||||
// 包标识
|
|
||||||
|
|
||||||
},
|
|
||||||
getPublicKey() {
|
|
||||||
let buffer = new ArrayBuffer(54)
|
|
||||||
let binaryData = new Uint8Array(buffer)
|
|
||||||
|
|
||||||
// 固定包头
|
|
||||||
binaryData[0] = 0xEF
|
|
||||||
binaryData[1] = 0x01
|
|
||||||
binaryData[2] = 0xEE
|
|
||||||
binaryData[3] = 0x02
|
|
||||||
|
|
||||||
// 包类型 发送
|
|
||||||
binaryData[4] = 0x01
|
|
||||||
|
|
||||||
// 包序号
|
|
||||||
binaryData[5] = this.number / 256
|
|
||||||
binaryData[6] = this.number % 256
|
|
||||||
this.number++
|
|
||||||
|
|
||||||
// 包标识
|
|
||||||
binaryData[7] = 0x20
|
|
||||||
|
|
||||||
// 数据长度
|
|
||||||
binaryData[8] = 42 / 256
|
|
||||||
binaryData[9] = 42 % 256
|
|
||||||
binaryData[10] = 42 / 256
|
|
||||||
binaryData[11] = 42 % 256
|
|
||||||
|
|
||||||
// 命令
|
|
||||||
binaryData[12] = 0x3090 / 256
|
|
||||||
binaryData[13] = 0x3090 % 256
|
|
||||||
|
|
||||||
// // 设备ID
|
|
||||||
for(let i=0; i < this.lockId.length; i++){
|
|
||||||
binaryData[14 + i] = this.lockId.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// crc
|
|
||||||
|
|
||||||
let newBuffer = new ArrayBuffer(56)
|
|
||||||
let newBinaryData = new Uint8Array(newBuffer)
|
|
||||||
for(let i = 0; i < 54; i++){
|
|
||||||
newBinaryData[i] = binaryData[i]
|
|
||||||
}
|
|
||||||
newBinaryData[54] = crc.crc16kermit(buffer) / 256
|
|
||||||
newBinaryData[55] = crc.crc16kermit(buffer) % 256
|
|
||||||
this.writeBLECharacteristicValue(newBuffer)
|
|
||||||
},
|
|
||||||
writeBLECharacteristicValue(data) {
|
|
||||||
const that = this
|
|
||||||
console.log('写入设备的设备 ID',that.deviceId)
|
|
||||||
console.log('写入设备的serviceId',that.serviceId)
|
|
||||||
console.log('写入设备的characteristicId',that.characteristicId2)
|
|
||||||
console.log('写入设备的lockID',that.lockId)
|
|
||||||
|
|
||||||
let Uint8ArrayData = new Uint8Array(data)
|
|
||||||
|
|
||||||
const hexString = Array.from(Uint8ArrayData, byte =>
|
|
||||||
byte.toString(10)).join(',')
|
|
||||||
console.log('未加工的数据', hexString)
|
|
||||||
|
|
||||||
for(let i = 0; i < Math.ceil(data.byteLength / 20); i++){
|
|
||||||
let buffer = new ArrayBuffer(20)
|
|
||||||
let binaryData = new Uint8Array(buffer)
|
|
||||||
for(let j = 0; j < 20; j++){
|
|
||||||
if(i * 20 + j < data.byteLength){
|
|
||||||
binaryData[j] = Uint8ArrayData[i * 20 + j]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uni.writeBLECharacteristicValue({
|
|
||||||
deviceId: that.deviceId,
|
|
||||||
serviceId: that.serviceId,
|
|
||||||
characteristicId: that.characteristicId2,
|
|
||||||
value: buffer,
|
|
||||||
success(write) {
|
|
||||||
const hexString = Array.from(binaryData, byte =>
|
|
||||||
byte.toString(10)).join(',')
|
|
||||||
console.log('写入的数据', hexString)
|
|
||||||
console.log('写入成功')
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('写入失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
notifyBLECharacteristicValueChange() {
|
|
||||||
const that = this
|
|
||||||
uni.notifyBLECharacteristicValueChange({
|
|
||||||
state: true,
|
|
||||||
deviceId: that.deviceId,
|
|
||||||
serviceId: that.serviceId,
|
|
||||||
characteristicId: that.characteristicId1,
|
|
||||||
type: 'notification',
|
|
||||||
success(res) {
|
|
||||||
console.log(res)
|
|
||||||
uni.onBLECharacteristicValueChange(function (res) {
|
|
||||||
console.log('设备特征值改变')
|
|
||||||
console.log(res)
|
|
||||||
let binaryData = new Uint8Array(res.value)
|
|
||||||
const hexString = Array.from(binaryData, byte =>
|
|
||||||
byte.toString(10)).join(',')
|
|
||||||
console.log(hexString)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
connect(item) {
|
|
||||||
const that = this
|
|
||||||
if(item.pair) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
uni.createBLEConnection({
|
|
||||||
deviceId: item.deviceId,
|
|
||||||
success(res) {
|
|
||||||
console.log('连接成功')
|
|
||||||
console.log(res)
|
|
||||||
uni.getBLEDeviceServices({
|
|
||||||
deviceId: item.deviceId,
|
|
||||||
success(res) {
|
|
||||||
console.log('获取服务成功')
|
|
||||||
console.log(res.services)
|
|
||||||
const uuid = res.services[0].uuid
|
|
||||||
that.lockId = item.name
|
|
||||||
console.log('锁ID', that.lockId)
|
|
||||||
uni.getBLEDeviceCharacteristics({
|
|
||||||
deviceId: item.deviceId,
|
|
||||||
serviceId: uuid,
|
|
||||||
success(res) {
|
|
||||||
console.log('获取特征值成功')
|
|
||||||
console.log(res)
|
|
||||||
that.deviceId = item.deviceId
|
|
||||||
that.serviceId = uuid
|
|
||||||
for (let i = 0; i < res.characteristics.length; i++) {
|
|
||||||
if (res.characteristics[i].uuid.indexOf("FFF1") !== -1) {
|
|
||||||
that.characteristicId1 = res.characteristics[i].uuid
|
|
||||||
}
|
|
||||||
if (res.characteristics[i].uuid.indexOf("FFF2") !== -1) {
|
|
||||||
that.characteristicId2 = res.characteristics[i].uuid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
that.showList = false
|
|
||||||
that.notifyBLECharacteristicValueChange()
|
|
||||||
uni.showToast({
|
|
||||||
title: '数据获取成功',
|
|
||||||
icon: 'none',
|
|
||||||
duration: 2000
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('获取特征值失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('获取服务失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('连接失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
startGetList() {
|
|
||||||
const that = this
|
|
||||||
this.getting = true
|
|
||||||
console.log('开始监听蓝牙列表更新')
|
|
||||||
uni.startBluetoothDevicesDiscovery({
|
|
||||||
allowDuplicatesKey: false,
|
|
||||||
powerLevel: 'high',
|
|
||||||
success: function (res) {
|
|
||||||
// 更新列表
|
|
||||||
console.log('列表发生变化', res)
|
|
||||||
that.getList()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
stopGetList(){
|
|
||||||
const that = this
|
|
||||||
uni.stopBluetoothDevicesDiscovery({
|
|
||||||
success: function () {
|
|
||||||
that.getting = false
|
|
||||||
console.log('停止获取设备列表成功')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getList() {
|
|
||||||
const that = this
|
|
||||||
uni.getBluetoothDevices({
|
|
||||||
success(res) {
|
|
||||||
console.log('获取设备列表成功')
|
|
||||||
console.log(res)
|
|
||||||
that.list = []
|
|
||||||
for(let i =0; i < res.devices.length; i++){
|
|
||||||
if(res.devices[i]?.advertisServiceUUIDs) {
|
|
||||||
const advertisServiceUUIDs =
|
|
||||||
res.devices[i]?.advertisServiceUUIDs[0]
|
|
||||||
if(advertisServiceUUIDs &&
|
|
||||||
advertisServiceUUIDs.slice(2,8)==='758824'){
|
|
||||||
res.devices[i].pair =
|
|
||||||
advertisServiceUUIDs.slice(30,32) === '01'
|
|
||||||
res.devices[i].sleep =
|
|
||||||
advertisServiceUUIDs.slice(32,34) === '00'
|
|
||||||
that.list.push(res.devices[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(that.list)
|
|
||||||
if(!that.getting) {
|
|
||||||
that.startGetList()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail(res) {
|
|
||||||
console.log('获取设备列表失败')
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.device {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
317
pages/home/home.vue
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view v-if="!penging">
|
||||||
|
<view v-if="isLogin">
|
||||||
|
<scroll-view scroll-y="true" :style="{ height: 'calc(100vh)' }" lower-threshold="100"
|
||||||
|
@refresherrefresh="refresherList" :refresher-enabled="true" @scrolltolower="nextPage"
|
||||||
|
:refresher-triggered="refresherTriggered">
|
||||||
|
<view class="search">
|
||||||
|
<up-search :searchIconSize="48" :inputStyle="{ fontSize: '32rpx' }" @focus="getFocus" @blur="getBlur"
|
||||||
|
:height="80" placeholder="搜索" :clearabled="false" @change="changeSearch"
|
||||||
|
v-model="search.searchStr" bgColor="#ffffff" :showAction="false" maxlength="20"></up-search>
|
||||||
|
</view>
|
||||||
|
<view class="lock-list" v-if="!penging">
|
||||||
|
<view v-if="lockList.length === 0 && search.searchStr === '' && !focus">
|
||||||
|
<image src="/static/images/icon_add.png" mode="aspectFill" class="button-add-big" @click="toSearchDevice"></image>
|
||||||
|
<view class="text">填加锁时,手机必须在锁旁边</view>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<view class="group" v-for="group in lockList" :key="group.groupId">
|
||||||
|
<view class="group-name">
|
||||||
|
<view class="group-name-text">{{group.groupName}}</view>
|
||||||
|
<view class="group-name-line"></view>
|
||||||
|
</view>
|
||||||
|
<view class="lock" v-for="lock in group.lockList" :key="lock.lockId" @click="toLockDeatil(lock)">
|
||||||
|
<view class="lock-top">
|
||||||
|
<image class="lock-image-lock" src="/static/images/icon_lock.png"></image>
|
||||||
|
<view class="lock-top-right">
|
||||||
|
<view class="lock-top-right-power">
|
||||||
|
<image class="lock-top-right-power-image" src="/static/images/icon_power.png"></image>
|
||||||
|
<view class="lock-top-right-power-text">{{lock.electricQuantity}}%</view>
|
||||||
|
</view>
|
||||||
|
<view>{{getRole(lock.userType)}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="lock-name">{{lock.lockName}}</view>
|
||||||
|
<view class="lock-time">
|
||||||
|
<view v-if="lock.keyType !== 1" style="font-size: 32rpx">{{ getTimeLimit(lock.keyType) }}</view>
|
||||||
|
<view v-else>
|
||||||
|
<view>{{ timeFormat(lock.startDate, 'yyyy-mm-dd h:M') }}</view>
|
||||||
|
<view>{{ timeFormat(lock.endDate, 'yyyy-mm-dd h:M ') + getTimeLimit(lock.keyType) }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<image v-if="lockList.length !== 0" src="/static/images/icon_add.png" mode="aspectFill"
|
||||||
|
class="button-add" @click="toSearchDevice"></image>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<view class="button-login" @click="login">登录</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { timeFormat } from 'uview-plus'
|
||||||
|
import { getUserInfoRequest } from '@/api/user'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { useLockStore } from '@/stores/lock'
|
||||||
|
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
import { mapState, mapActions } from 'pinia'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
search: {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 50,
|
||||||
|
searchStr: ''
|
||||||
|
},
|
||||||
|
refresherTriggered: false,
|
||||||
|
focus: false,
|
||||||
|
penging: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo', 'isLogin']),
|
||||||
|
...mapState(useLockStore, ['lockList', 'lockTotal']),
|
||||||
|
...mapState(useBluetoothStore, ['bluetoothStatus', 'isInitBluetooth']),
|
||||||
|
},
|
||||||
|
async onLoad() {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '加载中'
|
||||||
|
})
|
||||||
|
const token = uni.getStorageSync('token')
|
||||||
|
if(token) {
|
||||||
|
this.updateLoginStatus(true)
|
||||||
|
const code = await this.getUserInfo()
|
||||||
|
if(code === 0) {
|
||||||
|
await this.getLockList(this.search)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.penging = false
|
||||||
|
uni.hideLoading()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
timeFormat,
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo', 'updateLoginStatus', 'login']),
|
||||||
|
...mapActions(useLockStore, ['getLockList', 'getRole', 'getTimeLimit']),
|
||||||
|
...mapActions(useBluetoothStore, ['getBluetoothStatus', 'initAndListenBluetooth', 'updateCurrentLockInfo', 'checkSetting']),
|
||||||
|
...mapActions(useBasicStore, ['routeJump']),
|
||||||
|
async nextPage() {
|
||||||
|
if(this.lockList.length < this.lockTotal) {
|
||||||
|
this.search.pageNo++
|
||||||
|
const { code } = await this.getLockList(this.search)
|
||||||
|
if(code !== 0) {
|
||||||
|
this.search.pageNo--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async refresherList() {
|
||||||
|
this.refresherTriggered = true
|
||||||
|
this.search.pageNo = 1
|
||||||
|
await this.getLockList(this.search)
|
||||||
|
this.refresherTriggered = false
|
||||||
|
},
|
||||||
|
async changeSearch(data) {
|
||||||
|
this.search.searchStr = data
|
||||||
|
await this.getLockList(this.search)
|
||||||
|
},
|
||||||
|
async getUserInfo() {
|
||||||
|
const { code, data } = await getUserInfoRequest()
|
||||||
|
if(code === 0) {
|
||||||
|
this.updateUserInfo(data)
|
||||||
|
console.log(this.userInfo)
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
},
|
||||||
|
getFocus() {
|
||||||
|
this.focus = true
|
||||||
|
},
|
||||||
|
getBlur() {
|
||||||
|
this.focus = false
|
||||||
|
},
|
||||||
|
async toSearchDevice() {
|
||||||
|
if(this.bluetoothStatus !== 0) {
|
||||||
|
this.getBluetoothStatus()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let result = true
|
||||||
|
if(!this.isInitBluetooth) {
|
||||||
|
result = await this.initAndListenBluetooth()
|
||||||
|
}
|
||||||
|
if(result) {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'searchDevice'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.checkSetting()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async toLockDeatil(lock) {
|
||||||
|
if(this.bluetoothStatus !== 0) {
|
||||||
|
this.getBluetoothStatus()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let result = true
|
||||||
|
if(!this.isInitBluetooth) {
|
||||||
|
result = await this.initAndListenBluetooth()
|
||||||
|
}
|
||||||
|
if(result) {
|
||||||
|
this.updateCurrentLockInfo(lock)
|
||||||
|
this.routeJump({
|
||||||
|
name: 'lockDetail'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.checkSetting()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.search {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
width: 686rpx !important;
|
||||||
|
margin-left: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-login {
|
||||||
|
margin-top: 40vh;
|
||||||
|
border-radius: 46rpx;
|
||||||
|
width: 650rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
line-height: 120rpx;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 50rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 48rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-add {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
position: fixed;
|
||||||
|
right: 50rpx;
|
||||||
|
bottom: 50rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lock-list {
|
||||||
|
padding-bottom: 32rpx;
|
||||||
|
width: 672rpx;
|
||||||
|
margin-left: 39rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.lock {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
width: 320rpx;
|
||||||
|
height: 300rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
box-shadow: 0 8rpx 36rpx 0 rgba(0,0,0,0.12);
|
||||||
|
border-radius: 32rpx;
|
||||||
|
|
||||||
|
.lock-name {
|
||||||
|
padding: 0 24rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lock-time {
|
||||||
|
padding: 12rpx 24rpx 0 24rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lock-top {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24rpx 24rpx 12rpx 24rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
|
||||||
|
.lock-image-lock {
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lock-top-right-power {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.lock-top-right-power-image {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
width: 672rpx;
|
||||||
|
margin-top: 32rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.group-name {
|
||||||
|
width: 672rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-name-text {
|
||||||
|
padding: 0 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-name-line {
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 3rpx;
|
||||||
|
background: #E5E5E5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-add-big {
|
||||||
|
width: 400rpx;
|
||||||
|
height: 400rpx;
|
||||||
|
margin-top: 250rpx;
|
||||||
|
margin-left: 136rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
width: 672rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #999999;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,68 +1,205 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<image class="logo" src="/static/logo.png"></image>
|
<view v-if="!showConnect">
|
||||||
<view class="text-area">
|
<button class="button" v-if="showAdd" @click="getList">添加设备</button>
|
||||||
<text class="title">{{title}}{{userInfo.name}}</text>
|
<button class="button" v-else @click="stopGetList">停止搜索</button>
|
||||||
</view>
|
<view class="device-list" v-for="(item, index) in deviceList" :key="item.deviceId" @click="connect(item)">{{item.name}}</view>
|
||||||
<up-button type="primary" :plain="true" text="镂空"></up-button>
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<button class="button" @click="bindUser">添加用户</button>
|
||||||
|
<button class="button" @click="openDoorOperate">开门</button>
|
||||||
|
<button class="button" @click="closeDoorOperate">关门</button>
|
||||||
|
<button class="button" @click="reset">恢复出厂设置</button>
|
||||||
|
<button class="button" @click="getLockStatusResult">获取锁状态</button>
|
||||||
|
<button class="button" @click="resetPassword">重置锁密码</button>
|
||||||
|
<button class="button" @click="setPassword">设置密码</button>
|
||||||
|
<button class="button" @click="deletePassword">删除密码</button>
|
||||||
|
<view>名称:{{currentLockInfo.name}}</view>
|
||||||
|
<view>设备Id:{{currentLockInfo.deviceId}}</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useUserStore } from '../../stores/user.js'
|
import { useBluetoothStore } from '@/stores/bluetooth'
|
||||||
import { mapState, mapActions } from 'pinia'
|
import { mapState, mapActions } from 'pinia'
|
||||||
import { rgbToHex } from 'uview-plus'
|
|
||||||
import { login } from '../../api/user.js'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
title: 'Hello'
|
showAdd: true,
|
||||||
}
|
showConnect: false,
|
||||||
|
keyId: '0',
|
||||||
|
authUid: '294',
|
||||||
|
onlineToken: '0'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 允许读取this.userInfo
|
...mapState(useBluetoothStore, ['deviceList', 'currentLockInfo'])
|
||||||
...mapState(useUserStore, ['userInfo'])
|
|
||||||
},
|
|
||||||
async onLoad () {
|
|
||||||
this.update()
|
|
||||||
const data = await login({ code: '123' })
|
|
||||||
console.log(data)
|
|
||||||
console.log(rgbToHex('rgb(13, 145, 20)'))
|
|
||||||
console.log(111, uni.$u.config.v)
|
|
||||||
},
|
},
|
||||||
|
onLoad () {},
|
||||||
methods: {
|
methods: {
|
||||||
// 允许调用this.updateUserInfo()
|
...mapActions(useBluetoothStore, ['getBluetoothDevices', 'stopGetBluetoothDevices', 'updateCurrentLockInfo',
|
||||||
...mapActions(useUserStore, ['updateUserInfo']),
|
'connectBluetoothDevice', 'getPublicKey', 'getCommKey', 'getLockStatus', 'addLockUser', 'timestampToArray',
|
||||||
update() {
|
'openDoor', 'resetDevice', 'resetLockPassword', 'setLockPassword']),
|
||||||
this.updateUserInfo({ name: '123' })
|
async deletePassword() {
|
||||||
console.log(111, this.userInfo)
|
const timestamp = parseInt(new Date().getTime() / 1000)
|
||||||
|
const data = await this.setLockPassword({
|
||||||
|
keyId: this.keyId,
|
||||||
|
uid: this.authUid,
|
||||||
|
pwdNo: 2,
|
||||||
|
operate: 2,
|
||||||
|
isAdmin: 1,
|
||||||
|
pwd: '000000',
|
||||||
|
userCountLimit: 0,
|
||||||
|
startTime: timestamp,
|
||||||
|
endTime: timestamp
|
||||||
|
})
|
||||||
|
console.log('设置密码返回', data)
|
||||||
|
},
|
||||||
|
async setPassword() {
|
||||||
|
const timestamp = parseInt(new Date().getTime() / 1000)
|
||||||
|
const endTimestamp = timestamp + 3600 * 24 * 365
|
||||||
|
const data = await this.setLockPassword({
|
||||||
|
keyId: this.keyId,
|
||||||
|
uid: this.authUid,
|
||||||
|
pwdNo: 1,
|
||||||
|
operate: 0,
|
||||||
|
isAdmin: 1,
|
||||||
|
pwd: '000000',
|
||||||
|
userCountLimit: 0xffff,
|
||||||
|
startTime: timestamp,
|
||||||
|
endTime: endTimestamp
|
||||||
|
})
|
||||||
|
console.log('设置密码返回', data)
|
||||||
|
},
|
||||||
|
async resetPassword() {
|
||||||
|
const { code } = await this.resetLockPassword({
|
||||||
|
uid: this.authUid,
|
||||||
|
keyId: this.keyId
|
||||||
|
})
|
||||||
|
console.log('重置密码返回', code)
|
||||||
|
},
|
||||||
|
async openDoorOperate() {
|
||||||
|
const { code } = await this.openDoor({
|
||||||
|
name: this.currentLockInfo.name,
|
||||||
|
uid: this.authUid,
|
||||||
|
openMode: 0,
|
||||||
|
openTime: parseInt(new Date().getTime() / 1000),
|
||||||
|
onlineToken: this.onlineToken
|
||||||
|
})
|
||||||
|
console.log('开门返回', code)
|
||||||
|
},
|
||||||
|
async closeDoorOperate() {
|
||||||
|
const { code } = await this.openDoor({
|
||||||
|
name: this.currentLockInfo.name,
|
||||||
|
uid: this.authUid,
|
||||||
|
openMode: 32,
|
||||||
|
openTime: parseInt(new Date().getTime() / 1000),
|
||||||
|
onlineToken: this.onlineToken
|
||||||
|
})
|
||||||
|
console.log('关门返回', code)
|
||||||
|
},
|
||||||
|
async reset() {
|
||||||
|
const { code } = await this.resetDevice({
|
||||||
|
name: this.currentLockInfo.name,
|
||||||
|
authUid: this.authUid,
|
||||||
|
keyId: this.keyId
|
||||||
|
})
|
||||||
|
console.log('恢复出厂设置返回', code)
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
this.getBluetoothDevices()
|
||||||
|
this.showAdd = false
|
||||||
|
},
|
||||||
|
stopGetList() {
|
||||||
|
this.stopGetBluetoothDevices()
|
||||||
|
this.showAdd = true
|
||||||
|
},
|
||||||
|
async connect(item) {
|
||||||
|
this.updateCurrentLockInfo({
|
||||||
|
name: item.name,
|
||||||
|
deviceId: item.deviceId
|
||||||
|
})
|
||||||
|
const result = await this.connectBluetoothDevice()
|
||||||
|
if(result) {
|
||||||
|
this.showConnect = true
|
||||||
|
this.stopGetBluetoothDevices()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async bindUser() {
|
||||||
|
const { code } = await this.getPublicKey(this.currentLockInfo.name)
|
||||||
|
console.log('获取公钥返回', code)
|
||||||
|
if(code !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { code: getCommKeyCode } = await this.getCommKey(this.currentLockInfo.name, this.keyId, this.authUid,
|
||||||
|
parseInt(new Date().getTime() / 1000))
|
||||||
|
console.log('获取私钥返回', getCommKeyCode)
|
||||||
|
if(getCommKeyCode !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const timestamp = parseInt(new Date().getTime() / 1000)
|
||||||
|
const { code: addUserCode } = await this.addLockUser({
|
||||||
|
name: this.currentLockInfo.name,
|
||||||
|
keyId: this.keyId,
|
||||||
|
authUid: this.authUid,
|
||||||
|
uid: this.authUid,
|
||||||
|
publicKey: this.currentLockInfo.publicKey,
|
||||||
|
commKey: this.currentLockInfo.commKey,
|
||||||
|
openMode: 1,
|
||||||
|
keyType: 1,
|
||||||
|
startDate: timestamp,
|
||||||
|
expireDate: 0xffffffff,
|
||||||
|
useCountLimit: 0xffff,
|
||||||
|
isRound: 0,
|
||||||
|
weekRound: 0,
|
||||||
|
startHour: 0,
|
||||||
|
startMin: 0,
|
||||||
|
endHour: 0,
|
||||||
|
endMin: 0,
|
||||||
|
role: 0xff,
|
||||||
|
password: (Math.floor(Math.random() * 900000) + 100000).toString()
|
||||||
|
})
|
||||||
|
console.log('添加用户返回', addUserCode)
|
||||||
|
},
|
||||||
|
getLockStatusResult() {
|
||||||
|
const timnestamp = parseInt(new Date().getTime() / 1000)
|
||||||
|
this.getLockStatus({
|
||||||
|
name: this.currentLockInfo.name,
|
||||||
|
uid: this.authUid,
|
||||||
|
nowTime: timnestamp,
|
||||||
|
localTime: timnestamp
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss" scoped>
|
||||||
.content {
|
.content {
|
||||||
|
padding-top: 160rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.button {
|
||||||
height: 200rpx;
|
margin-top: 40rpx;
|
||||||
width: 200rpx;
|
width: 400rpx;
|
||||||
margin: 200rpx auto 50rpx;
|
height: 108rpx;
|
||||||
|
line-height: 108rpx;
|
||||||
|
background: #3F536E;
|
||||||
|
color: #ffffff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-area {
|
.device-list {
|
||||||
display: flex;
|
margin-top: 10rpx;
|
||||||
justify-content: center;
|
height: 100rpx;
|
||||||
}
|
width: 500rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
.title {
|
text-align: center;
|
||||||
font-size: 36rpx;
|
border: #dd524d solid 2rpx;
|
||||||
color: #8f8f94;
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
17
pages/lockDetail/lockDetail.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
167
pages/mine/mine.vue
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="buttonInfo">
|
||||||
|
<image src="/static/images/background_mine.png"
|
||||||
|
class="background-image"></image>
|
||||||
|
<view v-if="isLogin">
|
||||||
|
<view class="view">
|
||||||
|
<view class="view-button" @click="toUsereInfo">
|
||||||
|
<view>个人信息</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<label for="contact">
|
||||||
|
<view class="view-button">
|
||||||
|
<view>客服</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toWebview()">
|
||||||
|
<view>公司介绍</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toWebview('userAgreement')">
|
||||||
|
<view>用户协议</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toWebview('privacy')">
|
||||||
|
<view>隐私政策</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="button-logout" @click="logout">退出</view>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<view class="button-login" @click="login">登录</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button open-type="contact" id="contact"></button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { mapState, mapActions } from 'pinia'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
buttonInfo: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['isLogin'])
|
||||||
|
},
|
||||||
|
async onLoad() {
|
||||||
|
this.buttonInfo = await this.getButtonInfo()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useBasicStore, ['getButtonInfo', 'routeJump']),
|
||||||
|
...mapActions(useUserStore, ['updateLoginStatus', 'login']),
|
||||||
|
toUsereInfo() {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'userInfo'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toWebview(type) {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'webview',
|
||||||
|
params: {
|
||||||
|
type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
logout() {
|
||||||
|
const that = this
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定退出登录吗?',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
uni.removeStorageSync('token')
|
||||||
|
that.updateLoginStatus(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.background-image {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
width: 710rpx;
|
||||||
|
height: 156rpx;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
width: 710rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-button {
|
||||||
|
padding: 0 20rpx 0 40rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
color: #292826;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-arrow {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-line {
|
||||||
|
width: 100%;
|
||||||
|
height: 3rpx;
|
||||||
|
background: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-logout {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 46rpx;
|
||||||
|
bottom: 60rpx;
|
||||||
|
width: 710rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
background: #ec433c;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-login {
|
||||||
|
margin-top: 40vh;
|
||||||
|
border-radius: 46rpx;
|
||||||
|
width: 650rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
line-height: 120rpx;
|
||||||
|
text-align: center;
|
||||||
|
margin-left: 50rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 48rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
137
pages/safeQuestion/safeQuestion.vue
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="text">如果手机丢了,可以通过回答设置的安全问题来登录新设备</view>
|
||||||
|
<view class="safe-question" v-for="item in questionAnswer" :key="item.questionId">
|
||||||
|
<view class="question">
|
||||||
|
<view>{{item.question}}</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="line"></view>
|
||||||
|
<input class="input" :value="item.answer" maxlength="16" placeholder="请输入答案"
|
||||||
|
placeholder-class="input-placeholder" :disabled="true"></input>
|
||||||
|
</view>
|
||||||
|
<view class="button" @click="updateAnswer">修改</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getQuestionAnswerRequest, getQuestionListRequest, updateQuestionAnswerRequest } from '@/api/safeAnswer'
|
||||||
|
import { mapActions } from 'pinia'
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
questionAnswer: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.getQuestionAnswer()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useBasicStore, ['routeJump']),
|
||||||
|
async getQuestionAnswer() {
|
||||||
|
const { code, data, message } = await getQuestionAnswerRequest()
|
||||||
|
if(code === 0) {
|
||||||
|
this.questionAnswer = data
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateAnswer() {
|
||||||
|
this.routeJump({
|
||||||
|
type: 'redirectTo',
|
||||||
|
name: 'updateSafeQuestion'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.text {
|
||||||
|
padding-top: 20rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.safe-question {
|
||||||
|
width: 710rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question {
|
||||||
|
border-radius: 32rpx 32rpx 0 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 32rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-arrow {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border-radius: 0 0 32rpx 32rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
padding: 0 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-placeholder {
|
||||||
|
height: 100rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
width: 100%;
|
||||||
|
height: 2rpx;
|
||||||
|
background: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 100rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
font-size: 32rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
width: 680rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
line-height: 96rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
pages/searchDevice/searchDevice.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
</style>
|
||||||
209
pages/updateEmail/updateEmail.vue
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<input class="input-email" :value="email" placeholder="请输入邮箱"
|
||||||
|
placeholder-class="input-placeholder" :focus="true" @input="updateInputEmail"></input>
|
||||||
|
<view class="view-top">
|
||||||
|
<input type="number" class="input-verify" :value="verificationCode" maxlength="6" placeholder="请输入验证码"
|
||||||
|
placeholder-class="input-placeholder" @input="updateInputCode"></input>
|
||||||
|
<view class="button-verify" @click="getEmailCode">{{text}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="button" @click="toUpdateEmail">确定</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { getEmailCodeRequest, unbindEmailTokenRequest, updateEmailRequest, updateUserInfoRequest } from '@/api/user'
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
import { test } from 'uview-plus'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
text: '获取验证码',
|
||||||
|
verificationCode: '',
|
||||||
|
token: '',
|
||||||
|
email: '',
|
||||||
|
pending: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo'])
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
if(option.token){
|
||||||
|
this.token = option.token
|
||||||
|
} else {
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: '绑定邮箱'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo']),
|
||||||
|
...mapActions(useBasicStore, ['routeJump']),
|
||||||
|
updateInputEmail(data) {
|
||||||
|
this.email = data.detail.value
|
||||||
|
},
|
||||||
|
updateInputCode (data) {
|
||||||
|
this.verificationCode = data.detail.value
|
||||||
|
},
|
||||||
|
async getEmailCode () {
|
||||||
|
if (this.text !== '获取验证码') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(!test.email(this.email)){
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入正确的邮箱',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { code } = await getEmailCodeRequest({
|
||||||
|
account: this.email,
|
||||||
|
channel: '2',
|
||||||
|
codeType: 6
|
||||||
|
})
|
||||||
|
if (code === 0) {
|
||||||
|
this.updateTime()
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '验证码获取失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async toUpdateEmail () {
|
||||||
|
if(!test.email(this.email)){
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入正确的邮箱',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.verificationCode.length === 6 && test.digits(this.verificationCode)) {
|
||||||
|
if(this.pending){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pending = true
|
||||||
|
const params = {
|
||||||
|
verificationCode: this.verificationCode,
|
||||||
|
email: this.email
|
||||||
|
}
|
||||||
|
if(this.token !== ''){
|
||||||
|
params.unbindToken = this.token
|
||||||
|
}
|
||||||
|
const { code, data, message } = await updateEmailRequest(params)
|
||||||
|
if (code === 0) {
|
||||||
|
this.updateUserInfo({
|
||||||
|
...this.userInfo,
|
||||||
|
email: this.email
|
||||||
|
})
|
||||||
|
uni.navigateBack({
|
||||||
|
complete () {
|
||||||
|
uni.showToast({
|
||||||
|
title: '邮箱更新成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '验证码为6位纯数字',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateTime () {
|
||||||
|
let time = 120
|
||||||
|
this.text = `${time} s`
|
||||||
|
const now = new Date().getTime()
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
const second = parseInt((new Date().getTime() - now) / 1000)
|
||||||
|
this.text = `${time - second} s`
|
||||||
|
if (time <= second) {
|
||||||
|
clearInterval(timer)
|
||||||
|
this.text = '获取验证码'
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.input-email {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
margin-top: 48rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 616rpx;
|
||||||
|
padding-left: 32rpx;
|
||||||
|
padding-right: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-verify {
|
||||||
|
margin-top: 48rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 265rpx;
|
||||||
|
line-height: 108rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
|
||||||
|
background: #63b8af;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-top {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-verify {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
margin-top: 48rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 316rpx;
|
||||||
|
padding-left: 32rpx;
|
||||||
|
padding-right: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-placeholder {
|
||||||
|
height: 108rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 108rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
width: 680rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
line-height: 96rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
110
pages/updateName/updateName.vue
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<input class="input" :value="nickname" maxlength="20" placeholder="请输入昵称"
|
||||||
|
placeholder-class="input-placeholder" :focus="true" @input="updateInput"></input>
|
||||||
|
<view class="button" @click="updateName">保存</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { updateUserInfoRequest } from '@/api/user'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
nickname: '',
|
||||||
|
pending: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo'])
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.nickname = this.userInfo.nickname
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo']),
|
||||||
|
updateInput(data) {
|
||||||
|
this.nickname = data.detail.value
|
||||||
|
console.log(data)
|
||||||
|
},
|
||||||
|
async updateName() {
|
||||||
|
if(this.nickname === '') {
|
||||||
|
uni.showToast({
|
||||||
|
title: '昵称不能为空',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(this.pending) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pending = true
|
||||||
|
const { code } = await updateUserInfoRequest({
|
||||||
|
nickname: this.nickname
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
this.updateUserInfo({
|
||||||
|
...this.userInfo,
|
||||||
|
nickname: this.nickname
|
||||||
|
})
|
||||||
|
uni.navigateBack({
|
||||||
|
complete() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '昵称更新成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '昵称更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.input {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
margin-top: 48rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 616rpx;
|
||||||
|
padding-left: 32rpx;
|
||||||
|
padding-right: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-placeholder {
|
||||||
|
height: 108rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 108rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
width: 680rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
line-height: 96rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
143
pages/updatePassword/updatePassword.vue
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<input class="input" :password="true" style="margin-top: 48rpx;" :value="oldPassword" maxlength="20"
|
||||||
|
placeholder="请输入原密码" placeholder-class="input-placeholder" :focus="true" @input="updateOldPassword"></input>
|
||||||
|
<input class="input" :password="true" :value="newPassword" maxlength="20" placeholder="请输入新密码"
|
||||||
|
placeholder-class="input-placeholder" @input="updateNewPassword"></input>
|
||||||
|
<input class="input" :password="true" :value="confirmPassword" maxlength="20" placeholder="请确认密码"
|
||||||
|
placeholder-class="input-placeholder" @input="updateConfirmPassword"></input>
|
||||||
|
<view class="text-tips">密码必须是8-20位,至少包括数字/字母/符号中的2种</view>
|
||||||
|
<view class="button" @click="updatePassword">保存</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { updatePasswordRequest } from '@/api/user'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
oldPassword: '',
|
||||||
|
newPassword: '',
|
||||||
|
confirmPassword: '',
|
||||||
|
pending: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo']),
|
||||||
|
updateOldPassword (data) {
|
||||||
|
this.oldPassword = data.detail.value
|
||||||
|
},
|
||||||
|
updateNewPassword (data) {
|
||||||
|
this.newPassword = data.detail.value
|
||||||
|
},
|
||||||
|
updateConfirmPassword (data) {
|
||||||
|
this.confirmPassword = data.detail.value
|
||||||
|
},
|
||||||
|
async updatePassword () {
|
||||||
|
if (this.oldPassword === '' || this.newPassword === '' || this.confirmPassword === '') {
|
||||||
|
uni.showToast({
|
||||||
|
title: '密码不能为空',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.newPassword.length < 8 || this.newPassword.length > 20 || this.confirmPassword.length < 8 ||
|
||||||
|
this.confirmPassword.length > 20 || this.oldPassword.length < 8 || this.oldPassword.length > 20) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '密码长度必须是8-20位',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.newPassword !== this.confirmPassword) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '两次密码输入不一致',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(this.pending) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pending = true
|
||||||
|
const { code, message } = await updatePasswordRequest({
|
||||||
|
oldPassword: this.oldPassword,
|
||||||
|
newPassword: this.newPassword,
|
||||||
|
date: new Date().getTime()
|
||||||
|
})
|
||||||
|
if (code === 0) {
|
||||||
|
this.updateUserInfo({
|
||||||
|
...this.userInfo,
|
||||||
|
nickname: this.nickname
|
||||||
|
})
|
||||||
|
uni.navigateBack({
|
||||||
|
complete () {
|
||||||
|
uni.showToast({
|
||||||
|
title: '密码重置成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.input {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
margin-top: 24rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 616rpx;
|
||||||
|
padding-left: 32rpx;
|
||||||
|
padding-right: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-placeholder {
|
||||||
|
height: 108rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 108rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
width: 680rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
line-height: 96rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-tips {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 32rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #9B9B9B;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
252
pages/updateSafeQuestion/updateSafeQuestion.vue
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="text">如果手机丢了,可以通过回答设置的安全问题来登录新设备</view>
|
||||||
|
<view class="safe-question">
|
||||||
|
<view class="question" @click="popup('firstList')">
|
||||||
|
<view>{{answer[0].question}}</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="line"></view>
|
||||||
|
<input class="input" :value="answer[0].answer" maxlength="16" placeholder="请输入答案"
|
||||||
|
placeholder-class="input-placeholder" @input="changeFirstAnswer"></input>
|
||||||
|
</view>
|
||||||
|
<view class="safe-question">
|
||||||
|
<view class="question" @click="popup('secondList')">
|
||||||
|
<view>{{answer[1].question}}</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="line"></view>
|
||||||
|
<input class="input" :value="answer[1].answer" maxlength="16" placeholder="请输入答案"
|
||||||
|
placeholder-class="input-placeholder" @input="changeSecondAnswer"></input>
|
||||||
|
</view>
|
||||||
|
<view class="safe-question">
|
||||||
|
<view class="question" @click="popup('thirdList')">
|
||||||
|
<view>{{answer[2].question}}</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="line"></view>
|
||||||
|
<input class="input" :value="answer[2].answer" maxlength="16" placeholder="请输入答案"
|
||||||
|
placeholder-class="input-placeholder" @input="changeThirdAnswer"></input>
|
||||||
|
</view>
|
||||||
|
<view class="button" @click="updateAnswer">保存</view>
|
||||||
|
</view>
|
||||||
|
<up-popup :show="show" mode="bottom" round="16rpx" @close="close">
|
||||||
|
<view class="popup-title">选择问题</view>
|
||||||
|
<view class="line" style="height: 10rpx"></view>
|
||||||
|
<view v-for="item in currentQuestionList" :key="item.questionId" @click="selectQuestion(item)">
|
||||||
|
<view class="popup-content">{{item.question}}</view>
|
||||||
|
<view class="line"></view>
|
||||||
|
</view>
|
||||||
|
<view class="line" style="height: 10rpx"></view>
|
||||||
|
<view class="popup-title" @click="close">取消</view>
|
||||||
|
</up-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getQuestionAnswerRequest, getQuestionListRequest, updateQuestionAnswerRequest } from '@/api/safeAnswer'
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
questionList: {},
|
||||||
|
currentQuestionList: [],
|
||||||
|
currentIndex: 0,
|
||||||
|
answer:[{
|
||||||
|
question: '问题一',
|
||||||
|
answer: ''
|
||||||
|
}, {
|
||||||
|
question: '问题二',
|
||||||
|
answer: ''
|
||||||
|
}, {
|
||||||
|
question: '问题三',
|
||||||
|
answer: ''
|
||||||
|
}],
|
||||||
|
show: false,
|
||||||
|
pending: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo'])
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
this.getQuestionList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo']),
|
||||||
|
async updateAnswer() {
|
||||||
|
console.log('答案', this.answer)
|
||||||
|
for(let i = 0; i < this.answer.length; i++) {
|
||||||
|
if(!this.answer[i].questionId) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '问题不能为空',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(let i = 0; i < this.answer.length; i++) {
|
||||||
|
if(this.answer[i].answer === '') {
|
||||||
|
uni.showToast({
|
||||||
|
title: '答案不能为空',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(this.pending) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.pending = true
|
||||||
|
const { code, message } = await updateQuestionAnswerRequest({
|
||||||
|
questionAndAnswerList: this.answer
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
this.updateUserInfo({
|
||||||
|
...this.userInfo,
|
||||||
|
haveSafeAnswer: 1
|
||||||
|
})
|
||||||
|
uni.navigateBack({
|
||||||
|
complete() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '安全问题设置成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
},
|
||||||
|
changeFirstAnswer(data) {
|
||||||
|
this.answer[0].answer = data.detail.value
|
||||||
|
},
|
||||||
|
changeSecondAnswer(data) {
|
||||||
|
this.answer[1].answer = data.detail.value
|
||||||
|
},
|
||||||
|
changeThirdAnswer(data) {
|
||||||
|
this.answer[2].answer = data.detail.value
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.show = false
|
||||||
|
},
|
||||||
|
selectQuestion(item) {
|
||||||
|
this.answer[this.currentIndex].question = item.question
|
||||||
|
this.answer[this.currentIndex].questionId = item.questionId
|
||||||
|
this.show = false
|
||||||
|
},
|
||||||
|
popup(type) {
|
||||||
|
if(type === 'secondList') {
|
||||||
|
this.currentIndex = 1
|
||||||
|
} else if(type === 'thirdList') {
|
||||||
|
this.currentIndex = 2
|
||||||
|
} else {
|
||||||
|
this.currentIndex = 0
|
||||||
|
}
|
||||||
|
this.currentQuestionList = this.questionList[type]
|
||||||
|
this.show = true
|
||||||
|
},
|
||||||
|
async getQuestionList() {
|
||||||
|
const { code, data, message } = await getQuestionListRequest()
|
||||||
|
if(code === 0) {
|
||||||
|
this.questionList = data
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.text {
|
||||||
|
padding-top: 20rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.safe-question {
|
||||||
|
width: 710rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.question {
|
||||||
|
border-radius: 32rpx 32rpx 0 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx 32rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-arrow {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border-radius: 0 0 32rpx 32rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
line-height: 100rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
padding: 0 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-placeholder {
|
||||||
|
height: 100rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
width: 100%;
|
||||||
|
height: 2rpx;
|
||||||
|
background: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
height: 100rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 100rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
font-size: 32rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
width: 680rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
line-height: 96rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
251
pages/userInfo/userInfo.vue
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="view">
|
||||||
|
<label for="avatar">
|
||||||
|
<view class="view-button">
|
||||||
|
<view>头像</view>
|
||||||
|
<view class="view-button" style="padding: 0">
|
||||||
|
<image class="avatar" :src="userInfo.headUrl" mode="aspectFill"></image>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toUpdateName">
|
||||||
|
<view>昵称</view>
|
||||||
|
<view class="view-button" style="padding: 0">
|
||||||
|
<view class="info">{{userInfo.nickname}}</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button">
|
||||||
|
<view>手机号</view>
|
||||||
|
<view class="view-button" style="padding: 0">
|
||||||
|
<view v-if="userInfo.mobile !== ''" class="info">{{userInfo.mobile}}</view>
|
||||||
|
<view v-else class="red-dot"></view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toUpdateEmail">
|
||||||
|
<view>邮箱</view>
|
||||||
|
<view class="view-button" style="padding: 0">
|
||||||
|
<view v-if="userInfo.email !== ''" class="info">{{userInfo.email}}</view>
|
||||||
|
<view v-else class="red-dot"></view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toUpdatePassword">
|
||||||
|
<view>重置密码</view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button" @click="toSafeQuestion">
|
||||||
|
<view>安全问题</view>
|
||||||
|
<view class="view-button" style="padding: 0">
|
||||||
|
<view v-if="!userInfo.haveSafeAnswer" class="red-dot"></view>
|
||||||
|
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="view-line"></view>
|
||||||
|
<view class="view-button">
|
||||||
|
<view>国家/地区</view>
|
||||||
|
<view class="view-button" style="padding: 0">
|
||||||
|
<view class="info">{{userInfo.countryName}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button open-type="chooseAvatar" style="display:none" id="avatar" @chooseavatar="chooseAvatar"></button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
import { getUploadParamsRequest } from '@/api/file'
|
||||||
|
import { updateUserInfoRequest } from '@/api/user'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pending: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useBasicStore, ['routeJump']),
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo']),
|
||||||
|
chooseAvatar(e) {
|
||||||
|
console.log(e)
|
||||||
|
const that = this
|
||||||
|
|
||||||
|
if(that.pending) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
that.pending = true
|
||||||
|
|
||||||
|
const path = e.detail.avatarUrl
|
||||||
|
const list = path.split('/')
|
||||||
|
const filename = list[list.length - 1]
|
||||||
|
uni.getFileSystemManager().getFileInfo({
|
||||||
|
filePath: path,
|
||||||
|
async success (res) {
|
||||||
|
const size = res.size
|
||||||
|
const { code, data } = await getUploadParamsRequest({
|
||||||
|
size,
|
||||||
|
module: 'avatar',
|
||||||
|
userId: that.userInfo.userId,
|
||||||
|
filename
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
uni.uploadFile({
|
||||||
|
url: data.uploadUrl,
|
||||||
|
filePath: path,
|
||||||
|
name: 'file',
|
||||||
|
formData: data.formData,
|
||||||
|
async success (res) {
|
||||||
|
const { code: updateCode } = await updateUserInfoRequest({
|
||||||
|
headUrl: data.fileUrl
|
||||||
|
})
|
||||||
|
if(updateCode === 0) {
|
||||||
|
that.updateUserInfo({
|
||||||
|
...that.userInfo,
|
||||||
|
headUrl: data.fileUrl
|
||||||
|
})
|
||||||
|
uni.showToast({
|
||||||
|
title: '头像更新成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '头像更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
that.pending = false
|
||||||
|
},
|
||||||
|
fail(res) {
|
||||||
|
console.log('上传失败', res)
|
||||||
|
console.log(data.uploadUrl, path, data.formData)
|
||||||
|
uni.showToast({
|
||||||
|
title: '头像更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
that.pending = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '头像更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
that.pending = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toUpdateName() {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'updateName'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toUpdateEmail() {
|
||||||
|
if(this.userInfo.email === '') {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'updateEmail'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'verifyEmail'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toUpdatePassword() {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'updatePassword'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
toSafeQuestion() {
|
||||||
|
if(this.userInfo.haveSafeAnswer) {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'safeQuestion'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.routeJump({
|
||||||
|
name: 'updateSafeQuestion'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.view {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
width: 710rpx;
|
||||||
|
margin-left: 20rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-button {
|
||||||
|
padding: 0 20rpx 0 40rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
color: #292826;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
text-align: right;
|
||||||
|
width: 400rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red-dot {
|
||||||
|
margin-right: 20rpx;
|
||||||
|
background: #ec433c;
|
||||||
|
width: 20rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-arrow {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-line {
|
||||||
|
width: 100%;
|
||||||
|
height: 3rpx;
|
||||||
|
background: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
182
pages/verifyEmail/verifyEmail.vue
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="view-top">
|
||||||
|
<input type="number" class="input" :value="verificationCode" maxlength="20" placeholder="请输入验证码"
|
||||||
|
placeholder-class="input-placeholder" @input="updateInput"></input>
|
||||||
|
<view class="button-verify" @click="getEmailCode">{{text}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="button" @click="toUpdateEmail">下一步</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapActions, mapState } from 'pinia'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { getEmailCodeRequest, unbindEmailTokenRequest, updateUserInfoRequest } from '@/api/user'
|
||||||
|
import { useBasicStore } from '@/stores/basic'
|
||||||
|
import { test } from 'uview-plus'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
text: '获取验证码',
|
||||||
|
verificationCode: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(useUserStore, ['userInfo'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions(useUserStore, ['updateUserInfo']),
|
||||||
|
...mapActions(useBasicStore, ['routeJump']),
|
||||||
|
async getEmailCode() {
|
||||||
|
if(this.text !== '获取验证码') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { code } = await getEmailCodeRequest({
|
||||||
|
channel: '2',
|
||||||
|
codeType: 7
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
this.updateTime()
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '验证码获取失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async toUpdateEmail() {
|
||||||
|
if(this.verificationCode.length === 6 && test.digits(this.verificationCode)) {
|
||||||
|
const { code, data, message } = await unbindEmailTokenRequest({
|
||||||
|
verificationCode: this.verificationCode
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
this.routeJump({
|
||||||
|
type: 'redirectTo',
|
||||||
|
name: 'updateEmail',
|
||||||
|
params: {
|
||||||
|
token: data.token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '验证码为6位纯数字',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateTime() {
|
||||||
|
let time = 120
|
||||||
|
this.text = `${time} s`
|
||||||
|
const now = new Date().getTime()
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
const second = parseInt((new Date().getTime() - now) / 1000)
|
||||||
|
this.text = `${time - second} s`
|
||||||
|
if (time <= second) {
|
||||||
|
clearInterval(timer)
|
||||||
|
this.text = '获取验证码'
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
updateInput(data) {
|
||||||
|
this.verificationCode = data.detail.value
|
||||||
|
},
|
||||||
|
async updateName() {
|
||||||
|
if(this.nickname === '') {
|
||||||
|
uni.showToast({
|
||||||
|
title: '昵称不能为空',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { code } = await updateUserInfoRequest({
|
||||||
|
nickname: this.nickname
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
this.updateUserInfo({
|
||||||
|
...this.userInfo,
|
||||||
|
nickname: this.nickname
|
||||||
|
})
|
||||||
|
uni.navigateBack({
|
||||||
|
complete() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '昵称更新成功',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '昵称更新失败',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
page {
|
||||||
|
background-color: $uni-bg-color-grey;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.button-verify {
|
||||||
|
margin-top: 48rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 265rpx;
|
||||||
|
line-height: 108rpx;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
|
||||||
|
background: #63b8af;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-top {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
margin-top: 48rpx;
|
||||||
|
height: 108rpx;
|
||||||
|
width: 316rpx;
|
||||||
|
padding-left: 32rpx;
|
||||||
|
padding-right: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-placeholder {
|
||||||
|
height: 108rpx;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 108rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: 32rpx;
|
||||||
|
margin-left: 35rpx;
|
||||||
|
width: 680rpx;
|
||||||
|
height: 96rpx;
|
||||||
|
background: #63b8af;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
line-height: 96rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
40
pages/webview/webview.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<web-view :src="url"></web-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import baseConfig from '@/config/env'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
url: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad: function (options) {
|
||||||
|
console.log(baseConfig.webviewBaseUrl)
|
||||||
|
const officialAccounts = {
|
||||||
|
default: {
|
||||||
|
url: '/app/introduce',
|
||||||
|
name: '介绍'
|
||||||
|
},
|
||||||
|
userAgreement: {
|
||||||
|
url: '/app/userAgreement',
|
||||||
|
name: '用户协议'
|
||||||
|
},
|
||||||
|
privacy: {
|
||||||
|
url: '/app/privacy',
|
||||||
|
name: '隐私政策'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const item = officialAccounts[options?.type] || officialAccounts['default']
|
||||||
|
this.url = baseConfig.webviewBaseUrl + item['url']
|
||||||
|
console.log(this.url)
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: item['name']
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
BIN
static/images/background_mine.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
static/images/icon_add.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
static/images/icon_arrow.png
Normal file
|
After Width: | Height: | Size: 941 B |
BIN
static/images/icon_lock.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
static/images/icon_power.png
Executable file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
static/images/tabbar_key_no_select.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/images/tabbar_key_select.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/images/tabbar_mine_no_select.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
static/images/tabbar_mine_select.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
static/logo.png
|
Before Width: | Height: | Size: 3.9 KiB |
124
stores/basic.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
// 页面配置
|
||||||
|
const pages = [
|
||||||
|
{
|
||||||
|
name: 'home',
|
||||||
|
path: '/pages/home/home',
|
||||||
|
tabBar: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mine',
|
||||||
|
path: '/pages/mine/mine',
|
||||||
|
tabBar: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'userInfo',
|
||||||
|
path: '/pages/userInfo/userInfo',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'updateName',
|
||||||
|
path: '/pages/updateName/updateName',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'updatePassword',
|
||||||
|
path: '/pages/updatePassword/updatePassword',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'updateEmail',
|
||||||
|
path: '/pages/updateEmail/updateEmail',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'verifyEmail',
|
||||||
|
path: '/pages/verifyEmail/verifyEmail',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'safeQuestion',
|
||||||
|
path: '/pages/safeQuestion/safeQuestion',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'updateSafeQuestion',
|
||||||
|
path: '/pages/updateSafeQuestion/updateSafeQuestion',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'webview',
|
||||||
|
path: '/pages/webview/webview',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'lockDetail',
|
||||||
|
path: '/pages/lockDetail/lockDetail',
|
||||||
|
tabBar: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'searchDevice',
|
||||||
|
path: '/pages/searchDevice/searchDevice',
|
||||||
|
tabBar: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
export const useBasicStore = defineStore('basic', {
|
||||||
|
state() {
|
||||||
|
return {
|
||||||
|
// 设备信息
|
||||||
|
deviceInfo: null,
|
||||||
|
// 胶囊按钮的位置信息
|
||||||
|
buttonInfo: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
// 路由跳转
|
||||||
|
/* data 入参 name string页面名称 type string跳转方式 params object传递参数 delta number返回页面数
|
||||||
|
* 具体入参查看文档 https://www.uviewui.com/js/route.html */
|
||||||
|
routeJump(data) {
|
||||||
|
const page = pages.find((page) => {
|
||||||
|
return page.name === data.name
|
||||||
|
})
|
||||||
|
if (page) {
|
||||||
|
uni.$u.route({
|
||||||
|
url: page.path,
|
||||||
|
...data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获取设备信息
|
||||||
|
getDeviceInfo() {
|
||||||
|
const that = this
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (that.deviceInfo?.model) {
|
||||||
|
resolve(that.deviceInfo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.getSystemInfo({
|
||||||
|
success: function (res) {
|
||||||
|
that.deviceInfo = res
|
||||||
|
resolve(that.deviceInfo)
|
||||||
|
},
|
||||||
|
fail: function () {
|
||||||
|
resolve({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取胶囊信息
|
||||||
|
getButtonInfo() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (this.buttonInfo?.top) {
|
||||||
|
resolve(this.buttonInfo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.buttonInfo = uni.getMenuButtonBoundingClientRect()
|
||||||
|
resolve(this.buttonInfo)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
1024
stores/bluetooth.js
Normal file
54
stores/lock.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* @description 锁信息数据持久化
|
||||||
|
*/
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { getLockListRequest } from '@/api/lock'
|
||||||
|
|
||||||
|
export const useLockStore = defineStore('lock', {
|
||||||
|
state() {
|
||||||
|
return {
|
||||||
|
// 锁列表
|
||||||
|
lockList: [],
|
||||||
|
// 锁总数
|
||||||
|
lockTotal: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
getRole(userType) {
|
||||||
|
if(userType === 110301) {
|
||||||
|
return '超级管理员'
|
||||||
|
} else {
|
||||||
|
return '普通用户'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getTimeLimit(keyType) {
|
||||||
|
if(keyType === 1) {
|
||||||
|
return '永久'
|
||||||
|
} else if(keyType === 2) {
|
||||||
|
return '限时'
|
||||||
|
} else if(keyType === 3) {
|
||||||
|
return '单次'
|
||||||
|
} else {
|
||||||
|
return '循环'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getLockList(params) {
|
||||||
|
const { code, data, message } = await getLockListRequest(params)
|
||||||
|
if(code === 0) {
|
||||||
|
this.lockTotal = data.total
|
||||||
|
if(params.pageNo === 1) {
|
||||||
|
this.lockList = data.groupList
|
||||||
|
} else {
|
||||||
|
this.lockList = this.lockList.concat(data.groupList)
|
||||||
|
}
|
||||||
|
return { code }
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return { code, message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -2,16 +2,37 @@
|
|||||||
* @description 用户信息数据持久化
|
* @description 用户信息数据持久化
|
||||||
*/
|
*/
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { getUserInfoRequest } from '@/api/user'
|
||||||
|
import { useLockStore } from '@/stores/lock'
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', {
|
export const useUserStore = defineStore('user', {
|
||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
userInfo: {}
|
// 用户信息
|
||||||
|
userInfo: {},
|
||||||
|
// 登录状态
|
||||||
|
isLogin: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
updateUserInfo(data) {
|
updateUserInfo(data) {
|
||||||
this.userInfo = data
|
this.userInfo = data
|
||||||
|
},
|
||||||
|
updateLoginStatus(status) {
|
||||||
|
this.isLogin = status
|
||||||
|
},
|
||||||
|
async login() {
|
||||||
|
uni.setStorageSync('token', '3021|MZv7iEf0NwjCPSGx4QWs37zOjeVN3GrSJ2v7D56L7db1fcc5')
|
||||||
|
const { code, data } = await getUserInfoRequest()
|
||||||
|
await useLockStore().getLockList({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 50
|
||||||
|
})
|
||||||
|
if(code === 0) {
|
||||||
|
this.updateUserInfo(data)
|
||||||
|
}
|
||||||
|
this.isLogin = true
|
||||||
|
return this.isLogin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
2
uni.scss
@ -32,7 +32,7 @@ $uni-text-color-disable:#c0c0c0;
|
|||||||
|
|
||||||
/* 背景颜色 */
|
/* 背景颜色 */
|
||||||
$uni-bg-color:#ffffff;
|
$uni-bg-color:#ffffff;
|
||||||
$uni-bg-color-grey:#f8f8f8;
|
$uni-bg-color-grey:#f3f3f3;
|
||||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||||
|
|
||||||
|
|||||||
@ -12,9 +12,10 @@ import baseConfig from '@/config/env'
|
|||||||
|
|
||||||
const request = (config) => {
|
const request = (config) => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
const token = config?.token ? config.token : uni.getStorageSync('token')
|
||||||
const headerDefault = {
|
const headerDefault = {
|
||||||
version: baseConfig.version,
|
version: baseConfig.version,
|
||||||
token: config?.token ? config.token : uni.getStorageSync('token')
|
authorization: `Bearer ${token}`
|
||||||
}
|
}
|
||||||
const URL = config.baseUrl ? config.baseUrl + config.url : baseConfig.baseUrl + config.url
|
const URL = config.baseUrl ? config.baseUrl + config.url : baseConfig.baseUrl + config.url
|
||||||
const method = config.method || 'POST'
|
const method = config.method || 'POST'
|
||||||
@ -30,8 +31,29 @@ const request = (config) => {
|
|||||||
async success(res) {
|
async success(res) {
|
||||||
const { statusCode, data } = res
|
const { statusCode, data } = res
|
||||||
if (statusCode === 200) {
|
if (statusCode === 200) {
|
||||||
// 根据情况添加处理代码
|
const code = data.errorCode
|
||||||
resolve(data)
|
const message = data.errorMsg
|
||||||
|
if(code === 403) {
|
||||||
|
uni.removeStorageSync('token')
|
||||||
|
getApp().globalData.updateIsLogin(false)
|
||||||
|
resolve({ code: 403, data, message: '登录已过期' })
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '登录已过期,请重新登录',
|
||||||
|
showCancel: false,
|
||||||
|
success() {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/home/home'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
resolve({
|
||||||
|
code,
|
||||||
|
data: data.data,
|
||||||
|
message
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
resolve({ code: -1, data, message: '网络不太好哦,请稍后再试' })
|
resolve({ code: -1, data, message: '网络不太好哦,请稍后再试' })
|
||||||
}
|
}
|
||||||
@ -49,10 +71,9 @@ const request = (config) => {
|
|||||||
console.log(URL.substring(baseConfig.baseUrl.length + 1), {
|
console.log(URL.substring(baseConfig.baseUrl.length + 1), {
|
||||||
url: URL.substring(baseConfig.baseUrl.length + 1),
|
url: URL.substring(baseConfig.baseUrl.length + 1),
|
||||||
req: config?.data || {},
|
req: config?.data || {},
|
||||||
code: res?.data?.code,
|
code: res?.data?.errorCode,
|
||||||
res: res?.data?.data,
|
res: res?.data?.data,
|
||||||
requestId: res?.header ? res?.header['X-Ca-Request-Id'] : '',
|
token: header?.authorization || '',
|
||||||
token: header?.token || '',
|
|
||||||
duration: new Date().getTime() - timestamp
|
duration: new Date().getTime() - timestamp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||