fix: 修复多个外设无法认证的问题
refactor: 同时使用更加优雅的方式处理injection
This commit is contained in:
		@@ -48,14 +48,15 @@
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import { CheckCircle, XCircle, AlertTriangle, Info, X } from "lucide-vue-next";
 | 
			
		||||
import { useAlertStore } from ".";
 | 
			
		||||
import { useRequiredInjection } from "@/utils/Common";
 | 
			
		||||
 | 
			
		||||
const alertStore = useAlertStore();
 | 
			
		||||
const alertStore = useRequiredInjection(useAlertStore);
 | 
			
		||||
 | 
			
		||||
// Computed classes for different alert types
 | 
			
		||||
const alertClasses = computed(() => {
 | 
			
		||||
  const baseClasses = "shadow-lg max-w-sm";
 | 
			
		||||
 | 
			
		||||
  switch (alertStore?.alertState.value.type) {
 | 
			
		||||
  switch (alertStore.alertState.value.type) {
 | 
			
		||||
    case "success":
 | 
			
		||||
      return `${baseClasses} alert-success`;
 | 
			
		||||
    case "error":
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,12 @@
 | 
			
		||||
          <div class="waveform-display">
 | 
			
		||||
            <svg width="100%" height="120" viewBox="0 0 300 120">
 | 
			
		||||
              <rect width="300" height="120" fill="#1a1f25" />
 | 
			
		||||
              <path :d="currentWaveformPath" stroke="lime" stroke-width="2" fill="none" />
 | 
			
		||||
              <path
 | 
			
		||||
                :d="currentWaveformPath"
 | 
			
		||||
                stroke="lime"
 | 
			
		||||
                stroke-width="2"
 | 
			
		||||
                fill="none"
 | 
			
		||||
              />
 | 
			
		||||
 | 
			
		||||
              <!-- 频率和相位显示 -->
 | 
			
		||||
              <text x="20" y="25" fill="#0f0" font-size="14">
 | 
			
		||||
@@ -16,7 +21,13 @@
 | 
			
		||||
              <text x="200" y="25" fill="#0f0" font-size="14">
 | 
			
		||||
                φ: {{ phase }}°
 | 
			
		||||
              </text>
 | 
			
		||||
              <text x="150" y="110" fill="#0f0" font-size="14" text-anchor="middle">
 | 
			
		||||
              <text
 | 
			
		||||
                x="150"
 | 
			
		||||
                y="110"
 | 
			
		||||
                fill="#0f0"
 | 
			
		||||
                font-size="14"
 | 
			
		||||
                text-anchor="middle"
 | 
			
		||||
              >
 | 
			
		||||
                {{ displayTimebase }}
 | 
			
		||||
              </text>
 | 
			
		||||
            </svg>
 | 
			
		||||
@@ -35,10 +46,15 @@
 | 
			
		||||
 | 
			
		||||
          <!-- 波形选择区 -->
 | 
			
		||||
          <div class="waveform-selector">
 | 
			
		||||
            <div v-for="(name, index) in waveformNames" :key="`wave-${index}`" :class="[
 | 
			
		||||
              'waveform-option',
 | 
			
		||||
              { active: currentWaveformIndex === index },
 | 
			
		||||
            ]" @click="selectWaveform(index)">
 | 
			
		||||
            <div
 | 
			
		||||
              v-for="(name, index) in waveformNames"
 | 
			
		||||
              :key="`wave-${index}`"
 | 
			
		||||
              :class="[
 | 
			
		||||
                'waveform-option',
 | 
			
		||||
                { active: currentWaveformIndex === index },
 | 
			
		||||
              ]"
 | 
			
		||||
              @click="selectWaveform(index)"
 | 
			
		||||
            >
 | 
			
		||||
              {{ name }}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
@@ -51,8 +67,13 @@
 | 
			
		||||
                <button class="control-button" @click="decreaseFrequency">
 | 
			
		||||
                  -
 | 
			
		||||
                </button>
 | 
			
		||||
                <input v-model="frequencyInput" @blur="applyFrequencyInput" @keyup.enter="applyFrequencyInput"
 | 
			
		||||
                  class="control-input" type="text" />
 | 
			
		||||
                <input
 | 
			
		||||
                  v-model="frequencyInput"
 | 
			
		||||
                  @blur="applyFrequencyInput"
 | 
			
		||||
                  @keyup.enter="applyFrequencyInput"
 | 
			
		||||
                  class="control-input"
 | 
			
		||||
                  type="text"
 | 
			
		||||
                />
 | 
			
		||||
                <button class="control-button" @click="increaseFrequency">
 | 
			
		||||
                  +
 | 
			
		||||
                </button>
 | 
			
		||||
@@ -63,8 +84,13 @@
 | 
			
		||||
              <span class="control-label">相位:</span>
 | 
			
		||||
              <div class="control-buttons">
 | 
			
		||||
                <button class="control-button" @click="decreasePhase">-</button>
 | 
			
		||||
                <input v-model="phaseInput" @blur="applyPhaseInput" @keyup.enter="applyPhaseInput" class="control-input"
 | 
			
		||||
                  type="text" />
 | 
			
		||||
                <input
 | 
			
		||||
                  v-model="phaseInput"
 | 
			
		||||
                  @blur="applyPhaseInput"
 | 
			
		||||
                  @keyup.enter="applyPhaseInput"
 | 
			
		||||
                  class="control-input"
 | 
			
		||||
                  type="text"
 | 
			
		||||
                />
 | 
			
		||||
                <button class="control-button" @click="increasePhase">+</button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -75,9 +101,12 @@
 | 
			
		||||
            <div class="section-heading">自定义波形</div>
 | 
			
		||||
            <div class="input-group">
 | 
			
		||||
              <label class="input-label">函数表达式:</label>
 | 
			
		||||
              <input v-model="customWaveformExpression" class="function-input"
 | 
			
		||||
              <input
 | 
			
		||||
                v-model="customWaveformExpression"
 | 
			
		||||
                class="function-input"
 | 
			
		||||
                placeholder="例如: sin(t) 或 x^(2/3)+0.9*sqrt(3.3-x^2)*sin(a*PI*x) [a=7.8]"
 | 
			
		||||
                @keyup.enter="applyCustomWaveform" />
 | 
			
		||||
                @keyup.enter="applyCustomWaveform"
 | 
			
		||||
              />
 | 
			
		||||
              <button class="apply-button" @click="applyCustomWaveform">
 | 
			
		||||
                应用
 | 
			
		||||
              </button>
 | 
			
		||||
@@ -86,17 +115,26 @@
 | 
			
		||||
            <div class="example-functions">
 | 
			
		||||
              <div class="example-label">示例函数:</div>
 | 
			
		||||
              <div class="example-buttons">
 | 
			
		||||
                <button class="example-button" @click="applyExampleFunction('sin(t)')">
 | 
			
		||||
                <button
 | 
			
		||||
                  class="example-button"
 | 
			
		||||
                  @click="applyExampleFunction('sin(t)')"
 | 
			
		||||
                >
 | 
			
		||||
                  正弦波
 | 
			
		||||
                </button>
 | 
			
		||||
                <button class="example-button" @click="applyExampleFunction('sin(t)^3')">
 | 
			
		||||
                <button
 | 
			
		||||
                  class="example-button"
 | 
			
		||||
                  @click="applyExampleFunction('sin(t)^3')"
 | 
			
		||||
                >
 | 
			
		||||
                  立方正弦
 | 
			
		||||
                </button>
 | 
			
		||||
                <button class="example-button" @click="
 | 
			
		||||
                  applyExampleFunction(
 | 
			
		||||
                    '((x)^(2/3)+0.9*sqrt(3.3-(x)^2)*sin(10*PI*(x)))*0.75',
 | 
			
		||||
                  )
 | 
			
		||||
                  ">
 | 
			
		||||
                <button
 | 
			
		||||
                  class="example-button"
 | 
			
		||||
                  @click="
 | 
			
		||||
                    applyExampleFunction(
 | 
			
		||||
                      '((x)^(2/3)+0.9*sqrt(3.3-(x)^2)*sin(10*PI*(x)))*0.75',
 | 
			
		||||
                    )
 | 
			
		||||
                  "
 | 
			
		||||
                >
 | 
			
		||||
                  心形函数
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
@@ -105,8 +143,16 @@
 | 
			
		||||
            <div class="drawing-area">
 | 
			
		||||
              <div class="section-heading">波形绘制</div>
 | 
			
		||||
              <div class="waveform-canvas-container" ref="canvasContainer">
 | 
			
		||||
                <canvas ref="drawingCanvas" class="drawing-canvas" width="280" height="100" @mousedown="startDrawing"
 | 
			
		||||
                  @mousemove="draw" @mouseup="stopDrawing" @mouseleave="stopDrawing"></canvas>
 | 
			
		||||
                <canvas
 | 
			
		||||
                  ref="drawingCanvas"
 | 
			
		||||
                  class="drawing-canvas"
 | 
			
		||||
                  width="280"
 | 
			
		||||
                  height="100"
 | 
			
		||||
                  @mousedown="startDrawing"
 | 
			
		||||
                  @mousemove="draw"
 | 
			
		||||
                  @mouseup="stopDrawing"
 | 
			
		||||
                  @mouseleave="stopDrawing"
 | 
			
		||||
                ></canvas>
 | 
			
		||||
                <div class="canvas-actions">
 | 
			
		||||
                  <button class="canvas-button" @click="clearCanvas">
 | 
			
		||||
                    清除
 | 
			
		||||
@@ -123,19 +169,30 @@
 | 
			
		||||
          <div class="saved-waveforms">
 | 
			
		||||
            <div class="section-heading">波形存储槽</div>
 | 
			
		||||
            <div class="slot-container">
 | 
			
		||||
              <div v-for="(slot, index) in waveformSlots" :key="`slot-${index}`"
 | 
			
		||||
                :class="['waveform-slot', { empty: !slot.name }]" @click="loadWaveformSlot(index)">
 | 
			
		||||
              <div
 | 
			
		||||
                v-for="(slot, index) in waveformSlots"
 | 
			
		||||
                :key="`slot-${index}`"
 | 
			
		||||
                :class="['waveform-slot', { empty: !slot.name }]"
 | 
			
		||||
                @click="loadWaveformSlot(index)"
 | 
			
		||||
              >
 | 
			
		||||
                <span class="slot-name">{{
 | 
			
		||||
                  slot.name || `槽 ${index + 1}`
 | 
			
		||||
                  }}</span>
 | 
			
		||||
                <button class="save-button" @click.stop="saveCurrentToSlot(index)">
 | 
			
		||||
                }}</span>
 | 
			
		||||
                <button
 | 
			
		||||
                  class="save-button"
 | 
			
		||||
                  @click.stop="saveCurrentToSlot(index)"
 | 
			
		||||
                >
 | 
			
		||||
                  保存
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <button class="btn btn-primary text-primary-content w-full" :disabled="isApplying" @click="applyOutputWave">
 | 
			
		||||
          <button
 | 
			
		||||
            class="btn btn-primary text-primary-content w-full"
 | 
			
		||||
            :disabled="isApplying"
 | 
			
		||||
            @click="applyOutputWave"
 | 
			
		||||
          >
 | 
			
		||||
            <div v-if="isApplying">
 | 
			
		||||
              <span class="loading loading-spinner"></span>
 | 
			
		||||
              应用中...
 | 
			
		||||
@@ -151,10 +208,10 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, computed, watch, onMounted } from "vue";
 | 
			
		||||
import CollapsibleSection from "../CollapsibleSection.vue";
 | 
			
		||||
import { DDSClient } from "@/APIClient";
 | 
			
		||||
import { useEquipments } from "@/stores/equipments";
 | 
			
		||||
import { useDialogStore } from "@/stores/dialog";
 | 
			
		||||
import { toInteger } from "lodash";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
 | 
			
		||||
// Component Attributes
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
@@ -164,7 +221,7 @@ const props = defineProps<{
 | 
			
		||||
const emit = defineEmits(["update:modelValue"]);
 | 
			
		||||
 | 
			
		||||
// Global varibles
 | 
			
		||||
const dds = new DDSClient();
 | 
			
		||||
const dds = AuthManager.createAuthenticatedDDSClient();
 | 
			
		||||
const eqps = useEquipments();
 | 
			
		||||
const dialog = useDialogStore();
 | 
			
		||||
 | 
			
		||||
@@ -793,7 +850,7 @@ function saveCurrentToSlot(index: number) {
 | 
			
		||||
    type: waveforms[currentWaveformIndex.value],
 | 
			
		||||
    data:
 | 
			
		||||
      drawPoints.value.length > 0 &&
 | 
			
		||||
        currentWaveformIndex.value === waveforms.indexOf("custom")
 | 
			
		||||
      currentWaveformIndex.value === waveforms.indexOf("custom")
 | 
			
		||||
        ? [...drawPoints.value]
 | 
			
		||||
        : null,
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,42 +1,55 @@
 | 
			
		||||
import { ref, reactive, watchPostEffect } from 'vue'
 | 
			
		||||
import { defineStore } from 'pinia'
 | 
			
		||||
import { useLocalStorage } from '@vueuse/core'
 | 
			
		||||
import { isString, toNumber } from 'lodash';
 | 
			
		||||
import { Common } from '@/utils/Common';
 | 
			
		||||
import z from "zod"
 | 
			
		||||
import { isNumber } from 'mathjs';
 | 
			
		||||
import { ref, reactive, watchPostEffect } from "vue";
 | 
			
		||||
import { defineStore } from "pinia";
 | 
			
		||||
import { useLocalStorage } from "@vueuse/core";
 | 
			
		||||
import { isString, toNumber } from "lodash";
 | 
			
		||||
import z from "zod";
 | 
			
		||||
import { isNumber } from "mathjs";
 | 
			
		||||
import { JtagClient, MatrixKeyClient, PowerClient } from "@/APIClient";
 | 
			
		||||
import { Mutex, withTimeout } from 'async-mutex';
 | 
			
		||||
import { Mutex, withTimeout } from "async-mutex";
 | 
			
		||||
import { useConstraintsStore } from "@/stores/constraints";
 | 
			
		||||
import { useDialogStore } from './dialog';
 | 
			
		||||
import { useDialogStore } from "./dialog";
 | 
			
		||||
import { toFileParameterOrUndefined } from "@/utils/Common";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
 | 
			
		||||
export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
export const useEquipments = defineStore("equipments", () => {
 | 
			
		||||
  // Global Stores
 | 
			
		||||
  const constrainsts = useConstraintsStore();
 | 
			
		||||
  const dialog = useDialogStore();
 | 
			
		||||
 | 
			
		||||
  const boardAddr = useLocalStorage('fpga-board-addr', "127.0.0.1");
 | 
			
		||||
  const boardPort = useLocalStorage('fpga-board-port', 1234);
 | 
			
		||||
  const boardAddr = useLocalStorage("fpga-board-addr", "127.0.0.1");
 | 
			
		||||
  const boardPort = useLocalStorage("fpga-board-port", 1234);
 | 
			
		||||
 | 
			
		||||
  // Jtag
 | 
			
		||||
  const jtagBitstream = ref<File>();
 | 
			
		||||
  const jtagBoundaryScanFreq = ref(100);
 | 
			
		||||
  const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"))
 | 
			
		||||
  const jtagClient = new JtagClient();
 | 
			
		||||
  const jtagClientMutex = withTimeout(
 | 
			
		||||
    new Mutex(),
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("JtagClient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const jtagClient = AuthManager.createAuthenticatedJtagClient();
 | 
			
		||||
 | 
			
		||||
  // Matrix Key
 | 
			
		||||
  const matrixKeyStates = reactive(new Array<boolean>(16).fill(false))
 | 
			
		||||
  const matrixKeypadClientMutex = withTimeout(new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"));
 | 
			
		||||
  const matrixKeypadClient = new MatrixKeyClient();
 | 
			
		||||
  const matrixKeyStates = reactive(new Array<boolean>(16).fill(false));
 | 
			
		||||
  const matrixKeypadClientMutex = withTimeout(
 | 
			
		||||
    new Mutex(),
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("Matrixkeyclient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const matrixKeypadClient = AuthManager.createAuthenticatedMatrixKeyClient();
 | 
			
		||||
 | 
			
		||||
  // Power
 | 
			
		||||
  const powerClientMutex = withTimeout(new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"));
 | 
			
		||||
  const powerClient = new PowerClient();
 | 
			
		||||
  const powerClientMutex = withTimeout(
 | 
			
		||||
    new Mutex(),
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("Matrixkeyclient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const powerClient = AuthManager.createAuthenticatedPowerClient();
 | 
			
		||||
 | 
			
		||||
  // Enable Setting
 | 
			
		||||
  const enableJtagBoundaryScan = ref(false);
 | 
			
		||||
  const enableMatrixKey = ref(false);
 | 
			
		||||
  const enablePower = ref(false)
 | 
			
		||||
  const enablePower = ref(false);
 | 
			
		||||
 | 
			
		||||
  // Watch
 | 
			
		||||
  watchPostEffect(async () => {
 | 
			
		||||
@@ -60,8 +73,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
        boardPort.value = portNumber;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (isNumber(port)) {
 | 
			
		||||
    } else if (isNumber(port)) {
 | 
			
		||||
      if (z.number().nonnegative().max(65535).safeParse(port).success) {
 | 
			
		||||
        boardPort.value = port;
 | 
			
		||||
        return true;
 | 
			
		||||
@@ -70,7 +82,10 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setMatrixKey(keyNum: number | string | undefined, keyValue: boolean): boolean {
 | 
			
		||||
  function setMatrixKey(
 | 
			
		||||
    keyNum: number | string | undefined,
 | 
			
		||||
    keyValue: boolean,
 | 
			
		||||
  ): boolean {
 | 
			
		||||
    let _keyNum: number;
 | 
			
		||||
    if (isString(keyNum)) {
 | 
			
		||||
      _keyNum = toNumber(keyNum);
 | 
			
		||||
@@ -112,7 +127,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.uploadBitstream(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        Common.toFileParameterOrNull(bitstream),
 | 
			
		||||
        toFileParameterOrUndefined(bitstream),
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -127,7 +142,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.downloadBitstream(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -144,7 +159,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.getDeviceIDCode(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -161,7 +176,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
      const resp = await jtagClient.setSpeed(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        speed
 | 
			
		||||
        speed,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -179,7 +194,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
      const resp = await matrixKeypadClient.setMatrixKeyStatus(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        keyStates
 | 
			
		||||
        keyStates,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -223,7 +238,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
      const resp = await powerClient.setPowerOnOff(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        enable
 | 
			
		||||
        enable,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -266,6 +281,5 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    powerClient,
 | 
			
		||||
    powerClientMutex,
 | 
			
		||||
    powerSetOnOff,
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import { createInjectionState } from "@vueuse/core";
 | 
			
		||||
import { RemoteUpdateClient, DataClient, Board } from "@/APIClient";
 | 
			
		||||
import { Common } from "@/utils/Common";
 | 
			
		||||
import { isUndefined } from "lodash";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
import { toFileParameterOrNull } from "./Common";
 | 
			
		||||
 | 
			
		||||
// 统一的板卡数据接口,扩展原有的Board类型
 | 
			
		||||
export interface BoardData extends Board {
 | 
			
		||||
@@ -178,10 +178,10 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
 | 
			
		||||
      
 | 
			
		||||
      const uploadResult = await remoteUpdater.uploadBitstreams(
 | 
			
		||||
        board.ipAddr,
 | 
			
		||||
        Common.toFileParameterOrNull(goldBitstream),
 | 
			
		||||
        Common.toFileParameterOrNull(appBitstream1),
 | 
			
		||||
        Common.toFileParameterOrNull(appBitstream2),
 | 
			
		||||
        Common.toFileParameterOrNull(appBitstream3),
 | 
			
		||||
        toFileParameterOrNull(goldBitstream),
 | 
			
		||||
        toFileParameterOrNull(appBitstream1),
 | 
			
		||||
        toFileParameterOrNull(appBitstream2),
 | 
			
		||||
        toFileParameterOrNull(appBitstream3),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (!uploadResult) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,50 @@
 | 
			
		||||
import { type FileParameter } from "@/APIClient";
 | 
			
		||||
import { isNull, isUndefined } from "lodash";
 | 
			
		||||
 | 
			
		||||
export namespace Common {
 | 
			
		||||
  export function toFileParameter(object: File): FileParameter {
 | 
			
		||||
    if (isNull(object) || isUndefined(object))
 | 
			
		||||
      throw new Error("File is Null or Undefined");
 | 
			
		||||
export function toFileParameter(object: File): FileParameter {
 | 
			
		||||
  if (isNull(object) || isUndefined(object))
 | 
			
		||||
    throw new Error("File is Null or Undefined");
 | 
			
		||||
  return {
 | 
			
		||||
    data: object,
 | 
			
		||||
    fileName: object.name,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function toFileParameterOrNull(
 | 
			
		||||
  object?: File | null,
 | 
			
		||||
): FileParameter | null {
 | 
			
		||||
  if (isNull(object) || isUndefined(object)) return null;
 | 
			
		||||
  else
 | 
			
		||||
    return {
 | 
			
		||||
      data: object,
 | 
			
		||||
      fileName: object.name
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export function toFileParameterOrNull(object?: File | null): FileParameter | null {
 | 
			
		||||
    if (isNull(object) || isUndefined(object)) return null;
 | 
			
		||||
    else return {
 | 
			
		||||
      data: object,
 | 
			
		||||
      fileName: object.name
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
      fileName: object.name,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function toFileParameterOrUndefined(
 | 
			
		||||
  object?: File | undefined,
 | 
			
		||||
): FileParameter | undefined {
 | 
			
		||||
  if (isNull(object) || isUndefined(object)) return undefined;
 | 
			
		||||
  else
 | 
			
		||||
    return {
 | 
			
		||||
      data: object,
 | 
			
		||||
      fileName: object.name,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 自定义 Hook:检查依赖注入值是否为空
 | 
			
		||||
export function useRequiredInjection<T>(useFn: () => T | undefined): T {
 | 
			
		||||
  const value = useFn();
 | 
			
		||||
  if (value === undefined) {
 | 
			
		||||
    throw new Error("Missing required injection");
 | 
			
		||||
  }
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useOptionalInjection<T>(
 | 
			
		||||
  useFn: () => T | undefined,
 | 
			
		||||
  defaultValue: T,
 | 
			
		||||
): T {
 | 
			
		||||
  const value = useFn();
 | 
			
		||||
  return value ?? defaultValue;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user