first commit

This commit is contained in:
XiaoJia Chen 2025-04-15 01:51:54 +08:00
commit 40c821350f
47 changed files with 2816 additions and 0 deletions

22
.gitignore vendored Normal file
View File

@ -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

96
app.acss Normal file
View File

@ -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;
}

11
app.js Normal file
View File

@ -0,0 +1,11 @@
App({
onLaunch(options) {
// 第一次打开
// options.query == {number:1}
console.info('App onLaunch 胜佳');
},
onShow(options) {
// 从后台被 scheme 重新打开
// options.query == {number:1}
},
});

39
app.json Normal file
View File

@ -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"
}
}

42
docs.md Normal file
View File

@ -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',
};
},
});
```

View File

@ -0,0 +1,80 @@
<view>
<!-- 蓝牙启动关闭开关 = 初始化蓝牙 关闭本机蓝牙 开关 -->
<view class="page">
<view class="page-description">开关</view>
<view class="page-section">
<view class="page-section-demo switch-list">
<view class="switch-item">
<!-- checked:是否被选中初始状态默认开关 onChangechecked 改变时触发event.detail={value:checked}。 -->
<switch onChange="switchopenBluetoothAdapter" aria-label="{{switchopenBluetoothAdapter ? 'switch opened' : 'switch closed'}}" />
</view>
</view>
</view>
</view>
是否正在搜索设备{{discovering}}
蓝牙模块是否可用需支持 BLE 并且蓝牙是打开状态{{available}}
<!-- 开始搜索 停止搜索开关 开关 -->
<view class="page">
<view class="page-description">开关</view>
<view class="page-section">
<view class="page-section-demo switch-list">
<view class="switch-item">
<!-- checked:是否被选中初始状态默认开关 onChangechecked 改变时触发event.detail={value:checked}。 -->
<switch onChange="startBluetoothDevicesDiscovery" aria-label="{{startBluetoothDevicesDiscovery ? 'switch opened' : 'switch closed'}}" />
</view>
</view>
</view>
</view>
<view class="page">
<view class="page-description">图标</view>
<view class="page-section">
<view class="page-section-title">Type</view>
<view class="page-section-demo icon-list">
<block a:for="{{iconType}}">
<view class="item">
<icon type="{{item}}" aria-label="{{item}}" size="45" />
<text>{{item}}</text>
</view>
</block>
</view>
</view>
<view class="page">
<view class="page-description">单选框</view>
<view class="page-section">
<view class="section section_gap">
<form onSubmit="onSubmit" onReset="onReset">
<view class="page-section-demo">
<radio-group
class="radio-group"
onChange="radioChange"
name="lib"
>
<label a:for="{{devices}}" class="radio" key="label-{{index}}">
<radio
value="{{item.deviceId}}"
checked="{{item.checked}}"
disabled="{{item.disabled}}"
/>
<text class="radio-text">{{item.name}}</text>
</label>
</radio-group>
</view>
<view class="page-section-btns">
<view>
<button size="mini" type="ghost" formType="reset">待开发</button></view>
<view>
<button size="mini" type="primary" formType="submit">连接并打印</button></view>
</view>
</form>
</view>
</view>
</view>
指令集选择 下拉选择框
蓝牙选择框+选择+打印+清空查找更多蓝牙 devices 单选列表框
已经连接蓝牙名名称文本 文本 状态一行
获取蓝牙状态 有两个标识 打勾 状态一行
</view>

View File

@ -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);
}
}
});

View File

@ -0,0 +1,3 @@
{
"component": true
}

24
pages/deal/deal.acss Normal file
View File

@ -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;
}

5
pages/deal/deal.axml Normal file
View File

@ -0,0 +1,5 @@
<view class="nav-container">
<navigator open-type="navigate" url="/pages/deal/saleOrder/saleOrder" hover-class="navigator-hover" class="nav-button">销售</navigator>
<bluetooth-component/>
</view>

38
pages/deal/deal.js Normal file
View File

@ -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',
};
},
});

3
pages/deal/deal.json Normal file
View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -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;
}

View File

@ -0,0 +1,20 @@
<view class="page">
<view class="page-description">多项选择器</view>
<form onSubmit="onSubmit" onReset="onReset">
<view class="page-section">
<view class="page-section-title">选择你用过的框架:</view>
<view class="page-section-demo">
<checkbox-group onChange="onChange" name="libs">
<label class="checkbox order-item" a:for="{{items}}" key="label-{{index}}">
<checkbox value="{{item.id}}" checked="{{item.checked}}" disabled="{{item.disabled}}" />
<text class="checkbox-text">货号:{{item.name}} 色号:{{item.color_id_2[1]}} 细码:{{item.fineCode3Names}}</text>
</label>
</checkbox-group>
</view>
<view class="page-section-btns">
<view><button type="ghost" size="mini">重置</button></view>
<view><button type="primary" size="mini" formType="submit">提交</button></view>
</view>
</view>
</form>

View File

@ -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);
}
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -0,0 +1,3 @@
<view>
</view>

View File

@ -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
});
},
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -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;
}

View File

@ -0,0 +1,24 @@
<view>
<view>
<rich-text nodes="{{nodes}}" onTap="tap"></rich-text>
</view>
<view class="cart-bottom">
<view class="cart-info">
</view>
<navigator
open-type="navigate"
url="/pages/deal/saleOrder/kanban/saleOrderKanban"
class="confirm-button"
>
返回
</navigator>
<navigator
open-type="navigate"
url="/pages/deal/saleOrder/kanban/from/printTag/printTemplate/bluetooth/bluetooth"
class="confirm-button"
>
确认
</navigator>
</view>
</view>

View File

@ -0,0 +1,55 @@
Page({
data: {
nodes: [{
name: 'div',
attrs: {
class: 'wrapper',
style: 'color: orange;',
},
children: [{
type: 'text',
text: 'Hello&nbsp;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');
},
//
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -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;
}

View File

@ -0,0 +1,203 @@
<!-- components/BasicInfoTab/BasicInfoTab.aml -->
<view>
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">客户</view>
<input
name="databaseName"
class="form-row-content"
value="{{selectedOrder.partner_id[1]}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">地址</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">销售日期</view>
<input
name="databaseName"
class="form-row-content"
value="{{selectedOrder.date_order}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">计划收款日期</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">送货日期</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">默认仓库</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">业务员</view>
<input
name="databaseName"
class="form-row-content"
value="{{selectedOrder.user_id[1]}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">销售单号</view>
<input
name="databaseName"
class="form-row-content"
value="{{selectedOrder.name}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<view>
<tag>税率</tag>
</view>
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">订单金额</view>
<input
name="databaseName"
class="form-row-content"
value="{{selectedOrder.orde_ddje}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">优惠金额</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">合同金额</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">非产品费用</view>
<input
name="databaseName"
class="form-row-content"
value="{{}}"
placeholder="预留位置等待开发修改销售单数据"
/>
</view>
</picker>
</view>
<!-- -->
<view class="cart-bottom">
<view class="cart-info">
</view>
<navigator
open-type="navigate"
url="/pages/deal/saleOrder/kanban/saleOrderKanban"
class="confirm-button"
>
确认
</navigator>
<navigator
open-type="navigate"
url="/pages/deal/saleOrder/kanban/from/printTag/printTag"
class="confirm-button"
>
打印
</navigator>
</view>

View File

@ -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',
};
},
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -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;
}

View File

@ -0,0 +1,34 @@
<view>
<progress percent="{{isloading}}" active style="background-color: #e0e0e0; height: 10px; border-radius: 5px;" />
<view
a:for="{{combinedOrders}}"
a:key="id"
class="order-item"
onTap="handleTap"
data-info="{{item.id}}"
>
<view class="order-extra">{{item.date_order || '无订单日期'}}</view>
<view class="order-details order-title">{{item.name || '无订单名称'}}</view>
<view class="order-extra">总金额:{{item.amount_total || '无'}}</view>
<view class="order-details">{{item.partner_id[1] || '无客户名称'}}</view>
<view a:if="{{item.orderLines.length > 0}}">
<view a:for="{{item.orderLines}}" a:key="id" class="order-line-item">
<view class="order-extra">数量: {{item.product_uom_qty || '无数量'}}</view>
<view class="order-details order-title">货号: {{item.product_id? item.product_id[1] : '无产品名称'}}</view>
</view>
</view>
</view>
<view class="pagination">
<button disabled="{{currentPage === 1}}" onTap="handlePreviousPage" class="pagination-button disabled-button">上一页</button>
<text class="pagination-text">第 {{currentPage}} 页 / 共 {{totalRecords / pageSize}} 页</text>
<button
disabled="{{isLoading || currentPage === Math.ceil(totalRecords / pageSize)}}"
onTap="handleNextPage"
class="pagination-button"
>
下一页
</button>
</view>
</view>

View File

@ -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);
}
});
}
},
//
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

View File

@ -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;
}

View File

@ -0,0 +1,99 @@
<view>
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">客户</view>
<input
name="databaseName"
class="form-row-content"
value="{{[]}}"
placeholder="预留位置等待开发创建销售单"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">日期</view>
<input
name="databaseName"
class="form-row-content"
value="{{[]}}"
placeholder="预留位置等待开发创建销售单"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">默认仓库</view>
<input
name="databaseName"
class="form-row-content"
value="{{[]}}"
placeholder="预留位置等待开发创建销售单"
/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker >
<view class="form-row">
<view class="form-row-label">业务员</view>
<input
name="databaseName"
class="form-row-content"
value="{{[]}}"
placeholder="预留位置等待开发创建销售单"
/>
</view>
</picker>
</view>
<!-- -->
<view class="page-section">
<view class="page-section-title"></view>
<view class="page-section-demo">
<checkbox-group>
<view>
<label>
<checkbox value="客户货号" />
<text> 客户货号</text>
</label>
<label>
<checkbox value="进价" />
<text> 进价</text>
</label>
<label>
<checkbox value="+/-" />
<text> +/-</text>
</label>
</view>
</checkbox-group>
</view>
</view>
<!-- -->
<navigator open-type="redirect" hover-class="navigator-hover">产品列表</navigator>
<!-- -->
<!-- -->
<view class="cart-bottom">
<view class="cart-info">
</view>
<navigator
open-type="navigate"
url="/pages/deal/saleOrder/kanban/saleOrderKanban"
class="confirm-button"
>
确认
</navigator>
</view>
<!-- -->
</view>

View File

@ -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',
};
},
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

3
pages/index/index.acss Normal file
View File

@ -0,0 +1,3 @@
button + button {
margin-top: 32rpx;
}

54
pages/index/index.axml Normal file
View File

@ -0,0 +1,54 @@
<view class="page">
<form onSubmit="onSubmit" onReset="onReset">
<view class="page-section">
<view class="form-line" />
<view class="form-row">
<!-- -->
<view class="form-row-label">地址</view>
<view class="form-row-content">
<input name="apiurl" class="input" placeholder="https://" onBlur="postdb" />
</view>
</view>
<!-- -->
<!-- -->
<view class="page-section">
<picker onChange="bindPickerChange" value="{{index}}" range="{{databaseList}}" >
<view class="form-row">
<view class="form-row-label">账套</view>
<input name="databaseName" class="form-row-content" value="{{databaseList[index]}}" placeholder="****"/>
</view>
</picker>
</view>
<!-- -->
<!-- -->
<view class="form-row">
<view class="form-row-label">用户</view>
<view class="form-row-content">
<input name="username" class="input" placeholder="***@**.com" />
</view>
</view>
<!-- -->
<!-- -->
<view class="form-row">
<view class="form-row-label">密码</view>
<view class="form-row-content">
<input name="password" class="input" placeholder="*****" password />
</view>
</view>
<!-- -->
<!-- -->
<view class="page-section-btns">
<view>
<button type="ghost" size="mini" formType="reset">重置</button></view>
<view>
<button type="primary" size="mini" formType="submit">提交</button></view>
</view>
</view>
<!-- -->
</form>
<view class="page-section">
<view class="page-section-demo">
<text> v1.0.9 </text>
</view>
</view>
</view>

329
pages/index/index.js Normal file
View File

@ -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('未找到对应的数据库');
}
},
//
});

3
pages/index/index.json Normal file
View File

@ -0,0 +1,3 @@
{
"defaultTitle": "访问"
}

View File

View File

@ -0,0 +1,3 @@
<view>
<button type="primary" loading onTap="clearStorage">清除缓存并退出</button>
</view>

56
pages/storage/storage.js Normal file
View File

@ -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);
}
}
//
});

View File

@ -0,0 +1,3 @@
{
"usingComponents": {}
}

37
pages/ulti/jsonrpc.js Normal file
View File

@ -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)}`));
}
});
});
}

BIN
snapshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB