Commit 72d04d62 by 姜雷

修改测试环境地址

parents 3aca39eb e72c7a08
import { baseFetch, ResponseDataEntity } from './index';
import { ResponseDataEntity, smaproFetch } from './index';
export type Area = {
id: number;
......@@ -7,6 +7,6 @@ export type Area = {
};
export const fetchAllArea = (): Promise<ResponseDataEntity<Area[]>> =>
baseFetch({
url: '/area/queryAccessAreaList',
smaproFetch({
url: '/smpro/areaConfigs',
});
import { ResponseDataEntity, smaproFetch } from './index';
export enum ServiceTypeParams {
wechatPublicV = 1,
wechatAppV = 2,
aliPublicV = 3,
aliAppV = 4,
}
export type ServiceParams = {
areaId: number;
type: ServiceTypeParams;
};
export type Service = {
serviceId: number;
serviceName: string;
};
export const fetchAreaService = (
data: ServiceParams,
): Promise<ResponseDataEntity<Service[]>> =>
smaproFetch({
url: `/smpro/areaServiceConfigs/${data.areaId}/${data.type}`,
});
......@@ -7,6 +7,8 @@ import {
LogoutCode,
SuccessCode,
OLD_BASE_SERVER_URL,
SHOWER_APP_URL,
SMPRO_URL,
} from '../constants/index';
export type ResponseDataEntity<T> = {
......@@ -35,22 +37,24 @@ const createFetch = (basePath: string) => {
reqSource: 'wxmini',
},
url: basePath + entity.url,
}).then(({ data }: ResponseEntity) => {
if (data.code === SuccessCode) {
return data;
}
if (data.code === LogoutCode) {
Taro.redirectTo({
url: '/pages/Login/Login',
}).then(
({ data }: ResponseEntity): ResponseDataEntity<any> => {
if (data.code === SuccessCode) {
return data;
}
if (data.code === LogoutCode) {
Taro.redirectTo({
url: '/pages/Login/Login',
});
throw data;
}
Taro.showToast({
title: data.msg || '网络错误',
icon: 'none',
});
throw data;
}
Taro.showToast({
title: data.msg || '网络错误',
icon: 'none',
});
throw data;
});
},
);
};
};
......@@ -58,5 +62,7 @@ export const baseFetch = createFetch(BASE_SERVER_URL);
export const oldBaseFetch = createFetch(OLD_BASE_SERVER_URL);
export const customerFetch = createFetch(CUSTOMER_SERVER_URL);
export const schoolMainFetch = createFetch(SCHOOL_MAIN_URL);
export const showerFetch = createFetch(SHOWER_APP_URL);
export const smaproFetch = createFetch(SMPRO_URL);
export default createFetch;
import { showerFetch } from './index';
type ShowerParams = {
deviceCode: string;
customerId: string;
campusId: number;
};
export type DeviceInfoResponse = {
code: string;
isOnlyBluetooth: number;
position: string;
};
/**
* 通过设备码获取设备信息
*/
export const fetchShowerInfo = (params: ShowerParams) =>
showerFetch({
url: `/dcxy/api/shower/devices/${params.deviceCode}`,
data: params,
});
type UsingParams = {
customerId: number;
};
/**
* 通过用户查询在使用的设备信息
*/
export const fetchUsingShowerInfo = (params: UsingParams) =>
showerFetch({
url: '/dcxy/api/shower/devices/inuseByCurrentUser',
data: params,
});
type StartParams = {
deviceCode: string;
customerId: string;
customerName: string;
customerPhone: string;
};
/**
* 开启设备使用
*/
export const startShowerEquipment = (params: StartParams) =>
showerFetch({
url: `/dcxy/api/shower/devices/${params.deviceCode}/beginning`,
method: 'POST',
data: params,
});
import Taro from '@tarojs/taro';
export const connectSocket = (url: string) =>
Taro.connectSocket({
url: url,
});
// .then(task => {
// task.onOpen(function() {
// console.log('onOpen');
// task.send({ data: 'xxx' });
// });
// task.onMessage(function(msg) {
// console.log('onMessage: ', msg);
// task.close({
// code: 1000,
// });
// });
// task.onError(function() {
// console.log('onError');
// });
// task.onClose(function(e) {
// console.log('onClose: ', e);
// });
// })
// .catch(err => {
// console.error(err);
// });
......@@ -10,9 +10,9 @@ import './app.scss';
// 如果需要在 h5 环境中开启 React Devtools
// 取消以下注释:
if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5') {
require('nerv-devtools');
}
// if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5') {
// require('nerv-devtools');
// }
class App extends Component {
/**
......@@ -39,6 +39,7 @@ class App extends Component {
'pages/SelectCampus/SelectCampus',
'pages/Content/Content',
'pages/WebPage/WebPage',
'pages/Shower/Shower',
],
window: {
backgroundTextStyle: 'light',
......
......@@ -11,3 +11,6 @@ export const CUSTOMER_SERVER_URL =
export const SCHOOL_MAIN_URL =
'https://internal-test-school-home-bg.168cad.top';
export const ANN_LINK_URL = 'https://ex-test-wx.168cad.top/announcement/';
export const SHOWER_APP_URL = 'https://in-test-shower-app-server.168cad.top';
export const SOCKET_URL = 'wss://in-test-shower-hardware-server.168cad.top/ws';
export const SMPRO_URL = 'https://ex-test-dcxy-smapro-app.168cad.top';
......@@ -118,12 +118,18 @@
width: 40px;
height: 20px;
}
.Home-HairDryer {
.Home-Item {
position: relative;
height: 192px;
margin-top: 68px;
display: flex;
align-items: center;
}
.Home-Item-arrow {
width: 15px;
height: 23px;
}
.Home-HairDryer {
justify-content: flex-end;
.Home-HairDryer-shadow {
position: absolute;
......@@ -139,10 +145,23 @@
margin-right: 50px;
margin-top: 20px;
}
.Home-HairDryer-arrow {
.Home-Item-arrow {
margin-left: 10px;
}
}
.Home-Shower {
margin-top: 40px;
.bg {
height: 225px;
transform: scale(1.1);
}
.Home-Shower-text {
color: #fff;
font-size: 32px;
margin-left: 50px;
}
.Home-Item-arrow {
margin-left: 10px;
width: 15px;
height: 23px;
}
}
.Home-Announcement {
......
......@@ -13,6 +13,7 @@ import HBeanIcon from '../../images/home/icon_chuifengdou@2x.png';
import TBeanIcon from '../../images/home/icon_tongyongdou@2x.png';
import UserHeaderM from '../../images/home/img_boy_touxiang@2x.png';
import UserHeaderF from '../../images/home/img_girl_touxiang@2x.png';
import ShowerIcon from '../../images/home/ic_linyu@2x.png';
import './Home.scss';
import { connect } from '@tarojs/redux';
......@@ -26,6 +27,7 @@ import { fetchAnn, SectionItem } from '../../api/announcement';
import { appLogout } from '../../api/customer';
import { Customer } from '@/types/Customer/Customer';
import { shareHandle } from '@/common/shareMethod';
import { fetchAreaService, ServiceTypeParams, Service } from '@/api/home';
type PageStateProps = {
userinfo: Customer;
......@@ -39,6 +41,7 @@ type PageState = {
commBean: number;
hairDryerBean: number;
annItem: SectionItem;
serviceList: Service[];
};
type IProps = PageStateProps & PageDispatchProps;
......@@ -63,6 +66,7 @@ class Home extends Component {
barMenuVisiable: false,
commBean: 0.0,
hairDryerBean: 0.0,
serviceList: [],
annItem: {
id: 0,
styleType: '',
......@@ -89,6 +93,7 @@ class Home extends Component {
}
getInitData() {
this.getBeanCountData();
this.getServiceList();
const { userinfo } = this.props;
fetchAnn({
campusId: userinfo.areaId,
......@@ -105,6 +110,21 @@ class Home extends Component {
console.error(err);
});
}
getServiceList() {
const { userinfo } = this.props;
if (userinfo.areaId) {
fetchAreaService({
areaId: userinfo.areaId,
type: ServiceTypeParams.wechatAppV,
}).then(res => {
this.setState({
serviceList: res.data,
});
});
}
}
getBeanCountData() {
const { userinfo } = this.props;
fetchBeanCount({
......@@ -156,6 +176,12 @@ class Home extends Component {
});
}
goShower() {
Taro.navigateTo({
url: '/pages/Shower/Shower',
});
}
toggleBarMenu() {
this.setState(({ barMenuVisiable }: PageState) => ({
barMenuVisiable: !barMenuVisiable,
......@@ -184,7 +210,13 @@ class Home extends Component {
}
render() {
const { userinfo } = this.props;
const { commBean, hairDryerBean, annItem, barMenuVisiable } = this.state;
const {
commBean,
hairDryerBean,
annItem,
barMenuVisiable,
serviceList,
} = this.state;
return (
<View className='Home'>
{barMenuVisiable ? (
......@@ -251,14 +283,52 @@ class Home extends Component {
</View>
</View>
</View>
<View className='Home-HairDryer' onClick={this.goBarCode}>
<Image className='bg' src={HairDryerBg} />
<View className='Home-HairDryer-shadow' />
<View className='Home-HairDryer-text'>
吹风
<Image className='Home-HairDryer-arrow' src={HairDryerArr} />
</View>
</View>
{serviceList.map(service =>
service.serviceId === 4 || service.serviceId === 11 ? (
// 自助吹风
<View
key={service.serviceId}
className='Home-Item Home-HairDryer'
onClick={this.goBarCode}>
<Image className='bg' src={HairDryerBg} />
<View className='Home-HairDryer-shadow' />
<View className='Home-HairDryer-text'>
吹风
<Image className='Home-Item-arrow' src={HairDryerArr} />
</View>
</View>
) : service.serviceId === 10 || service.serviceId === 5 ? (
// 自助吹风
<View
key={service.serviceId}
className='Home-Item Home-Shower'
onClick={this.goShower}>
<Image className='bg' src={ShowerIcon} />
<View className='Home-Shower-shadow' />
<View className='Home-Shower-text'>
洗浴
<Image className='Home-Item-arrow' src={HairDryerArr} />
</View>
</View>
) : service.serviceId === 3 || service.serviceId === 11 ? (
// 自助饮水
<View
key={service.serviceId}
className='Home-Item Home-Water'
onClick={this.goBarCode}>
<Image className='bg' src={HairDryerBg} />
<View className='Home-Water-shadow' />
<View className='Home-Water-text'>
饮水
<Image className='Home-Item-arrow' src={HairDryerArr} />
</View>
</View>
) : service.serviceId === 9 ? (
// 壁挂饮水
<View key={service.serviceId} />
) : null,
)}
{annItem.id ? (
<View className='Home-Announcement'>
<Image className='bg' src={AnnouncementBg} />
......
.Shower {
padding-top: 126px;
.equipment-info-box {
width: 630px;
height: 572px;
margin: 0 auto;
border-radius: 176px;
border: 2px solid #dfdfdf;
background-color: #f1f1f1;
}
.equipment-info {
width: 610px;
height: 552px;
border-radius: 176px;
margin: 10px auto 0;
background-color: #fff;
overflow: hidden;
.equipment-title {
margin-top: 114px;
font-size: 44px;
text-align: center;
&.matched {
color: #6180f4;
}
}
.equipment-line {
display: block;
width: 460px;
height: 8px;
margin: 46px auto 0;
}
.equipment-noCode {
margin-top: 108px;
text-align: center;
font-size: 32px;
color: #666;
}
.equipment-list {
margin-top: 64px;
}
.equipment-item {
display: flex;
margin-bottom: 20px;
align-items: center;
font-size: 32px;
.equipment-label {
margin-left: 110px;
}
.equipment-value {
width: 260px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
.btn-box {
margin: 72px auto 0;
width: 534px;
display: flex;
justify-content: space-between;
align-items: center;
.shower-scan-btn {
width: 116px;
height: 116px;
border-radius: 50%;
&:active {
box-shadow: #ddd 0 0 40px;
}
}
.shower-start-btn {
width: 276px;
height: 128px;
border-radius: 50px;
&:active {
box-shadow: #ddd 0 0 40px;
}
}
}
}
import './Shower.scss';
import Taro, { Component, Config } from '@tarojs/taro';
import { View, Image, Text } from '@tarojs/components';
import ShowerStart from '../../images/shower/ic_sel@2x.png';
import ShowerCantStart from '../../images/shower/ic_nor@2x.png';
import LineImg from '../../images/shower/img_nor@2x.png';
import ScanIcon from '../../images/shower/ic_saoma@2x.png';
import { shareHandle } from '@/common/shareMethod';
import {
fetchShowerInfo,
DeviceInfoResponse,
startShowerEquipment,
fetchUsingShowerInfo,
} from '@/api/shower';
import { connect } from '@tarojs/redux';
import { Customer } from '@/types/Customer/Customer';
import { ComponentClass } from 'react';
import { ResponseDataEntity } from '@/api';
import { connectSocket } from '@/api/socket';
import { SOCKET_URL } from '@/constants';
import { BluetoothDevice } from '@/types/Shower/Shower';
import { updateBluetoothDevice } from './actions';
import { ab2str, str2ab } from '@/utils/arrayBuffer';
type DeviceInfo = {
deviceId: string;
uuid: string;
isPrimary: boolean;
serviceId: string;
notifyId: string;
writeId: string;
readId: string;
};
type PageStateProps = {
userinfo: Customer;
bluetoothDevice: BluetoothDevice;
};
type PageDispatchProps = {
updateBluetoothDevice: (entity: BluetoothDevice) => void;
};
type IProps = PageStateProps & PageDispatchProps;
type PageState = {
bluetoothState: boolean;
task: Taro.SocketTask | null;
timer: number | undefined;
reConnectting: boolean;
deviceInfo: DeviceInfo;
sockedDone: boolean;
deviceDone: boolean;
showerState: boolean;
};
const StopCode = 1000;
interface Shower {
props: IProps;
state: PageState;
}
@connect(
({ userinfo, Shower }) => ({
userinfo,
bluetoothDevice: Shower,
}),
dispatch => ({
updateBluetoothDevice(data: BluetoothDevice) {
dispatch(updateBluetoothDevice(data));
},
}),
)
class Shower extends Component {
config: Config = {
navigationBarTitleText: '洗 浴',
};
constructor(props) {
super(props);
this.state = {
bluetoothState: false,
task: null,
timer: undefined,
reConnectting: false,
sockedDone: false,
deviceDone: false,
showerState: false,
deviceInfo: {
deviceId: '',
uuid: '',
isPrimary: false,
serviceId: '',
notifyId: '',
writeId: '',
readId: '',
},
};
}
onShareAppMessage = shareHandle;
componentWillMount() {
this.openBluetooth();
this.connectDeviceSocket();
this.checkUsingDevice();
}
componentWillUnmount() {
this.closeBluetooth();
this.closeDeviceSocket();
}
connectDeviceSocket() {
connectSocket(SOCKET_URL).then(task => {
task.onOpen(() => {
console.log('onOpen');
const { reConnectting } = this.state;
if (reConnectting) {
this.reConnectDeviceSocket(true);
}
this.setState({
task: task,
sockedDone: true,
});
task.send({ data: str2ab('{}') });
this.sendDeviceCode();
});
task.onMessage(res => {
const msg: string = ab2str(res.data);
console.log('socket onMessage: ', msg);
if (msg === '[0]') {
console.log('结束蓝牙以及socket: ', msg);
this.closeDeviceSocket();
this.closeBluetoothConnection();
} else if (msg === '[]') {
} else {
if (msg.length > 100) {
this.sendMessageToDevice('[]');
} else if (msg.length > 20) {
for (let index = 0; index <= Math.floor(msg.length / 20); index++) {
let str = msg.substring(index * 20, (index + 1) * 20);
this.sendMessageToDevice(str);
}
} else {
if (msg) {
this.sendMessageToDevice(msg);
}
}
}
});
task.onClose(e => {
console.log('socked关闭', e);
this.setState({
task: null,
sockedDone: false,
});
if (e.code === StopCode) {
console.log('正确结束socket连接');
} else {
this.reConnectDeviceSocket(false);
}
});
});
}
reConnectDeviceSocket(cancel: boolean) {
const { timer, reConnectting } = this.state;
if (cancel) {
clearTimeout(timer);
this.setState({
timer: null,
reConnectting: false,
});
return;
}
console.log(reConnectting, timer);
if (reConnectting) {
this.connectDeviceSocket();
} else if (timer) {
clearTimeout(timer);
this.setState({
timer: null,
reConnectting: false,
});
console.log('请保证网络正常');
Taro.showModal({
title: '警告',
content: '请保持网络畅通正常',
});
} else {
let newTimer = setTimeout(() => {
this.setState({
reConnectting: false,
});
}, 10000);
console.log(reConnectting, timer);
this.setState({
timer: newTimer,
reConnectting: true,
});
this.connectDeviceSocket();
}
}
sendDeviceCode() {
const { task, sockedDone, deviceDone } = this.state;
const { bluetoothDevice } = this.props;
console.log('socket状态:', sockedDone, '蓝牙状态:', deviceDone);
if (sockedDone && task && deviceDone) {
let deviceData = '{<' + bluetoothDevice.code + '>}';
console.log('发送设备编号:', deviceData);
task.send({
data: str2ab(deviceData),
});
}
}
closeDeviceSocket() {
const { task } = this.state;
console.log('in close', task);
if (task) {
task.close({
code: StopCode,
complete: () => {
this.setState({
task: null,
});
},
});
}
}
checkUsingDevice() {
const { userinfo, updateBluetoothDevice } = this.props;
fetchUsingShowerInfo({
customerId: userinfo.customerId,
})
.then(res => {
const data: DeviceInfoResponse | null = res.data;
if (data) {
updateBluetoothDevice(data);
this.setState({
showerState: true,
});
if (this.checkBluetoothState()) {
this.startUseShower(true);
} else if (data.isOnlyBluetooth) {
this.warnBluetoothOpen();
} else {
this.startUseShower(true);
}
}
})
.catch(err => {
console.error(err);
});
}
openBluetooth() {
Taro.openBluetoothAdapter()
.then(res => {
console.log(res);
this.setState({
bluetoothState: true,
});
})
.catch(err => {
console.error(err);
Taro.onBluetoothAdapterStateChange(res => {
console.log('adapterState changed, now is', res);
if (res.available) {
this.setState({
bluetoothState: true,
});
}
});
});
}
checkBluetoothState() {
const { bluetoothState } = this.state;
return bluetoothState;
}
closeBluetoothConnection() {
const { deviceInfo } = this.state;
this.setState({
showerState: false,
});
Taro.closeBLEConnection({
deviceId: deviceInfo.deviceId,
})
.then(() => {
this.setState({
deviceDone: false,
});
})
.catch(err => {
console.log('断开蓝牙连接失败!');
console.error(err);
});
}
closeBluetooth() {
Taro.closeBluetoothAdapter();
}
warnBluetoothOpen() {
Taro.showModal({
title: '警告',
content: '为保障正常使用,请打开蓝牙功能',
});
}
scanEquipment() {
return Taro.scanCode({
onlyFromCamera: true,
scanType: ['qrCode'],
})
.then(res => {
console.log(res);
const { result } = res;
const { userinfo, updateBluetoothDevice } = this.props;
return fetchShowerInfo({
deviceCode: result,
customerId: userinfo.customerId.toString(),
campusId: userinfo.areaId,
})
.then((res: ResponseDataEntity<DeviceInfoResponse>) => {
const data = res.data;
updateBluetoothDevice({
code: data.code,
isOnlyBluetooth: data.isOnlyBluetooth,
position: data.position,
});
})
.catch(err => {
console.error(err);
Taro.showToast({
title: err.msg || '请扫描正确的设备码',
icon: 'none',
});
});
})
.catch(err => {
console.error(err);
// Taro.showToast({
// title: err.msg || '呼起扫码失败!',
// icon: 'none',
// });
});
}
startDevicesDiscovery() {
if (this.checkBluetoothState()) {
return Taro.startBluetoothDevicesDiscovery()
.then(() => {
const { code, isOnlyBluetooth } = this.props.bluetoothDevice;
let timer: number | null = null;
return new Promise(resolve => {
if (isOnlyBluetooth) {
timer = setTimeout(() => {
Taro.stopBluetoothDevicesDiscovery();
}, 10000);
} else {
timer = setTimeout(() => {
Taro.stopBluetoothDevicesDiscovery();
}, 5000);
}
Taro.onBluetoothDeviceFound(res => {
const devices = res.devices;
if (devices[0].name === code) {
let deviceId = devices[0].deviceId;
Taro.stopBluetoothDevicesDiscovery();
this.setState({
deviceId,
});
if (timer) {
clearInterval(timer);
}
resolve(deviceId);
}
});
});
})
.catch(err => {
// Taro.stopBluetoothDevicesDiscovery();
Taro.hideLoading();
console.error('startBluetoothDevicesDiscovery: ', err);
this.warnBluetoothOpen();
});
} else {
Taro.hideLoading();
this.warnBluetoothOpen();
throw '未开启蓝牙';
}
}
createConnection(deviceId: string) {
console.log(deviceId);
return new Promise((resolve, reject) => {
Taro.createBLEConnection({
deviceId,
});
let abStr = '';
Taro.onBLECharacteristicValueChange(res => {
console.log(
`characteristic ${res.characteristicId} has changed, now is ${
res.value
}`,
);
console.log(res.value);
let datastr = ab2str(res.value);
console.log('获取socket消息: ', datastr);
if (datastr === '<>') {
console.log('结束蓝牙以及socket: ', datastr);
this.closeDeviceSocket();
this.closeBluetoothConnection();
} else {
const { task } = this.state;
if (
datastr.substring(0, 1) === '{' &&
datastr.substring(datastr.length - 1, datastr.length) === '}'
) {
console.log('发送完整数据: ', datastr);
if (task) {
task.send({
data: str2ab(datastr),
});
}
} else if (datastr.substring(0, 1) === '{') {
console.log('接受头部数据: ', datastr);
abStr = datastr;
} else if (
abStr.length &&
datastr.substring(datastr.length - 1, datastr.length) === '}'
) {
abStr += datastr;
console.log('接受尾部数据后: ', abStr);
console.log('发送完整数据: ', abStr);
if (task) {
task.send({
data: str2ab(abStr),
});
}
abStr = '';
} else {
console.log('弃掉数据:', datastr);
}
}
});
Taro.onBLEConnectionStateChange(res => {
const { showerState } = this.state;
console.log(
`device ${res.deviceId} state has changed, connected: ${
res.connected
}`,
);
if (res.connected) {
this.setState({
deviceDone: true,
showerState: true,
});
resolve(res.deviceId);
} else {
console.log(res);
this.setState({
deviceDone: false,
});
if (showerState) {
this.reConnectDeviceBluetooth();
}
reject('蓝牙未成功连接');
}
});
});
}
sendMessageToDevice(msg: string) {
const { deviceInfo } = this.state;
console.log(msg, str2ab(msg).byteLength);
if (deviceInfo.writeId) {
Taro.writeBLECharacteristicValue({
deviceId: deviceInfo.deviceId,
serviceId: deviceInfo.serviceId,
characteristicId: deviceInfo.writeId,
value: str2ab(msg),
});
}
}
reConnectDeviceBluetooth() {
if (this.checkBluetoothState()) {
const { deviceInfo } = this.state;
this.createConnection(deviceInfo.deviceId);
}
}
getDeviceServices(deviceId: string) {
return Taro.getBLEDeviceServices({
deviceId: deviceId,
}).then(services => {
return { deviceId: deviceId, services: services.services };
});
}
getDeviceCharacter({
deviceId,
serviceId,
}: {
deviceId: string;
serviceId: string;
}) {
return Taro.getBLEDeviceCharacteristics({
deviceId,
serviceId,
}).then(res => {
let notifyId = '',
writeId = '',
readId = '';
for (let i = 0; i < res.characteristics.length; i++) {
let charc = res.characteristics[i];
if (charc.properties.notify) {
notifyId = charc.uuid;
}
if (charc.properties.write) {
writeId = charc.uuid;
}
if (charc.properties.write) {
readId = charc.uuid;
}
}
return {
notifyId,
writeId,
readId,
};
});
}
openNotify({ notifyId, writeId, readId }) {
this.setState(({ deviceInfo }: PageState) => ({
deviceInfo: {
...deviceInfo,
notifyId,
writeId,
readId,
},
}));
const { deviceInfo } = this.state;
return Taro.notifyBLECharacteristicValueChange({
deviceId: deviceInfo.deviceId,
serviceId: deviceInfo.serviceId,
characteristicId: notifyId,
state: true,
}).then(res => {
console.log(res);
let abStr = '';
Taro.onBLECharacteristicValueChange(res => {
let msg = ab2str(res.value);
console.log('获取蓝牙设备消息: ', msg);
if (msg === '<>') {
this.closeBluetoothConnection();
this.closeDeviceSocket();
} else {
if (
msg.substring(0, 1) === '{' &&
msg.substring(msg.length - 1, msg.length) === '}'
) {
const { task } = this.state;
console.log('发送给socket完整数据: ', msg);
task &&
task.send({
data: str2ab(msg),
});
} else if (msg.substring(0, 1) === '{') {
console.log('接受头部数据: ', msg);
abStr = msg;
} else if (
abStr.length &&
msg.substring(msg.length - 1, msg.length) === '}'
) {
abStr += msg;
console.log('接受尾部数据后: ', abStr);
console.log('发送给socket完整数据: ', abStr);
const { task } = this.state;
task &&
task.send({
data: str2ab(abStr),
});
abStr = '';
} else {
if (abStr.length) {
abStr += msg;
} else {
console.log('弃掉数据:', msg);
}
}
}
});
});
}
startUseShower(reConnect) {
if (reConnect) {
Taro.showLoading({
title: '开启中',
mask: true,
});
}
const { sockedDone } = this.state;
if (!sockedDone) {
this.connectDeviceSocket();
}
this.startDevicesDiscovery()
.then((deviceId: string) => this.createConnection(deviceId))
.then(this.getDeviceServices)
.then(res => {
const deviceId = res.deviceId;
const services = res.services;
let service = services[services.length - 1];
const serviceId = service.uuid;
this.setState(({ deviceInfo }: PageState) => ({
deviceInfo: {
...deviceInfo,
deviceId,
serviceId,
},
}));
return this.getDeviceCharacter({
deviceId,
serviceId,
});
})
.then(res => this.openNotify(res))
.then(() => {
this.sendDeviceCode();
if (!reConnect) {
setTimeout(() => {
this.sendStartShower();
}, 2000);
}
})
.catch(err => {
console.error(err);
Taro.hideLoading();
});
}
sendStartShower() {
const { code } = this.props.bluetoothDevice;
const { userinfo } = this.props;
startShowerEquipment({
deviceCode: code,
customerId: userinfo.customerId.toString(),
customerName: userinfo.customerName,
customerPhone: userinfo.customerPhone,
})
.then(res => {
console.log(res);
Taro.showToast({
title: '开启成功!',
});
this.setState({
showerState: true,
});
})
.catch(err => {
console.error(err);
Taro.showToast({
title: err.msg || '开启失败!',
icon: 'none',
});
this.closeBluetoothConnection();
});
}
render() {
const {
bluetoothDevice: { code, position },
} = this.props;
const { showerState } = this.state;
return (
<View className='Shower'>
<View className='equipment-info-box'>
<View className='equipment-info'>
{code ? (
<View className='equipment-title matched'>已匹配设备</View>
) : (
<View className='equipment-title'>未匹配设备</View>
)}
<Image className='equipment-line' src={LineImg} />
{code ? (
<View className='equipment-list'>
<View className='equipment-item'>
<Text className='equipment-label'>设备编号:</Text>
<Text className='equipment-value'>{code}</Text>
</View>
<View className='equipment-item'>
<Text className='equipment-label'>设备位置:</Text>
<Text className='equipment-value'>{position}</Text>
</View>
</View>
) : (
<View v-loading='loading' className='equipment-noCode'>
点击左下角扫一扫完成匹配
</View>
)}
</View>
</View>
<View className='btn-box'>
<Image
className='shower-scan-btn'
src={ScanIcon}
onClick={this.scanEquipment}
/>
{code && !showerState ? (
<Image
className='shower-start-btn'
src={ShowerStart}
onClick={() => this.startUseShower(false)}
/>
) : (
<Image className='shower-start-btn' src={ShowerCantStart} />
)}
</View>
</View>
);
}
}
export default Shower as ComponentClass<PageStateProps, PageState>;
import Actions from '@/types/Store/Actions';
import { BluetoothDevice } from '@/types/Shower/Shower';
export const UPDATE_BLUETOOTH_DEVICE = 'UPDATE_BLUETOOTH_DEVICE';
export const UPDATE_PAY_LIST = 'UPDATE_PAY_LIST';
export const UPDATE_ALL_LIST = 'UPDATE_ALL_LIST';
export type UpdateOrderParams<T> = {
lastOrderId?: number;
list: T[];
};
export const updateBluetoothDevice = (state: BluetoothDevice): Actions => ({
type: UPDATE_BLUETOOTH_DEVICE,
payload: state,
});
import Actions from '@/types/Store/Actions';
import { BluetoothDevice } from '@/types/Shower/Shower';
import { UPDATE_BLUETOOTH_DEVICE } from './actions';
import Taro from '@tarojs/taro';
const storeKey = 'DeviceInfo';
let INITIAL_STATE = {
code: '',
isOnlyBluetooth: undefined,
position: '',
};
try {
var value = Taro.getStorageSync(storeKey);
if (value) {
INITIAL_STATE = value;
}
} catch (e) {
console.error(e);
}
export default function ShowerReducer(
state: StoreState<BluetoothDevice> = INITIAL_STATE,
actions: Actions,
) {
switch (actions.type) {
case UPDATE_BLUETOOTH_DEVICE:
Taro.setStorage({
key: storeKey,
data: actions.payload,
});
return {
...state,
...actions.payload,
};
default:
return state;
}
}
import { combineReducers } from 'redux';
import userinfo from './rootReducers/userinfo';
import OrderList from '../pages/Order/OrderList/store';
import ShowerReducer from '@/pages/Shower/store';
export default combineReducers({
userinfo,
OrderList,
Shower: ShowerReducer,
});
export type BluetoothDevice = {
code: string;
isOnlyBluetooth: number;
position: string;
};
export const ab2str = (buf: ArrayBuffer): string => {
return String.fromCharCode.apply(null, new Int8Array(buf));
};
export const str2ab = (str: string): ArrayBuffer => {
var buf = new ArrayBuffer(str.length);
var bufView = new Int8Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment