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