怎样建设网站陕西网站建设

昆山合汇富电子科技有限公司 2026/09/09 17:38:12

蓝牙页面-手动点击搜索蓝牙 然后选中某个打印机 进行手动点击打印--权限配置什么的 在上面某个都已配置了

import React, { useEffect, useState, useRef } from 'react'; import { Button, View, Alert, PermissionsAndroid, Platform, Text, ScrollView, TouchableOpacity, } from 'react-native'; import { BleManager, Device } from 'react-native-ble-plx'; import { Buffer } from 'buffer'; import iconv from 'iconv-lite'; const manager = new BleManager(); const BluetoothPrinter = ({ route }) => { const { arrearsData } = route.params || {}; console.log('打印数据:', arrearsData); const [isScanning, setIsScanning] = useState(false); const [foundDevices, setFoundDevices] = useState([]); const [isConnected, setIsConnected] = useState(false); const [currentDevice, setCurrentDevice] = useState(null); const [servicesInfo, setServicesInfo] = useState(''); const [connectionStatus, setConnectionStatus] = useState('未连接'); const [writeCharacteristics, setWriteCharacteristics] = useState([]); const [scanTimeLeft, setScanTimeLeft] = useState(0); const scanTimeoutRef = useRef(null); const scanTimerRef = useRef(null); useEffect(() => { const stateSubscription = manager.onStateChange(state => { console.log('蓝牙状态:', state); if (state === 'PoweredOn') { console.log('蓝牙已开启'); } else if (state === 'PoweredOff') { Alert.alert('提示', '请开启手机蓝牙'); setConnectionStatus('蓝牙未开启'); stopScan(); // 蓝牙关闭时停止扫描 } }, true); return () => { stateSubscription.remove(); stopScan(); // 组件卸载时停止扫描 }; }, []); // 权限请求函数 const requestBluetoothPermission = async () => { if (Platform.OS !== 'android') { return true; } try { const apiLevel = Platform.Version; let permissions = []; if (apiLevel >= 31) { permissions = [ 'android.permission.BLUETOOTH_SCAN', 'android.permission.BLUETOOTH_CONNECT', 'android.permission.ACCESS_FINE_LOCATION', ]; } else { permissions = [ 'android.permission.BLUETOOTH', 'android.permission.BLUETOOTH_ADMIN', 'android.permission.ACCESS_FINE_LOCATION', ]; } const granted = await PermissionsAndroid.requestMultiple(permissions); const allGranted = permissions.every( permission => granted[permission] === PermissionsAndroid.RESULTS.GRANTED, ); return allGranted; } catch (err) { console.warn('权限请求错误:', err); return false; } }; const scanDevices = async () => { try { const hasPermission = await requestBluetoothPermission(); if (!hasPermission) { Alert.alert('权限被拒绝', '需要蓝牙权限才能扫描设备'); return; } const state = await manager.state(); if (state !== 'PoweredOn') { Alert.alert('蓝牙未开启', '请先开启手机蓝牙'); return; } setIsScanning(true); setFoundDevices([]); setServicesInfo(''); setConnectionStatus('扫描中...'); setScanTimeLeft(15); // 设置15秒倒计时 console.log('开始扫描蓝牙设备...'); // 启动倒计时 scanTimerRef.current = setInterval(() => { setScanTimeLeft(prev => { if (prev <= 1) { clearInterval(scanTimerRef.current); return 0; } return prev - 1; }); }, 1000); // 15秒后自动停止扫描 scanTimeoutRef.current = setTimeout(() => { if (isScanning) { console.log('自动停止扫描'); stopScan(); Alert.alert( '提示', '扫描已完成,共找到 ' + foundDevices.length + ' 个设备', ); } }, 15000); manager.startDeviceScan(null, null, (error, device) => { if (error) { console.log('扫描错误:', error); stopScan(); setConnectionStatus('扫描失败'); return; } if (device && device.name) { console.log('发现设备:', device.name, '信号:', device.rssi); setFoundDevices(prev => { const exists = prev.find(d => d.id === device.id); if (!exists) { return [ ...prev, { id: device.id, name: device.name || '未知设备', localName: device.localName, rssi: device.rssi, isPrinter: isLikelyPrinter(device), }, ].sort((a, b) => b.rssi - a.rssi); } return prev; }); } }); } catch (error) { console.log('扫描失败:', error); stopScan(); setConnectionStatus('扫描失败'); } }; // 停止扫描函数 const stopScan = () => { try { manager.stopDeviceScan(); } catch (error) { console.log('停止扫描错误:', error); } setIsScanning(false); setConnectionStatus('扫描完成'); // 清除定时器 if (scanTimeoutRef.current) { clearTimeout(scanTimeoutRef.current); scanTimeoutRef.current = null; } if (scanTimerRef.current) { clearInterval(scanTimerRef.current); scanTimerRef.current = null; } setScanTimeLeft(0); }; // 判断设备是否可能是打印机 const isLikelyPrinter = device => { if (!device.name) return false; const name = device.name.toLowerCase(); const localName = device.localName?.toLowerCase() || ''; const printerKeywords = [ 'printer', 'print', 'prt', 'pos', 'receipt', 'bt', 'blue', 'thermal', '58mm', '80mm', 'tsc', 'rtk', 'u26', 'xp', 'sp', ]; return printerKeywords.some( keyword => name.includes(keyword) || localName.includes(keyword), ); }; const discoverAllServicesAndCharacteristics = async device => { try { console.log('开始发现服务和特征...'); setConnectionStatus('发现服务中...'); await device.discoverAllServicesAndCharacteristics(); const services = await device.services(); console.log('发现的服务数量:', services.length); const allWriteCharacteristics = []; for (const service of services) { try { const characteristics = await device.characteristicsForService( service.uuid, ); for (const char of characteristics) { // 收集所有可写特征 if (char.isWritableWithResponse || char.isWritableWithoutResponse) { allWriteCharacteristics.push({ serviceUUID: service.uuid, characteristicUUID: char.uuid, isWritableWithResponse: char.isWritableWithResponse, isWritableWithoutResponse: char.isWritableWithoutResponse, }); } } } catch (charError) { console.log(`获取服务 ${service.uuid} 特征失败:`, charError); } } console.log('所有可写特征:', allWriteCharacteristics); return allWriteCharacteristics; } catch (error) { console.log('发现服务失败:', error); throw error; } }; // 连接设备(不打印) const connectToDevice = async (deviceId, deviceName) => { try { // 连接设备前先停止扫描 stopScan(); setConnectionStatus('连接中...'); Alert.alert('提示', `正在连接: ${deviceName}`); console.log('连接设备:', deviceName); // 连接设备 const device = await manager.connectToDevice(deviceId, { timeout: 15000, }); console.log('设备连接成功'); setIsConnected(true); setCurrentDevice(device); setConnectionStatus('已连接'); // 发现所有服务和特征 const characteristics = await discoverAllServicesAndCharacteristics( device, ); setWriteCharacteristics(characteristics); if (characteristics.length === 0) { throw new Error('未找到可写的特征'); } Alert.alert( '连接成功', `已连接到: ${deviceName}

发现 ${characteristics.length} 个可写特征
现在可以点击"打印"按钮进行打印`, ); } catch (error) { console.log('连接失败:', error); setIsConnected(false); setCurrentDevice(null); setWriteCharacteristics([]); setConnectionStatus('连接失败'); throw error; } }; // 断开连接 const disconnectDevice = async () => { if (currentDevice) { try { await manager.cancelDeviceConnection(currentDevice.id); setIsConnected(false); setCurrentDevice(null); setWriteCharacteristics([]); setConnectionStatus('已断开'); console.log('设备已断开连接'); } catch (error) { console.log('断开连接错误:', error); } } }; // 打印函数 const handlePrint = async () => { if (!currentDevice || writeCharacteristics.length === 0) { Alert.alert('错误', '请先连接打印机'); return; } try { setConnectionStatus('打印中...'); // 准备打印数据 const printContent = [ 'x1Bx40', // 初始化打印机 'x1Bx61x01', // 居中对齐 'x1Bx45x01', // 加粗 '=== 用水通知单 ===
', 'x1Bx45x00', // 关闭加粗 'x1Bx61x00', // 左对齐 `本期应收: ${arrearsData?.Payment || ''}
`, `总欠费金额: ${arrearsData?.TotalPayment || ''}
`, `余额: ${arrearsData?.Balance || ''}
`, '--------------------------------
', 'x1Bx45x01', // 加粗 '温馨提示:请及时通过微信公众号或者营业厅进行缴费
', 'x1Bx45x00', // 取消加粗 `打印日期: ${new Date().toLocaleString()}
`, '
', '谢谢合作!
', '


', 'x1Dx56x00', // 切纸 ].join(''); // 使用 GBK 编码 const gbkBuffer = iconv.encode(printContent, 'gbk'); const base64Data = gbkBuffer.toString('base64'); let printSuccess = false; let lastError = null; // 尝试所有可写特征 for (const charInfo of writeCharacteristics) { try { console.log(`尝试特征: ${charInfo.characteristicUUID}`); if (charInfo.isWritableWithResponse) { await currentDevice.writeCharacteristicWithResponseForService( charInfo.serviceUUID, charInfo.characteristicUUID, base64Data, ); } else { await currentDevice.writeCharacteristicWithoutResponseForService( charInfo.serviceUUID, charInfo.characteristicUUID, base64Data, ); } printSuccess = true; break; } catch (error) { console.log( `特征 ${charInfo.characteristicUUID} 失败:`, error.message, ); lastError = error; } } if (printSuccess) { Alert.alert('打印成功', '用水通知单已发送到打印机'); setConnectionStatus('打印成功'); } else { throw new Error(`所有特征尝试失败: ${lastError?.message}`); } } catch (error) { console.log('打印失败:', error); Alert.alert('打印失败', error.message); setConnectionStatus('打印失败'); } }; const getSignalStrength = rssi => { if (rssi > -50) return { text: '强', color: 'green' }; if (rssi > -70) return { text: '中', color: 'orange' }; return { text: '弱', color: 'red' }; }; return ( <View style={{ padding: 20, flex: 1, backgroundColor: 'white' }}> <View style={{ marginBottom: 20, padding: 10, backgroundColor: '#f0f0f0', borderRadius: 5, }}> <Text style={{ fontWeight: 'bold', fontSize: 16 }}> 状态: {connectionStatus} {isScanning && ` (${scanTimeLeft}秒后自动停止)`} </Text> {currentDevice && ( <Text style={{ fontSize: 14, color: 'green', marginTop: 5 }}> 已连接设备: {currentDevice.name} </Text> )} {writeCharacteristics.length > 0 && ( <Text style={{ fontSize: 12, color: 'blue', marginTop: 2 }}> 发现 {writeCharacteristics.length} 个可写特征 </Text> )} </View> {/* 操作按钮区域 */} <View style={{ flexDirection: 'row', flexWrap: 'wrap', marginBottom: 20, gap: 10, }}> <Button title={isScanning ? `停止扫描 (${scanTimeLeft}s)` : '扫描设备'} onPress={isScanning ? stopScan : scanDevices} color={isScanning ? 'red' : '#007AFF'} /> {isConnected && ( <> <Button title="打印通知单" onPress={handlePrint} color="green" /> <Button title="断开连接" onPress={disconnectDevice} color="orange" /> </> )} </View> <ScrollView style={{ flex: 1 }}> {foundDevices.length > 0 && ( <View> <Text style={{ fontWeight: 'bold', marginBottom: 10, fontSize: 16 }}> 发现的设备 ({foundDevices.length}个): </Text> {foundDevices.map(device => { const signal = getSignalStrength(device.rssi); return ( <TouchableOpacity key={device.id} style={{ marginBottom: 12, padding: 12, backgroundColor: device.isPrinter ? '#e8f5e8' : '#f5f5f5', borderRadius: 8, borderWidth: 1, borderColor: device.isPrinter ? 'green' : '#ddd', }} onPress={() => connectToDevice(device.id, device.name)}> <Text style={{ fontWeight: 'bold', color: device.isPrinter ? 'green' : 'black', fontSize: 16, }}> {device.name} {device.isPrinter ? '🖨️' : '📱'} </Text> <Text style={{ fontSize: 12, color: 'gray', marginTop: 4 }}> ID: {device.id} </Text> <Text style={{ fontSize: 12, color: 'gray' }}> 信号强度: {device.rssi}dBm ({signal.text}) </Text> {device.localName && device.localName !== device.name && ( <Text style={{ fontSize: 12, color: 'gray' }}> 本地名: {device.localName} </Text> )} <Text style={{ fontSize: 12, color: device.isPrinter ? 'green' : 'blue', marginTop: 4, fontWeight: 'bold', }}> {device.isPrinter ? '点击连接此打印机' : '点击连接此设备'} </Text> </TouchableOpacity> ); })} </View> )} {!isScanning && foundDevices.length === 0 && ( <View style={{ alignItems: 'center', marginTop: 50 }}> <Text style={{ textAlign: 'center', color: 'gray', fontSize: 16, marginBottom: 10, }}> 点击"扫描设备"开始搜索蓝牙设备 </Text> <Text style={{ textAlign: 'center', color: 'darkgray', fontSize: 14 }}> 扫描将在15秒后自动停止 </Text> </View> )} {isConnected && ( <View style={{ marginTop: 20, padding: 15, backgroundColor: '#e8f5e8', borderRadius: 8, }}> <Text style={{ fontWeight: 'bold', fontSize: 16, color: 'green', marginBottom: 10, }}> ✅ 已连接打印机 </Text> <Text style={{ fontSize: 14, marginBottom: 5 }}> 设备名称: {currentDevice?.name} </Text> <Text style={{ fontSize: 14, marginBottom: 5 }}> 可写特征: {writeCharacteristics.length} 个 </Text> <Text style={{ fontSize: 12, color: 'darkgreen' }}> 现在可以点击"打印通知单"按钮进行打印 </Text> </View> )} </ScrollView> </View> ); }; export default BluetoothPrinter;

2.注意使用GBK编码打印 解决打印乱码问题

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

台州网站建设安徽省建设厅网站

网易云音乐NCM格式转换完全攻略:轻松解锁音乐自由【免费下载链接】ncmdump项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump还在为网

2026/06/30 14:16:39

商务网站建设孝感网站建设

PowerShell 管理脚本与操作示例详解1. 使用 WMI 获取系统信息在 PowerShell 中,使用 WMI(Windows Management Instrumentation)来获取系统

2026/06/30 11:11:54

绍兴网站建设安徽网站建设

SmallJava语言的类型检查与作用域机制详解1. 类型检查基础在编程中,确保表达式的类型与使用它的上下文所期望的类型一致至关重要。比如在条件语句中,表达式的类型应该是布尔型。为了实现类型检查,我们

2026/06/30 12:50:33

滨州网站建设建设网站的公司

特性高输入电压:最高可达26.4伏固定输出电压:1.5V、1.8V、2.5V、2.8V、3.0V、3.3V、3.6V、4.4V和5.0V可调输出电压范围:1.5V至5.0V输出电流:50毫安输出电压精

2026/06/30 12:37:32

建设银行网站松江网站建设

结构简介假设要存储有关篮球运动员的信息,则可能需要存储他(她)的姓名、工资、身高、体重、平均得分、命中率、助攻次数等。希望有一种数据格式可以将所有这些信息存储

2026/06/30 13:57:08

郑州网站建设网站建设维护

快速体验打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容:创建一个快速部署Web服务的CentOS7镜像方案,要求&#x

2026/06/30 11:50:27

温州网站建设荆门网站建设

量子计算:云访问与学习资源指南1. 量子计算云访问:Strangeworks平台1.1 成本与选择在量子计算领域,成本可能会以意想不到的方式增加。尝试新事物的初始成本可能较低,甚至可以通过免费信用额度

2026/06/30 14:00:08

广州网站建设中小企业网站建设

科研实验室以太网POE温湿度监控系统设计方案一、方案设计背景与目标1. 设计背景科研实验室(如生物培养室、化学试剂存储室、电子元器件测试实验室等)对温湿度环境具有极高敏感性

2026/06/30 12:01:58

山东网站建设广西网站建设

Qwen3-VL安全性评估:防止恶意图像注入攻击的防护机制在智能系统日益依赖视觉输入的今天,一张看似普通的图片可能暗藏玄机——它可能是精心构造的钓鱼界面、携带隐蔽指令的二维

2026/06/30 13:35:36

个人网站建设开县网站建设

Protenix蛋白质结构预测终极指南:从零基础到实战精通的完整教程【免费下载链接】ProtenixA trainable PyTorch reproduction of AlphaFo

2026/06/30 13:39:37