feat: wifi配网相关逻辑+p2p测试
This commit is contained in:
parent
9b47ddea95
commit
ee584cc262
@ -41,8 +41,17 @@ module.exports = {
|
||||
'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', // 禁止不规则的空白\
|
||||
'no-use-before-define': 'error', // 禁止在 函数/类/变量 定义之前使用它们
|
||||
'no-irregular-whitespace': 'off', // 禁止不规则的空白
|
||||
'no-undef': 'error', // 禁止使用未声明的变量
|
||||
'vue/script-setup-uses-vars': 'off', // 关闭此规则,因为它可能会干扰no-undef的检测
|
||||
'vue/no-undef-components': 'off', // 关闭组件未定义的检查
|
||||
'vue/no-undef-properties': [
|
||||
'error',
|
||||
{
|
||||
ignore: ['getDeviceInfo', 'getBluetoothDevices', 'stopGetBluetoothDevices']
|
||||
}
|
||||
], // 忽略特定方法的未定义检查
|
||||
'import/no-cycle': 0,
|
||||
'no-nested-ternary': 0,
|
||||
'import/prefer-default-export': 0,
|
||||
@ -61,7 +70,6 @@ module.exports = {
|
||||
'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
|
||||
|
||||
12
api/sdk.js
Normal file
12
api/sdk.js
Normal file
@ -0,0 +1,12 @@
|
||||
import request from '../utils/request'
|
||||
|
||||
// sdk 模块
|
||||
|
||||
// 获取SDK Token
|
||||
export function getSdkToken(data) {
|
||||
return request({
|
||||
url: '/wechat/tencentYunBind',
|
||||
method: 'POST',
|
||||
data
|
||||
})
|
||||
}
|
||||
@ -91,13 +91,13 @@
|
||||
|
||||
<style scoped lang="scss">
|
||||
.name {
|
||||
height: 100rpx;
|
||||
width: 750rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
font-weight: bold;
|
||||
width: 750rpx;
|
||||
height: 100rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
background-color: #ffffff;
|
||||
|
||||
.name-text {
|
||||
width: 168rpx;
|
||||
@ -106,11 +106,11 @@
|
||||
}
|
||||
|
||||
.picker {
|
||||
margin-right: 32rpx;
|
||||
text-align: right;
|
||||
width: 518rpx;
|
||||
height: 100rpx;
|
||||
margin-right: 32rpx;
|
||||
line-height: 100rpx;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -53,53 +53,52 @@
|
||||
from {
|
||||
transform: rotate(0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
.spinner-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.circle-border {
|
||||
padding: 3upx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
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: absolute;
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 3upx;
|
||||
background: rgb(99, 184, 175);
|
||||
background: linear-gradient(0deg, rgba(99, 184, 175, 0.1) 33%, rgba(99, 184, 175, 1) 100%);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear 0s infinite;
|
||||
}
|
||||
|
||||
.circle-border-stop {
|
||||
padding: 3upx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
background: rgb(99, 184, 175);
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 3upx;
|
||||
background: rgb(99, 184, 175);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.circle-core {
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
9
config/constants.js
Normal file
9
config/constants.js
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 应用全局常量配置
|
||||
*/
|
||||
|
||||
// P2P相关常量
|
||||
export const P2P_PLAYER_ID = 'p2p-player'
|
||||
export const P2P_PUSHER_ID = 'p2p-pusher'
|
||||
|
||||
// 其他常量可以在这里添加
|
||||
@ -38,5 +38,13 @@ const SKY = {
|
||||
buildNumber
|
||||
}
|
||||
|
||||
const GE = {
|
||||
name: 'ge',
|
||||
baseUrl: 'http://lock.ge.star-lock.cn/api',
|
||||
webviewBaseUrl: 'http://lock.ge.star-lock.cn',
|
||||
version,
|
||||
buildNumber
|
||||
}
|
||||
|
||||
// 更换环境的时候 切换导出就行
|
||||
export default { DEV, PRE, XHJ, SKY }
|
||||
export default { DEV, PRE, XHJ, SKY, GE }
|
||||
|
||||
3
exportForPlayerPlugin.js
Normal file
3
exportForPlayerPlugin.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
wx
|
||||
}
|
||||
22
exportForXp2pPlugin.js
Normal file
22
exportForXp2pPlugin.js
Normal file
@ -0,0 +1,22 @@
|
||||
const appParams = {
|
||||
appid: 123,
|
||||
appOauthId: 'xxx',
|
||||
appKey: 'xxx',
|
||||
appSecretKey: 'xxx',
|
||||
appPackage: 'ios.test.com'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
wx,
|
||||
getXp2pAppParams() {
|
||||
return appParams
|
||||
},
|
||||
getXp2pConfig() {
|
||||
return {
|
||||
enableCrypto: true
|
||||
}
|
||||
},
|
||||
getPlayerPlugin() {
|
||||
return requirePlugin('wechat-p2p-player')
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,6 @@
|
||||
"description": "",
|
||||
"versionName": "1.2.0",
|
||||
"versionCode": "35",
|
||||
"transformPx": false,
|
||||
"mp-weixin": {
|
||||
"appid": "wx9829a39e65550757",
|
||||
"setting": {
|
||||
@ -24,6 +23,22 @@
|
||||
"lazyCodeLoading": "requiredComponents",
|
||||
"optimization": {
|
||||
"subPackages": true
|
||||
},
|
||||
"plugins": {
|
||||
"xp2p": {
|
||||
"version": "latest",
|
||||
"provider": "wx1319af22356934bf",
|
||||
"export": "exportForXp2pPlugin.js"
|
||||
},
|
||||
"wechat-p2p-player": {
|
||||
"version": "latest",
|
||||
"provider": "wx9e8fbc98ceac2628",
|
||||
"export": "exportForPlayerPlugin.js"
|
||||
},
|
||||
"wmpf-voip": {
|
||||
"version": "latest",
|
||||
"provider": "wxf830863afde621eb"
|
||||
}
|
||||
}
|
||||
},
|
||||
"vueVersion": "3"
|
||||
|
||||
6968
package-lock.json
generated
6968
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,10 @@
|
||||
"dependencies": {
|
||||
"pinia": "^2.2.0",
|
||||
"pinia-plugin-unistorage": "^0.1.2",
|
||||
"qcloud-iotexplorer-appdev-plugin-wificonf-blecombo": "^3.0.118",
|
||||
"qcloud-iotexplorer-appdev-plugin-wificonf-core": "^3.0.118",
|
||||
"qcloud-iotexplorer-appdev-sdk": "^3.0.118",
|
||||
"qcloud-iotexplorer-bluetooth-adapter": "^3.0.118",
|
||||
"uview-plus": "^3.3.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -19,6 +23,7 @@
|
||||
"husky": "^9.1.7",
|
||||
"js-md5": "^0.8.3",
|
||||
"lint-staged": "^15.4.3",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"prettier": "^3.4.2",
|
||||
"sm-crypto": "^0.3.13",
|
||||
"stylelint": "^16.14.1",
|
||||
@ -28,8 +33,7 @@
|
||||
"stylelint-config-standard": "^37.0.0",
|
||||
"unocss": "^65.4.3",
|
||||
"unocss-preset-weapp": "^65.4.1",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"postcss-scss": "^4.0.9"
|
||||
"vite-plugin-eslint": "^1.8.1"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,vue,json,css,scss}\"",
|
||||
|
||||
19
pages.json
19
pages.json
@ -8,6 +8,23 @@
|
||||
}
|
||||
},
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "pages/p2p",
|
||||
"pages": [
|
||||
{
|
||||
"path": "p2pPlayer",
|
||||
"style": {
|
||||
"navigationBarTitleText": "监控",
|
||||
"mp-weixin": {
|
||||
"usingComponents": {
|
||||
"iot-p2p-player-with-mjpg": "plugin://xp2p/iot-p2p-player-with-mjpg",
|
||||
"iot-p2p-voice": "plugin://xp2p/iot-p2p-voice"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/addDeviceForWiFi",
|
||||
"pages": [
|
||||
@ -574,7 +591,7 @@
|
||||
],
|
||||
"preloadRule": {
|
||||
"pages/main/home": {
|
||||
"packages": ["pages/others", "pages/addDeviceForBluetooth"]
|
||||
"packages": ["pages/others", "pages/addDeviceForBluetooth", "pages/p2p"]
|
||||
},
|
||||
"pages/main/lockDetail": {
|
||||
"packages": ["pages/lockUserManage", "pages/featureForBluetooth", "pages/settingForBluetooth"]
|
||||
|
||||
@ -175,16 +175,16 @@
|
||||
}
|
||||
|
||||
.device {
|
||||
background: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100rpx;
|
||||
background: #ffffff;
|
||||
|
||||
.device-lock {
|
||||
margin-left: 24rpx;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.device-name {
|
||||
|
||||
@ -6,12 +6,11 @@
|
||||
<up-steps-item title="连接设备蓝牙" :itemStyle="{ fontSize: '48rpx' }"></up-steps-item>
|
||||
<up-steps-item title="开始配网" :itemStyle="{ fontSize: '48rpx' }"></up-steps-item>
|
||||
</up-steps>
|
||||
<view class="mt-8 mx-8">
|
||||
<view class="mt-8 mx-8 flex flex-col h-[calc(100vh-300rpx)]">
|
||||
<view v-if="current === 0">
|
||||
<view class="text-lg font-bold mb-4">请选择WiFi并输入密码</view>
|
||||
<view class="py-2 border-b border-gray-200">
|
||||
<view class="pt-2 pb-3 border-b-2 border-b-solid border-gray-200">
|
||||
<picker
|
||||
v-if="wifiList.length > 0"
|
||||
mode="selector"
|
||||
:range="wifiList"
|
||||
:value="wifiIndex"
|
||||
@ -20,22 +19,86 @@
|
||||
>
|
||||
<view class="flex items-center">
|
||||
<view class="mr-4">WiFi</view>
|
||||
<view>{{ wifiList[wifiIndex].SSID }}</view>
|
||||
<view>{{ wifiList[wifiIndex]?.SSID ?? '加载中...' }}</view>
|
||||
<view class="ml-a">
|
||||
<up-icon name="arrow-right" size="24rpx"></up-icon>
|
||||
</view>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="py-2 border-b border-gray-200">
|
||||
<view class="py-2 border-b-2 border-b-solid border-gray-200 flex items-center">
|
||||
<view>密码</view>
|
||||
<view>
|
||||
<up-input v-model="password" placeholder="请输入密码" type="password" />
|
||||
<view class="flex-1">
|
||||
<up-input
|
||||
:customStyle="{
|
||||
padding: '0 28rpx',
|
||||
outline: 'none',
|
||||
height: '80rpx',
|
||||
backgroundColor: '#FFFFFF',
|
||||
border: 0
|
||||
}"
|
||||
placeholder-class="!text-base !line-height-[80rpx]"
|
||||
v-model="password"
|
||||
placeholder="请输入密码"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
>
|
||||
<template #suffix>
|
||||
<up-icon
|
||||
:name="showPassword ? 'eye-fill' : 'eye-off'"
|
||||
size="42rpx"
|
||||
@click="togglePassword"
|
||||
></up-icon>
|
||||
</template>
|
||||
</up-input>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="current === 1" class="flex flex-col h-[calc(100vh-230rpx)]">
|
||||
<view class="text-lg font-bold mb-2">请连接设备蓝牙</view>
|
||||
<view class="text-[#999999]">已发现设备如下</view>
|
||||
<scroll-view scroll-y class="flex-1 mt-4 overflow-hidden">
|
||||
<view
|
||||
v-for="item in deviceList"
|
||||
:key="item.deviceId"
|
||||
@click="connectDevice(item)"
|
||||
class="bg-[#efedf1] rounded-xl py-4 px-3 mt-2 flex justify-between"
|
||||
>
|
||||
<view>{{ item.name }}</view>
|
||||
<view class="text-[#63b8af]">连接</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="flex justify-center items-center mt-2">
|
||||
<up-loading-icon
|
||||
size="70rpx"
|
||||
text="搜索中"
|
||||
:vertical="true"
|
||||
textSize="28rpx"
|
||||
></up-loading-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="current === 2">
|
||||
<view class="flex justify-center mt-10">
|
||||
<image
|
||||
src="https://oss-lock.xhjcn.ltd/mp/cloud_server.png"
|
||||
mode="aspectFill"
|
||||
class="w-200rpx h-200rpx p-4"
|
||||
></image>
|
||||
</view>
|
||||
<view
|
||||
v-for="(item, index) in stepList"
|
||||
:key="item"
|
||||
class="flex items-center mt-4 justify-center w-full"
|
||||
>
|
||||
<view class="flex items-center justify-start w-400rpx">
|
||||
<up-loading-icon mode="circle" v-if="step < index + 1" size="36rpx"></up-loading-icon>
|
||||
<up-icon name="checkbox-mark" color="#63b8af" size="36rpx" v-else></up-icon>
|
||||
<view class="ml-3">{{ item }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="current === 0"
|
||||
class="fixed bottom-[calc(env(safe-area-inset-bottom)+32rpx)] w-686rpx mx-4 h-88rpx text-center text-white bg-[#63b8af] leading-[88rpx] rounded-44rpx font-bold"
|
||||
@click="handleNext"
|
||||
>下一步</view
|
||||
@ -46,13 +109,46 @@
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { constants as WifiConfConstants } from 'qcloud-iotexplorer-appdev-plugin-wificonf-core'
|
||||
import { BlueToothAdapter } from 'qcloud-iotexplorer-bluetooth-adapter'
|
||||
import {
|
||||
BleComboEspDeviceAdapter,
|
||||
BleComboLLSyncDeviceAdapter
|
||||
} from 'qcloud-iotexplorer-appdev-plugin-wificonf-blecombo'
|
||||
import { useBasicStore } from '@/stores/basic'
|
||||
import { useSdkStore } from '@/stores/sdk'
|
||||
|
||||
const bluetoothAdapter = new BlueToothAdapter({
|
||||
deviceAdapters: [BleComboEspDeviceAdapter, BleComboLLSyncDeviceAdapter]
|
||||
})
|
||||
|
||||
const { WifiConfStepCode, WifiConfErrorMsg } = WifiConfConstants
|
||||
|
||||
const $basic = useBasicStore()
|
||||
const $sdk = useSdkStore()
|
||||
|
||||
const current = ref(0)
|
||||
const wifiList = ref([])
|
||||
const wifiIndex = ref(0)
|
||||
const wifiIndex = ref()
|
||||
const password = ref('')
|
||||
|
||||
const step = ref(1)
|
||||
|
||||
const deviceList = ref([])
|
||||
|
||||
const showPassword = ref(false)
|
||||
|
||||
const stepList = ref([
|
||||
'手机与设备连接成功',
|
||||
'向设备发送信息成功',
|
||||
'设备连接云端成功',
|
||||
'初始化成功'
|
||||
])
|
||||
|
||||
const wifiInfo = ref({
|
||||
SSID: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
const deviceInfo = $basic.deviceInfo
|
||||
|
||||
@ -82,7 +178,7 @@
|
||||
return acc
|
||||
}, [])
|
||||
wifiList.value = uniqueWifiList
|
||||
console.log('WiFi列表:', wifiList.value)
|
||||
wifiIndex.value = 0
|
||||
})
|
||||
},
|
||||
fail: err => {
|
||||
@ -126,18 +222,134 @@
|
||||
})
|
||||
})
|
||||
|
||||
const togglePassword = () => {
|
||||
showPassword.value = !showPassword.value
|
||||
}
|
||||
|
||||
const changeWifi = e => {
|
||||
wifiIndex.value = e.detail.value
|
||||
}
|
||||
|
||||
const handleNext = () => {
|
||||
if (current.value === 0) {
|
||||
uni.offGetWifiList()
|
||||
if (deviceInfo.platform === 'android') {
|
||||
uni.stopWifi()
|
||||
}
|
||||
current.value++
|
||||
function bleComboConfigure({ token, wifiInfo, familyId = 'default', roomId, deviceAdapter }) {
|
||||
const onStepChange = progress => {
|
||||
step.value = progress
|
||||
}
|
||||
|
||||
const onProgress = data => {
|
||||
console.info(data.code, data.detail)
|
||||
switch (data.code) {
|
||||
case WifiConfStepCode.PROTOCOL_START:
|
||||
onStepChange(1)
|
||||
break
|
||||
case WifiConfStepCode.PROTOCOL_SUCCESS:
|
||||
onStepChange(2)
|
||||
break
|
||||
case WifiConfStepCode.BUSINESS_QUERY_TOKEN_STATE_SUCCESS:
|
||||
onStepChange(3)
|
||||
break
|
||||
case WifiConfStepCode.WIFI_CONF_SUCCESS:
|
||||
onStepChange(4)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const onComplete = ({ productId, deviceName }) => {
|
||||
console.log('配网成功', productId, deviceName)
|
||||
}
|
||||
|
||||
const onError = async ({ code, detail }) => {
|
||||
const msg = WifiConfErrorMsg[code]
|
||||
console.log('配网错误(onError)', code, msg, detail)
|
||||
}
|
||||
|
||||
$sdk.getSdk().plugins.wifiConfBleCombo.start({
|
||||
wifiConfToken: token,
|
||||
targetWifiInfo: wifiInfo,
|
||||
deviceAdapter,
|
||||
familyId,
|
||||
roomId,
|
||||
onProgress,
|
||||
onError,
|
||||
onComplete
|
||||
})
|
||||
}
|
||||
|
||||
const connectDevice = async device => {
|
||||
try {
|
||||
const deviceAdapter = await bluetoothAdapter.connectDevice(device)
|
||||
console.log(1111, deviceAdapter)
|
||||
bleComboConfigure({
|
||||
token: '1234567890',
|
||||
wifiInfo: wifiInfo.value,
|
||||
familyId: 'default',
|
||||
roomId: 'default',
|
||||
deviceAdapter
|
||||
})
|
||||
current.value++
|
||||
} catch (err) {
|
||||
console.error('连接设备出错', err)
|
||||
}
|
||||
}
|
||||
|
||||
const searchDevice = async () => {
|
||||
try {
|
||||
await bluetoothAdapter.startSearch({
|
||||
onError: error => {
|
||||
console.log('搜索设备出错', error)
|
||||
bluetoothAdapter.stopSearch()
|
||||
},
|
||||
onSearch: devices => {
|
||||
if (devices.length > 0) {
|
||||
console.log('搜索到设备', devices)
|
||||
deviceList.value = devices
|
||||
}
|
||||
},
|
||||
timeout: 1.4 * 15 * 1000
|
||||
})
|
||||
} catch (error) {
|
||||
console.log('搜索设备出错1', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleNext = () => {
|
||||
current.value++
|
||||
searchDevice()
|
||||
if (wifiIndex.value === undefined) {
|
||||
uni.showToast({
|
||||
title: '请选择WiFi',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (password.value === '') {
|
||||
uni.showToast({
|
||||
title: '请输入密码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (password.value.length < 8) {
|
||||
uni.showToast({
|
||||
title: '密码长度不能小于8位',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wifiInfo.value = {
|
||||
SSID: wifiList.value[wifiIndex.value].SSID,
|
||||
password: password.value
|
||||
}
|
||||
|
||||
uni.offGetWifiList()
|
||||
if (deviceInfo.platform === 'android') {
|
||||
uni.stopWifi()
|
||||
}
|
||||
current.value++
|
||||
|
||||
searchDevice()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -182,6 +182,7 @@
|
||||
import { deleteKeyRequest } from '@/api/key'
|
||||
import { deleteLockRequest } from '@/api/lock'
|
||||
import { setStorage, getStorage } from '@/utils/storage'
|
||||
import { useSdkStore } from '@/stores/sdk'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@ -224,7 +225,11 @@
|
||||
this.deviceInfo = await this.getDeviceInfo()
|
||||
const token = getStorage('token')
|
||||
if (token) {
|
||||
await Promise.all([this.getLockList(this.lockSearch), this.getUserInfo()]).then(res => {
|
||||
await Promise.all([
|
||||
this.getLockList(this.lockSearch),
|
||||
this.getUserInfo(),
|
||||
this.initSdk()
|
||||
]).then(res => {
|
||||
this.pending = false
|
||||
uni.hideLoading()
|
||||
const list = getStorage('lockList')
|
||||
@ -272,6 +277,7 @@
|
||||
'resetDevice'
|
||||
]),
|
||||
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType', 'shareJump']),
|
||||
...mapActions(useSdkStore, ['initSdk']),
|
||||
async deleteLock(lock, groupIndex, lockIndex) {
|
||||
const that = this
|
||||
const netWork = await this.getNetworkType()
|
||||
@ -416,6 +422,7 @@
|
||||
that.getLockList(that.lockSearch)
|
||||
await that.getUserInfo()
|
||||
that.updateLoginStatus(true)
|
||||
that.initSdk()
|
||||
resolve(true)
|
||||
} else {
|
||||
that.updateLoginStatus(false)
|
||||
@ -530,8 +537,11 @@
|
||||
this.focus = false
|
||||
},
|
||||
async toSearchDevice() {
|
||||
// this.routeJump({
|
||||
// name: 'selectDeviceType'
|
||||
// })
|
||||
this.routeJump({
|
||||
name: 'selectDeviceType'
|
||||
name: 'p2pPlayer'
|
||||
})
|
||||
},
|
||||
async toLockDetail(lock) {
|
||||
|
||||
@ -156,7 +156,7 @@
|
||||
removeStorage('userInfo')
|
||||
removeStorage('lockList')
|
||||
uni.reLaunch({
|
||||
url: '/pages/home/home'
|
||||
url: '/pages/main/home'
|
||||
})
|
||||
},
|
||||
async changePhone(res) {
|
||||
@ -273,30 +273,30 @@
|
||||
|
||||
<style scoped lang="scss">
|
||||
.background-image {
|
||||
margin-top: 32rpx;
|
||||
margin-left: 20rpx;
|
||||
width: 710rpx;
|
||||
height: 156rpx;
|
||||
margin-top: 32rpx;
|
||||
margin-left: 20rpx;
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
|
||||
.view {
|
||||
margin-top: 32rpx;
|
||||
border-radius: 32rpx;
|
||||
width: 710rpx;
|
||||
margin-top: 32rpx;
|
||||
margin-left: 20rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
|
||||
.view-button {
|
||||
padding: 0 20rpx 0 40rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #292826;
|
||||
justify-content: space-between;
|
||||
padding: 0 20rpx 0 40rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 80rpx;
|
||||
color: #292826;
|
||||
}
|
||||
|
||||
.icon-arrow {
|
||||
@ -312,60 +312,60 @@
|
||||
|
||||
.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;
|
||||
line-height: 80rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
background: #63b8af;
|
||||
border-radius: 46rpx;
|
||||
}
|
||||
|
||||
.env {
|
||||
position: absolute;
|
||||
bottom: 180rpx;
|
||||
width: 600rpx;
|
||||
margin-left: 75rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
margin-left: 75rpx;
|
||||
|
||||
.env-text {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #999999;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.env-button {
|
||||
background: inherit;
|
||||
color: #022b7c;
|
||||
font-size: 0.8rem;
|
||||
color: #022b7c;
|
||||
text-align: right;
|
||||
text-decoration: underline;
|
||||
background: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
line-height: 120rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
background: #63b8af;
|
||||
border-radius: 46rpx;
|
||||
}
|
||||
|
||||
.tips {
|
||||
margin-top: 25vh;
|
||||
padding: 32rpx 0;
|
||||
text-align: center;
|
||||
margin-top: 25vh;
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
92
pages/p2p/p2pPlayer.vue
Normal file
92
pages/p2p/p2pPlayer.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<view>
|
||||
<iot-p2p-player-with-mjpg
|
||||
ref="playerRef"
|
||||
:deviceInfo="deviceInfo"
|
||||
:xp2pInfo="xp2pInfo"
|
||||
:rotate="90"
|
||||
:fill="true"
|
||||
orientation="horizontal"
|
||||
>
|
||||
</iot-p2p-player-with-mjpg>
|
||||
<iot-p2p-voice
|
||||
:deviceInfo="deviceInfo"
|
||||
:xp2pInfo="xp2pInfo"
|
||||
class="w-5 h-5"
|
||||
voiceType="Pusher"
|
||||
id="voiceComponent"
|
||||
:showLog="true"
|
||||
@voicestatechange="handleVoiceStateChange"
|
||||
@voiceerror="handleVoiceError"
|
||||
>
|
||||
</iot-p2p-voice>
|
||||
|
||||
<view class="fixed bottom-20">
|
||||
<button v-if="!isVoice" @click="startVoice">开始语音</button>
|
||||
<button v-else @click="stopVoice">停止语音</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { getXp2pManager } from './xp2pManager'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
let xp2pManager = null
|
||||
|
||||
const playerRef = ref(null)
|
||||
|
||||
const deviceInfo = ref({
|
||||
deviceId: 'NIHQMTTLM4/1000000000',
|
||||
productId: 'NIHQMTTLM4',
|
||||
deviceName: '1000000000'
|
||||
})
|
||||
const xp2pInfo = ref('XP2Pd2ZwIis8ld9kRmeZSH+6vQ==%2.4.49')
|
||||
|
||||
const isVoice = ref(false)
|
||||
|
||||
onMounted(async () => {
|
||||
if (!xp2pManager) {
|
||||
xp2pManager = getXp2pManager()
|
||||
}
|
||||
|
||||
const servicePromise = await xp2pManager.startP2PService({
|
||||
deviceInfo: deviceInfo.value,
|
||||
xp2pInfo: xp2pInfo.value,
|
||||
caller: 1
|
||||
})
|
||||
})
|
||||
|
||||
const handleVoiceStateChange = state => {
|
||||
console.log(111111, state)
|
||||
}
|
||||
|
||||
const handleVoiceError = error => {
|
||||
console.log(1111113, error)
|
||||
}0
|
||||
|
||||
const startVoice = () => {
|
||||
console.log(1111113, playerRef.value)
|
||||
// const voiceNode = res[0].node
|
||||
// if (voiceNode) {
|
||||
// voiceNode.startVoice({
|
||||
// needRecord: false,
|
||||
// customPusher: {}
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
const stopVoice = () => {
|
||||
isVoice.value = false
|
||||
const query = uni.createSelectorQuery()
|
||||
query
|
||||
.select('#voiceComponent')
|
||||
.node()
|
||||
.exec(res => {
|
||||
const voiceNode = res[0].node
|
||||
if (voiceNode) {
|
||||
voiceNode.stopVoice()
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
29
pages/p2p/utils.js
Normal file
29
pages/p2p/utils.js
Normal file
@ -0,0 +1,29 @@
|
||||
export const getUserId = () => {
|
||||
return 1
|
||||
}
|
||||
|
||||
export function compareVersion(ver1, ver2) {
|
||||
const v1 = ver1.split('.')
|
||||
const v2 = ver2.split('.')
|
||||
const len = Math.max(v1.length, v2.length)
|
||||
|
||||
while (v1.length < len) {
|
||||
v1.push('0')
|
||||
}
|
||||
while (v2.length < len) {
|
||||
v2.push('0')
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(v1[i])
|
||||
const num2 = parseInt(v2[i])
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1
|
||||
} else if (num1 < num2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
118
pages/p2p/xp2pManager.js
Normal file
118
pages/p2p/xp2pManager.js
Normal file
@ -0,0 +1,118 @@
|
||||
import { getUserId, compareVersion } from './utils'
|
||||
|
||||
let xp2pManager = null
|
||||
export const getXp2pManager = () => {
|
||||
if (!xp2pManager) {
|
||||
let xp2pPlugin = requirePlugin('xp2p')
|
||||
|
||||
console.log(11111, xp2pPlugin)
|
||||
|
||||
const iotExports = xp2pPlugin.iot
|
||||
const app = getApp()
|
||||
|
||||
// 用户id,微信用户在此小程序中的唯一标识
|
||||
iotExports?.setUserId?.(getUserId() || 'demo')
|
||||
|
||||
// 开发版才打插件log
|
||||
if (app.pluginLogger && uni.getAccountInfoSync().miniProgram.envVersion === 'develop') {
|
||||
iotExports?.setPluginLogger?.(app.pluginLogger)
|
||||
}
|
||||
|
||||
// 设置优先使用的打洞协议
|
||||
if (
|
||||
compareVersion(uni.getSystemInfoSync().SDKVersion, '3.4.1') >= 0 &&
|
||||
xp2pPlugin.p2p.setTcpFirst
|
||||
) {
|
||||
const tcpFirstKey = 'tcpFirst'
|
||||
const tcpFirstTime = parseInt(uni.getStorageSync(tcpFirstKey), 10)
|
||||
const tcpFirst = !!(tcpFirstTime && Date.now() - tcpFirstTime < 3600000 * 24) // 24小时内有效
|
||||
console.log('tcpFirst', tcpFirst)
|
||||
xp2pPlugin.p2p.setTcpFirst(tcpFirst)
|
||||
|
||||
// 给index页用,方便测试时调整tcpFirst
|
||||
app.tcpFirst = tcpFirst
|
||||
app.toggleTcpFirst = async () => {
|
||||
const modalRes = await uni.showModal({
|
||||
title: '确定切换 tcpFirst 吗?',
|
||||
content: '切换后需要重新进入小程序'
|
||||
})
|
||||
if (!modalRes || !modalRes.confirm) {
|
||||
return
|
||||
}
|
||||
uni.setStorageSync(tcpFirstKey, tcpFirst ? '' : Date.now())
|
||||
app.restart()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置是否连接对端stun
|
||||
if (xp2pPlugin.p2p.setCrossStunTurn) {
|
||||
const crossStunTurnKey = 'crossStunTurn'
|
||||
const crossStunTurnTime = parseInt(uni.getStorageSync(crossStunTurnKey), 10)
|
||||
const crossStunTurn = !!(crossStunTurnTime && Date.now() - crossStunTurnTime < 3600000 * 24) // 24小时内有效
|
||||
xp2pPlugin.p2p.setCrossStunTurn(crossStunTurn)
|
||||
// 给index页用,方便测试时调整crossStunTurn
|
||||
app.crossStunTurn = crossStunTurn
|
||||
app.toggleCrossStunTurn = async () => {
|
||||
const modalRes = await uni.showModal({
|
||||
title: '确定切换 crossStunTurn 吗?',
|
||||
content: '切换后需要重新进入小程序'
|
||||
})
|
||||
if (!modalRes || !modalRes.confirm) {
|
||||
return
|
||||
}
|
||||
uni.setStorageSync(crossStunTurnKey, crossStunTurn ? '' : Date.now())
|
||||
app.restart()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置切换端口
|
||||
if (xp2pPlugin.p2p.updateStunPort) {
|
||||
const portKey = 'STUN_PORT'
|
||||
const stunPort = uni.getStorageSync(portKey) || 20002
|
||||
xp2pPlugin.p2p.updateStunPort(stunPort)
|
||||
app.stunPort = stunPort
|
||||
app.togglePort = async port => {
|
||||
const modalRes = await uni.showModal({
|
||||
title: '确定切换 stunPort 吗?',
|
||||
content: '切换后需要重新进入小程序'
|
||||
})
|
||||
if (!modalRes || !modalRes.confirm) {
|
||||
return
|
||||
}
|
||||
uni.setStorageSync(portKey, port)
|
||||
app.restart()
|
||||
}
|
||||
}
|
||||
|
||||
// 设置切换配置跟随
|
||||
if (xp2pPlugin.p2p.setUseDeliveryConfig) {
|
||||
const useDeliveryConfigKey = 'useDeliveryConfig'
|
||||
const useDeliveryConfigTime = parseInt(uni.getStorageSync(useDeliveryConfigKey), 10)
|
||||
const useDeliveryConfig = !!(
|
||||
useDeliveryConfigTime && Date.now() - useDeliveryConfigTime < 3600000 * 24
|
||||
) // 24小时内有效
|
||||
xp2pPlugin.p2p.setUseDeliveryConfig(useDeliveryConfig)
|
||||
app.useDeliveryConfig = useDeliveryConfig
|
||||
app.toggleUseDeliveryConfig = async () => {
|
||||
const modalRes = await uni.showModal({
|
||||
title: '确定切换 使用设备跟随 吗?',
|
||||
content: '切换后需要重新进入小程序'
|
||||
})
|
||||
if (!modalRes || !modalRes.confirm) {
|
||||
return
|
||||
}
|
||||
uni.setStorageSync(useDeliveryConfigKey, useDeliveryConfig ? '' : Date.now())
|
||||
app.restart()
|
||||
}
|
||||
}
|
||||
|
||||
xp2pManager = iotExports.getXp2pManager()
|
||||
app.logger?.log('xp2pManager', {
|
||||
P2PPlayerVersion: xp2pManager.P2PPlayerVersion,
|
||||
XP2PVersion: xp2pManager.XP2PVersion,
|
||||
// uuid,插件随机生成的id,存储在小程序本地,删除小程序后会重新生成
|
||||
uuid: xp2pManager.uuid
|
||||
})
|
||||
}
|
||||
return xp2pManager
|
||||
}
|
||||
@ -391,6 +391,11 @@ const pages = [
|
||||
name: 'distributionNetwork',
|
||||
path: '/pages/addDeviceForWiFi/distributionNetwork',
|
||||
tabBar: false
|
||||
},
|
||||
{
|
||||
name: 'p2pPlayer',
|
||||
path: '/pages/p2p/p2pPlayer',
|
||||
tabBar: false
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
45
stores/sdk.js
Normal file
45
stores/sdk.js
Normal file
@ -0,0 +1,45 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { AppDevSdk } from 'qcloud-iotexplorer-appdev-sdk'
|
||||
import { getSdkToken } from '@/api/sdk'
|
||||
|
||||
export const useSdkStore = defineStore('sdk', {
|
||||
state() {
|
||||
return {
|
||||
sdk: null
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async getSdk() {
|
||||
if (this.sdk.loginManager.isLogin) {
|
||||
return this.sdk
|
||||
}
|
||||
await this.initSdk()
|
||||
return this.sdk
|
||||
},
|
||||
async initSdk() {
|
||||
try {
|
||||
const getAccessToken = async () => {
|
||||
const { code, data, message } = await getSdkToken()
|
||||
if (code === 0) {
|
||||
return data
|
||||
}
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none'
|
||||
})
|
||||
return null
|
||||
}
|
||||
|
||||
this.sdk = await new AppDevSdk({
|
||||
appKey: 'mtBfaXFtISXFYVVsd',
|
||||
getAccessToken
|
||||
})
|
||||
|
||||
this.sdk.init()
|
||||
} catch (error) {
|
||||
console.log(111, this.sdk)
|
||||
console.log('error', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user