cjb před 1 týdnem
rodič
revize
c5e5e9b44d

+ 220 - 0
entry/src/main/ets/common/util/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 ProcessRequest from '../util/request/ProcessRequest';
+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.1.3:20001" //江山
+  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',
+      }
+      ProcessRequest.request({
+        method:  "post",
+        url: "/api/v1/base/uploadBase64",
+        data: base64Data
+      }).then( async (res: AxiosResponse) => {
+
+        let result: FileDataModel = JSON.parse(JSON.stringify(res))
+
+
+        // 上传完成后调其他接口
+        if (result.fileUrl) {
+          let data: APIParamsModel = {
+            filePath: result.fileUrl,
+            operationMediaId: this.uploadParams?.operationMediaId ?? "679",
+            processId: this.uploadParams?.processId ?? "",
+            seqNo: this.uploadParams?.seqNo ?? "",
+          }
+
+          await ProcessRequest.request({
+            method: this.uploadParams?.method ?? "post",
+            url: "/api/v1/process/media/add",
+            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 ProcessRequest.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;

+ 447 - 0
entry/src/main/ets/view/process/MultiMediaCollect.ets

@@ -0,0 +1,447 @@
+import image from '@ohos.multimedia.image';
+import fs from "@ohos.file.fs"
+import CommonEventManager from '@ohos.commonEventManager'
+import uploadInstance from '../../common/util/UploadUtil';
+import router from '@ohos.router';
+import fileIo from '@ohos.file.fs';
+const TAG = "Process camera upload"
+@Component
+export struct MultiMediaCollect {
+  @State isExpanded: boolean = false
+  @State selectedIndex:number = 0
+  @State shootButtonClick:number =1
+
+  @State isUploading: boolean = false
+  @State commodityPixelMap: PixelMap | null = null;
+  @State isButtonPressed: boolean = false;
+  @State isCapturing: boolean = false;
+  @State isStopView: boolean = false;
+  @State reminds:string = ''
+  @State readTimer:number = 0
+  private previewManager: PreviewManager | null = null; // 初始化为 null
+
+  subscriber: CommonEventManager.CommonEventSubscriber | null = null;
+  subscribeInfo: CommonEventManager.CommonEventSubscribeInfo = { events: ["sonycamera_callback"] };
+  //订阅回调(code=1代表连接成功,code=2代表拍照成功)
+  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(TAG,"SubscribeCallBack err=" + JSON.stringify(err));
+        } else {
+          console.info(TAG,"SubscribeCallBack data=" + JSON.stringify(data));
+          if (data && data.code&&data.code === 2) {
+            this.uploadPhoto();//拍照成功->上传照片
+          }else if (data && data.code&&data.code === 3) {
+            console.info(TAG,"开始预览" );
+            this.startView();//连接成功开始预览
+          }
+        }
+      });
+    }
+  };
+  //连接相机
+  connectCamera = async () => {
+    CommonEventManager.publish("opensession", (err) => {
+      if (err?.code) {
+        console.info(TAG,"Publish openSession err=" + JSON.stringify(err))
+      } else {
+        console.info(TAG,"Publish openSession succeed ")
+      }
+    })
+  }
+
+  //开始预览
+  startView=()=>{
+    CommonEventManager.publish("startview", (err) => {
+      if (err?.code) {
+        console.error(TAG, JSON.stringify(err));
+      } else {
+        this.isCapturing = false;
+        this.isStopView =false;
+        this.liveShow();
+      }
+    });
+  }
+  //重连相机
+  reconnectCamera=()=>{
+    CommonEventManager.publish("reconnect", (err) => {
+      if (err?.code) {
+        console.info("[CommonEvent] Publish CallBack err=" + JSON.stringify(err))
+      } else {
+        console.info("[CommonEvent] Publish reconnect succeed ")
+        AlertDialog.show(
+          {
+            title: '请重新插入相机USB线缆',
+            message: '请重新插入相机USB线缆',
+            confirm: {
+              value: '确定',
+              action: () => {
+                console.info('执行重新连接操作');
+                router.back();
+                // 这里可以添加重连逻辑
+              }
+            },
+            cancel: () => {
+              console.info('用户取消操作');
+            }
+          }
+        )
+      }
+    })
+  }
+
+  //开始预览 50ms一张图片(20帧)
+  liveShow = async () => {
+    this.previewManager = new PreviewManager(getContext(this));
+    let index = 0;
+    this.readTimer = setInterval(async () => {
+      if (!this.isStopView && !this.isCapturing) {
+        try {
+          const success = await this.previewManager!.processFrame(index);
+          if (success) {
+            this.commodityPixelMap = this.previewManager!.getActiveBuffer();
+          }
+        } catch (error) {
+          console.warn(TAG, "预览更新失败:", error);
+        }
+      }
+    }, 50);
+  };
+
+  //断开相机(停止预览->关闭连接)
+  disconnectCamera = () => {
+    CommonEventManager.publish("stopview", (err) => {
+      if (err?.code) {
+        console.info(TAG,"Publish stopview err=" + JSON.stringify(err))
+      } else {
+        console.info(TAG,"Publish stopview succeed ")
+        CommonEventManager.publish("closesession", (err) => {
+          if (err?.code) {
+            console.info(TAG,"Publish closesession err=" + JSON.stringify(err))
+          } else {
+            console.info(TAG,"Publish closesession succeed ")
+          }
+        })
+      }
+    })
+  }
+
+  //拍照(停止预览->拍照->开始预览)
+  takePhoto = async () => {
+    this.isStopView = true;
+    this.isCapturing = true;
+    CommonEventManager.publish("stopview", (err) => {
+      if (err?.code) {
+        console.info(TAG,"Publish stopview err=" + JSON.stringify(err));
+        this.isCapturing = false;
+      } else {
+        console.info(TAG,"Publish Publish stopview succeed");
+        CommonEventManager.publish("shootonly", (err) => {
+          if (err?.code) {
+            console.info(TAG,"Publish  shootonly error=" + JSON.stringify(err));
+            this.isCapturing = false;
+          } else {
+            console.info(TAG,"Publish Publish shootonly succeed");
+          }
+        });
+      }
+    });
+  };
+
+  setFlashMode = (mode: 'openflash' | 'closeflash' | 'autoflash') => {
+    this.isStopView = true;
+    CommonEventManager.publish("stopview", (err) => {
+      if (err?.code) {
+        console.info(TAG,"Publish stopview err=" + JSON.stringify(err));
+      } else {
+        console.info(TAG,"Publish Publish stopview succeed");
+        CommonEventManager.publish(mode, (err) => {
+          if (err?.code) {
+            console.info(TAG,"Publish  shootonly error=" + JSON.stringify(err));
+          } else {
+            console.info(TAG,"Publish Publish shootonly succeed");
+             CommonEventManager.publish("startview", (err) => {
+               this.isStopView = false;
+               if (err?.code) {
+                 console.info(TAG,"Publish  shootonly error=" + JSON.stringify(err));
+               }else{
+                 console.info(TAG,"Publish Publish shootonly succeed");
+               }
+             })
+          }
+        });
+      }
+    });
+  }
+
+  //上传照片
+  uploadPhoto=()=>{
+    let imageUri: string = "/data/storage/el2/base/haps/entry/files/image_base64.txt"
+    try {
+      uploadInstance.startUploadBase64(imageUri, () => {
+        this.isUploading = false
+        this.startView();//上传完恢复预览
+      })
+    } catch (error) {
+      console.error(TAG,"upload failed:", error.code);
+    }
+  }
+  async aboutToAppear() {
+    await this.createSubscriber();
+    await this.connectCamera();
+    await this.liveShow();
+  }
+
+  aboutToDisappear(): void {
+    this.isStopView = true;
+    sleep(100)
+    this.disconnectCamera()
+    if (this.subscriber) {
+      CommonEventManager.unsubscribe(this.subscriber);
+    }
+    if (this.readTimer) {
+      clearInterval(this.readTimer);
+    }
+    if (this.commodityPixelMap) {
+      this.commodityPixelMap.release();
+      this.commodityPixelMap = null;
+    }
+    if (this.previewManager) {
+      this.previewManager.release();
+    }
+  }
+  build() {
+    Row() {
+      Stack(){
+        if (this.commodityPixelMap) {
+          Image(this.commodityPixelMap)
+            .width('100%')
+            .height('100%')
+            .objectFit(ImageFit.Fill)
+        }
+        if(this.isUploading){
+            Column() {
+              Text('正在上传中...')
+                .fontSize($r('app.float.fontSize_30'))
+                .margin({bottom:'10%'})
+              LoadingProgress()
+                .color(Color.Blue)
+                .width('25%')
+                .width('25%')
+            }
+            .height('30%')
+            .width('25%')
+            .backgroundColor(Color.White)
+            .borderRadius($r('app.float.virtualSize_16'))
+            .justifyContent(FlexAlign.Center)
+          }
+        Row() {
+            Image(
+              this.selectedIndex === 0 ? $r('app.media.process_flash_auto') :
+                this.selectedIndex === 1 ? $r('app.media.process_flash_open') :
+                $r('app.media.process_flash_close')
+            )
+              .width($r('app.float.virtualSize_48'))
+              .height($r('app.float.virtualSize_48'))
+              .enabled(!this.isUploading)
+              .onClick(() => {
+                this.isExpanded = !this.isExpanded
+              })
+              .margin({right:'5%'})
+            if (this.isExpanded) {
+              Row() {
+                Row(){
+                  Text('自动')
+                    .fontSize($r('app.float.fontSize_24'))
+                    .fontColor(this.selectedIndex===0?$r('app.color.FFFFFF'):$r('app.color.60FFFFFF'))
+                }
+                .width('33.3%')
+                .height('100%')
+                .justifyContent(FlexAlign.Center)
+                .borderRadius($r('app.float.virtualSize_16'))
+                .backgroundColor(this.selectedIndex===0?$r('app.color.0A84FF'):$r('app.color.60000000'))
+                .onClick(() => {
+                  this.setFlashMode('autoflash')
+                  this.isExpanded = false
+                  this.selectedIndex = 0
+                })
+                Row(){
+                  Text('开启')
+                    .fontSize($r('app.float.fontSize_24'))
+                    .fontColor(this.selectedIndex===1?$r('app.color.FFFFFF'):$r('app.color.60FFFFFF'))
+                }
+                .width('33.3%')
+                .height('100%')
+                .justifyContent(FlexAlign.Center)
+                .borderRadius($r('app.float.virtualSize_16'))
+                .backgroundColor(this.selectedIndex===1?$r('app.color.0A84FF'):$r('app.color.60000000'))
+                .onClick(() => {
+                  this.setFlashMode('openflash')
+                  this.isExpanded = false
+                  this.selectedIndex = 1
+                })
+
+                Row(){
+                  Text('关闭')
+                    .fontSize($r('app.float.fontSize_24'))
+                    .fontColor(this.selectedIndex===2?$r('app.color.FFFFFF'):$r('app.color.60FFFFFF'))
+                }
+                .width('33.3%')
+                .height('100%')
+                .justifyContent(FlexAlign.Center)
+                .borderRadius($r('app.float.virtualSize_16'))
+                .backgroundColor(this.selectedIndex===2?$r('app.color.0A84FF'):$r('app.color.60000000'))
+                .onClick(() => {
+                  this.setFlashMode('closeflash')
+                  this.isExpanded = false
+                  this.selectedIndex = 2
+                })
+              }
+              .animation({ duration: 300, curve: Curve.EaseOut }) // 展开动画
+              .backgroundColor($r('app.color.60000000'))
+              .borderRadius($r('app.float.virtualSize_16'))
+              .width('85%')
+              .height('100%')
+            }
+          }
+          .justifyContent(FlexAlign.Start)
+          .alignItems(VerticalAlign.Bottom)
+          .position({ x: '2%', y: '92%' })
+          .height('5%')
+          .width('24%')
+        Image(this.shootButtonClick===1?$r('app.media.process_no_shoot'):$r('app.media.process_shoot'))
+            .width($r('app.float.virtualSize_88'))
+            .height($r('app.float.virtualSize_88'))
+            .scale({ x: this.shootButtonClick, y: this.shootButtonClick })
+            .borderRadius($r('app.float.fontSize_16'))
+            .enabled(!this.isUploading)
+            .animation({
+              duration: 200,
+              curve: Curve.Linear
+            })
+            .onClick(() => {
+              this.shootButtonClick = 0.9;
+              setTimeout(() => {
+                this.shootButtonClick = 1;
+              }, 200);
+              if(this.isUploading){
+                return
+              }
+              this.isUploading = true
+              this.takePhoto();
+            })
+            .position({ x: '48%', y: '90%' })
+      }
+      .width('80%')
+      .height('100%')
+      .backgroundColor($r('app.color.000000'))
+      .border({width:2,color:$r('app.color.10FFFFFF')})
+    }
+    .width('100%')
+    .height('100%')
+    .backgroundColor($r('app.color.10FFFFFF'))
+    .borderRadius($r('app.float.fontSize_16'))
+  }
+}
+
+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;
+    }
+  }
+}
+

+ 4 - 0
entry/src/main/resources/base/element/font.json

@@ -9,6 +9,10 @@
       "value": "48vp"
     },
     {
+      "name": "virtualSize_88",
+      "value": "52.8vp"
+    },
+    {
       "name": "virtualSize_56",
       "value": "33.6vp"
     },

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 4 - 0
entry/src/main/resources/base/media/process_flash_auto.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 4 - 0
entry/src/main/resources/base/media/process_flash_close.svg


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 0
entry/src/main/resources/base/media/process_flash_open.svg


+ 4 - 0
entry/src/main/resources/base/media/process_no_shoot.svg

@@ -0,0 +1,4 @@
+<svg width="88" height="88" viewBox="0 0 88 88" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M44 82C64.9868 82 82 64.9868 82 44C82 23.0132 64.9868 6 44 6C23.0132 6 6 23.0132 6 44C6 64.9868 23.0132 82 44 82ZM44 88C68.3005 88 88 68.3005 88 44C88 19.6995 68.3005 0 44 0C19.6995 0 0 19.6995 0 44C0 68.3005 19.6995 88 44 88Z" fill="#E5E5E5"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M44 73C60.0163 73 73 60.0163 73 44C73 27.9837 60.0163 15 44 15C27.9837 15 15 27.9837 15 44C15 60.0163 27.9837 73 44 73ZM44 77C62.2254 77 77 62.2254 77 44C77 25.7746 62.2254 11 44 11C25.7746 11 11 25.7746 11 44C11 62.2254 25.7746 77 44 77Z" fill="#FFD60A"/>
+</svg>

+ 6 - 0
entry/src/main/resources/base/media/process_shoot.svg

@@ -0,0 +1,6 @@
+<svg width="88" height="88" viewBox="0 0 88 88" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.6">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M44 82C64.9868 82 82 64.9868 82 44C82 23.0132 64.9868 6 44 6C23.0132 6 6 23.0132 6 44C6 64.9868 23.0132 82 44 82ZM44 88C68.3005 88 88 68.3005 88 44C88 19.6995 68.3005 0 44 0C19.6995 0 0 19.6995 0 44C0 68.3005 19.6995 88 44 88Z" fill="#E5E5E5"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M44.0004 63.0984C54.549 63.0984 63.1004 54.5471 63.1004 43.9984C63.1004 33.4498 54.549 24.8984 44.0004 24.8984C33.4518 24.8984 24.9004 33.4498 24.9004 43.9984C24.9004 54.5471 33.4518 63.0984 44.0004 63.0984ZM44.0004 67.0984C56.7582 67.0984 67.1004 56.7562 67.1004 43.9984C67.1004 31.2407 56.7582 20.8984 44.0004 20.8984C31.2426 20.8984 20.9004 31.2407 20.9004 43.9984C20.9004 56.7562 31.2426 67.0984 44.0004 67.0984Z" fill="#FFD60A"/>
+</g>
+</svg>