Ver código fonte

一体机 演示相机代码

dengrui 1 semana atrás
pai
commit
ccce84a000

+ 1 - 1
product/phone/src/main/ets/common/util/UploadUtil.ets

@@ -43,7 +43,7 @@ interface FileDataModel {
 class UploadUtil {
   private baseUrl: string = baseUrl
   //private fileUrl: string = "http://10.88.11.201:9000" //上传完成后可以查看的
-  private fileUrl: string = "http://192.168.2.100:9000" //江山
+  private fileUrl: string = "http://192.168.1.3:9000" //创客
   private uploadPath: string = "/api/v1/base/upload"
   controller: web_webview.WebviewController | null = null
   ports: web_webview.WebMessagePort[] = [];

+ 520 - 0
product/phone/src/main/ets/pages/camera/CameraVersion2.ets

@@ -0,0 +1,520 @@
+import image from '@ohos.multimedia.image';
+import fs from "@ohos.file.fs"
+import common from '@ohos.app.ability.common';
+import photoAccessHelper from '@ohos.file.photoAccessHelper';
+import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
+import commonEvent from "@ohos.commonEvent";
+import CommonEventManager from '@ohos.commonEventManager'
+import uploadInstance from '../../utils/UploadUtil';
+import router from '@ohos.router';
+import fileIo from '@ohos.file.fs';
+const TAG = "openHarmonyBridge upload"
+@Entry
+@Component
+struct Index {
+
+  @State isUploading: boolean = false
+  /*相机需要启动lib脚本
+   * hdc shell mount -o remount,rw /vendor
+   * */
+  @State commodityPixelMap: PixelMap | null = null;
+  @State isButtonPressed: boolean = false;
+  @State isCapturing: boolean = false;
+  @State isCloseView: boolean = false;// 新增状态控制拍摄状态
+  @State reminds:string = ''
+
+  remindController: CustomDialogController = new CustomDialogController({
+    builder: RemindDialog({
+      remind: this.reminds,}
+    ),
+  })
+  //
+  subscriber: CommonEventManager.CommonEventSubscriber | null = null; // Used to save the created subscriber object for subsequent subscription and unsubscription.
+  // Subscriber information.
+  subscribeInfo: CommonEventManager.CommonEventSubscribeInfo = { events: ["sonycamera_callback"] };
+  getPermission = async () => {
+    let context = getContext(this) as common.UIAbilityContext;
+    let atManager = abilityAccessCtrl.createAtManager();
+    try {
+      atManager.requestPermissionsFromUser(context, ['ohos.permission.WRITE_IMAGEVIDEO', 'ohos.permission.READ_IMAGEVIDEO'])
+        .then((data) => {
+          console.log('data: ' + JSON.stringify(data));
+        })
+        .catch((err: object) => {
+          console.log('err: ' + JSON.stringify(err));
+        })
+    } catch (err) {
+      console.log('catch err->' + JSON.stringify(err));
+    }
+  }
+  //订阅回调(拍照完接收到照片收到回调)
+  createSubscriber = async () => {
+    this.subscriber = await CommonEventManager.createSubscriber(this.subscribeInfo);
+    if (this.subscriber) {
+      console.info(TAG,"创建订阅回调成功");
+      CommonEventManager.subscribe(this.subscriber, (err, data) => {
+        if (err?.code) {
+          console.error("[CommonEvent] SubscribeCallBack err=" + JSON.stringify(err));
+        } else {
+          console.info("[CommonEvent] SubscribeCallBack data=" + JSON.stringify(data));
+          if (data && data.code&&data.code === 2) {
+            console.info(TAG,"开始传输照片");
+            this.handleCaptureSuccess()
+          }else if (data && data.code&&data.code === 3) {
+            console.info(TAG,"开始预览" );
+            this.publishStartView();
+          }
+        }
+      });
+    }
+  };
+
+  handleCaptureSuccess = () => {
+    this.savePhoto();
+    // commonEvent.publish("startview", (err) => {
+    //   if (err?.code) {
+    //     console.error("Restart preview error:", JSON.stringify(err));
+    //   } else {
+    //     this.isCapturing = false;
+    //     this.isCloseView =false;
+    //     this.liveShow();// 拍摄完成后恢复预览
+    //     console.log("Restart success")
+    //   }
+    // });
+  };
+  publishStartView=()=>{
+    commonEvent.publish("startview", (err) => {
+      if (err?.code) {
+        console.error("Restart preview error:", JSON.stringify(err));
+      } else {
+        this.isCapturing = false;
+        this.isCloseView =false;
+        this.liveShow();// 拍摄完成后恢复预览
+        console.log("Restart success")
+      }
+    });
+  }
+
+  connectCamera = async () => {
+    commonEvent.publish("opensession", (err) => {
+      if (err?.code) {
+        console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
+      } else {
+        console.info("[CommonEvent] Publish opensession succeed ")
+      }
+    })
+  }
+  disconnectCamera = () => {
+    commonEvent.publish("stopview", (err) => {
+      if (err?.code) {
+        console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
+      } else {
+        console.info("[CommonEvent] Publish stopview succeed ")
+        commonEvent.publish("closesession", (err) => {
+          if (err?.code) {
+            console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
+          } else {
+            console.info("[CommonEvent] Publish closesession succeed ")
+          }
+        })
+      }
+    })
+  }
+  savePhoto=()=>{
+    let imageUri: string = "/data/storage/el2/base/haps/entry/files/image_base64.txt"
+    console.log(TAG, "进入了savephoto")
+    try {
+      const file = fileIo.openSync(imageUri, fileIo.OpenMode.READ_ONLY);
+      fileIo.closeSync(file.fd); // 关闭文件描述符
+      this.reminds= "照片传输到小黑盒成功"
+      this.remindController.open()
+      delayExecution(()=>{
+        this.remindController.close()
+      }, 1000)
+    } catch (error) {
+      console.error('文件不存在或无法访问:', error);
+      this.reminds= "照片传输到小黑盒失败"
+      this.remindController.open()
+      delayExecution(()=>{
+        this.remindController.close()
+      }, 1000)
+
+    }
+    try {
+      // 获取相册访问的 helper 实例
+
+      console.log(TAG, "进入了savephoto1")
+      // 创建一个新的图片资产,并获取目标 URI
+      // const dest = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
+
+      // console.log(TAG, "进入了savephoto2")
+      // 打开源文件和目标文件  这个是写死的 app的名字不能改
+      // let imageUri: string = "/data/storage/el2/base/haps/entry/files/shoots.jpg"
+      // 开始上传
+      console.log(TAG, "开始上传", imageUri)
+      uploadInstance.startUploadBase64(imageUri, () => {
+
+        console.log(TAG, "上传完成后的callback")
+        this.isUploading = false
+        this.publishStartView();
+      })
+
+
+      // let res = fs.accessSync(imageUri);
+      // console.info("demo1"+ "file " + imageUri)
+      // if (res) {
+      //   console.info("demo1"+"file exists");
+      // } else {
+      //   console.info("demo1"+"file not exists");
+      // }
+      // const srcFile = fs.openSync(imageUri);
+      // const destFile = fs.openSync(dest, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+      // fs.copyFileSync(srcFile.fd, destFile.fd);
+      // fs.closeSync(srcFile);
+      // fs.closeSync(destFile);
+      // console.log("demo1"+'Image saved to album successfully:', dest);
+    } catch (error) {
+      console.log(TAG, "进入了savephoto3")
+      console.error("demo1"+'Failed to save image to album:', error.code);
+    }
+  }
+  takePhoto = async () => {
+    this.isCloseView = true;
+    this.isCapturing = true;
+    commonEvent.publish("stopview", (err) => {
+      if (err?.code) {
+        console.info("demo1"+"[CommonEvent] Publish CallBack err=" + JSON.stringify(err));
+        this.isCapturing = false;
+      } else {
+        console.info("demo1"+"[CommonEvent] Publish stopview succeed");
+        commonEvent.publish("shootonly", (err) => {
+          if (err?.code) {
+            console.info("demo1"+"[CommonEvent] Publish CallBack err=" + JSON.stringify(err));
+            this.isCapturing = false;
+          } else {
+            console.info("demo1"+"[CommonEvent] Publish shootonly succeed");
+          }
+        });
+      }
+    });
+  };
+
+  readTimer = 0
+
+  liveShow = async () => {
+
+    const previewManager = new PreviewManager(getContext(this));
+    let index = 0;
+
+    this.readTimer = setInterval(async () => {
+      if (!this.isCloseView && !this.isCapturing) {
+        try {
+          const success = await previewManager.processFrame(index);
+          if (success) {
+            this.commodityPixelMap = previewManager.getActiveBuffer();
+            //index = (index + 1) % 10;
+          }
+        } catch (error) {
+          console.warn(TAG, "预览更新失败:", error);
+        }
+      }
+    }, 50); // 30ms interval for ~30fps
+
+    // 清理资源
+    return () => {
+      previewManager.release();
+      if (this.commodityPixelMap) {
+        this.commodityPixelMap.release();
+        this.commodityPixelMap = null;
+      }
+    };
+  };
+
+  aboutToAppear(): void {
+    this.createSubscriber();
+    this.connectCamera();
+    this.getPermission();
+    this.liveShow();
+  }
+
+  aboutToDisappear(): void {
+    this.isCloseView = true;
+    this.disconnectCamera();
+    if (this.subscriber) {
+      CommonEventManager.unsubscribe(this.subscriber);
+    }
+    if (this.readTimer) {
+      clearInterval(this.readTimer);
+    }
+    if (this.commodityPixelMap) {
+      this.commodityPixelMap.release();
+      this.commodityPixelMap = null;
+    }
+  }
+  build() {
+    Column() {
+      Row() {
+
+      }
+      .width('100%')
+      .height('5%')
+      .alignItems(VerticalAlign.Center)
+      Row() {
+        if (this.commodityPixelMap) {
+          Stack({ alignContent: Alignment.Center }) {
+            Image(this.commodityPixelMap)
+              .width('100%')
+              .height('100%')
+              .objectFit(ImageFit.Contain)
+
+          }
+        }
+        if (this.isUploading) {
+          Stack({ alignContent: Alignment.Center }) {
+            // 半透明黑色背景蒙层
+            Column() {
+              Text('正在上传中...')
+                .fontSize(22)
+                .margin({ top: 10, bottom: 10 })
+
+              LoadingProgress()
+                .color(Color.Blue)
+                .width(50)
+                .height(50)
+            }
+            .height(140)
+            .width(150)
+            .backgroundColor(Color.White)
+            .borderRadius(10)
+            .justifyContent(FlexAlign.Center)
+          }
+          .width('100%')
+          .height('100%')
+          .position({ x: 0, y: 0 })
+        }
+      }
+      .width('100%')
+      .height('80%')
+      .backgroundColor('#000000') // 背景为黑色
+
+      // 底部:拍照按钮区域
+      Row() {
+        Button('', { type: ButtonType.Circle})
+          .width(this.isButtonPressed ? 70 : 80) // 按下时缩小按钮
+          .height(this.isButtonPressed ? 70 : 80)
+          .backgroundColor(this.isButtonPressed ? '#CCCCCC' : '#FFFFFF') // 按下时按钮颜色变灰
+          .border({ width: 4, color: '#FFFFFF' })// 白色边框
+          .onClick(() => {
+            console.log(TAG, "点击了拍照按钮")
+            if(this.isUploading){
+              return
+            }
+            this.isUploading = true
+            this.takePhoto();
+
+          })
+          .onTouch((event: TouchEvent) => {
+            if(this.isUploading){
+              return
+            }
+            if (event.type === TouchType.Down) {
+              this.isButtonPressed = true; // 按下时设置为 true
+            } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) {
+              this.isButtonPressed = false; // 松开时设置为 false
+            }
+          })
+        Button(){
+          Image($r('app.media.close'))
+            .width(40)
+            .height(40)
+        }
+        .width(70)
+        .height(70)
+        .backgroundColor('#1c1c1c')
+        .onClick(() => {
+          this.isCloseView = true;
+          sleep(100)
+          this.disconnectCamera()
+          router.back()        })
+
+      }.width('100%')
+      .height('15%')
+      .justifyContent(FlexAlign.SpaceEvenly) // 按钮居中
+      .backgroundColor('#000000') // 底部背景为黑色
+    }
+    .width('100%')
+    .height('100%')
+    .backgroundColor('#000000')
+  }
+
+  // 整体背景为黑色
+  /* Text("sada")
+        .onClick(async () => {
+          console.info("sssss");
+          // 异步加载图片
+          const context: Context = getContext(this);
+          let index = 0; // 初始化索引
+          while (true) { // 无限循环
+            const filePath: string = `${context.filesDir}/live${index}.jpg`;
+            try {
+              fs.accessSync(filePath); // 检查文件是否存在
+              console.info("file " + filePath);
+              const imageSource = image.createImageSource(filePath);
+              if (imageSource) {
+                this.commodityPixelMap = await imageSource.createPixelMap();
+              }
+              console.info("file exists");
+            } catch (error) {
+              console.info("file not exists");
+            }
+            index = index  % 10; // 更新索引,循环从0到9
+            await sleep(100);
+          }
+
+
+        }).width('20%')
+        .height('10%')
+      Text("nihao")
+        .onClick(async () => {
+          const context = getContext() as common.UIAbilityContext;
+          try {
+            // 获取相册访问的 helper 实例
+            const helper = photoAccessHelper.getPhotoAccessHelper(context);
+
+            // 创建一个新的图片资产,并获取目标 URI
+            const dest = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
+
+            // 打开源文件和目标文件
+            let imageUri: string = "/data/storage/el2/base/haps/entry/files/shoot.jpg"
+            let res = fs.accessSync(imageUri);
+            console.info("file " + imageUri)
+            if (res) {
+              console.info("file exists");
+            } else {
+              console.info("file not exists");
+            }
+            const srcFile = fs.openSync(imageUri);
+            console.info("file 1")
+            const destFile = fs.openSync(dest, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+            console.info("file 2")
+            // 将源文件内容复制到目标文件
+            fs.copyFileSync(srcFile.fd, destFile.fd);
+            console.info("file 3")
+            // 关闭文件句柄
+            fs.closeSync(srcFile);
+            fs.closeSync(destFile);
+
+            console.log('Image saved to album successfully:', dest);
+
+          } catch (error) {
+            console.error('Failed to save image to album:', error.code);
+            throw new Error(`Failed to save image to album: ${error.message}`);
+          }
+        })
+
+        .width('100%')
+        .height('100%')
+        .backgroundColor('#F1F3F5')
+    }
+  }
+}*/
+}
+function sleep(ms: number): Promise<void> {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
+@CustomDialog
+struct RemindDialog {
+  controller: CustomDialogController
+  @Link remind: string
+  build() {
+    Column() {
+      Text(this.remind)
+        .fontSize(20)
+        .margin({ top: 10, bottom: 10 })
+    }
+  }
+}
+
+function delayExecution(callback: Function, delay: number) {
+  let timerId = setInterval(() => {
+    clearInterval(timerId);
+    callback();
+  }, delay);
+}
+
+class PreviewManager {
+  private context: Context;
+  private activeBuffer: PixelMap | null = null;
+  private nextBuffer: PixelMap | null = null;
+  private isProcessing: boolean = false;
+  private lastFrameTime: number = 0;
+  private frameInterval: number = 50;
+
+  constructor(context: Context) {
+    this.context = context;
+  }
+
+  async processFrame(index: number): Promise<boolean> {
+    if (this.isProcessing) return false;
+
+    const now = Date.now();
+    if (now - this.lastFrameTime < this.frameInterval) {
+      return false;
+    }
+
+    this.isProcessing = true;
+    try {
+      const filePath = `${this.context.filesDir}/live${index}.jpg`;
+
+      // 检查文件是否存在
+      try {
+        fs.accessSync(filePath);
+      } catch {
+        this.isProcessing = false;
+        return false;
+      }
+
+      const imageSource = image.createImageSource(filePath);
+      if (!imageSource) {
+        this.isProcessing = false;
+        return false;
+      }
+
+      // 创建较小尺寸的PixelMap以提高性能
+
+      this.nextBuffer = await imageSource.createPixelMap();
+      imageSource.release();
+
+      // 交换缓冲区
+      if (this.activeBuffer) {
+        this.activeBuffer.release();
+      }
+      this.activeBuffer = this.nextBuffer;
+      this.nextBuffer = null;
+      this.lastFrameTime = now;
+      return true;
+    } catch (error) {
+      console.warn(TAG, "处理预览帧失败:", error);
+      return false;
+    } finally {
+      this.isProcessing = false;
+    }
+  }
+
+  getActiveBuffer(): PixelMap | null {
+    return this.activeBuffer;
+  }
+
+  release() {
+    if (this.activeBuffer) {
+      this.activeBuffer.release();
+      this.activeBuffer = null;
+    }
+    if (this.nextBuffer) {
+      this.nextBuffer.release();
+      this.nextBuffer = null;
+    }
+  }
+}
+
+

+ 97 - 0
product/phone/src/main/ets/utils/Request.ets

@@ -0,0 +1,97 @@
+import axios, {
+  AxiosError,
+  AxiosResponse,
+  AxiosRequestHeaders,
+  AxiosRequestConfig,
+  CreateAxiosDefaults,
+  InternalAxiosRequestConfig
+} from '@ohos/axios';
+
+//import PreferencesUtil from '../PreferencesUtil';
+import { printError, printRequest, printResponse, handleRes } from './Helps';
+
+import uploadInstance from './UploadUtil';
+
+// jxq: 项目基本请求路径 险峰的
+//export  const JGRequestBaseUrl = "http://10.88.11.200:8079/" //险峰
+// export  const JGRequestBaseUrl = "http://192.168.2.100:8079/" //江山
+export  const JGRequestBaseUrl = "http://192.168.1.3:8079/" // 创客
+
+const DEBUG = true //
+
+// 创建实例
+const JGRequest = axios.create(
+  {
+    baseURL: JGRequestBaseUrl,
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    },
+    timeout: 20 * 1000,
+  }
+)
+
+// 添加请求拦截器
+JGRequest.interceptors.request.use((config: InternalAxiosRequestConfig) => {
+
+  // 以后登录之后可以在这里传
+  config.headers.Authorization = uploadInstance?.uploadParams?.token ?? ""
+  printRequest(config)
+
+  return config;
+}, (error: AxiosError) => {
+  // 对请求错误做些什么
+  printError(error)
+  return Promise.reject(error);
+});
+// 添加响应拦截器
+JGRequest.interceptors.response.use((response: AxiosResponse) => {
+  // 对响应数据做点什么
+  printResponse(response)
+
+  let res = handleRes(response)
+  let success = res[0] as boolean
+  let msg = res[1] as string
+  // console.debug("handleRes的返回结果 ", success, msg)
+
+  if (success) {
+    return response.data.data;
+  }
+  else {
+    return Promise.reject<string>(msg)
+  }
+
+}, (error: AxiosError) => {
+  // 对响应错误做点什么
+  printError(error)
+
+  return Promise.reject(error);
+});
+
+// // 添加响应拦截器
+// JGRequest.interceptors.response.use((response: AxiosResponse)=> {
+//   // 对响应数据做点什么
+//   printResponse(response)
+//
+//   let [success, msg] = handleRes(response)
+//   // console.debug("handleRes的返回结果 ", success, msg)
+//
+//   if (success) {
+//     return response.data.data;
+//   }
+//   else {
+//     return Promise.reject(msg)
+//   }
+//
+// }, (error:AxiosError)=> {
+//   // 对响应错误做点什么
+//   printError(error)
+//
+//   return Promise.reject(error);
+// });
+
+
+export default JGRequest;
+
+
+
+

+ 220 - 0
product/phone/src/main/ets/utils/UploadUtil.ets

@@ -0,0 +1,220 @@
+import { BusinessError } from '@ohos.base'
+import http from '@ohos.net.http'
+import { FormData, File, FileUpload } from "@ohos/commons-fileupload"
+import fs from '@ohos.file.fs';
+import JGRequest, { JGRequestBaseUrl } from './Request';
+import web_webview from '@ohos.web.webview';
+import { AxiosResponse } from '@ohos/axios';
+
+const TAG = "openHarmonyBridge upload"
+
+
+// 从webview那边穿过来的 用于上传完成后调接口的值
+interface BridgeParams {
+  token?: string,
+  operationMediaId?: string,
+  processId?: string,
+  seqNo?: string,
+  methodName?: string,
+  apiUrlPath?: string //上传完成后调的接口 不包含baseurl
+  method?: string
+  stationIP?: string
+  messageKey?: string //web端会进行window.addEventListener('messageKey' 然后把url整体传回去, 为了后续定义传回去对象的json {fullUrl: ''}
+}
+
+// 上传文件后,返回一个图片的url,然后再调用其他接口上传url和一些值, 如果有其他接口需要key,在这里添加,然后在下面赋值就行了
+interface APIParamsModel extends BridgeParams {
+  filePath?: string, //工序的多媒体采集需要用到的key
+  file?: string,
+  fileName?: string,
+}
+
+interface ResultModel {
+  code?: string
+  data?: FileDataModel
+  msg?: string
+}
+
+interface FileDataModel {
+  fileUrl?: string
+}
+
+
+class UploadUtil {
+  private baseUrl: string = JGRequestBaseUrl
+  //private fileUrl: string = "http://10.88.11.201:9000" //上传完成后可以查看的
+  private fileUrl: string = "http://192.168.2.100:9000" //江山
+  private uploadPath: string = "/api/v1/base/upload"
+  controller: web_webview.WebviewController | null = null
+  ports: web_webview.WebMessagePort[] = [];
+
+  private constructor() {
+  }
+
+  public uploadParams: BridgeParams = {}
+  // public token: string = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOnsiaWQiOjEwMDAwLCJ1c2VyTmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJzdGF0aW9uSWQiOjAsImF2YXRhciI6Ii9qZ2ZpbGUvLzIwMjQvNS8yNy8yNzQzMjkzOTU4Mzg4NTIuanBnIiwib3JnSWQiOjF9LCJkZXZpY2UiOiJiYWNrIiwiZWZmIjoxNzI0MTIyNTQwMTQwLCJyblN0ciI6IkRkakc3akFSNEtkZ1h5VWV5emhROFVib1ZlOTJUVVo4In0.yVzW8YkjiqLf9T4oUsJUPUifqPFANWX78pov8aGRsFQ"
+  private static instance: UploadUtil; //单例实例
+
+  public static getInstance(): UploadUtil {
+    if (!UploadUtil.instance) {
+      UploadUtil.instance = new UploadUtil();
+    }
+    return UploadUtil.instance;
+  }
+
+  public configUploadParam(p: string) {
+    let model: BridgeParams = JSON.parse(p)
+    this.uploadParams = model
+  }
+
+  startUploadBase64(uri: string, callBack: () => void) {
+
+
+    try {
+
+      let base64Test =  fs.readTextSync(uri)
+      console.log(TAG, "baes64",base64Test)
+
+      let base64Data: APIParamsModel = {
+        file: base64Test,
+        fileName: 'test.jpg',
+      }
+      JGRequest.request({
+        method:  "post",
+        url: "api/v1/base/uploadBase64",
+        data: base64Data
+      }).then( async (res: AxiosResponse) => {
+
+        let result: FileDataModel = JSON.parse(JSON.stringify(res))
+
+
+        // 上传完成后调其他接口
+        if (this.uploadParams.apiUrlPath && result.fileUrl) {
+          let data: APIParamsModel = {
+            filePath: result.fileUrl,
+            operationMediaId: this.uploadParams?.operationMediaId ?? "",
+            processId: this.uploadParams?.processId ?? "",
+            seqNo: this.uploadParams?.seqNo ?? "",
+          }
+
+          await JGRequest.request({
+            method: this.uploadParams?.method ?? "post",
+            url: this.uploadParams?.apiUrlPath,
+            data: data
+          })
+        }
+
+        // 这个是 给webview发送post messages 通知的
+        if (this.uploadParams.messageKey) {
+          uploadInstance.ports = uploadInstance.controller!.createWebMessagePorts();
+          uploadInstance.controller!.postMessage(JSON.stringify({
+            fullUrl: this.fileUrl + result.fileUrl ?? "",
+            messageKey: this.uploadParams.messageKey ?? ""
+          }), [uploadInstance.ports[0]], '*');
+        }
+
+        callBack()
+      }).catch(() => {
+        callBack()
+      })
+
+
+    }
+    catch (e) {
+      callBack()
+      console.log(TAG, 'mk-logger', 'photoPlugin-str', JSON.stringify(e))
+    }
+  }
+
+  startUpload(uri: string, callBack: () => void) {
+
+
+    //   开始上传
+    try {
+      // 2.2 根据uri同步打开文件
+      const file = fs.openSync(uri)
+      // 2.3 同步获取文件的详细信息
+      const stat = fs.statSync(file.fd)
+      // 2.4 创建缓冲区存储读取的文件流
+      const buffer = new ArrayBuffer(stat.size)
+      // 2.5 开始同步读取文件流到缓冲区
+      fs.readSync(file.fd, buffer)
+      // 2.6 关闭文件流
+      fs.closeSync(file)
+
+      // 3. 转成base64编码的字符串
+      // const helper = new util.Base64Helper()
+      // const str = helper.encodeToStringSync(new Uint8Array(buffer))
+      // console.log('mk-logger', 'photoPlugin-str', buffer.byteLength, JSON.stringify(buffer))
+
+      let toUpFile = new File()
+      toUpFile.fileName = "test.jpg"
+      toUpFile.fileData = buffer
+
+      let fileUpload = new FileUpload({
+        baseUrl: this.baseUrl,
+        readTimeout: 60000,
+        connectTimeout: 60000,
+      })
+
+      const formData = new FormData();
+      // formData.append("key", 1); //可以添加基本类型的值,目前支持string、number
+      // formData.append("fileName", "test.jpg"); //也可以添加File类型的对象
+      formData.append('file', toUpFile)
+      console.log(TAG,"================toUpFile", toUpFile)
+      console.log(TAG,"================formData", formData)
+      fileUpload.post(this.uploadPath, formData, {
+        header: {
+          'Content-Type': 'multipart/form-data',
+          // "Authorization": this.token
+          'Authorization': this.uploadParams?.token ?? "",
+        },
+      }).then(async (res: http.HttpResponse) => {
+
+        let result: ResultModel = JSON.parse(res.result as string)
+        console.log(TAG, "ddddddd success", JSON.stringify(result?.data ?? ""));
+
+
+        // 上传完成后调其他接口
+        if (this.uploadParams.apiUrlPath) {
+          let data: APIParamsModel = {
+            filePath: result.data?.fileUrl ?? "",
+            operationMediaId: this.uploadParams?.operationMediaId ?? "",
+            processId: this.uploadParams?.processId ?? "",
+            seqNo: this.uploadParams?.seqNo ?? "",
+          }
+
+          await JGRequest.request({
+            method: this.uploadParams?.method ?? "post",
+            url: this.uploadParams?.apiUrlPath,
+            data: data
+          })
+        }
+
+        // 这个是 给webview发送post messages 通知的
+        if (this.uploadParams.messageKey) {
+          uploadInstance.ports = uploadInstance.controller!.createWebMessagePorts();
+          uploadInstance.controller!.postMessage(JSON.stringify({
+            fullUrl: this.fileUrl + result.data?.fileUrl ?? "",
+            messageKey: this.uploadParams.messageKey ?? ""
+          }), [uploadInstance.ports[0]], '*');
+        }
+
+        callBack()
+
+        //上传完成后浏览器可以产看的图片地址  http://10.88.11.201:9000
+      }).catch((err: BusinessError) => {
+        callBack()
+        console.error(TAG, "ddddddd    fail", JSON.stringify(err));
+      })
+    }
+    catch (e) {
+      callBack()
+      console.log(TAG, 'mk-logger', 'photoPlugin-str', JSON.stringify(e))
+    }
+  }
+}
+
+let uploadInstance = UploadUtil.getInstance();
+
+export default uploadInstance;

+ 110 - 0
product/phone/src/main/ets/utils/helps.ets

@@ -0,0 +1,110 @@
+import { InternalAxiosRequestConfig, AxiosResponse, AxiosError } from "@ohos/axios"
+import promptAction from '@ohos.promptAction'
+
+// 是否在控制台打印某项log
+const pConfig = true
+const pHeaders = true
+const pUrl = true
+const pParams = true
+const pBody = true
+const pResponse = true
+const pData = true
+const pError = true
+
+const TAG = "openHarmonyBridge" //webview和vue沟通的名称
+
+// @CustomDialog
+// struct CustomDialogExample {
+//   controller: CustomDialogController
+//   build() {
+//     Column() {
+//       Text('我是内容')
+//         .fontSize(20)
+//         .margin({ top: 10, bottom: 10 })
+//     }
+//   }
+// }
+
+const printRequest = (config: InternalAxiosRequestConfig) => {
+  if (pConfig) {
+    console.debug(TAG, "printRequest config", JSON.stringify(config))
+  }
+
+  if (pHeaders) {
+    console.debug(TAG, "printRequest headers", JSON.stringify(config.headers))
+  }
+
+  if (pUrl) {
+    console.debug(TAG, "printRequest url", `Method:${config.method} ${config.baseURL}${config.url}`)
+  }
+
+  if (pBody) {
+    console.debug(TAG, "printRequest 请求参数data", JSON.stringify(config.data))
+  }
+
+  if (pParams) {
+    console.debug(TAG, "printRequest 请求参数params", JSON.stringify(config.params))
+  }
+
+}
+
+const printResponse = (response: AxiosResponse) => {
+  if (pResponse) {
+    console.debug(TAG, 'printResponse response: ', JSON.stringify(response))
+  }
+  if (pData) {
+    console.debug(TAG, "printResponse data", JSON.stringify(response.data))
+  }
+}
+
+const printError = (error: AxiosError) => {
+  if (pError) {
+    console.debug(TAG, "printError error", error.message)
+  }
+  promptAction.showToast({
+    message: error.message ?? "请求出错",
+    duration: 1500,
+    bottom: 100
+  })
+}
+
+
+// 处理返回数据
+const handleRes = (response: AxiosResponse): [boolean, string] => {
+  let isSuccess = true
+  let msg = ""
+
+  if (response.status === 200) { //判断返回状态是否为200
+    if (String(response.data?.code) === "200") { //判断数据的code是否为200,有可能是500的服务器错误
+      isSuccess = true
+      msg = `请求数据成功`
+    }
+    else {
+      isSuccess = false
+      // msg = `${response.data?.code}: ${response.data?.msg ?? "服务器错误"}`
+      msg = `${response.data?.msg ?? "服务器错误"}`
+    }
+  }
+  else {
+    isSuccess = false
+    msg = `状态码非200 status: ${response.status}}`
+  }
+
+  if (!isSuccess) {
+    promptAction.showToast({
+      message: msg,
+      duration: 1500,
+      bottom: 100
+    })
+
+    // const dialogController: CustomDialogController = new CustomDialogController({
+    //   builder: CustomDialogExample({}),
+    // })
+    // dialogController.open()
+  }
+
+  return [isSuccess, msg]
+}
+
+
+export { printRequest, printResponse, printError, handleRes }

+ 2 - 1
product/phone/src/main/resources/base/profile/main_pages.json

@@ -20,6 +20,7 @@
     "pages/warehouse/MechanicalArmDebugging",
     "pages/warehouse/StationDevicesPage",
     "pages/warehouse/RobotErrorHandle",
-    "pages/warehouse/OutboundStation"
+    "pages/warehouse/OutboundStation",
+    "pages/camera/CameraVersion2"
   ]
 }