commit 40c821350fe2c8339fd4430dba198d0500e7e85b Author: XiaoJia Chen <441785369@qq.com> Date: Tue Apr 15 01:51:54 2025 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa556e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ + +# dependencies +**/node_modules + +.idea +.DS_Store + +# misc +npm-debug.log* +yarn-error.log +yarn.lock +package-lock.json +*bak + +# visual studio code +.vscode +.history +*.log +functions/* +.temp/** + +.eslintcache diff --git a/app.acss b/app.acss new file mode 100644 index 0000000..ecebb80 --- /dev/null +++ b/app.acss @@ -0,0 +1,96 @@ +page { + background-color: #F7F7F7; + border: 1px solid rgba(0,0,0,0); + box-sizing: border-box; +} + +.page { + font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif; + font-size: 24rpx; + padding: 32rpx; + flex: 1; +} + +.page-description { + margin-bottom: 32rpx; +} + +.page-section { + background: #fff; + margin-bottom: 32rpx; +} + +.page-section-title { + padding: 16rpx 32rpx; +} + +.page-section-demo { + padding: 32rpx; +} + +.page-section-btns { + border-top: 1px solid #ddd; + display: flex; + justify-content: space-around; + align-items: center; +} + +.page-section-btns > view { + flex: 1; + height: 84rpx; + display: flex; + align-items: center; + justify-content: space-around; + color: #49a9ee; +} +.page-section-btns > view + view { + border-left: 1px solid #ddd; +} + +button { + margin-top:20rpx; + margin-bottom:20rpx; +} + +.bc_blue { + background-color: #49A9EE; +} + +.bc_red { + background-color: #F04134; +} + +.bc_yellow { + background-color: #FFBF00; +} + +.bc_green { + background-color: #00A854; +} + +.form-row { + display: flex; + align-items: center; + padding: 0 30rpx; + height: 88rpx; + align-items: center; +} + +.form-row-label { + width: 180rpx; + font-size: 34rpx; + margin-right: 10rpx; + text-align: left; + color: #000; +} + +.form-row-content { + flex: 1; + font-size: 34rpx; +} + +.form-line { + height: 1px; + background-color: #ddd; + margin-left: 30rpx; +} diff --git a/app.js b/app.js new file mode 100644 index 0000000..b402ca4 --- /dev/null +++ b/app.js @@ -0,0 +1,11 @@ +App({ + onLaunch(options) { + // 第一次打开 + // options.query == {number:1} + console.info('App onLaunch 胜佳'); + }, + onShow(options) { + // 从后台被 scheme 重新打开 + // options.query == {number:1} + }, +}); diff --git a/app.json b/app.json new file mode 100644 index 0000000..320d5f3 --- /dev/null +++ b/app.json @@ -0,0 +1,39 @@ +{ + "pages": [ + "pages/index/index", + "pages/deal/deal", + "pages/index/index", + "pages/deal/saleOrder/saleOrder", + "pages/deal/saleOrder/kanban/saleOrderKanban", + "pages/deal/saleOrder/kanban/from/saleOrderFrom", + "pages/deal/saleOrder/kanban/from/printTag/printTag", + "pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate", + "pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth", + "pages/storage/storage" + ], + "tabBar": { + "textColor": "#404040", + "selectedColor": "#108ee9", + "backgroundColor": "#F5F5F9", + "items": [ + { + "pagePath": "pages/deal/deal", + "icon": "", + "activeIcon": "", + "name": "买卖" + }, + { + "pagePath": "pages/storage/storage", + "icon": "", + "activeIcon": "", + "name": "我的" + } + ] + }, + "window": { + "defaultTitle": "胜佳" + }, + "usingComponents": { + "bluetooth-component": "./pages/components/bluetooth/bluetooth" + } +} diff --git a/docs.md b/docs.md new file mode 100644 index 0000000..5a52a9e --- /dev/null +++ b/docs.md @@ -0,0 +1,42 @@ +``` +Page({ + data: { + + }, + onLoad(query) { + // 页面加载 + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, +}); + +``` + diff --git a/pages/components/bluetooth/bluetooth.acss b/pages/components/bluetooth/bluetooth.acss new file mode 100644 index 0000000..e69de29 diff --git a/pages/components/bluetooth/bluetooth.axml b/pages/components/bluetooth/bluetooth.axml new file mode 100644 index 0000000..c155db6 --- /dev/null +++ b/pages/components/bluetooth/bluetooth.axml @@ -0,0 +1,80 @@ + + + + 开关 + + + + + + + + + + 是否正在搜索设备{{discovering}} + 蓝牙模块是否可用需支持 BLE 并且蓝牙是打开状态{{available}} + + + 开关 + + + + + + + + + + + 图标 + + Type + + + + + {{item}} + + + + + + 单选框 + + +
+ + + + + + + + + + + +
+
+
+
+ 指令集选择 下拉选择框 + + 蓝牙选择框+选择+打印+清空查找更多蓝牙 devices 单选列表框 + + + + 已经连接蓝牙名名称文本 文本 状态一行 + 获取蓝牙状态 有两个标识 打勾 状态一行 +
\ No newline at end of file diff --git a/pages/components/bluetooth/bluetooth.js b/pages/components/bluetooth/bluetooth.js new file mode 100644 index 0000000..1ce2f22 --- /dev/null +++ b/pages/components/bluetooth/bluetooth.js @@ -0,0 +1,766 @@ +Component({ + mixins: [], + data: { + // 初始化蓝牙的开关状态,false 表示关闭,true 表示打开 + switchswitchopenBluetoothAdapter: false, + // 搜索蓝牙设备的开关状态,false 表示停止搜索,true 表示开始搜索 + switchstartBluetoothDevicesDiscovery: false, + // 蓝牙模块是否处于搜索状态,'' 表示初始值,后续会更新为 true 或 false + discovering: '', + // 蓝牙模块是否可用,'' 表示初始值,后续会更新为 true 或 false + available: '', + // 存储已发现的蓝牙设备列表 + deviceslist: [], + // 选择的保持连接的蓝牙对象 + devices: [], + devices: {}, + selectedDevice: {}, + // 存储设备名称,可根据需求调整 + devicesName: [], + // 当前选中的蓝牙设备的 ID + deviceId: '', + // 只是查找某个蓝牙设备 + services: '', + // 图标类型数组,这里只包含 'cancel',可根据需求添加其他图标类型 + iconType: [ + // 'success', + 'cancel', + ], + // 蓝牙连接状态 + isConnected: false, + // 心跳定时器 ID + heartbeatTimer: null, + // 存储获取到的可写特征值列表 + writableCharacteristics: [], + // 存储所有服务及其特征值 + allServicesAndCharacteristics: {} + }, + props: {}, + didMount() { + // 获取本机蓝牙模块的状态 + this.getBluetoothAdapterState(); + // 监听新设备发现事件 + this.listenDeviceFound(); + // 监听蓝牙连接断开事件 + this.listenBLEConnectionStateChanged(); + }, + didUpdate() {}, + didUnmount() { + try { + // 取消监听新设备发现事件,避免内存泄漏 + dd.offBluetoothDeviceFound(this.handleDeviceFound); + } catch (error) { + console.warn('取消监听新设备发现事件时出错:', error); + } + try { + // 关闭蓝牙连接 + this.closeBluetoothConnection(); + } catch (error) { + console.warn('关闭蓝牙连接时出错:', error); + } + try { + // 清除心跳定时器 + if (this.data.heartbeatTimer) { + clearInterval(this.data.heartbeatTimer); + } + } catch (error) { + console.warn('清除心跳定时器时出错:', error); + } + try { + // 取消监听蓝牙连接状态变化事件 + dd.offBLEConnectionStateChanged(this.handleBLEConnectionStateChanged); + } catch (error) { + console.warn('取消监听蓝牙连接状态变化事件时出错:', error); + } + }, + methods: { + getBluetoothAdapterState() { + // 调用 dd.getBluetoothAdapterState 方法获取本机蓝牙模块的状态 + dd.getBluetoothAdapterState({ + success: (res) => { + console.log('本机蓝牙模块状态:', res); + // 更新组件数据,将蓝牙模块的搜索状态和可用性状态存储到 data 中 + this.setData({ + // res.discovering 为 true 表示蓝牙模块处于搜索状态,false 表示不处于搜索状态 + discovering: res.discovering, + // res.available 为 true 表示蓝牙模块可用,false 表示不可用 + available: res.available + }); + }, + fail: (res) => { + console.log('获取本机蓝牙模块状态失败,错误码:', res.errorCode); + if (res.errorCode === 10000) { + dd.showToast({ + title: '请先打开蓝牙开关', + icon: 'none' + }); + } else { + // dd.showToast({ + // title: `获取本机蓝牙模块状态失败,错误码: ${res.errorCode}`, + // icon: 'none' + // }); + } + }, + complete: (res) => { + console.log('获取本机蓝牙模块状态调用结束', res); + } + }); + }, + switchopenBluetoothAdapter(e) { + console.log('switchopenBluetoothAdapter 发生 change 事件,携带值为', e.detail.value); + // 更新组件数据,将开关的新状态存储到 data 中 + this.setData({ + switchswitchopenBluetoothAdapter: e.detail.value, + }); + if (e.detail.value) { + // 开关打开,初始化蓝牙模块 + // 调用 dd.openBluetoothAdapter 方法初始化蓝牙模块 + dd.openBluetoothAdapter({ + // 自动关闭蓝牙适配器 + autoClose: true, + success: (res) => { + console.log('蓝牙模块初始化成功,是否支持 BLE:', res.isSupportBLE); + dd.showToast({ + title: '蓝牙模块初始化成功', + icon: 'success' + }); + // 监听手机蓝牙状态的改变 + dd.onBluetoothAdapterStateChange((res) => { + console.log('蓝牙适配器状态改变:', res); + }); + }, + fail: (res) => { + console.error('蓝牙模块初始化失败,错误码:', res.errorCode); + // const title = `蓝牙模块初始化失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + // 根据不同的错误码给出相应的提示信息 + switch (res.errorCode) { + case 12: + console.log('请尝试打开蓝牙。'); + break; + case 13: + console.log('请尝试重新连接。'); + break; + case 14: + console.log('请授权使用蓝牙功能。'); + break; + case 15: + console.log('未知错误。'); + break; + case 10000: + console.log('未初始化蓝牙适配器'); + break; + default: + console.log('其他错误'); + } + }, + complete: (res) => { + console.log('蓝牙模块初始化调用结束', res); + } + }); + } else { + // 开关关闭,关闭蓝牙模块 + // 调用 dd.closeBluetoothAdapter 方法关闭蓝牙模块 + dd.closeBluetoothAdapter({ + success: () => { + console.log('蓝牙模块已关闭'); + dd.showToast({ + title: '蓝牙模块已关闭', + icon: 'success' + }); + }, + fail: (res) => { + console.error('关闭蓝牙模块失败,错误码:', res.errorCode); + // const title = `关闭蓝牙模块失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + }, + complete: () => { + console.log('关闭蓝牙模块调用结束'); + } + }); + } + }, + startBluetoothDevicesDiscovery(e) { + console.log('startBluetoothDevicesDiscovery 发生 change 事件,携带值为', e.detail.value); + // 更新组件数据,将开关的新状态存储到 data 中 + this.setData({ + switchstartBluetoothDevicesDiscovery: e.detail.value, + }); + if (e.detail.value) { + // 开关打开,开始搜索蓝牙设备 + console.log('开始搜寻附近的蓝牙外围设备'); + // 调用 dd.startBluetoothDevicesDiscovery 方法开始搜索蓝牙设备 + dd.startBluetoothDevicesDiscovery({ + // 搜索指定服务 UUID 的蓝牙设备 + // services: ['fff0'], + success: (res) => { + console.log(res); + dd.showToast({ + title: '开始搜索蓝牙设备', + icon: 'success' + }); + // 开始搜索后获取已发现设备 + this.getDiscoveredDevices(); + }, + fail: (res) => { + console.error('搜寻蓝牙设备失败,错误码:', res.errorCode); + // const title = `搜寻蓝牙设备失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + }, + complete: (res) => { + console.log('搜寻蓝牙设备调用结束', res); + } + }); + } else { + // 开关关闭,停止搜索蓝牙设备 + console.log('停止搜寻附近的蓝牙外围设备'); + // 调用 dd.stopBluetoothDevicesDiscovery 方法停止搜索蓝牙设备 + dd.stopBluetoothDevicesDiscovery({ + success: (res) => { + console.log(res); + dd.showToast({ + title: '停止搜索蓝牙设备', + icon: 'success' + }); + }, + fail: (res) => { + console.error('停止搜寻蓝牙设备失败,错误码:', res.errorCode); + // const title = `停止搜寻蓝牙设备失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + }, + complete: (res) => { + console.log('停止搜寻蓝牙设备调用结束', res); + } + }); + } + }, + getDiscoveredDevices() { + // 调用 dd.getBluetoothDevices 方法获取已发现的蓝牙设备列表 + dd.getBluetoothDevices({ + success: (res) => { + console.log('已发现的蓝牙设备:', res.devices); + // 更新组件数据,将已发现的设备列表和设备名称存储到 data 中 + this.setData({ + deviceslist: res.devices, + devicesName: res.devices.map(device => device.name), + devices: res.devices // 将完整的设备对象保存到 devices 数组中 + }); + // dd.showToast({ + // title: '获取已发现蓝牙设备成功', + // icon: 'success' + // }); + }, + fail: (res) => { + console.error('获取已发现的蓝牙设备失败,错误码:', res.errorCode); + // const title = `获取已发现的蓝牙设备失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + }, + complete: (res) => { + console.log('获取已发现的蓝牙设备调用结束', res); + } + }); + }, + listenDeviceFound() { + // 绑定 handleDeviceFound 方法的上下文,确保在事件回调中 this 指向正确 + this.handleDeviceFound = this.handleDeviceFound.bind(this); + // 调用 dd.onBluetoothDeviceFound 方法监听新设备发现事件 + dd.onBluetoothDeviceFound(this.handleDeviceFound); + }, + handleDeviceFound(res) { + // console.log('新发现的蓝牙设备:', res.devices); + // 获取当前已发现的设备列表 + const currentDevices = this.data.devices; + // 过滤出新发现的设备,避免重复添加 + const newDevices = res.devices.filter(device => { + return currentDevices.every(existingDevice => existingDevice.deviceId !== device.deviceId); + }); + // 更新组件数据,将新发现的设备添加到已发现设备列表中 + this.setData({ + devices: [...currentDevices, ...newDevices], + devicesName: [...this.data.devicesName, ...newDevices.map(device => device.name)] + }); + // const title = '发现新的蓝牙设备'; + // if (title) { + // dd.showToast({ + // title, + // icon: 'success' + // }); + // } + }, + radioChange(e) { + console.log('选择的蓝牙是', e.detail.value); + const deviceId = e.detail.value; + const devices = this.data.devices; + const selectedDevice = devices.find(device => device.deviceId === deviceId); + + if (selectedDevice) { + this.setData({ + deviceId, + selectedDevice: selectedDevice // 将选中的蓝牙设备对象保存到 data 的 devices 中 + }); + // const title = '已选择蓝牙设备,开始连接'; + // if (title) { + // dd.showToast({ + // title, + // icon: 'success' + // }); + // } + this.connectBluetoothDevice(); + } else { + console.log('未找到选中的蓝牙设备'); + // const title = '未找到选中的蓝牙设备'; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + } + }, + connectBluetoothDevice() { + const deviceId = this.data.deviceId; + if (deviceId) { + dd.connectBLEDevice({ + deviceId, + success: (res) => { + console.log('连接蓝牙设备成功', res); + this.setData({ + isConnected: true, + iconType: [ + 'success', + ], + }); + // const title = '蓝牙设备连接成功'; + // if (title) { + // dd.showToast({ + // title, + // icon: 'success' + // }); + // } + // 获取设备的服务列表 + this.getBLEDeviceServices(deviceId); + }, + fail: (res) => { + console.error('连接蓝牙设备失败,错误码:', res.errorCode); + // const title = `连接蓝牙设备失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title, + // icon: 'none' + // }); + // } + }, + complete: (res) => { + console.log('连接蓝牙设备调用结束', res); + } + }); + } else { + console.log('请先选择要连接的蓝牙设备'); + const title = '请先选择要连接的蓝牙设备'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + } + }, + /** + * 获取设备的服务列表 + * @param {string} deviceId - 设备 ID + */ + getBLEDeviceServices(deviceId) { + dd.getBLEDeviceServices({ + deviceId, + success: (serviceRes) => { + const services = serviceRes.services; + if (services && services.length > 0) { + services.forEach((service) => { + const serviceUuid = service.uuid || service.serviceId; + if (serviceUuid) { + this.getBLEDeviceCharacteristics(deviceId, serviceUuid); + } else { + console.error('服务的 UUID 和 serviceId 均为空,无法获取特征值。服务详情:', service); + const title = '服务 UUID 和 serviceId 均为空,无法获取特征值'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + } + }); + } else { + console.error('未获取到服务列表'); + const title = '未获取到服务列表'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + } + }, + fail: (serviceErr) => { + console.error('获取服务失败', serviceErr); + const title = '获取服务失败'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + } + }); + }, + /** + * 获取设备的特征值列表 + * @param {string} deviceId - 设备 ID + * @param {string} serviceId - 服务 ID + */ + getBLEDeviceCharacteristics(deviceId, serviceId) { + if (!deviceId || !serviceId) { + console.error('deviceId 或 serviceId 为空,无法获取特征值'); + return; + } + dd.getBLEDeviceCharacteristics({ + deviceId, + serviceId, + success: (characteristicRes) => { + const characteristics = characteristicRes.characteristics; + console.log('获取到的所有特征值:', characteristics); + // 先筛选出可读可写的特征值 + const readableAndWritable = characteristics.filter( + (characteristic) => characteristic.properties.read && characteristic.properties.write + ); + // 如果没有可读可写的特征值,则筛选出只可写的特征值 + const writable = readableAndWritable.length > 0 ? + readableAndWritable : + characteristics.filter( + (characteristic) => characteristic.properties.write + ); + console.log('筛选出的可写特征值:', writable); + // 更新组件数据,存储可写特征值列表 + this.setData({ + writableCharacteristics: [...this.data.writableCharacteristics, ...writable] + }); + console.log('获取特征值成功', characteristicRes); + const title = '获取特征值成功'; + if (title) { + dd.showToast({ + title, + icon: 'success' + }); + } + }, + fail: (characteristicErr) => { + console.error('获取特征值失败', characteristicErr); + const title = '获取特征值失败'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + } + }); + }, + /** + * 重新连接蓝牙设备 + */ + reconnectBluetoothDevice() { + const deviceId = this.data.deviceId; + if (deviceId) { + setTimeout(() => { + dd.createBLEConnection({ + deviceId, + success: (res) => { + console.log('重新连接蓝牙设备成功', res); + this.setData({ + isConnected: true, + iconType: [ + 'success', + ], + }); + const title = '蓝牙设备重新连接成功'; + if (title) { + dd.showToast({ + title, + icon: 'success' + }); + } + // this.startHeartbeat(); + }, + fail: (res) => { + console.error('重新连接蓝牙设备失败,错误码:', res.errorCode); + const title = `重新连接蓝牙设备失败,错误码: ${res.errorCode}`; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + this.reconnectBluetoothDevice(); + }, + complete: (res) => { + console.log('重新连接蓝牙设备调用结束', res); + } + }); + }, 2000); // 2 秒后重试 + } + }, + /** + * 关闭蓝牙连接 + */ + closeBluetoothConnection() { + const deviceId = this.data.deviceId; + if (deviceId && this.data.isConnected) { + dd.closeBLEConnection({ + deviceId, + success: (res) => { + console.log('蓝牙连接已关闭', res); + this.setData({ + isConnected: false, + iconType: [ + 'cancel', + ], + }); + if (this.data.heartbeatTimer) { + clearInterval(this.data.heartbeatTimer); + } + const title = '蓝牙连接已关闭'; + if (title) { + dd.showToast({ + title, + icon: 'success' + }); + } + }, + fail: (res) => { + console.error('关闭蓝牙连接失败,错误码:', res.errorCode); + const title = `关闭蓝牙连接失败,错误码: ${res.errorCode}`; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + }, + complete: (res) => { + console.log('关闭蓝牙连接调用结束', res); + } + }); + } + }, + /** + * 监听蓝牙连接状态变化事件 + */ + listenBLEConnectionStateChanged() { + // 先关闭之前的事件监听 + dd.offBLEConnectionStateChanged(this.handleBLEConnectionStateChanged); + // 绑定回调函数上下文 + this.handleBLEConnectionStateChanged = this.handleBLEConnectionStateChanged.bind(this); + // 监听蓝牙连接状态变化事件 + dd.onBLEConnectionStateChanged(this.handleBLEConnectionStateChanged); + }, + /** + * 处理蓝牙连接状态变化事件的回调函数 + */ + handleBLEConnectionStateChanged(res) { + const { + deviceId, + connected + } = res; + if (connected) { + console.log(`蓝牙设备 ${deviceId} 连接成功`); + const title = `蓝牙设备 ${deviceId} 连接成功`; + if (title) { + dd.showToast({ + title, + icon: 'success' + }); + } + this.setData({ + isConnected: true, + iconType: [ + 'success', + ], + }); + } else { + console.log(`蓝牙设备 ${deviceId} 连接断开,尝试重新连接`); + const title = `蓝牙设备 ${deviceId} 连接断开,尝试重新连接`; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + this.setData({ + isConnected: false, + iconType: [ + // 'success', + 'cancel' + ], + }); + this.reconnectBluetoothDevice(); + } + }, + onSubmit() { + const selectedDevice = this.data.selectedDevice; + console.log('selectedDevice', selectedDevice); + const isConnected = this.data.isConnected; + // 检查蓝牙设备是否已连接 + if (!selectedDevice || !isConnected) { + console.log('请先连接蓝牙设备'); + const title = '请先连接蓝牙设备'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + return; + } + + // 从可写特征值列表中获取第一个可写特征值(这里假设只有一个可写特征值,你可以根据实际情况调整) + const writableCharacteristic = this.data.writableCharacteristics[0]; + console.log('writableCharacteristics', this.data.writableCharacteristics); + if (!writableCharacteristic) { + console.log('未找到可写特征值'); + const title = '未找到可写特征值'; + if (title) { + dd.showToast({ + title, + icon: 'none' + }); + } + return; + } + + const serviceId = writableCharacteristic.serviceId; + const characteristicId = writableCharacteristic.characteristicId; + const deviceId = selectedDevice.deviceId; + + // 检查参数完整性 + if (!deviceId || !serviceId || !characteristicId) { + console.error('缺少必要参数:', { + deviceId, + serviceId, + characteristicId + }); + const title = '缺少必要参数,请检查连接'; + if (title) { + dd.showToast({ + // title, + icon: 'none' + }); + } + return; + } + + // 假设 printcode 是一个变量,需要在代码里定义 + const printcode = [1, 2, 3, 4]; + + const sendPrintCode = (index) => { + if (index >= printcode.length) { + console.log('所有 printcode 数据发送完成'); + // const title = '所有 printcode 数据发送完成'; + // if (title) { + // dd.showToast({ + // // title, + // icon: 'success' + // }); + // } + return; + } + + const currentCode = printcode[index]; + const command = ` + SIZE 7,5 + GAP 2,0 + CLS + QRCODE 20,150,H,5,A,0,"${currentCode}" + TEXT 20,350,"2",0,1,1,"${currentCode}" + PRINT 1,1 + `; + const encoder = new TextEncoder('utf-8'); + const commandBuffer = encoder.encode(command); + + // 将二进制数据转换为 hex 编码 + const hexValue = Array.from(commandBuffer) + .map(byte => byte.toString(16).padStart(2, '0')) + .join(''); + + // 分段发送数据 + const chunkSize = 40; // 每个分段的长度,20 字节 = 40 个十六进制字符 + const chunks = []; + for (let i = 0; i < hexValue.length; i += chunkSize) { + chunks.push(hexValue.slice(i, i + chunkSize)); + } + + const sendNextChunk = (chunkIndex) => { + if (chunkIndex >= chunks.length) { + console.log(`printcode ${currentCode} 的所有数据分段发送完成`); + sendPrintCode(index + 1); + return; + } + + const currentChunk = chunks[chunkIndex]; + console.log(`准备发送 printcode ${currentCode} 的第 ${chunkIndex + 1} 个数据分段,长度: ${currentChunk.length}`, currentChunk); + dd.writeBLECharacteristicValue({ + deviceId, + serviceId, + characteristicId, + value: currentChunk, + success: (res) => { + console.log(`printcode ${currentCode} 的第 ${chunkIndex + 1} 个数据分段发送成功`, res); + sendNextChunk(chunkIndex + 1); + }, + fail: (res) => { + console.error(`printcode ${currentCode} 的第 ${chunkIndex + 1} 个数据分段发送失败,错误码:`, res.errorCode); + const title = `printcode ${currentCode} 的第 ${chunkIndex + 1} 个数据分段发送失败,错误码: ${res.errorCode}`; + // if (title) { + // dd.showToast({ + // title: title, + // icon: 'none' + // }); + // } + }, + complete: (res) => { + console.log(`printcode ${currentCode} 的第 ${chunkIndex + 1} 个数据分段发送调用结束`, res); + } + }); + }; + + sendNextChunk(0); + }; + + sendPrintCode(0); + } + } +}); \ No newline at end of file diff --git a/pages/components/bluetooth/bluetooth.json b/pages/components/bluetooth/bluetooth.json new file mode 100644 index 0000000..467ce29 --- /dev/null +++ b/pages/components/bluetooth/bluetooth.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/pages/deal/deal.acss b/pages/deal/deal.acss new file mode 100644 index 0000000..75a1cea --- /dev/null +++ b/pages/deal/deal.acss @@ -0,0 +1,24 @@ +navigator { + background-color: rgb(74, 110, 207); + color: #fff; + margin-bottom: 10rpx; + padding: 60rpx; + text-align: center; + /* 圆角 */ + border-radius: 8px; + background: linear-gradient(45deg, #007BFF, #00BFFF); +} + +.navigator-hover { + background-color: lightskyblue; + color: #fff; +} + +.nav-button:hover { + transform: translateY(-3px); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); +} + +.navigator-hover { + opacity: 0.8; +} \ No newline at end of file diff --git a/pages/deal/deal.axml b/pages/deal/deal.axml new file mode 100644 index 0000000..93a3a67 --- /dev/null +++ b/pages/deal/deal.axml @@ -0,0 +1,5 @@ + + 销售 + + + \ No newline at end of file diff --git a/pages/deal/deal.js b/pages/deal/deal.js new file mode 100644 index 0000000..1b01880 --- /dev/null +++ b/pages/deal/deal.js @@ -0,0 +1,38 @@ +Page({ + data: { + + }, + onLoad(query) { + // 页面加载 + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, +}); \ No newline at end of file diff --git a/pages/deal/deal.json b/pages/deal/deal.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/deal.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTag.acss b/pages/deal/saleOrder/kanban/from/printTag/printTag.acss new file mode 100644 index 0000000..80da02c --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTag.acss @@ -0,0 +1,15 @@ +.checkbox { + display: block; + margin-bottom: 20rpx; +} + +.order-item { + /* 卡片边框颜色 */ + border: 1px solid #161515; + padding: 10px; + margin: 10px; + cursor: pointer; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + background-color: #ffffff; +} \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTag.axml b/pages/deal/saleOrder/kanban/from/printTag/printTag.axml new file mode 100644 index 0000000..0f69cff --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTag.axml @@ -0,0 +1,20 @@ + + 多项选择器 +
+ + 选择你用过的框架: + + + + + + + + + + +
+ diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTag.js b/pages/deal/saleOrder/kanban/from/printTag/printTag.js new file mode 100644 index 0000000..2d45818 --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTag.js @@ -0,0 +1,113 @@ +Page({ + data: { + items: [] + }, + onLoad(query) { + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + dd.getStorage({ + key: 'saleOrderlines', + success: (res) => { + const selectedOrder = res.data; + const orderLinesoptions = selectedOrder.orderLines; + this.setData({ + items: orderLinesoptions + }); + console.log('从本地存储获取到的数据:', selectedOrder); + }, + fail: (err) => { + console.error('从本地存储获取数据失败:', err); + } + }); + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index' + }; + }, +onSubmit(e) { + console.log('onSubmit', e); + const selectedIds = e.detail.value.libs.map(Number); // 将 selectedIds 中的元素转换为数字类型 + console.log('选中的 ID:', selectedIds); + + if (selectedIds.length === 0) { + console.log('未选中任何 ID,清空本地缓存'); + dd.removeStorage({ + key: 'selectedSaleOrderLines', + success: () => { + console.log('本地缓存 selectedSaleOrderLines 已清空'); + }, + fail: (err) => { + console.error('清空本地缓存 selectedSaleOrderLines 失败:', err); + } + }); + return; + } + + const saleOrderLines = this.data.items; + console.log('所有销售订单行数据:', saleOrderLines); + + const selectedItems = saleOrderLines.filter(line => selectedIds.includes(line.id)); + const selectedSaleOrderLines = { + selectedItems + }; + console.log('选中的销售订单行记录:', selectedItems); + + dd.setStorage({ + key: 'selectedSaleOrderLines', + data: selectedSaleOrderLines, + success: () => { + console.log('选中的销售订单行记录已保存到本地存储:', selectedItems); + }, + fail: (err) => { + console.error('保存选中的销售订单行记录到本地存储失败:', err); + } + }); + dd.reLaunch({ + url: "/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate", + success () { + // 导航成功的回调函数 + console.log("导航成功"); + }, + fail: function (err) { + // 导航失败的回调函数 + console.error("导航失败", err); + }, + complete: function () { + // 导航结束的回调函数(无论成功或失败都会执行) + console.log("导航操作结束"); + } + }); + // my.alert({ + // content: `你选择的框架是 ${selectedIds.join(', ')}`, + // }); +}, + onReset(e) { + console.log('onReset', e); + }, + onChange(e) { + console.log(e); + } +}); \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTag.json b/pages/deal/saleOrder/kanban/from/printTag/printTag.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTag.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.acss b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.acss new file mode 100644 index 0000000..e69de29 diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.axml b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.axml new file mode 100644 index 0000000..7f1dc3b --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.axml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.js b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.js new file mode 100644 index 0000000..c2e565d --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.js @@ -0,0 +1,54 @@ +Page({ + data: { + switch1: '', + switch2: '', + switch3: '', + switch4: '', + iconType: [ + 'cancel', + ], + // 'success',连接成功打勾 + // 'info', 感叹号 + // 'warn', 黄色感叹号 + // 'waiting',时钟 + // 'clear',打叉 + // 'success_no_circle',打勾 + // 'download',下载 + // 'cancel',打叉 + // 'search',搜索 + array: ['TSPL', 'ZPL', 'CPCL', 'ESC/POS'], + value: {}, + printdata: {}, + blueoptions: [], + deviceId: '', + connected: false, + devices: [], + showDeviceList: false, + currentDeviceServices: [], + currentDeviceCharacteristics: [], + hasLocation: false, + location: {}, + deviceCount: 0, + targetDeviceId: 'DC:0D:30:63:9E:0E', + isSearching: true, + printFormat: 'TSPL', + maxAllowedLength: 1024, + delayTime: 5000, // 默认延迟 5 秒,单位:毫秒 + paperSize: { + width: 80, // 默认宽度 80mm + height: 60 // 默认高度 60mm + }, + index: 0 //指令集默认选择 + }, + + onLoad() { + const selectedSaleOrderLines = dd.getStorageSync({ + key: 'selectedSaleOrderLines' + }).data; + const printdata = selectedSaleOrderLines || {}; + this.setData({ + printdata + }); + }, + +}); \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.json b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.acss b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.acss new file mode 100644 index 0000000..9366157 --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.acss @@ -0,0 +1,26 @@ +.cart-bottom { + position: fixed; + bottom: 0; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + align-items: center; + background-color: #fff; + padding: 10px; + border-top: 1px solid #eee; +} + +.cart-info { + display: flex; + flex-direction: column; +} + +.confirm-button { + background-color: #ff5722; + color: #fff; + padding: 20px 50px; + border: none; + border-radius: 5px; +} + \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.axml b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.axml new file mode 100644 index 0000000..8b131fd --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.axml @@ -0,0 +1,24 @@ + + + + + + + + + + 返回 + + + 确认 + + + \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.js b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.js new file mode 100644 index 0000000..3684555 --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.js @@ -0,0 +1,55 @@ + + +Page({ + data: { + nodes: [{ + name: 'div', + attrs: { + class: 'wrapper', + style: 'color: orange;', + }, + children: [{ + type: 'text', + text: 'Hello World! 拖拉设计打印模板待开发', + }], + }], + }, + onLoad(query) { + // 页面加载 + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, + // + tap() { + console.log('tap'); + }, + // +}); \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.json b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/printTag/printTemplate/printTemplate.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/deal/saleOrder/kanban/from/saleOrderFrom.acss b/pages/deal/saleOrder/kanban/from/saleOrderFrom.acss new file mode 100644 index 0000000..9366157 --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/saleOrderFrom.acss @@ -0,0 +1,26 @@ +.cart-bottom { + position: fixed; + bottom: 0; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + align-items: center; + background-color: #fff; + padding: 10px; + border-top: 1px solid #eee; +} + +.cart-info { + display: flex; + flex-direction: column; +} + +.confirm-button { + background-color: #ff5722; + color: #fff; + padding: 20px 50px; + border: none; + border-radius: 5px; +} + \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/saleOrderFrom.axml b/pages/deal/saleOrder/kanban/from/saleOrderFrom.axml new file mode 100644 index 0000000..a37f8c4 --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/saleOrderFrom.axml @@ -0,0 +1,203 @@ + + + + + + + 客户 + + + + + + + + + + 地址 + + + + + + + + + + 销售日期 + + + + + + + + + + 计划收款日期 + + + + + + + + + + 送货日期 + + + + + + + + + + 默认仓库 + + + + + + + + + + 业务员 + + + + + + + + + + 销售单号 + + + + + + + 税率 + + + + + + 订单金额 + + + + + + + + + + 优惠金额 + + + + + + + + + + 合同金额 + + + + + + + + + + 非产品费用 + + + + + + + + + + 确认 + + + 打印 + + \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/saleOrderFrom.js b/pages/deal/saleOrder/kanban/from/saleOrderFrom.js new file mode 100644 index 0000000..3d945bd --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/saleOrderFrom.js @@ -0,0 +1,55 @@ +Page({ + data: { + selectedOrder:{} + }, + onLoad(query) { + // 页面加载 + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + const objectKey = query.objectKey; + if (objectKey) { + dd.getStorage({ + key: objectKey, + success: (res) => { + const selectedOrder = res.data; + this.setData({ + selectedOrder + }); + console.log('从本地存储获取到的数据:', selectedOrder); + // 在这里可以对 selectedOrder 进行进一步处理 + }, + fail: (err) => { + console.error('从本地存储获取数据失败:', err); + } + }); + } + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, +}); \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/from/saleOrderFrom.json b/pages/deal/saleOrder/kanban/from/saleOrderFrom.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/saleOrder/kanban/from/saleOrderFrom.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/deal/saleOrder/kanban/saleOrderKanban.acss b/pages/deal/saleOrder/kanban/saleOrderKanban.acss new file mode 100644 index 0000000..c866d5e --- /dev/null +++ b/pages/deal/saleOrder/kanban/saleOrderKanban.acss @@ -0,0 +1,83 @@ + +.list-header { + font-size: 18px; + font-weight: bold; + padding: 10px; + background-color: #f0f0f0; +} + +.order-item { + /* 卡片边框颜色 */ + border: 1px solid #161515; + padding: 10px; + margin: 10px; + cursor: pointer; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + background-color: #ffffff; +} + +.order-title { + font-size: 16px; + font-weight: bold; + color: #dbe45a; +} + +.order-brief { + font-size: 14px; + color: #666; +} + +.order-extra { + font-size: 14px; + color: #666; + float: right; +} + +.order-details { + font-size: 14px; + margin-top: 5px; + color: #444444; +} + +.order-line-item { + border: 1px solid #eee; + padding: 5px; + margin-top: 5px; + border-radius: 3px; + /* 销售订单行背景色 */ + background-color: #f9f9f9; +} + +.pagination { + display: flex; + justify-content: center; + align-items: center; + margin-top: 20px; +} + +.pagination-button { + padding: 8px 16px; + margin: 0 10px; + border: none; + border-radius: 5px; + background-color: #007aff; + color: #ffffff; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.pagination-button:hover { + background-color: #0056b3; +} + +.disabled-button { + background-color: #cccccc; + cursor: not-allowed; +} + +.pagination-text { + font-size: 14px; + color: #333333; + margin: 0 10px; +} \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/saleOrderKanban.axml b/pages/deal/saleOrder/kanban/saleOrderKanban.axml new file mode 100644 index 0000000..c2d433f --- /dev/null +++ b/pages/deal/saleOrder/kanban/saleOrderKanban.axml @@ -0,0 +1,34 @@ + + + + {{item.date_order || '无订单日期'}} + {{item.name || '无订单名称'}} + 总金额:{{item.amount_total || '无'}} + {{item.partner_id[1] || '无客户名称'}} + + + 数量: {{item.product_uom_qty || '无数量'}} + 货号: {{item.product_id? item.product_id[1] : '无产品名称'}} + + + + + + + + 第 {{currentPage}} 页 / 共 {{totalRecords / pageSize}} 页 + + + diff --git a/pages/deal/saleOrder/kanban/saleOrderKanban.js b/pages/deal/saleOrder/kanban/saleOrderKanban.js new file mode 100644 index 0000000..b5bd847 --- /dev/null +++ b/pages/deal/saleOrder/kanban/saleOrderKanban.js @@ -0,0 +1,307 @@ +import jsonrpcFunc from '../../../ulti/jsonrpc' + +Page({ + data: { + loginInfo: '', //权限验证信息 + combinedOrders: [], //销售数据汇总 + currentPage: 1, //当前第几页 + pageSize: 10, //一页多少数据 + totalRecords: 0, //整个模型目前有多少条记录 + orderlineIDs: [], //销售订单行数据 + isloading: 50 //加载进度条百分比 + }, + onLoad(query) { + // 页面加载 + // console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + const loginInfo = dd.getStorageSync({ + key: 'loginInfo' + }).data; + if (loginInfo && loginInfo.apiurl && loginInfo.databaseName && loginInfo.username && loginInfo.password && loginInfo.uid > 0) { + this.setData({ + loginInfo + }); + // console.log('销售页得到的本地信息', loginInfo); + //执行获取销售订单第一页数据分页第一页默认 + this.fetchData(1); + } else { + // console.log('本地缓存中未获取到登录信息'); + } + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, + fetchData(page) { + const { + loginInfo, + pageSize + } = this.data; + const offset = (page - 1) * pageSize; + // 调用 search_count 方法获取总记录数 + const saleOrderCountData = { + "jsonrpc": "2.0", + "method": "call", + "id": 2, + "params": { + "service": "object", + "method": "execute_kw", + "args": [ + loginInfo.databaseName, + loginInfo.uid, + loginInfo.password, + 'sale.order', + "search_count", + [ + [] + ] + ] + } + }; + jsonrpcFunc(loginInfo, saleOrderCountData) + .then((count) => { + this.setData({ + totalRecords: count + }); + // console.log('销售订单总记录数:', count); + + const saleOrderData = { + "jsonrpc": "2.0", + "method": "call", + "id": 2, + "params": { + "service": "object", + "method": "execute_kw", + "args": [ + loginInfo.databaseName, + loginInfo.uid, + loginInfo.password, + 'sale.order', + "search_read", + [], + { + fields: [], + "limit": pageSize, + "offset": offset, + "order": "id DESC" + } + ] + } + }; + return jsonrpcFunc(loginInfo, saleOrderData); + }) + .then((salesOrderData) => { + this.setData({ + combinedOrders: salesOrderData.map(order => ({ + ...order, + orderLines: [] + })) + }); + // console.log('销售订单数据:', salesOrderData); + const orderlineIDs = []; + salesOrderData.forEach(order => { + if (order.order_line && Array.isArray(order.order_line)) { + order.order_line.forEach(id => { + if (!orderlineIDs.includes(id)) { + orderlineIDs.push(id); + } + }); + } + }); + this.setData({ + orderlineIDs + }); + // console.log('获取到的销售订单行 ID:', orderlineIDs); + if (orderlineIDs.length > 0) { + const domain = orderlineIDs; + const saleOrderLineData = { + "jsonrpc": "2.0", + "method": "call", + "id": 2, + "params": { + "service": "object", + "method": "execute_kw", + "args": [ + loginInfo.databaseName, + loginInfo.uid, + loginInfo.password, + 'sale.order.line', + "read", + [domain], + { + fields: [], + } + ] + } + }; + // console.log('saleOrderLineData ', saleOrderLineData); + return jsonrpcFunc(loginInfo, saleOrderLineData); + } + return null; + }) + .then((salesOrderLineData) => { + if (salesOrderLineData) { + const { + combinedOrders + } = this.data; + salesOrderLineData.forEach(orderLine => { + const orderId = orderLine.order_id && orderLine.order_id[0]; + const targetOrder = combinedOrders.find(order => order.id === orderId); + if (targetOrder) { + targetOrder.orderLines.push(orderLine); + } + }); + this.setData({ + combinedOrders + }); + // console.log('销售订单行数据:', salesOrderLineData); + // console.log('合并后的订单数据:', combinedOrders); + + // 提取所有 fineCode_3 的 ID + const fineCode3Ids = []; + combinedOrders.forEach(order => { + order.orderLines.forEach(orderLine => { + if (orderLine.fineCode_3 && Array.isArray(orderLine.fineCode_3)) { + orderLine.fineCode_3.forEach(id => { + if (!fineCode3Ids.includes(id)) { + fineCode3Ids.push(id); + } + }); + } + }); + }); + + if (fineCode3Ids.length > 0) { + const fineCode3Data = { + "jsonrpc": "2.0", + "method": "call", + "id": 2, + "params": { + "service": "object", + "method": "execute_kw", + "args": [ + loginInfo.databaseName, + loginInfo.uid, + loginInfo.password, + // 这里需要替换为 fineCode_3 关联的模型名称 + 'finecode_xima_l', + "read", + [fineCode3Ids], + { + fields: ['name'] + } + ] + } + }; + return jsonrpcFunc(loginInfo, fineCode3Data); + } + } + return null; + }) + .then((fineCode3Data) => { + if (fineCode3Data) { + const { + combinedOrders + } = this.data; + const fineCode3NameMap = {}; + fineCode3Data.forEach(item => { + fineCode3NameMap[item.id] = item.name; + }); + combinedOrders.forEach(order => { + order.orderLines.forEach(orderLine => { + if (orderLine.fineCode_3 && Array.isArray(orderLine.fineCode_3)) { + orderLine.fineCode3Names = orderLine.fineCode_3.map(id => fineCode3NameMap[id]); + } + }); + }); + this.setData({ + combinedOrders, + isloading: 100 + }); + // console.log('合并后的订单数据(包含 fineCode_3 名称):', combinedOrders); + } + }) + .catch((error) => { + console.error('请求数据时出错:', error); + }); + }, + //下一页逻辑 + handleNextPage() { + const { + currentPage, + totalRecords, + pageSize + } = this.data; + const totalPages = Math.ceil(totalRecords / pageSize); + if (currentPage < totalPages) { + this.setData({ + currentPage: currentPage + 1 + }); + this.fetchData(currentPage + 1); + } + }, + // + //上一页逻辑 + handlePreviousPage() { + const { + currentPage + } = this.data; + if (currentPage > 1) { + this.setData({ + currentPage: currentPage - 1 + }); + this.fetchData(currentPage - 1); + } + }, + // + //点击卡片触发这条记录保存 + handleTap(e) { + const orderId = e.currentTarget.dataset.info; + const { + combinedOrders + } = this.data; + const selectedOrder = combinedOrders.find(order => order.id === orderId); + if (selectedOrder) { + + const objectKey = `saleOrderlines`; + // const objectKey = `order_${orderId}`; + dd.setStorage({ + key: objectKey, + data: selectedOrder, + success: function () { + dd.navigateTo({ + url: `/pages/deal/saleOrder/kanban/from/saleOrderFrom?objectKey=${objectKey}` + }); + }, + fail: function (err) { + console.error('存储数据到本地存储失败:', err); + } + }); + } + }, + // +}); \ No newline at end of file diff --git a/pages/deal/saleOrder/kanban/saleOrderKanban.json b/pages/deal/saleOrder/kanban/saleOrderKanban.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/saleOrder/kanban/saleOrderKanban.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/deal/saleOrder/saleOrder.acss b/pages/deal/saleOrder/saleOrder.acss new file mode 100644 index 0000000..9366157 --- /dev/null +++ b/pages/deal/saleOrder/saleOrder.acss @@ -0,0 +1,26 @@ +.cart-bottom { + position: fixed; + bottom: 0; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + align-items: center; + background-color: #fff; + padding: 10px; + border-top: 1px solid #eee; +} + +.cart-info { + display: flex; + flex-direction: column; +} + +.confirm-button { + background-color: #ff5722; + color: #fff; + padding: 20px 50px; + border: none; + border-radius: 5px; +} + \ No newline at end of file diff --git a/pages/deal/saleOrder/saleOrder.axml b/pages/deal/saleOrder/saleOrder.axml new file mode 100644 index 0000000..ca0b5cb --- /dev/null +++ b/pages/deal/saleOrder/saleOrder.axml @@ -0,0 +1,99 @@ + + + + + + 客户 + + + + + + + + + + 日期 + + + + + + + + + + 默认仓库 + + + + + + + + + + 业务员 + + + + + + + + + + + + + + + + + + + 产品列表 + + + + + + + 确认 + + + + \ No newline at end of file diff --git a/pages/deal/saleOrder/saleOrder.js b/pages/deal/saleOrder/saleOrder.js new file mode 100644 index 0000000..1b01880 --- /dev/null +++ b/pages/deal/saleOrder/saleOrder.js @@ -0,0 +1,38 @@ +Page({ + data: { + + }, + onLoad(query) { + // 页面加载 + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, +}); \ No newline at end of file diff --git a/pages/deal/saleOrder/saleOrder.json b/pages/deal/saleOrder/saleOrder.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/deal/saleOrder/saleOrder.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/index/index.acss b/pages/index/index.acss new file mode 100644 index 0000000..323d1d6 --- /dev/null +++ b/pages/index/index.acss @@ -0,0 +1,3 @@ +button + button { + margin-top: 32rpx; +} \ No newline at end of file diff --git a/pages/index/index.axml b/pages/index/index.axml new file mode 100644 index 0000000..5bb094c --- /dev/null +++ b/pages/index/index.axml @@ -0,0 +1,54 @@ + +
+ + + + + 地址 + + + + + + + + + + 账套 + + + + + + + + 用户 + + + + + + + + 密码 + + + + + + + + + + + + + + + + + + v1.0.9 + + +
\ No newline at end of file diff --git a/pages/index/index.js b/pages/index/index.js new file mode 100644 index 0000000..dca7b2d --- /dev/null +++ b/pages/index/index.js @@ -0,0 +1,329 @@ +Page({ + data: { + apiurl: '', + username: '', + password: '', + databaseList: '', + index: 0, //数据库选择的页面ID + databaseName: '', + Uid: null, //登录获取的信息保存本地设备 + }, + onLoad(query) { + // 页面加载 + console.info(`胜佳Page onLoad with query: ${JSON.stringify(query)}`); + // 检查本地缓存中是否有登录信息 要四个不为空才渲染// + const loginInfo = dd.getStorageSync({ + key: 'loginInfo' + }).data; + if (loginInfo && loginInfo.apiurl && loginInfo.databaseName && loginInfo.username && loginInfo.password && loginInfo.uid > 0) { + const { + apiurl, + databaseName, + username, + password + } = loginInfo; + // 这里假定 apiurl 可以从其他地方获取或者有默认值'; + this.setData({ + apiurl, + databaseName, + username, + password + }); + dd.switchTab({ + url: '/pages/deal/deal', + success: () => { + dd.showToast({ + content: '登录成功,已跳转页面', + type:'success', + duration: 1000, + success() { + console.log('toast end'); + } + }); + }, + }); + + } else { + console.log('本地缓存中未获取到登录信息'); + } + + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: '钉钉胜佳', + desc: 'My App description', + path: 'pages/index/index', + }; + }, + onSubmit(e) { + if (!e || !e.detail || !e.detail.value) { + + dd.showToast({ + content: '传入的事件对象或其属性未定义', + type: 'none', + duration: 3000, + success() { + console.log('toast end'); + } + }); + return; + } + + const { + apiurl, + databaseName + } = this.data; + const { + username: username, + password: password + } = e.detail.value; + + this.setData({ + apiurl, + databaseName, + username, + password + }); + + if (!databaseName || !apiurl) { + dd.showToast({ + content: '账套或地址有为空', + type: 'none', + duration: 3000, + success() { + console.log('toast end'); + } + }); + return; + } + + const data = { + "jsonrpc": "2.0", + "method": "call", + "id": 2, + "params": { + "service": "common", + "method": "authenticate", + "args": [ + databaseName, + username, + password, + {} + ] + } + }; + + return new Promise((resolve, reject) => { + dd.httpRequest({ + url: `${apiurl}/jsonrpc`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + data: JSON.stringify(data), + success: (res) => { + if (res.statusCode < 200 || res.statusCode >= 300) { + reject(new Error(`HTTP error! status: ${res.statusCode}`)); + return; + } + const result = res.data; + if (Object.prototype.hasOwnProperty.call(result, 'error')) { + reject(new Error(`认证失败: ${JSON.stringify(result.error)}`)); + return; + } + const uid = result.result; + + try { + const loginInfo = { + apiurl, + uid, + username, + password, + databaseName + }; + dd.setStorageSync({ + key: 'loginInfo', + data: loginInfo + }); + } catch (e) { + reject(new Error(`保存登录信息到本地缓存失败: ${e.message}`)); + return; + } + + if (uid) { + dd.switchTab({ + url: '/pages/deal/deal', + success: () => { + dd.showToast({ + content: '登录成功,已跳转页面', + type: 'success', + duration: 3000, + success() { + console.log('toast end'); + } + }); + resolve(uid); + }, + fail: (err) => { + reject(new Error(`页面跳转失败: ${JSON.stringify(err)}`)); + } + }); + } else { + reject(new Error('认证失败,未获取到有效的用户 ID')); + } + }, + fail: (err) => { + reject(new Error(`请求失败: ${JSON.stringify(err)}`)); + } + }); + }) + .catch((error) => { + dd.showToast({ + content: error.message, + type: 'none', + duration: 3000, + success() { + console.log('toast end'); + } + }); + }); + }, + onReset() { + dd.clearStorageSync(); + this.setData({ + apiurl: '', + username: '', + password: '' + }); + }, + //失去聚焦触发根据url获取数据库列表 + postdb(e) { + const apiurl = e.detail.value; + console.log(apiurl) + if (!apiurl) { + return; + } + const data = { + "jsonrpc": "2.0", + "method": "call", + "params": { + "service": "db", + "method": "list", + "args": [] + }, + "id": 1 + }; + + new Promise((resolve, reject) => { + dd.httpRequest({ + url: `${apiurl}/jsonrpc`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + data: JSON.stringify(data), + success: (res) => { + if (res.statusCode < 200 || res.statusCode >= 300) { + reject(new Error(`HTTP error! status: ${res.statusCode}`)); + return; + } + const result = res.data; + if ('error' in result) { + resolve([]); + } else if ('result' in result) { + if (result['result'].length > 0) { + // this.setData({ + // username: '', + // password: '', + // }); + } + resolve(result['result']); + } else { + reject(new Error('请求发生错误')); + } + }, + fail: (err) => { + reject(err); + } + }); + }) + .then((databaseList) => { + this.setData({ + databaseList, + }); + if (databaseList.length > 0) { + this.setData({ + databaseName: databaseList[0], + index: 0, + apiurl: apiurl + }); + dd.showToast({ + content: '成功获取可用数据库列表', + type: 'success', + duration: 1000, + success() { + console.log('toast end'); + }, + }); + } else { + dd.showToast({ + content: '未获取到可用的数据库。', + type: 'none', + duration: 1000, + success() { + console.log('toast end'); + }, + }); + } + }) + .catch((error) => { + dd.showToast({ + content: '请求发生错误', + type: 'none', + duration: 1000, + success() { + console.log('toast end'); + }, + fail() { + console.log(error.message); + } + }); + }); + }, + // + //数据库列表选择逻辑层获取name值 + bindPickerChange(e) { + const selectedDatabase = this.data.databaseList[e.detail.value]; // 根据索引获取数据库名称 + if (selectedDatabase) { + this.setData({ + databaseName: selectedDatabase, // 设置数据库名称 + index: e.detail.value, // 更新索引 + }); + } else { + console.log('未找到对应的数据库'); + } + }, + // +}); \ No newline at end of file diff --git a/pages/index/index.json b/pages/index/index.json new file mode 100644 index 0000000..9d7e4af --- /dev/null +++ b/pages/index/index.json @@ -0,0 +1,3 @@ +{ + "defaultTitle": "访问" +} \ No newline at end of file diff --git a/pages/storage/storage.acss b/pages/storage/storage.acss new file mode 100644 index 0000000..e69de29 diff --git a/pages/storage/storage.axml b/pages/storage/storage.axml new file mode 100644 index 0000000..def5d45 --- /dev/null +++ b/pages/storage/storage.axml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/pages/storage/storage.js b/pages/storage/storage.js new file mode 100644 index 0000000..8299071 --- /dev/null +++ b/pages/storage/storage.js @@ -0,0 +1,56 @@ +Page({ + data: { + + }, + onLoad(query) { + // 页面加载 + console.info(`Page onLoad with query: ${JSON.stringify(query)}`); + }, + onReady() { + // 页面加载完成 + }, + onShow() { + // 页面显示 + }, + onHide() { + // 页面隐藏 + }, + onUnload() { + // 页面被关闭 + }, + onTitleClick() { + // 标题被点击 + }, + onPullDownRefresh() { + // 页面被下拉 + }, + onReachBottom() { + // 页面被拉到底部 + }, + onShareAppMessage() { + // 返回自定义分享信息 + return { + title: 'My App', + desc: 'My App description', + path: 'pages/index/index', + }; + }, + // + clearStorage() { + try { + dd.clearStorageSync(); + console.log('本地缓存已清空'); + dd.reLaunch({ + url: '/pages/index/index', + success: () => { + }, + fail: (err) => { + console.error('页面跳转失败:', err); + } + }); + } catch (e) { + console.error('清空本地缓存失败', e); + } + } + // +}); \ No newline at end of file diff --git a/pages/storage/storage.json b/pages/storage/storage.json new file mode 100644 index 0000000..a97367d --- /dev/null +++ b/pages/storage/storage.json @@ -0,0 +1,3 @@ +{ + "usingComponents": {} +} diff --git a/pages/ulti/jsonrpc.js b/pages/ulti/jsonrpc.js new file mode 100644 index 0000000..0e5a15e --- /dev/null +++ b/pages/ulti/jsonrpc.js @@ -0,0 +1,37 @@ +export default function jsonrpc(loginInfo, data) { + if (!loginInfo.apiurl) { + return Promise.reject(new Error('API URL is missing')); + } + + return new Promise((resolve, reject) => { + dd.httpRequest({ + url: `${loginInfo.apiurl}/jsonrpc`, + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + data: JSON.stringify(data), + success: (res) => { + // console.log(`响应状态码: ${res.statusCode}`); + if (res.statusCode < 200 || res.statusCode >= 300) { + reject(new Error(`HTTP error! status: ${res.statusCode}`)); + return; + } + const result = res.data; + // console.log(`接收到的 JSON - RPC 响应数据: ${JSON.stringify(result)}`); + if (Object.prototype.hasOwnProperty.call(result, 'error')) { + console.error('获取订单数据失败:', result.error); + reject(new Error(`获取订单数据失败: ${JSON.stringify(result.error)}`)); + return; + } + const ObjectData = result.result; + console.log('获取订单数据成功:', ObjectData); + resolve(ObjectData); + }, + fail: (err) => { + console.error('请求失败:', err); + reject(new Error(`请求失败: ${JSON.stringify(err)}`)); + } + }); + }); +} diff --git a/snapshot.png b/snapshot.png new file mode 100644 index 0000000..3a78436 Binary files /dev/null and b/snapshot.png differ