1. 添加lint 2. 引入star-cloud-uni

This commit is contained in:
范鹏 2025-02-06 11:37:41 +08:00
parent c66735b8b9
commit 150b1a0e75
47 changed files with 13765 additions and 4621 deletions

36
.commitlintrc.cjs Normal file
View File

@ -0,0 +1,36 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [1, 'always'],
'body-max-line-length': [2, 'always', 100],
'footer-leading-blank': [1, 'always'],
'footer-max-line-length': [1, 'always', 100],
'header-max-length': [2, 'always', 100],
'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']],
'subject-empty': [2, 'never'],
'subject-full-stop': [2, 'never', '.'],
'type-case': [2, 'always', 'lower-case'],
'type-empty': [2, 'never'],
'type-enum': [
2,
'always',
[
'build',
'chore',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test',
'conflict',
'fonts',
'delete',
'stash'
]
]
}
}

6
.eslintignore Normal file
View File

@ -0,0 +1,6 @@
dist
node_modules
unpackage
public
.idea
*.md

View File

@ -0,0 +1,79 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"computed": true,
"createApp": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"effectScope": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useLink": true,
"useRoute": true,
"useRouter": true,
"useSlots": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"DirectiveBinding": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"onWatcherCleanup": true,
"useId": true,
"useModel": true,
"useTemplateRef": true
}
}

87
.eslintrc.cjs Normal file
View File

@ -0,0 +1,87 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true
},
globals: {
uni: 'writable',
getApp: 'writable',
wx: 'writable'
},
// 指定如何解析语法
parser: 'vue-eslint-parser',
// 优先级低于 parse 的语法解析配置
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: {
jsx: false
}
},
// 继承某些已有的规则
extends: [
'plugin:vue/vue3-recommended', // 使用插件支持vue3
'airbnb-base',
'plugin:prettier/recommended',
'./.eslintrc-auto-import.json'
],
/**
* "off" 0 ==> 关闭规则
* "warn" 1 ==> 打开的规则作为警告不影响代码执行
* "error" 2 ==> 规则作为一个错误代码不能执行界面报错
*/
rules: {
// eslint (http://eslint.cn/docs/rules)
'prettier/prettier': 'error',
'import/extensions': 0,
'prefer-template': 0,
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['error', { max: 1 }], // 不允许多个空行
'prefer-const': 'off', // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们
'no-irregular-whitespace': 'off', // 禁止不规则的空白\
'import/no-cycle': 0,
'no-nested-ternary': 0,
'import/prefer-default-export': 0,
'import/no-unresolved': 0,
'prefer-destructuring': 0,
'no-shadow': 0,
'no-param-reassign': 0,
'consistent-return': 0,
'no-case-declarations': 0,
'prefer-promise-reject-errors': 0,
'jsx-a11y/click-events-have-key-events': 0,
'jsx-a11y/no-static-element-interactions': 0,
camelcase: 0,
'import/no-extraneous-dependencies': 0,
'no-underscore-dangle': 0,
'no-debugger': 0,
'no-promise-executor-return': 0,
// vue (https://eslint.vuejs.org/rules)
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用此规则仅在启用该no-unused-vars规则时有效。
'vue/v-slot-style': 'error', // 强制执行 v-slot 指令样式
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/no-v-html': 'off', // 禁止使用 v-html
'vue/custom-event-name-casing': 'off', // 为自定义事件名称强制使用特定大小写
'vue/attributes-order': 'off', // vue api使用顺序强制执行属性顺序
'vue/one-component-per-file': 'off', // 强制每个组件都应该在自己的文件中
'vue/html-closing-bracket-newline': 'off', // 在标签的右括号之前要求或禁止换行
'vue/max-attributes-per-line': 'off', // 强制每行的最大属性数
'vue/multiline-html-element-content-newline': 'off', // 在多行元素的内容之前和之后需要换行符
'vue/singleline-html-element-content-newline': 'off', // 在单行元素的内容之前和之后需要换行符
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
'vue/require-default-prop': 'off', // 此规则要求为每个 prop 为必填时,必须提供默认值
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue.prefer-template': 'off',
'vuejs-accessibility/click-events-have-key-events': 'off',
'no-console': 'off',
'no-plusplus': 'off',
'no-await-in-loop': 'off',
'no-async-promise-executor': 'off',
'no-return-await': 'off',
'no-loop-func': 'off',
'no-bitwise': 'off'
}
}

9
.lintstagedrc.json Normal file
View File

@ -0,0 +1,9 @@
{
"src/**/*.{vue,js}": [
"npm run prettier",
"npm run eslint"
],
"src/**/*.{vue,scss,css,less}": [
"npm run stylelint:out"
]
}

6
.prettierignore Normal file
View File

@ -0,0 +1,6 @@
dist
unpackage
node_modules
public
.idea
*.md

22
.prettierrc.json Normal file
View File

@ -0,0 +1,22 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "none",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"bracketSameLine": false,
"arrowParens": "avoid",
"endOfLine": "auto",
"embeddedLanguageFormatting": "auto",
"vueIndentScriptAndStyle": true,
"singleAttributePerLine": false,
"htmlWhitespaceSensitivity": "css",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve"
}

9
.stylelintignore Normal file
View File

@ -0,0 +1,9 @@
/.husky/*
/.vscode/*
/bin
/node_modules/*
/docs/*
/html/*
/dist/*
/public/*
/scripts/*

47
.stylelintrc.cjs Normal file
View File

@ -0,0 +1,47 @@
// @see https://stylelint.bootcss.com/
module.exports = {
extends: [
'stylelint-config-standard', // 配置stylelint拓展插件
'stylelint-config-html/vue', // 配置 vue 中 template 样式格式化
'stylelint-config-standard-scss', // 配置stylelint scss插件
'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化
'stylelint-config-recess-order' // 配置stylelint css属性书写顺序插件,
// 'stylelint-config-prettier', // 配置stylelint和prettier兼容, 注意stylelint大于等于v15是已经不需要此插件
],
overrides: [
{
files: ['**/*.(scss|css|vue|html)'],
customSyntax: 'postcss-scss'
},
{
files: ['**/*.(html|vue)'],
customSyntax: 'postcss-html'
}
],
ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts', '**/*.json', '**/*.md', '**/*.yaml'],
/**
* null => 关闭该规则
* always => 必须
*/
rules: {
'font-family-no-missing-generic-family-keyword': null,
'value-keyword-case': null, // 在 css 中使用 v-bind不报错
'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
'function-url-quotes': 'always', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
'no-empty-source': null, // 关闭禁止空源码
'selector-class-pattern': null, // 关闭强制选择器类名的格式
'property-no-unknown': null, // 禁止未知的属性(true 为不允许)
// 'block-opening-brace-space-before': 'always', //大括号之前必须有一个空格或不能有空白符
'value-no-vendor-prefix': null, // 关闭 属性值前缀 --webkit-box
'property-no-vendor-prefix': null, // 关闭 属性前缀 -webkit-mask
'scss/dollar-variable-pattern': null,
'scss/at-mixin-pattern': null,
'selector-pseudo-class-no-unknown': [
// 不允许未知的选择器
true,
{
ignorePseudoClasses: ['global', 'v-deep', 'deep'] // 忽略属性修改element默认样式的时候能使用到
}
]
}
}

54
App.vue
View File

@ -1,11 +1,12 @@
<script> <script>
import { mapState, mapActions } from 'pinia'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { mapState, mapActions } from 'pinia'
import { getStorage } from './utils/storage' import { getStorage } from './utils/storage'
let firstCheckSetting = true let firstCheckSetting = true
export default { export default {
globalData: { globalData: {
// //
updateIsLogin(isLogin) { updateIsLogin(isLogin) {
@ -16,25 +17,24 @@
// //
envVersion: '', envVersion: '',
// //
getEnvConfig () { getEnvConfig() {
const envVersionStorage = getStorage('envVersion') const envVersionStorage = getStorage('envVersion')
if (envVersionStorage) { if (envVersionStorage) {
return envVersionStorage return envVersionStorage
} else {
if (this.envVersion === 'develop') {
return 'XHJ'
} else if (this.envVersion === 'trial') {
return 'PRE'
} else {
return 'XHJ'
}
} }
if (this.envVersion === 'develop') {
return 'XHJ'
}
if (this.envVersion === 'trial') {
return 'PRE'
}
return 'XHJ'
} }
}, },
computed: { computed: {
...mapState(useBluetoothStore, ['bluetoothStatus']), ...mapState(useBluetoothStore, ['bluetoothStatus'])
}, },
onLaunch: async function() { async onLaunch() {
// //
this.updateMiniProgram() this.updateMiniProgram()
// //
@ -42,20 +42,28 @@
// //
const checkResult = await this.checkSetting() const checkResult = await this.checkSetting()
console.log(checkResult) console.log(checkResult)
if(checkResult === true) { if (checkResult === true) {
this.initAndListenBluetooth(false) this.initAndListenBluetooth(false)
} }
}, },
onShow() { onShow() {
if(firstCheckSetting) { if (firstCheckSetting) {
firstCheckSetting = false firstCheckSetting = false
} else { } else {
this.checkSetting() this.checkSetting()
} }
}, },
methods: { methods: {
...mapActions(useBluetoothStore, ['initBluetooth', 'onBluetoothState', 'updateBluetoothStatus', 'checkSetting', ...mapActions(useBluetoothStore, [
'onBluetoothConnectStatus', 'onBluetoothCharacteristicValueChange', 'updateInitBluetooth', 'initAndListenBluetooth']), 'initBluetooth',
'onBluetoothState',
'updateBluetoothStatus',
'checkSetting',
'onBluetoothConnectStatus',
'onBluetoothCharacteristicValueChange',
'updateInitBluetooth',
'initAndListenBluetooth'
]),
...mapActions(useUserStore, ['updateLoginStatus']), ...mapActions(useUserStore, ['updateLoginStatus']),
// //
updateMiniProgram() { updateMiniProgram() {
@ -65,16 +73,16 @@
title: '更新提示', title: '更新提示',
content: '新版本已经准备好,是否重启应用?', content: '新版本已经准备好,是否重启应用?',
showCancel: false, showCancel: false,
success: function () { success() {
updateManager.applyUpdate() updateManager.applyUpdate()
} }
}) })
}) })
} }
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@import "uview-plus/index.scss"; @import 'uview-plus/index.scss';
</style> </style>

View File

@ -1,105 +1,115 @@
<template> <template>
<view> <view>
<view @click="changeShow" class="name"> <view @click="changeShow" class="name">
<view class="name-text">{{ title }}</view> <view class="name-text">{{ title }}</view>
<view class="picker"> <view class="picker">
{{ timeFormat(time, 'yyyy-mm-dd h:M') }} {{ timeFormat(time, 'yyyy-mm-dd h:M') }}
</view> </view>
</view> </view>
<up-datetime-picker :filter="filter" itemHeight="60" :minDate="minDate" :show="show" <up-datetime-picker
v-model="time" :formatter="formatter" :maxDate="maxDate" :filter="filter"
mode="datetime" @confirm="confirm" :closeOnClickOverlay="true" itemHeight="60"
@close="close" @cancel="close"></up-datetime-picker> :minDate="minDate"
:show="show"
v-model="time"
:formatter="formatter"
:maxDate="maxDate"
mode="datetime"
@confirm="confirm"
:closeOnClickOverlay="true"
@close="close"
@cancel="close"
></up-datetime-picker>
</view> </view>
</template> </template>
<script> <script>
import { timeFormat } from 'uview-plus' import { timeFormat } from 'uview-plus'
export default { export default {
name: 'LockDatetimePicker', name: 'LockDatetimePicker',
props: { props: {
title: String, title: String,
value: Number, value: Number,
minDate: Number, minDate: Number,
maxDate: Number, maxDate: Number,
type: { type: {
type: String, type: String,
default: 'datetime' default: 'datetime'
}
},
data() {
return {
time: 0,
show: false
}
},
created() {
this.time = this.value
},
methods: {
timeFormat,
formatter(type, value) {
if (type === 'year') {
return `${value}`;
} }
if (type === 'month') {
return `${value}`;
}
if (type === 'day') {
return `${value}`;
}
if (type === 'hour') {
return `${value}`;
}
if (type === 'minute') {
return `${value}`;
}
return value;
}, },
filter(mode, options) { data() {
if (mode === 'minute' && this.type === 'datehour') { return {
return options.filter((option) => option === '00') time: 0,
show: false
} }
},
created() {
this.time = this.value
},
methods: {
timeFormat,
formatter(type, value) {
if (type === 'year') {
return `${value}`
}
if (type === 'month') {
return `${value}`
}
if (type === 'day') {
return `${value}`
}
if (type === 'hour') {
return `${value}`
}
if (type === 'minute') {
return `${value}`
}
return value
},
filter(mode, options) {
if (mode === 'minute' && this.type === 'datehour') {
return options.filter(option => option === '00')
}
return options return options
}, },
changeShow() { changeShow() {
this.show = !this.show this.show = !this.show
}, },
close() { close() {
this.show = false this.show = false
}, },
confirm(e) { confirm(e) {
this.show = false this.show = false
this.$emit('changeTime', e.value) this.$emit('changeTime', e.value)
}
} }
} }
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.name { .name {
height: 100rpx;
width: 750rpx;
display: flex;
align-items: center;
background-color: #ffffff;
font-weight: bold;
font-size: 32rpx;
.name-text {
width: 168rpx;
margin-left: 32rpx;
line-height: 100rpx;
}
.picker {
margin-right: 32rpx;
text-align: right;
width: 518rpx;
height: 100rpx; height: 100rpx;
line-height: 100rpx; width: 750rpx;
display: flex;
align-items: center;
background-color: #ffffff;
font-weight: bold;
font-size: 32rpx;
.name-text {
width: 168rpx;
margin-left: 32rpx;
line-height: 100rpx;
}
.picker {
margin-right: 32rpx;
text-align: right;
width: 518rpx;
height: 100rpx;
line-height: 100rpx;
}
} }
}
</style> </style>

View File

@ -2,59 +2,65 @@
<view> <view>
<view class="name"> <view class="name">
<view class="name-text">{{ title }}</view> <view class="name-text">{{ title }}</view>
<input :value="value" class="name-input" :placeholder="placeholder" placeholder-class="placeholder-class" <input
maxlength="50" @input="changeInput"></input> :value="value"
class="name-input"
:placeholder="placeholder"
placeholder-class="placeholder-class"
maxlength="50"
@input="changeInput"
/>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
name: 'LockInput', name: 'LockInput',
props:{ props: {
title: String, title: String,
placeholder: String, placeholder: String,
value: String value: String
}, },
methods: { methods: {
changeInput(e) { changeInput(e) {
this.$emit('changeInput', e.detail.value) this.$emit('changeInput', e.detail.value)
}
} }
}, }
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.name { .name {
height: 100rpx;
width: 750rpx;
display: flex;
align-items: center;
background-color: #ffffff;
.name-text {
width: 168rpx;
margin-left: 32rpx;
font-weight: bold;
font-size: 32rpx;
line-height: 100rpx;
}
.name-input {
margin-right: 32rpx;
text-align: right;
width: 518rpx;
height: 100rpx; height: 100rpx;
width: 750rpx;
display: flex;
align-items: center;
background-color: #ffffff;
.name-text {
width: 168rpx;
margin-left: 32rpx;
font-weight: bold;
font-size: 32rpx;
line-height: 100rpx;
}
.name-input {
margin-right: 32rpx;
text-align: right;
width: 518rpx;
height: 100rpx;
font-size: 32rpx;
line-height: 100rpx;
border: none;
outline: none;
}
}
.placeholder-class {
text-align: right;
font-size: 32rpx; font-size: 32rpx;
line-height: 100rpx; line-height: 100rpx;
border: none;
outline: none;
} }
}
.placeholder-class {
text-align: right;
font-size: 32rpx;
line-height: 100rpx;
}
</style> </style>

View File

@ -1,95 +1,105 @@
<template> <template>
<view> <view>
<view class="spinner-box" :style="{width: size + 'rpx', height: size + 'rpx'}"> <view class="spinner-box" :style="{ width: size + 'rpx', height: size + 'rpx' }">
<view v-if="show" class="circle-border" :style="{width: size * 0.75 + 'rpx', height: size * 0.75 + 'rpx'}"> <view
v-if="show"
class="circle-border"
:style="{ width: size * 0.75 + 'rpx', height: size * 0.75 + 'rpx' }"
>
</view> </view>
<view v-else class="circle-border-stop" :style="{width: size * 0.75 + 'rpx', height: size * 0.75 + 'rpx'}"></view> <view
<view class="circle-core" :style="{width: size * 0.75 - 2 + 'rpx', height: size * 0.75 - 2 + 'rpx'}"> v-else
<image src="/static/images/icon_lock_transparent.png" mode="aspectFill" :style="{width: size * 0.35 + 'rpx', class="circle-border-stop"
height: size * 0.35 + 'rpx'}"></image> :style="{ width: size * 0.75 + 'rpx', height: size * 0.75 + 'rpx' }"
></view>
<view
class="circle-core"
:style="{ width: size * 0.75 - 2 + 'rpx', height: size * 0.75 - 2 + 'rpx' }"
>
<image
src="/static/images/icon_lock_transparent.png"
mode="aspectFill"
:style="{ width: size * 0.35 + 'rpx', height: size * 0.35 + 'rpx' }"
></image>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
export default { export default {
name: "SwitchLoading", name: 'SwitchLoading',
props:{ props: {
size: Number, size: Number
},
data () {
return {
show: false
}
},
methods: {
open () {
this.show = true
}, },
close () { data() {
this.show = false return {
show: false
}
},
methods: {
open() {
this.show = true
},
close() {
this.show = false
}
} }
} }
};
</script> </script>
<style> <style>
@keyframes spin { @keyframes spin {
from { from {
transform: rotate(0); transform: rotate(0);
}
to {
transform: rotate(359deg);
}
} }
to {
transform: rotate(359deg); .spinner-box {
display: flex;
justify-content: center;
align-items: center;
background-color: transparent;
position: relative;
} }
}
.spinner-box { .circle-border {
display: flex; padding: 3upx;
justify-content: center; display: flex;
align-items: center; justify-content: center;
background-color: transparent; align-items: center;
border-radius: 50%;
background: rgb(99, 184, 175);
background: linear-gradient(0deg, rgba(99, 184, 175, 0.1) 33%, rgba(99, 184, 175, 1) 100%);
animation: spin 0.8s linear 0s infinite;
position: relative; position: absolute;
} z-index: 0;
}
.circle-border { .circle-border-stop {
padding: 3upx; padding: 3upx;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 50%; border-radius: 50%;
background: rgb(99, 184, 175); background: rgb(99, 184, 175);
background: linear-gradient( position: absolute;
0deg, z-index: 0;
rgba(99, 184, 175, 0.1) 33%, }
rgba(99, 184, 175, 1) 100%
);
animation: spin 0.8s linear 0s infinite;
position: absolute; .circle-core {
z-index: 0; z-index: 1;
} width: 100%;
height: 100%;
.circle-border-stop { background-color: #ffffff;
padding: 3upx; border-radius: 50%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
border-radius: 50%; }
background: rgb(99, 184, 175);
position: absolute;
z-index: 0;
}
.circle-core {
z-index: 1;
width: 100%;
height: 100%;
background-color: #FFFFFF;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
</style> </style>

View File

@ -1,11 +1,11 @@
let version = '-' let version = '-'
let buildNumber = "-" let buildNumber = '-'
uni.getSystemInfo({ uni.getSystemInfo({
success: function (res) { success(res) {
version = res.appVersion version = res.appVersion
buildNumber = res.appVersionCode buildNumber = res.appVersionCode
} }
}); })
const DEV = { const DEV = {
name: 'dev', name: 'dev',

View File

@ -1,14 +1,14 @@
import App from './App'
import * as Pinia from 'pinia' import * as Pinia from 'pinia'
import { createSSRApp } from 'vue' import { createSSRApp } from 'vue'
import { createUnistorage } from 'pinia-plugin-unistorage' import { createUnistorage } from 'pinia-plugin-unistorage'
import uviewPlus, { setConfig } from 'uview-plus' import uviewPlus, { setConfig } from 'uview-plus'
import App from './App'
setConfig({ setConfig({
config: { config: {
// 修改默认单位为rpx // 修改默认单位为rpx
unit: 'rpx' unit: 'rpx'
}, }
}) })
export function createApp() { export function createApp() {

8119
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,27 @@
"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", "sm-crypto": "^0.3.13",
"star-cloud-uni": "file:../starCloud",
"stylelint": "^16.14.1",
"stylelint-config-recess-order": "^6.0.0",
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-config-standard": "^37.0.0",
"uview-plus": "^3.3.12" "uview-plus": "^3.3.12"
},
"devDependencies": {
"@commitlint/cli": "^19.7.1",
"@commitlint/config-conventional": "^19.7.1",
"commitizen": "^4.3.1",
"cz-git": "^1.11.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-vue": "^9.32.0",
"husky": "^9.1.7",
"lint-staged": "^15.4.3",
"prettier": "^3.4.2",
"vite-plugin-eslint": "^1.8.1"
} }
} }

View File

@ -8,73 +8,77 @@
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return {} return {}
},
computed: {
...mapState(useBluetoothStore, ['bluetoothStatus', 'isInitBluetooth']),
},
methods: {
...mapActions(useBluetoothStore, ['getBluetoothStatus', 'initAndListenBluetooth', 'checkSetting']),
...mapActions(useBasicStore, ['routeJump']),
async toSearchDevice() {
if(this.bluetoothStatus !== 0) {
this.getBluetoothStatus()
return
}
let result = true
if(!this.isInitBluetooth) {
result = await this.initAndListenBluetooth()
}
if(result) {
this.routeJump({
type: 'redirectTo',
name: 'searchDevice'
})
} else {
this.checkSetting()
}
}, },
}, computed: {
} ...mapState(useBluetoothStore, ['bluetoothStatus', 'isInitBluetooth'])
},
methods: {
...mapActions(useBluetoothStore, [
'getBluetoothStatus',
'initAndListenBluetooth',
'checkSetting'
]),
...mapActions(useBasicStore, ['routeJump']),
async toSearchDevice() {
if (this.bluetoothStatus !== 0) {
this.getBluetoothStatus()
return
}
let result = true
if (!this.isInitBluetooth) {
result = await this.initAndListenBluetooth()
}
if (result) {
this.routeJump({
type: 'redirectTo',
name: 'searchDevice'
})
} else {
this.checkSetting()
}
}
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.title { .title {
text-align: center; text-align: center;
margin-top: 200rpx; margin-top: 200rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
} }
.icon { .icon {
width: 300rpx; width: 300rpx;
height: 300rpx; height: 300rpx;
margin: 150rpx 225rpx; margin: 150rpx 225rpx;
} }
.tips { .tips {
text-align: center; text-align: center;
font-size: 28rpx; font-size: 28rpx;
color: #999; color: #999;
margin-bottom: 100rpx; margin-bottom: 100rpx;
font-weight: bold; font-weight: bold;
} }
.button { .button {
width: 600rpx; width: 600rpx;
height: 100rpx; height: 100rpx;
line-height: 100rpx; line-height: 100rpx;
text-align: center; text-align: center;
background-color: #63b8af; background-color: #63b8af;
color: #fff; color: #fff;
border-radius: 50rpx; border-radius: 50rpx;
margin: 0 auto; margin: 0 auto;
font-size: 36rpx; font-size: 36rpx;
} }
</style> </style>

View File

@ -1,195 +1,205 @@
<template> <template>
<view> <view>
<view class="text">如需修改名字请重新命名点击确定添加锁</view> <view class="text">如需修改名字请重新命名点击确定添加锁</view>
<input class="input" :value="name" maxlength="50" placeholder="请输入名称" placeholder-class="input-placeholder" <input
@input="uopdateName" class="input"
></input> :value="name"
maxlength="50"
placeholder="请输入名称"
placeholder-class="input-placeholder"
@input="updateName"
/>
<view class="button" @click="bindLock">确定</view> <view class="button" @click="bindLock">确定</view>
</view> </view>
</template> </template>
<script> <script>
import { useBluetoothStore } from '@/stores/bluetooth' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { useBluetoothStore } from '@/stores/bluetooth'
import { mapActions, mapState } from 'pinia' import { useUserStore } from '@/stores/user'
import { bindLockAdmin } from '@/api/lock' import { bindLockAdmin } from '@/api/lock'
import { useLockStore } from '@/stores/lock' import { useLockStore } from '@/stores/lock'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return { return {
name: '' name: ''
} }
},
computed: {
...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
...mapState(useUserStore, ['userInfo']),
...mapState(useLockStore, ['lockSearch']),
},
onLoad() {
this.name = this.currentLockInfo.name
console.log(this.currentLockInfo)
console.log(this.name)
},
methods: {
...mapActions(useBluetoothStore, ['addLockUser', 'closeBluetoothConnection', 'updateBindedDeviceName',
'closeAllBluetooth', 'initAndListenBluetooth']),
...mapActions(useLockStore, ['getLockList', 'updateLockSearch']),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
uopdateName(data) {
this.name = data.detail.value
}, },
async bindLock() { computed: {
if(this.name === '') { ...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
uni.showToast({ ...mapState(useUserStore, ['userInfo']),
title: '请输入名称', ...mapState(useLockStore, ['lockSearch'])
icon: 'none' },
onLoad() {
this.name = this.currentLockInfo.name
console.log(this.currentLockInfo)
console.log(this.name)
},
methods: {
...mapActions(useBluetoothStore, [
'addLockUser',
'closeBluetoothConnection',
'updateBindedDeviceName',
'closeAllBluetooth',
'initAndListenBluetooth'
]),
...mapActions(useLockStore, ['getLockList', 'updateLockSearch']),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
updateName(data) {
this.name = data.detail.value
},
async bindLock() {
if (this.name === '') {
uni.showToast({
title: '请输入名称',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
uni.showLoading({
title: '添加中',
mask: true
}) })
return this.updateBindedDeviceName(this.currentLockInfo.name)
} const timestamp = parseInt(new Date().getTime() / 1000, 10)
const netWork = await this.getNetworkType() const password = (Math.floor(Math.random() * 900000) + 100000).toString()
if(!netWork) { const { code: addUserCode } = await this.addLockUser({
return name: this.currentLockInfo.name,
} keyId: this.keyId,
uni.showLoading({ authUid: this.userInfo.uid.toString(),
title: '添加中', uid: this.userInfo.uid.toString(),
mask: true openMode: 1,
}) keyType: 0,
this.updateBindedDeviceName(this.currentLockInfo.name) startDate: timestamp,
const timestamp = parseInt(new Date().getTime() / 1000) expireDate: 0xffffffff,
const password = (Math.floor(Math.random() * 900000) + 100000).toString() useCountLimit: 0xffff,
const { code: addUserCode } = await this.addLockUser({ isRound: 0,
name: this.currentLockInfo.name, weekRound: 0,
keyId: this.keyId, startHour: 0,
authUid: this.userInfo.uid.toString(), startMin: 0,
uid: this.userInfo.uid.toString(), endHour: 0,
openMode: 1, endMin: 0,
keyType: 0, role: 0xff,
startDate: timestamp, password
expireDate: 0xffffffff,
useCountLimit: 0xffff,
isRound: 0,
weekRound: 0,
startHour: 0,
startMin: 0,
endHour: 0,
endMin: 0,
role: 0xff,
password
})
if(addUserCode === 0) {
this.closeBluetoothConnection()
this.closeAllBluetooth()
this.initAndListenBluetooth()
} else if(addUserCode === -1) {
uni.hideLoading()
uni.showToast({
title: '添加失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
}) })
return if (addUserCode === 0) {
} else { this.closeBluetoothConnection()
uni.hideLoading() this.closeAllBluetooth()
return this.initAndListenBluetooth()
} } else if (addUserCode === -1) {
const params = { uni.hideLoading()
lockAlias: this.name, uni.showToast({
lockInfo: { title: '添加失败,请靠近设备并保持设备处于唤醒状态',
...this.currentLockInfo.lockConfig, icon: 'none'
adminPwd: password })
}, return
bluetooth: { } else {
bluetoothDeviceName: this.currentLockInfo.name, uni.hideLoading()
bluetoothDeviceId: this.currentLockInfo.deviceId, return
publicKey: this.currentLockInfo.publicKey, }
privateKey: this.currentLockInfo.commKey, const params = {
signKey: this.currentLockInfo.signKey, lockAlias: this.name,
}, lockInfo: {
lockUserNo: this.currentLockInfo.lockUserNo, ...this.currentLockInfo.lockConfig,
pwdTimestamp: this.currentLockInfo.pwdTimestamp, adminPwd: password
featureValue: this.currentLockInfo.featureValue, },
featureSettingValue: this.currentLockInfo.featureSettingValue, bluetooth: {
featureSettingParams: this.currentLockInfo.featureSettingParams bluetoothDeviceName: this.currentLockInfo.name,
} bluetoothDeviceId: this.currentLockInfo.deviceId,
if(this.currentLockInfo.position) { publicKey: this.currentLockInfo.publicKey,
params.position = { privateKey: this.currentLockInfo.commKey,
latitude: this.currentLockInfo.position.latitude, signKey: this.currentLockInfo.signKey
longitude: this.currentLockInfo.position.longitude, },
province: this.currentLockInfo.position.province, lockUserNo: this.currentLockInfo.lockUserNo,
city: this.currentLockInfo.position.city, pwdTimestamp: this.currentLockInfo.pwdTimestamp,
district: this.currentLockInfo.position.district, featureValue: this.currentLockInfo.featureValue,
country: this.currentLockInfo.position.country, featureSettingValue: this.currentLockInfo.featureSettingValue,
township: this.currentLockInfo.position.township, featureSettingParams: this.currentLockInfo.featureSettingParams
address: this.currentLockInfo.position.address }
if (this.currentLockInfo.position) {
params.position = {
latitude: this.currentLockInfo.position.latitude,
longitude: this.currentLockInfo.position.longitude,
province: this.currentLockInfo.position.province,
city: this.currentLockInfo.position.city,
district: this.currentLockInfo.position.district,
country: this.currentLockInfo.position.country,
township: this.currentLockInfo.position.township,
address: this.currentLockInfo.position.address
}
}
const { code, message } = await bindLockAdmin(params)
console.log('添加锁返回', code, message)
if (code === 0) {
this.updateLockSearch({
...this.lockSearch,
pageNo: 1
})
this.getLockList(this.lockSearch)
setTimeout(() => {
uni.hideLoading()
this.backAndToast('添加成功')
}, 1000)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
} }
} }
const { code, message } = await bindLockAdmin(params)
console.log('添加锁返回', code, message)
if(code === 0) {
this.updateLockSearch({
...this.lockSearch,
pageNo: 1
})
this.getLockList(this.lockSearch)
setTimeout(() => {
uni.hideLoading()
this.backAndToast('添加成功')
}, 1000)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} }
}, }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.text { .text {
color: #2b2a28; color: #2b2a28;
padding: 100rpx 0; padding: 100rpx 0;
font-size: 34rpx; font-size: 34rpx;
text-align: center; text-align: center;
} }
.input { .input {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 24rpx; margin-top: 24rpx;
height: 108rpx; height: 108rpx;
width: 616rpx; width: 616rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.input-placeholder { .input-placeholder {
height: 108rpx; height: 108rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
line-height: 108rpx; line-height: 108rpx;
} }
.button { .button {
margin-top: 160rpx; margin-top: 160rpx;
margin-left: 35rpx; margin-left: 35rpx;
width: 680rpx; width: 680rpx;
height: 96rpx; height: 96rpx;
background: #63b8af; background: #63b8af;
border-radius: 16rpx; border-radius: 16rpx;
line-height: 96rpx; line-height: 96rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: #FFFFFF; color: #ffffff;
} }
</style> </style>

View File

@ -1,36 +1,79 @@
<template> <template>
<view> <view>
<view class="tabs"> <view class="tabs">
<up-tabs :list="tabs" lineWidth="40rpx" lineHeight="5rpx" :current="currnetIndex" lineColor="#63b8af" <up-tabs
@click="clickTab" :inactiveStyle="{color:'#a3a3a3', fontSize: '32rpx', fontWeight: 'bold'}" :list="tabs"
:activeStyle="{color:'#63b8af', fontSize: '32rpx', fontWeight: 'bold'}"> lineWidth="40rpx"
lineHeight="5rpx"
:current="currnetIndex"
lineColor="#63b8af"
@click="clickTab"
:inactiveStyle="{ color: '#a3a3a3', fontSize: '32rpx', fontWeight: 'bold' }"
:activeStyle="{ color: '#63b8af', fontSize: '32rpx', fontWeight: 'bold' }"
>
</up-tabs> </up-tabs>
</view> </view>
<swiper :style="{height: deviceInfo.screenHeight - deviceInfo.safeArea.top - 44 + 'px'}" v-if="deviceInfo" <swiper
:list="tabs" :autoplay="false" :style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top - 44 + 'px' }"
:circular="true" :current="currnetIndex" @change="changeSwiper"> v-if="deviceInfo"
:list="tabs"
:autoplay="false"
:circular="true"
:current="currnetIndex"
@change="changeSwiper"
>
<swiper-item> <swiper-item>
<LockInput :value="permanentAccount" title="接收者" placeholder="请输入手机号或邮箱" <LockInput
@changeInput="changePermanentAccountInput"></LockInput> :value="permanentAccount"
<LockInput :value="permanentName" title="姓名" placeholder="请输入姓名" title="接收者"
@changeInput="changePermanentNameInput"></LockInput> placeholder="请输入手机号或邮箱"
<view class="text" style="margin-top: 40rpx;">接收者可使用此小程序开关锁</view> @change-input="changePermanentAccountInput"
<view class="text" style="margin-bottom: 50rpx;">小程序暂不支持邮箱登录若接收者账号为邮箱可先使用星星锁APP登录绑定手机号后可使用小程序登录</view> ></LockInput>
<LockInput
:value="permanentName"
title="姓名"
placeholder="请输入姓名"
@change-input="changePermanentNameInput"
></LockInput>
<view class="text" style="margin-top: 40rpx">接收者可使用此小程序开关锁</view>
<view class="text" style="margin-bottom: 50rpx"
>小程序暂不支持邮箱登录若接收者账号为邮箱可先使用星星锁APP登录绑定手机号后可使用小程序登录</view
>
<view class="button" @click="createKey('permanent')">发送</view> <view class="button" @click="createKey('permanent')">发送</view>
</swiper-item> </swiper-item>
<swiper-item :style="{height: deviceInfo.windowHeight - 44 + 'px'}"> <swiper-item :style="{ height: deviceInfo.windowHeight - 44 + 'px' }">
<LockInput :value="temporaryAccount" title="接收者" placeholder="请输入手机号或邮箱" <LockInput
@changeInput="changeTemporaryAccountInput"></LockInput> :value="temporaryAccount"
<LockInput :value="temporaryName" title="姓名" placeholder="请输入姓名" title="接收者"
@changeInput="changeTemporaryNameInput"></LockInput> placeholder="请输入手机号或邮箱"
@change-input="changeTemporaryAccountInput"
></LockInput>
<LockInput
:value="temporaryName"
title="姓名"
placeholder="请输入姓名"
@change-input="changeTemporaryNameInput"
></LockInput>
<view style="margin-top: 20rpx"> <view style="margin-top: 20rpx">
<LockDatetimePicker title="生效时间" :value="temporaryValidTime" :minDate="minDate" <LockDatetimePicker
@changeTime="changeTemporaryValidTime" :maxDate="maxDate"></LockDatetimePicker> title="生效时间"
<LockDatetimePicker title="失效时间" :value="temporaryInvalidTime" :minDate="minDate" :value="temporaryValidTime"
@changeTime="changeTemporaryInvalidTime" :maxDate="maxDate"></LockDatetimePicker> :minDate="minDate"
@change-time="changeTemporaryValidTime"
:maxDate="maxDate"
></LockDatetimePicker>
<LockDatetimePicker
title="失效时间"
:value="temporaryInvalidTime"
:minDate="minDate"
@change-time="changeTemporaryInvalidTime"
:maxDate="maxDate"
></LockDatetimePicker>
</view> </view>
<view class="text" style="margin-top: 40rpx;">接收者在有效期内可以不限次数使用</view> <view class="text" style="margin-top: 40rpx">接收者在有效期内可以不限次数使用</view>
<view class="text" style="margin-bottom: 50rpx;">小程序暂不支持邮箱登录若接收者账号为邮箱可先使用星星锁APP登录绑定手机号后可使用小程序登录</view> <view class="text" style="margin-bottom: 50rpx"
>小程序暂不支持邮箱登录若接收者账号为邮箱可先使用星星锁APP登录绑定手机号后可使用小程序登录</view
>
<view class="button" @click="createKey('temporary')">发送</view> <view class="button" @click="createKey('temporary')">发送</view>
</swiper-item> </swiper-item>
</swiper> </swiper>
@ -38,200 +81,203 @@
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia'
import { test } from 'uview-plus'
import { useBasicStore } from '@/stores/basic'
import LockInput from '@/components/LockInput/LockInput.vue'
import LockDatetimePicker from '@/components/LockDatetimePicker/LockDatetimePicker.vue'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock'
import { createKeyRequest } from '@/api/key'
import { mapActions, mapState } from 'pinia' export default {
import { useBasicStore } from '@/stores/basic' components: {
import LockInput from '@/components/LockInput/LockInput.vue' LockInput,
import LockDatetimePicker from '@/components/LockDatetimePicker/LockDatetimePicker.vue' LockDatetimePicker
import { createPsaawordRequest } from '@/api/keyboardPwd'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock'
import { test } from 'uview-plus'
import { createKeyRequest } from '@/api/key'
export default {
data () {
return {
tabs: [{
name: '永久'
}, {
name: '限时'
}],
permanentName: '',
permanentAccount: '',
temporaryName: '',
temporaryAccount: '',
temporaryValidTime: Number(new Date()),
temporaryInvalidTime: Number(new Date()),
minDate: Number(new Date()),
maxDate: Number(4133951940000),
currnetIndex: 0,
deviceInfo: null,
pending: false
}
},
components: {
LockInput,
LockDatetimePicker
},
computed: {
...mapState(useBluetoothStore, ['currentLockInfo']),
...mapState(useLockStore, ['keySearch']),
},
async onLoad () {
this.deviceInfo = await this.getDeviceInfo()
// this.temporaryInvalidTime = this.setTime()
},
methods: {
...mapActions(useBasicStore, ['getDeviceInfo', 'backAndToast', 'getNetworkType']),
...mapActions(useLockStore, ['getKeyList', 'updateKeySearch']),
setTime () {
const now = new Date()
now.setMinutes(0, 0, 0)
now.setDate(now.getDate() + 3)
return now.getTime()
}, },
async createKey (type, createUser = false) { data() {
return {
if ((type === 'temporary' && !(test.email(this.temporaryAccount) || test.mobile(this.temporaryAccount))) || tabs: [
(type === 'permanent' && !(test.email(this.permanentAccount) || test.mobile(this.permanentAccount)))) { {
uni.showToast({ name: '永久'
title: '请输入格式正确的手机号或邮箱', },
icon: 'none' {
}) name: '限时'
return
}
if(type === 'temporary' && this.temporaryValidTime >= this.temporaryInvalidTime) {
uni.showToast({
title: '失效时间必须大于生效时间',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
if (this.pending) {
return
}
this.pending = true
let params = {
faceAuthentication: '2',
isRemoteUnlock: '2',
lockId: this.currentLockInfo.lockId,
keyRight: '0',
remarks: '',
countryCode: '86',
createUser: '0'
}
if(createUser) {
params.createUser = '1'
params.usernameType = test.mobile(this.temporaryAccount) ? '1' : '2'
}
if (type === 'temporary') {
params.keyNameForAdmin = this.temporaryName
params.endDate = this.temporaryInvalidTime.toString()
params.keyType = '2'
params.receiverUsername = this.temporaryAccount
params.startDate = this.temporaryValidTime.toString()
} else {
params.keyNameForAdmin = this.permanentName
params.startDate = new Date().getTime().toString()
params.endDate = '0'
params.keyType = '1'
params.receiverUsername = this.permanentAccount
}
const { code, message } = await createKeyRequest(params)
if (code === 0) {
uni.reportEvent("create_key", {
})
this.updateKeySearch({
...this.keySearch,
pageNo: 1
})
this.getKeyList(this.keySearch)
this.backAndToast('钥匙已发送')
} else if(code === 425) {
this.pending = false
uni.showModal({
title: '提示',
content: `是否发送电子钥匙给未注册账号\n${ params.receiverUsername }`,
success: async (res) => {
if (res.confirm) {
await this.createKey(type, true)
}
} }
}) ],
} else { permanentName: '',
uni.showToast({ permanentAccount: '',
title: message, temporaryName: '',
icon: 'none' temporaryAccount: '',
}) temporaryValidTime: Number(new Date()),
temporaryInvalidTime: Number(new Date()),
minDate: Number(new Date()),
maxDate: Number(4133951940000),
currnetIndex: 0,
deviceInfo: null,
pending: false
} }
this.pending = false
}, },
changePermanentAccountInput (e) { computed: {
this.permanentAccount = e ...mapState(useBluetoothStore, ['currentLockInfo']),
...mapState(useLockStore, ['keySearch'])
}, },
changePermanentNameInput (e) { async onLoad() {
this.permanentName = e this.deviceInfo = await this.getDeviceInfo()
// this.temporaryInvalidTime = this.setTime()
}, },
changeTemporaryNameInput (e) { methods: {
this.temporaryName = e ...mapActions(useBasicStore, ['getDeviceInfo', 'backAndToast', 'getNetworkType']),
}, ...mapActions(useLockStore, ['getKeyList', 'updateKeySearch']),
changeTemporaryAccountInput (e) { setTime() {
this.temporaryAccount = e const now = new Date()
}, now.setMinutes(0, 0, 0)
changeTemporaryValidTime (e) { now.setDate(now.getDate() + 3)
this.temporaryValidTime = e
}, return now.getTime()
changeTemporaryInvalidTime (e) { },
this.temporaryInvalidTime = e async createKey(type, createUser = false) {
}, if (
clickTab (data) { (type === 'temporary' &&
this.currnetIndex = data.index !(test.email(this.temporaryAccount) || test.mobile(this.temporaryAccount))) ||
}, (type === 'permanent' &&
changeSwiper (e) { !(test.email(this.permanentAccount) || test.mobile(this.permanentAccount)))
this.currnetIndex = e.detail.current ) {
uni.showToast({
title: '请输入格式正确的手机号或邮箱',
icon: 'none'
})
return
}
if (type === 'temporary' && this.temporaryValidTime >= this.temporaryInvalidTime) {
uni.showToast({
title: '失效时间必须大于生效时间',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
if (this.pending) {
return
}
this.pending = true
let params = {
faceAuthentication: '2',
isRemoteUnlock: '2',
lockId: this.currentLockInfo.lockId,
keyRight: '0',
remarks: '',
countryCode: '86',
createUser: '0'
}
if (createUser) {
params.createUser = '1'
params.usernameType = test.mobile(this.temporaryAccount) ? '1' : '2'
}
if (type === 'temporary') {
params.keyNameForAdmin = this.temporaryName
params.endDate = this.temporaryInvalidTime.toString()
params.keyType = '2'
params.receiverUsername = this.temporaryAccount
params.startDate = this.temporaryValidTime.toString()
} else {
params.keyNameForAdmin = this.permanentName
params.startDate = new Date().getTime().toString()
params.endDate = '0'
params.keyType = '1'
params.receiverUsername = this.permanentAccount
}
const { code, message } = await createKeyRequest(params)
if (code === 0) {
uni.reportEvent('create_key', {})
this.updateKeySearch({
...this.keySearch,
pageNo: 1
})
this.getKeyList(this.keySearch)
this.backAndToast('钥匙已发送')
} else if (code === 425) {
this.pending = false
uni.showModal({
title: '提示',
content: `是否发送电子钥匙给未注册账号\n${params.receiverUsername}`,
success: async res => {
if (res.confirm) {
await this.createKey(type, true)
}
}
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.pending = false
},
changePermanentAccountInput(e) {
this.permanentAccount = e
},
changePermanentNameInput(e) {
this.permanentName = e
},
changeTemporaryNameInput(e) {
this.temporaryName = e
},
changeTemporaryAccountInput(e) {
this.temporaryAccount = e
},
changeTemporaryValidTime(e) {
this.temporaryValidTime = e
},
changeTemporaryInvalidTime(e) {
this.temporaryInvalidTime = e
},
clickTab(data) {
this.currnetIndex = data.index
},
changeSwiper(e) {
this.currnetIndex = e.detail.current
}
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.tabs { .tabs {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.text { .text {
color: #262626; color: #262626;
font-size: 26rpx; font-size: 26rpx;
padding: 0 32rpx; padding: 0 32rpx;
} }
.button { .button {
border-radius: 64rpx; border-radius: 64rpx;
width: 686rpx; width: 686rpx;
margin-left: 32rpx; margin-left: 32rpx;
height: 100rpx; height: 100rpx;
line-height: 100rpx; line-height: 100rpx;
text-align: center; text-align: center;
background-color: #63b8af; background-color: #63b8af;
color: #fff; color: #fff;
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
} }
</style> </style>

View File

@ -1,26 +1,53 @@
<template> <template>
<view> <view>
<view class="tabs"> <view class="tabs">
<up-tabs :list="tabs" lineWidth="40rpx" lineHeight="5rpx" :current="currnetIndex" lineColor="#63b8af" <up-tabs
@click="clickTab" :inactiveStyle="{color:'#a3a3a3', fontSize: '32rpx', fontWeight: 'bold'}" :list="tabs"
:activeStyle="{color:'#63b8af', fontSize: '32rpx', fontWeight: 'bold'}"> lineWidth="40rpx"
lineHeight="5rpx"
:current="currnetIndex"
lineColor="#63b8af"
@click="clickTab"
:inactiveStyle="{ color: '#a3a3a3', fontSize: '32rpx', fontWeight: 'bold' }"
:activeStyle="{ color: '#63b8af', fontSize: '32rpx', fontWeight: 'bold' }"
>
</up-tabs> </up-tabs>
</view> </view>
<swiper :style="{height: deviceInfo.screenHeight - deviceInfo.safeArea.top - 44 + 'px'}" v-if="deviceInfo" <swiper
:list="tabs" :autoplay="false" :style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top - 44 + 'px' }"
:circular="true" :current="currnetIndex" @change="changeSwiper"> v-if="deviceInfo"
:list="tabs"
:autoplay="false"
:circular="true"
:current="currnetIndex"
@change="changeSwiper"
>
<swiper-item> <swiper-item>
<LockInput :value="permanentName" title="姓名" placeholder="请给密码命名" <LockInput
@changeInput="changePermanentInput"></LockInput> :value="permanentName"
title="姓名"
placeholder="请给密码命名"
@change-input="changePermanentInput"
></LockInput>
<view class="text">{{ text }}</view> <view class="text">{{ text }}</view>
<view class="button" @click="createPassword('permanent')">获取密码</view> <view class="button" @click="createPassword('permanent')">获取密码</view>
</swiper-item> </swiper-item>
<swiper-item :style="{height: deviceInfo.windowHeight - 44 + 'px'}"> <swiper-item :style="{ height: deviceInfo.windowHeight - 44 + 'px' }">
<LockInput :value="temporaryName" title="姓名" placeholder="请给密码命名" <LockInput
@changeInput="changeTemporaryInput"></LockInput> :value="temporaryName"
title="姓名"
placeholder="请给密码命名"
@change-input="changeTemporaryInput"
></LockInput>
<view style="margin-top: 20rpx"> <view style="margin-top: 20rpx">
<LockDatetimePicker title="失效时间" :value="temporaryTime" :minDate="minDate" :maxDate="maxDate" type="datehour" <LockDatetimePicker
@changeTime="changeTemporaryTime"></LockDatetimePicker> title="失效时间"
:value="temporaryTime"
:minDate="minDate"
:maxDate="maxDate"
type="datehour"
@change-time="changeTemporaryTime"
></LockDatetimePicker>
</view> </view>
<view class="text">{{ text }}</view> <view class="text">{{ text }}</view>
<view class="button" @click="createPassword('temporary')">获取密码</view> <view class="button" @click="createPassword('temporary')">获取密码</view>
@ -30,203 +57,206 @@
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia'
import { useBasicStore } from '@/stores/basic'
import LockInput from '@/components/LockInput/LockInput.vue'
import LockDatetimePicker from '@/components/LockDatetimePicker/LockDatetimePicker.vue'
import { createPsaawordRequest } from '@/api/keyboardPwd'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock'
import { mapActions, mapState } from 'pinia' export default {
import { useBasicStore } from '@/stores/basic' components: {
import LockInput from '@/components/LockInput/LockInput.vue' LockInput,
import LockDatetimePicker from '@/components/LockDatetimePicker/LockDatetimePicker.vue' LockDatetimePicker
import { createPsaawordRequest } from '@/api/keyboardPwd'
import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock'
export default {
data () {
return {
tabs: [{
name: '永久'
}, {
name: '限时'
}],
permanentName: '',
temporaryName: '',
temporaryTime: Number(new Date()),
minDate: Number(new Date()),
maxDate: Number(4133951940000),
currnetIndex: 0,
deviceInfo: null,
pending: false,
text: '密码生成后请在当日2359前使用一次进行激活否则过0点后未激活则失效。密码激活后有效期内不限次数使用。'
}
},
components: {
LockInput,
LockDatetimePicker
},
computed: {
...mapState(useBluetoothStore, ['currentLockInfo']),
...mapState(useLockStore, ['passwordSearch']),
},
async onLoad() {
this.deviceInfo = await this.getDeviceInfo()
this.temporaryTime = this.setTime()
this.minDate = Number(this.getNextFullHour())
this.maxDate = Number(this.getFutureTimestamp())
},
methods: {
...mapActions(useBasicStore, ['getDeviceInfo', 'backAndToast', 'getNetworkType']),
...mapActions(useLockStore, ['getPasswordList', 'updatePasswordSearch']),
//
getNextFullHour() {
const now = new Date()
const currentHour = now.getHours()
now.setHours(currentHour);
now.setMinutes(0);
now.setSeconds(0);
now.setMilliseconds(0);
return now;
}, },
getFutureTimestamp() { data() {
const currentDate = new Date(); return {
tabs: [
const year = currentDate.getFullYear(); {
const month = currentDate.getMonth(); name: '永久'
const day = currentDate.getDate(); },
{
const futureDate = new Date(year + 3, month, day, 23, 0, 0); name: '限时'
return futureDate.getTime();
},
setTime() {
const now = new Date()
now.setMinutes(0, 0, 0)
return now.getTime()
},
async createPassword(type) {
const that = this
if((type === 'temporary' && this.temporaryName === '') || (type === 'permanent' && this.permanentName === '')) {
uni.showToast({
title: '名称不能为空',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
if(this.pending) {
return
}
this.pending = true
let params = {
lockId: this.currentLockInfo.lockId,
isCoerced: 2,
pwdRight: 0
}
if(type === 'temporary') {
params.keyboardPwdName = this.temporaryName
params.keyboardPwdType = 3
params.startDate = new Date().getTime()
params.endDate = this.temporaryTime
params.hoursStart = 0
params.hoursEnd = 0
} else {
params.startDate = 0
params.endDate = 0
params.keyboardPwdName = this.permanentName
params.keyboardPwdType = 2
params.hoursStart = 0
params.hoursEnd = 0
}
const { code, data, message } = await createPsaawordRequest(params)
if(code === 0) {
uni.reportEvent("create_password", {
})
this.updatePasswordSearch({
...this.passwordSearch,
pageNo: 1
})
this.getPasswordList(this.passwordSearch)
uni.showModal({
title: '密码生成成功',
content: `密码:${data.keyboardPwd}`,
cancelText: '复制',
success: (res) => {
if(res.confirm) {
uni.navigateBack()
} else {
uni.setClipboardData({
data: data.keyboardPwd,
success: () => {
that.backAndToast('复制成功')
}
})
}
} }
}) ],
} else { permanentName: '',
uni.showToast({ temporaryName: '',
title: message, temporaryTime: Number(new Date()),
icon: 'none' minDate: Number(new Date()),
}) maxDate: Number(4133951940000),
currnetIndex: 0,
deviceInfo: null,
pending: false,
text: '密码生成后请在当日2359前使用一次进行激活否则过0点后未激活则失效。密码激活后有效期内不限次数使用。'
} }
this.pending = false
}, },
changePermanentInput(e) { computed: {
this.permanentName = e ...mapState(useBluetoothStore, ['currentLockInfo']),
...mapState(useLockStore, ['passwordSearch'])
}, },
changeTemporaryInput(e) { async onLoad() {
this.temporaryName = e this.deviceInfo = await this.getDeviceInfo()
this.temporaryTime = this.setTime()
this.minDate = Number(this.getNextFullHour())
this.maxDate = Number(this.getFutureTimestamp())
}, },
changeTemporaryTime(e) { methods: {
this.temporaryTime = e ...mapActions(useBasicStore, ['getDeviceInfo', 'backAndToast', 'getNetworkType']),
}, ...mapActions(useLockStore, ['getPasswordList', 'updatePasswordSearch']),
clickTab(data) { //
this.currnetIndex = data.index getNextFullHour() {
}, const now = new Date()
changeSwiper(e) { const currentHour = now.getHours()
this.currnetIndex = e.detail.current now.setHours(currentHour)
now.setMinutes(0)
now.setSeconds(0)
now.setMilliseconds(0)
return now
},
getFutureTimestamp() {
const currentDate = new Date()
const year = currentDate.getFullYear()
const month = currentDate.getMonth()
const day = currentDate.getDate()
const futureDate = new Date(year + 3, month, day, 23, 0, 0)
return futureDate.getTime()
},
setTime() {
const now = new Date()
now.setMinutes(0, 0, 0)
return now.getTime()
},
async createPassword(type) {
const that = this
if (
(type === 'temporary' && this.temporaryName === '') ||
(type === 'permanent' && this.permanentName === '')
) {
uni.showToast({
title: '名称不能为空',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
if (this.pending) {
return
}
this.pending = true
let params = {
lockId: this.currentLockInfo.lockId,
isCoerced: 2,
pwdRight: 0
}
if (type === 'temporary') {
params.keyboardPwdName = this.temporaryName
params.keyboardPwdType = 3
params.startDate = new Date().getTime()
params.endDate = this.temporaryTime
params.hoursStart = 0
params.hoursEnd = 0
} else {
params.startDate = 0
params.endDate = 0
params.keyboardPwdName = this.permanentName
params.keyboardPwdType = 2
params.hoursStart = 0
params.hoursEnd = 0
}
const { code, data, message } = await createPsaawordRequest(params)
if (code === 0) {
uni.reportEvent('create_password', {})
this.updatePasswordSearch({
...this.passwordSearch,
pageNo: 1
})
this.getPasswordList(this.passwordSearch)
uni.showModal({
title: '密码生成成功',
content: `密码:${data.keyboardPwd}`,
cancelText: '复制',
success: res => {
if (res.confirm) {
uni.navigateBack()
} else {
uni.setClipboardData({
data: data.keyboardPwd,
success: () => {
that.backAndToast('复制成功')
}
})
}
}
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.pending = false
},
changePermanentInput(e) {
this.permanentName = e
},
changeTemporaryInput(e) {
this.temporaryName = e
},
changeTemporaryTime(e) {
this.temporaryTime = e
},
clickTab(data) {
this.currnetIndex = data.index
},
changeSwiper(e) {
this.currnetIndex = e.detail.current
}
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.tabs { .tabs {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.text { .text {
margin-top: 40rpx; margin-top: 40rpx;
margin-bottom: 50rpx; margin-bottom: 50rpx;
color: #262626; color: #262626;
font-size: 26rpx; font-size: 26rpx;
padding: 0 32rpx; padding: 0 32rpx;
} }
.button { .button {
border-radius: 64rpx; border-radius: 64rpx;
width: 686rpx; width: 686rpx;
margin-left: 32rpx; margin-left: 32rpx;
height: 100rpx; height: 100rpx;
line-height: 100rpx; line-height: 100rpx;
text-align: center; text-align: center;
background-color: #63b8af; background-color: #63b8af;
color: #fff; color: #fff;
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
} }
</style> </style>

View File

@ -1,62 +1,125 @@
<template> <template>
<view> <view>
<view v-if="!penging"> <view v-if="!penging">
<view v-if="isLogin"> <view v-if="isLogin">
<scroll-view v-if="deviceInfo" scroll-y="true" :style="{ height: deviceInfo.windowHeight + 'px' }" <scroll-view
lower-threshold="100" @refresherrefresh="refresherList" :refresher-enabled="true" @scrolltolower="nextPage" v-if="deviceInfo"
:refresher-triggered="refresherTriggered"> scroll-y="true"
<view class="search" v-if="!(lockList.length === 0 && lockSearch.searchStr === '' && !focus)"> :style="{ height: deviceInfo.windowHeight + 'px' }"
<up-search :searchIconSize="48" :inputStyle="{ fontSize: '32rpx' }" @focus="getFocus" @blur="getBlur" lower-threshold="100"
:height="80" placeholder="搜索" :clearabled="false" @change="changeSearch" @refresherrefresh="refresherList"
v-model="lockSearch.searchStr" bgColor="#ffffff" :showAction="false" maxlength="50"></up-search> :refresher-enabled="true"
@scrolltolower="nextPage"
:refresher-triggered="refresherTriggered"
>
<view
class="search"
v-if="!(lockList.length === 0 && lockSearch.searchStr === '' && !focus)"
>
<up-search
:searchIconSize="48"
:inputStyle="{ fontSize: '32rpx' }"
@focus="getFocus"
@blur="getBlur"
:height="80"
placeholder="搜索"
:clearabled="false"
@change="changeSearch"
v-model="lockSearch.searchStr"
bgColor="#ffffff"
:showAction="false"
maxlength="50"
></up-search>
</view> </view>
<view class="lock-list" v-if="!penging"> <view class="lock-list" v-if="!penging">
<view v-if="lockList.length === 0 && lockSearch.searchStr === '' && !focus"> <view v-if="lockList.length === 0 && lockSearch.searchStr === '' && !focus">
<image src="/static/images/icon_add_round.png" mode="aspectFill" class="button-add-big" <image
@click="toSearchDevice"></image> src="/static/images/icon_add_round.png"
mode="aspectFill"
class="button-add-big"
@click="toSearchDevice"
></image>
<view class="text">添加锁时手机必须在锁旁边</view> <view class="text">添加锁时手机必须在锁旁边</view>
</view> </view>
<view v-else> <view v-else>
<view class="group" v-for="(group, grounIndex) in lockList" :key="group.groupId"> <view class="group" v-for="(group, grounIndex) in lockList" :key="group.groupId">
<view class="group-name"> <view class="group-name">
<view class="group-name-text">{{group.groupName}}</view> <view class="group-name-text">{{ group.groupName }}</view>
<view class="group-name-line"></view> <view class="group-name-line"></view>
</view> </view>
<up-swipe-action> <up-swipe-action>
<up-swipe-action-item class="lock" :ref="'swipeItem' + grounIndex" :options="options" v-for="(lock, <up-swipe-action-item
lockIndex) in group.lockList" :key="lock.lockId" :threshold="50" @click="deleteLock(lock, class="lock"
grounIndex, lockIndex)"> :ref="'swipeItem' + grounIndex"
:options="options"
v-for="(lock, lockIndex) in group.lockList"
:key="lock.lockId"
:threshold="50"
@click="deleteLock(lock, grounIndex, lockIndex)"
>
<view class="lock" @click="toLockDeatil(lock)"> <view class="lock" @click="toLockDeatil(lock)">
<view class="lock-top"> <view class="lock-top">
<image class="lock-image-lock" src="/static/images/icon_lock.png"></image> <image class="lock-image-lock" src="/static/images/icon_lock.png"></image>
<view class="lock-top-right"> <view class="lock-top-right">
<view class="lock-top-right-power"> <view class="lock-top-right-power">
<image class="lock-top-right-power-image" :src="getPowerIcon(lock.electricQuantity)"></image> <image
<view class="lock-top-right-power-text">{{ lock.electricQuantity }}%</view> class="lock-top-right-power-image"
:src="getPowerIcon(lock.electricQuantity)"
></image>
<view class="lock-top-right-power-text"
>{{ lock.electricQuantity }}%</view
>
</view> </view>
<view>{{getRole(lock.userType, lock.keyRight)}}</view> <view>{{ getRole(lock.userType, lock.keyRight) }}</view>
</view> </view>
</view> </view>
<view class="lock-name">{{lock.lockAlias}}</view> <view class="lock-name">{{ lock.lockAlias }}</view>
<view style="display: flex;align-items: center"> <view style="display: flex; align-items: center">
<view v-if="lock.keyStatus === 110412" class="lock-status">已过期</view> <view v-if="lock.keyStatus === 110412" class="lock-status">已过期</view>
<view v-if="lock.days" class="lock-status" style="background-color: #63b8af">{{lock.days}}</view> <view v-if="lock.days" class="lock-status" style="background-color: #63b8af"
<view v-if="lock.keyStatus === 110403" class="lock-status" style="background-color: #63b8af">未生效</view> >{{ lock.days }}</view
>
<view
v-if="lock.keyStatus === 110403"
class="lock-status"
style="background-color: #63b8af"
>未生效</view
>
<view v-if="lock.keyStatus === 110405" class="lock-status">已冻结</view> <view v-if="lock.keyStatus === 110405" class="lock-status">已冻结</view>
<view v-if="(lock.remoteEnable === 1 && lock.keyRight === 0) || <view
(lock.lockSetting.remoteUnlock === 1 && lock.keyRight === 1)" class="lock-status" v-if="
style="background-color: #63b8af">远程开锁 (lock.remoteEnable === 1 && lock.keyRight === 0) ||
(lock.lockSetting.remoteUnlock === 1 && lock.keyRight === 1)
"
class="lock-status"
style="background-color: #63b8af"
>远程开锁
</view> </view>
</view> </view>
<view class="lock-time" <view
:style="{padding: lock.keyStatus === 110401 && !lock.days && class="lock-time"
!((lock.remoteEnable === 1 && lock.keyRight === 0) || (lock.lockSetting.remoteUnlock === 1 :style="{
&& lock.keyRight === 1)) === 0 ? '12rpx 24rpx 0 24rpx' :'6rpx 24rpx 0 24rpx'}"> padding:
<view v-if="lock.keyType === 1 || lock.keyType === 3" style="font-size: 32rpx">{{ lock.keyStatus === 110401 &&
getTimeLimit(lock.keyType) }}</view> !lock.days &&
!(
(lock.remoteEnable === 1 && lock.keyRight === 0) ||
(lock.lockSetting.remoteUnlock === 1 && lock.keyRight === 1)
) === 0
? '12rpx 24rpx 0 24rpx'
: '6rpx 24rpx 0 24rpx'
}"
>
<view
v-if="lock.keyType === 1 || lock.keyType === 3"
style="font-size: 32rpx"
>{{ getTimeLimit(lock.keyType) }}</view
>
<view v-else> <view v-else>
<view>{{ timeFormat(lock.startDate, 'yyyy-mm-dd h:M') }}</view> <view>{{ timeFormat(lock.startDate, 'yyyy-mm-dd h:M') }}</view>
<view>{{ timeFormat(lock.endDate, 'yyyy-mm-dd h:M ') + getTimeLimit(lock.keyType) }}</view> <view>{{
timeFormat(lock.endDate, 'yyyy-mm-dd h:M ') + getTimeLimit(lock.keyType)
}}</view>
</view> </view>
</view> </view>
</view> </view>
@ -66,8 +129,13 @@
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
<image v-if="lockList.length !== 0" src="/static/images/icon_add_round.png" mode="aspectFill" <image
class="button-add" @click="toSearchDevice"></image> v-if="lockList.length !== 0"
src="/static/images/icon_add_round.png"
mode="aspectFill"
class="button-add"
@click="toSearchDevice"
></image>
</view> </view>
<view v-else> <view v-else>
<view class="tips">因智能门锁与账号绑定登录为手机号登录</view> <view class="tips">因智能门锁与账号绑定登录为手机号登录</view>
@ -76,11 +144,22 @@
</label> </label>
</view> </view>
</view> </view>
<button open-type="getPhoneNumber" style="display:none" id="phone" @getphonenumber="getphonenumber"></button> <button
<up-modal :show="showModal" title="是否删除授权管理员钥匙?" :showCancelButton="true" width="600rpx" @cancel="cancelModal" open-type="getPhoneNumber"
@confirm="confirmModal"> style="display: none"
id="phone"
@getphonenumber="getphonenumber"
></button>
<up-modal
:show="showModal"
title="是否删除授权管理员钥匙?"
:showCancelButton="true"
width="600rpx"
@cancel="cancelModal"
@confirm="confirmModal"
>
<view class="slot-content" @click="changeRadio"> <view class="slot-content" @click="changeRadio">
<view style="display: flex;align-items: center;"> <view style="display: flex; align-items: center">
<radio :checked="checked"></radio> <radio :checked="checked"></radio>
<view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view> <view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view>
</view> </view>
@ -91,38 +170,45 @@
<script> <script>
import { timeFormat } from 'uview-plus' import { timeFormat } from 'uview-plus'
import { mapState, mapActions } from 'pinia'
import { getUserInfoRequest, loginRequest } from '@/api/user' import { getUserInfoRequest, loginRequest } from '@/api/user'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useLockStore } from '@/stores/lock' import { useLockStore } from '@/stores/lock'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
import { mapState, mapActions } from 'pinia'
import { deleteKeyRequest } from '@/api/key' import { deleteKeyRequest } from '@/api/key'
import { deleteLockRequest } from '@/api/lock' import { deleteLockRequest } from '@/api/lock'
import { setStorage, getStorage } from '../../utils/storage' import { setStorage, getStorage } from '../../utils/storage'
export default { export default {
data() { data() {
return { return {
refresherTriggered: false, refresherTriggered: false,
focus: false, focus: false,
penging: true, penging: true,
deviceInfo: null, deviceInfo: null,
options: [{ options: [
text: '删除', {
style: { text: '删除',
backgroundColor: '#f56c6c' style: {
backgroundColor: '#f56c6c'
}
} }
}], ],
showModal: false, showModal: false,
checked: false, checked: false,
deleteLockInfo: null deleteLockInfo: null
} }
}, },
computed: { computed: {
...mapState(useUserStore, ['userInfo', 'isLogin']), ...mapState(useUserStore, ['userInfo', 'isLogin']),
...mapState(useLockStore, ['lockList', 'lockTotal', 'lockSearch']), ...mapState(useLockStore, ['lockList', 'lockTotal', 'lockSearch']),
...mapState(useBluetoothStore, ['bluetoothStatus', 'isInitBluetooth', 'keyId', 'currentLockInfo']), ...mapState(useBluetoothStore, [
'bluetoothStatus',
'isInitBluetooth',
'keyId',
'currentLockInfo'
])
}, },
async onLoad(data) { async onLoad(data) {
uni.showLoading({ uni.showLoading({
@ -134,16 +220,13 @@
getApp().globalData.envVersion = accountInfo.miniProgram.envVersion getApp().globalData.envVersion = accountInfo.miniProgram.envVersion
this.deviceInfo = await this.getDeviceInfo() this.deviceInfo = await this.getDeviceInfo()
const token = getStorage('token') const token = getStorage('token')
if(token) { if (token) {
await Promise.all([ await Promise.all([this.getLockList(this.lockSearch), this.getUserInfo()]).then(res => {
this.getLockList(this.lockSearch),
this.getUserInfo()
]).then((res) => {
this.penging = false this.penging = false
uni.hideLoading() uni.hideLoading()
const list = getStorage('lockList') const list = getStorage('lockList')
const userInfo = getStorage('userInfo') const userInfo = getStorage('userInfo')
if(res[0].code === -1 && res[1] === -1 && list && userInfo) { if (res[0].code === -1 && res[1] === -1 && list && userInfo) {
uni.showToast({ uni.showToast({
title: '网络访问失败,请检查网络是否正常', title: '网络访问失败,请检查网络是否正常',
icon: 'none' icon: 'none'
@ -161,57 +244,78 @@
const _data = JSON.parse(JSON.stringify(data)) const _data = JSON.parse(JSON.stringify(data))
this.shareJump(_data) this.shareJump(_data)
}, },
methods: { methods: {
timeFormat, timeFormat,
...mapActions(useUserStore, ['updateUserInfo', 'updateLoginStatus', 'phoneLogin', 'getUserInfo']), ...mapActions(useUserStore, [
...mapActions(useLockStore, ['getLockList', 'updateLockList', 'getRole', 'getTimeLimit', 'updateLockSearch', 'getPowerIcon']), 'updateUserInfo',
...mapActions(useBluetoothStore, ['getBluetoothStatus', 'initAndListenBluetooth', 'updateCurrentLockInfo', 'updateLoginStatus',
'checkSetting', 'updateKeyId', 'resetDevice']), 'phoneLogin',
'getUserInfo'
]),
...mapActions(useLockStore, [
'getLockList',
'updateLockList',
'getRole',
'getTimeLimit',
'updateLockSearch',
'getPowerIcon'
]),
...mapActions(useBluetoothStore, [
'getBluetoothStatus',
'initAndListenBluetooth',
'updateCurrentLockInfo',
'checkSetting',
'updateKeyId',
'resetDevice'
]),
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType', 'shareJump']), ...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType', 'shareJump']),
async deleteLock(lock, groupIndex, lockIndex) { async deleteLock(lock, groupIndex, lockIndex) {
const that = this const that = this
const netWork = await this.getNetworkType() const netWork = await this.getNetworkType()
if(!netWork) { if (!netWork) {
return return
} }
that.$refs['swipeItem' + groupIndex][lockIndex].closeHandler() that.$refs['swipeItem' + groupIndex][lockIndex].closeHandler()
if(lock.userType !== 110301 && lock.keyRight === 1) { if (lock.userType !== 110301 && lock.keyRight === 1) {
this.deleteLockInfo = lock this.deleteLockInfo = lock
this.showModal = true this.showModal = true
return return
} }
const message = lock.userType === 110301 ? '删除锁后,所有信息都会一起删除,确定删除锁吗?' : '确定删除该钥匙吗?' const message =
lock.userType === 110301
? '删除锁后,所有信息都会一起删除,确定删除锁吗?'
: '确定删除该钥匙吗?'
const data = { const data = {
...lock, ...lock,
name: lock.bluetooth.bluetoothDeviceName, name: lock.bluetooth.bluetoothDeviceName,
deviceId: lock.bluetooth.bluetoothDeviceId, deviceId: lock.bluetooth.bluetoothDeviceId,
commKey: lock.bluetooth.privateKey, commKey: lock.bluetooth.privateKey,
signKey: lock.bluetooth.signKey, signKey: lock.bluetooth.signKey,
publicKey: lock.bluetooth.publicKey, publicKey: lock.bluetooth.publicKey
} }
this.updateKeyId(lock.keyId.toString()) this.updateKeyId(lock.keyId.toString())
this.updateCurrentLockInfo(data) this.updateCurrentLockInfo(data)
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: message, content: message,
success: async function (res) { async success(res) {
if (res.confirm) { if (res.confirm) {
uni.showLoading({ uni.showLoading({
title: '删除中', title: '删除中',
mask: true mask: true
}) })
if(that.currentLockInfo.userType === 110301) { if (that.currentLockInfo.userType === 110301) {
const { code: resetDeviceCode } = await that.resetDevice({ const { code: resetDeviceCode } = await that.resetDevice({
name: that.currentLockInfo.name, name: that.currentLockInfo.name,
authUid: that.userInfo.uid.toString(), authUid: that.userInfo.uid.toString(),
keyId: that.keyId.toString() keyId: that.keyId.toString()
}) })
if(resetDeviceCode === 0 || resetDeviceCode === -2) { if (resetDeviceCode === 0 || resetDeviceCode === -2) {
const { code, message } = await deleteLockRequest({ const { code, message } = await deleteLockRequest({
lockId: that.currentLockInfo.lockId lockId: that.currentLockInfo.lockId
}) })
if(code === 0) { if (code === 0) {
uni.hideLoading() uni.hideLoading()
that.updateLockSearch({ that.updateLockSearch({
...that.lockSearch, ...that.lockSearch,
@ -229,7 +333,7 @@
icon: 'none' icon: 'none'
}) })
} }
} else if(resetDeviceCode === -1) { } else if (resetDeviceCode === -1) {
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: '删除失败,请保持在锁附近', title: '删除失败,请保持在锁附近',
@ -240,7 +344,7 @@
const { code } = await deleteKeyRequest({ const { code } = await deleteKeyRequest({
keyId: that.keyId keyId: that.keyId
}) })
if(code === 0) { if (code === 0) {
uni.hideLoading() uni.hideLoading()
that.updateLockSearch({ that.updateLockSearch({
...that.lockSearch, ...that.lockSearch,
@ -274,7 +378,7 @@
includeUnderlings: that.checked ? 1 : 0 includeUnderlings: that.checked ? 1 : 0
}) })
that.showModal = false that.showModal = false
if(code === 0) { if (code === 0) {
uni.hideLoading() uni.hideLoading()
that.updateLockSearch({ that.updateLockSearch({
...that.lockSearch, ...that.lockSearch,
@ -295,16 +399,16 @@
}, },
homeLogin() { homeLogin() {
const that = this const that = this
return new Promise((resolve) => { return new Promise(resolve => {
uni.login({ uni.login({
provider: 'weixin', provider: 'weixin',
success: async function (loginRes) { async success(loginRes) {
const { code, data } = await loginRequest({ const { code, data } = await loginRequest({
js_code: loginRes.code js_code: loginRes.code
}) })
if(code === 0) { if (code === 0) {
await setStorage('openid', data.openid) await setStorage('openid', data.openid)
if(data.accessToken) { if (data.accessToken) {
setStorage('token', data.accessToken) setStorage('token', data.accessToken)
that.getLockList(that.lockSearch) that.getLockList(that.lockSearch)
await that.getUserInfo() await that.getUserInfo()
@ -322,7 +426,7 @@
resolve(false) resolve(false)
} }
}, },
fail: function () { fail() {
uni.showToast({ uni.showToast({
title: '登录失败,请重试', title: '登录失败,请重试',
icon: 'none' icon: 'none'
@ -340,14 +444,14 @@
this.checked = false this.checked = false
}, },
async getphonenumber(data) { async getphonenumber(data) {
if(data.detail.errMsg === 'getPhoneNumber:fail user deny') { if (data.detail.errMsg === 'getPhoneNumber:fail user deny') {
return return
} }
const result = await this.phoneLogin({ const result = await this.phoneLogin({
encryptedData: data.detail.encryptedData, encryptedData: data.detail.encryptedData,
iv: data.detail.iv iv: data.detail.iv
}) })
if(!result) { if (!result) {
uni.showToast({ uni.showToast({
title: '登录失败,请重试', title: '登录失败,请重试',
icon: 'none' icon: 'none'
@ -355,13 +459,13 @@
} }
}, },
async nextPage() { async nextPage() {
if(this.lockList.length < this.lockTotal) { if (this.lockList.length < this.lockTotal) {
const sreach = { const sreach = {
...this.lockSearch, ...this.lockSearch,
pageNo: this.lockSearch.pageNo + 1 pageNo: this.lockSearch.pageNo + 1
} }
const { code } = await this.getLockList(search) const { code } = await this.getLockList(search)
if(code !== 0) { if (code !== 0) {
uni.showToast({ uni.showToast({
title: message, title: message,
icon: 'none' icon: 'none'
@ -378,7 +482,7 @@
pageNo: 1 pageNo: 1
}) })
const { code, message } = await this.getLockList(this.lockSearch) const { code, message } = await this.getLockList(this.lockSearch)
if(code === 0) { if (code === 0) {
uni.showToast({ uni.showToast({
title: '刷新成功', title: '刷新成功',
icon: 'none' icon: 'none'
@ -410,18 +514,18 @@
}) })
}, },
async toLockDeatil(lock) { async toLockDeatil(lock) {
if(!(this.bluetoothStatus === 0 || this.bluetoothStatus === -1)) { if (!(this.bluetoothStatus === 0 || this.bluetoothStatus === -1)) {
this.getBluetoothStatus() this.getBluetoothStatus()
return return
} }
if(lock.keyStatus === 110412) { if (lock.keyStatus === 110412) {
uni.showToast({ uni.showToast({
title: '钥匙已过期', title: '钥匙已过期',
icon: 'none' icon: 'none'
}) })
return return
} }
if(lock.keyStatus === 110405) { if (lock.keyStatus === 110405) {
uni.showToast({ uni.showToast({
title: '钥匙已冻结', title: '钥匙已冻结',
icon: 'none' icon: 'none'
@ -429,17 +533,17 @@
return return
} }
let result = true let result = true
if(!this.isInitBluetooth) { if (!this.isInitBluetooth) {
result = await this.initAndListenBluetooth() result = await this.initAndListenBluetooth()
} }
if(result) { if (result) {
const data = { const data = {
...lock, ...lock,
name: lock.bluetooth.bluetoothDeviceName, name: lock.bluetooth.bluetoothDeviceName,
deviceId: lock.bluetooth.bluetoothDeviceId, deviceId: lock.bluetooth.bluetoothDeviceId,
commKey: lock.bluetooth.privateKey, commKey: lock.bluetooth.privateKey,
signKey: lock.bluetooth.signKey, signKey: lock.bluetooth.signKey,
publicKey: lock.bluetooth.publicKey, publicKey: lock.bluetooth.publicKey
} }
this.updateKeyId(lock.keyId.toString()) this.updateKeyId(lock.keyId.toString())
this.updateCurrentLockInfo(data) this.updateCurrentLockInfo(data)
@ -450,197 +554,197 @@
this.checkSetting() this.checkSetting()
} }
} }
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
.u-swipe-action { .u-swipe-action {
overflow: inherit !important; overflow: inherit !important;
padding-bottom: 32rpx; padding-bottom: 32rpx;
width: 672rpx; width: 672rpx;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
} }
.u-swipe-action-item { .u-swipe-action-item {
margin-top: 32rpx; margin-top: 32rpx;
overflow: inherit !important; overflow: inherit !important;
border-radius: 32rpx !important; border-radius: 32rpx !important;
width: 320rpx; width: 320rpx;
height: 300rpx; height: 300rpx;
} }
.u-swipe-action-item__right { .u-swipe-action-item__right {
border-radius: 32rpx !important; border-radius: 32rpx !important;
} }
.u-swipe-action-item__content { .u-swipe-action-item__content {
border-radius: 32rpx !important; border-radius: 32rpx !important;
} }
.u-swipe-action-item__right__button { .u-swipe-action-item__right__button {
border-radius: 32rpx !important; border-radius: 32rpx !important;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.search { .search {
margin-top: 32rpx; margin-top: 32rpx;
width: 686rpx !important; width: 686rpx !important;
margin-left: 32rpx; margin-left: 32rpx;
}
.button-login {
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 {
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;
line-height: 38rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
.lock-time {
padding: 6rpx 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: 24rpx;
margin-right: 10rpx;
}
}
}
} }
.group { .button-login {
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; width: 672rpx;
margin-top: 32rpx; margin-left: 39rpx;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
.group-name { .lock {
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;
line-height: 38rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
.lock-time {
padding: 6rpx 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: 24rpx;
margin-right: 10rpx;
}
}
}
}
.group {
width: 672rpx; width: 672rpx;
margin-top: 32rpx;
display: flex; display: flex;
align-items: center; flex-wrap: wrap;
font-size: 32rpx; justify-content: space-between;
font-weight: bold;
}
.group-name-text { .group-name {
padding: 0 32rpx; width: 672rpx;
word-break: break-all; display: flex;
} align-items: center;
font-size: 32rpx;
font-weight: bold;
}
.group-name-line { .group-name-text {
flex-grow: 1; padding: 0 32rpx;
height: 3rpx; word-break: break-all;
background: #E5E5E5; }
.group-name-line {
flex-grow: 1;
height: 3rpx;
background: #e5e5e5;
}
} }
} }
}
.button-add-big { .button-add-big {
width: 400rpx; width: 400rpx;
height: 400rpx; height: 400rpx;
margin-top: 300rpx; margin-top: 300rpx;
margin-left: 136rpx; margin-left: 136rpx;
} }
.text { .text {
width: 672rpx; width: 672rpx;
font-size: 32rpx; font-size: 32rpx;
color: #999999; color: #999999;
text-align: center; text-align: center;
margin-top: 32rpx; margin-top: 32rpx;
font-weight: bold; font-weight: bold;
} }
.tips { .tips {
margin-top: 40vh; margin-top: 40vh;
padding: 32rpx 0; padding: 32rpx 0;
text-align: center; text-align: center;
font-size: 28rpx; font-size: 28rpx;
color: #999999; color: #999999;
} }
.lock-status { .lock-status {
margin-top: 5rpx; margin-top: 5rpx;
margin-left: 24rpx; margin-left: 24rpx;
color: #FFFFFF; color: #ffffff;
border-radius: 8rpx; border-radius: 8rpx;
font-size: 22rpx; font-size: 22rpx;
font-weight: bold; font-weight: bold;
display: inline-block; display: inline-block;
padding: 4rpx 8rpx; padding: 4rpx 8rpx;
background-color: #ecab1f; background-color: #ecab1f;
text-align: center; text-align: center;
} }
</style> </style>

View File

@ -13,18 +13,24 @@
<view class="item-content">{{ timeFormat(currentKeyInfo.endDate, 'yyyy-mm-dd') }}</view> <view class="item-content">{{ timeFormat(currentKeyInfo.endDate, 'yyyy-mm-dd') }}</view>
</view> </view>
<view v-else> <view v-else>
<view class="item-content">{{ timeFormat(currentKeyInfo.startDate, 'yyyy-mm-dd h:M') }}</view> <view class="item-content">{{
timeFormat(currentKeyInfo.startDate, 'yyyy-mm-dd h:M')
}}</view>
<view class="item-content">{{ timeFormat(currentKeyInfo.endDate, 'yyyy-mm-dd h:M') }}</view> <view class="item-content">{{ timeFormat(currentKeyInfo.endDate, 'yyyy-mm-dd h:M') }}</view>
</view> </view>
</view> </view>
<view v-if="currentKeyInfo.keyType === 4" class="item" style="margin-top: 2rpx"> <view v-if="currentKeyInfo.keyType === 4" class="item" style="margin-top: 2rpx">
<view class="item-title">有效日</view> <view class="item-title">有效日</view>
<view class="item-content">{{ convertWeekDaysToChineseString(currentKeyInfo.weekDays) }}</view> <view class="item-content">{{
convertWeekDaysToChineseString(currentKeyInfo.weekDays)
}}</view>
</view> </view>
<view class="item" v-if="currentKeyInfo.keyType === 4" style="margin-top: 2rpx"> <view class="item" v-if="currentKeyInfo.keyType === 4" style="margin-top: 2rpx">
<view class="item-title">有效时间</view> <view class="item-title">有效时间</view>
<view class="item-content"> <view class="item-content">
{{ timeFormat(currentKeyInfo.startDate, 'h:M') }}{{ timeFormat(currentKeyInfo.endDate, 'h:M') }} {{ timeFormat(currentKeyInfo.startDate, 'h:M') }}{{
timeFormat(currentKeyInfo.endDate, 'h:M')
}}
</view> </view>
</view> </view>
<view class="item" style="margin-top: 20rpx"> <view class="item" style="margin-top: 20rpx">
@ -40,10 +46,16 @@
<view class="item-content">{{ timeFormat(currentKeyInfo.sendDate, 'yyyy-mm-dd h:M') }}</view> <view class="item-content">{{ timeFormat(currentKeyInfo.sendDate, 'yyyy-mm-dd h:M') }}</view>
</view> </view>
<view class="button" @click="deleteKey">删除</view> <view class="button" @click="deleteKey">删除</view>
<up-modal :show="showModal" title="是否删除授权管理员钥匙?" :showCancelButton="true" width="600rpx" @cancel="cancelModal" <up-modal
@confirm="confirmModal"> :show="showModal"
title="是否删除授权管理员钥匙?"
:showCancelButton="true"
width="600rpx"
@cancel="cancelModal"
@confirm="confirmModal"
>
<view class="slot-content" @click="changeRadio"> <view class="slot-content" @click="changeRadio">
<view style="display: flex;align-items: center;"> <view style="display: flex; align-items: center">
<radio :checked="checked"></radio> <radio :checked="checked"></radio>
<view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view> <view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view>
</view> </view>
@ -53,133 +65,137 @@
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useLockStore } from '@/stores/lock' import { timeFormat } from 'uview-plus'
import { timeFormat } from 'uview-plus' import { useLockStore } from '@/stores/lock'
import { deleteKeyRequest } from '@/api/key' import { deleteKeyRequest } from '@/api/key'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return { return {
showModal: false, showModal: false,
checked: false checked: false
}
},
computed: {
...mapState(useLockStore, ['currentKeyInfo', 'keySearch']),
},
methods: {
timeFormat,
...mapActions(useLockStore, ['updateKeySearch', 'getKeyList', 'convertWeekDaysToChineseString']),
...mapActions(useBasicStore, ['backAndToast']),
cancelModal() {
this.showModal = false
this.checked = false
},
changeRadio() {
this.checked = !this.checked
},
async confirmModal() {
uni.showLoading({
title: '删除中',
mask: true
})
const that = this
const { code } = await deleteKeyRequest({
keyId: that.currentKeyInfo.keyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if(code === 0) {
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
that.getKeyList(that.keySearch)
uni.hideLoading()
that.backAndToast('删除成功')
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
} }
}, },
async deleteKey () { computed: {
const that = this ...mapState(useLockStore, ['currentKeyInfo', 'keySearch'])
if(that.currentKeyInfo.keyRight === 1) { },
that.showModal = true methods: {
return timeFormat,
} ...mapActions(useLockStore, [
uni.showModal({ 'updateKeySearch',
title: '提示', 'getKeyList',
content: '确定要删除该钥匙', 'convertWeekDaysToChineseString'
async success(res) { ]),
if(res.confirm) { ...mapActions(useBasicStore, ['backAndToast']),
uni.showLoading({ cancelModal() {
title: '删除中', this.showModal = false
mask: true this.checked = false
}) },
const { code: requestCode, message } = await deleteKeyRequest({ changeRadio() {
keyId: that.currentKeyInfo.keyId this.checked = !this.checked
}) },
if(requestCode === 0) { async confirmModal() {
uni.hideLoading() uni.showLoading({
that.updateKeySearch({ title: '删除中',
...that.keySearch, mask: true
pageNo: 1 })
const that = this
const { code } = await deleteKeyRequest({
keyId: that.currentKeyInfo.keyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if (code === 0) {
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
that.getKeyList(that.keySearch)
uni.hideLoading()
that.backAndToast('删除成功')
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
},
async deleteKey() {
const that = this
if (that.currentKeyInfo.keyRight === 1) {
that.showModal = true
return
}
uni.showModal({
title: '提示',
content: '确定要删除该钥匙',
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
}) })
await that.getKeyList(that.keySearch) const { code: requestCode, message } = await deleteKeyRequest({
that.backAndToast('删除成功') keyId: that.currentKeyInfo.keyId
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
}) })
if (requestCode === 0) {
uni.hideLoading()
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
await that.getKeyList(that.keySearch)
that.backAndToast('删除成功')
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} }
} }
} })
}) }
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.item { .item {
padding: 24rpx 32rpx; padding: 24rpx 32rpx;
background-color: #FFFFFF; background-color: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
font-size: 32rpx; font-size: 32rpx;
font-weight: 500; font-weight: 500;
} }
.tips { .tips {
padding: 24rpx 32rpx; padding: 24rpx 32rpx;
font-size: 24rpx; font-size: 24rpx;
color: #999999; color: #999999;
} }
.button { .button {
margin: 32rpx; margin: 32rpx;
width: 686rpx; width: 686rpx;
height: 88rpx; height: 88rpx;
background-color: #df282d; background-color: #df282d;
color: white; color: white;
text-align: center; text-align: center;
line-height: 88rpx; line-height: 88rpx;
border-radius: 44rpx; border-radius: 44rpx;
font-weight: bold; font-weight: bold;
} }
</style> </style>

View File

@ -1,32 +1,74 @@
<template> <template>
<view> <view>
<scroll-view v-if="deviceInfo" scroll-y="true" :style="{height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px'}" lower-threshold="100" <scroll-view
@refresherrefresh="refresherList" :refresher-enabled="true" @scrolltolower="nextPage" v-if="deviceInfo"
:refresher-triggered="refresherTriggered"> scroll-y="true"
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px' }"
lower-threshold="100"
@refresherrefresh="refresherList"
:refresher-enabled="true"
@scrolltolower="nextPage"
:refresher-triggered="refresherTriggered"
>
<view class="search"> <view class="search">
<up-search shape="square" :searchIconSize="48" :inputStyle="{ fontSize: '32rpx' }" :height="80" placeholder="搜索" <up-search
:clearabled="false" @change="changeSearch" shape="square"
v-model="keySearch.searchStr" bgColor="#ffffff" :showAction="false" maxlength="50"></up-search> :searchIconSize="48"
:inputStyle="{ fontSize: '32rpx' }"
:height="80"
placeholder="搜索"
:clearabled="false"
@change="changeSearch"
v-model="keySearch.searchStr"
bgColor="#ffffff"
:showAction="false"
maxlength="50"
></up-search>
</view> </view>
<view style="padding: 32rpx 0 calc(env(safe-area-inset-bottom) + 250rpx) 0"> <view style="padding: 32rpx 0 calc(env(safe-area-inset-bottom) + 250rpx) 0">
<view v-if="keyList.length === 0 && requestFinished"> <view v-if="keyList.length === 0 && requestFinished">
<image class="empty-list" src="/static/images/background_empty_list.png" mode="aspectFill"></image> <image
class="empty-list"
src="/static/images/background_empty_list.png"
mode="aspectFill"
></image>
<view class="empty-list-text">暂无数据</view> <view class="empty-list-text">暂无数据</view>
</view> </view>
<view v-else> <view v-else>
<up-swipe-action> <up-swipe-action>
<up-swipe-action-item ref="swipeItem" :options="options" v-for="(key, index) in keyList" <up-swipe-action-item
:key="key.keyboardPwdId" :threshold="50" @click="deleteKey(key)"> ref="swipeItem"
:options="options"
v-for="key in keyList"
:key="key.keyboardPwdId"
:threshold="50"
@click="deleteKey(key)"
>
<view class="key" @click="toKeyDetail(key)"> <view class="key" @click="toKeyDetail(key)">
<image class="key-left" :src="key.headUrl === '' ? '/static/images/icon_user.png' : key.headUrl" <image
mode="aspectFill"></image> class="key-left"
:src="key.headUrl === '' ? '/static/images/icon_user.png' : key.headUrl"
mode="aspectFill"
></image>
<view class="key-right"> <view class="key-right">
<view style="display: flex;"> <view style="display: flex">
<view class="key-right-top">{{ key.keyName }}</view> <view class="key-right-top">{{ key.keyName }}</view>
<image class="key-admin" mode="aspectFill" v-if="key.remoteEnable === 1" <image
src="/static/images/icon_remote_unlock.png"></image> class="key-admin"
<image class="key-admin" mode="aspectFill" v-if="key.keyRight === 1" src="/static/images/icon_admin.png"></image> mode="aspectFill"
<view class="key-status" :style="{ color: (key.keyStatus === 110401) ? '#63b8af' : '#df282d' }"> v-if="key.remoteEnable === 1"
src="/static/images/icon_remote_unlock.png"
></image>
<image
class="key-admin"
mode="aspectFill"
v-if="key.keyRight === 1"
src="/static/images/icon_admin.png"
></image>
<view
class="key-status"
:style="{ color: key.keyStatus === 110401 ? '#63b8af' : '#df282d' }"
>
{{ getKeyStatus(key.keyStatus) }} {{ getKeyStatus(key.keyStatus) }}
</view> </view>
</view> </view>
@ -43,10 +85,16 @@
<view class="button-reset" @click="resetKey">重置钥匙</view> <view class="button-reset" @click="resetKey">重置钥匙</view>
<view class="button-create" @click="toCreateKey">发送钥匙</view> <view class="button-create" @click="toCreateKey">发送钥匙</view>
</view> </view>
<up-modal :show="showModal" title="是否删除授权管理员钥匙?" :showCancelButton="true" width="600rpx" @cancel="cancelModal" <up-modal
@confirm="confirmModal"> :show="showModal"
title="是否删除授权管理员钥匙?"
:showCancelButton="true"
width="600rpx"
@cancel="cancelModal"
@confirm="confirmModal"
>
<view class="slot-content" @click="changeRadio"> <view class="slot-content" @click="changeRadio">
<view style="display: flex;align-items: center;"> <view style="display: flex; align-items: center">
<radio :checked="checked"></radio> <radio :checked="checked"></radio>
<view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view> <view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view>
</view> </view>
@ -56,360 +104,367 @@
</template> </template>
<script> <script>
import { useBasicStore } from '@/stores/basic' import { mapActions, mapState } from 'pinia'
import { mapActions, mapState } from 'pinia' import { useBasicStore } from '@/stores/basic'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock' import { useLockStore } from '@/stores/lock'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { deletePsaawordRequest, resetPsaawordListRequest } from '@/api/keyboardPwd' import { deleteKeyRequest, resetKeyRequest } from '@/api/key'
import { deleteKeyRequest, resetKeyRequest } from '@/api/key'
export default { export default {
data () { data() {
return { return {
showModal: false, showModal: false,
checked: false, checked: false,
deviceInfo: null, deviceInfo: null,
refresherTriggered: false, refresherTriggered: false,
requestFinished: false, requestFinished: false,
options: [{ options: [
text: '删除', {
style: { text: '删除',
backgroundColor: '#f56c6c' style: {
} backgroundColor: '#f56c6c'
}], }
deleteKeyId: '' }
} ],
}, deleteKeyId: ''
computed: { }
...mapState(useUserStore, ['userInfo']),
...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
...mapState(useLockStore, ['keyTotal', 'keyList', 'keySearch']),
},
async onLoad() {
uni.showLoading({
title: '加载中',
mask: true
})
this.deviceInfo = await this.getDeviceInfo()
this.updateKeySearch({
...this.keySearch,
lockId: this.currentLockInfo.lockId
})
const { code, message } = await this.getKeyList(this.keySearch)
uni.hideLoading()
this.requestFinished = true
if(code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
onUnload() {
this.clearList('key')
},
methods: {
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo']),
...mapActions(useLockStore, ['getKeyList', 'updateCurrentKeyInfo', 'updateKeySearch', 'getKeyStatus', 'clearList']),
changeRadio() {
this.checked = !this.checked
}, },
async confirmModal() { computed: {
...mapState(useUserStore, ['userInfo']),
...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
...mapState(useLockStore, ['keyTotal', 'keyList', 'keySearch'])
},
async onLoad() {
uni.showLoading({ uni.showLoading({
title: '删除中', title: '加载中',
mask: true mask: true
}) })
const that = this this.deviceInfo = await this.getDeviceInfo()
const { code } = await deleteKeyRequest({
keyId: that.deleteKeyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if(code === 0) {
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
that.getKeyList(that.keySearch)
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'none'
})
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
},
cancelModal() {
this.showModal = false
this.checked = false
},
toKeyDetail(key) {
this.updateCurrentKeyInfo(key)
this.routeJump({
name: 'keyDetail'
})
},
async deleteKey(data) {
const key = data
const that = this
let index = this.keyList.findIndex(item => item.keyId === key.keyId)
that.$refs.swipeItem[index].closeHandler()
if(data.keyRight === 1) {
this.deleteKeyId = key.keyId
this.showModal = true
return
}
uni.showModal({
title: '提示',
content: '确定要删除该钥匙',
async success(res) {
if(res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
})
const { code: requestCode, message } = await deleteKeyRequest({
keyId: key.keyId
})
if(requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'none'
})
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
await that.getKeyList(that.keySearch)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
async resetKey() {
const that = this
if(that.keyList.length === 0) {
uni.showToast({
title: '暂无钥匙,无需重置',
icon: 'none'
})
return
}
uni.showModal({
title: '提示',
content: '确定要重置钥匙,该锁的所有钥匙都将被删除',
async success(res) {
if(res.confirm) {
const { code: requestCode, message } = await resetKeyRequest({
lockId: that.currentLockInfo.lockId,
})
console.log('重置钥匙返回', requestCode, message)
if(requestCode === 0) {
uni.showToast({
title: '重置钥匙成功',
icon: 'none'
})
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
await that.getKeyList(that.keySearch)
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
toCreateKey() {
this.routeJump({
name: 'createKey'
})
},
async refresherList() {
this.refresherTriggered = true
this.updateKeySearch({ this.updateKeySearch({
...this.keySearch, ...this.keySearch,
pageNo: 1 lockId: this.currentLockInfo.lockId
}) })
const { code, message } = await this.getKeyList(this.keySearch) const { code, message } = await this.getKeyList(this.keySearch)
if(code === 0) { uni.hideLoading()
uni.showToast({ this.requestFinished = true
title: '刷新成功', if (code !== 0) {
icon: 'none'
})
} else {
uni.showToast({ uni.showToast({
title: message, title: message,
icon: 'none' icon: 'none'
}) })
} }
this.refresherTriggered = false
}, },
async nextPage() { onUnload() {
if(this.keyTotal <= this.keySearch.pageNo * this.keySearch.pageSize) { this.clearList('key')
return },
} methods: {
const pageNo = this.keySearch.pageNo + 1 ...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo']),
const params = { ...mapActions(useLockStore, [
...this.keySearch, 'getKeyList',
pageNo 'updateCurrentKeyInfo',
} 'updateKeySearch',
const { code, message } = await this.getKeyList(params) 'getKeyStatus',
if(code === 0) { 'clearList'
]),
changeRadio() {
this.checked = !this.checked
},
async confirmModal() {
uni.showLoading({
title: '删除中',
mask: true
})
const that = this
const { code } = await deleteKeyRequest({
keyId: that.deleteKeyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if (code === 0) {
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
that.getKeyList(that.keySearch)
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'none'
})
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
},
cancelModal() {
this.showModal = false
this.checked = false
},
toKeyDetail(key) {
this.updateCurrentKeyInfo(key)
this.routeJump({
name: 'keyDetail'
})
},
async deleteKey(data) {
const key = data
const that = this
let index = this.keyList.findIndex(item => item.keyId === key.keyId)
that.$refs.swipeItem[index].closeHandler()
if (data.keyRight === 1) {
this.deleteKeyId = key.keyId
this.showModal = true
return
}
uni.showModal({
title: '提示',
content: '确定要删除该钥匙',
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
})
const { code: requestCode, message } = await deleteKeyRequest({
keyId: key.keyId
})
if (requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'none'
})
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
await that.getKeyList(that.keySearch)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
async resetKey() {
const that = this
if (that.keyList.length === 0) {
uni.showToast({
title: '暂无钥匙,无需重置',
icon: 'none'
})
return
}
uni.showModal({
title: '提示',
content: '确定要重置钥匙,该锁的所有钥匙都将被删除',
async success(res) {
if (res.confirm) {
const { code: requestCode, message } = await resetKeyRequest({
lockId: that.currentLockInfo.lockId
})
console.log('重置钥匙返回', requestCode, message)
if (requestCode === 0) {
uni.showToast({
title: '重置钥匙成功',
icon: 'none'
})
that.updateKeySearch({
...that.keySearch,
pageNo: 1
})
await that.getKeyList(that.keySearch)
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
toCreateKey() {
this.routeJump({
name: 'createKey'
})
},
async refresherList() {
this.refresherTriggered = true
this.updateKeySearch({ this.updateKeySearch({
...this.keySearch,
pageNo: 1
})
const { code, message } = await this.getKeyList(this.keySearch)
if (code === 0) {
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.refresherTriggered = false
},
async nextPage() {
if (this.keyTotal <= this.keySearch.pageNo * this.keySearch.pageSize) {
return
}
const pageNo = this.keySearch.pageNo + 1
const params = {
...this.keySearch, ...this.keySearch,
pageNo pageNo
}
const { code, message } = await this.getKeyList(params)
if (code === 0) {
this.updateKeySearch({
...this.keySearch,
pageNo
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
},
async changeSearch(data) {
this.updateKeySearch({
...this.keySearch,
searchStr: data
}) })
} else { const { code, message } = await this.getKeyList(this.keySearch)
uni.showToast({ if (code !== 0) {
title: message, uni.showToast({
icon: 'none' title: message,
}) icon: 'none'
})
}
} }
}, }
async changeSearch(data) { }
this.updateKeySearch({
...this.keySearch,
searchStr: data
})
const { code, message } = await this.getKeyList(this.keySearch)
if(code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
},
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.search { .search {
margin-top: 32rpx; margin-top: 32rpx;
width: 686rpx !important; width: 686rpx !important;
margin-left: 32rpx;
}
.button {
display: flex;
align-items: center;
position: fixed;
bottom: calc(env(safe-area-inset-bottom) + 48rpx);
font-weight: bold;
.button-reset {
margin-left: 50rpx;
width: 300rpx;
height: 88rpx;
background-color: #df282d;
color: white;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
}
.button-create {
margin-left: 50rpx;
width: 300rpx;
height: 88rpx;
background-color: #63b8af;
color: white;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
}
}
.key {
display: flex;
align-items: center;
background-color: #FFFFFF;
height: 120rpx;
width: 750rpx;
.key-left {
margin-left: 32rpx; margin-left: 32rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
} }
.key-right { .button {
margin-left: 32rpx; display: flex;
margin-right: 32rpx; align-items: center;
width: 574rpx; position: fixed;
bottom: calc(env(safe-area-inset-bottom) + 48rpx);
font-weight: bold;
.key-right-top { .button-reset {
max-width: 400rpx; margin-left: 50rpx;
font-size: 32rpx; width: 300rpx;
font-weight: bold; height: 88rpx;
padding-bottom: 6rpx; background-color: #df282d;
white-space: nowrap; color: white;
overflow: hidden; text-align: center;
text-overflow: ellipsis; line-height: 88rpx;
border-radius: 44rpx;
} }
.key-admin { .button-create {
margin-top: 8rpx; margin-left: 50rpx;
margin-left: 10rpx; width: 300rpx;
width: 25rpx; height: 88rpx;
height: 25rpx; background-color: #63b8af;
} color: white;
text-align: center;
.key-right-bottom { line-height: 88rpx;
font-size: 24rpx; border-radius: 44rpx;
color: #999999;
} }
} }
.key-status { .key {
margin-top: 4rpx; display: flex;
margin-left: auto; align-items: center;
font-size: 26rpx; background-color: #ffffff;
color: #63b8af; height: 120rpx;
width: 750rpx;
.key-left {
margin-left: 32rpx;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.key-right {
margin-left: 32rpx;
margin-right: 32rpx;
width: 574rpx;
.key-right-top {
max-width: 400rpx;
font-size: 32rpx;
font-weight: bold;
padding-bottom: 6rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.key-admin {
margin-top: 8rpx;
margin-left: 10rpx;
width: 25rpx;
height: 25rpx;
}
.key-right-bottom {
font-size: 24rpx;
color: #999999;
}
}
.key-status {
margin-top: 4rpx;
margin-left: auto;
font-size: 26rpx;
color: #63b8af;
}
} }
}
.line { .line {
width: 100%; width: 100%;
height: 2rpx; height: 2rpx;
background: #EBEBEB; background: #ebebeb;
} }
.empty-list { .empty-list {
width: 150rpx; width: 150rpx;
height: 150rpx; height: 150rpx;
margin: 300rpx auto 20rpx 50%; margin: 300rpx auto 20rpx 50%;
transform: translateX(-50%); transform: translateX(-50%);
} }
.empty-list-text { .empty-list-text {
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: #999999; color: #999999;
} }
</style> </style>

View File

@ -3,10 +3,18 @@
<view class="days" v-if="currentLockInfo.days">钥匙将在{{ currentLockInfo.days }}天后失效</view> <view class="days" v-if="currentLockInfo.days">钥匙将在{{ currentLockInfo.days }}天后失效</view>
<view class="lock-name">{{ currentLockInfo.lockAlias }}</view> <view class="lock-name">{{ currentLockInfo.lockAlias }}</view>
<view class="top"> <view class="top">
<image class="top-background" src="/static/images/background_main.jpg" mode="aspectFill"></image> <image
<view style="width: 100%;height: 50rpx"> class="top-background"
src="/static/images/background_main.jpg"
mode="aspectFill"
></image>
<view style="width: 100%; height: 50rpx">
<view class="power" @click="powerTip"> <view class="power" @click="powerTip">
<image class="power-icon" :src="getPowerIcon(currentLockInfo.electricQuantity)" mode="aspectFill"></image> <image
class="power-icon"
:src="getPowerIcon(currentLockInfo.electricQuantity)"
mode="aspectFill"
></image>
<view class="power-text">{{ currentLockInfo.electricQuantity }}%</view> <view class="power-text">{{ currentLockInfo.electricQuantity }}%</view>
<image class="power-tips" src="/static/images/icon_tips.png" mode="aspectFill"></image> <image class="power-tips" src="/static/images/icon_tips.png" mode="aspectFill"></image>
</view> </view>
@ -21,10 +29,20 @@
<view>{{ getRole(currentLockInfo.userType, currentLockInfo.keyRight) }}</view> <view>{{ getRole(currentLockInfo.userType, currentLockInfo.keyRight) }}</view>
</view> </view>
<view class="bottom-side"> <view class="bottom-side">
<image class="bottom-icon" :src=" currentLockInfo.lockSetting.appUnlockOnline ? <image
'/static/images/icon_cloud_active.png' : '/static/images/icon_cloud.png' " class="bottom-icon"
mode="aspectFill" style="width: 40rpx;height: 40rpx;"></image> :src="
<view :style="{color: currentLockInfo.lockSetting.appUnlockOnline ? '#63b8af' : '#a3a3a3'}">手机需联网</view> currentLockInfo.lockSetting.appUnlockOnline
? '/static/images/icon_cloud_active.png'
: '/static/images/icon_cloud.png'
"
mode="aspectFill"
style="width: 40rpx; height: 40rpx"
></image>
<view
:style="{ color: currentLockInfo.lockSetting.appUnlockOnline ? '#63b8af' : '#a3a3a3' }"
>手机需联网</view
>
</view> </view>
</view> </view>
</view> </view>
@ -34,13 +52,19 @@
<view>功能</view> <view>功能</view>
</view> </view>
<view class="menu-main"> <view class="menu-main">
<view v-if="currentLockInfo.keyRight === 1" <view
class="menu-main-view" @click="routeJump({ name: 'keyList' })"> v-if="currentLockInfo.keyRight === 1"
class="menu-main-view"
@click="routeJump({ name: 'keyList' })"
>
<image class="menu-main-image" src="/static/images/tabbar_key_select.png"></image> <image class="menu-main-image" src="/static/images/tabbar_key_select.png"></image>
<view>电子钥匙</view> <view>电子钥匙</view>
</view> </view>
<view v-if="currentLockInfo.lockFeature.password || currentLockInfo.keyRight === 1" <view
class="menu-main-view" @click="routeJump({ name: 'passwordList' })"> v-if="currentLockInfo.lockFeature.password || currentLockInfo.keyRight === 1"
class="menu-main-view"
@click="routeJump({ name: 'passwordList' })"
>
<image class="menu-main-image" src="/static/images/icon_lock_transparent.png"></image> <image class="menu-main-image" src="/static/images/icon_lock_transparent.png"></image>
<view>密码</view> <view>密码</view>
</view> </view>
@ -51,11 +75,23 @@
<view class="setting-text">设置</view> <view class="setting-text">设置</view>
<image class="setting-arrow" mode="aspectFill" src="/static/images/icon_arrow.png"></image> <image class="setting-arrow" mode="aspectFill" src="/static/images/icon_arrow.png"></image>
</view> </view>
<up-popup :show="show" @close="closePopup" mode="center" :closeOnClickOverlay="true" bgColor="transparent"> <up-popup
:show="show"
@close="closePopup"
mode="center"
:closeOnClickOverlay="true"
bgColor="transparent"
>
<view class="popup" @click="closePopup"> <view class="popup" @click="closePopup">
<image class="popup-background" :src="type === 'close' ? '/static/images/background_close_door.png' : <image
'/static/images/background_open_door.png'" class="popup-background"
mode="aspectFill"></image> :src="
type === 'close'
? '/static/images/background_close_door.png'
: '/static/images/background_open_door.png'
"
mode="aspectFill"
/>
<view> <view>
<view class="popup-name">{{ currentLockInfo.lockAlias }}</view> <view class="popup-name">{{ currentLockInfo.lockAlias }}</view>
<view class="popup-time">{{ timeFormat('', 'mm/dd h:M') }}</view> <view class="popup-time">{{ timeFormat('', 'mm/dd h:M') }}</view>
@ -66,396 +102,401 @@
</template> </template>
<script> <script>
import { useBluetoothStore } from '@/stores/bluetooth' import { mapState, mapActions } from 'pinia'
import { useBasicStore } from '@/stores/basic' import { timeFormat } from 'uview-plus'
import { mapState, mapActions } from 'pinia' import { useBluetoothStore } from '@/stores/bluetooth'
import SwitchLoading from '@/components/SwitchLoading/SwitchLoading.vue' import { useBasicStore } from '@/stores/basic'
import { useLockStore } from '@/stores/lock' import SwitchLoading from '@/components/SwitchLoading/SwitchLoading.vue'
import { useUserStore } from '@/stores/user' import { useLockStore } from '@/stores/lock'
import { getLockNetTokenRequest } from '@/api/lock' import { useUserStore } from '@/stores/user'
import { timeFormat } from 'uview-plus' import { getLockNetTokenRequest } from '@/api/lock'
import { deleteKeyRequest } from '@/api/key' import { deleteKeyRequest } from '@/api/key'
export default { export default {
data () { data() {
return { return {
time: 0, time: 0,
onlineToken: '0', onlineToken: '0',
pending: false, pending: false,
show: false, show: false,
type: '' type: ''
} }
},
computed: {
...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
...mapState(useUserStore, ['userInfo']),
...mapState(useLockStore, ['lockSearch']),
},
components: {
SwitchLoading
},
onLoad() {
this.getServeTime()
},
methods: {
timeFormat,
...mapActions(useLockStore, ['getRole', 'updateLockSearch', 'getLockList', 'getPowerIcon']),
...mapActions(useBluetoothStore, ['openDoor', 'updateServerTimestamp', 'closeBluetoothConnection']),
...mapActions(useBasicStore, ['routeJump', 'backAndToast', 'getNetworkType']),
closePopup() {
this.show = false
}, },
powerTip() { computed: {
const that = this ...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
const time = timeFormat(that.currentLockInfo.electricQuantityDate, 'yyyy-mm-dd h:M') ...mapState(useUserStore, ['userInfo']),
console.log('更新时间', that.currentLockInfo.electricQuantityDate, time) ...mapState(useLockStore, ['lockSearch'])
uni.showModal({
title: '锁电量更新时间',
content: time,
showCancel: false
})
}, },
async getNetToken(){ components: {
const { code, data, message } = await getLockNetTokenRequest({ SwitchLoading
lockId: this.currentLockInfo.lockId },
}) onLoad() {
if(code === 0) { this.getServeTime()
this.onlineToken = data.token },
return true methods: {
} else { timeFormat,
...mapActions(useLockStore, ['getRole', 'updateLockSearch', 'getLockList', 'getPowerIcon']),
...mapActions(useBluetoothStore, [
'openDoor',
'updateServerTimestamp',
'closeBluetoothConnection'
]),
...mapActions(useBasicStore, ['routeJump', 'backAndToast', 'getNetworkType']),
closePopup() {
this.show = false
},
powerTip() {
const that = this
const time = timeFormat(that.currentLockInfo.electricQuantityDate, 'yyyy-mm-dd h:M')
console.log('更新时间', that.currentLockInfo.electricQuantityDate, time)
uni.showModal({
title: '锁电量更新时间',
content: time,
showCancel: false
})
},
async getNetToken() {
const { code, data, message } = await getLockNetTokenRequest({
lockId: this.currentLockInfo.lockId
})
if (code === 0) {
this.onlineToken = data.token
return true
}
uni.showToast({ uni.showToast({
title: message, title: message,
icon: 'none' icon: 'none'
}) })
return false return false
} },
}, async getServeTime() {
async getServeTime() { const { code, data } = await this.updateServerTimestamp()
const { code, data } = await this.updateServerTimestamp() if (code === 0) {
if(code === 0) { this.time = parseInt((data.date - new Date().getTime()) / 1000, 10)
this.time = parseInt((data.date - new Date().getTime()) / 1000)
}
},
async openDoorOperate(type) {
const timestamp = new Date().getTime()
if(this.currentLockInfo.faceAuthentication === 1 &&
((this.currentLockInfo.nextFaceValidateTime <= new Date().getTime() + this.time * 1000) &&
this.currentLockInfo.nextFaceValidateTime !== 0)) {
uni.showModal({
title: '提示',
content: '开门前需进行实名认证小程序暂不支持请使用APP认证开门',
showCancel: false
})
return
}
if(this.pending) {
return
}
if(this.currentLockInfo.lockSetting.appUnlockOnline) {
const netWork = await this.getNetworkType()
if(!netWork) {
return
} }
} },
uni.vibrateLong() async openDoorOperate(type) {
this.pending = true const timestamp = new Date().getTime()
this.$refs.loading.open() if (
if(type === 'close') { this.currentLockInfo.faceAuthentication === 1 &&
uni.showToast({ this.currentLockInfo.nextFaceValidateTime <= new Date().getTime() + this.time * 1000 &&
title: `正在尝试闭锁……`, this.currentLockInfo.nextFaceValidateTime !== 0
icon: 'none' ) {
}) uni.showModal({
} title: '提示',
if(this.currentLockInfo.lockSetting.appUnlockOnline) { content: '开门前需进行实名认证小程序暂不支持请使用APP认证开门',
const result = await this.getNetToken() showCancel: false
if(!result) {
this.$refs.loading.close()
this.pending = false
return
}
}
let openMode
if(type === 'close') {
openMode = this.currentLockInfo.lockSetting.appUnlockOnline ? 33 : 32
} else {
openMode = this.currentLockInfo.lockSetting.appUnlockOnline ? 1 : 0
}
const { code } = await this.openDoor({
name: this.currentLockInfo.name,
uid: this.userInfo.uid.toString(),
openMode: openMode,
openTime: parseInt(new Date().getTime() / 1000) + this.time,
onlineToken: this.onlineToken
})
this.closeBluetoothConnection()
if(type === 'open') {
uni.reportEvent("open_door", {
result: code,
duration: new Date().getTime() - timestamp
})
} else if(type === 'close') {
uni.reportEvent("close_door", {
result: code,
duration: new Date().getTime() - timestamp
})
}
if(code === 0) {
this.show = true
this.type = type
setTimeout(() => {
this.show = false
}, 3000)
if(this.currentLockInfo.keyType === 3) {
const { code: deleteKeyCode } = await deleteKeyRequest({
keyId: this.keyId
}) })
if(deleteKeyCode === 0) { return
this.updateLockSearch({ }
...this.lockSearch, if (this.pending) {
pageNo: 1 return
}) }
this.getLockList(this.lockSearch) if (this.currentLockInfo.lockSetting.appUnlockOnline) {
this.backAndToast('单次钥匙已在被使用后删除', 1) const netWork = await this.getNetworkType()
if (!netWork) {
return
} }
} }
} else if(code === 13) { uni.vibrateLong()
uni.showToast({ this.pending = true
title: `只能在循环时间内操作门锁`, this.$refs.loading.open()
icon: 'none' if (type === 'close') {
}) uni.showToast({
} else if(code === -1) { title: `正在尝试闭锁……`,
uni.showToast({ icon: 'none'
title: `${type === 'close' ? '关' : '开'}锁失败,请保证在锁附近`, })
icon: 'none' }
if (this.currentLockInfo.lockSetting.appUnlockOnline) {
const result = await this.getNetToken()
if (!result) {
this.$refs.loading.close()
this.pending = false
return
}
}
let openMode
if (type === 'close') {
openMode = this.currentLockInfo.lockSetting.appUnlockOnline ? 33 : 32
} else {
openMode = this.currentLockInfo.lockSetting.appUnlockOnline ? 1 : 0
}
const { code } = await this.openDoor({
name: this.currentLockInfo.name,
uid: this.userInfo.uid.toString(),
openMode,
openTime: parseInt(new Date().getTime() / 1000, 10) + this.time,
onlineToken: this.onlineToken
}) })
this.closeBluetoothConnection()
if (type === 'open') {
uni.reportEvent('open_door', {
result: code,
duration: new Date().getTime() - timestamp
})
} else if (type === 'close') {
uni.reportEvent('close_door', {
result: code,
duration: new Date().getTime() - timestamp
})
}
if (code === 0) {
this.show = true
this.type = type
setTimeout(() => {
this.show = false
}, 3000)
if (this.currentLockInfo.keyType === 3) {
const { code: deleteKeyCode } = await deleteKeyRequest({
keyId: this.keyId
})
if (deleteKeyCode === 0) {
this.updateLockSearch({
...this.lockSearch,
pageNo: 1
})
this.getLockList(this.lockSearch)
this.backAndToast('单次钥匙已在被使用后删除', 1)
}
}
} else if (code === 13) {
uni.showToast({
title: `只能在循环时间内操作门锁`,
icon: 'none'
})
} else if (code === -1) {
uni.showToast({
title: `${type === 'close' ? '关' : '开'}锁失败,请保证在锁附近`,
icon: 'none'
})
}
this.$refs.loading.close()
this.pending = false
} }
this.$refs.loading.close()
this.pending = false
} }
} }
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.popup { .popup {
display: flex; display: flex;
position: relative; position: relative;
width: 400rpx;
height: 389rpx;
text-align: center;
flex-wrap: wrap;
.popup-background {
z-index: -1;
width: 400rpx; width: 400rpx;
height: 389rpx; height: 389rpx;
position: absolute; text-align: center;
flex-wrap: wrap;
.popup-background {
z-index: -1;
width: 400rpx;
height: 389rpx;
position: absolute;
}
.popup-name {
margin-left: 30rpx;
z-index: 9;
margin-top: 180rpx;
color: #676b6d;
width: 340rpx;
max-height: 80rpx;
line-height: 40rpx;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
.popup-time {
margin-top: 10rpx;
width: 400rpx;
}
} }
.popup-name { .days {
margin-left: 30rpx; line-height: 60rpx;
z-index: 9; background: #faecc9;
margin-top: 180rpx; color: #bc9839;
color: #676b6d; text-align: center;
width: 340rpx; font-size: 32rpx;
max-height: 80rpx; width: 750rpx;
line-height: 40rpx; height: 60rpx;
}
.lock-name {
text-align: center;
font-size: 32rpx;
padding: 32rpx 32rpx 0 32rpx;
font-weight: bold;
word-break: break-all; word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
} }
.popup-time { .top {
margin-top: 10rpx; margin-top: 32rpx;
width: 400rpx; margin-left: 32rpx;
}
}
.days {
line-height: 60rpx;
background: #faecc9;
color: #bc9839;
text-align: center;
font-size: 32rpx;
width: 750rpx;
height: 60rpx;
}
.lock-name {
text-align: center;
font-size: 32rpx;
padding: 32rpx 32rpx 0 32rpx;
font-weight: bold;
word-break: break-all;
}
.top {
margin-top: 32rpx;
margin-left: 32rpx;
width: 686rpx;
height: 464rpx;
border-radius: 32rpx;
position: relative;
.top-background {
z-index: -1;
position: absolute;
width: 686rpx; width: 686rpx;
height: 464rpx; height: 464rpx;
border-radius: 32rpx; border-radius: 32rpx;
} position: relative;
.switch { .top-background {
margin-top: 20rpx; z-index: -1;
margin-left: 218rpx; position: absolute;
display: flex; width: 686rpx;
justify-content: center; height: 464rpx;
align-items: center; border-radius: 32rpx;
width: 250rpx;
height: 250rpx;
background: #FFFFFF;
border-radius: 50%;
box-shadow: 0 8rpx 36rpx 0 rgba(0,0,0,0.12);
}
.power {
float: right;
padding-top: 18rpx;
//width: 100%;
display: flex;
align-items: center;
height: 50rpx;
justify-content: flex-end;
.power-icon {
width: 50rpx;
margin-right: 10rpx;
height: 30rpx;
} }
.power-text { .switch {
font-size: 32rpx; margin-top: 20rpx;
font-weight: bold; margin-left: 218rpx;
margin-right: 10rpx; display: flex;
line-height: 50rpx; justify-content: center;
align-items: center;
width: 250rpx;
height: 250rpx;
background: #ffffff;
border-radius: 50%;
box-shadow: 0 8rpx 36rpx 0 rgba(0, 0, 0, 0.12);
} }
.power-tips { .power {
margin-right: 32rpx; float: right;
width: 40rpx; padding-top: 18rpx;
height: 40rpx; //width: 100%;
} display: flex;
} align-items: center;
height: 50rpx;
justify-content: flex-end;
.switch-text { .power-icon {
margin-top: 10rpx; width: 50rpx;
text-align: center; margin-right: 10rpx;
} height: 30rpx;
} }
.bottom { .power-text {
width: 686rpx; font-size: 32rpx;
position: absolute; font-weight: bold;
bottom: 0; margin-right: 10rpx;
display: flex; line-height: 50rpx;
align-items: center; }
background-color: rgba(0, 0, 0, 0.1);
height: 48rpx;
line-height: 48rpx;
font-size: 32rpx;
color: #63b8af;
border-radius: 0 0 32rpx 32rpx;
justify-content: space-around;
.bottom-side { .power-tips {
display: flex; margin-right: 32rpx;
align-items: center;
}
.bottom-icon {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
}
.menu {
margin-top: 32rpx;
margin-left: 32rpx;
padding-bottom: 32rpx;
width: 686rpx;
background-color: #ffffff;
border-radius: 32rpx;
box-shadow: 0 8rpx 36rpx 0 rgba(0,0,0,0.12);
font-size: 40rpx;
.menu-title {
padding: 24rpx 32rpx;
display: flex;
align-items: center;
}
.menu-image {
margin-right: 40rpx;
width: 40rpx;
height: 40rpx;
}
.menu-main {
padding-top: 32rpx;
padding-bottom: 32rpx;
display: flex;
align-items: center;
font-size: 32rpx;
flex-wrap: wrap;
text-align: center;
margin-left: 43rpx;
.menu-main-view {
width: 150rpx;
.menu-main-image {
filter: sepia(100%) saturate(10000%) hue-rotate(180deg) brightness(0.1);
margin-bottom: 10rpx;
width: 40rpx; width: 40rpx;
height: 40rpx; height: 40rpx;
} }
} }
}
}
.setting { .switch-text {
padding: 24rpx 0; margin-top: 10rpx;
margin-top: 32rpx; text-align: center;
margin-left: 32rpx; }
display: flex;
align-items: center;
width: 686rpx;
background-color: #ffffff;
border-radius: 32rpx;
box-shadow: 0 8rpx 36rpx 0 rgba(0,0,0,0.12);
font-size: 40rpx;
.setting-text {
margin-left: 32rpx;
} }
.setting-arrow { .bottom {
margin-right: 32rpx; width: 686rpx;
width: 48rpx; position: absolute;
bottom: 0;
display: flex;
align-items: center;
background-color: rgba(0, 0, 0, 0.1);
height: 48rpx; height: 48rpx;
margin-left: auto; line-height: 48rpx;
font-size: 32rpx;
color: #63b8af;
border-radius: 0 0 32rpx 32rpx;
justify-content: space-around;
.bottom-side {
display: flex;
align-items: center;
}
.bottom-icon {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
}
} }
.setting-image { .menu {
margin-top: 32rpx;
margin-left: 32rpx; margin-left: 32rpx;
width: 48rpx; padding-bottom: 32rpx;
height: 48rpx; width: 686rpx;
background-color: #ffffff;
border-radius: 32rpx;
box-shadow: 0 8rpx 36rpx 0 rgba(0, 0, 0, 0.12);
font-size: 40rpx;
.menu-title {
padding: 24rpx 32rpx;
display: flex;
align-items: center;
}
.menu-image {
margin-right: 40rpx;
width: 40rpx;
height: 40rpx;
}
.menu-main {
padding-top: 32rpx;
padding-bottom: 32rpx;
display: flex;
align-items: center;
font-size: 32rpx;
flex-wrap: wrap;
text-align: center;
margin-left: 43rpx;
.menu-main-view {
width: 150rpx;
.menu-main-image {
filter: sepia(100%) saturate(10000%) hue-rotate(180deg) brightness(0.1);
margin-bottom: 10rpx;
width: 40rpx;
height: 40rpx;
}
}
}
}
.setting {
padding: 24rpx 0;
margin-top: 32rpx;
margin-left: 32rpx;
display: flex;
align-items: center;
width: 686rpx;
background-color: #ffffff;
border-radius: 32rpx;
box-shadow: 0 8rpx 36rpx 0 rgba(0, 0, 0, 0.12);
font-size: 40rpx;
.setting-text {
margin-left: 32rpx;
}
.setting-arrow {
margin-right: 32rpx;
width: 48rpx;
height: 48rpx;
margin-left: auto;
}
.setting-image {
margin-left: 32rpx;
width: 48rpx;
height: 48rpx;
}
} }
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<view v-if="buttonInfo"> <view v-if="buttonInfo">
<view v-if="isLogin"> <view v-if="isLogin">
<view class="view"> <view class="view">
<view class="view-button" @click="toUsereInfo"> <view class="view-button" @click="toUsereInfo">
@ -30,9 +30,11 @@
</view> </view>
</view> </view>
<view class="env" v-if="env"> <view class="env" v-if="env">
<view class="env-text">{{env.name}} {{env.version}}+{{env.buildNumber}}</view> <view class="env-text">{{ env.name }} {{ env.version }}+{{ env.buildNumber }}</view>
<view>{{ env.baseUrl.split('/').slice(0, 3).join('/') }}</view> <view>{{ env.baseUrl.split('/').slice(0, 3).join('/') }}</view>
<view v-if="envVersion !== 'release' && env" class="env-button" @click="show=true">切换环境</view> <view v-if="envVersion !== 'release' && env" class="env-button" @click="show = true"
>切换环境</view
>
</view> </view>
<label for="changePhone"> <label for="changePhone">
<view class="switch-account">切换账号</view> <view class="switch-account">切换账号</view>
@ -44,39 +46,60 @@
<view class="button-login">登录</view> <view class="button-login">登录</view>
</label> </label>
<view class="env" v-if="env"> <view class="env" v-if="env">
<view class="env-text">{{env.name}} {{env.version}}+{{env.buildNumber}}</view> <view class="env-text">{{ env.name }} {{ env.version }}+{{ env.buildNumber }}</view>
<view>{{ env.baseUrl.split('/').slice(0, 3).join('/') }}</view> <view>{{ env.baseUrl.split('/').slice(0, 3).join('/') }}</view>
<view v-if="envVersion !== 'release' && env" class="env-button" @click="show=true">切换环境</view> <view v-if="envVersion !== 'release' && env" class="env-button" @click="show = true"
>切换环境</view
>
</view> </view>
</view> </view>
</view> </view>
<button open-type="contact" style="display:none" id="contact"></button> <button open-type="contact" style="display: none" id="contact"></button>
<button open-type="getPhoneNumber" style="display:none" id="phone" @getphonenumber="getphonenumber"></button> <button
<button open-type="getPhoneNumber" style="display:none" id="changePhone" @getphonenumber="changePhone"></button> open-type="getPhoneNumber"
<up-action-sheet :actions="envList" :closeOnClickOverlay="true" title="切换环境" cancelText="取消" :closeOnClickAction="true" style="display: none"
:show="show" :safeAreaInsetBottom="true" @close="show=false" @select="selectEnv"></up-action-sheet> id="phone"
@getphonenumber="getphonenumber"
></button>
<button
open-type="getPhoneNumber"
style="display: none"
id="changePhone"
@getphonenumber="changePhone"
></button>
<up-action-sheet
:actions="envList"
:closeOnClickOverlay="true"
title="切换环境"
cancelText="取消"
:closeOnClickAction="true"
:show="show"
:safeAreaInsetBottom="true"
@close="show = false"
@select="selectEnv"
></up-action-sheet>
</template> </template>
<script> <script>
import { mapState, mapActions } from 'pinia'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useLockStore } from '@/stores/lock' import { useLockStore } from '@/stores/lock'
import { mapState, mapActions } from 'pinia'
import { phoneLoginRequest } from '@/api/user' import { phoneLoginRequest } from '@/api/user'
import env from '@/config/env' import env from '@/config/env'
import { setStorage, getStorage, removeStorage } from '@/utils/storage' import { setStorage, getStorage, removeStorage } from '@/utils/storage'
import { useNotificationStore } from '../../stores/notification' import { useNotificationStore } from '@/stores/notification'
export default { export default {
data() { data() {
return { return {
buttonInfo: null, buttonInfo: null,
env: null, env: null,
envVersion: '', envVersion: '',
envList: [], envList: [],
show: false show: false
} }
}, },
computed: { computed: {
...mapState(useUserStore, ['isLogin']), ...mapState(useUserStore, ['isLogin']),
...mapState(useLockStore, ['lockSearch']), ...mapState(useLockStore, ['lockSearch']),
@ -86,20 +109,26 @@
this.buttonInfo = await this.getButtonInfo() this.buttonInfo = await this.getButtonInfo()
this.env = await env[await getApp().globalData.getEnvConfig()] this.env = await env[await getApp().globalData.getEnvConfig()]
this.envVersion = getApp().globalData.envVersion this.envVersion = getApp().globalData.envVersion
// eslint-disable-next-line guard-for-in,no-restricted-syntax
for (let key in env) { for (let key in env) {
this.envList.push({ this.envList.push({
...env[key], ...env[key],
key: key key
}) })
} }
console.log(this.envList) console.log(this.envList)
}, },
methods: { methods: {
...mapActions(useBasicStore, ['getButtonInfo', 'routeJump']), ...mapActions(useBasicStore, ['getButtonInfo', 'routeJump']),
...mapActions(useLockStore, ['getLockList', 'updateLockSearch']), ...mapActions(useLockStore, ['getLockList', 'updateLockSearch']),
...mapActions(useNotificationStore, ['getNotificationList', 'updateNotificationSearch']), ...mapActions(useNotificationStore, ['getNotificationList', 'updateNotificationSearch']),
...mapActions(useUserStore, ['updateLoginStatus', 'phoneLogin', 'updateUserInfo', 'getUserInfo', ...mapActions(useUserStore, [
'checkSession']), 'updateLoginStatus',
'phoneLogin',
'updateUserInfo',
'getUserInfo',
'checkSession'
]),
selectEnv(env) { selectEnv(env) {
setStorage('envVersion', env.key) setStorage('envVersion', env.key)
removeStorage('token') removeStorage('token')
@ -111,11 +140,11 @@
}) })
}, },
async changePhone(res) { async changePhone(res) {
if(res.detail.errMsg === 'getPhoneNumber:fail user deny') { if (res.detail.errMsg === 'getPhoneNumber:fail user deny') {
return return
} }
const result = await this.checkSession() const result = await this.checkSession()
if(!result) { if (!result) {
uni.showToast({ uni.showToast({
title: '登录失败,请重试', title: '登录失败,请重试',
icon: 'none' icon: 'none'
@ -129,7 +158,7 @@
rebind: true, rebind: true,
openid openid
}) })
if(code === 0) { if (code === 0) {
removeStorage('userInfo') removeStorage('userInfo')
removeStorage('lockList') removeStorage('lockList')
setStorage('token', data.accessToken) setStorage('token', data.accessToken)
@ -147,8 +176,8 @@
title: '账号切换成功', title: '账号切换成功',
icon: 'none' icon: 'none'
}) })
} else if(code === 438) { } else if (code === 438) {
/* empty */
} else { } else {
uni.showToast({ uni.showToast({
title: message, title: message,
@ -157,14 +186,14 @@
} }
}, },
async getphonenumber(data) { async getphonenumber(data) {
if(data.detail.errMsg === 'getPhoneNumber:fail user deny') { if (data.detail.errMsg === 'getPhoneNumber:fail user deny') {
return return
} }
const result = await this.phoneLogin({ const result = await this.phoneLogin({
encryptedData: data.detail.encryptedData, encryptedData: data.detail.encryptedData,
iv: data.detail.iv iv: data.detail.iv
}) })
if(!result) { if (!result) {
uni.showToast({ uni.showToast({
title: '登录失败,请重试', title: '登录失败,请重试',
icon: 'none' icon: 'none'
@ -185,111 +214,110 @@
}) })
} }
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.background-image { .background-image {
margin-top: 32rpx; margin-top: 32rpx;
margin-left: 20rpx; margin-left: 20rpx;
width: 710rpx; width: 710rpx;
height: 156rpx; height: 156rpx;
border-radius: 32rpx; border-radius: 32rpx;
} }
.view { .view {
margin-top: 32rpx; margin-top: 32rpx;
border-radius: 32rpx; border-radius: 32rpx;
width: 710rpx; width: 710rpx;
margin-left: 20rpx; margin-left: 20rpx;
background: #FFFFFF; background: #ffffff;
} }
.view-button { .view-button {
padding: 0 20rpx 0 40rpx; padding: 0 20rpx 0 40rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
color: #292826; color: #292826;
font-size: 32rpx; font-size: 32rpx;
font-weight: bold;
line-height: 80rpx;
}
.icon-arrow {
width: 40rpx;
height: 40rpx;
}
.view-line {
width: 100%;
height: 3rpx;
background: #EBEBEB;
}
.switch-account {
position: absolute;
border-radius: 46rpx;
bottom: 60rpx;
width: 600rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
background: #63b8af;
color: #ffffff;
font-size: 40rpx;
font-weight: bold;
}
.env {
position: absolute;
bottom: 180rpx;
width: 600rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
.env-text {
font-weight: bold; font-weight: bold;
line-height: 80rpx;
}
.icon-arrow {
width: 40rpx;
height: 40rpx;
}
.view-line {
width: 100%;
height: 3rpx;
background: #ebebeb;
}
.switch-account {
position: absolute;
border-radius: 46rpx;
bottom: 60rpx;
width: 600rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
background: #63b8af;
color: #ffffff;
font-size: 40rpx;
font-weight: bold;
}
.env {
position: absolute;
bottom: 180rpx;
width: 600rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
.env-text {
font-weight: bold;
color: #999999;
font-size: 30rpx;
}
.env-button {
background: inherit;
color: #022b7c;
font-size: 0.8rem;
text-align: right;
text-decoration: underline;
}
}
.button-login {
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;
}
.tips {
margin-top: 25vh;
padding: 32rpx 0;
text-align: center;
font-size: 28rpx;
color: #999999; color: #999999;
font-size: 30rpx;
} }
.env-button {
background: inherit;
color: #022b7c;
font-size: .8rem;
text-align: right;
text-decoration: underline;
}
}
.button-login {
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;
}
.tips {
margin-top: 25vh;
padding: 32rpx 0;
text-align: center;
font-size: 28rpx;
color: #999999;
}
</style> </style>

View File

@ -1,56 +1,56 @@
<template> <template>
<view v-if="notification"> <view v-if="notification">
<view class="time">创建时间{{ timeFormat(notification.createdAt, 'yyyy-mm-dd h:M') }}</view> <view class="time">创建时间{{ timeFormat(notification.createdAt, 'yyyy-mm-dd h:M') }}</view>
<view class="content">{{notification.data}}</view> <view class="content">{{ notification.data }}</view>
</view> </view>
</template> </template>
<script> <script>
import { timeFormat } from 'uview-plus' import { timeFormat } from 'uview-plus'
export default { export default {
data () { data() {
return { return {
notification: null notification: null
}
},
onLoad(options) {
this.notification = JSON.parse(options.notification)
console.log(this.notification)
},
methods: {
timeFormat
} }
}, }
onLoad(options) {
this.notification = JSON.parse(options.notification)
console.log(this.notification)
},
methods: {
timeFormat,
},
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.time { .time {
margin-top: 24rpx; margin-top: 24rpx;
margin-left: 25rpx; margin-left: 25rpx;
color: #6c6c6c; color: #6c6c6c;
font-size: 28rpx; font-size: 28rpx;
font-weight: bold; font-weight: bold;
} }
.content { .content {
font-size: 28rpx; font-size: 28rpx;
font-weight: bold; font-weight: bold;
color: #6c6c6c; color: #6c6c6c;
width: 652rpx; width: 652rpx;
margin-left: 25rpx; margin-left: 25rpx;
margin-top: 20rpx; margin-top: 20rpx;
border-radius: 24rpx; border-radius: 24rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 24rpx; padding: 24rpx;
box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.2); box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.2);
} }
</style> </style>

View File

@ -1,30 +1,65 @@
<template> <template>
<scroll-view v-if="deviceInfo" scroll-y="true" :style="{ height: deviceInfo.windowHeight + 'px' }" <scroll-view
lower-threshold="100" @refresherrefresh="refresherList" :refresher-enabled="true" @scrolltolower="nextPage" v-if="deviceInfo"
:refresher-triggered="refresherTriggered" @scroll="scroll"> scroll-y="true"
:style="{ height: deviceInfo.windowHeight + 'px' }"
lower-threshold="100"
@refresherrefresh="refresherList"
:refresher-enabled="true"
@scrolltolower="nextPage"
:refresher-triggered="refresherTriggered"
@scroll="scroll"
>
<view v-if="isLogin"> <view v-if="isLogin">
<view class="list" v-if="requestFinished"> <view class="list" v-if="requestFinished">
<view v-if="notificationList.length === 0"> <view v-if="notificationList.length === 0">
<image class="empty-list" src="/static/images/background_empty_list.png" mode="aspectFill"></image> <image
class="empty-list"
src="/static/images/background_empty_list.png"
mode="aspectFill"
></image>
<view class="empty-list-text">暂无数据</view> <view class="empty-list-text">暂无数据</view>
</view> </view>
<up-swipe-action v-else> <up-swipe-action v-else>
<up-swipe-action-item class="item" ref="swipeItem" :options="options" <up-swipe-action-item
v-for="(notification,index) in notificationList" :key="notification.id" class="item"
:threshold="50" @click="deleteNotification(notification, index)" :index="index" ref="swipeItem"
:name="index"> :options="options"
<view class="notification" @click="toDetail(index,notification)"> v-for="(notification, index) in notificationList"
<view v-if="notification.readAt === 0"> :key="notification.id"
<image class="icon" src="/static/images/icon_notification_unread.png" mode="aspectFill"></image> :threshold="50"
<view class="point"></view> @click="deleteNotification(notification, index)"
:index="index"
:name="index"
>
<view class="notification" @click="toDetail(index, notification)">
<view v-if="notification.readAt === 0">
<image
class="icon"
src="/static/images/icon_notification_unread.png"
mode="aspectFill"
></image>
<view class="point"></view>
</view>
<image
v-else
class="icon"
src="/static/images/icon_notification_read.png"
mode="aspectFill"
></image>
<view>
<view
class="content"
:style="{ color: notification.readAt === 0 ? '#000000' : '#6c6c6c' }"
>{{ notification.data }}</view
>
<view
class="time"
:style="{ color: notification.readAt === 0 ? '#000000' : '#6c6c6c' }"
>{{ timeFormat(notification.createdAt, 'yyyy-mm-dd h:M') }}</view
>
</view>
</view> </view>
<image v-else class="icon" src="/static/images/icon_notification_read.png" mode="aspectFill"></image>
<view>
<view class="content" :style="{color:notification.readAt === 0?'#000000':'#6c6c6c'}">{{ notification.data
}}</view>
<view class="time" :style="{color:notification.readAt === 0?'#000000':'#6c6c6c'}">{{ timeFormat(notification.createdAt, 'yyyy-mm-dd h:M') }}</view>
</view>
</view>
</up-swipe-action-item> </up-swipe-action-item>
</up-swipe-action> </up-swipe-action>
</view> </view>
@ -36,336 +71,362 @@
</label> </label>
</view> </view>
</scroll-view> </scroll-view>
<view class="delete" @click="deleteAllNotification" v-if="isLogin && requestFinished && notificationList.length !== <view
0"> class="delete"
<image class="delete-image" src="/static/images/icon_delete.png" mode="aspectFill"></image> @click="deleteAllNotification"
v-if="isLogin && requestFinished && notificationList.length !== 0"
>
<image class="delete-image" src="/static/images/icon_delete.png" mode="aspectFill" />
</view> </view>
<button open-type="getPhoneNumber" style="display:none" id="phone" @getphonenumber="getphonenumber"></button> <button
open-type="getPhoneNumber"
style="display: none"
id="phone"
@getphonenumber="getphonenumber"
></button>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useNotificationStore } from '@/stores/notification' import { timeFormat } from 'uview-plus'
import { useBasicStore } from '@/stores/basic' import { useNotificationStore } from '@/stores/notification'
import { timeFormat } from 'uview-plus' import { useBasicStore } from '@/stores/basic'
import { deleteAllNotification, deleteNotification, markAsReadNotification } from '@/api/notification' import {
import { useUserStore } from '@/stores/user' deleteAllNotification,
deleteNotification,
markAsReadNotification
} from '@/api/notification'
import { useUserStore } from '@/stores/user'
export default { export default {
data () { data() {
return { return {
refresherTriggered: false, refresherTriggered: false,
requestFinished: false, requestFinished: false,
deviceInfo: null, deviceInfo: null,
options: [{ options: [
text: '删除', {
style: { text: '删除',
backgroundColor: '#f56c6c' style: {
} backgroundColor: '#f56c6c'
}],
}
},
computed: {
...mapState(useNotificationStore, ['notificationTotal', 'notificationList', 'notificationSearch']),
...mapState(useUserStore, ['isLogin']),
},
async onLoad () {
this.deviceInfo = await this.getDeviceInfo()
if(this.isLogin) {
await this.getList()
}
this.requestFinished = true
},
methods: {
timeFormat,
...mapActions(useNotificationStore, ['getNotificationList', 'updateNotificationSearch', 'updateNotificationItem','deleteNotificationItem']),
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType']),
...mapActions(useUserStore, ['phoneLogin']),
async getList() {
uni.showLoading({
title: '加载中',
mask: true
})
const { code, message } = await this.getNotificationList(this.notificationSearch)
uni.hideLoading()
if (code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
async getphonenumber(data) {
if(data.detail.errMsg === 'getPhoneNumber:fail user deny') {
return
}
const result = await this.phoneLogin({
encryptedData: data.detail.encryptedData,
iv: data.detail.iv
})
if(!result) {
uni.showToast({
title: '登录失败,请重试',
icon: 'none'
})
}
},
scroll() {
this.$refs.swipeItem.forEach(item => {
if(item.show) {
item.closeHandler()
}
})
},
async deleteNotification (notification, index) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
this.$refs.swipeItem[index].closeHandler()
uni.showModal({
title: '提示',
content: '确定要删除该通知吗?',
success: async (res) => {
if (res.confirm) {
const { code, message } = await deleteNotification({
id: notification.id
})
if (code === 0) {
this.deleteNotificationItem(index)
uni.showToast({
title: '删除成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
} }
} }
} ]
}) }
}, },
deleteAllNotification() { computed: {
uni.showModal({ ...mapState(useNotificationStore, [
title: '提示', 'notificationTotal',
content: '确定要删除所有通知吗?', 'notificationList',
success: async (res) => { 'notificationSearch'
if (res.confirm) { ]),
const { code, message } = await deleteAllNotification() ...mapState(useUserStore, ['isLogin'])
if (code === 0) { },
uni.showToast({ async onLoad() {
title: '删除成功', this.deviceInfo = await this.getDeviceInfo()
icon: 'none' if (this.isLogin) {
}) await this.getList()
this.updateNotificationSearch({ }
pageNo: 1 this.requestFinished = true
}) },
await this.getNotificationList(this.notificationSearch) methods: {
} else { timeFormat,
uni.showToast({ ...mapActions(useNotificationStore, [
title: message, 'getNotificationList',
icon: 'none' 'updateNotificationSearch',
'updateNotificationItem',
'deleteNotificationItem'
]),
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType']),
...mapActions(useUserStore, ['phoneLogin']),
async getList() {
uni.showLoading({
title: '加载中',
mask: true
})
const { code, message } = await this.getNotificationList(this.notificationSearch)
uni.hideLoading()
if (code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
async getphonenumber(data) {
if (data.detail.errMsg === 'getPhoneNumber:fail user deny') {
return
}
const result = await this.phoneLogin({
encryptedData: data.detail.encryptedData,
iv: data.detail.iv
})
if (!result) {
uni.showToast({
title: '登录失败,请重试',
icon: 'none'
})
}
},
scroll() {
this.$refs.swipeItem.forEach(item => {
if (item.show) {
item.closeHandler()
}
})
},
async deleteNotification(notification, index) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
this.$refs.swipeItem[index].closeHandler()
uni.showModal({
title: '提示',
content: '确定要删除该通知吗?',
success: async res => {
if (res.confirm) {
const { code, message } = await deleteNotification({
id: notification.id
}) })
if (code === 0) {
this.deleteNotificationItem(index)
uni.showToast({
title: '删除成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
} }
} }
})
},
deleteAllNotification() {
uni.showModal({
title: '提示',
content: '确定要删除所有通知吗?',
success: async res => {
if (res.confirm) {
const { code, message } = await deleteAllNotification()
if (code === 0) {
uni.showToast({
title: '删除成功',
icon: 'none'
})
this.updateNotificationSearch({
pageNo: 1
})
await this.getNotificationList(this.notificationSearch)
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
}
}
})
},
toDetail(index, notification) {
if (notification.readAt === 0) {
notification.readAt = 1
this.updateNotificationItem(index, notification)
markAsReadNotification({
id: notification.id
})
} }
}) this.routeJump({
}, name: 'notificationDetail',
toDetail(index, notification) { params: {
if(notification.readAt === 0) { notification: JSON.stringify(notification)
notification.readAt = 1 }
this.updateNotificationItem(index,notification)
markAsReadNotification({
id: notification.id
}) })
} },
this.routeJump({ async refresherList() {
name: 'notificationDetail', this.refresherTriggered = true
params: {
notification: JSON.stringify(notification)
}
})
},
async refresherList() {
this.refresherTriggered = true
this.updateNotificationSearch({
pageNo: 1
})
const { code, message } = await this.getNotificationList(this.notificationSearch)
if(code === 0) {
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.refresherTriggered = false
},
async nextPage() {
if(this.notificationTotal <= this.notificationSearch.pageNo * this.notificationSearch.pageSize) {
return
}
const pageNo = this.notificationSearch.pageNo + 1
const params = {
...this.notificationSearch,
pageNo
}
const { code, message } = await this.getNotificationList(params)
if(code === 0) {
this.updateNotificationSearch({ this.updateNotificationSearch({
pageNo: 1
})
const { code, message } = await this.getNotificationList(this.notificationSearch)
if (code === 0) {
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.refresherTriggered = false
},
async nextPage() {
if (
this.notificationTotal <=
this.notificationSearch.pageNo * this.notificationSearch.pageSize
) {
return
}
const pageNo = this.notificationSearch.pageNo + 1
const params = {
...this.notificationSearch,
pageNo pageNo
}) }
} else { const { code, message } = await this.getNotificationList(params)
uni.showToast({ if (code === 0) {
title: message, this.updateNotificationSearch({
icon: 'none' pageNo
}) })
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
} }
}, }
}, }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
.u-swipe-action { .u-swipe-action {
overflow: inherit !important; overflow: inherit !important;
width: 700rpx; width: 700rpx;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
padding-bottom: 140rpx !important; padding-bottom: 140rpx !important;
} }
.u-swipe-action-item { .u-swipe-action-item {
overflow: inherit !important; overflow: inherit !important;
border-radius: 32rpx !important; border-radius: 32rpx !important;
background: transparent !important; background: transparent !important;
} }
.u-swipe-action-item__right { .u-swipe-action-item__right {
margin-top: 32rpx; margin-top: 32rpx;
border-radius: 32rpx !important; border-radius: 32rpx !important;
} }
.u-swipe-action-item__content { .u-swipe-action-item__content {
border-radius: 32rpx !important; border-radius: 32rpx !important;
margin-left: 25rpx; margin-left: 25rpx;
} }
.u-swipe-action-item__right__button { .u-swipe-action-item__right__button {
border-radius: 32rpx !important; border-radius: 32rpx !important;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.item { .item {
border-radius: 32rpx; border-radius: 32rpx;
}
.notification {
border-radius: 32rpx;
margin-top: 32rpx;
display: flex;
width: 636rpx;
padding: 32rpx;
justify-content: space-between;
align-items: center;
position: relative;
box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.3);
.icon {
width: 50rpx;
height: 50rpx;
} }
.point { .notification {
width: 16rpx; border-radius: 32rpx;
height: 16rpx; margin-top: 32rpx;
background-color: #ff0000; display: flex;
width: 636rpx;
padding: 32rpx;
justify-content: space-between;
align-items: center;
position: relative;
box-shadow: 2rpx 2rpx 10rpx rgba(0, 0, 0, 0.3);
.icon {
width: 50rpx;
height: 50rpx;
}
.point {
width: 16rpx;
height: 16rpx;
background-color: #ff0000;
border-radius: 50%;
position: absolute;
top: 41rpx;
left: 72rpx;
}
.content {
width: 550rpx;
font-size: 28rpx;
color: #6c6c6c;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: bold;
}
.time {
font-size: 24rpx;
color: #6c6c6c;
margin-top: 5rpx;
font-weight: bold;
}
}
.delete {
width: 100rpx;
height: 100rpx;
border-radius: 50%; border-radius: 50%;
position: absolute; background-color: #5db5aa;
top: 41rpx; position: fixed;
left: 72rpx; bottom: 80rpx;
right: 30rpx;
display: flex;
justify-content: center;
align-items: center;
.delete-image {
width: 45rpx;
height: 45rpx;
}
} }
.content { .empty-list {
width: 550rpx; width: 150rpx;
height: 150rpx;
margin: 400rpx auto 20rpx 50%;
transform: translateX(-50%);
}
.empty-list-text {
text-align: center;
font-size: 32rpx;
color: #999999;
}
.tips {
margin-top: 40vh;
padding: 32rpx 0;
text-align: center;
font-size: 28rpx; font-size: 28rpx;
color: #6c6c6c; color: #999999;
white-space: nowrap; }
overflow: hidden;
text-overflow: ellipsis; .button-login {
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; font-weight: bold;
} }
.time {
font-size: 24rpx;
color: #6c6c6c;
margin-top: 5rpx;
font-weight: bold;
}
}
.delete {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
background-color: #5db5aa;
position: fixed;
bottom: 80rpx;
right: 30rpx;
display: flex;
justify-content: center;
align-items: center;
.delete-image {
width: 45rpx;
height: 45rpx;
}
}
.empty-list {
width: 150rpx;
height: 150rpx;
margin: 400rpx auto 20rpx 50%;
transform: translateX(-50%);
}
.empty-list-text {
text-align: center;
font-size: 32rpx;
color: #999999;
}
.tips {
margin-top: 40vh;
padding: 32rpx 0;
text-align: center;
font-size: 28rpx;
color: #999999;
}
.button-login {
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> </style>

View File

@ -12,8 +12,12 @@
<view class="item-title">有效期</view> <view class="item-title">有效期</view>
<view v-if="currentPasswordInfo.keyboardPwdType === 2">永久</view> <view v-if="currentPasswordInfo.keyboardPwdType === 2">永久</view>
<view v-else-if="currentPasswordInfo.keyboardPwdType <= 4"> <view v-else-if="currentPasswordInfo.keyboardPwdType <= 4">
<view class="item-content">{{ timeFormat(currentPasswordInfo.startDate, 'yyyy-mm-dd h:M') }}</view> <view class="item-content">{{
<view class="item-content">{{ timeFormat(currentPasswordInfo.endDate, 'yyyy-mm-dd h:M') }}</view> timeFormat(currentPasswordInfo.startDate, 'yyyy-mm-dd h:M')
}}</view>
<view class="item-content">{{
timeFormat(currentPasswordInfo.endDate, 'yyyy-mm-dd h:M')
}}</view>
</view> </view>
<view v-else> <view v-else>
{{ currentPasswordInfo.timeText.slice(0, -3) }} {{ currentPasswordInfo.timeText.slice(0, -3) }}
@ -25,136 +29,137 @@
</view> </view>
<view class="item" style="margin-top: 2rpx"> <view class="item" style="margin-top: 2rpx">
<view class="item-title">发送时间</view> <view class="item-title">发送时间</view>
<view class="item-content">{{ timeFormat(currentPasswordInfo.sendDate, 'yyyy-mm-dd h:M') }}</view> <view class="item-content">{{
timeFormat(currentPasswordInfo.sendDate, 'yyyy-mm-dd h:M')
}}</view>
</view> </view>
<view class="button" @click="deletePassword">删除</view> <view class="button" @click="deletePassword">删除</view>
</view> </view>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useLockStore } from '@/stores/lock' import { timeFormat } from 'uview-plus'
import { timeFormat } from 'uview-plus' import { useLockStore } from '@/stores/lock'
import { deletePsaawordRequest } from '@/api/keyboardPwd' import { deletePsaawordRequest } from '@/api/keyboardPwd'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return {} return {}
}, },
computed: { computed: {
...mapState(useLockStore, ['currentPasswordInfo', 'passwordSearch']), ...mapState(useLockStore, ['currentPasswordInfo', 'passwordSearch']),
...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']), ...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
...mapState(useUserStore, ['userInfo']) ...mapState(useUserStore, ['userInfo'])
}, },
methods: { methods: {
timeFormat, timeFormat,
...mapActions(useBluetoothStore, ['setLockPassword', 'closeBluetoothConnection']), ...mapActions(useBluetoothStore, ['setLockPassword', 'closeBluetoothConnection']),
...mapActions(useLockStore, ['updatePasswordSearch', 'getPasswordList']), ...mapActions(useLockStore, ['updatePasswordSearch', 'getPasswordList']),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']), ...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
async deletePassword () { async deletePassword() {
const netWork = await this.getNetworkType() const netWork = await this.getNetworkType()
if(!netWork) { if (!netWork) {
return return
} }
const that = this const that = this
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '确定要删除该密码', content: '确定要删除该密码',
async success(res) { async success(res) {
if(res.confirm) { if (res.confirm) {
uni.showLoading({ uni.showLoading({
title: '删除中', title: '删除中',
mask: true mask: true
})
const timestamp = parseInt(new Date().getTime() / 1000)
const { code } = await that.setLockPassword({
keyId: that.keyId.toString(),
uid: that.userInfo.uid.toString(),
pwdNo: that.currentPasswordInfo.pwdUserNo,
operate: 3,
isAdmin: that.currentPasswordInfo.pwdRight,
pwd: that.currentPasswordInfo.keyboardPwd,
userCountLimit: 0xFFFF,
startTime: timestamp,
endTime: timestamp
})
that.closeBluetoothConnection()
if(code === 0) {
const { code: requestCode, message } = await deletePsaawordRequest({
lockId: that.currentLockInfo.lockId,
keyboardPwdId: that.currentPasswordInfo.keyboardPwdId,
deleteType: 1
}) })
if(requestCode === 0) { const timestamp = parseInt(new Date().getTime() / 1000, 10)
uni.hideLoading() const { code } = await that.setLockPassword({
that.updatePasswordSearch({ keyId: that.keyId.toString(),
...that.passwordSearch, uid: that.userInfo.uid.toString(),
pageNo: 1 pwdNo: that.currentPasswordInfo.pwdUserNo,
operate: 3,
isAdmin: that.currentPasswordInfo.pwdRight,
pwd: that.currentPasswordInfo.keyboardPwd,
userCountLimit: 0xffff,
startTime: timestamp,
endTime: timestamp
})
that.closeBluetoothConnection()
if (code === 0) {
const { code: requestCode, message } = await deletePsaawordRequest({
lockId: that.currentLockInfo.lockId,
keyboardPwdId: that.currentPasswordInfo.keyboardPwdId,
deleteType: 1
}) })
that.getPasswordList(that.passwordSearch) if (requestCode === 0) {
that.backAndToast('删除成功') uni.hideLoading()
} else { that.updatePasswordSearch({
...that.passwordSearch,
pageNo: 1
})
that.getPasswordList(that.passwordSearch)
that.backAndToast('删除成功')
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} else if (code === -1) {
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: message, title: '删除失败,请保持在锁附近',
icon: 'none' icon: 'none'
}) })
} }
} else if(code === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
} }
} }
} })
}) }
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.item-title {
width: 350rpx;
}
.item-title { .item {
width: 350rpx; padding: 24rpx 32rpx;
} background-color: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 32rpx;
font-weight: 500;
}
.item { .tips {
padding: 24rpx 32rpx; padding: 24rpx 32rpx;
background-color: #FFFFFF; font-size: 24rpx;
display: flex; color: #999999;
align-items: center; }
justify-content: space-between;
font-size: 32rpx;
font-weight: 500;
}
.tips { .button {
padding: 24rpx 32rpx; margin: 32rpx;
font-size: 24rpx; width: 686rpx;
color: #999999; height: 88rpx;
} background-color: #df282d;
color: white;
.button { text-align: center;
margin: 32rpx; line-height: 88rpx;
width: 686rpx; border-radius: 44rpx;
height: 88rpx; font-weight: bold;
background-color: #df282d; }
color: white;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
font-weight: bold;
}
</style> </style>

View File

@ -1,24 +1,55 @@
<template> <template>
<view> <view>
<scroll-view v-if="deviceInfo" scroll-y="true" :style="{height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px'}" lower-threshold="100" <scroll-view
@refresherrefresh="refresherList" :refresher-enabled="true" @scrolltolower="nextPage" v-if="deviceInfo"
:refresher-triggered="refresherTriggered"> scroll-y="true"
:style="{ height: deviceInfo.screenHeight - deviceInfo.safeArea.top + 'px' }"
lower-threshold="100"
@refresherrefresh="refresherList"
:refresher-enabled="true"
@scrolltolower="nextPage"
:refresher-triggered="refresherTriggered"
>
<view class="search"> <view class="search">
<up-search shape="square" :searchIconSize="48" :inputStyle="{ fontSize: '32rpx' }" :height="80" placeholder="搜索" <up-search
:clearabled="false" @change="changeSearch" shape="square"
v-model="passwordSearch.searchStr" bgColor="#ffffff" :showAction="false" maxlength="50"></up-search> :searchIconSize="48"
:inputStyle="{ fontSize: '32rpx' }"
:height="80"
placeholder="搜索"
:clearabled="false"
@change="changeSearch"
v-model="passwordSearch.searchStr"
bgColor="#ffffff"
:showAction="false"
maxlength="50"
></up-search>
</view> </view>
<view style="padding: 32rpx 0 calc(env(safe-area-inset-bottom) + 250rpx) 0"> <view style="padding: 32rpx 0 calc(env(safe-area-inset-bottom) + 250rpx) 0">
<view v-if="passwordList.length === 0 && requestFinished"> <view v-if="passwordList.length === 0 && requestFinished">
<image class="empty-list" src="/static/images/background_empty_list.png" mode="aspectFill"></image> <image
class="empty-list"
src="/static/images/background_empty_list.png"
mode="aspectFill"
></image>
<view class="empty-list-text">暂无数据</view> <view class="empty-list-text">暂无数据</view>
</view> </view>
<view v-else> <view v-else>
<up-swipe-action> <up-swipe-action>
<up-swipe-action-item ref="swipeItem" :options="options" v-for="(password, index) in passwordList" <up-swipe-action-item
:key="password.keyboardPwdId" :threshold="50" @click="deletePassword(password)"> ref="swipeItem"
:options="options"
v-for="password in passwordList"
:key="password.keyboardPwdId"
:threshold="50"
@click="deletePassword(password)"
>
<view class="password" @click="toPasswordDetail(password)"> <view class="password" @click="toPasswordDetail(password)">
<image class="password-left" src="/static/images/icon_password.png" mode="aspectFill"></image> <image
class="password-left"
src="/static/images/icon_password.png"
mode="aspectFill"
></image>
<view class="password-right"> <view class="password-right">
<view style="display: flex; align-items: center"> <view style="display: flex; align-items: center">
<view class="password-right-top">{{ password.keyboardPwdName }}</view> <view class="password-right-top">{{ password.keyboardPwdName }}</view>
@ -43,352 +74,365 @@
</template> </template>
<script> <script>
import { useBasicStore } from '@/stores/basic' import { mapActions, mapState } from 'pinia'
import { mapActions, mapState } from 'pinia' import { useBasicStore } from '@/stores/basic'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useLockStore } from '@/stores/lock' import { useLockStore } from '@/stores/lock'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { deletePsaawordRequest, resetPsaawordListRequest } from '@/api/keyboardPwd' import { deletePsaawordRequest, resetPsaawordListRequest } from '@/api/keyboardPwd'
export default { export default {
data () { data() {
return { return {
deviceInfo: null, deviceInfo: null,
refresherTriggered: false, refresherTriggered: false,
requestFinished: false, requestFinished: false,
options: [{ options: [
text: '删除', {
style: { text: '删除',
backgroundColor: '#f56c6c' style: {
} backgroundColor: '#f56c6c'
}]
}
},
computed: {
...mapState(useUserStore, ['userInfo']),
...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
...mapState(useLockStore, ['passwordTotal', 'passwordList', 'passwordSearch']),
},
async onLoad() {
uni.showLoading({
title: '加载中',
mask: true
})
this.deviceInfo = await this.getDeviceInfo()
this.updatePasswordSearch({
...this.passwordSearch,
lockId: this.currentLockInfo.lockId,
lockStatus: this.currentLockInfo.lockStatus
})
const { code, message } = await this.getPasswordList(this.passwordSearch)
this.requestFinished = true
uni.hideLoading()
if(code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
onUnload() {
this.clearList('password')
},
methods: {
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType']),
...mapActions(useLockStore, ['getPasswordList', 'updateCurrentPasswordInfo', 'updatePasswordSearch',
'getPasswordStatus', 'clearList']),
...mapActions(useBluetoothStore, ['resetLockPassword', 'setLockPassword', 'closeBluetoothConnection']),
toPasswordDetail(password) {
this.updateCurrentPasswordInfo(password)
this.routeJump({
name: 'passwordDetail'
})
},
async deletePassword(data) {
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
const password = data
const that = this
let index = this.passwordList.findIndex(item => item.keyboardPwdId === password.keyboardPwdId)
that.$refs.swipeItem[index].closeHandler()
uni.showModal({
title: '提示',
content: '确定要删除该密码',
async success(res) {
if(res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
})
const timestamp = parseInt(new Date().getTime() / 1000)
const { code } = await that.setLockPassword({
keyId: that.keyId.toString(),
uid: that.userInfo.uid.toString(),
pwdNo: password.pwdUserNo,
operate: 3,
isAdmin: password.pwdRight,
pwd: password.keyboardPwd,
userCountLimit: 0xFFFF,
startTime: timestamp,
endTime: timestamp
})
that.closeBluetoothConnection()
if(code === 0) {
const { code: requestCode, message } = await deletePsaawordRequest({
lockId: that.currentLockInfo.lockId,
keyboardPwdId: password.keyboardPwdId,
deleteType: 1
})
if(requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'none'
})
that.updatePasswordSearch({
...that.passwordSearch,
pageNo: 1
})
await that.getPasswordList(that.passwordSearch)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} else if(code === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
} }
} }
} ]
})
},
async resetPassword() {
const that = this
const netWork = await this.getNetworkType()
if(!netWork) {
return
} }
uni.showModal({
title: '提示',
content: '确定要重置密码,该锁的所有密码都将被删除',
async success(res) {
if(res.confirm) {
uni.showLoading({
title: '重置中',
mask: true
})
const { code } = await that.resetLockPassword({
uid: that.userInfo.uid.toString(),
keyId: that.currentLockInfo.keyId.toString()
})
that.closeBluetoothConnection()
if(code === 0) {
const { code: requestCode, message } = await resetPsaawordListRequest({
lockId: that.currentLockInfo.lockId,
passwordKey: that.currentLockInfo.encrpyKey
})
console.log('重置密码返回', requestCode, message)
if(requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: '重置密码成功',
icon: 'none'
})
that.updatePasswordSearch({
...that.passwordSearch,
pageNo: 1
})
that.getPasswordList(that.passwordSearch)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} else if(code === -1) {
uni.hideLoading()
uni.showToast({
title: '重置密码失败,请保持在锁附近',
icon: 'none'
})
}
}
}
})
}, },
toCreatePassword() { computed: {
this.routeJump({ ...mapState(useUserStore, ['userInfo']),
name: 'createPassword' ...mapState(useBluetoothStore, ['currentLockInfo', 'keyId']),
}) ...mapState(useLockStore, ['passwordTotal', 'passwordList', 'passwordSearch'])
}, },
async refresherList() { async onLoad() {
this.refresherTriggered = true uni.showLoading({
title: '加载中',
mask: true
})
this.deviceInfo = await this.getDeviceInfo()
this.updatePasswordSearch({ this.updatePasswordSearch({
...this.passwordSearch, ...this.passwordSearch,
pageNo: 1 lockId: this.currentLockInfo.lockId,
lockStatus: this.currentLockInfo.lockStatus
}) })
const { code, message } = await this.getPasswordList(this.passwordSearch) const { code, message } = await this.getPasswordList(this.passwordSearch)
if(code === 0) { this.requestFinished = true
uni.showToast({ uni.hideLoading()
title: '刷新成功', if (code !== 0) {
icon: 'none'
})
} else {
uni.showToast({ uni.showToast({
title: message, title: message,
icon: 'none' icon: 'none'
}) })
} }
this.refresherTriggered = false
}, },
async nextPage() { onUnload() {
if(this.passwordTotal <= this.passwordSearch.pageNo * this.passwordSearch.pageSize) { this.clearList('password')
return },
} methods: {
const pageNo = this.passwordSearch.pageNo + 1 ...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType']),
const params = { ...mapActions(useLockStore, [
...this.passwordSearch, 'getPasswordList',
pageNo 'updateCurrentPasswordInfo',
} 'updatePasswordSearch',
const { code, message } = await this.getPasswordList(params) 'getPasswordStatus',
if(code === 0) { 'clearList'
that.updatePasswordSearch({ ]),
...that.passwordSearch, ...mapActions(useBluetoothStore, [
'resetLockPassword',
'setLockPassword',
'closeBluetoothConnection'
]),
toPasswordDetail(password) {
this.updateCurrentPasswordInfo(password)
this.routeJump({
name: 'passwordDetail'
})
},
async deletePassword(data) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
const password = data
const that = this
let index = this.passwordList.findIndex(
item => item.keyboardPwdId === password.keyboardPwdId
)
that.$refs.swipeItem[index].closeHandler()
uni.showModal({
title: '提示',
content: '确定要删除该密码',
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
})
const timestamp = parseInt(new Date().getTime() / 1000, 10)
const { code } = await that.setLockPassword({
keyId: that.keyId.toString(),
uid: that.userInfo.uid.toString(),
pwdNo: password.pwdUserNo,
operate: 3,
isAdmin: password.pwdRight,
pwd: password.keyboardPwd,
userCountLimit: 0xffff,
startTime: timestamp,
endTime: timestamp
})
that.closeBluetoothConnection()
if (code === 0) {
const { code: requestCode, message } = await deletePsaawordRequest({
lockId: that.currentLockInfo.lockId,
keyboardPwdId: password.keyboardPwdId,
deleteType: 1
})
if (requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'none'
})
that.updatePasswordSearch({
...that.passwordSearch,
pageNo: 1
})
await that.getPasswordList(that.passwordSearch)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} else if (code === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
}
}
}
})
},
async resetPassword() {
const that = this
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
uni.showModal({
title: '提示',
content: '确定要重置密码,该锁的所有密码都将被删除',
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '重置中',
mask: true
})
const { code } = await that.resetLockPassword({
uid: that.userInfo.uid.toString(),
keyId: that.currentLockInfo.keyId.toString()
})
that.closeBluetoothConnection()
if (code === 0) {
const { code: requestCode, message } = await resetPsaawordListRequest({
lockId: that.currentLockInfo.lockId,
passwordKey: that.currentLockInfo.encrpyKey
})
console.log('重置密码返回', requestCode, message)
if (requestCode === 0) {
uni.hideLoading()
uni.showToast({
title: '重置密码成功',
icon: 'none'
})
that.updatePasswordSearch({
...that.passwordSearch,
pageNo: 1
})
that.getPasswordList(that.passwordSearch)
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
} else if (code === -1) {
uni.hideLoading()
uni.showToast({
title: '重置密码失败,请保持在锁附近',
icon: 'none'
})
}
}
}
})
},
toCreatePassword() {
this.routeJump({
name: 'createPassword'
})
},
async refresherList() {
this.refresherTriggered = true
this.updatePasswordSearch({
...this.passwordSearch,
pageNo: 1
})
const { code, message } = await this.getPasswordList(this.passwordSearch)
if (code === 0) {
uni.showToast({
title: '刷新成功',
icon: 'none'
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.refresherTriggered = false
},
async nextPage() {
if (this.passwordTotal <= this.passwordSearch.pageNo * this.passwordSearch.pageSize) {
return
}
const pageNo = this.passwordSearch.pageNo + 1
const params = {
...this.passwordSearch,
pageNo pageNo
}
const { code, message } = await this.getPasswordList(params)
if (code === 0) {
this.updatePasswordSearch({
...this.passwordSearch,
pageNo
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
},
async changeSearch(data) {
this.updatePasswordSearch({
...this.passwordSearch,
searchStr: data
}) })
} else { const { code, message } = await this.getPasswordList(this.passwordSearch)
uni.showToast({ if (code !== 0) {
title: message, uni.showToast({
icon: 'none' title: message,
}) icon: 'none'
})
}
} }
}, }
async changeSearch(data) { }
this.updatePasswordSearch({
...this.passwordSearch,
searchStr: data
})
const { code, message } = await this.getPasswordList(this.passwordSearch)
if(code !== 0) {
uni.showToast({
title: message,
icon: 'none'
})
}
},
},
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.search { .search {
margin-top: 32rpx; margin-top: 32rpx;
width: 686rpx !important; width: 686rpx !important;
margin-left: 32rpx;
}
.button {
display: flex;
align-items: center;
position: fixed;
bottom: calc(env(safe-area-inset-bottom) + 48rpx);
font-weight: bold;
.button-reset {
margin-left: 50rpx;
width: 300rpx;
height: 88rpx;
background-color: #df282d;
color: white;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
}
.button-create {
margin-left: 50rpx;
width: 300rpx;
height: 88rpx;
background-color: #63b8af;
color: white;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
}
}
.password {
display: flex;
align-items: center;
background-color: #FFFFFF;
height: 120rpx;
width: 750rpx;
.password-left {
margin-left: 32rpx; margin-left: 32rpx;
width: 80rpx;
height: 80rpx;
} }
.password-right { .button {
margin-right: 32rpx; display: flex;
margin-left: 32rpx; align-items: center;
width: 574rpx; position: fixed;
bottom: calc(env(safe-area-inset-bottom) + 48rpx);
font-weight: bold;
.password-right-top { .button-reset {
max-width: 400rpx; margin-left: 50rpx;
font-size: 32rpx; width: 300rpx;
font-weight: bold; height: 88rpx;
padding-bottom: 6rpx; background-color: #df282d;
white-space: nowrap; color: white;
overflow: hidden; text-align: center;
text-overflow: ellipsis; line-height: 88rpx;
border-radius: 44rpx;
} }
.password-right-bottom { .button-create {
font-size: 24rpx; margin-left: 50rpx;
color: #999999; width: 300rpx;
height: 88rpx;
background-color: #63b8af;
color: white;
text-align: center;
line-height: 88rpx;
border-radius: 44rpx;
} }
} }
}
.line { .password {
width: 100%; display: flex;
height: 2rpx; align-items: center;
background: #EBEBEB; background-color: #ffffff;
} height: 120rpx;
width: 750rpx;
.empty-list { .password-left {
width: 150rpx; margin-left: 32rpx;
height: 150rpx; width: 80rpx;
margin: 300rpx auto 20rpx 50%; height: 80rpx;
transform: translateX(-50%); }
}
.empty-list-text { .password-right {
text-align: center; margin-right: 32rpx;
font-size: 32rpx; margin-left: 32rpx;
color: #999999; width: 574rpx;
}
.key-status { .password-right-top {
margin-left: auto; max-width: 400rpx;
font-size: 26rpx; font-size: 32rpx;
color: #df282d; font-weight: bold;
} padding-bottom: 6rpx;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.password-right-bottom {
font-size: 24rpx;
color: #999999;
}
}
}
.line {
width: 100%;
height: 2rpx;
background: #ebebeb;
}
.empty-list {
width: 150rpx;
height: 150rpx;
margin: 300rpx auto 20rpx 50%;
transform: translateX(-50%);
}
.empty-list-text {
text-align: center;
font-size: 32rpx;
color: #999999;
}
.key-status {
margin-left: auto;
font-size: 26rpx;
color: #df282d;
}
</style> </style>

View File

@ -1,173 +1,200 @@
<template> <template>
<view> <view>
<scroll-view v-if="deviceInfo" class="scroll-view" scroll-y="true" :style="{ height: deviceInfo.screenHeight - deviceInfo.statusBarHeight + 'px' }"> <scroll-view
v-if="deviceInfo"
class="scroll-view"
scroll-y="true"
:style="{ height: deviceInfo.screenHeight - deviceInfo.statusBarHeight + 'px' }"
>
<view style="padding-bottom: calc(env(safe-area-inset-bottom) + 300rpx)"> <view style="padding-bottom: calc(env(safe-area-inset-bottom) + 300rpx)">
<view class="device" v-for="device in deviceList" @click="connect(device)"> <view
<view class="device" style="justify-content:flex-start;"> class="device"
<image class="device-lock" src="/static/images/icon_door_lock.png"></image> v-for="(device, index) in deviceList"
<view class="device-name">{{device.name}}</view> :key="index"
@click="connect(device)"
>
<view class="device" style="justify-content: flex-start">
<image class="device-lock" src="/static/images/icon_door_lock.png"></image>
<view class="device-name">{{ device.name }}</view>
</view> </view>
<image class="device-add" src="/static/images/icon_add.png"></image> <image class="device-add" src="/static/images/icon_add.png"></image>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
<view class="loading"> <view class="loading">
<up-loading-icon size="80rpx" text="搜索中" :vertical="true" textSize="32rpx"></up-loading-icon> <up-loading-icon
size="80rpx"
text="搜索中"
:vertical="true"
textSize="32rpx"
></up-loading-icon>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import { mapState, mapActions } from 'pinia' import { mapState, mapActions } from 'pinia'
import { useBluetoothStore } from '@/stores/bluetooth' import { useBluetoothStore } from '@/stores/bluetooth'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
export default { export default {
data () { data() {
return { return {
deviceInfo: null deviceInfo: null
}
},
computed: {
...mapState(useBluetoothStore, ['deviceList', 'currentLockInfo', 'serverTimestamp', 'keyId']),
...mapState(useUserStore, ['userInfo'])
},
async onLoad() {
this.deviceInfo = await this.getDeviceInfo()
this.getBluetoothDevices()
},
onUnload() {
this.stopGetBluetoothDevices()
},
methods: {
...mapActions(useBluetoothStore, ['getBluetoothDevices', 'stopGetBluetoothDevices', 'updateCurrentLockInfo',
'getPublicKey', 'getCommKey', 'connectBluetoothDevice', 'updateServerTimestamp', 'getLockStatus']),
...mapActions(useBasicStore, ['getDeviceInfo', 'routeJump', 'getNetworkType']),
async connect(device) {
const netWork = await this.getNetworkType()
if(!netWork) {
return
} }
uni.showLoading({ },
title: '连接中', computed: {
mask: true ...mapState(useBluetoothStore, ['deviceList', 'currentLockInfo', 'serverTimestamp', 'keyId']),
}) ...mapState(useUserStore, ['userInfo'])
const { code: serverTimestampCode, message } = await this.updateServerTimestamp() },
if(serverTimestampCode !== 0) { async onLoad() {
uni.showToast({ this.deviceInfo = await this.getDeviceInfo()
title: message, this.getBluetoothDevices()
icon: 'none' },
onUnload() {
this.stopGetBluetoothDevices()
},
methods: {
...mapActions(useBluetoothStore, [
'getBluetoothDevices',
'stopGetBluetoothDevices',
'updateCurrentLockInfo',
'getPublicKey',
'getCommKey',
'connectBluetoothDevice',
'updateServerTimestamp',
'getLockStatus'
]),
...mapActions(useBasicStore, ['getDeviceInfo', 'routeJump', 'getNetworkType']),
async connect(device) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
uni.showLoading({
title: '连接中',
mask: true
}) })
uni.hideLoading() const { code: serverTimestampCode, message } = await this.updateServerTimestamp()
return if (serverTimestampCode !== 0) {
} uni.showToast({
this.updateCurrentLockInfo({ title: message,
name: device.name, icon: 'none'
deviceId: device.deviceId
})
try {
const result = await this.connectBluetoothDevice()
if(result) {
this.stopGetBluetoothDevices()
const { code: getPublicKeyCode } = await this.getPublicKey(this.currentLockInfo.name)
console.log('获取公钥返回', getPublicKeyCode, [...this.currentLockInfo.publicKey])
if(getPublicKeyCode !== 0) {
uni.hideLoading()
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
return
}
const { code: getCommKeyCode } = await this.getCommKey(this.currentLockInfo.name, this.keyId,
this.userInfo.uid.toString(), this.serverTimestamp)
console.log('获取私钥返回', getCommKeyCode)
if(getCommKeyCode !== 0) {
uni.hideLoading()
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
return
}
const date = new Date()
const timestamp = parseInt(date.getTime() / 1000) - date.getTimezoneOffset() * 60
const { code } = await this.getLockStatus({
name: this.currentLockInfo.name,
uid: this.userInfo.uid,
nowTime: this.serverTimestamp,
localTime: timestamp
}) })
if (code !== 0) { uni.hideLoading()
return
}
this.updateCurrentLockInfo({
name: device.name,
deviceId: device.deviceId
})
try {
const result = await this.connectBluetoothDevice()
if (result) {
this.stopGetBluetoothDevices()
const { code: getPublicKeyCode } = await this.getPublicKey(this.currentLockInfo.name)
console.log('获取公钥返回', getPublicKeyCode, [...this.currentLockInfo.publicKey])
if (getPublicKeyCode !== 0) {
uni.hideLoading()
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
return
}
const { code: getCommKeyCode } = await this.getCommKey(
this.currentLockInfo.name,
this.keyId,
this.userInfo.uid.toString(),
this.serverTimestamp
)
console.log('获取私钥返回', getCommKeyCode)
if (getCommKeyCode !== 0) {
uni.hideLoading()
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
return
}
const date = new Date()
const timestamp = parseInt(date.getTime() / 1000, 10) - date.getTimezoneOffset() * 60
const { code } = await this.getLockStatus({
name: this.currentLockInfo.name,
uid: this.userInfo.uid,
nowTime: this.serverTimestamp,
localTime: timestamp
})
if (code !== 0) {
uni.hideLoading()
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
return
}
this.routeJump({
type: 'redirectTo',
name: 'selectAddress'
})
} else {
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态', title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none' icon: 'none'
}) })
return
} }
this.routeJump({ } catch (res) {
type: 'redirectTo',
name: 'selectAddress'
})
} else {
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态', title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none' icon: 'none'
}) })
} }
} catch (res) {
uni.hideLoading()
uni.showToast({
title: '连接失败,请靠近设备并保持设备处于唤醒状态',
icon: 'none'
})
} }
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.loading { .loading {
position: fixed; position: fixed;
bottom: calc(env(safe-area-inset-bottom) + 50rpx) ; bottom: calc(env(safe-area-inset-bottom) + 50rpx);
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
}
.device {
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
height: 100rpx;
.device-lock {
margin-left: 24rpx;
width: 72rpx;
height: 72rpx;
} }
.device-name { .device {
margin-left: 24rpx; background: #ffffff;
font-size: 28rpx; display: flex;
font-weight: bold; align-items: center;
} justify-content: space-between;
height: 100rpx;
.device-add { .device-lock {
float: right; margin-left: 24rpx;
width: 60rpx; width: 72rpx;
height: 60rpx; height: 72rpx;
margin-right: 24rpx; }
.device-name {
margin-left: 24rpx;
font-size: 28rpx;
font-weight: bold;
}
.device-add {
float: right;
width: 60rpx;
height: 60rpx;
margin-right: 24rpx;
}
} }
}
</style> </style>

View File

@ -2,12 +2,22 @@
<view> <view>
<view class="title">地理位置</view> <view class="title">地理位置</view>
<view v-if="show"> <view v-if="show">
<map class="map" :longitude="longitude" :latitude="latitude" :scale="16" :markers="markers" <map
:enable-zoom="true" :enable-scroll="true"></map> class="map"
:longitude="longitude"
:latitude="latitude"
:scale="16"
:markers="markers"
:enable-zoom="true"
:enable-scroll="true"
></map>
</view> </view>
<view v-else class="map"></view> <view v-else class="map"></view>
<view class="explain">检查以确保以下地址是正确的</view> <view class="explain">检查以确保以下地址是正确的</view>
<view class="view-address" :style="{height: calculateStringTotalWidth(address) > 44 ? '120rpx' : '80rpx'}"> <view
class="view-address"
:style="{ height: calculateStringTotalWidth(address) > 44 ? '120rpx' : '80rpx' }"
>
<view class="address">{{ address }}</view> <view class="address">{{ address }}</view>
</view> </view>
<view class="bottom"> <view class="bottom">
@ -18,257 +28,256 @@
</template> </template>
<script> <script>
import { test } from 'uview-plus' import { mapState, mapActions } from 'pinia'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
import { mapState, mapActions } from 'pinia' import { getGeocodeAddress } from '@/api/geocode'
import { getGeocodeAddress } from '@/api/geocode' import { useBluetoothStore } from '@/stores/bluetooth'
import { useBluetoothStore } from '@/stores/bluetooth'
export default { export default {
data () { data() {
return { return {
latitude: null, latitude: null,
longitude: null, longitude: null,
show: false, show: false,
markers: [], markers: [],
address: '', address: '',
first: true first: true
} }
}, },
computed: { computed: {
...mapState(useBluetoothStore, ['currentLockInfo']) ...mapState(useBluetoothStore, ['currentLockInfo'])
}, },
onLoad() { onLoad() {
this.getLocation() this.getLocation()
}, },
onShow() { onShow() {
if(this.first) { if (this.first) {
this.first = false this.first = false
} else { } else if (!this.show) {
if(!this.show) {
this.getLocation() this.getLocation()
} }
}
},
methods: {
...mapActions(useBasicStore, ['routeJump', 'calculateStringTotalWidth']),
...mapActions(useBluetoothStore, ['updateCurrentLockInfo']),
toBindLock() {
const that = this
if(this.address === '') {
uni.showModal({
title: '提示',
content: '暂未获取到地理位置信息,请重试',
confirmText: '重试',
success: (res) => {
if(res.confirm) {
that.getLocation()
}
}
})
return
}
this.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}, },
skipAddress() { methods: {
const that = this ...mapActions(useBasicStore, ['routeJump', 'calculateStringTotalWidth']),
if(this.address !== '') { ...mapActions(useBluetoothStore, ['updateCurrentLockInfo']),
uni.showModal({ toBindLock() {
title: '提示', const that = this
content: '已获取当前地理位置,确定跳过吗', if (this.address === '') {
confirmText: '跳过', uni.showModal({
cancelText: '取消', title: '提示',
success: (res) => { content: '暂未获取到地理位置信息,请重试',
if(res.confirm) { confirmText: '重试',
const lockInfo = that.currentLockInfo success: res => {
delete lockInfo.position if (res.confirm) {
that.updateCurrentLockInfo(lockInfo) that.getLocation()
this.routeJump({ }
type: 'redirectTo', }
name: 'bindLock' })
return
}
this.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
},
skipAddress() {
const that = this
if (this.address !== '') {
uni.showModal({
title: '提示',
content: '已获取当前地理位置,确定跳过吗',
confirmText: '跳过',
cancelText: '取消',
success: res => {
if (res.confirm) {
const lockInfo = that.currentLockInfo
delete lockInfo.position
that.updateCurrentLockInfo(lockInfo)
this.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
})
return
}
this.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
},
async getLocation() {
const that = this
uni.getLocation({
isHighAccuracy: true,
type: 'gcj02',
async success(res) {
that.latitude = res.latitude
that.longitude = res.longitude
that.markers = [
{
id: 1,
latitude: res.latitude,
longitude: res.longitude,
iconPath: '/static/images/icon_address.png',
width: '48rpx',
height: '48rpx'
}
]
that.show = true
const { code, data: result } = await getGeocodeAddress({
latitude: that.latitude,
longitude: that.longitude
})
if (code === 0) {
that.address = result.addr
const position = {
...result,
latitude: that.latitude,
longitude: that.longitude
}
console.log('获取地理位置信息', that.currentLockInfo)
that.updateCurrentLockInfo({
...that.currentLockInfo,
position
})
console.log('获取地理位置信息', that.currentLockInfo)
}
},
fail(res) {
console.log('获取地理位置信息失败', res)
if (res.errMsg === 'getLocation:fail auth deny') {
uni.showModal({
title: '提示',
content: '拒绝授权将无法使用定位功能',
confirmText: '去授权',
cancelText: '跳过',
success(res) {
if (res.confirm) {
uni.openSetting()
} else {
that.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
})
} else if (res.errMsg === 'getLocation:fail system permission denied') {
uni.showModal({
title: '提示',
content: '定位失败,请打开微信的位置权限',
confirmText: '去打开',
cancelText: '跳过',
success(res) {
if (res.confirm) {
uni.openAppAuthorizeSetting()
} else {
that.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
})
} else {
uni.showModal({
title: '提示',
content: '获取地理位置信息失败',
confirmText: '重试',
cancelText: '跳过',
success(res) {
if (res.confirm) {
that.getLocation()
} else {
that.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
}) })
} }
} }
}) })
return
} }
this.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
},
async getLocation() {
const that = this
uni.getLocation({
isHighAccuracy: true,
type: 'gcj02',
async success (res) {
that.latitude = res.latitude
that.longitude = res.longitude
that.markers = [{
id: 1,
latitude: res.latitude,
longitude: res.longitude,
iconPath: '/static/images/icon_address.png',
width: '48rpx',
height: '48rpx'
}]
that.show = true
const { code, data: result } = await getGeocodeAddress({
latitude: that.latitude,
longitude: that.longitude
})
if(code === 0) {
that.address = result.addr
const position = {
...result,
latitude: that.latitude,
longitude: that.longitude
}
console.log('获取地理位置信息', that.currentLockInfo)
that.updateCurrentLockInfo({
...that.currentLockInfo,
position
})
console.log('获取地理位置信息', that.currentLockInfo)
}
},
fail (res) {
console.log('获取地理位置信息失败', res)
if(res.errMsg === 'getLocation:fail auth deny') {
uni.showModal({
title: '提示',
content: '拒绝授权将无法使用定位功能',
confirmText: '去授权',
cancelText: '跳过',
success (res) {
if (res.confirm) {
uni.openSetting()
} else {
that.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
})
} else if(res.errMsg === 'getLocation:fail system permission denied') {
uni.showModal({
title: '提示',
content: '定位失败,请打开微信的位置权限',
confirmText: '去打开',
cancelText: '跳过',
success (res) {
if (res.confirm) {
uni.openAppAuthorizeSetting()
} else {
that.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
})
} else {
uni.showModal({
title: '提示',
content: '获取地理位置信息失败',
confirmText: '重试',
cancelText: '跳过',
success (res) {
if (res.confirm) {
that.getLocation()
} else {
that.routeJump({
type: 'redirectTo',
name: 'bindLock'
})
}
}
})
}
}
})
} }
}, }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.map { .map {
width: 750rpx; width: 750rpx;
height: 650rpx; height: 650rpx;
} }
.title { .title {
padding: 40rpx 30rpx; padding: 40rpx 30rpx;
font-size: 80rpx; font-size: 80rpx;
font-weight: bold; font-weight: bold;
} }
.explain { .explain {
padding: 20rpx 30rpx 0 30rpx; padding: 20rpx 30rpx 0 30rpx;
font-size: 40rpx; font-size: 40rpx;
} }
.view-address { .view-address {
display: flex; display: flex;
align-items: center; align-items: center;
width: 690rpx;
color: #c4c4c4;
font-size: 32rpx;
margin: 0 30rpx;
border-bottom: #63b8af 3rpx solid;
.address {
width: 690rpx; width: 690rpx;
text-align: left; color: #c4c4c4;
word-break: break-all; font-size: 32rpx;
display: -webkit-box; margin: 0 30rpx;
-webkit-box-orient: vertical; border-bottom: #63b8af 3rpx solid;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
}
}
.bottom { .address {
width: 600rpx; width: 690rpx;
display: flex; text-align: left;
justify-content: space-between; word-break: break-all;
padding: 0 75rpx; display: -webkit-box;
position: fixed; -webkit-box-orient: vertical;
bottom: calc(30rpx + env(safe-area-inset-bottom)); -webkit-line-clamp: 2;
overflow: hidden;
.skip { text-overflow: ellipsis;
width: 225rpx; white-space: normal;
height: 80rpx; }
line-height: 80rpx;
text-align: center;
font-size: 36rpx;
border-radius: 64rpx;
border: 3rpx solid #63b8af;
} }
.confirm { .bottom {
border-radius: 64rpx; width: 600rpx;
color: #FFFFFF; display: flex;
background-color: #63b8af; justify-content: space-between;
width: 225rpx; padding: 0 75rpx;
height: 80rpx; position: fixed;
line-height: 80rpx; bottom: calc(30rpx + env(safe-area-inset-bottom));
text-align: center;
font-size: 36rpx; .skip {
width: 225rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 36rpx;
border-radius: 64rpx;
border: 3rpx solid #63b8af;
}
.confirm {
border-radius: 64rpx;
color: #ffffff;
background-color: #63b8af;
width: 225rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
font-size: 36rpx;
}
} }
}
</style> </style>

View File

@ -4,28 +4,30 @@
<view class="view-button"> <view class="view-button">
<view style="width: 150rpx">名称</view> <view style="width: 150rpx">名称</view>
<view class="view-button" style="padding: 20rpx 0"> <view class="view-button" style="padding: 20rpx 0">
<view class="info" style="line-height: 40rpx;word-break: break-all;">{{currentLockInfo.lockAlias}}</view> <view class="info" style="line-height: 40rpx; word-break: break-all">{{
currentLockInfo.lockAlias
}}</view>
</view> </view>
</view> </view>
<view class="view-line"></view> <view class="view-line"></view>
<view class="view-button"> <view class="view-button">
<view>锁编号</view> <view>锁编号</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view class="info">{{currentLockInfo.name}}</view> <view class="info">{{ currentLockInfo.name }}</view>
</view> </view>
</view> </view>
<view class="view-line"></view> <view class="view-line"></view>
<view class="view-button"> <view class="view-button">
<view>MAC/ID</view> <view>MAC/ID</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view class="info">{{currentLockInfo.mac}}/{{currentLockInfo.lockId}}</view> <view class="info">{{ currentLockInfo.mac }}/{{ currentLockInfo.lockId }}</view>
</view> </view>
</view> </view>
<view class="view-line"></view> <view class="view-line"></view>
<view class="view-button"> <view class="view-button">
<view>电量</view> <view>电量</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view class="info">{{currentLockInfo.electricQuantity}}%</view> <view class="info">{{ currentLockInfo.electricQuantity }}%</view>
</view> </view>
</view> </view>
</view> </view>
@ -33,8 +35,15 @@
<view class="view-button"> <view class="view-button">
<view>开锁时是否需联网</view> <view>开锁时是否需联网</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<up-switch v-model="unlockApp" :size="40" activeColor="#63b8af" :asyncChange="true" <up-switch
@change="changeUnlockApp" :activeValue="1" :inactiveValue="0"></up-switch> v-model="unlockApp"
:size="40"
activeColor="#63b8af"
:asyncChange="true"
@change="changeUnlockApp"
:activeValue="1"
:inactiveValue="0"
></up-switch>
</view> </view>
</view> </view>
</view> </view>
@ -43,7 +52,11 @@
<view class="view-button"> <view class="view-button">
<view>有效期</view> <view>有效期</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view class="info">{{ timeFormat(currentLockInfo.startDate, 'yyyy-mm-dd') }}{{ timeFormat(currentLockInfo.endDate, 'yyyy-mm-dd') }}</view> <view class="info"
>{{ timeFormat(currentLockInfo.startDate, 'yyyy-mm-dd') }}{{
timeFormat(currentLockInfo.endDate, 'yyyy-mm-dd')
}}</view
>
</view> </view>
</view> </view>
<view class="view-line"></view> <view class="view-line"></view>
@ -57,8 +70,11 @@
<view class="view-button"> <view class="view-button">
<view>有效时间</view> <view>有效时间</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view class="info">{{ timeFormat(currentLockInfo.startDate, 'h:M') }}{{ <view class="info"
timeFormat(currentLockInfo.endDate, 'h:M') }}</view> >{{ timeFormat(currentLockInfo.startDate, 'h:M') }}{{
timeFormat(currentLockInfo.endDate, 'h:M')
}}</view
>
</view> </view>
</view> </view>
</view> </view>
@ -77,10 +93,16 @@
</view> </view>
</view> </view>
<view class="button-logout" @click="deleteLock">删除</view> <view class="button-logout" @click="deleteLock">删除</view>
<up-modal :show="showModal" title="是否删除授权管理员钥匙?" :showCancelButton="true" width="600rpx" @cancel="cancelModal" <up-modal
@confirm="confirmModal"> :show="showModal"
title="是否删除授权管理员钥匙?"
:showCancelButton="true"
width="600rpx"
@cancel="cancelModal"
@confirm="confirmModal"
>
<view class="slot-content" @click="changeRadio"> <view class="slot-content" @click="changeRadio">
<view style="display: flex;align-items: center;"> <view style="display: flex; align-items: center">
<radio :checked="checked"></radio> <radio :checked="checked"></radio>
<view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view> <view>同时删除其发送的所有钥匙钥匙删除后不能恢复</view>
</view> </view>
@ -90,133 +112,166 @@
</template> </template>
<script> <script>
import { useBluetoothStore } from '@/stores/bluetooth' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { timeFormat } from 'uview-plus'
import { mapActions, mapState } from 'pinia' import { useBluetoothStore } from '@/stores/bluetooth'
import { deleteLockRequest } from '@/api/lock' import { useUserStore } from '@/stores/user'
import { useLockStore } from '@/stores/lock' import { deleteLockRequest } from '@/api/lock'
import { updateLockSettingRequest } from '@/api/lockSetting' import { useLockStore } from '@/stores/lock'
import { deleteKeyRequest } from '@/api/key' import { updateLockSettingRequest } from '@/api/lockSetting'
import { useBasicStore } from '@/stores/basic' import { deleteKeyRequest } from '@/api/key'
import { timeFormat } from 'uview-plus' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return { return {
unlockApp: 0, unlockApp: 0,
showModal: false, showModal: false,
checked: false checked: false
}
},
computed: {
...mapState(useUserStore, ['userInfo']),
...mapState(useBluetoothStore, ['keyId', 'currentLockInfo']),
...mapState(useLockStore, ['lockSearch'])
},
onLoad() {
this.unlockApp = this.currentLockInfo.lockSetting.appUnlockOnline
},
methods: {
timeFormat,
...mapActions(useBluetoothStore, ['resetDevice', 'updateCurrentLockInfo']),
...mapActions(useLockStore, ['getLockList', 'updateLockSearch', 'convertWeekDaysToChineseString']),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
changeRadio() {
this.checked = !this.checked
},
cancelModal() {
this.showModal = false
this.checked = false
},
async confirmModal() {
uni.showLoading({
title: '删除中',
mask: true
})
const that = this
const { code } = await deleteKeyRequest({
keyId: that.keyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if(code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
} }
}, },
async changeUnlockApp(value) { computed: {
const netWork = await this.getNetworkType() ...mapState(useUserStore, ['userInfo']),
if(!netWork) { ...mapState(useBluetoothStore, ['keyId', 'currentLockInfo']),
return ...mapState(useLockStore, ['lockSearch'])
}
uni.showLoading({
title: '更新中',
mask: true
})
const { code, message } = await updateLockSettingRequest({
lockId: this.currentLockInfo.lockId,
appUnlockOnline: value
})
if(code === 0) {
this.unlockApp = value
const data = this.currentLockInfo
data.lockSetting.appUnlockOnline = value
this.updateCurrentLockInfo(data)
uni.hideLoading()
uni.showToast({
title: '更新成功',
icon: 'none'
})
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
}, },
async deleteLock() { onLoad() {
const netWork = await this.getNetworkType() this.unlockApp = this.currentLockInfo.lockSetting.appUnlockOnline
if(!netWork) { },
return methods: {
} timeFormat,
const that = this ...mapActions(useBluetoothStore, ['resetDevice', 'updateCurrentLockInfo']),
if(this.currentLockInfo.userType !== 110301 && this.currentLockInfo.keyRight === 1) { ...mapActions(useLockStore, [
this.showModal = true 'getLockList',
return 'updateLockSearch',
} 'convertWeekDaysToChineseString'
const message = that.currentLockInfo.userType === 110301 ? '删除锁后,所有信息都会一起删除,确定删除锁吗?' : '确定删除该钥匙吗?' ]),
uni.showModal({ ...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
title: '提示', changeRadio() {
content: message, this.checked = !this.checked
success: async function (res) { },
if (res.confirm) { cancelModal() {
uni.showLoading({ this.showModal = false
title: '删除中', this.checked = false
mask: true },
}) async confirmModal() {
if(that.currentLockInfo.userType === 110301) { uni.showLoading({
const { code: resetDeviceCode } = await that.resetDevice({ title: '删除中',
name: that.currentLockInfo.name, mask: true
authUid: that.userInfo.uid.toString(), })
keyId: that.keyId.toString() const that = this
const { code } = await deleteKeyRequest({
keyId: that.keyId,
includeUnderlings: that.checked ? 1 : 0
})
that.showModal = false
if (code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
},
async changeUnlockApp(value) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
uni.showLoading({
title: '更新中',
mask: true
})
const { code, message } = await updateLockSettingRequest({
lockId: this.currentLockInfo.lockId,
appUnlockOnline: value
})
if (code === 0) {
this.unlockApp = value
const data = this.currentLockInfo
data.lockSetting.appUnlockOnline = value
this.updateCurrentLockInfo(data)
uni.hideLoading()
uni.showToast({
title: '更新成功',
icon: 'none'
})
} else {
uni.hideLoading()
uni.showToast({
title: message,
icon: 'none'
})
}
},
async deleteLock() {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
const that = this
if (this.currentLockInfo.userType !== 110301 && this.currentLockInfo.keyRight === 1) {
this.showModal = true
return
}
const message =
that.currentLockInfo.userType === 110301
? '删除锁后,所有信息都会一起删除,确定删除锁吗?'
: '确定删除该钥匙吗?'
uni.showModal({
title: '提示',
content: message,
async success(res) {
if (res.confirm) {
uni.showLoading({
title: '删除中',
mask: true
}) })
if(resetDeviceCode === 0 || resetDeviceCode === -2) { if (that.currentLockInfo.userType === 110301) {
const { code, message } = await deleteLockRequest({ const { code: resetDeviceCode } = await that.resetDevice({
lockId: that.currentLockInfo.lockId name: that.currentLockInfo.name,
authUid: that.userInfo.uid.toString(),
keyId: that.keyId.toString()
}) })
if(code === 0) { if (resetDeviceCode === 0 || resetDeviceCode === -2) {
const { code } = await deleteLockRequest({
lockId: that.currentLockInfo.lockId
})
if (code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
}
} else if (resetDeviceCode === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
}
} else {
const { code } = await deleteKeyRequest({
keyId: that.keyId
})
if (code === 0) {
uni.hideLoading() uni.hideLoading()
that.updateLockSearch({ that.updateLockSearch({
...that.lockSearch, ...that.lockSearch,
@ -231,102 +286,75 @@ export default {
icon: 'none' icon: 'none'
}) })
} }
} else if(resetDeviceCode === -1) {
uni.hideLoading()
uni.showToast({
title: '删除失败,请保持在锁附近',
icon: 'none'
})
}
} else {
const { code } = await deleteKeyRequest({
keyId: that.keyId
})
if(code === 0) {
uni.hideLoading()
that.updateLockSearch({
...that.lockSearch,
pageNo: 1
})
that.getLockList(that.lockSearch)
that.backAndToast('删除成功', 2)
} else {
uni.hideLoading()
uni.showToast({
title: 'message',
icon: 'none'
})
} }
} }
} }
} })
}) }
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.button-logout { .button-logout {
position: absolute; position: absolute;
border-radius: 46rpx; border-radius: 46rpx;
bottom: calc(env(safe-area-inset-bottom) + 30rpx); bottom: calc(env(safe-area-inset-bottom) + 30rpx);
width: 600rpx; width: 600rpx;
height: 80rpx; height: 80rpx;
line-height: 80rpx; line-height: 80rpx;
text-align: center; text-align: center;
margin-left: 75rpx; margin-left: 75rpx;
background: #ec433c; background: #ec433c;
color: #ffffff; color: #ffffff;
font-size: 40rpx; font-size: 40rpx;
font-weight: bold; font-weight: bold;
} }
.view { .view {
margin-top: 32rpx; margin-top: 32rpx;
border-radius: 32rpx; border-radius: 32rpx;
width: 710rpx; width: 710rpx;
margin-left: 20rpx; margin-left: 20rpx;
background: #FFFFFF; background: #ffffff;
} }
.view-button { .view-button {
padding: 0 40rpx; padding: 0 40rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
color: #292826; color: #292826;
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
line-height: 80rpx; line-height: 80rpx;
} }
.view-line { .view-line {
width: 100%; width: 100%;
height: 3rpx; height: 3rpx;
background: #EBEBEB; background: #ebebeb;
} }
radio .wx-radio-input.wx-radio-input-checked {
radio .wx-radio-input.wx-radio-input-checked { border: none;
border: none; background: #c1885a;
background: #c1885a; }
} radio .wx-radio-input.wx-radio-input-checked::before {
radio .wx-radio-input.wx-radio-input-checked::before { border-radius: 50%; /* 圆角 */
border-radius: 50%; /* 圆角 */ width: 28rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
width: 28rpx; /* 选中后对勾大小,不要超过背景的尺寸 */ height: 28rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
height: 28rpx; /* 选中后对勾大小,不要超过背景的尺寸 */ line-height: 28rpx;
line-height: 28rpx; text-align: center;
text-align: center; font-size: 20rpx; /* 对勾大小 30rpx */
font-size: 20rpx; /* 对勾大小 30rpx */ color: #fff; /* 对勾颜色 白色 */
color: #fff; /* 对勾颜色 白色 */ background: #c1885a;
background: #c1885a; transform: translate(-50%, -50%) scale(1);
transform: translate(-50%, -50%) scale(1); }
}
</style> </style>

View File

@ -1,217 +1,230 @@
<template> <template>
<view> <view>
<view class="tips">找回密码和登录新设备时可通过绑定的邮箱验证</view> <view class="tips">找回密码和登录新设备时可通过绑定的邮箱验证</view>
<input class="input-email" :value="email" placeholder="请输入邮箱" <input
placeholder-class="input-placeholder" :focus="true" @input="updateInputEmail"></input> class="input-email"
:value="email"
placeholder="请输入邮箱"
placeholder-class="input-placeholder"
:focus="true"
@input="updateInputEmail"
/>
<view class="view-top"> <view class="view-top">
<input type="number" class="input-verify" :value="verificationCode" maxlength="6" placeholder="请输入验证码" <input
placeholder-class="input-placeholder" @input="updateInputCode"></input> type="number"
<view class="button-verify" @click="getEmailCode">{{text}}</view> class="input-verify"
:value="verificationCode"
maxlength="6"
placeholder="请输入验证码"
placeholder-class="input-placeholder"
@input="updateInputCode"
/>
<view class="button-verify" @click="getEmailCode">{{ text }}</view>
</view> </view>
<view class="button" @click="toUpdateEmail">确定</view> <view class="button" @click="toUpdateEmail">确定</view>
</view> </view>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { test } from 'uview-plus'
import { getEmailCodeRequest, unbindEmailTokenRequest, updateEmailRequest, updateUserInfoRequest } from '@/api/user' import { useUserStore } from '@/stores/user'
import { useBasicStore } from '@/stores/basic' import { getEmailCodeRequest, updateEmailRequest } from '@/api/user'
import { test } from 'uview-plus' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return { return {
text: '获取验证码', text: '获取验证码',
verificationCode: '', verificationCode: '',
token: '', token: '',
email: '', email: '',
pending: false 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', 'backAndToast', 'getNetworkType']),
updateInputEmail(data) {
this.email = data.detail.value
}, },
updateInputCode (data) { computed: {
this.verificationCode = data.detail.value ...mapState(useUserStore, ['userInfo'])
}, },
async getEmailCode () { onLoad(option) {
if (this.text !== '获取验证码') { if (option.token) {
return this.token = option.token
}
if(!test.email(this.email)){
uni.showToast({
title: '请输入正确的邮箱',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
const { code } = await getEmailCodeRequest({
account: this.email,
channel: '2',
codeType: 6
})
if (code === 0) {
this.updateTime()
} else { } else {
uni.showToast({ uni.setNavigationBarTitle({
title: '验证码获取失败', title: '绑定邮箱'
icon: 'none'
}) })
} }
}, },
async toUpdateEmail () { methods: {
if(!test.email(this.email)){ ...mapActions(useUserStore, ['updateUserInfo']),
uni.showToast({ ...mapActions(useBasicStore, ['routeJump', 'backAndToast', 'getNetworkType']),
title: '请输入正确的邮箱', updateInputEmail(data) {
icon: 'none' this.email = data.detail.value
}) },
return updateInputCode(data) {
} this.verificationCode = data.detail.value
if (this.verificationCode.length === 6 && test.digits(this.verificationCode)) { },
const netWork = await this.getNetworkType() async getEmailCode() {
if(!netWork) { if (this.text !== '获取验证码') {
return return
} }
if(this.pending){ if (!test.email(this.email)) {
return uni.showToast({
} title: '请输入正确的邮箱',
this.pending = true icon: 'none'
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
}) })
this.backAndToast('邮箱绑定成功') return
}
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
const { code } = await getEmailCodeRequest({
account: this.email,
channel: '2',
codeType: 6
})
if (code === 0) {
this.updateTime()
} else { } else {
uni.showToast({ uni.showToast({
title: message, title: '验证码获取失败',
icon: 'none' icon: 'none'
}) })
} }
this.pending = false },
} else { async toUpdateEmail() {
uni.showToast({ if (!test.email(this.email)) {
title: '验证码为6位纯数字', uni.showToast({
icon: 'none' title: '请输入正确的邮箱',
}) icon: 'none'
} })
}, return
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) if (this.verificationCode.length === 6 && test.digits(this.verificationCode)) {
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
if (this.pending) {
return
}
this.pending = true
const params = {
verificationCode: this.verificationCode,
email: this.email
}
if (this.token !== '') {
params.unbindToken = this.token
}
const { code, message } = await updateEmailRequest(params)
if (code === 0) {
this.updateUserInfo({
...this.userInfo,
email: this.email
})
this.backAndToast('邮箱绑定成功')
} 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, 10)
this.text = `${time - second} s`
if (time <= second) {
clearInterval(timer)
this.text = '获取验证码'
}
}, 1000)
}
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.tips { .tips {
padding: 24rpx 32rpx 0 32rpx; padding: 24rpx 32rpx 0 32rpx;
font-size: 28rpx; font-size: 28rpx;
color: #999999; color: #999999;
} }
.input-email { .input-email {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 616rpx; width: 616rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.button-verify { .button-verify {
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 265rpx; width: 265rpx;
line-height: 108rpx; line-height: 108rpx;
border-radius: 16rpx; border-radius: 16rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
background: #63b8af; background: #63b8af;
color: #FFFFFF; color: #ffffff;
} }
.view-top { .view-top {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.input-verify { .input-verify {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 316rpx; width: 316rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.input-placeholder { .input-placeholder {
height: 108rpx; height: 108rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
line-height: 108rpx; line-height: 108rpx;
} }
.button { .button {
margin-top: 32rpx; margin-top: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
width: 680rpx; width: 680rpx;
height: 96rpx; height: 96rpx;
background: #63b8af; background: #63b8af;
border-radius: 16rpx; border-radius: 16rpx;
line-height: 96rpx; line-height: 96rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: #FFFFFF; color: #ffffff;
} }
</style> </style>

View File

@ -1,109 +1,116 @@
<template> <template>
<view> <view>
<input class="input" :value="nickname" maxlength="50" placeholder="请输入昵称" <input
placeholder-class="input-placeholder" :focus="true" @input="updateInput"></input> class="input"
:value="nickname"
maxlength="50"
placeholder="请输入昵称"
placeholder-class="input-placeholder"
:focus="true"
@input="updateInput"
/>
<view class="button" @click="updateName">保存</view> <view class="button" @click="updateName">保存</view>
</view> </view>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { updateUserInfoRequest } from '@/api/user' import { updateUserInfoRequest } from '@/api/user'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
export default { export default {
data() { data() {
return { return {
nickname: '', nickname: '',
pending: false pending: false
} }
},
computed: {
...mapState(useUserStore, ['userInfo'])
},
onLoad() {
this.nickname = this.userInfo.nickname
},
methods: {
...mapActions(useUserStore, ['updateUserInfo']),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
updateInput(data) {
this.nickname = data.detail.value
console.log(data)
}, },
async updateName() { computed: {
if(this.nickname === '') { ...mapState(useUserStore, ['userInfo'])
uni.showToast({ },
title: '昵称不能为空', onLoad() {
icon: 'none' this.nickname = this.userInfo.nickname
}) },
return methods: {
} ...mapActions(useUserStore, ['updateUserInfo']),
const netWork = await this.getNetworkType() ...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
if(!netWork) { updateInput(data) {
return this.nickname = data.detail.value
} console.log(data)
if(this.pending) { },
return async updateName() {
} if (this.nickname === '') {
this.pending = true uni.showToast({
const { code } = await updateUserInfoRequest({ title: '昵称不能为空',
nickname: this.nickname icon: 'none'
}) })
if(code === 0) { return
this.updateUserInfo({ }
...this.userInfo, const netWork = await this.getNetworkType()
if (!netWork) {
return
}
if (this.pending) {
return
}
this.pending = true
const { code } = await updateUserInfoRequest({
nickname: this.nickname nickname: this.nickname
}) })
this.backAndToast('昵称更新成功') if (code === 0) {
} else { this.updateUserInfo({
uni.showToast({ ...this.userInfo,
title: '昵称更新失败', nickname: this.nickname
icon: 'none' })
}) this.backAndToast('昵称更新成功')
} else {
uni.showToast({
title: '昵称更新失败',
icon: 'none'
})
}
this.pending = false
} }
this.pending = false
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.input { .input {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 616rpx; width: 616rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.input-placeholder { .input-placeholder {
height: 108rpx; height: 108rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
line-height: 108rpx; line-height: 108rpx;
} }
.button { .button {
margin-top: 32rpx; margin-top: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
width: 680rpx; width: 680rpx;
height: 96rpx; height: 96rpx;
background: #63b8af; background: #63b8af;
border-radius: 16rpx; border-radius: 16rpx;
line-height: 96rpx; line-height: 96rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: #FFFFFF; color: #ffffff;
} }
</style> </style>

View File

@ -1,11 +1,25 @@
<template> <template>
<view> <view>
<input class="input" :password="true" :value="password" maxlength="20" placeholder="请输入新密码" <input
placeholder-class="input-placeholder" @input="updateNewPassword"></input> class="input"
:password="true"
:value="password"
maxlength="20"
placeholder="请输入新密码"
placeholder-class="input-placeholder"
@input="updateNewPassword"
/>
<view class="view-top"> <view class="view-top">
<input type="number" class="input-verify" :value="verificationCode" maxlength="6" placeholder="请输入验证码" <input
placeholder-class="input-placeholder" @input="updateInputCode"></input> type="number"
<view class="button-verify" @click="getPhoneCode">{{text}}</view> class="input-verify"
:value="verificationCode"
maxlength="6"
placeholder="请输入验证码"
placeholder-class="input-placeholder"
@input="updateInputCode"
/>
<view class="button-verify" @click="getPhoneCode">{{ text }}</view>
</view> </view>
<view class="text-tips">密码必须是8-20至少包括数字/字母/符号中的2种</view> <view class="text-tips">密码必须是8-20至少包括数字/字母/符号中的2种</view>
<view class="button" @click="updatePassword">保存</view> <view class="button" @click="updatePassword">保存</view>
@ -13,188 +27,188 @@
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { test } from 'uview-plus'
import { changePasswordRequest, getEmailCodeRequest, updatePasswordRequest } from '@/api/user' import { useUserStore } from '@/stores/user'
import { test } from 'uview-plus' import { changePasswordRequest, getEmailCodeRequest } from '@/api/user'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
export default { export default {
data () { data() {
return { return {
text: '获取验证码', text: '获取验证码',
password: '', password: '',
pending: false, pending: false,
verificationCode: '' verificationCode: ''
}
},
computed: {
...mapState(useUserStore, ['userInfo'])
},
methods: {
...mapActions(useUserStore, ['updateUserInfo']),
...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
updateNewPassword (data) {
this.password = data.detail.value
},
updateInputCode (data) {
this.verificationCode = data.detail.value
},
async getPhoneCode () {
if (this.text !== '获取验证码') {
return
}
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
const { code, message } = await getEmailCodeRequest({
channel: '1',
codeType: 9
})
if (code === 0) {
this.updateTime()
} else {
uni.showToast({
title: message,
icon: 'none'
})
} }
}, },
updateTime () { computed: {
let time = 120 ...mapState(useUserStore, ['userInfo'])
this.text = `${time} s` },
const now = new Date().getTime() methods: {
const timer = setInterval(() => { ...mapActions(useUserStore, ['updateUserInfo']),
const second = parseInt((new Date().getTime() - now) / 1000) ...mapActions(useBasicStore, ['backAndToast', 'getNetworkType']),
this.text = `${time - second} s` updateNewPassword(data) {
if (time <= second) { this.password = data.detail.value
clearInterval(timer) },
this.text = '获取验证码' updateInputCode(data) {
this.verificationCode = data.detail.value
},
async getPhoneCode() {
if (this.text !== '获取验证码') {
return
} }
}, 1000) const netWork = await this.getNetworkType()
}, if (!netWork) {
async updatePassword () { return
if (this.password === '') { }
uni.showToast({ const { code, message } = await getEmailCodeRequest({
title: '密码不能为空', channel: '1',
icon: 'none' codeType: 9
}) })
return if (code === 0) {
} this.updateTime()
if (this.password.length < 8 || this.password.length > 20) { } else {
uni.showToast({ uni.showToast({
title: '密码长度必须是8-20位', title: message,
icon: 'none' 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, 10)
this.text = `${time - second} s`
if (time <= second) {
clearInterval(timer)
this.text = '获取验证码'
}
}, 1000)
},
async updatePassword() {
if (this.password === '') {
uni.showToast({
title: '密码不能为空',
icon: 'none'
})
return
}
if (this.password.length < 8 || this.password.length > 20) {
uni.showToast({
title: '密码长度必须是8-20位',
icon: 'none'
})
return
}
if (!(this.verificationCode.length === 6 && test.digits(this.verificationCode))) {
uni.showToast({
title: '验证码为6位纯数字',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if (!netWork) {
return
}
if (this.pending) {
return
}
this.pending = true
const { code, message } = await changePasswordRequest({
verificationCode: this.verificationCode,
password: this.password,
channel: '1'
}) })
return if (code === 0) {
this.backAndToast('密码重置成功')
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.pending = false
} }
if (!(this.verificationCode.length === 6 && test.digits(this.verificationCode))) {
uni.showToast({
title: '验证码为6位纯数字',
icon: 'none'
})
return
}
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
if(this.pending) {
return
}
this.pending = true
const { code, message } = await changePasswordRequest({
verificationCode: this.verificationCode,
password: this.password,
channel: '1'
})
if (code === 0) {
this.backAndToast('密码重置成功')
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
this.pending = false
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.input { .input {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 616rpx; width: 616rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.input-placeholder { .input-placeholder {
height: 108rpx; height: 108rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
line-height: 108rpx; line-height: 108rpx;
} }
.button { .button {
margin-top: 32rpx; margin-top: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
width: 680rpx; width: 680rpx;
height: 96rpx; height: 96rpx;
background: #63b8af; background: #63b8af;
border-radius: 16rpx; border-radius: 16rpx;
line-height: 96rpx; line-height: 96rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: #FFFFFF; color: #ffffff;
} }
.text-tips { .text-tips {
text-align: center; text-align: center;
margin-top: 32rpx; margin-top: 32rpx;
font-size: 28rpx; font-size: 28rpx;
color: #9B9B9B; color: #9b9b9b;
} }
.view-top { .view-top {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.input-verify { .input-verify {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 316rpx; width: 316rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.button-verify { .button-verify {
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 265rpx; width: 265rpx;
line-height: 108rpx; line-height: 108rpx;
border-radius: 16rpx; border-radius: 16rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
background: #63b8af; background: #63b8af;
color: #FFFFFF; color: #ffffff;
} }
</style> </style>

View File

@ -14,7 +14,7 @@
<view class="view-button" @click="toUpdateName"> <view class="view-button" @click="toUpdateName">
<view>昵称</view> <view>昵称</view>
<view class="view-button" style="padding: 20rpx 0"> <view class="view-button" style="padding: 20rpx 0">
<view class="name-info">{{userInfo.nickname}}</view> <view class="name-info">{{ userInfo.nickname }}</view>
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image> <image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
</view> </view>
</view> </view>
@ -23,7 +23,7 @@
<view class="view-button"> <view class="view-button">
<view>手机号</view> <view>手机号</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view v-if="userInfo.mobile !== ''" class="info">{{userInfo.mobile}}</view> <view v-if="userInfo.mobile !== ''" class="info">{{ userInfo.mobile }}</view>
<view v-else class="red-dot"></view> <view v-else class="red-dot"></view>
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image> <image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
</view> </view>
@ -33,7 +33,7 @@
<view class="view-button" @click="toUpdateEmail"> <view class="view-button" @click="toUpdateEmail">
<view>邮箱</view> <view>邮箱</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view v-if="userInfo.email !== ''" class="info">{{userInfo.email}}</view> <view v-if="userInfo.email !== ''" class="info">{{ userInfo.email }}</view>
<view v-else class="red-dot"></view> <view v-else class="red-dot"></view>
<image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image> <image class="icon-arrow" src="/static/images/icon_arrow.png" mode="aspectFill"></image>
</view> </view>
@ -47,237 +47,246 @@
<view class="view-button"> <view class="view-button">
<view>国家/地区</view> <view>国家/地区</view>
<view class="view-button" style="padding: 0"> <view class="view-button" style="padding: 0">
<view class="info">{{userInfo.countryName}}</view> <view class="info">{{ userInfo.countryName }}</view>
</view> </view>
</view> </view>
</view> </view>
<button open-type="chooseAvatar" style="display:none" id="avatar" @chooseavatar="chooseAvatar"></button> <button
<button open-type="getPhoneNumber" style="display:none" id="phone" @getphonenumber="rebindPhone"></button> open-type="chooseAvatar"
style="display: none"
id="avatar"
@chooseavatar="chooseAvatar"
></button>
<button
open-type="getPhoneNumber"
style="display: none"
id="phone"
@getphonenumber="rebindPhone"
></button>
</view> </view>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { useBasicStore } from '@/stores/basic' import { useBasicStore } from '@/stores/basic'
import { getUploadParamsRequest } from '@/api/file' import { getUploadParamsRequest } from '@/api/file'
import { rebindPhoneRequest, updateUserInfoRequest } from '@/api/user' import { rebindPhoneRequest, updateUserInfoRequest } from '@/api/user'
export default { export default {
data() { data() {
return { return {
pending: false pending: false
}
},
computed: {
...mapState(useUserStore, ['userInfo'])
},
methods: {
...mapActions(useBasicStore, ['routeJump', 'getNetworkType']),
...mapActions(useUserStore, ['updateUserInfo', 'checkSession', 'getUserInfo']),
async rebindPhone(detail) {
if(!(detail.detail.encryptedData && detail.detail.iv)) {
return
} }
if(detail.detail.errMsg === 'getPhoneNumber:fail user deny') {
return
}
if(this.pending) {
return
}
this.pending = true
const result = await this.checkSession()
if(result) {
const { code, data, message } = await rebindPhoneRequest({
encryptedData: detail.detail.encryptedData,
iv: detail.detail.iv
})
if(code === 0) {
this.getUserInfo()
uni.showToast({
title: '更换成功',
icon: 'none'
})
} else if(code === 421) {
uni.showToast({
title: '手机号已被其他账号绑定',
icon: 'none'
})
} else if(code === 438) {
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
} else {
this.rebindPhone()
}
this.pending = false
}, },
chooseAvatar(e) { computed: {
const that = this ...mapState(useUserStore, ['userInfo'])
if(that.pending) { },
return methods: {
} ...mapActions(useBasicStore, ['routeJump', 'getNetworkType']),
that.pending = true ...mapActions(useUserStore, ['updateUserInfo', 'checkSession', 'getUserInfo']),
async rebindPhone(detail) {
const path = e.detail.avatarUrl if (!(detail.detail.encryptedData && detail.detail.iv)) {
const list = path.split('/') return
const filename = list[list.length - 1] }
uni.getFileSystemManager().getFileInfo({ if (detail.detail.errMsg === 'getPhoneNumber:fail user deny') {
filePath: path, return
async success (res) { }
const size = res.size if (this.pending) {
const { code, data } = await getUploadParamsRequest({ return
size, }
module: 'avatar', this.pending = true
userId: that.userInfo.userId, const result = await this.checkSession()
filename if (result) {
const { code, message } = await rebindPhoneRequest({
encryptedData: detail.detail.encryptedData,
iv: detail.detail.iv
}) })
if(code === 0) { if (code === 0) {
uni.uploadFile({ this.getUserInfo()
url: data.uploadUrl, uni.showToast({
filePath: path, title: '更换成功',
name: 'file', icon: 'none'
formData: data.formData, })
async success (res) { } else if (code === 421) {
const { code: updateCode } = await updateUserInfoRequest({ uni.showToast({
headUrl: data.fileUrl title: '手机号已被其他账号绑定',
}) icon: 'none'
if(updateCode === 0) { })
that.updateUserInfo({ } else if (code === 438) {
...that.userInfo, /* empty */
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
} else {
this.rebindPhone()
}
this.pending = false
},
chooseAvatar(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() {
const { code: updateCode } = await updateUserInfoRequest({
headUrl: data.fileUrl headUrl: data.fileUrl
}) })
uni.showToast({ if (updateCode === 0) {
title: '头像更新成功', that.updateUserInfo({
icon: 'none' ...that.userInfo,
}) headUrl: data.fileUrl
} else { })
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({ uni.showToast({
title: '头像更新失败', title: '头像更新失败',
icon: 'none' icon: 'none'
}) })
that.pending = false
} }
that.pending = false })
}, } else {
fail(res) { uni.showToast({
console.log('上传失败', res) title: '头像更新失败',
console.log(data.uploadUrl, path, data.formData) icon: 'none'
uni.showToast({ })
title: '头像更新失败', that.pending = false
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 { },
toUpdateName() {
this.routeJump({ this.routeJump({
name: 'verifyEmail' name: 'updateName'
})
},
toUpdateEmail() {
if (this.userInfo.email === '') {
this.routeJump({
name: 'updateEmail'
})
} else {
this.routeJump({
name: 'verifyEmail'
})
}
},
toUpdatePassword() {
this.routeJump({
name: 'updatePassword'
}) })
} }
},
toUpdatePassword() {
this.routeJump({
name: 'updatePassword'
})
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.view { .view {
margin-top: 32rpx; margin-top: 32rpx;
border-radius: 32rpx; border-radius: 32rpx;
width: 710rpx; width: 710rpx;
margin-left: 20rpx; margin-left: 20rpx;
background: #FFFFFF; background: #ffffff;
} }
.view-button { .view-button {
padding: 0 20rpx 0 40rpx; padding: 0 20rpx 0 40rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
color: #292826; color: #292826;
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
line-height: 80rpx; line-height: 80rpx;
} }
.info { .info {
text-align: right; text-align: right;
width: 400rpx; width: 400rpx;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
margin-right: 20rpx; margin-right: 20rpx;
} }
.name-info { .name-info {
line-height: 40rpx; line-height: 40rpx;
text-align: right; text-align: right;
width: 520rpx; width: 520rpx;
overflow: hidden; overflow: hidden;
word-break: break-all; word-break: break-all;
margin-right: 20rpx; margin-right: 20rpx;
} }
.red-dot { .red-dot {
margin-right: 20rpx; margin-right: 20rpx;
background: #ec433c; background: #ec433c;
width: 20rpx; width: 20rpx;
height: 20rpx; height: 20rpx;
border-radius: 50%; border-radius: 50%;
} }
.icon-arrow { .icon-arrow {
width: 40rpx; width: 40rpx;
height: 40rpx; height: 40rpx;
} }
.view-line { .view-line {
width: 100%; width: 100%;
height: 3rpx; height: 3rpx;
background: #EBEBEB; background: #ebebeb;
} }
.avatar { .avatar {
width: 80rpx; width: 80rpx;
height: 80rpx; height: 80rpx;
border-radius: 50%; border-radius: 50%;
margin-right: 20rpx; margin-right: 20rpx;
margin-top: 20rpx; margin-top: 20rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
} }
</style> </style>

View File

@ -2,165 +2,172 @@
<view> <view>
<view class="tips">为了你的账号安全修改账号前请先使用验证码验证</view> <view class="tips">为了你的账号安全修改账号前请先使用验证码验证</view>
<view class="view-top"> <view class="view-top">
<input type="number" class="input" :value="verificationCode" maxlength="6" placeholder="请输入验证码" <input
placeholder-class="input-placeholder" @input="updateInput"></input> type="number"
<view class="button-verify" @click="getEmailCode">{{text}}</view> class="input"
:value="verificationCode"
maxlength="6"
placeholder="请输入验证码"
placeholder-class="input-placeholder"
@input="updateInput"
/>
<view class="button-verify" @click="getEmailCode">{{ text }}</view>
</view> </view>
<view class="button" @click="toUpdateEmail">下一步</view> <view class="button" @click="toUpdateEmail">下一步</view>
</view> </view>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'pinia' import { mapActions, mapState } from 'pinia'
import { useUserStore } from '@/stores/user' import { test } from 'uview-plus'
import { getEmailCodeRequest, unbindEmailTokenRequest, updateUserInfoRequest } from '@/api/user' import { useUserStore } from '@/stores/user'
import { useBasicStore } from '@/stores/basic' import { getEmailCodeRequest, unbindEmailTokenRequest } from '@/api/user'
import { test } from 'uview-plus' import { useBasicStore } from '@/stores/basic'
export default { export default {
data() { data() {
return { return {
text: '获取验证码', text: '获取验证码',
verificationCode: '' verificationCode: ''
}
},
computed: {
...mapState(useUserStore, ['userInfo'])
},
methods: {
...mapActions(useUserStore, ['updateUserInfo']),
...mapActions(useBasicStore, ['routeJump', 'getNetworkType']),
async getEmailCode() {
if(this.text !== '获取验证码') {
return
}
const netWork = await this.getNetworkType()
if(!netWork) {
return
}
const { code } = await getEmailCodeRequest({
channel: '2',
codeType: 7
})
if(code === 0) {
this.updateTime()
} else {
uni.showToast({
title: '验证码获取失败',
icon: 'none'
})
} }
}, },
async toUpdateEmail() { computed: {
if(this.verificationCode.length === 6 && test.digits(this.verificationCode)) { ...mapState(useUserStore, ['userInfo'])
const netWork = await this.getNetworkType() },
if(!netWork) { methods: {
...mapActions(useUserStore, ['updateUserInfo']),
...mapActions(useBasicStore, ['routeJump', 'getNetworkType']),
async getEmailCode() {
if (this.text !== '获取验证码') {
return return
} }
const { code, data, message } = await unbindEmailTokenRequest({ const netWork = await this.getNetworkType()
verificationCode: this.verificationCode if (!netWork) {
return
}
const { code } = await getEmailCodeRequest({
channel: '2',
codeType: 7
}) })
if(code === 0) { if (code === 0) {
this.routeJump({ this.updateTime()
type: 'redirectTo',
name: 'updateEmail',
params: {
token: data.token
}
})
} else { } else {
uni.showToast({ uni.showToast({
title: message, title: '验证码获取失败',
icon: 'none' icon: 'none'
}) })
} }
} else { },
uni.showToast({ async toUpdateEmail() {
title: '验证码为6位纯数字', if (this.verificationCode.length === 6 && test.digits(this.verificationCode)) {
icon: 'none' const netWork = await this.getNetworkType()
}) if (!netWork) {
} return
}, }
updateTime() { const { code, data, message } = await unbindEmailTokenRequest({
let time = 120 verificationCode: this.verificationCode
this.text = `${time} s` })
const now = new Date().getTime() if (code === 0) {
const timer = setInterval(() => { this.routeJump({
const second = parseInt((new Date().getTime() - now) / 1000) type: 'redirectTo',
this.text = `${time - second} s` name: 'updateEmail',
if (time <= second) { params: {
clearInterval(timer) token: data.token
this.text = '获取验证码' }
})
} else {
uni.showToast({
title: message,
icon: 'none'
})
}
} else {
uni.showToast({
title: '验证码为6位纯数字',
icon: 'none'
})
} }
}, 1000) },
}, updateTime() {
updateInput(data) { let time = 120
this.verificationCode = data.detail.value this.text = `${time} s`
const now = new Date().getTime()
const timer = setInterval(() => {
const second = parseInt((new Date().getTime() - now) / 1000, 10)
this.text = `${time - second} s`
if (time <= second) {
clearInterval(timer)
this.text = '获取验证码'
}
}, 1000)
},
updateInput(data) {
this.verificationCode = data.detail.value
}
} }
} }
}
</script> </script>
<style lang="scss"> <style lang="scss">
page { page {
background-color: $uni-bg-color-grey; background-color: $uni-bg-color-grey;
} }
</style> </style>
<style scoped lang="scss"> <style scoped lang="scss">
.tips { .tips {
padding: 24rpx 32rpx 0 32rpx; padding: 24rpx 32rpx 0 32rpx;
font-size: 28rpx; font-size: 28rpx;
color: #999999; color: #999999;
} }
.button-verify { .button-verify {
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 265rpx; width: 265rpx;
line-height: 108rpx; line-height: 108rpx;
border-radius: 16rpx; border-radius: 16rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
background: #63b8af; background: #63b8af;
color: #FFFFFF; color: #ffffff;
} }
.view-top { .view-top {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.input { .input {
border-radius: 16rpx; border-radius: 16rpx;
background: #FFFFFF; background: #ffffff;
margin-left: 35rpx; margin-left: 35rpx;
margin-top: 48rpx; margin-top: 48rpx;
height: 108rpx; height: 108rpx;
width: 316rpx; width: 316rpx;
padding-left: 32rpx; padding-left: 32rpx;
padding-right: 32rpx; padding-right: 32rpx;
} }
.input-placeholder { .input-placeholder {
height: 108rpx; height: 108rpx;
font-size: 36rpx; font-size: 36rpx;
font-weight: bold; font-weight: bold;
line-height: 108rpx; line-height: 108rpx;
} }
.button { .button {
margin-top: 32rpx; margin-top: 32rpx;
margin-left: 35rpx; margin-left: 35rpx;
width: 680rpx; width: 680rpx;
height: 96rpx; height: 96rpx;
background: #63b8af; background: #63b8af;
border-radius: 16rpx; border-radius: 16rpx;
line-height: 96rpx; line-height: 96rpx;
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: #FFFFFF; color: #ffffff;
} }
</style> </style>

View File

@ -5,37 +5,37 @@
</template> </template>
<script> <script>
import env from '@/config/env' import env from '@/config/env'
export default { export default {
data() { data() {
return { return {
url: '', url: '',
env: null env: null
}
},
onLoad: async function (options) {
this.env = await env[await getApp().globalData.getEnvConfig()]
const officialAccounts = {
default: {
url: '/app/introduce',
name: '介绍'
},
userAgreement: {
url: '/app/userAgreement',
name: '用户协议'
},
privacy: {
url: '/app/privacy',
name: '隐私政策'
} }
},
async onLoad(options) {
this.env = await env[await getApp().globalData.getEnvConfig()]
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 = this.env.webviewBaseUrl + item.url
console.log(this.url)
uni.setNavigationBarTitle({
title: item.name
})
} }
const item = officialAccounts[options?.type] || officialAccounts['default']
this.url = this.env.webviewBaseUrl + item['url']
console.log(this.url)
uni.setNavigationBarTitle({
title: item['name']
})
} }
}
</script> </script>

View File

@ -114,7 +114,6 @@ const pages = [
} }
] ]
export const useBasicStore = defineStore('basic', { export const useBasicStore = defineStore('basic', {
state() { state() {
return { return {
@ -131,7 +130,7 @@ export const useBasicStore = defineStore('basic', {
/* data name string type string params object delta number /* data name string type string params object delta number
* 具体入参查看文档 https://www.uviewui.com/js/route.html */ * 具体入参查看文档 https://www.uviewui.com/js/route.html */
routeJump(data) { routeJump(data) {
const page = pages.find((page) => { const page = pages.find(page => {
return page.name === data.name return page.name === data.name
}) })
if (page) { if (page) {
@ -143,10 +142,10 @@ export const useBasicStore = defineStore('basic', {
}, },
// 获取当前网络状态 // 获取当前网络状态
getNetworkType() { getNetworkType() {
return new Promise((resolve) => { return new Promise(resolve => {
uni.getNetworkType({ uni.getNetworkType({
success: function (res) { success(res) {
if(res.networkType === 'none') { if (res.networkType === 'none') {
uni.showToast({ uni.showToast({
title: '网络访问失败,请检查网络是否正常', title: '网络访问失败,请检查网络是否正常',
icon: 'none' icon: 'none'
@ -156,7 +155,7 @@ export const useBasicStore = defineStore('basic', {
} }
resolve(true) resolve(true)
}, },
fail: function () { fail() {
resolve(false) resolve(false)
} }
}) })
@ -165,17 +164,17 @@ export const useBasicStore = defineStore('basic', {
// 获取设备信息 // 获取设备信息
getDeviceInfo() { getDeviceInfo() {
const that = this const that = this
return new Promise((resolve) => { return new Promise(resolve => {
if (that.deviceInfo?.model) { if (that.deviceInfo?.model) {
resolve(that.deviceInfo) resolve(that.deviceInfo)
return return
} }
uni.getSystemInfo({ uni.getSystemInfo({
success: function (res) { success(res) {
that.deviceInfo = res that.deviceInfo = res
resolve(that.deviceInfo) resolve(that.deviceInfo)
}, },
fail: function () { fail() {
resolve({}) resolve({})
} }
}) })
@ -183,14 +182,13 @@ export const useBasicStore = defineStore('basic', {
}, },
// 获取胶囊信息 // 获取胶囊信息
getButtonInfo() { getButtonInfo() {
return new Promise((resolve, reject) => { return new Promise(resolve => {
if (this.buttonInfo?.top) { if (this.buttonInfo?.top) {
resolve(this.buttonInfo) resolve(this.buttonInfo)
return return
} }
this.buttonInfo = uni.getMenuButtonBoundingClientRect() this.buttonInfo = uni.getMenuButtonBoundingClientRect()
resolve(this.buttonInfo) resolve(this.buttonInfo)
return
}) })
}, },
// 计算字符串长度 // 计算字符串长度
@ -212,10 +210,9 @@ export const useBasicStore = defineStore('basic', {
}, },
// 回退页面并弹出toast提示 // 回退页面并弹出toast提示
backAndToast(message, delta = 1) { backAndToast(message, delta = 1) {
const that = this
uni.navigateBack({ uni.navigateBack({
delta: delta, delta,
complete: function () { complete() {
setTimeout(() => { setTimeout(() => {
uni.showToast({ uni.showToast({
title: message, title: message,
@ -234,7 +231,7 @@ export const useBasicStore = defineStore('basic', {
} else { } else {
delete data.path delete data.path
} }
const page = pages.find((page) => { const page = pages.find(page => {
return page.name === target[0] return page.name === target[0]
}) })
if (page) { if (page) {
@ -256,7 +253,7 @@ export const useBasicStore = defineStore('basic', {
function getParams(params) { function getParams(params) {
let paramStr = '' let paramStr = ''
Object.keys(params).forEach((item) => { Object.keys(params).forEach(item => {
if (paramStr === '') { if (paramStr === '') {
paramStr = `${item}=${params[item]}` paramStr = `${item}=${params[item]}`
} else { } else {
@ -265,6 +262,6 @@ export const useBasicStore = defineStore('basic', {
}) })
return paramStr return paramStr
} }
}, }
} }
}) })

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,9 @@
* @description 锁信息数据持久化 * @description 锁信息数据持久化
*/ */
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { timeFormat } from 'uview-plus'
import { getLockListRequest } from '@/api/lock' import { getLockListRequest } from '@/api/lock'
import { getPsaawordListRequest } from '@/api/keyboardPwd' import { getPsaawordListRequest } from '@/api/keyboardPwd'
import { timeFormat } from 'uview-plus'
import { getKeyListRequest } from '@/api/key' import { getKeyListRequest } from '@/api/key'
import { setStorage } from '@/utils/storage' import { setStorage } from '@/utils/storage'
@ -48,7 +48,7 @@ export const useLockStore = defineStore('lock', {
startDate: '0', startDate: '0',
keyStatus: [110401, 110402, 110412, 110405, 110403], keyStatus: [110401, 110402, 110412, 110405, 110403],
keyRight: 0 keyRight: 0
}, }
} }
}, },
actions: { actions: {
@ -62,17 +62,19 @@ export const useLockStore = defineStore('lock', {
}, },
// 获取电量icon // 获取电量icon
getPowerIcon(power) { getPowerIcon(power) {
if(power >= 80) { if (power >= 80) {
return '/static/images/icon_power_5.png' return '/static/images/icon_power_5.png'
} else if(power >= 60) {
return '/static/images/icon_power_4.png'
} else if(power >= 40) {
return '/static/images/icon_power_3.png'
} else if(power >= 20) {
return '/static/images/icon_power_2.png'
} else {
return '/static/images/icon_power_1.png'
} }
if (power >= 60) {
return '/static/images/icon_power_4.png'
}
if (power >= 40) {
return '/static/images/icon_power_3.png'
}
if (power >= 20) {
return '/static/images/icon_power_2.png'
}
return '/static/images/icon_power_1.png'
}, },
// 将星期转换为中文字符串 // 将星期转换为中文字符串
convertWeekDaysToChineseString(weekDays) { convertWeekDaysToChineseString(weekDays) {
@ -106,153 +108,165 @@ export const useLockStore = defineStore('lock', {
this.currentPasswordInfo = info this.currentPasswordInfo = info
}, },
getRole(userType, keyRight) { getRole(userType, keyRight) {
if(userType === 110301) { if (userType === 110301) {
return '超级管理员' return '超级管理员'
} else if(keyRight === 1) {
return '授权管理员'
} else {
return '普通用户'
} }
if (keyRight === 1) {
return '授权管理员'
}
return '普通用户'
}, },
getKeyStatus(keyStatus) { getKeyStatus(keyStatus) {
if(keyStatus === 110401) { if (keyStatus === 110401) {
return ''
} else if(keyStatus === 110403) {
return '未生效'
} else if(keyStatus === 110402) {
return '待接收'
} else if(keyStatus === 110412) {
return '已过期'
} else if(keyStatus === 110405) {
return '已冻结'
} else {
return '' return ''
} }
if (keyStatus === 110403) {
return '未生效'
}
if (keyStatus === 110402) {
return '待接收'
}
if (keyStatus === 110412) {
return '已过期'
}
if (keyStatus === 110405) {
return '已冻结'
}
return ''
}, },
getPasswordStatus(passwordStatus) { getPasswordStatus(passwordStatus) {
if(passwordStatus === 2) { if (passwordStatus === 2) {
return '已过期' return '已过期'
} else if(passwordStatus === 3) {
return '未生效'
} else {
return ''
} }
if (passwordStatus === 3) {
return '未生效'
}
return ''
}, },
getTimeLimit(keyType) { getTimeLimit(keyType) {
if(keyType === 1) { if (keyType === 1) {
return '永久' return '永久'
} else if(keyType === 2) {
return '限时'
} else if(keyType === 3) {
return '单次'
} else {
return '循环'
} }
if (keyType === 2) {
return '限时'
}
if (keyType === 3) {
return '单次'
}
return '循环'
}, },
async getLockList(params) { async getLockList(params) {
const { code, data, message } = await getLockListRequest(params) const { code, data, message } = await getLockListRequest(params)
if(code === 0) { if (code === 0) {
this.lockTotal = data.total this.lockTotal = data.total
for(let i = 0; i < data.groupList.length; i++) { for (let i = 0; i < data.groupList.length; i++) {
for (let j = 0; j < data.groupList[i].lockList.length; j++) { for (let j = 0; j < data.groupList[i].lockList.length; j++) {
if((data.groupList[i].lockList[j].keyType === 2 || data.groupList[i].lockList[j].keyType === 4) && data.groupList[i].lockList[j].keyStatus === 110401) { if (
(data.groupList[i].lockList[j].keyType === 2 ||
data.groupList[i].lockList[j].keyType === 4) &&
data.groupList[i].lockList[j].keyStatus === 110401
) {
const now = new Date().getTime() const now = new Date().getTime()
const diffInMilliseconds = data.groupList[i].lockList[j].endDate - now const diffInMilliseconds = data.groupList[i].lockList[j].endDate - now
const millisecondsPerDay = 24 * 60 * 60 * 1000 const millisecondsPerDay = 24 * 60 * 60 * 1000
const diffInDays = Math.floor(diffInMilliseconds / millisecondsPerDay) const diffInDays = Math.floor(diffInMilliseconds / millisecondsPerDay)
if(diffInDays > 0 && diffInDays <= 15) { if (diffInDays > 0 && diffInDays <= 15) {
data.groupList[i].lockList[j].days = diffInDays data.groupList[i].lockList[j].days = diffInDays
} }
} }
} }
} }
if(params.pageNo === 1) { if (params.pageNo === 1) {
this.lockList = data.groupList this.lockList = data.groupList
} else { } else {
this.lockList = this.lockList.concat(data.groupList) this.lockList = this.lockList.concat(data.groupList)
} }
setStorage('lockList', this.lockList) setStorage('lockList', this.lockList)
return { code } return { code }
} else {
return { code, message }
} }
return { code, message }
}, },
async getPasswordList(params) { async getPasswordList(params) {
const { code, data, message } = await getPsaawordListRequest(params) const { code, data, message } = await getPsaawordListRequest(params)
if(code === 0) { if (code === 0) {
this.passwordTotal = data.total this.passwordTotal = data.total
for(let i = 0; i < data.list.length; i++) { for (let i = 0; i < data.list.length; i++) {
if(data.list[i].keyboardPwdType === 1) { if (data.list[i].keyboardPwdType === 1) {
data.list[i].timeText = `${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} 单次` data.list[i].timeText =
} else if(data.list[i].keyboardPwdType === 2) { `${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} 单次`
data.list[i].timeText = `${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} 永久` } else if (data.list[i].keyboardPwdType === 2) {
} else if(data.list[i].keyboardPwdType === 3) { data.list[i].timeText =
`${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} 永久`
} else if (data.list[i].keyboardPwdType === 3) {
data.list[i].timeText = `${data.list[i].validTimeStr} 限时` data.list[i].timeText = `${data.list[i].validTimeStr} 限时`
} else if(data.list[i].keyboardPwdType === 4) { } else if (data.list[i].keyboardPwdType === 4) {
data.list[i].timeText = `${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} 清空码` data.list[i].timeText =
`${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} 清空码`
} else { } else {
let text = '' let text = ''
if(data.list[i].keyboardPwdType === 5) { if (data.list[i].keyboardPwdType === 5) {
text = '周末' text = '周末'
} else if(data.list[i].keyboardPwdType === 6) { } else if (data.list[i].keyboardPwdType === 6) {
text = '每日' text = '每日'
} else if(data.list[i].keyboardPwdType === 7) { } else if (data.list[i].keyboardPwdType === 7) {
text = '工作日' text = '工作日'
} else if(data.list[i].keyboardPwdType === 8) { } else if (data.list[i].keyboardPwdType === 8) {
text = '周一' text = '周一'
} else if(data.list[i].keyboardPwdType === 9) { } else if (data.list[i].keyboardPwdType === 9) {
text = '周二' text = '周二'
} else if(data.list[i].keyboardPwdType === 10) { } else if (data.list[i].keyboardPwdType === 10) {
text = '周三' text = '周三'
} else if(data.list[i].keyboardPwdType === 11) { } else if (data.list[i].keyboardPwdType === 11) {
text = '周四' text = '周四'
} else if(data.list[i].keyboardPwdType === 12) { } else if (data.list[i].keyboardPwdType === 12) {
text = '周五' text = '周五'
} else if(data.list[i].keyboardPwdType === 13) { } else if (data.list[i].keyboardPwdType === 13) {
text = '周六' text = '周六'
} else if(data.list[i].keyboardPwdType === 14) { } else if (data.list[i].keyboardPwdType === 14) {
text = '周日' text = '周日'
} }
data.list[i].timeText = `${text} ${data.list[i].hoursStart}:00-${data.list[i].hoursEnd}:00 循环` data.list[i].timeText =
`${text} ${data.list[i].hoursStart}:00-${data.list[i].hoursEnd}:00 循环`
} }
if(data.list[i].isCustom === 1) { if (data.list[i].isCustom === 1) {
data.list[i].timeText += ' 自定义' data.list[i].timeText += ' 自定义'
} }
} }
if(params.pageNo === 1) { if (params.pageNo === 1) {
this.passwordList = data.list this.passwordList = data.list
} else { } else {
this.passwordList = this.passwordList.concat(data.list) this.passwordList = this.passwordList.concat(data.list)
} }
return { code } return { code }
} else {
return { code, message }
} }
return { code, message }
}, },
async getKeyList(params) { async getKeyList(params) {
const { code, data, message } = await getKeyListRequest(params) const { code, data, message } = await getKeyListRequest(params)
if(code === 0) { if (code === 0) {
this.keyTotal = data.total this.keyTotal = data.total
for(let i = 0; i < data.list.length; i++) { for (let i = 0; i < data.list.length; i++) {
if(data.list[i].keyType === 1) { if (data.list[i].keyType === 1) {
data.list[i].timeText = `${timeFormat(new Date(data.list[i].sendDate), 'yyyy-mm-dd h:M')} 永久` data.list[i].timeText =
} else if(data.list[i].keyType === 2) { `${timeFormat(new Date(data.list[i].sendDate), 'yyyy-mm-dd h:M')} 永久`
data.list[i].timeText = `${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} - ${timeFormat(new Date(data.list[i].endDate), 'yyyy-mm-dd h:M')} 限时` } else if (data.list[i].keyType === 2) {
} else if(data.list[i].keyType === 3) { data.list[i].timeText =
data.list[i].timeText = `${timeFormat(new Date(data.list[i].sendDate), 'yyyy-mm-dd h:M')} 单次` `${timeFormat(new Date(data.list[i].startDate), 'yyyy-mm-dd h:M')} - ${timeFormat(new Date(data.list[i].endDate), 'yyyy-mm-dd h:M')} 限时`
} else if (data.list[i].keyType === 3) {
data.list[i].timeText =
`${timeFormat(new Date(data.list[i].sendDate), 'yyyy-mm-dd h:M')} 单次`
} else { } else {
data.list[i].timeText = `循环` data.list[i].timeText = `循环`
} }
} }
if(params.pageNo === 1) { if (params.pageNo === 1) {
this.keyList = data.list this.keyList = data.list
} else { } else {
this.keyList = this.keyList.concat(data.list) this.keyList = this.keyList.concat(data.list)
} }
return { code } return { code }
} else {
return { code, message }
} }
return { code, message }
} }
} }
}) })

View File

@ -11,37 +11,39 @@ export const useNotificationStore = defineStore('notification', {
// 通知列表搜索数据 // 通知列表搜索数据
notificationSearch: { notificationSearch: {
pageNo: 1, pageNo: 1,
pageSize: 50, pageSize: 50
}, }
} }
}, },
actions: { actions: {
// 删除通知列表某一项数据 // 删除通知列表某一项数据
deleteNotificationItem (index) { deleteNotificationItem(index) {
this.notificationList.splice(index, 1) this.notificationList.splice(index, 1)
}, },
// 更新某一项通知列表数据 // 更新某一项通知列表数据
updateNotificationItem (index, params) { updateNotificationItem(index, params) {
this.notificationList[index] = { ...this.notificationList[index], ...params } this.notificationList[index] = { ...this.notificationList[index], ...params }
}, },
// 更新通知列表搜索数据 // 更新通知列表搜索数据
updateNotificationSearch (params) { updateNotificationSearch(params) {
this.notificationSearch = { ...this.notificationSearch, ...params } this.notificationSearch = { ...this.notificationSearch, ...params }
}, },
// 获取通知列表 // 获取通知列表
async getNotificationList (params) { async getNotificationList(params) {
const { code, data, message } = await getNotificationList({ pageNo: params.pageNo, pageSize: params.pageSize }) const { code, data, message } = await getNotificationList({
if(code === 0) { pageNo: params.pageNo,
pageSize: params.pageSize
})
if (code === 0) {
this.notificationTotal = data.total this.notificationTotal = data.total
if(params.pageNo === 1) { if (params.pageNo === 1) {
this.notificationList = data.list this.notificationList = data.list
} else { } else {
this.notificationList = this.notificationList.concat(data.list) this.notificationList = this.notificationList.concat(data.list)
} }
return { code } return { code }
} else {
return { code, message }
} }
}, return { code, message }
}
} }
}) })

View File

@ -26,7 +26,7 @@ export const useUserStore = defineStore('user', {
// 获取用户信息 // 获取用户信息
async getUserInfo() { async getUserInfo() {
const { code, data } = await getUserInfoRequest() const { code, data } = await getUserInfoRequest()
if(code === 0) { if (code === 0) {
setStorage('userInfo', data) setStorage('userInfo', data)
this.updateUserInfo(data) this.updateUserInfo(data)
this.updateLoginStatus(true) this.updateLoginStatus(true)
@ -36,11 +36,11 @@ export const useUserStore = defineStore('user', {
async phoneLogin(params) { async phoneLogin(params) {
const { iv, encryptedData } = params const { iv, encryptedData } = params
const openid = await getStorage('openid') const openid = await getStorage('openid')
if(!openid) { if (!openid) {
return false return false
} }
const { code, data } = await phoneLoginRequest({ iv, encryptedData, openid }) const { code, data } = await phoneLoginRequest({ iv, encryptedData, openid })
if(code === 0) { if (code === 0) {
setStorage('token', data.accessToken) setStorage('token', data.accessToken)
this.getUserInfo() this.getUserInfo()
useLockStore().updateLockSearch({ useLockStore().updateLockSearch({
@ -54,12 +54,11 @@ export const useUserStore = defineStore('user', {
}) })
useNotificationStore().getNotificationList(useNotificationStore().notificationSearch) useNotificationStore().getNotificationList(useNotificationStore().notificationSearch)
return true return true
} else {
return false
} }
return false
}, },
async checkSession() { async checkSession() {
return new Promise((resolve) => { return new Promise(resolve => {
uni.checkSession({ uni.checkSession({
success() { success() {
resolve(true) resolve(true)
@ -67,7 +66,7 @@ export const useUserStore = defineStore('user', {
fail() { fail() {
uni.login({ uni.login({
provider: 'weixin', provider: 'weixin',
success: async function (loginRes) { async success(loginRes) {
const { code, data } = await loginRequest({ const { code, data } = await loginRequest({
js_code: loginRes.code js_code: loginRes.code
}) })

View File

@ -1,10 +1,16 @@
uni.addInterceptor({ uni.addInterceptor({
returnValue (res) { returnValue(res) {
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { if (
return res; !(
!!res &&
(typeof res === 'object' || typeof res === 'function') &&
typeof res.then === 'function'
)
) {
return res
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
res.then((res) => res[0] ? reject(res[0]) : resolve(res[1])); res.then(res => (res[0] ? reject(res[0]) : resolve(res[1])))
}); })
}, }
}); })

View File

@ -1,4 +1,4 @@
var log = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : null let log = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : null
export default { export default {
debug() { debug() {
@ -17,12 +17,14 @@ export default {
if (!log) return if (!log) return
log.error.apply(log, arguments) log.error.apply(log, arguments)
}, },
setFilterMsg(msg) { // 从基础库2.7.3开始支持 setFilterMsg(msg) {
// 从基础库2.7.3开始支持
if (!log || !log.setFilterMsg) return if (!log || !log.setFilterMsg) return
if (typeof msg !== 'string') return if (typeof msg !== 'string') return
log.setFilterMsg(msg) log.setFilterMsg(msg)
}, },
addFilterMsg(msg) { // 从基础库2.8.1开始支持 addFilterMsg(msg) {
// 从基础库2.8.1开始支持
if (!log || !log.addFilterMsg) return if (!log || !log.addFilterMsg) return
if (typeof msg !== 'string') return if (typeof msg !== 'string') return
log.addFilterMsg(msg) log.addFilterMsg(msg)

View File

@ -2,18 +2,18 @@ import env from '@/config/env'
import { getStorage, removeStorage } from './storage' import { getStorage, removeStorage } from './storage'
/* /*
* config * config
* baseUrl: 请求域名 * baseUrl: 请求域名
* url: 请求路径 * url: 请求路径
* method: 请求方法 * method: 请求方法
* header: 请求头 * header: 请求头
* token: 请求token * token: 请求token
* data: 请求参数 * data: 请求参数
* */ * */
const request = (config) => { const request = config => {
let timer let timer
return new Promise(async (resolve) => { return new Promise(async resolve => {
const baseConfig = await env[getApp().globalData.getEnvConfig()] const baseConfig = await env[getApp().globalData.getEnvConfig()]
const token = config?.token ? config.token : getStorage('token') const token = config?.token ? config.token : getStorage('token')
@ -36,7 +36,7 @@ const request = (config) => {
header, header,
data, data,
timeout: 3000, timeout: 3000,
async success (res) { async success(res) {
const { statusCode, data } = res const { statusCode, data } = res
if (timer) { if (timer) {
clearTimeout(timer) clearTimeout(timer)
@ -52,7 +52,7 @@ const request = (config) => {
title: '提示', title: '提示',
content: '登录已过期,请重新登录', content: '登录已过期,请重新登录',
showCancel: false, showCancel: false,
success () { success() {
uni.reLaunch({ uni.reLaunch({
url: '/pages/home/home' url: '/pages/home/home'
}) })
@ -69,14 +69,14 @@ const request = (config) => {
resolve({ code: -1, data, message: '网络访问失败,请检查网络是否正常' }) resolve({ code: -1, data, message: '网络访问失败,请检查网络是否正常' })
} }
}, },
async fail (res) { async fail(res) {
console.log('网络访问失败', res) console.log('网络访问失败', res)
if (timer) { if (timer) {
clearTimeout(timer) clearTimeout(timer)
} }
resolve({ code: -1, message: '网络访问失败,请检查网络是否正常' }) resolve({ code: -1, message: '网络访问失败,请检查网络是否正常' })
}, },
async complete (res) { async complete(res) {
console.log(URL.substring(baseConfig.baseUrl.length + 1), { console.log(URL.substring(baseConfig.baseUrl.length + 1), {
env: await getApp().globalData.getEnvConfig(), env: await getApp().globalData.getEnvConfig(),
url: URL.substring(baseConfig.baseUrl.length + 1), url: URL.substring(baseConfig.baseUrl.length + 1),