Commit e77fcdb1 by 姜雷

添加洗浴

parent e0487a8f
......@@ -3,3 +3,4 @@ export const LogoutCode = -2;
export const NotRegisterCode = 1005;
export const BASE_SERVER_URL = 'https://ex-dev-dcxy-smapro-app.168cad.top';
export const SOCKET_URL = 'wss://dev-shower-wss1.168cad.top:9443/ws';
......@@ -12,7 +12,23 @@ import ECBmode from 'crypto-js/mode-ecb';
import PaddingPkcs7 from 'crypto-js/pad-pkcs7';
// import { paySuccess } from '../../api/Order/paySuccess';
import './pay.scss';
import { SOCKET_URL } from '@/constants';
import { str2ab, ab2str } from '@/utils/arrayBuffer';
enum BlueToothError {
BlueToothNotOpen = 'BlueToothNotOpen',
DeviceNotFound = 'DeviceNotFound',
}
type DeviceInfo = {
deviceId: string;
uuid: string;
isPrimary: boolean;
serviceId: string;
notifyId: string;
writeId: string;
readId: string;
};
type PageStateProps = {
device: Device;
prepayConfig: PrepayConfig[];
......@@ -23,6 +39,11 @@ type PageDispatchProps = {};
type PageState = {
payId: undefined | number;
bluetoothState: boolean;
deviceInfo: DeviceInfo;
sockedDone: boolean;
deviceDone: boolean;
showerState: boolean;
};
type Iprop = PageStateProps & PageDispatchProps;
......@@ -31,6 +52,11 @@ interface Pay {
state: PageState;
}
const StopCode = 1000;
let timer: NodeJS.Timeout | null = null;
let reConnectting: boolean = false;
let socketTask: Taro.SocketTask | null = null;
@connect(({ device, prepayConfig, userinfo }) => ({
device,
prepayConfig,
......@@ -44,7 +70,589 @@ class Pay extends Component {
super(props);
this.state = {
payId: undefined,
bluetoothState: false,
sockedDone: false,
deviceDone: false,
showerState: false,
deviceInfo: {
deviceId: '',
uuid: '',
isPrimary: false,
serviceId: '',
notifyId: '',
writeId: '',
readId: '',
},
};
this.checkBluetoothAndWs();
}
connectDeviceSocket() {
Taro.connectSocket({ url: SOCKET_URL }).then(task => {
socketTask = task;
task.onOpen(() => {
console.log('onOpen');
if (reConnectting) {
this.reConnectDeviceSocket(true);
}
this.setState({
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, reConnectting, timer);
this.setState({
sockedDone: false,
});
socketTask = null;
if (e.code === StopCode) {
console.log('正确结束socket连接');
} else {
console.log('开始重连socket');
this.reConnectDeviceSocket(false);
}
});
});
}
reConnectDeviceSocket(cancel: boolean) {
if (cancel) {
timer && clearTimeout(timer);
timer = null;
reConnectting = false;
return;
}
console.log(reConnectting, timer);
if (reConnectting) {
this.connectDeviceSocket();
} else if (timer) {
clearTimeout(timer);
reConnectting = false;
timer = null;
console.log('请保证网络正常');
Taro.showModal({
title: '警告',
content: '请保持网络畅通正常',
});
} else {
timer = setTimeout(() => {
reConnectting = false;
}, 10000);
reConnectting = true;
console.log(reConnectting, timer);
this.connectDeviceSocket();
}
}
sendDeviceCode() {
const { sockedDone, deviceDone } = this.state;
const { device } = this.props;
console.log('socket状态:', sockedDone, '蓝牙状态:', deviceDone);
if (sockedDone && socketTask && deviceDone) {
let deviceData = '{<' + device.code + '>}';
console.log('<---发送设备编号:', deviceData);
socketTask.send({
data: str2ab(deviceData),
success: msg => {
console.log('发送设备编号:', msg, '--->');
},
fail: err => {
console.log('发送设备编号:', err, '--->');
},
});
}
}
closeDeviceSocket() {
console.log('in close', socketTask, timer);
if (socketTask) {
socketTask.close({
code: StopCode,
complete: () => {
socketTask = null;
},
});
}
if (timer) {
clearTimeout(timer);
}
}
checkIsShower(): boolean {
const { device } = this.props;
return device.serviceId === 2;
}
checkBluetoothAndWs() {
if (this.checkIsShower()) {
console.log('打开蓝牙和WebSocket');
}
}
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() {
return Taro.showModal({
title: '警告',
content: '为保障正常使用,请打开蓝牙功能',
});
}
startDevicesDiscovery() {
if (this.checkBluetoothState()) {
return Taro.startBluetoothDevicesDiscovery()
.then(() => {
const {
code,
// isOnlyBluetooth
} = this.props.device;
let timer: NodeJS.Timeout | null = null;
return new Promise((resolve, reject) => {
// if (isOnlyBluetooth) {
// timer = setTimeout(() => {
// reject({ msg: BlueToothError.DeviceNotFound });
// }, 10000);
// } else {
timer = setTimeout(() => {
reject({ msg: BlueToothError.DeviceNotFound });
}, 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();
if (timer) {
clearInterval(timer);
}
Taro.hideLoading();
console.error('startBluetoothDevicesDiscovery: ', err);
// if (err.msg === BlueToothError.DeviceNotFound) {
Taro.stopBluetoothDevicesDiscovery();
this.sendStartShower();
throw err;
// } else {
// return this.warnBluetoothOpen();
// }
});
} else {
Taro.hideLoading();
return this.warnBluetoothOpen().then(res => {
if (res.confirm) {
// const { isOnlyBluetooth } = this.props.bluetoothDevice;
// if (!isOnlyBluetooth) {
// Taro.showLoading({
// title: '开启中',
// mask: true,
// });
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// this.sendStartShower();
// reject();
// }, 5000);
// });
// }
}
throw BlueToothError.BlueToothNotOpen;
});
}
}
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 {
if (
datastr.substring(0, 1) === '{' &&
datastr.substring(datastr.length - 1, datastr.length) === '}'
) {
console.log('<---发送完整数据: ', datastr);
if (socketTask) {
socketTask.send({
data: str2ab(datastr),
success: msg => {
console.log('发送完整数据:', msg, '--->');
},
fail: err => {
console.log('发送完整数据:', err, '--->');
},
});
}
} 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 (socketTask) {
socketTask.send({
data: str2ab(abStr),
success: msg => {
console.log('发送完整数据:', msg, '--->');
},
fail: err => {
console.log('发送完整数据:', err, '--->');
},
});
}
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) === '}'
) {
console.log('<---发送给socket完整数据: ', msg);
socketTask &&
socketTask.send({
data: str2ab(msg),
success: msg => {
console.log('发送给socket完整数据:', msg, '--->');
},
fail: err => {
console.log('发送给socket完整数据:', err, '--->');
},
});
} 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);
socketTask &&
socketTask.send({
data: str2ab(abStr),
success: msg => {
console.log('发送给socket完整数据:', msg, '--->');
},
fail: err => {
console.log('发送给socket完整数据:', err, '--->');
},
});
abStr = '';
} else {
if (abStr.length) {
abStr += msg;
} else {
console.log('弃掉数据:', msg);
}
}
}
});
});
}
userWarnningHandle(thresholdPrompt, money, beanAmount) {
Taro.hideLoading();
console.log('in userWarnningHandle');
let arr = [money, beanAmount];
let i = -1;
return Taro.showModal({
title: '提示',
content: thresholdPrompt.replace(/(\{.*?\})/g, () => {
i++;
return arr[i];
}),
}).then(res => {
if (res.confirm) {
Taro.showLoading({
title: '开启中',
mask: true,
});
return Promise.resolve();
} else {
return Promise.reject();
}
});
}
startUseShower(reConnect: boolean) {
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.find(
item =>
item.uuid.toLocaleLowerCase() ===
'6e401103-b5a3-f393-e0a9-e50e24dcca9e',
);
if (!service) {
service = services[0];
}
console.log('获取全部services: ', services, '. serviceId: ', service);
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() {
console.log('开启洗浴');
}
selectPayConfig(id: number) {
......@@ -102,11 +710,7 @@ class Pay extends Component {
icon: 'success',
mask: true,
});
setTimeout(() => {
Taro.navigateTo({
url: '/pages/index/index?', // 需要问号不然回到首页可以取到业务参数
});
}, 2000);
this.gobackHandle();
});
})
.catch(err => {
......@@ -124,6 +728,17 @@ class Pay extends Component {
}
}
gobackHandle() {
if (this.checkIsShower()) {
} else {
setTimeout(() => {
Taro.navigateTo({
url: '/pages/index/index?', // 需要问号不然回到首页可以取到业务参数
});
}, 2000);
}
}
render() {
const { device, prepayConfig } = this.props;
const { payId } = this.state;
......
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;
};
......@@ -15,16 +15,14 @@
"sourceMap": true,
"baseUrl": ".",
"rootDir": ".",
"paths": {
"@/*": ["./src/*"]
},
"jsx": "preserve",
"jsxFactory": "Taro.createElement",
"allowJs": true,
"typeRoots": [
"node_modules/@types"
]
"typeRoots": ["node_modules/@types"]
},
"exclude": [
"node_modules",
"dist"
],
"exclude": ["node_modules", "dist"],
"compileOnSave": false
}
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