huangxw 1 viikko sitten
vanhempi
säilyke
09dfa91a1e

+ 4 - 1
src/plant/export-print/models/export-print-confirm.vue

@@ -154,6 +154,7 @@ const upFormUpRef = ref();
 const emit = defineEmits(['next', 'prev', 'formdata']);
 const form = ref<any>({
     printCount: props.opts?.printedCount,
+    printType: '2', // 打印类型 1-喷印 2-排版
     extraInfo: {
         fileType: '1',
         fileFormat: '1',
@@ -259,8 +260,10 @@ const submitForm = async () => {
         ...props.opts,
         ...form.value,
     };
-    const res = props.opts?.id ? await useClientRequest.get(`/plt-api/app/printLog/update/${props.opts.id}`, payload?.extraInfo) : await useClientRequest.post('/plt-api/app/printLog/printNext', payload);
+    const res = props.opts?.id ? await useClientRequest.post(`/plt-api/app/printLog/update/${props.opts.id}`, payload?.extraInfo) : await useClientRequest.post('/plt-api/app/printLog/printNext', payload);
     if (!res || res.code !== 200) return;
+    console.log(res);
+    
     uni.$emit('refreshPackTaskList');
     uni.$emit('refreshPackTaskDetail');
     await useClientRequest.get(`/plt-api/app/printLog/export/${res.data?.id || props.opts?.id}`);

+ 6 - 1
src/plant/models/pack-card.vue

@@ -46,8 +46,13 @@
                     <span class="c-#666">待打印数量:</span>
                     <span class="c-#333 f-w-5">{{ item?.actualCount - item?.printCount }}{{ item?.unit }}</span>
                 </view>
+                <template v-if="+item?.restCapacity">
+                    <view class="c-#666 f-s-24">
+                        <span>首{{ item?.unit }}为{{ item?.restCapacity }}{{ item?.storageUseUnit }}</span>
+                        <span v-if="item?.restCode">,追溯码:{{ item?.restCode }}</span>
+                    </view>
+                </template>
             </view>
-          
             <slot></slot>
         </view>
     </view>

+ 71 - 13
src/plant/print/models/connect-printer.vue

@@ -12,7 +12,7 @@
 
         <!-- 操作按钮区域 -->
         <view class="pd-24 action-buttons">
-            <up-button @click="handleStartSearch" class="mb-30" type="primary" :disabled="isConnected">
+            <up-button @click="handleStartSearch" class="mb-30" type="primary" :disabled="isSearching">
                 {{ isSearching ? '搜索中...' : '开始搜索' }}
             </up-button>
             <view class="d-flex a-c j-c">
@@ -41,7 +41,8 @@
                         <view v-if="device.RSSI !== undefined" class="signal-strength"> 信号:{{ device.RSSI }} dBm </view>
                     </view>
                     <view class="device-status">
-                        <text v-if="connectedDevice?.deviceId === device.deviceId" class="status-connected">已连接</text>
+                        <text v-if="isConnecting && connectingDeviceId === device.deviceId" class="status-new">连接中...</text>
+                        <text v-else-if="connectedDevice?.deviceId === device.deviceId" class="status-connected">已连接</text>
                         <text v-else class="status-new">未连接</text>
                     </view>
                 </view>
@@ -56,7 +57,7 @@
 </template>
 
 <script setup lang="ts">
-import { checkBluetoothPermission, initBluetoothAdapter, getBluetoothAdapterState, startBluetoothDevicesDiscovery, stopBluetoothDevicesDiscovery, connectBLEDevice, closeBLEConnection, getBLEDeviceServicesAndCharacteristics, getBluetoothDevices } from '@/utils/blue-device-services';
+import { checkBluetoothPermission, initBluetoothAdapter, getBluetoothAdapterState, startBluetoothDevicesDiscovery, stopBluetoothDevicesDiscovery, connectBLEDevice, closeBLEConnection, getBLEDeviceServicesAndCharacteristics, getBluetoothDevices, onBLEConnectionStateChange } from '@/utils/blue-device-services';
 const props = defineProps({
     info: {
         type: Object,
@@ -76,10 +77,12 @@ const props = defineProps({
 const emit = defineEmits(['connected', 'disconnected', 'next', 'prev']);
 const isSearching = ref(false);
 const isInitialized = ref(false);
+const isConnecting = ref(false);
+const connectingDeviceId = ref('');
 const devices = ref<Array<any>>([]);
 const connectedDevice = ref<any | null>(null);
-const isConnected = computed(() => !!connectedDevice.value);
 let stopDiscoveryListener: (() => void) | null = null;
+let stopConnectionStateListener: (() => void) | null = null;
 let searchTimeout: number | null = null;
 
 const toast = (title: string) => {
@@ -88,8 +91,9 @@ const toast = (title: string) => {
 
 const updateDeviceList = (device: any) => {
     if (!device?.deviceId) return;
-    if (device.name.startsWith('未知或不支持的设备')) return;
-    if (!device.name.startsWith('GP-')) return;
+    const deviceName = device.name || '';
+    if (deviceName.startsWith('未知或不支持的设备')) return;
+    if (!deviceName.startsWith('GP-')) return;
     const idx = devices.value.findIndex((d) => d.deviceId === device.deviceId);
     if (idx >= 0) {
         devices.value[idx] = { ...devices.value[idx], ...device };
@@ -134,12 +138,33 @@ const initBluetooth = async () => {
     }
 };
 
+const setupConnectionStateListener = () => {
+    if (stopConnectionStateListener) return;
+
+    stopConnectionStateListener = onBLEConnectionStateChange(async (res: any) => {
+        if (!res?.deviceId || res.connected) return;
+        if (connectedDevice.value?.deviceId !== res.deviceId) return;
+
+        const disconnectedDeviceId = connectedDevice.value.deviceId;
+        connectedDevice.value = null;
+
+        try {
+            await closeBLEConnection(disconnectedDeviceId);
+        } catch {
+            // ignore
+        }
+
+        emit('disconnected', { deviceId: disconnectedDeviceId, reason: 'connection-lost' });
+        toast('设备连接已断开');
+    });
+};
+
 const handleStartSearch = async () => {
     if (isSearching.value) return;
 
     if (!isInitialized.value) {
-        toast('请先初始化蓝牙,再开始搜索');
-        return;
+        await initBluetooth();
+        if (!isInitialized.value) return;
     }
 
     isSearching.value = true;
@@ -188,13 +213,31 @@ const handleConnectDevice = async (device: any) => {
         return;
     }
 
+    if (isConnecting.value) {
+        toast('正在连接,请稍候');
+        return;
+    }
+
     if (connectedDevice.value?.deviceId === device.deviceId) {
         toast('已连接该设备');
         return;
     }
 
     try {
+        isConnecting.value = true;
+        connectingDeviceId.value = device.deviceId;
+
         await stopSearch();
+
+        if (connectedDevice.value?.deviceId) {
+            try {
+                await closeBLEConnection(connectedDevice.value.deviceId);
+            } catch {
+                // ignore
+            }
+            connectedDevice.value = null;
+        }
+
         await connectBLEDevice(device.deviceId);
 
         const { services, characteristicsMap } = await getBLEDeviceServicesAndCharacteristics(device.deviceId);
@@ -232,24 +275,33 @@ const handleConnectDevice = async (device: any) => {
             characteristicId,
         };
         updateDeviceList(connectedDevice.value);
+        emit('connected', connectedDevice.value);
 
         toast('蓝牙已连接');
     } catch (error: any) {
         console.error('连接失败', error);
         toast(error?.message || '设备连接失败,请重试');
+    } finally {
+        isConnecting.value = false;
+        connectingDeviceId.value = '';
     }
 };
 
-const handleDisconnect = async () => {
+const handleDisconnect = async (silent = false) => {
     if (!connectedDevice.value?.deviceId) return;
 
+    const deviceId = connectedDevice.value.deviceId;
+
     try {
-        await closeBLEConnection(connectedDevice.value.deviceId);
-        toast('已断开连接');
+        await closeBLEConnection(deviceId);
+        if (!silent) {
+            toast('已断开连接');
+        }
     } catch (error) {
         console.warn('断开连接失败', error);
     }
     connectedDevice.value = null;
+    emit('disconnected', { deviceId, reason: 'manual-disconnect' });
 };
 const nextSteps = () => {
     if (!connectedDevice.value || !connectedDevice.value?.deviceId || !connectedDevice.value?.serviceId) {
@@ -272,10 +324,16 @@ const prevSteps = () => {
     });
 };
 onMounted(() => {
+    setupConnectionStateListener();
     initBluetooth();
 });
-onBeforeUnmount(() => {
-    stopSearch();
+onBeforeUnmount(async () => {
+    await stopSearch();
+    if (connectedDevice.value?.deviceId) {
+        await handleDisconnect(true);
+    }
+    stopConnectionStateListener?.();
+    stopConnectionStateListener = null;
 });
 </script>
 

+ 5 - 2
src/plant/print/models/print-tem.ts

@@ -4,12 +4,15 @@ export const tem30x30 = (command: any, info: any[], item: any) => {
     const leftInfo = info[0];
     const rightInfo = info?.[1];
     command.setText(30, 10, 'TSS16.BF2', 1, 1, '品名:' + item.proName);
-    command.setText(30, 30, 'TSS16.BF2', 1, 1, '数量(重量):' + item.specn);
+    command.setText(30, 40, 'TSS16.BF2', 1, 1, '数量(重量):' + item.specn);
     command.setQR(55, 75, 'L', 4, 'A', leftInfo.url);
+    // 底部加sn序号
+    command.setText(80, 190, 'TSS16.BF2', 1, 1, leftInfo.padSn);
     if (rightInfo) {
         command.setText(280, 10, 'TSS16.BF2', 1, 1, '品名:' + item.proName);
-        command.setText(280, 30, 'TSS16.BF2', 1, 1, '数量(重量):' + item.specn);
+        command.setText(280, 40, 'TSS16.BF2', 1, 1, '数量(重量):' + item.specn);
         command.setQR(315, 75, 'L', 4, 'A', rightInfo.url);
+        command.setText(330, 190, 'TSS16.BF2', 1, 1, rightInfo.padSn);
     }
     return command;
 };

+ 0 - 1
src/plant/print/print-all/index.vue

@@ -26,7 +26,6 @@ import PrintWrapper from '../models/print-wrapper.vue';
 import { writeBLECharacteristicSend } from '@/utils/blue-device-services';
 import jpPrinter from '../models/tspl';
 import { useClientRequest } from '@/utils/request';
-import RangePrint from '../models/range-print.vue';
 const printSpec = ref('30x30');
 const printCodes = async (data: any) => {
     printSpec.value = data.printSpec;

+ 46 - 4
src/utils/blue-device-services.ts

@@ -38,6 +38,8 @@ export async function checkBluetoothPermission(): Promise<void> {
 }
 
 export async function initBluetoothAdapter(): Promise<void> {
+    type BluetoothMode = 'central' | 'peripheral';
+
     const closeAdapter = () =>
         new Promise<void>((resolve) => {
             uni.closeBluetoothAdapter({
@@ -46,15 +48,21 @@ export async function initBluetoothAdapter(): Promise<void> {
             });
         });
 
-    const openAdapter = () =>
+    const openAdapter = (mode?: BluetoothMode) =>
         new Promise<void>((resolve, reject) => {
-            uni.openBluetoothAdapter({
+            const options: any = {
                 success: () => resolve(),
                 fail: (err) => {
                     console.log(err);
                     reject(new Error(err.errMsg || `openBluetoothAdapter 失败`));
                 },
-            });
+            };
+
+            if (mode) {
+                options.mode = mode;
+            }
+
+            uni.openBluetoothAdapter(options);
         });
 
     // 先尝试关闭现有 adapter,避免重复初始化导致的异常
@@ -64,7 +72,21 @@ export async function initBluetoothAdapter(): Promise<void> {
     const platform = uni.getSystemInfoSync?.()?.platform || '';
     console.log(platform, 'initBluetoothAdapter platform');
 
-    // Android 等其他平台只需 central 模式
+    if (platform === 'ios') {
+        // iOS 在 central/peripheral 两种模式都初始化一次,且需显式指定 mode。
+        await closeAdapter();
+        await openAdapter('central');
+
+        await closeAdapter();
+        await openAdapter('peripheral');
+
+        // 最终回到 central,保证后续扫描/连接 BLE 外设稳定可用。
+        await closeAdapter();
+        await openAdapter('central');
+        return;
+    }
+
+    // Android 等其他平台保持默认初始化流程
     await openAdapter();
 }
 
@@ -134,6 +156,26 @@ export async function closeBLEConnection(deviceId: string): Promise<void> {
     });
 }
 
+export function onBLEConnectionStateChange(onChange: (res: any) => void): () => void {
+    const listener = (res: any) => {
+        onChange(res);
+    };
+
+    uni.onBLEConnectionStateChange(listener);
+
+    return () => {
+        try {
+            uni.offBLEConnectionStateChange(listener);
+        } catch {
+            try {
+                uni.offBLEConnectionStateChange();
+            } catch {
+                // ignore
+            }
+        }
+    };
+}
+
 export async function getBluetoothDevices(): Promise<any[]> {
     return new Promise((resolve, reject) => {
         uni.getBluetoothDevices({