ソースを参照

增加小程序日志, 运行环境判断, 打印优化等

“shengjie.huang” 1 年間 前
コミット
628dd44ced

+ 1 - 1
env/.env

@@ -2,7 +2,7 @@ VITE_APP_TITLE = 'printer-miniapp'
 VITE_APP_PORT = 9000
 
 VITE_UNI_APPID = '__UNI__DD53B81'
-VITE_WX_APPID = 'wx46467fc3f5573a68'
+VITE_WX_APPID = 'wx3b8d4805a9249482'
 
 # h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
 VITE_APP_PUBLIC_BASE = /printer-h5/

+ 1 - 1
src/interceptors/request.ts

@@ -43,7 +43,7 @@ const httpInterceptor = {
       // TIPS: 如果需要对接多个后端服务,也可以在这里处理,拼接成所需要的地址
     }
     // 1. 请求超时
-    options.timeout = options.timeout || 20000 // 20s
+    options.timeout = options.timeout || 120000 // 120s
     // 2. (可选)添加小程序端请求头标识
     options.header = {
       platform, // 可选,与 uniapp 定义的平台一致,告诉后台来源

+ 1 - 1
src/manifest.json

@@ -83,7 +83,7 @@
   },
   "quickapp": {},
   "mp-weixin": {
-    "appid": "wx46467fc3f5573a68",
+    "appid": "wx3b8d4805a9249482",
     "setting": {
       "urlCheck": false
     },

+ 29 - 13
src/pages/assistant/detail.vue

@@ -100,23 +100,36 @@ defineOptions({
   name: 'UserHubDetail',
 })
 
-function getDetailById(id: string) {
+function getDetailById(id: string, success?: any, fail?: any) {
   getUserHub(id).then((res: any) => {
     if (res.code == 0 && res.body) {
       formData.value = res.body || { }
+      if (success) success()
+    } else {
+      if (fail) fail()
     }
+  }).catch((error) => {
+    console.log(error)
   })
 }
 
 function scanQRCode() {
   uni.scanCode({
     success: (res) => {
-      formData.value.hostname = res.result
+      if (res.scanType == 'WX_CODE') {
+        if (res.path.includes('scene=')) {
+          formData.value.hostname = res.path.split('scene=')[1] || ""
+        } else {
+          toast.warning("暂未能识别该小程序码")
+        }
+      } else {
+        formData.value.hostname = res.result
+      }
     },
     fail: (err) => {
       console.log('err: ', err);
       toast.error('扫码失败')
-    },
+    }
   })
 }
 
@@ -149,18 +162,21 @@ function handleSubmit() {
 }
 
 onLoad((option) => {
-  // 通过分享传参
+  // 通过分享场景参数scene带入数据
   type.value = option.type || "add"
   if (type.value == 'add' && option.scene) {
-    formData.value.hostname = option.scene
-    formData.value.asname = option.scene
-    message.confirm({
-      msg: `是否添加设备"${option.scene}"到我的打印助手`,
-      closeOnClickModal: false,
-    }).then(() => {
-      handleSubmit()
-    }).catch((error) => {
-    })
+    // 分享情况下的格式: share_xxxx
+    if (option.scene.startsWith("share_")) {
+      let id = option.scene.split('_')[1]
+      getDetailById(id, () => {
+        toast.success("已填入设备信息")
+      }, () => {
+        toast.error("查询设备信息失败, 请稍后重试")
+      })
+    } else {
+      // 设备扫码添加
+      formData.value.hostname = option.scene
+    }
   }
   if (option && option.id) getDetailById(option.id)
 })

+ 11 - 4
src/pages/assistant/index.vue

@@ -32,7 +32,7 @@
         <view v-for="item of dataList" :key="item.id" class="list-box" @click="toDetail('view', item.id)">
           <view class="name">
             <view class="main-text">
-              <view>{{ item.asname }}</view>
+              <view class="inline-text">{{ item.asname }}</view>
               <wd-tag :type="item.onlineStatus == 'online' ? 'success' : 'danger'" mark custom-class="ml-2">
                 {{ getLabel(item.onlineStatus || 'offline', onlineStatus) }}
               </wd-tag>
@@ -280,7 +280,8 @@ onReachBottom(() => {
 onShareAppMessage(() => {
   return {
     title: "分享设备:给你分享了一个打印助手,可点击添加",
-    path: `pages/assistant/detail?scene=${currentData.value.hostname}`,
+    path: `pages/assistant/detail?scene=share_${currentData.value.id}`,
+    // path: `pages/assistant/detail?scene=${currentData.value.hostname}`,
     imageUrl: deviceImgSrc.value,
   }
 })
@@ -328,8 +329,14 @@ onShareAppMessage(() => {
     .name {
       flex: 1;
       .main-text {
-        display: flex;
-        align-items: center;
+        word-break: break-all;
+        vertical-align: middle;
+
+        .inline-text {
+          display: inline;
+          vertical-align: middle;
+          word-break: break-all;
+        }
       }
       .sub-text {
         margin-top: 20rpx;

+ 16 - 8
src/pages/index/index.vue

@@ -101,6 +101,7 @@ defineOptions({
   name: 'Home',
 })
 
+const deviceInfo = uni.getDeviceInfo()  // 更多系统信息用 getSystemInfoSync
 const toast = useToast()
 const isLogined = computed(() => !!useUserStore().token)
 const nvRef: any = ref()
@@ -162,16 +163,10 @@ function toUserHub() {
 }
 
 function openWebView() {
-  const url = "https://service.1ai.ltd/webview-upload/index.html"
-  uni.navigateTo({
-    url: `/pages/webview/index?url=${encodeURIComponent(url)}`,
-  })
-}
-
-function toPrint(accept) {
   if (isLogined.value) {
+    const url = "https://service.1ai.ltd/webview-upload/index.html"
     uni.navigateTo({
-      url: `/pages/print/index?accept=${accept}`,
+      url: `/pages/webview/index?url=${encodeURIComponent(url)}`,
     })
   } else {
     toast.warning('请先前往登录')
@@ -179,6 +174,19 @@ function toPrint(accept) {
   }
 }
 
+function toPrint(accept) {
+  if (!isLogined.value) {
+    toast.warning('请先前往登录')
+    toLogin(1500)
+  } else if (['windows', 'mac'].includes(deviceInfo.platform) && accept != 'image') {
+    toast.warning('PC版小程序不支持该功能,请使用手机打开')
+  } else {
+    uni.navigateTo({
+      url: `/pages/print/index?accept=${accept}`,
+    })
+  }
+}
+
 function developing() {
   toast.warning('该功能开发中...')
 }

+ 1 - 5
src/pages/login/index.vue

@@ -115,11 +115,7 @@ function onGetPhoneNumber(detail) {
 		} else {
 			tips = "验证失败,请稍后重试"
 		}
-    uni.showToast({
-      title: tips,
-      icon: "none",
-      duration: 2000
-    })
+    toast.warning(tips)
   }
 }
 

+ 143 - 34
src/pages/print/index.vue

@@ -161,11 +161,10 @@ import {
   testByIP,
   getAttrByLocal
 } from '@/service/api'
-import { getEnvBaseUrl, redirectToUpload, reLaunchToHome } from '@/utils'
-import { useUserStore } from '@/store'
+import { getEnvBaseUrl, redirectToUpload, reLaunchToHome, logManager } from '@/utils'
 
-const userStore = useUserStore()
-const token = userStore.token
+const deviceInfo = uni.getDeviceInfo()  // 更多系统信息用 getSystemInfoSync
+const fs = wx.getFileSystemManager();
 const baseUrl = getEnvBaseUrl()
 const toast = useToast()
 const message = useMessage()
@@ -239,7 +238,8 @@ function checkUserHub() {
         }
       });
     }
-  }).catch(() => {
+  }).catch((err) => {
+    console.log('getUserHubPage catch: ', err);
   })
 }
 
@@ -250,7 +250,9 @@ function checkIP(ip, userHubId) {
       userHubList.value.find(i => i.id == userHubId).isIntranet = true
       updateShowName()
     }
-  }).catch(() => {})
+  }).catch((err) => {
+    console.log('checkIP catch: ', err);
+  })
 }
 
 // 更新打印机展示名称
@@ -276,7 +278,9 @@ function getPrinterList() {
         checkUserHub()
       }
     })
-    .catch((e) => {})
+    .catch((err) => {
+      console.log('getUserHubPrints catch: ', err);
+    })
 }
 
 // 处理更换打印机, 获取配置参数
@@ -328,7 +332,8 @@ function handlePrinterChange(item: any) {
         }
       }
     })
-    .catch((e) => {
+    .catch((err) => {
+      console.log('getFn catch: ', err);
     })
     .finally(() => {})
 }
@@ -348,6 +353,23 @@ function getFileIcon(fileName) {
   return srcMap[getFileType(fileName)] || otherSrc
 }
 
+// 复制文件并重命名
+function copyAndRenamed(fileName, filePath) {
+  // const targetPath = `${uni.env.USER_DATA_PATH}/${fileName}`
+  // // 写入文件
+  // fs.writeFile({
+  //   filePath: targetPath,
+  //   data: fileData,
+  //   encoding: 'binary', // 与 readFile 的编码一致
+  //   success() {
+  //     console.log('文件保存成功:', targetPath);
+  //   },
+  //   fail(err) {
+  //     console.error('写入失败:', err);
+  //   }
+  // });
+}
+
 // 处理选择文件
 function selectFile() {
   switch(accept.value) {
@@ -359,7 +381,10 @@ function selectFile() {
           console.log('chooseMessageFile IMG res: ', res);
           if (res.errMsg == "chooseMessageFile:ok") {
             let failList = []
+
             res.tempFiles.forEach(item => {
+              // 使用 getFileSystemManager 复制一个文件到目标路径
+              let copyFile = copyAndRenamed(item.name, item.path)
               if (item.size > maxSize || !allowType.includes(getFileType(item.name))) {
                 failList.push(item)
               } else {
@@ -375,8 +400,27 @@ function selectFile() {
             toast.warning("选择微信图片异常, 请重试")
           }
         },
-        fail () {
-          toast.warning("选择微信图片失败, 请重试")
+        fail (err) {
+          console.log('chooseMessageFile IMG err: ', err);
+          let tips = "选择微信图片失败, 请重试"
+          switch (err.errMsg) {
+            case "chooseMessageFile:fail cancel":
+              tips = "已取消选择微信图片"
+              break;
+            case "chooseMessageFile:fail auth deny":
+            case "chooseMessageFile:fail permission denied":
+              tips = "未授权文件访问权限,无法访问文件"
+              break;
+            case "chooseMessageFile:fail file not found":
+              tips = "选择的文件已被删除或移动"
+              break;
+            case "chooseMessageFile:fail system error":
+              tips = "微信内部错误,请检查微信版本、重启小程序或设备"
+              break;
+            default:
+              logManager.error("未处理的选择微信图片异常 errMsg::", JSON.stringify(err.errMsg))
+          }
+          toast.warning(tips)
         }
       })
       break;
@@ -405,8 +449,27 @@ function selectFile() {
             toast.warning("选择微信文件异常, 请重试")
           }
         },
-        fail () {
-          toast.warning("选择微信文件失败, 请重试")
+        fail (err) {
+          console.log('chooseMessageFile FILE err: ', err);
+          let tips = "选择微信文件失败, 请重试"
+          switch (err.errMsg) {
+            case "chooseMessageFile:fail cancel":
+              tips = "已取消选择微信文件"
+              break;
+            case "chooseMessageFile:fail auth deny":
+            case "chooseMessageFile:fail permission denied":
+              tips = "未授权文件访问权限,无法访问文件"
+              break;
+            case "chooseMessageFile:fail file not found":
+              tips = "选择的文件已被删除或移动"
+              break;
+            case "chooseMessageFile:fail system error":
+              tips = "微信内部错误,请检查微信版本、重启小程序或设备"
+              break;
+            default:
+              logManager.error("未处理的选择微信文件失败 errMsg::", JSON.stringify(err.errMsg))
+          }
+          toast.warning(tips)
         }
       })
       break;
@@ -437,8 +500,30 @@ function selectFile() {
             toast.warning("选择相册图片异常, 请重试")
           }
         },
-        fail () {
-          toast.warning("选择相册图片失败, 请重试")
+        fail (err) {
+          console.log('chooseImage err: ', err);
+          let tips = ['windows', 'mac'].includes(deviceInfo.platform) ? "已取消选择相册图片" : "选择相册图片失败, 请重试"
+          switch (err.errMsg) {
+            case "chooseImage:fail cancel":
+              tips = "已取消选择相册图片"
+              break;
+            case "chooseImage:fail auth deny":
+            case "chooseImage:fail permission denied":
+              tips = "未授权相册或摄像头权限,无法访问相册图片"
+              break;
+            case "chooseImage:fail file not found":
+              tips = "选择的图片已被删除或移动"
+              break;
+            case "chooseImage:fail system error":
+              tips = "微信内部错误,请检查微信版本、重启小程序或设备"
+              break;
+            case "chooseImage:fail operation too frequent":
+              tips = "短时间内多次调用,请稍后重试"
+              break;
+            default:
+              logManager.error("未处理的选择相册图片失败 errMsg::", JSON.stringify(err.errMsg))
+          }
+          toast.warning(tips)
         }
       })
       break;
@@ -464,8 +549,9 @@ function selectFile() {
                     }
                   });
                 }
-              }).catch(() => {
+              }).catch((err) => {
                 toast.warning("获取发票信息异常")
+                console.log('getInvoiceBatch catch: ', err);
               })
             }
           } else {
@@ -473,17 +559,42 @@ function selectFile() {
           }
         },
         fail (err) {
+          console.log('chooseInvoice err: ', err);
           let tips = "选择微信发票失败, 请重试"
           switch (err.errMsg) {
             case "chooseInvoice:fail cancel":
-              tips = "已取消选择发票"
+              tips = "已取消选择微信发票"
               break;
             case "chooseInvoice:fail auth deny":
-              tips = "已拒绝授权,无法访问发票信息"
+            case "chooseInvoice:fail permission denied":
+              tips = "未授权发票访问权限,无法访问发票信息"
+              break;
+            case "chooseInvoice:fail no invoice":
+              tips = "当前没有可选的发票"
               break;
             case "chooseInvoice:fail system error":
-              tips = "系统错误"
+              tips = "微信内部错误,请检查微信版本、重启小程序或设备"
+              break;
+            case "chooseInvoice:fail invoice expired":
+              tips = "选择的发票已超过有效期"
+              break;
+            case "chooseInvoice:fail invoice not supported":
+              tips = "选择的发票类型不被小程序支持"
+              break;
+            case "chooseInvoice:fail merchant not match":
+              tips = "发票所属商户与当前小程序不匹配"
               break;
+            case "chooseInvoice:fail need verify password":
+              tips = "需要输入密码才能查看发票"
+              break;
+            case "chooseInvoice:fail operation too frequent":
+              tips = "短时间内多次调用,请稍后重试"
+              break;
+            case "chooseInvoice:fail 开发者工具暂时不支持此 API 调试,请使用真机进行开发":
+              tips = "开发者工具暂时不支持此 API 调试,请使用真机进行开发"
+              break;
+            default:
+              logManager.error("未处理的选择微信发票失败 errMsg::", JSON.stringify(err.errMsg))
           }
           toast.warning(tips)
         }
@@ -583,7 +694,7 @@ async function handleBatchPrint() {
 
       try {
         // 上传文件并监听进度
-        const uploadRes = await handlePrint(filePath, (progress) => {
+        const uploadRes = await handlePrint(fileName, filePath, (progress) => {
           toast.loading({
             loadingType: 'ring',
             msg: `文件 ${i + 1} 上传进度: ${progress}%`
@@ -592,6 +703,8 @@ async function handleBatchPrint() {
         toast.success(`文件 ${i + 1} 上传成功`)
       } catch (error) {
         toast.error(`文件 ${i + 1} 上传失败`)
+        logManager.error(`文件 ${fileName} 上传失败::`, error.errMsg)
+        console.log('error: ', error);
         failedFiles.value.push(fileList.value[i]); // 记录失败的文件
       }
     }
@@ -605,13 +718,14 @@ async function handleBatchPrint() {
       }).then(async () => {
         await retryUploadFiles(failedFiles.value); // 重新上传失败的文件
       }).catch((error) => {
-        msgConfirm("上传完成", "取消重新上传, 其余文件已上传成功!")
+        msgConfirm("提示", `已取消重新上传${failedFiles.value.length < fileList.value.length ? ', 其余文件已上传成功!' : ""}`)
       })
     } else {
       toast.success("所有文件上传成功")
       msgConfirm("上传完成", "所有文件上传成功")
     }
   } catch(error) {
+    logManager.error(`上传过程中发生错误::`, JSON.stringify(error))
     console.log("上传过程中发生错误", error);
   }
 }
@@ -629,7 +743,7 @@ async function retryUploadFiles(failedFiles) {
     })
 
     try {
-      const uploadRes = await handlePrint(filePath, (progress) => {
+      const uploadRes = await handlePrint(fileName, filePath, (progress) => {
         toast.loading({
           loadingType: 'ring',
           msg: `文件 ${i + 1} 上传进度: ${progress}%`
@@ -637,7 +751,8 @@ async function retryUploadFiles(failedFiles) {
       });
       toast.success(`文件 ${i + 1} 重新上传成功`)
     } catch (error) {
-      toast.error(`文件 ${i + 1} 重新上传成功`)
+      toast.error(`文件 ${i + 1} 重新上传失败`)
+      logManager.error(`文件重新上传失败 :: 文件名 ${fileName} :: 文件路径 ${filePath} :: `, JSON.stringify(error))
       newFailedFiles.push(failedFiles[i]); // 记录重新上传失败的文件
     }
   }
@@ -657,12 +772,13 @@ async function retryUploadFiles(failedFiles) {
 }
 
 // 打印文件 (单个打印任务)
-function handlePrint(filePath, onProgress) {
+function handlePrint(fileName, filePath, onProgress) {
   return new Promise((resolve, reject) => {
     // 构造提交数据
     let params = {
       id: formData.value.userHubId,
       printer: formData.value.printerName,
+      originalName: fileName,
     }
     printerOptions.value.forEach(option => {
       switch(option.type) {
@@ -687,18 +803,20 @@ function handlePrint(filePath, onProgress) {
       url: getURL(),
       filePath: filePath,
       name: 'file', // 文件对应的 key
-      formData: {
-        // 其他表单数据
+      formData: {   // 其他表单数据
+        originalName: fileName // 文件名称
       },
       success: (res) => {
         if (res.statusCode === 200 && ((isLocal.value && JSON.parse(res.data).code === 200) || (!isLocal.value && JSON.parse(res.data).code === 0))) {
           resolve(res.data);
         } else {
           reject(new Error(`上传失败,状态码: ${res.statusCode}`));
+          logManager.error(`上传失败,状态码: ${res.statusCode}`)
         }
       },
       fail: (err) => {
         reject(err);
+        logManager.error(`上传失败,fail err:: ${JSON.stringify(err)}`)
       },
     });
 
@@ -787,15 +905,6 @@ function msgConfirm(title="提示", msg="文件已上传成功!") {
   })
 }
 
-// 打开SSE webview页面
-// function openWebViewSSE() {
-//   let list = JSON.stringify(fileList.value.map(item => item.name).join(",") || "")
-//   const url = `https://service.1ai.ltd/webview-sse/index.html?token=${token}&list=${list}&t=${new Date().getTime()}`
-//   uni.navigateTo({
-//     url: `/pages/webview/sse?url=${encodeURIComponent(url)}`,
-//   })
-// }
-
 onLoad((option) => {
   if (option && option.accept) {
     accept.value = option.accept

+ 26 - 20
src/pages/webview/index.vue

@@ -14,6 +14,9 @@
 </template>
 
 <script lang="ts" setup>
+import { logManager } from '@/utils';
+import { useToast } from 'wot-design-uni'
+const toast = useToast()
 const url = ref("")
 
 function handleFileList(fileList) {
@@ -53,27 +56,30 @@ function base64ToTempFilePath(fileName, base64Data) {
 // setStorageSync 单条只能存储1MB, 总空间10MB
 // getFileSystemManager 使用文件存储API 单个支持10MB, 总存储空间200MB
 async function handleMessage(data) {
-  uni.removeStorageSync('fileList');
-  let fileList = JSON.parse(data.detail.data)
-  uni.showLoading({
-    title: '文件处理中...', // 提示文字
-    mask: true // 显示透明蒙层,防止触摸穿透
-  });
-  handleFileList(fileList).then((filePaths) => {
-    uni.setStorageSync('fileList', filePaths)
-    uni.hideLoading();
-    uni.navigateTo({
-      url: `/pages/print/index?accept=all`,
-    })
-  }).catch(() => {
-    uni.hideLoading();
-    // 提示用户处理失败
-    uni.showToast({
-      title: '文件处理失败,请重试',
-      icon: 'none',
-      duration: 2000
+  try {
+    uni.removeStorageSync('fileList');
+    let fileList = JSON.parse(data.detail.data)
+    uni.showLoading({
+      title: '文件处理中...', // 提示文字
+      mask: true // 显示透明蒙层,防止触摸穿透
     });
-  })
+    handleFileList(fileList).then((filePaths) => {
+      uni.setStorageSync('fileList', filePaths)
+      uni.hideLoading();
+      uni.navigateTo({
+        url: `/pages/print/index?accept=all`,
+      })
+    }).catch(() => {
+      uni.hideLoading();
+      // 提示用户处理失败
+      toast.warning('文件处理失败,请重试')
+    })
+  } catch(error) {
+    // 处理异常
+    console.log('handleMessage error: ', error);
+    toast.warning('文件处理异常,请重试')
+    logManager.error("处理从webview页面传回来文件异常::", JSON.stringify(error))
+  }
 }
 
 onLoad((option) => {

+ 1 - 0
src/utils/http.ts

@@ -26,6 +26,7 @@ export const http = <T>(options: CustomRequestOptions) => {
           // 提取核心数据 res.data
           resolve(res.data as IResData<T>)
         } else if (res.statusCode === 401) {
+          useUserStore().setToken("")
           if (options.url == "/api/wx/mini/login") {
             // 401错误(登录接口) -> 清理用户信息,跳转到登录页
             uni.setStorageSync("redirectPath", currFullPath())

+ 6 - 1
src/utils/index.ts

@@ -285,4 +285,9 @@ export function timestampToDatetime(timestamp) {
   let seconds = ("0" + date.getSeconds()).slice(-2);
   
   return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
-}
+}
+
+
+// 小程序实时日志
+// 查看位置:微信公众平台(https://mp.weixin.qq.com/)--数据--性能质量--实时日志
+export const logManager = wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : null