2025年04月21日18:27:41

This commit is contained in:
luojiayi 2025-04-21 18:27:42 +08:00
parent bc8449a5c3
commit 3dd224963a
35 changed files with 837 additions and 144 deletions

View File

@ -15,6 +15,7 @@ export default defineConfig(async (merge, { command, mode }) => {
'@src': require('path').resolve(__dirname, '../src/src'),
'@api': require('path').resolve(__dirname, '../src/api'),
'@config': require('path').resolve(__dirname, '../src/config'),
'@baseRouter': require('path').resolve(__dirname, '../src/baseRouter'),
},
projectName: 'myApp',
date: '2023-8-18',

View File

@ -8,6 +8,7 @@
"@/images/*": ["./src/images/*"],
"@/api/*": ["./src/api/*"],
"@/store/*": ["./src/store/*"],
"@/baseRouter/*": ["./src/baseRouter/*"],
"@/src/*": ["./src/*"]
}
}

View File

@ -1,5 +1,7 @@
export default defineAppConfig({
pages: [
"pages/device/index",
"pages/deviceList/index",
"pages/index/index",
"pages/game/index",
"pages/history/index",
@ -10,4 +12,23 @@ export default defineAppConfig({
navigationBarBackgroundColor: "#fff",
navigationBarTextStyle: "black",
},
tabBar: {
color: "#787878",
selectedColor: "#5F93FA",
list: [
{
pagePath: "pages/index/index",
text: "控制",
iconPath: "./assets/menu/m1.png",
selectedIconPath: "./assets/menu/m1_a.png",
},
{
pagePath: "pages/device/index",
text: "设备",
iconPath: "./assets/menu/m2.png",
selectedIconPath: "./assets/menu/m2_a.png",
},
],
},
});

View File

@ -5,7 +5,7 @@ import BLESDK from './utils/ble'
function App({ children }) {
useLaunch(() => {
// BLESDK.openBluetoothAdapter()
BLESDK.openBluetoothAdapter()
})
// children 是将要会渲染的页面

View File

@ -1,7 +1,3 @@
.index {
flex: 1;
}
page {
margin: 0;
padding: 0;
@ -13,5 +9,9 @@ page {
overflow: hidden;
display: flex;
flex-direction: column;
}
.index {
flex: 1;
background: #F7F7F7;
}

BIN
src/assets/addDev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

BIN
src/assets/connectble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/assets/menu/m1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
src/assets/menu/m1_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/assets/menu/m2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
src/assets/menu/m2_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/assets/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
src/assets/roundble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

92
src/baseRouter/index.js Normal file
View File

@ -0,0 +1,92 @@
import { getCurrentPages, debounce } from "@/utils/index";
import Taro from "@tarojs/taro";
class BaseRouter {
// 防止重复点击跳转页面
toPageFlag = false;
data = null;
verifyIsLogin(options) {
const token = Taro.getStorageSync("token");
if (options?.isLogin && !token) {
Taro.showToast({ title: "登录后可使用所有功能", icon: "error" });
return false;
}
return true;
}
/**
*
* @param {*} url 跳转url
* @param {*} options 要传递的参数
* @returns
*/
navigate(url, options) {
return new Promise(async (resolve) => {
if (!this.verifyIsLogin(options)) return;
this.data = options;
if (this.toPageFlag) return;
this.toPageFlag = true;
Taro.navigateTo({
url,
events: {
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
acceptDataFromOpenedPage: (data) => {
resolve(data);
},
},
}).finally(() => {
setTimeout(() => {
this.toPageFlag = false;
}, 1000);
});
});
}
/**
*
* @param {*} url 跳转url
* @param {*} options 要传递的参数
* @returns
*/
reLaunch(url, options) {
this.data = options;
return new Promise(async (resolve) => {
if (!this.verifyIsLogin(options)) return;
Taro.reLaunch({
url,
events: {
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
acceptDataFromOpenedPage: (data) => {
resolve(data);
},
},
});
});
}
/**
* 返回上一页面
* @param delta
* @param data
*/
back = debounce((data, delta = 1) => {
this.data = null;
const eventChannel = getCurrentPages();
if (data != null) eventChannel?.emit("acceptDataFromOpenedPage", data);
Taro.navigateBack({ delta });
});
/**
*
* @returns 获取上一个页面传递过来的参数
*/
getData(fn) {
this.eventChannel = getCurrentPages();
this.eventChannel.on &&
this.eventChannel.on("acceptDataFromOpenedPage", (res) => {
fn && fn(res);
});
}
}
export default new BaseRouter();

View File

@ -5,11 +5,11 @@ import { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import { Popup } from "@taroify/core"
export default function Index({ open, handleColorPicker }) {
export default function Index({ open, onChange }) {
let [data, setData] = useState({
boundaryData: [], //
gradient: '',
hex: '#000000',
hex: '#ff0000',
rgba: {
r: 255,
g: 0,
@ -18,8 +18,8 @@ export default function Index({ open, handleColorPicker }) {
},
hsb: {
h: 0,
s: 0,
b: 0
s: 100,
b: 100
},
bgcolor: {
r: 255,
@ -37,15 +37,6 @@ export default function Index({ open, handleColorPicker }) {
}],
})
useEffect(() => {
setData((state) => {
state.hsb = rgbToHsb(data.rgba)
state.hex = '#' + rgbToHex(data.rgba)
return { ...state }
})
}, [])
useEffect(() => {
if (open) {
setTimeout(() => {
@ -62,18 +53,16 @@ export default function Index({ open, handleColorPicker }) {
return
}
data.boundaryData = res
console.log(res);
setData({ ...data })
}).exec()
}
const confirm = () => {
handleColorPicker({ rgba: [data.rgba.r, data.rgba.g, data.rgba.b, data.rgba.a], hex: data.hex })
onChange({ rgba: `${data.rgba.r}, ${data.rgba.g}, ${data.rgba.b}`, hex: data.hex })
}
const close = () => {
handleColorPicker()
onChange()
}
const touchstart = (e) => {
@ -137,7 +126,6 @@ export default function Index({ open, handleColorPicker }) {
b: rgb.b,
a: data.rgba.a
}
// data
setData((state) => {
state.point[index] = {

View File

@ -0,0 +1,72 @@
import { View, Image, Text } from '@tarojs/components'
import './index.less'
import connectble from "@/assets/connectble.png";
import addDev from "@/assets/addDev.png";
import router from '@/baseRouter/index'
import BLESDK from '@/utils/ble'
import { useEffect, useState } from 'react';
import Taro, { useDidShow } from '@tarojs/taro';
export default function Index() {
const [isLink, setIsLink] = useState(BLESDK.deviceInfo.state)
const addDevice = () => {
router.navigate('/pages/deviceList/index')
}
const deviceCallBack = () => {
setIsLink(BLESDK.deviceInfo.state)
}
useDidShow(() => {
BLESDK.deviceCallBack(deviceCallBack)
setIsLink(BLESDK.deviceInfo.state)
})
useEffect(() => {
if (BLESDK.deviceInfo.name) {
BLESDK.createBleConnection()
}
}, [])
const unbind = () => {
Taro.showModal({
title: '解绑设备',
content: '确认解绑当前设备?',
success: (res) => {
if (res.confirm) {
setIsLink(false)
BLESDK.unBindDevice()
Taro.removeStorageSync('deviceInfo')
Taro.showToast({ title: '设备解绑成功', icon: 'success' })
}
}
})
}
console.log(BLESDK.deviceInfo, BLESDK.deviceInfo?.name ? 1 : 2, 'BLESDK.deviceInfo');
return (
<View className="index device">
{BLESDK.deviceInfo?.name ? <>
<View className="deviceinfo">
<Image src={connectble} className='deviceimg' />
<View className="item">
<View className="item-label">连接状态</View>
<View className="item-text active">{isLink ? '已连接' : '未连接'}</View>
</View>
<View className="item">
<View className="item-label">设备名称</View>
<View className="item-text">{BLESDK.deviceInfo.name}</View>
</View>
<View className="item">
<View className="item-label">MAC 地址</View>
<View className="item-text">{BLESDK.deviceInfo.mac}</View>
</View>
</View>
<View className='btn' onClick={unbind}>解绑设备</View>
</> :
<View className='adddevice' onClick={addDevice}>
<Image src={addDev} className='addimg' />
<View className='text'>添加设备</View>
</View>
}
</View>
)
}

View File

@ -0,0 +1,79 @@
.device {
background: #F7F7F7;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.deviceinfo {
width: 686rpx;
border-radius: 24rpx;
background: #FFFFFF;
padding: 48rpx 32rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 30rpx;
.deviceimg {
width: 300rpx;
height: 300rpx;
}
.item {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-top: 64rpx;
.item-label {
color: #212121;
font-size: 30rpx;
}
.item-text {
color: #666666;
font-size: 30rpx;
}
.active {
color: #5F93FA;
}
}
}
.btn {
width: 686rpx;
height: 80rpx;
border-radius: 50rpx;
background: #E0EBFF;
text-align: center;
line-height: 80rpx;
color: #5F93FA;
font-size: 30rpx;
margin-top: 48rpx;
}
.adddevice {
width: 544rpx;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.addimg {
width: 544rpx;
height: 334rpx;
}
.text {
color: #BABABA;
font-size: 32rpx;
margin-top: 32rpx;
text-align: center;
}
}
}

View File

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "设备列表",
});

View File

@ -0,0 +1,65 @@
import { View } from '@tarojs/components'
import './index.less'
import Taro from '@tarojs/taro'
import { useState, useEffect } from 'react'
import router from '@/baseRouter/index'
import BLESDK from '@/utils/ble'
export default function Index() {
let [deviceList, setDeviceList] = useState([])
const connect = (item) => {
Taro.showLoading({
title: '正在连接设备',
mask: true,
})
BLESDK.deviceInfo = item
BLESDK.createBleConnection()
}
useEffect(() => {
BLESDK.startBluetoothDevicesDiscovery()
Taro.showLoading({ title: '设备搜索中..', mask: true })
BLESDK.deviceCallBack(deviceCallBack)
setTimeout(() => {
Taro.hideLoading()
}, 3000)
return () => {
BLESDK.stopBluetoothDevicesDiscovery()
}
}, [])
const deviceCallBack = (res) => {
Taro.hideLoading()
router.back()
}
BLESDK.onBluetoothDeviceFound((item) => {
if (JSON.stringify(deviceList).indexOf(item.mac) != -1) return
deviceList.push(item)
setDeviceList([...deviceList])
})
return (
<View className="index deviceList">
<View className="head">
<View className="radar">
<View className="yuan1 yuan"></View>
<View className="yuan2 yuan"></View>
<View className="yuan3 yuan"></View>
</View>
<View className="text">请确保手机蓝牙开启同时待激活设备也处于上电开启状态尽量靠近设备强信号有助于提高设备激活的成功率!</View>
</View>
<View className='list'>
{deviceList.map(item => <View className='item'>
<View className='item-img'></View>
<View className='item-content'>
<View className='item-content-name'>{item.name}</View>
<View className='item-content-mac'>{item.mac}</View>
</View>
<View className='item-btn' onClick={() => connect(item)}>连接</View>
</View>)}
</View>
</View >
)
}

View File

@ -0,0 +1,126 @@
.deviceList {
display: flex;
flex-direction: column;
overflow: hidden;
.head {
display: flex;
align-items: center;
position: relative;
padding-top: 1rpx;
padding: 0 32rpx;
.radar {
width: 62rpx;
height: 62rpx;
position: relative;
.yuan {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
border: 1rpx solid #5F93FA;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.yuan1 {
&::after {
content: ' ';
display: block;
background-image: linear-gradient(44deg, rgba(0, 255, 51, 0) 10%, #5F93FA 100%);
width: 50%;
height: 50%;
position: absolute;
top: 0;
left: 0;
animation: zhuan 2s infinite;
animation-timing-function: linear;
transform-origin: bottom right;
border-radius: 100% 0 0 0;
}
}
.yuan2 {
width: 40rpx;
height: 40rpx;
}
.yuan3 {
width: 20rpx;
height: 20rpx;
}
@keyframes zhuan {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
}
.text {
margin-left: 20rpx;
flex: 1;
font-size: 24rpx;
font-family: AlibabaPuHuiTi_2_45_Light;
}
}
.list {
flex: 1;
margin-top: 32rpx;
overflow: auto;
padding: 0 32rpx 50rpx;
.item {
display: flex;
align-items: center;
padding: 26rpx 24rpx;
border-radius: 24rpx;
background: #FFFFFF;
margin-bottom: 24rpx;
.item-img {
width: 60rpx;
height: 60rpx;
background: url('../../assets/roundble.png') no-repeat;
background-size: 100% 100%;
}
.item-content {
flex: 1;
margin: 0 16rpx;
.item-content-name {
color: #000000;
font-size: 32rpx;
}
.item-content-mac {
color: #999999;
font-size: 28rpx;
}
}
.item-btn {
width: 140rpx;
height: 58rpx;
border-radius: 61rpx;
background: #5F93FA;
text-align: center;
line-height: 58rpx;
color: #FFFFFF;
font-size: 28rpx;
}
}
}
}

View File

@ -3,35 +3,80 @@ import './index.less'
import ColorPicker from "@/components/color-picker";
import { useEffect, useState } from 'react';
import history from "../../assets/history.png";
import Taro from '@tarojs/taro';
import { hex, strInsert } from '@/utils/sendOrder';
import BLESDK from '@/utils/ble'
import router from '@/baseRouter/index'
export default function Index() {
const list = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',]
const [list, setList] = useState(["255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255", "255, 255, 255"])
const [open, setOpen] = useState(false)
const [curColor, setCurColor] = useState({
hex: '#ff0000',
rgba: '255, 0, 0'
})
const toPage = () => {
router.navigate('/pages/history/index').then((data) => {
setList([...data])
})
}
const handleColorPicker = (e) => {
console.log(e);
if (e) {
setCurColor(e)
}
setOpen(false)
}
useEffect(() => {
const addColor = (index) => {
setList((state) => {
state[index] = curColor.rgba
return [...state]
})
}
const submit = () => {
let str = '7B55EA10B2'
for (let i = 0; i < list.length; i++) {
const item = list[i].split(',')
str += hex(item[0])
str += hex(item[1])
str += hex(item[2])
str += hex(1)
}
BLESDK.writeBleValue(new Uint8Array(strInsert(str)).buffer)
}
const saveTemplate = () => {
let historyList = Taro.getStorageSync('colorList') || []
if (historyList.length > 10) {
historyList[0] = list
} else {
historyList.unshift(list)
}
Taro.setStorageSync('colorList', historyList)
Taro.showToast({
title: '保存成功',
icon: "none",
})
}
}, [])
return (
<View className="index">
<View className='head'>
<View className='head-left'>像素跳动</View>
<View className='head-right'> <Image className='icon' src={history} />历史记录</View>
<View className='head-right' onClick={toPage}> <Image className='icon' src={history} />历史记录</View>
</View>
<View className="grid">
{list.map((item, index) => <View className={`grid-item ${index == 0 ? 'active' : ''}`} key={index}></View>)}
{list.map((item, index) => <View className="grid-item" style={{ backgroundColor: `rgb(${item})` }} key={index} onClick={() => addColor(index)}></View>)}
</View >
<View className='colorbox'>
<View className='colorbox-icon' onClick={() => setOpen(true)}></View>
<View className='colorbox-btn' onClick={() => setOpen(true)}>#EDEDED</View>
<View className='colorbox-btn' style={{ backgroundColor: curColor.hex }} onClick={() => setOpen(true)}>{curColor.hex}</View>
</View>
<View className='hint'>*请选取喜欢的颜色再点击小方格填入颜色</View>
<View className='btn' >传输画面到音响屏幕</View>
<ColorPicker open={open} handleColorPicker={handleColorPicker} />
<View className='btn' onClick={submit}>传输画面到音响屏幕</View>
<View className='btn' onClick={saveTemplate}>保存模板</View>
<ColorPicker open={open} onChange={handleColorPicker} />
</View >
)
}

View File

@ -60,10 +60,6 @@
border-radius: 8px;
background: #FAFAFA;
border: 1px solid #999999;
&.active {
border: 1px solid #5F93FA;
}
}
}
@ -109,7 +105,7 @@
line-height: 80rpx;
color: #FFFFFF;
font-size: 30rpx;
margin: 0 auto;
margin: 0 auto 30rpx;
}

View File

@ -4,41 +4,52 @@ import "./index.less";
import { useEffect, useState } from "react";
import Taro from "@tarojs/taro";
import empty from "@/assets/empty.png";
import { ActionSheet } from "@taroify/core"
import router from '@/baseRouter/index'
export default function Index() {
const list = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',]
const history = [{}]
const [open, setOpen] = useState(false)
const actions = [
{ name: "使用此套颜色方案", value: "1", style: { color: "#5A8FFA" } },
{ name: "删除此套颜色方案", value: "2", style: { color: "#FF575F" } },
]
let [history, setHistory] = useState(Taro.getStorageSync("colorList") || [])
const delItem = (index) => {
Taro.showModal({
title: '提示',
content: '是否确认删除?',
success: (res) => {
if (res.confirm) {
history.splice(index, 1)
setHistory([...history])
Taro.setStorageSync("colorList", history)
}
}
})
}
const useItem = (item) => {
router.back(item)
}
return (
<View className="index">
<View className="history index">
{
history.length ?
<View>
{
history.map((item, index) => {
return <View className="grid" key={index} onClick={() => setOpen(true)}>
{list.map((ite, ide) => <View className="grid-item" key={`${index}_${ide}`}></View>)}
history.map((item, index) => <View className="card" key={index}>
<View className="grid">
{item.map((ite, ide) => <View className="grid-item" style={{ backgroundColor: `rgb(${ite})` }} key={`_${ide}`}></View>)}
</View >
})
<View className="btns">
<View className="btn del" onClick={() => delItem(index)}>删除</View>
<View className="btn use" onClick={() => useItem(item)}>使用</View>
</View>
</View>)
}
</View>
: <View className="empty">
</View> :
<View className="empty">
<Image src={empty} className="empty-img" />
<View className="empty-text">暂无历史记录</View>
</View>
}
<ActionSheet
cancelText="取消"
actions={actions}
open={open}
onSelect={() => setOpen(false)}
onCancel={() => setOpen(false)}
/>
</View>
);
}

View File

@ -1,31 +1,65 @@
.index {
.history {
overflow: scroll;
padding: 32rpx;
display: flex;
flex-direction: column;
background: #F7F7F7;
.grid {
flex-shrink: 0;
.card {
border-radius: 16rpx;
background: #F9F9F9;
overflow: hidden;
border: 1px solid #999999;
display: grid;
grid-template-columns: repeat(9, 1fr);
gap: 8rpx;
padding: 32rpx;
box-sizing: border-box;
margin-bottom: 30rpx;
margin-bottom: 32rpx;
background: #FFFFFF;
flex-shrink: 0;
.grid-item {
width: 50px;
height: 50px;
border-radius: 8px;
border: 1px solid #999999;
.grid {
flex-shrink: 0;
display: grid;
grid-template-columns: repeat(9, 1fr);
gap: 8rpx;
.grid-item {
width: 50px;
height: 50px;
border-radius: 8px;
border: 1px solid #999999;
flex-shrink: 0;
}
}
.btns {
display: flex;
align-items: center;
justify-content: center;
margin-top: 32rpx;
.btn {
width: 200rpx;
height: 60rpx;
border-radius: 30rpx;
text-align: center;
line-height: 60rpx;
}
.del {
background: #FFDEE3;
color: #FC3258;
}
.use {
background: #DEE9FF;
color: #5F93FA;
margin-left: 24rpx;
}
}
}
.empty {
position: absolute;
top: 40%;

View File

@ -5,9 +5,93 @@ import ble from "@/assets/ble.png";
import soundCard from "@/assets/soundCard.png";
import game from "@/assets/game.png";
import ai from "@/assets/ai.png";
import Taro from '@tarojs/taro';
import { useCallback, useState } from 'react';
import { hex, strInsert } from '@/utils/sendOrder';
import { debounce } from '@/utils/index'
import BLESDK from '@/utils/ble'
export default function Index() {
const sourceList = ['Line', 'OPT', 'ARC', 'USB']
const [ruleForm, setRuleForm] = useState({
volume: 0, //
music: 0, //
source: 0, //
bleSwitch: 0, //
soundCadSwitch: 0, //
playMode: 0, //
musicControl: 0, //
girth: 0, //
reverb: 1, //
microphoneReverberation: 0, //
AI: 0, //AI
playPause: 0, //
})
const toPage = () => {
Taro.navigateTo({ url: '/pages/game/index' })
}
const sendCode = useCallback(debounce((e) => {
BLESDK.writeBleValue(new Uint8Array(strInsert(e)).buffer)
}), [])
const handleChange = (e, key) => {
setRuleForm({
...ruleForm,
[key]: e
})
let str = ''
switch (key) {
case 'volume':
str = `7B05EA05B2${hex(e)}`
break;
case 'music':
str = `7B05EA06B2${hex(e)}`
break;
case 'source':
str = `7B05EA07B2${hex(e)}`
break;
case 'bleSwitch':
str = `7B05EA08B2${hex(e)}`
break;
case 'soundCadSwitch':
str = `7B05EA09B2${hex(e)}`
break;
case 'playMode':
str = `7B05EA0AB2${hex(e)}`
break;
case 'musicControl':
str = `7B05EA0BB2${hex(e)}`
break;
case 'girth':
str = `7B05EA0CB2${hex(e)}`
break;
case 'reverb':
str = `7B05EA0DB2${hex(e)}`
break;
case 'microphoneReverberation':
str = `7B05EA0EB2${hex(e)}`
break;
case 'AI':
str = `7B05EA11B2${hex(e)}`
break;
}
sendCode(str)
}
// 0 1 2 3 4
const musicControl = (num) => {
let str = `7B05EA0BB2${hex(num)}`
sendCode(str)
}
const control = (type) => {
let num = ruleForm.girth
if (type == "+" && ruleForm.girth < 3) {
num++
} else if (type == "-" && ruleForm.girth > 0) {
num--
}
handleChange(num, 'girth')
}
return (
<View className="index">
<View className="headbox">
@ -16,14 +100,13 @@ export default function Index() {
<View className="list">
{
sourceList.map((item, index) => {
return <View className={`list-item ${index == 0 ? 'active' : ''}`} key={index}>
return <View className={`list-item ${index == ruleForm.source ? 'active' : ''}`} key={index} onClick={() => handleChange(index, 'source')}>
<View className="yuan"></View>
<View className="line"></View>
<View className="text">{item}</View>
</View>
})
}
</View>
</View>
@ -32,23 +115,26 @@ export default function Index() {
<View className="switch-item">
<Image className='img' src={ble} />
<Text className='text'>蓝牙</Text>
<Switch size="20" />
<Switch size="20" onChange={(e) => handleChange(e, 'bleSwitch')} checked={ruleForm.bleSwitch} />
</View>
<View className="switch-item">
<Image className='img' src={soundCard} />
<Text className='text'>声卡</Text>
<Switch size="20" />
<Switch size="20" onChange={(e) => handleChange(e, 'soundCadSwitch')} checked={ruleForm.soundCadSwitch} />
</View>
</View>
</View>
<View className='play'>
<View className='play-icon pre'></View>
<View className='play-play'></View>
<View className='play-icon next'></View>
<View className='play-icon pre' onClick={() => musicControl(3)}></View>
<View className={ruleForm.playPause ? 'play-pause' : 'play-play'} onClick={() => {
musicControl(ruleForm.playPause ? 2 : 1)
handleChange(!ruleForm.playPause, 'playPause')
}}></View>
<View className='play-icon next' onClick={() => musicControl(4)}></View>
</View>
<View className='card'>
<View className='funitem'>
<View className='funitem-text'>音乐音量</View>
<View className='funitem-text'>音乐模式</View>
<View className='mode'>
<View className='icon l'></View>
<View className='input'>MODE 1</View>
@ -60,9 +146,22 @@ export default function Index() {
<View className='funitem'>
<View className='funitem-text'>超低音强度</View>
<View className='mode'>
<View className='icon l'></View>
<View className='input'>+ 1</View>
<View className='icon r'></View>
<View className='icon l' onClick={() => control("-")}></View>
<View className='input'>{ruleForm.girth}</View>
<View className='icon r' onClick={() => control("+")}></View>
</View>
</View>
</View>
<View className='card'>
<View className='funitem'>
<View className='funitem-text'>音乐音量</View>
<View className='funitem-right'>
<View className='num'>{ruleForm.volume}%</View>
<Slider className="custom-color" min={0} max={100} size={4} onChange={(e) => handleChange(e, 'volume')} value={ruleForm.volume} >
<Slider.Thumb>
<View className="custom-thumb"></View>
</Slider.Thumb>
</Slider>
</View>
</View>
</View>
@ -70,40 +169,36 @@ export default function Index() {
<View className='funitem'>
<View className='funitem-text'>话筒音量</View>
<View className='funitem-right'>
<View className='num'>50%</View>
<Slider className="custom-color" size={4} defaultValue={50} />
</View>
</View>
</View>
<View className='card'>
<View className='funitem'>
<View className='funitem-text'>话筒音量</View>
<View className='funitem-right'>
<View className='num'>50%</View>
<Slider className="custom-color" size={4} defaultValue={50} />
<View className='num'>{ruleForm.music}%</View>
<Slider className="custom-color" min={0} max={100} size={4} onChange={(e) => handleChange(e, 'music')} value={ruleForm.music} >
<Slider.Thumb>
<View className="custom-thumb"></View>
</Slider.Thumb>
</Slider>
</View>
</View>
<View className='funitem'>
<View className='funitem-text'>话筒混响音量</View>
<View className='funitem-right'>
<View className='num'>50%</View>
<Slider className="custom-color" size={4} defaultValue={50} />
<View className='num'>{ruleForm.microphoneReverberation}%</View>
<Slider className="custom-color" min={0} max={32} size={4} onChange={(e) => handleChange(e, 'microphoneReverberation')} value={ruleForm.microphoneReverberation} >
<Slider.Thumb>
<View className="custom-thumb"></View>
</Slider.Thumb>
</Slider>
</View>
</View>
<View className='funitem'>
<View className='funitem-text'>话筒混响模式</View>
<View className='numlist'>
<View className='numlist-num active'>1</View>
<View className='numlist-num'>2</View>
<View className='numlist-num'>3</View>
<View className='numlist-num'>4</View>
<View className='numlist-num'>5</View>
<View className='numlist-num'>6</View>
{[1, 2, 3, 4, 5, 6].map(item => {
return <View className={`numlist-num ${ruleForm.reverb == item ? 'active' : ''} `} key={item} onClick={() => handleChange(item, 'reverb')}>{item}</View>
})}
</View>
</View>
</View>
<View className='btns'>
<View className='btn-item'>
<View className='btn-item' onClick={toPage}>
<Image src={game} className='img' />
GAME
</View>

View File

@ -144,6 +144,17 @@
background-size: 46rpx 39rpx;
}
.play-pause {
width: 246rpx;
height: 246rpx;
background: url('../../assets/pause.png') no-repeat;
background-size: 246rpx 246rpx;
&:active {
transform: scale(0.95);
}
}
.play-play {
width: 246rpx;
height: 246rpx;
@ -310,3 +321,10 @@
.custom-color {
--slider-active-background-color: #5A8FFA;
}
.custom-thumb {
width: 60rpx;
height: 60rpx;
background: url('../../assets/sliding.png') no-repeat;
background-size: 60rpx 60rpx;
}

View File

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "首页",
});

View File

@ -1,7 +1,5 @@
import Taro from "@tarojs/taro";
import { handshake1, handshake2 } from "./sendOrder";
import useStore from "@/store/index";
import { aes128Decrypt } from "@/utils/index";
import TASK from "./taskQueue";
const errMsg = {
@ -23,9 +21,13 @@ const errMsg = {
class Bluetooth {
config = {
serviceId: "4E31BF4A-8507-3A2B-7344-C7EDACD38104", //设备服务id
NotifyUUID: "4E31BF4B-8507-3A2B-7344-C7EDACD38104",
WriteUUID: "4E31BF4C-8507-3A2B-7344-C7EDACD38104",
// serviceId: "4E31BF4A-8507-3A2B-7344-C7EDACD38104", //设备服务id
// NotifyUUID: "4E31BF4B-8507-3A2B-7344-C7EDACD38104",
// WriteUUID: "4E31BF4C-8507-3A2B-7344-C7EDACD38104",
serviceId: 'C7E6FAE0-E966-1000-8000-BEF9C723DF6A', //设备服务id
NotifyUUID: 'C7E6FAE1-E966-1000-8000-BEF9C723DF6A',
WriteUUID: 'C7E6FAE2-E966-1000-8000-BEF9C723DF6A',
};
// 连接状态
@ -43,17 +45,11 @@ class Bluetooth {
platform = Taro.getSystemInfoSync().platform;
appAuthorize = Taro.getAppAuthorizeSetting();
deviceInfo = {};
deviceInfo = Taro.getStorageSync('deviceInfo') || {}
callBack = () => { };
searchBack = () => { };
constructor() {
// if (this.platform == "android") {
// this.deviceInfo = { deviceId: "50:C0:F0:F2:99:5B", mac: "50:C0:F0:F2:99:5B", name: "W53A", state: false };
// } else {
// this.deviceInfo = { deviceId: "", mac: "50:C0:F0:C8:CC:88", name: "W53A", state: false };
// // this.deviceInfo = { deviceId: "A890AB3C-0BC3-1418-1132-CA27514B147B", mac: "50:C0:F0:F2:99:5B", name: "W53A", state: false };
// }
this.onBluetoothAdapterStateChange();
this.onBLEConnectionStateChange();
this.onBluetoothDeviceFound();
@ -140,7 +136,7 @@ class Bluetooth {
// 监听搜索到新设备的事件
// 定义一个方法用于处理蓝牙设备发现事件
onBluetoothDeviceFound() {
onBluetoothDeviceFound(fn) {
Taro.onBluetoothDeviceFound((res) => {
const devices = res.devices[0];
const advertisData = this.ab2hex(devices.advertisData);
@ -148,17 +144,18 @@ class Bluetooth {
// 判断是否有搜索到设备
this.isFindBt && this.clearTimeoutFn("isFindBt");
if (devices.name && devices.name == "LE-AB2020") {
if (devices.name && devices.name == "W53A") {
// if (devices.name && devices.name == "LE-AB2020") {
const item = {
deviceId: devices.deviceId,
mac: mac,
name: devices.name,
};
console.log(JSON.stringify(item), "搜索到设备");
this.deviceInfo = { ...this.deviceInfo, ...item }
this.stopBluetoothDevicesDiscovery();
this.createBleConnection();
// this.deviceInfo = { ...this.deviceInfo, ...item }
// this.stopBluetoothDevicesDiscovery();
// this.createBleConnection();
fn && fn(item)
}
});
}
@ -201,7 +198,6 @@ class Bluetooth {
deviceId: this.deviceInfo.deviceId,
success: (res) => {
console.log(JSON.stringify(res), 'JSON.stringify(res)');
this.getBLEDeviceCharacteristics();
},
fail: (err) => this.fail(err),
@ -228,6 +224,7 @@ class Bluetooth {
state: true,
success: (res) => {
console.log("连接成功");
Taro.setStorageSync("deviceInfo", this.deviceInfo);
handshake1()
this.callBack(this.deviceInfo);
},
@ -262,9 +259,6 @@ class Bluetooth {
characteristicId: this.config.WriteUUID,
writeType: "writeNoResponse",
value: value,
success(res) {
console.log('writeBLECharacteristicValue success', JSON.stringify(res));
}
});
}
@ -316,6 +310,11 @@ class Bluetooth {
});
return hexArr.join("").toLocaleLowerCase();
}
unBindDevice() {
this.deviceInfo = {}
wx.removeStorageSync('deviceInfo')
this.closeBluetoothAdapter()
}
/**
* 字符串插入字符
* @param {*} str 字符串

View File

@ -1,7 +1,5 @@
import Taro from "@tarojs/taro";
import { useEffect, useRef, useState, useCallback } from "react";
import CryptoJS from "crypto-js";
import useStore from "@/store/index";
/**
*
@ -69,3 +67,15 @@ export const debounce = (fn, time = 300) => {
}, time);
};
}
/**
* 获取页面的占
* @param {*} len
* @returns
*/
export function getCurrentPages(len = 1) {
const pages = Taro.getCurrentPages();
const current = pages[pages.length - len];
const eventChannel = current.getOpenerEventChannel();
return eventChannel;
}

View File

@ -61,12 +61,6 @@ export function asyncDate() {
// -----------------获取---------------------
export function getInitData() {
// 话筒音量
TASK.addTask(strInsert(`7B05EA05B100`));
// 音乐音量
TASK.addTask(strInsert(`7B05EA06B100`));
// 音源设置
TASK.addTask(strInsert(`7B05EA07B100`));
@ -76,22 +70,24 @@ export function getInitData() {
// 声卡开关
TASK.addTask(strInsert(`7B05EA09B100`));
// 播放模式
// 播放模式 (音乐模式)
TASK.addTask(strInsert(`7B05EA0AB100`));
// 音乐控制
TASK.addTask(strInsert(`7B05EA0BB100`));
// 超低音强度
TASK.addTask(strInsert(`7B05EA0CB100`));
// 混响模式
TASK.addTask(strInsert(`7B05EA0DB100`));
// 音乐音量
TASK.addTask(strInsert(`7B05EA06B100`));
// 话筒混响
// 话筒音量
TASK.addTask(strInsert(`7B05EA05B100`));
// 话筒混响音量
TASK.addTask(strInsert(`7B05EA0EB100`));
// AI
TASK.addTask(strInsert(`7B05EA11B100`));
// 话筒混响模式
TASK.addTask(strInsert(`7B05EA0DB100`));
}

View File

@ -0,0 +1,38 @@
import BLESDK from './ble'
class taskQueue {
list = []
isExecute = false
overtime = null
addTask(buffer) {
if (!BLESDK.deviceInfo.state) return
this.list.push(buffer)
if (this.isExecute) return
this.executeTask()
}
executeTask() {
this.isExecute = !!this.list.length
if (!this.list.length) return
if (!BLESDK.deviceInfo.state) {
this.list = []
this.isExecute = !!this.list.length
return
}
BLESDK.writeBleValue(new Uint8Array([...this.list[0]]).buffer)
this.list.shift()
this.overtime = setTimeout(() => {
this.stopOverTime()
this.executeTask()
}, 800)
}
stopOverTime() {
clearTimeout(this.overtime)
this.overtime = null
}
}
export default new taskQueue()