refactor: 使用更简洁的方式进行认证

This commit is contained in:
SikongJueluo 2025-08-16 14:53:28 +08:00
parent c974de593a
commit e61cf96c07
No known key found for this signature in database
24 changed files with 2118 additions and 2089 deletions

View File

@ -1,4 +1,4 @@
import { ResourcePurpose } from "@/APIClient"; import { ResourceClient, ResourcePurpose } from "@/APIClient";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
// 定义 diagram.json 的类型结构 // 定义 diagram.json 的类型结构
@ -94,7 +94,7 @@ export async function loadDiagramData(examId?: string): Promise<DiagramData> {
// 如果提供了examId优先从API加载实验的diagram // 如果提供了examId优先从API加载实验的diagram
if (examId) { if (examId) {
try { try {
const resourceClient = AuthManager.createAuthenticatedResourceClient(); const resourceClient = AuthManager.createClient(ResourceClient);
// 获取diagram类型的资源列表 // 获取diagram类型的资源列表
const resources = await resourceClient.getResourceList( const resources = await resourceClient.getResourceList(

View File

@ -31,8 +31,16 @@ export type Channel = {
// 全局模式选项 // 全局模式选项
const globalModes = [ const globalModes = [
{value: GlobalCaptureMode.AND,label: "AND",description: "所有条件都满足时触发",}, {
{value: GlobalCaptureMode.OR,label: "OR",description: "任一条件满足时触发",}, value: GlobalCaptureMode.AND,
label: "AND",
description: "所有条件都满足时触发",
},
{
value: GlobalCaptureMode.OR,
label: "OR",
description: "任一条件满足时触发",
},
{ value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" }, { value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" },
{ value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" }, { value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" },
]; ];
@ -70,21 +78,53 @@ const channelDivOptions = [
]; ];
const ClockDivOptions = [ const ClockDivOptions = [
{ value: AnalyzerClockDiv.DIV1, label: "120MHz", description: "采样频率120MHz" }, {
{ value: AnalyzerClockDiv.DIV2, label: "60MHz", description: "采样频率60MHz" }, value: AnalyzerClockDiv.DIV1,
{ value: AnalyzerClockDiv.DIV4, label: "30MHz", description: "采样频率30MHz" }, label: "120MHz",
{ value: AnalyzerClockDiv.DIV8, label: "15MHz", description: "采样频率15MHz" }, description: "采样频率120MHz",
{ value: AnalyzerClockDiv.DIV16, label: "7.5MHz", description: "采样频率7.5MHz" }, },
{ value: AnalyzerClockDiv.DIV32, label: "3.75MHz", description: "采样频率3.75MHz" }, {
{ value: AnalyzerClockDiv.DIV64, label: "1.875MHz", description: "采样频率1.875MHz" }, value: AnalyzerClockDiv.DIV2,
{ value: AnalyzerClockDiv.DIV128, label: "937.5KHz", description: "采样频率937.5KHz" }, label: "60MHz",
description: "采样频率60MHz",
},
{
value: AnalyzerClockDiv.DIV4,
label: "30MHz",
description: "采样频率30MHz",
},
{
value: AnalyzerClockDiv.DIV8,
label: "15MHz",
description: "采样频率15MHz",
},
{
value: AnalyzerClockDiv.DIV16,
label: "7.5MHz",
description: "采样频率7.5MHz",
},
{
value: AnalyzerClockDiv.DIV32,
label: "3.75MHz",
description: "采样频率3.75MHz",
},
{
value: AnalyzerClockDiv.DIV64,
label: "1.875MHz",
description: "采样频率1.875MHz",
},
{
value: AnalyzerClockDiv.DIV128,
label: "937.5KHz",
description: "采样频率937.5KHz",
},
]; ];
// 捕获深度限制常量 // 捕获深度限制常量
const CAPTURE_LENGTH_MIN = 1024; // 最小捕获深度 1024 const CAPTURE_LENGTH_MIN = 1024; // 最小捕获深度 1024
const CAPTURE_LENGTH_MAX = 0x10000000 - 0x01000000; // 最大捕获深度 const CAPTURE_LENGTH_MAX = 0x10000000 - 0x01000000; // 最大捕获深度
// 预捕获深度限制常量 // 预捕获深度限制常量
const PRE_CAPTURE_LENGTH_MIN = 2; // 最小预捕获深度 2 const PRE_CAPTURE_LENGTH_MIN = 2; // 最小预捕获深度 2
// 默认颜色数组 // 默认颜色数组
@ -170,40 +210,64 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
// 转换通道数字到枚举值 // 转换通道数字到枚举值
const getChannelDivEnum = (channelCount: number): AnalyzerChannelDiv => { const getChannelDivEnum = (channelCount: number): AnalyzerChannelDiv => {
switch (channelCount) { switch (channelCount) {
case 1: return AnalyzerChannelDiv.ONE; case 1:
case 2: return AnalyzerChannelDiv.TWO; return AnalyzerChannelDiv.ONE;
case 4: return AnalyzerChannelDiv.FOUR; case 2:
case 8: return AnalyzerChannelDiv.EIGHT; return AnalyzerChannelDiv.TWO;
case 16: return AnalyzerChannelDiv.XVI; case 4:
case 32: return AnalyzerChannelDiv.XXXII; return AnalyzerChannelDiv.FOUR;
default: return AnalyzerChannelDiv.EIGHT; case 8:
return AnalyzerChannelDiv.EIGHT;
case 16:
return AnalyzerChannelDiv.XVI;
case 32:
return AnalyzerChannelDiv.XXXII;
default:
return AnalyzerChannelDiv.EIGHT;
} }
}; };
// 验证捕获深度 // 验证捕获深度
const validateCaptureLength = (value: number): { valid: boolean; message?: string } => { const validateCaptureLength = (
value: number,
): { valid: boolean; message?: string } => {
if (!Number.isInteger(value)) { if (!Number.isInteger(value)) {
return { valid: false, message: "捕获深度必须是整数" }; return { valid: false, message: "捕获深度必须是整数" };
} }
if (value < CAPTURE_LENGTH_MIN) { if (value < CAPTURE_LENGTH_MIN) {
return { valid: false, message: `捕获深度不能小于 ${CAPTURE_LENGTH_MIN}` }; return {
valid: false,
message: `捕获深度不能小于 ${CAPTURE_LENGTH_MIN}`,
};
} }
if (value > CAPTURE_LENGTH_MAX) { if (value > CAPTURE_LENGTH_MAX) {
return { valid: false, message: `捕获深度不能大于 ${CAPTURE_LENGTH_MAX.toLocaleString()}` }; return {
valid: false,
message: `捕获深度不能大于 ${CAPTURE_LENGTH_MAX.toLocaleString()}`,
};
} }
return { valid: true }; return { valid: true };
}; };
// 验证预捕获深度 // 验证预捕获深度
const validatePreCaptureLength = (value: number, currentCaptureLength: number): { valid: boolean; message?: string } => { const validatePreCaptureLength = (
value: number,
currentCaptureLength: number,
): { valid: boolean; message?: string } => {
if (!Number.isInteger(value)) { if (!Number.isInteger(value)) {
return { valid: false, message: "预捕获深度必须是整数" }; return { valid: false, message: "预捕获深度必须是整数" };
} }
if (value < PRE_CAPTURE_LENGTH_MIN) { if (value < PRE_CAPTURE_LENGTH_MIN) {
return { valid: false, message: `预捕获深度不能小于 ${PRE_CAPTURE_LENGTH_MIN}` }; return {
valid: false,
message: `预捕获深度不能小于 ${PRE_CAPTURE_LENGTH_MIN}`,
};
} }
if (value >= currentCaptureLength) { if (value >= currentCaptureLength) {
return { valid: false, message: `预捕获深度不能大于等于捕获深度 (${currentCaptureLength})` }; return {
valid: false,
message: `预捕获深度不能大于等于捕获深度 (${currentCaptureLength})`,
};
} }
return { valid: true }; return { valid: true };
}; };
@ -215,13 +279,13 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
alert?.error(validation.message!, 3000); alert?.error(validation.message!, 3000);
return false; return false;
} }
// 检查预捕获深度是否仍然有效 // 检查预捕获深度是否仍然有效
if (preCaptureLength.value >= value) { if (preCaptureLength.value >= value) {
preCaptureLength.value = Math.max(0, value - 1); preCaptureLength.value = Math.max(0, value - 1);
alert?.warn(`预捕获深度已自动调整为 ${preCaptureLength.value}`, 3000); alert?.warn(`预捕获深度已自动调整为 ${preCaptureLength.value}`, 3000);
} }
captureLength.value = value; captureLength.value = value;
return true; return true;
}; };
@ -233,7 +297,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
alert?.error(validation.message!, 3000); alert?.error(validation.message!, 3000);
return false; return false;
} }
preCaptureLength.value = value; preCaptureLength.value = value;
return true; return true;
}; };
@ -241,12 +305,12 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
// 设置通道组 // 设置通道组
const setChannelDiv = (channelCount: number) => { const setChannelDiv = (channelCount: number) => {
// 验证通道数量是否有效 // 验证通道数量是否有效
if (!channelDivOptions.find(option => option.value === channelCount)) { if (!channelDivOptions.find((option) => option.value === channelCount)) {
console.error(`无效的通道组设置: ${channelCount}`); console.error(`无效的通道组设置: ${channelCount}`);
return; return;
} }
currentChannelDiv.value = channelCount; currentChannelDiv.value = channelCount;
// 禁用所有通道 // 禁用所有通道
channels.forEach((channel) => { channels.forEach((channel) => {
channel.enabled = false; channel.enabled = false;
@ -257,7 +321,9 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
channels[i].enabled = true; channels[i].enabled = true;
} }
const option = channelDivOptions.find(opt => opt.value === channelCount); const option = channelDivOptions.find(
(opt) => opt.value === channelCount,
);
alert?.success(`已设置为${option?.label}`, 2000); alert?.success(`已设置为${option?.label}`, 2000);
}; };
@ -294,7 +360,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
const getCaptureData = async () => { const getCaptureData = async () => {
try { try {
const client = AuthManager.createAuthenticatedLogicAnalyzerClient(); const client = AuthManager.createClient(LogicAnalyzerClient);
// 获取捕获数据,使用当前设置的捕获长度 // 获取捕获数据,使用当前设置的捕获长度
const base64Data = await client.getCaptureData(captureLength.value); const base64Data = await client.getCaptureData(captureLength.value);
@ -308,7 +374,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
// 根据当前通道数量解析数据 // 根据当前通道数量解析数据
const channelCount = currentChannelDiv.value; const channelCount = currentChannelDiv.value;
const timeStepNs = currentSamplePeriodNs.value; const timeStepNs = currentSamplePeriodNs.value;
let sampleCount: number; let sampleCount: number;
let x: number[]; let x: number[];
let y: number[][]; let y: number[][];
@ -316,19 +382,16 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
if (channelCount === 1) { if (channelCount === 1) {
// 1通道每个字节包含8个时间单位的数据 // 1通道每个字节包含8个时间单位的数据
sampleCount = bytes.length * 8; sampleCount = bytes.length * 8;
// 创建时间轴 // 创建时间轴
x = Array.from( x = Array.from(
{ length: sampleCount }, { length: sampleCount },
(_, i) => (i * timeStepNs) / 1000, (_, i) => (i * timeStepNs) / 1000,
); // 转换为微秒 ); // 转换为微秒
// 创建通道数据数组 // 创建通道数据数组
y = Array.from( y = Array.from({ length: 1 }, () => new Array(sampleCount));
{ length: 1 },
() => new Array(sampleCount),
);
// 解析数据每个字节的8个位对应8个时间单位 // 解析数据每个字节的8个位对应8个时间单位
for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) { for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
const byte = bytes[byteIndex]; const byte = bytes[byteIndex];
@ -340,19 +403,16 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
} else if (channelCount === 2) { } else if (channelCount === 2) {
// 2通道每个字节包含4个时间单位的数据 // 2通道每个字节包含4个时间单位的数据
sampleCount = bytes.length * 4; sampleCount = bytes.length * 4;
// 创建时间轴 // 创建时间轴
x = Array.from( x = Array.from(
{ length: sampleCount }, { length: sampleCount },
(_, i) => (i * timeStepNs) / 1000, (_, i) => (i * timeStepNs) / 1000,
); // 转换为微秒 ); // 转换为微秒
// 创建通道数据数组 // 创建通道数据数组
y = Array.from( y = Array.from({ length: 2 }, () => new Array(sampleCount));
{ length: 2 },
() => new Array(sampleCount),
);
// 解析数据每个字节的8个位对应4个时间单位的2通道数据 // 解析数据每个字节的8个位对应4个时间单位的2通道数据
// 位分布:[T3_CH1, T3_CH0, T2_CH1, T2_CH0, T1_CH1, T1_CH0, T0_CH1, T0_CH0] // 位分布:[T3_CH1, T3_CH0, T2_CH1, T2_CH0, T1_CH1, T1_CH0, T0_CH1, T0_CH0]
for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) { for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
@ -360,37 +420,34 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
for (let timeUnit = 0; timeUnit < 4; timeUnit++) { for (let timeUnit = 0; timeUnit < 4; timeUnit++) {
const timeIndex = byteIndex * 4 + timeUnit; const timeIndex = byteIndex * 4 + timeUnit;
const bitOffset = timeUnit * 2; const bitOffset = timeUnit * 2;
y[0][timeIndex] = (byte >> bitOffset) & 1; // CH0 y[0][timeIndex] = (byte >> bitOffset) & 1; // CH0
y[1][timeIndex] = (byte >> (bitOffset + 1)) & 1; // CH1 y[1][timeIndex] = (byte >> (bitOffset + 1)) & 1; // CH1
} }
} }
} else if (channelCount === 4) { } else if (channelCount === 4) {
// 4通道每个字节包含2个时间单位的数据 // 4通道每个字节包含2个时间单位的数据
sampleCount = bytes.length * 2; sampleCount = bytes.length * 2;
// 创建时间轴 // 创建时间轴
x = Array.from( x = Array.from(
{ length: sampleCount }, { length: sampleCount },
(_, i) => (i * timeStepNs) / 1000, (_, i) => (i * timeStepNs) / 1000,
); // 转换为微秒 ); // 转换为微秒
// 创建通道数据数组 // 创建通道数据数组
y = Array.from( y = Array.from({ length: 4 }, () => new Array(sampleCount));
{ length: 4 },
() => new Array(sampleCount),
);
// 解析数据每个字节的8个位对应2个时间单位的4通道数据 // 解析数据每个字节的8个位对应2个时间单位的4通道数据
// 位分布:[T1_CH3, T1_CH2, T1_CH1, T1_CH0, T0_CH3, T0_CH2, T0_CH1, T0_CH0] // 位分布:[T1_CH3, T1_CH2, T1_CH1, T1_CH0, T0_CH3, T0_CH2, T0_CH1, T0_CH0]
for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) { for (let byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
const byte = bytes[byteIndex]; const byte = bytes[byteIndex];
// 处理第一个时间单位低4位 // 处理第一个时间单位低4位
const timeIndex1 = byteIndex * 2; const timeIndex1 = byteIndex * 2;
for (let channel = 0; channel < 4; channel++) { for (let channel = 0; channel < 4; channel++) {
y[channel][timeIndex1] = (byte >> channel) & 1; y[channel][timeIndex1] = (byte >> channel) & 1;
} }
// 处理第二个时间单位高4位 // 处理第二个时间单位高4位
const timeIndex2 = byteIndex * 2 + 1; const timeIndex2 = byteIndex * 2 + 1;
for (let channel = 0; channel < 4; channel++) { for (let channel = 0; channel < 4; channel++) {
@ -400,19 +457,16 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
} else if (channelCount === 8) { } else if (channelCount === 8) {
// 8通道每个字节包含1个时间单位的8个通道数据 // 8通道每个字节包含1个时间单位的8个通道数据
sampleCount = bytes.length; sampleCount = bytes.length;
// 创建时间轴 // 创建时间轴
x = Array.from( x = Array.from(
{ length: sampleCount }, { length: sampleCount },
(_, i) => (i * timeStepNs) / 1000, (_, i) => (i * timeStepNs) / 1000,
); // 转换为微秒 ); // 转换为微秒
// 创建8个通道的数据 // 创建8个通道的数据
y = Array.from( y = Array.from({ length: 8 }, () => new Array(sampleCount));
{ length: 8 },
() => new Array(sampleCount),
);
// 解析每个字节的8个位到对应通道 // 解析每个字节的8个位到对应通道
for (let i = 0; i < sampleCount; i++) { for (let i = 0; i < sampleCount; i++) {
const byte = bytes[i]; const byte = bytes[i];
@ -424,30 +478,27 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
} else if (channelCount === 16) { } else if (channelCount === 16) {
// 16通道每2个字节包含1个时间单位的16个通道数据 // 16通道每2个字节包含1个时间单位的16个通道数据
sampleCount = bytes.length / 2; sampleCount = bytes.length / 2;
// 创建时间轴 // 创建时间轴
x = Array.from( x = Array.from(
{ length: sampleCount }, { length: sampleCount },
(_, i) => (i * timeStepNs) / 1000, (_, i) => (i * timeStepNs) / 1000,
); // 转换为微秒 ); // 转换为微秒
// 创建16个通道的数据 // 创建16个通道的数据
y = Array.from( y = Array.from({ length: 16 }, () => new Array(sampleCount));
{ length: 16 },
() => new Array(sampleCount),
);
// 解析数据每2个字节为一个时间单位 // 解析数据每2个字节为一个时间单位
for (let timeIndex = 0; timeIndex < sampleCount; timeIndex++) { for (let timeIndex = 0; timeIndex < sampleCount; timeIndex++) {
const byteIndex = timeIndex * 2; const byteIndex = timeIndex * 2;
const byte1 = bytes[byteIndex]; // [7:0] const byte1 = bytes[byteIndex]; // [7:0]
const byte2 = bytes[byteIndex + 1]; // [15:8] const byte2 = bytes[byteIndex + 1]; // [15:8]
// 处理低8位通道 [7:0] // 处理低8位通道 [7:0]
for (let channel = 0; channel < 8; channel++) { for (let channel = 0; channel < 8; channel++) {
y[channel][timeIndex] = (byte1 >> channel) & 1; y[channel][timeIndex] = (byte1 >> channel) & 1;
} }
// 处理高8位通道 [15:8] // 处理高8位通道 [15:8]
for (let channel = 0; channel < 8; channel++) { for (let channel = 0; channel < 8; channel++) {
y[channel + 8][timeIndex] = (byte2 >> channel) & 1; y[channel + 8][timeIndex] = (byte2 >> channel) & 1;
@ -456,42 +507,39 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
} else if (channelCount === 32) { } else if (channelCount === 32) {
// 32通道每4个字节包含1个时间单位的32个通道数据 // 32通道每4个字节包含1个时间单位的32个通道数据
sampleCount = bytes.length / 4; sampleCount = bytes.length / 4;
// 创建时间轴 // 创建时间轴
x = Array.from( x = Array.from(
{ length: sampleCount }, { length: sampleCount },
(_, i) => (i * timeStepNs) / 1000, (_, i) => (i * timeStepNs) / 1000,
); // 转换为微秒 ); // 转换为微秒
// 创建32个通道的数据 // 创建32个通道的数据
y = Array.from( y = Array.from({ length: 32 }, () => new Array(sampleCount));
{ length: 32 },
() => new Array(sampleCount),
);
// 解析数据每4个字节为一个时间单位 // 解析数据每4个字节为一个时间单位
for (let timeIndex = 0; timeIndex < sampleCount; timeIndex++) { for (let timeIndex = 0; timeIndex < sampleCount; timeIndex++) {
const byteIndex = timeIndex * 4; const byteIndex = timeIndex * 4;
const byte1 = bytes[byteIndex]; // [7:0] const byte1 = bytes[byteIndex]; // [7:0]
const byte2 = bytes[byteIndex + 1]; // [15:8] const byte2 = bytes[byteIndex + 1]; // [15:8]
const byte3 = bytes[byteIndex + 2]; // [23:16] const byte3 = bytes[byteIndex + 2]; // [23:16]
const byte4 = bytes[byteIndex + 3]; // [31:24] const byte4 = bytes[byteIndex + 3]; // [31:24]
// 处理 [7:0] // 处理 [7:0]
for (let channel = 0; channel < 8; channel++) { for (let channel = 0; channel < 8; channel++) {
y[channel][timeIndex] = (byte1 >> channel) & 1; y[channel][timeIndex] = (byte1 >> channel) & 1;
} }
// 处理 [15:8] // 处理 [15:8]
for (let channel = 0; channel < 8; channel++) { for (let channel = 0; channel < 8; channel++) {
y[channel + 8][timeIndex] = (byte2 >> channel) & 1; y[channel + 8][timeIndex] = (byte2 >> channel) & 1;
} }
// 处理 [23:16] // 处理 [23:16]
for (let channel = 0; channel < 8; channel++) { for (let channel = 0; channel < 8; channel++) {
y[channel + 16][timeIndex] = (byte3 >> channel) & 1; y[channel + 16][timeIndex] = (byte3 >> channel) & 1;
} }
// 处理 [31:24] // 处理 [31:24]
for (let channel = 0; channel < 8; channel++) { for (let channel = 0; channel < 8; channel++) {
y[channel + 24][timeIndex] = (byte4 >> channel) & 1; y[channel + 24][timeIndex] = (byte4 >> channel) & 1;
@ -525,11 +573,11 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
isCapturing.value = true; isCapturing.value = true;
const release = await operationMutex.acquire(); const release = await operationMutex.acquire();
try { try {
const client = AuthManager.createAuthenticatedLogicAnalyzerClient(); const client = AuthManager.createClient(LogicAnalyzerClient);
// 1. 先应用配置 // 1. 先应用配置
alert?.info("正在应用配置...", 2000); alert?.info("正在应用配置...", 2000);
// 准备配置数据 - 包含所有32个通道未启用的通道设置为默认值 // 准备配置数据 - 包含所有32个通道未启用的通道设置为默认值
const allSignals = signalConfigs.map((signal, index) => { const allSignals = signalConfigs.map((signal, index) => {
if (channels[index].enabled) { if (channels[index].enabled) {
@ -632,7 +680,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
const release = await operationMutex.acquire(); const release = await operationMutex.acquire();
try { try {
const client = AuthManager.createAuthenticatedLogicAnalyzerClient(); const client = AuthManager.createClient(LogicAnalyzerClient);
// 执行强制捕获来停止当前捕获 // 执行强制捕获来停止当前捕获
const forceSuccess = await client.setCaptureMode(false, false); const forceSuccess = await client.setCaptureMode(false, false);
@ -661,7 +709,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
const release = await operationMutex.acquire(); const release = await operationMutex.acquire();
try { try {
const client = AuthManager.createAuthenticatedLogicAnalyzerClient(); const client = AuthManager.createClient(LogicAnalyzerClient);
// 执行强制捕获来停止当前捕获 // 执行强制捕获来停止当前捕获
const forceSuccess = await client.setCaptureMode(true, true); const forceSuccess = await client.setCaptureMode(true, true);
@ -677,7 +725,7 @@ const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
`强制捕获失败: ${error instanceof Error ? error.message : "未知错误"}`, `强制捕获失败: ${error instanceof Error ? error.message : "未知错误"}`,
3000, 3000,
); );
} finally{ } finally {
release(); release();
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -145,6 +145,7 @@ import {
ChevronDownIcon, ChevronDownIcon,
} from "lucide-vue-next"; } from "lucide-vue-next";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { DataClient } from "@/APIClient";
const router = useRouter(); const router = useRouter();
@ -158,7 +159,7 @@ const loadUserInfo = async () => {
try { try {
const authenticated = await AuthManager.isAuthenticated(); const authenticated = await AuthManager.isAuthenticated();
if (authenticated) { if (authenticated) {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const userInfo = await client.getUserInfo(); const userInfo = await client.getUserInfo();
userName.value = userInfo.name; userName.value = userInfo.name;
isLoggedIn.value = true; isLoggedIn.value = true;

View File

@ -4,6 +4,7 @@ import { Mutex } from "async-mutex";
import { import {
OscilloscopeFullConfig, OscilloscopeFullConfig,
OscilloscopeDataResponse, OscilloscopeDataResponse,
OscilloscopeApiClient,
} from "@/APIClient"; } from "@/APIClient";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { useAlertStore } from "@/components/Alert"; import { useAlertStore } from "@/components/Alert";
@ -31,257 +32,269 @@ const DEFAULT_CONFIG: OscilloscopeFullConfig = new OscilloscopeFullConfig({
}); });
// 采样频率常量(后端返回) // 采样频率常量(后端返回)
const [useProvideOscilloscope, useOscilloscopeState] = createInjectionState(() => { const [useProvideOscilloscope, useOscilloscopeState] = createInjectionState(
const oscData = shallowRef<OscilloscopeDataType>(); () => {
const alert = useRequiredInjection(useAlertStore); const oscData = shallowRef<OscilloscopeDataType>();
const alert = useRequiredInjection(useAlertStore);
// 互斥锁 // 互斥锁
const operationMutex = new Mutex(); const operationMutex = new Mutex();
// 状态 // 状态
const isApplying = ref(false); const isApplying = ref(false);
const isCapturing = ref(false); const isCapturing = ref(false);
// 配置 // 配置
const config = reactive<OscilloscopeFullConfig>(new OscilloscopeFullConfig({ ...DEFAULT_CONFIG })); const config = reactive<OscilloscopeFullConfig>(
new OscilloscopeFullConfig({ ...DEFAULT_CONFIG }),
);
// 采样点数(由后端数据决定) // 采样点数(由后端数据决定)
const sampleCount = ref(0); const sampleCount = ref(0);
// 采样周期ns由adFrequency计算 // 采样周期ns由adFrequency计算
const samplePeriodNs = computed(() => const samplePeriodNs = computed(() =>
oscData.value?.adFrequency ? 1_000_000_000 / oscData.value.adFrequency : 200 oscData.value?.adFrequency
); ? 1_000_000_000 / oscData.value.adFrequency
: 200,
);
// 应用配置 // 应用配置
const applyConfiguration = async () => { const applyConfiguration = async () => {
if (operationMutex.isLocked()) { if (operationMutex.isLocked()) {
alert.warn("有其他操作正在进行中,请稍后再试", 3000); alert.warn("有其他操作正在进行中,请稍后再试", 3000);
return; return;
}
const release = await operationMutex.acquire();
isApplying.value = true;
try {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
const success = await client.initialize({ ...config });
if (success) {
alert.success("示波器配置已应用", 2000);
} else {
throw new Error("应用失败");
} }
} catch (error) { const release = await operationMutex.acquire();
alert.error("应用配置失败", 3000); isApplying.value = true;
} finally { try {
isApplying.value = false; const client = AuthManager.createClient(OscilloscopeApiClient);
release(); const success = await client.initialize({ ...config });
} if (success) {
}; alert.success("示波器配置已应用", 2000);
} else {
// 重置配置 throw new Error("应用失败");
const resetConfiguration = () => { }
Object.assign(config, { ...DEFAULT_CONFIG }); } catch (error) {
alert.info("配置已重置", 2000); alert.error("应用配置失败", 3000);
}; } finally {
isApplying.value = false;
const clearOscilloscopeData = () => { release();
oscData.value = undefined;
}
// 获取数据
const getOscilloscopeData = async () => {
try {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
const resp: OscilloscopeDataResponse = await client.getData();
// 解析波形数据
const binaryString = atob(resp.waveformData);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
} }
sampleCount.value = bytes.length; };
// 构建时间轴 // 重置配置
const resetConfiguration = () => {
Object.assign(config, { ...DEFAULT_CONFIG });
alert.info("配置已重置", 2000);
};
const clearOscilloscopeData = () => {
oscData.value = undefined;
};
// 获取数据
const getOscilloscopeData = async () => {
try {
const client = AuthManager.createClient(OscilloscopeApiClient);
const resp: OscilloscopeDataResponse = await client.getData();
// 解析波形数据
const binaryString = atob(resp.waveformData);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
sampleCount.value = bytes.length;
// 构建时间轴
const x = Array.from(
{ length: bytes.length },
(_, i) => (i * samplePeriodNs.value) / 1000, // us
);
const y = Array.from(bytes);
oscData.value = {
x,
y,
xUnit: "us",
yUnit: "V",
adFrequency: resp.adFrequency,
adVpp: resp.adVpp,
adMax: resp.adMax,
adMin: resp.adMin,
};
} catch (error) {
alert.error("获取示波器数据失败", 3000);
}
};
// 定时器引用
let refreshIntervalId: number | undefined;
// 刷新间隔(毫秒),可根据需要调整
const refreshIntervalMs = ref(1000);
// 定时刷新函数
const startAutoRefresh = () => {
if (refreshIntervalId !== undefined) return;
refreshIntervalId = window.setInterval(async () => {
await refreshRAM();
await getOscilloscopeData();
}, refreshIntervalMs.value);
};
const stopAutoRefresh = () => {
if (refreshIntervalId !== undefined) {
clearInterval(refreshIntervalId);
refreshIntervalId = undefined;
isCapturing.value = false;
}
};
// 启动捕获
const startCapture = async () => {
if (operationMutex.isLocked()) {
alert.warn("有其他操作正在进行中,请稍后再试", 3000);
return;
}
isCapturing.value = true;
const release = await operationMutex.acquire();
try {
const client = AuthManager.createClient(OscilloscopeApiClient);
const started = await client.startCapture();
if (!started) throw new Error("无法启动捕获");
alert.info("开始捕获...", 2000);
// 启动定时刷新
startAutoRefresh();
} catch (error) {
alert.error("捕获失败", 3000);
isCapturing.value = false;
stopAutoRefresh();
} finally {
release();
}
};
// 停止捕获
const stopCapture = async () => {
if (!isCapturing.value) {
alert.warn("当前没有正在进行的捕获操作", 2000);
return;
}
isCapturing.value = false;
stopAutoRefresh();
const release = await operationMutex.acquire();
try {
const client = AuthManager.createClient(OscilloscopeApiClient);
const stopped = await client.stopCapture();
if (!stopped) throw new Error("无法停止捕获");
alert.info("捕获已停止", 2000);
} catch (error) {
alert.error("停止捕获失败", 3000);
} finally {
release();
}
};
// 更新触发参数
const updateTrigger = async (level: number, risingEdge: boolean) => {
const client = AuthManager.createClient(OscilloscopeApiClient);
try {
const ok = await client.updateTrigger(level, risingEdge);
if (ok) {
config.triggerLevel = level;
config.triggerRisingEdge = risingEdge;
alert.success("触发参数已更新", 2000);
} else {
throw new Error();
}
} catch {
alert.error("更新触发参数失败", 2000);
}
};
// 更新采样参数
const updateSampling = async (
horizontalShift: number,
decimationRate: number,
) => {
const client = AuthManager.createClient(OscilloscopeApiClient);
try {
const ok = await client.updateSampling(horizontalShift, decimationRate);
if (ok) {
config.horizontalShift = horizontalShift;
config.decimationRate = decimationRate;
alert.success("采样参数已更新", 2000);
} else {
throw new Error();
}
} catch {
alert.error("更新采样参数失败", 2000);
}
};
// 手动刷新RAM
const refreshRAM = async () => {
const client = AuthManager.createClient(OscilloscopeApiClient);
try {
const ok = await client.refreshRAM();
if (ok) {
// alert.success("RAM已刷新", 2000);
} else {
throw new Error();
}
} catch {
alert.error("刷新RAM失败", 2000);
}
};
// 生成测试数据
const generateTestData = () => {
const freq = 5_000_000;
const duration = 0.001; // 1ms
const points = Math.floor(freq * duration);
const x = Array.from( const x = Array.from(
{ length: bytes.length }, { length: points },
(_, i) => (i * samplePeriodNs.value) / 1000 // us (_, i) => (i * 1_000_000_000) / freq / 1000,
);
const y = Array.from({ length: points }, (_, i) =>
Math.floor(Math.sin(i * 0.01) * 127 + 128),
); );
const y = Array.from(bytes);
oscData.value = { oscData.value = {
x, x,
y, y,
xUnit: "us", xUnit: "us",
yUnit: "V", yUnit: "V",
adFrequency: resp.adFrequency, adFrequency: freq,
adVpp: resp.adVpp, adVpp: 2.0,
adMax: resp.adMax, adMax: 255,
adMin: resp.adMin, adMin: 0,
}; };
} catch (error) { alert.success("测试数据生成成功", 2000);
alert.error("获取示波器数据失败", 3000);
}
};
// 定时器引用
let refreshIntervalId: number | undefined;
// 刷新间隔(毫秒),可根据需要调整
const refreshIntervalMs = ref(1000);
// 定时刷新函数
const startAutoRefresh = () => {
if (refreshIntervalId !== undefined) return;
refreshIntervalId = window.setInterval(async () => {
await refreshRAM();
await getOscilloscopeData();
}, refreshIntervalMs.value);
};
const stopAutoRefresh = () => {
if (refreshIntervalId !== undefined) {
clearInterval(refreshIntervalId);
refreshIntervalId = undefined;
isCapturing.value = false;
}
};
// 启动捕获
const startCapture = async () => {
if (operationMutex.isLocked()) {
alert.warn("有其他操作正在进行中,请稍后再试", 3000);
return;
}
isCapturing.value = true;
const release = await operationMutex.acquire();
try {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
const started = await client.startCapture();
if (!started) throw new Error("无法启动捕获");
alert.info("开始捕获...", 2000);
// 启动定时刷新
startAutoRefresh();
} catch (error) {
alert.error("捕获失败", 3000);
isCapturing.value = false;
stopAutoRefresh();
} finally {
release();
}
};
// 停止捕获
const stopCapture = async () => {
if (!isCapturing.value) {
alert.warn("当前没有正在进行的捕获操作", 2000);
return;
}
isCapturing.value = false;
stopAutoRefresh();
const release = await operationMutex.acquire();
try {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
const stopped = await client.stopCapture();
if (!stopped) throw new Error("无法停止捕获");
alert.info("捕获已停止", 2000);
} catch (error) {
alert.error("停止捕获失败", 3000);
} finally {
release();
}
};
// 更新触发参数
const updateTrigger = async (level: number, risingEdge: boolean) => {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
try {
const ok = await client.updateTrigger(level, risingEdge);
if (ok) {
config.triggerLevel = level;
config.triggerRisingEdge = risingEdge;
alert.success("触发参数已更新", 2000);
} else {
throw new Error();
}
} catch {
alert.error("更新触发参数失败", 2000);
}
};
// 更新采样参数
const updateSampling = async (horizontalShift: number, decimationRate: number) => {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
try {
const ok = await client.updateSampling(horizontalShift, decimationRate);
if (ok) {
config.horizontalShift = horizontalShift;
config.decimationRate = decimationRate;
alert.success("采样参数已更新", 2000);
} else {
throw new Error();
}
} catch {
alert.error("更新采样参数失败", 2000);
}
};
// 手动刷新RAM
const refreshRAM = async () => {
const client = AuthManager.createAuthenticatedOscilloscopeApiClient();
try {
const ok = await client.refreshRAM();
if (ok) {
// alert.success("RAM已刷新", 2000);
} else {
throw new Error();
}
} catch {
alert.error("刷新RAM失败", 2000);
}
};
// 生成测试数据
const generateTestData = () => {
const freq = 5_000_000;
const duration = 0.001; // 1ms
const points = Math.floor(freq * duration);
const x = Array.from({ length: points }, (_, i) => (i * 1_000_000_000 / freq) / 1000);
const y = Array.from({ length: points }, (_, i) =>
Math.floor(Math.sin(i * 0.01) * 127 + 128)
);
oscData.value = {
x,
y,
xUnit: "us",
yUnit: "V",
adFrequency: freq,
adVpp: 2.0,
adMax: 255,
adMin: 0,
}; };
alert.success("测试数据生成成功", 2000);
};
return { return {
oscData, oscData,
config, config,
isApplying, isApplying,
isCapturing, isCapturing,
sampleCount, sampleCount,
samplePeriodNs, samplePeriodNs,
refreshIntervalMs, refreshIntervalMs,
applyConfiguration, applyConfiguration,
resetConfiguration, resetConfiguration,
clearOscilloscopeData, clearOscilloscopeData,
getOscilloscopeData, getOscilloscopeData,
startCapture, startCapture,
stopCapture, stopCapture,
updateTrigger, updateTrigger,
updateSampling, updateSampling,
refreshRAM, refreshRAM,
generateTestData, generateTestData,
}; };
}); },
);
export { useProvideOscilloscope, useOscilloscopeState, DEFAULT_CONFIG }; export { useProvideOscilloscope, useOscilloscopeState, DEFAULT_CONFIG };

View File

@ -81,7 +81,7 @@
import { ref, onMounted, onUnmounted } from "vue"; import { ref, onMounted, onUnmounted } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import type { ExamInfo } from "@/APIClient"; import { ExamClient, ResourceClient, type ExamInfo } from "@/APIClient";
// //
interface Tutorial { interface Tutorial {
@ -121,7 +121,7 @@ onMounted(async () => {
console.log("正在从数据库加载实验数据..."); console.log("正在从数据库加载实验数据...");
// //
const client = AuthManager.createAuthenticatedExamClient(); const client = AuthManager.createClient(ExamClient);
// //
const examList: ExamInfo[] = await client.getExamList(); const examList: ExamInfo[] = await client.getExamList();
@ -142,7 +142,7 @@ onMounted(async () => {
try { try {
// //
const resourceClient = AuthManager.createAuthenticatedResourceClient(); const resourceClient = AuthManager.createClient(ResourceClient);
const resourceList = await resourceClient.getResourceList( const resourceList = await resourceClient.getResourceList(
exam.id, exam.id,
"cover", "cover",

View File

@ -95,6 +95,7 @@ import {
import { ProgressStatus } from "@/utils/signalR/server.Hubs"; import { ProgressStatus } from "@/utils/signalR/server.Hubs";
import { useRequiredInjection } from "@/utils/Common"; import { useRequiredInjection } from "@/utils/Common";
import { useAlertStore } from "./Alert"; import { useAlertStore } from "./Alert";
import { ResourceClient } from "@/APIClient";
interface Props { interface Props {
maxMemory?: number; maxMemory?: number;
@ -138,8 +139,7 @@ const progressHubReceiver: IProgressReceiver = {
}, },
}; };
onMounted(async () => { onMounted(async () => {
progressHubConnection.value = progressHubConnection.value = AuthManager.createHubConnection("ProgressHub");
AuthManager.createAuthenticatedProgressHubConnection();
progressHubProxy.value = getHubProxyFactory("IProgressHub").createHubProxy( progressHubProxy.value = getHubProxyFactory("IProgressHub").createHubProxy(
progressHubConnection.value, progressHubConnection.value,
); );
@ -175,7 +175,7 @@ async function loadAvailableBitstreams() {
} }
try { try {
const resourceClient = AuthManager.createAuthenticatedResourceClient(); const resourceClient = AuthManager.createClient(ResourceClient);
// 使ResourceClient API // 使ResourceClient API
const resources = await resourceClient.getResourceList( const resources = await resourceClient.getResourceList(
props.examId, props.examId,
@ -199,7 +199,7 @@ async function downloadExampleBitstream(bitstream: {
isDownloading.value = true; isDownloading.value = true;
try { try {
const resourceClient = AuthManager.createAuthenticatedResourceClient(); const resourceClient = AuthManager.createClient(ResourceClient);
// 使ResourceClient API // 使ResourceClient API
const response = await resourceClient.getResourceById(bitstream.id); const response = await resourceClient.getResourceById(bitstream.id);

View File

@ -212,6 +212,7 @@ 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"; import { AuthManager } from "@/utils/AuthManager";
import { DDSClient } from "@/APIClient";
// Component Attributes // Component Attributes
const props = defineProps<{ const props = defineProps<{
@ -221,7 +222,7 @@ const props = defineProps<{
const emit = defineEmits(["update:modelValue"]); const emit = defineEmits(["update:modelValue"]);
// Global varibles // Global varibles
const dds = AuthManager.createAuthenticatedDDSClient(); const dds = AuthManager.createClient(DDSClient);
const eqps = useEquipments(); const eqps = useEquipments();
const dialog = useDialogStore(); const dialog = useDialogStore();

View File

@ -1,17 +1,30 @@
// filepath: c:\_Project\FPGA_WebLab\FPGA_WebLab\src\components\equipments\Switch.vue
<template> <template>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
:width="width" :width="width"
:height="height" :height="height"
:viewBox="`4 6 ${props.switchCount + 2} 4`" :viewBox="`4 6 ${props.switchCount + 2} 4`"
class="dip-switch" class="dip-switch"
> >
<defs> <defs>
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%"> <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feFlood result="flood" flood-color="#f08a5d" flood-opacity="1"></feFlood> <feFlood
<feComposite in="flood" result="mask" in2="SourceGraphic" operator="in"></feComposite> result="flood"
<feMorphology in="mask" result="dilated" operator="dilate" radius="0.02"></feMorphology> flood-color="#f08a5d"
flood-opacity="1"
></feFlood>
<feComposite
in="flood"
result="mask"
in2="SourceGraphic"
operator="in"
></feComposite>
<feMorphology
in="mask"
result="dilated"
operator="dilate"
radius="0.02"
></feMorphology>
<feGaussianBlur in="dilated" stdDeviation="0.05" result="blur1" /> <feGaussianBlur in="dilated" stdDeviation="0.05" result="blur1" />
<feGaussianBlur in="dilated" stdDeviation="0.1" result="blur2" /> <feGaussianBlur in="dilated" stdDeviation="0.1" result="blur2" />
<feGaussianBlur in="dilated" stdDeviation="0.2" result="blur3" /> <feGaussianBlur in="dilated" stdDeviation="0.2" result="blur3" />
@ -23,29 +36,41 @@
</feMerge> </feMerge>
</filter> </filter>
</defs> </defs>
<g> <g>
<!-- 红色背景随开关数量变化宽度 --> <rect
<rect :width="props.switchCount + 2" height="4" x="4" y="6" fill="#c01401" rx="0.1" /> :width="props.switchCount + 2"
<text v-if="props.showLabels" fill="white" font-size="0.7" x="4.25" y="6.75">ON</text> height="4"
x="4"
y="6"
fill="#c01401"
rx="0.1"
/>
<text
v-if="props.showLabels"
fill="white"
font-size="0.7"
x="4.25"
y="6.75"
>
ON
</text>
<g> <g>
<template v-for="(_, index) in Array(props.switchCount)" :key="index"> <template v-for="(_, index) in Array(props.switchCount)" :key="index">
<rect <rect
class="glow interactive" class="glow interactive"
@click="toggleBtnStatus(index)" @click="toggleBtnStatus(index)"
width="0.7" width="0.7"
height="2" height="2"
fill="#68716f" fill="#68716f"
:x="5.15 + index" :x="5.15 + index"
y="7" y="7"
rx="0.1" rx="0.1"
/> />
<text <text
v-if="props.showLabels" v-if="props.showLabels"
:x="5.5 + index" :x="5.5 + index"
y="9.5" y="9.5"
font-size="0.4" font-size="0.4"
text-anchor="middle" text-anchor="middle"
fill="#444" fill="#444"
> >
@ -53,19 +78,21 @@
</text> </text>
</template> </template>
</g> </g>
<g> <g>
<template v-for="(location, index) in btnLocation" :key="`btn-${index}`"> <template
<rect v-for="(location, index) in btnLocation"
:key="`btn-${index}`"
>
<rect
class="interactive" class="interactive"
@click="toggleBtnStatus(index)" @click="toggleBtnStatus(index)"
width="0.65" width="0.65"
height="0.65" height="0.65"
fill="white" fill="white"
:x="5.175 + index" :x="5.175 + index"
:y="location" :y="location"
rx="0.1" rx="0.1"
opacity="1" opacity="1"
/> />
</template> </template>
</g> </g>
@ -74,118 +101,99 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, watch } from "vue"; import { ref, computed, watch, onMounted } from "vue";
interface Props { interface Props {
size?: number; size?: number;
switchCount?: number; switchCount?: number;
// initialValues?: boolean[] | string;
initialValues?: boolean[] | string; // showLabels?: boolean;
showLabels?: boolean; //
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
size: 1, size: 1,
switchCount: 6, switchCount: 6,
initialValues: () => [], initialValues: () => [],
showLabels: true showLabels: true,
}); });
const emit = defineEmits(["change"]);
// //
const width = computed(() => { function parseInitialValues(): boolean[] {
// 25px(20px)
return (props.switchCount * 25 + 20) * props.size;
});
const height = computed(() => 85 * props.size); //
//
const emit = defineEmits(['change', 'switch-toggle']);
//
const parseInitialValues = () => {
if (Array.isArray(props.initialValues)) { if (Array.isArray(props.initialValues)) {
return [...props.initialValues].slice(0, props.switchCount); return [...props.initialValues].slice(0, props.switchCount);
} else if (typeof props.initialValues === 'string' && props.initialValues.trim() !== '') {
//
const values = props.initialValues.split(',')
.map(val => val.trim() === '1' || val.trim().toLowerCase() === 'true')
.slice(0, props.switchCount);
// false
while (values.length < props.switchCount) {
values.push(false);
}
return values;
} }
// false if (
typeof props.initialValues === "string" &&
props.initialValues.trim() !== ""
) {
const arr = props.initialValues
.split(",")
.map((val) => val.trim() === "1" || val.trim().toLowerCase() === "true");
while (arr.length < props.switchCount) arr.push(false);
return arr.slice(0, props.switchCount);
}
return Array(props.switchCount).fill(false); return Array(props.switchCount).fill(false);
}; }
// //
const btnStatus = ref(parseInitialValues()); const btnStatus = ref<boolean[]>(parseInitialValues());
// switchCount //
watch(() => props.switchCount, (newCount) => { const width = computed(() => (props.switchCount * 25 + 20) * props.size);
if (newCount !== btnStatus.value.length) { const height = computed(() => 85 * props.size);
//
if (newCount > btnStatus.value.length) {
btnStatus.value = [
...btnStatus.value,
...Array(newCount - btnStatus.value.length).fill(false)
];
} else {
//
btnStatus.value = btnStatus.value.slice(0, newCount);
}
}
}, { immediate: true });
// initialValues //
watch(() => props.initialValues, () => { const btnLocation = computed(() =>
btnStatus.value = parseInitialValues(); btnStatus.value.map((status) => (status ? 7.025 : 8.325)),
}); );
const btnLocation = computed(() => { //
return btnStatus.value.map((status) => { function updateStatus(newStates: boolean[], index?: number) {
return status ? 7.025 : 8.325; btnStatus.value = newStates.slice(0, props.switchCount);
SwitchClient.setStates(btnStatus.value); //
emit("change", {
index,
value: index !== undefined ? btnStatus.value[index] : undefined,
states: [...btnStatus.value],
}); });
});
function setBtnStatus(btnNum: number, isOn: boolean): void {
if (btnNum >= 0 && btnNum < btnStatus.value.length) {
btnStatus.value[btnNum] = isOn;
emit('change', { index: btnNum, value: isOn, states: [...btnStatus.value] });
}
} }
function toggleBtnStatus(btnNum: number): void { //
if (btnNum >= 0 && btnNum < btnStatus.value.length) { function toggleBtnStatus(idx: number) {
btnStatus.value[btnNum] = !btnStatus.value[btnNum]; if (idx < 0 || idx >= btnStatus.value.length) return;
emit('switch-toggle', { const newStates = [...btnStatus.value];
index: btnNum, newStates[idx] = !newStates[idx];
value: btnStatus.value[btnNum], updateStatus(newStates, idx);
states: [...btnStatus.value]
});
}
} }
// //
function setAllStates(states: boolean[]): void { function setAllStates(states: boolean[]) {
const newStates = states.slice(0, props.switchCount); updateStatus(states);
while (newStates.length < props.switchCount) {
newStates.push(false);
}
btnStatus.value = newStates;
emit('change', { states: [...btnStatus.value] });
} }
// //
defineExpose({ function setBtnStatus(idx: number, isOn: boolean) {
setBtnStatus, if (idx < 0 || idx >= btnStatus.value.length) return;
toggleBtnStatus, const newStates = [...btnStatus.value];
setAllStates, newStates[idx] = isOn;
getBtnStatus: () => [...btnStatus.value] updateStatus(newStates, idx);
}
// props
watch(
() => [props.switchCount, props.initialValues],
() => {
btnStatus.value = parseInitialValues();
SwitchClient.setStates(btnStatus.value);
},
);
//
onMounted(() => {
SwitchClient.onStateChange((states: boolean[]) => {
btnStatus.value = states.slice(0, props.switchCount);
});
}); });
</script> </script>
@ -194,16 +202,14 @@ defineExpose({
display: block; display: block;
padding: 0; padding: 0;
margin: 0; margin: 0;
line-height: 0; /* 移除行高导致的额外间距 */ line-height: 0;
font-size: 0; /* 防止文本节点造成的间距 */ font-size: 0;
box-sizing: content-box; box-sizing: content-box;
overflow: visible; overflow: visible;
} }
rect { rect {
transition: all 100ms ease-in-out; transition: all 100ms ease-in-out;
} }
.interactive { .interactive {
cursor: pointer; cursor: pointer;
} }

View File

@ -17,7 +17,14 @@ import {
getHubProxyFactory, getHubProxyFactory,
getReceiverRegister, getReceiverRegister,
} from "@/utils/signalR/TypedSignalR.Client"; } from "@/utils/signalR/TypedSignalR.Client";
import { ResourcePurpose, type ResourceInfo } from "@/APIClient"; import {
JtagClient,
MatrixKeyClient,
PowerClient,
ResourceClient,
ResourcePurpose,
type ResourceInfo,
} from "@/APIClient";
import type { import type {
IDigitalTubesHub, IDigitalTubesHub,
IJtagHub, IJtagHub,
@ -46,8 +53,7 @@ export const useEquipments = defineStore("equipments", () => {
onMounted(async () => { onMounted(async () => {
// 每次挂载都重新创建连接 // 每次挂载都重新创建连接
jtagHubConnection.value = jtagHubConnection.value = AuthManager.createHubConnection("JtagHub");
AuthManager.createAuthenticatedJtagHubConnection();
jtagHubProxy.value = getHubProxyFactory("IJtagHub").createHubProxy( jtagHubProxy.value = getHubProxyFactory("IJtagHub").createHubProxy(
jtagHubConnection.value, jtagHubConnection.value,
); );
@ -101,7 +107,7 @@ export const useEquipments = defineStore("equipments", () => {
// 自动开启电源 // 自动开启电源
await powerSetOnOff(true); await powerSetOnOff(true);
const resourceClient = AuthManager.createAuthenticatedResourceClient(); const resourceClient = AuthManager.createClient(ResourceClient);
const resp = await resourceClient.addResource( const resp = await resourceClient.addResource(
"bitstream", "bitstream",
ResourcePurpose.User, ResourcePurpose.User,
@ -133,7 +139,7 @@ export const useEquipments = defineStore("equipments", () => {
// 自动开启电源 // 自动开启电源
await powerSetOnOff(true); await powerSetOnOff(true);
const jtagClient = AuthManager.createAuthenticatedJtagClient(); const jtagClient = AuthManager.createClient(JtagClient);
const resp = await jtagClient.downloadBitstream( const resp = await jtagClient.downloadBitstream(
boardAddr.value, boardAddr.value,
boardPort.value, boardPort.value,
@ -155,7 +161,7 @@ export const useEquipments = defineStore("equipments", () => {
// 自动开启电源 // 自动开启电源
await powerSetOnOff(true); await powerSetOnOff(true);
const jtagClient = AuthManager.createAuthenticatedJtagClient(); const jtagClient = AuthManager.createClient(JtagClient);
const resp = await jtagClient.getDeviceIDCode( const resp = await jtagClient.getDeviceIDCode(
boardAddr.value, boardAddr.value,
boardPort.value, boardPort.value,
@ -175,7 +181,7 @@ export const useEquipments = defineStore("equipments", () => {
// 自动开启电源 // 自动开启电源
await powerSetOnOff(true); await powerSetOnOff(true);
const jtagClient = AuthManager.createAuthenticatedJtagClient(); const jtagClient = AuthManager.createClient(JtagClient);
const resp = await jtagClient.setSpeed( const resp = await jtagClient.setSpeed(
boardAddr.value, boardAddr.value,
boardPort.value, boardPort.value,
@ -221,8 +227,7 @@ export const useEquipments = defineStore("equipments", () => {
async function matrixKeypadSetKeyStates(keyStates: boolean[]) { async function matrixKeypadSetKeyStates(keyStates: boolean[]) {
const release = await matrixKeypadClientMutex.acquire(); const release = await matrixKeypadClientMutex.acquire();
try { try {
const matrixKeypadClient = const matrixKeypadClient = AuthManager.createClient(MatrixKeyClient);
AuthManager.createAuthenticatedMatrixKeyClient();
const resp = await matrixKeypadClient.setMatrixKeyStatus( const resp = await matrixKeypadClient.setMatrixKeyStatus(
boardAddr.value, boardAddr.value,
boardPort.value, boardPort.value,
@ -240,8 +245,7 @@ export const useEquipments = defineStore("equipments", () => {
async function matrixKeypadEnable(enable: boolean) { async function matrixKeypadEnable(enable: boolean) {
const release = await matrixKeypadClientMutex.acquire(); const release = await matrixKeypadClientMutex.acquire();
try { try {
const matrixKeypadClient = const matrixKeypadClient = AuthManager.createClient(MatrixKeyClient);
AuthManager.createAuthenticatedMatrixKeyClient();
if (enable) { if (enable) {
const resp = await matrixKeypadClient.enabelMatrixKey( const resp = await matrixKeypadClient.enabelMatrixKey(
boardAddr.value, boardAddr.value,
@ -276,7 +280,7 @@ export const useEquipments = defineStore("equipments", () => {
async function powerSetOnOff(enable: boolean) { async function powerSetOnOff(enable: boolean) {
const release = await powerClientMutex.acquire(); const release = await powerClientMutex.acquire();
try { try {
const powerClient = AuthManager.createAuthenticatedPowerClient(); const powerClient = AuthManager.createClient(PowerClient);
const resp = await powerClient.setPowerOnOff( const resp = await powerClient.setPowerOnOff(
boardAddr.value, boardAddr.value,
boardPort.value, boardPort.value,
@ -338,7 +342,7 @@ export const useEquipments = defineStore("equipments", () => {
onMounted(async () => { onMounted(async () => {
// 每次挂载都重新创建连接 // 每次挂载都重新创建连接
sevenSegmentDisplayHub.value = sevenSegmentDisplayHub.value =
AuthManager.createAuthenticatedDigitalTubesHubConnection(); AuthManager.createHubConnection("DigitalTubesHub");
sevenSegmentDisplayHubProxy.value = getHubProxyFactory( sevenSegmentDisplayHubProxy.value = getHubProxyFactory(
"IDigitalTubesHub", "IDigitalTubesHub",
).createHubProxy(sevenSegmentDisplayHub.value); ).createHubProxy(sevenSegmentDisplayHub.value);

View File

@ -1,322 +1,105 @@
import { import { DataClient } from "@/APIClient";
DataClient,
VideoStreamClient,
BsdlParserClient,
DDSClient,
JtagClient,
MatrixKeyClient,
PowerClient,
RemoteUpdateClient,
TutorialClient,
UDPClient,
LogicAnalyzerClient,
NetConfigClient,
OscilloscopeApiClient,
DebuggerClient,
ExamClient,
ResourceClient,
HdmiVideoStreamClient,
} from "@/APIClient";
import router from "@/router";
import { HubConnectionBuilder } from "@microsoft/signalr"; import { HubConnectionBuilder } from "@microsoft/signalr";
import axios, { type AxiosInstance } from "axios"; import axios, { type AxiosInstance } from "axios";
import { isNull } from "lodash";
// 支持的客户端类型联合类型
type SupportedClient =
| DataClient
| VideoStreamClient
| BsdlParserClient
| DDSClient
| JtagClient
| MatrixKeyClient
| PowerClient
| RemoteUpdateClient
| TutorialClient
| LogicAnalyzerClient
| UDPClient
| NetConfigClient
| OscilloscopeApiClient
| DebuggerClient
| ExamClient
| ResourceClient
| HdmiVideoStreamClient;
// 简单到让人想哭的认证管理器
export class AuthManager { export class AuthManager {
// 存储token到localStorage private static readonly TOKEN_KEY = "authToken";
public static setToken(token: string): void {
localStorage.setItem("authToken", token); // 核心数据:就是个字符串
static getToken(): string | null {
return localStorage.getItem(this.TOKEN_KEY);
} }
// 从localStorage获取token static setToken(token: string): void {
public static getToken(): string | null { localStorage.setItem(this.TOKEN_KEY, token);
return localStorage.getItem("authToken");
} }
// 清除token static clearToken(): void {
public static clearToken(): void { localStorage.removeItem(this.TOKEN_KEY);
localStorage.removeItem("authToken");
} }
// 检查是否已认证 // 核心功能创建带认证的HTTP配置
public static async isAuthenticated(): Promise<boolean> { static getAuthHeaders(): Record<string, string> {
return await AuthManager.verifyToken(); const token = this.getToken();
return token ? { Authorization: `Bearer ${token}` } : {};
} }
// 通用的为HTTP请求添加Authorization header的方法 // 一个方法搞定所有客户端不要17个垃圾方法
public static addAuthHeader(client: SupportedClient): void { static createClient<T>(
const token = AuthManager.getToken(); ClientClass: new (baseUrl?: string, config?: any) => T,
if (token) { baseUrl?: string,
// 创建一个自定义的 http 对象,包装原有的 fetch 方法
const customHttp = {
fetch: (url: RequestInfo, init?: RequestInit) => {
if (!init) init = {};
if (!init.headers) init.headers = {};
// 添加Authorization header
if (typeof init.headers === "object" && init.headers !== null) {
(init.headers as any)["Authorization"] = `Bearer ${token}`;
}
// 使用全局 fetch 或 window.fetch
return (window as any).fetch(url, init);
},
};
// 重新构造客户端,传入自定义的 http 对象
const ClientClass = client.constructor as new (
baseUrl?: string,
http?: any,
) => SupportedClient;
const newClient = new ClientClass(undefined, customHttp);
// 将新客户端的属性复制到原客户端(这是一个 workaround
// 更好的做法是返回新的客户端实例
Object.setPrototypeOf(client, Object.getPrototypeOf(newClient));
Object.assign(client, newClient);
}
}
// 私有方法创建带认证的HTTP客户端
private static createAuthenticatedHttp() {
const token = AuthManager.getToken();
if (!token) {
return null;
}
return {
fetch: (url: RequestInfo, init?: RequestInit) => {
if (!init) init = {};
if (!init.headers) init.headers = {};
if (typeof init.headers === "object" && init.headers !== null) {
(init.headers as any)["Authorization"] = `Bearer ${token}`;
}
return (window as any).fetch(url, init);
},
};
}
// 私有方法创建带认证的Axios实例
private static createAuthenticatedAxiosInstance(): AxiosInstance | null {
const token = AuthManager.getToken();
if (!token) return null;
const instance = axios.create();
instance.interceptors.request.use((config) => {
config.headers = config.headers || {};
(config.headers as any)["Authorization"] = `Bearer ${token}`;
return config;
});
return instance;
}
// 通用的创建已认证客户端的方法(使用泛型)
public static createAuthenticatedClient<T extends SupportedClient>(
ClientClass: new (baseUrl?: string, instance?: AxiosInstance) => T,
): T { ): T {
const axiosInstance = AuthManager.createAuthenticatedAxiosInstance(); const token = this.getToken();
return axiosInstance if (!token) {
? new ClientClass(undefined, axiosInstance) return new ClientClass(baseUrl);
: new ClientClass(); }
// 对于axios客户端
const axiosInstance = axios.create({
headers: this.getAuthHeaders(),
});
return new ClientClass(baseUrl, axiosInstance);
} }
// 便捷方法:创建已配置认证的各种客户端 // SignalR连接 - 简单明了
public static createAuthenticatedDataClient(): DataClient { static createHubConnection(
return AuthManager.createAuthenticatedClient(DataClient); hubPath: "ProgressHub" | "JtagHub" | "DigitalTubesHub",
} ) {
public static createAuthenticatedVideoStreamClient(): VideoStreamClient {
return AuthManager.createAuthenticatedClient(VideoStreamClient);
}
public static createAuthenticatedBsdlParserClient(): BsdlParserClient {
return AuthManager.createAuthenticatedClient(BsdlParserClient);
}
public static createAuthenticatedDDSClient(): DDSClient {
return AuthManager.createAuthenticatedClient(DDSClient);
}
public static createAuthenticatedJtagClient(): JtagClient {
return AuthManager.createAuthenticatedClient(JtagClient);
}
public static createAuthenticatedMatrixKeyClient(): MatrixKeyClient {
return AuthManager.createAuthenticatedClient(MatrixKeyClient);
}
public static createAuthenticatedPowerClient(): PowerClient {
return AuthManager.createAuthenticatedClient(PowerClient);
}
public static createAuthenticatedRemoteUpdateClient(): RemoteUpdateClient {
return AuthManager.createAuthenticatedClient(RemoteUpdateClient);
}
public static createAuthenticatedTutorialClient(): TutorialClient {
return AuthManager.createAuthenticatedClient(TutorialClient);
}
public static createAuthenticatedUDPClient(): UDPClient {
return AuthManager.createAuthenticatedClient(UDPClient);
}
public static createAuthenticatedLogicAnalyzerClient(): LogicAnalyzerClient {
return AuthManager.createAuthenticatedClient(LogicAnalyzerClient);
}
public static createAuthenticatedNetConfigClient(): NetConfigClient {
return AuthManager.createAuthenticatedClient(NetConfigClient);
}
public static createAuthenticatedOscilloscopeApiClient(): OscilloscopeApiClient {
return AuthManager.createAuthenticatedClient(OscilloscopeApiClient);
}
public static createAuthenticatedDebuggerClient(): DebuggerClient {
return AuthManager.createAuthenticatedClient(DebuggerClient);
}
public static createAuthenticatedExamClient(): ExamClient {
return AuthManager.createAuthenticatedClient(ExamClient);
}
public static createAuthenticatedResourceClient(): ResourceClient {
return AuthManager.createAuthenticatedClient(ResourceClient);
}
public static createAuthenticatedHdmiVideoStreamClient(): HdmiVideoStreamClient {
return AuthManager.createAuthenticatedClient(HdmiVideoStreamClient);
}
public static createAuthenticatedJtagHubConnection() {
return new HubConnectionBuilder() return new HubConnectionBuilder()
.withUrl("http://127.0.0.1:5000/hubs/JtagHub", { .withUrl(`http://127.0.0.1:5000/hubs/${hubPath}`, {
accessTokenFactory: () => this.getToken() ?? "", accessTokenFactory: () => this.getToken() ?? "",
}) })
.withAutomaticReconnect() .withAutomaticReconnect()
.build(); .build();
} }
public static createAuthenticatedProgressHubConnection() { // 认证逻辑 - 去除所有废话
return new HubConnectionBuilder() static async login(username: string, password: string): Promise<boolean> {
.withUrl("http://127.0.0.1:5000/hubs/ProgressHub", {
accessTokenFactory: () => this.getToken() ?? "",
})
.withAutomaticReconnect()
.build();
}
public static createAuthenticatedDigitalTubesHubConnection() {
return new HubConnectionBuilder()
.withUrl("http://127.0.0.1:5000/hubs/DigitalTubesHub", {
accessTokenFactory: () => this.getToken() ?? "",
})
.withAutomaticReconnect()
.build();
}
// 登录函数
public static async login(
username: string,
password: string,
): Promise<boolean> {
try { try {
const client = new DataClient(); const client = new DataClient();
const token = await client.login(username, password); const token = await client.login(username, password);
if (token) { if (!token) return false;
AuthManager.setToken(token);
// 验证token this.setToken(token);
const authClient = AuthManager.createAuthenticatedDataClient();
await authClient.testAuth();
return true; // 验证token - 如果失败直接抛异常
} await this.createClient(DataClient).testAuth();
return false;
} catch (error) {
AuthManager.clearToken();
throw error;
}
}
// 登出函数
public static logout(): void {
AuthManager.clearToken();
}
// 验证当前token是否有效
public static async verifyToken(): Promise<boolean> {
try {
const token = AuthManager.getToken();
if (!token) {
return false;
}
const client = AuthManager.createAuthenticatedDataClient();
await client.testAuth();
return true; return true;
} catch (error) { } catch {
AuthManager.clearToken(); this.clearToken();
return false; throw new Error("Login failed");
} }
} }
// 验证管理员权限 static logout(): void {
public static async verifyAdminAuth(): Promise<boolean> { this.clearToken();
}
// 简单的验证 - 不要搞复杂
static async isAuthenticated(): Promise<boolean> {
if (!this.getToken()) return false;
try { try {
const token = AuthManager.getToken(); await this.createClient(DataClient).testAuth();
if (!token) {
return false;
}
const client = AuthManager.createAuthenticatedDataClient();
await client.testAdminAuth();
return true; return true;
} catch (error) { } catch {
// 只有在token完全无效的情况下才清除token this.clearToken();
// 401错误表示token有效但权限不足不应清除token
if (error && typeof error === "object" && "status" in error) {
// 如果是403 (Forbidden) 或401 (Unauthorized)说明token有效但权限不足
if (error.status === 401 || error.status === 403) {
return false;
}
// 其他状态码可能表示token无效清除token
AuthManager.clearToken();
} else {
// 网络错误等不清除token
console.error("管理员权限验证失败:", error);
}
return false; return false;
} }
} }
// 检查客户端是否已配置认证 static async isAdminAuthenticated(): Promise<boolean> {
public static isClientAuthenticated(client: SupportedClient): boolean { if (!this.getToken()) return false;
const token = AuthManager.getToken();
return !!token; try {
await this.createClient(DataClient).testAdminAuth();
return true;
} catch {
this.clearToken();
return false;
}
} }
} }

View File

@ -17,7 +17,7 @@ export interface BoardData extends Board {
const [useProvideBoardManager, useBoardManager] = createInjectionState(() => { const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
// 远程升级相关参数 // 远程升级相关参数
const devPort = 1234; const devPort = 1234;
const remoteUpdater = AuthManager.createAuthenticatedRemoteUpdateClient(); const remoteUpdater = AuthManager.createClient(RemoteUpdateClient);
// 统一的板卡数据 // 统一的板卡数据
const boards = ref<BoardData[]>([]); const boards = ref<BoardData[]>([]);
@ -35,13 +35,13 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
async function getAllBoards(): Promise<{ success: boolean; error?: string }> { async function getAllBoards(): Promise<{ success: boolean; error?: string }> {
try { try {
// 验证管理员权限 // 验证管理员权限
const hasAdminAuth = await AuthManager.verifyAdminAuth(); const hasAdminAuth = await AuthManager.isAdminAuthenticated();
if (!hasAdminAuth) { if (!hasAdminAuth) {
console.error("权限验证失败"); console.error("权限验证失败");
return { success: false, error: "权限不足" }; return { success: false, error: "权限不足" };
} }
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const result = await client.getAllBoards(); const result = await client.getAllBoards();
if (result) { if (result) {
@ -77,7 +77,7 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
): Promise<{ success: boolean; error?: string; boardId?: string }> { ): Promise<{ success: boolean; error?: string; boardId?: string }> {
try { try {
// 验证管理员权限 // 验证管理员权限
const hasAdminAuth = await AuthManager.verifyAdminAuth(); const hasAdminAuth = await AuthManager.isAdminAuthenticated();
if (!hasAdminAuth) { if (!hasAdminAuth) {
console.error("权限验证失败"); console.error("权限验证失败");
return { success: false, error: "权限不足" }; return { success: false, error: "权限不足" };
@ -89,11 +89,11 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
return { success: false, error: "参数不完整" }; return { success: false, error: "参数不完整" };
} }
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const boardId = await client.addBoard(name); const boardId = await client.addBoard(name);
if (boardId) { if (boardId) {
console.log("新增板卡成功", { boardId, name}); console.log("新增板卡成功", { boardId, name });
// 刷新板卡列表 // 刷新板卡列表
await getAllBoards(); await getAllBoards();
return { success: true }; return { success: true };
@ -119,7 +119,7 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
): Promise<{ success: boolean; error?: string }> { ): Promise<{ success: boolean; error?: string }> {
try { try {
// 验证管理员权限 // 验证管理员权限
const hasAdminAuth = await AuthManager.verifyAdminAuth(); const hasAdminAuth = await AuthManager.isAdminAuthenticated();
if (!hasAdminAuth) { if (!hasAdminAuth) {
console.error("权限验证失败"); console.error("权限验证失败");
return { success: false, error: "权限不足" }; return { success: false, error: "权限不足" };
@ -130,7 +130,7 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
return { success: false, error: "板卡ID不能为空" }; return { success: false, error: "板卡ID不能为空" };
} }
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const result = await client.deleteBoard(boardId); const result = await client.deleteBoard(boardId);
if (result > 0) { if (result > 0) {

View File

@ -274,7 +274,7 @@ const handleSignUp = async () => {
// token // token
const checkExistingToken = async () => { const checkExistingToken = async () => {
try { try {
const isValid = await AuthManager.verifyToken(); const isValid = await AuthManager.isAuthenticated();
if (isValid) { if (isValid) {
// tokenproject // tokenproject
router.go(-1); router.go(-1);

View File

@ -418,7 +418,12 @@ import {
FileArchiveIcon, FileArchiveIcon,
FileJsonIcon, FileJsonIcon,
} from "lucide-vue-next"; } from "lucide-vue-next";
import { ExamDto, type FileParameter } from "@/APIClient"; import {
ExamClient,
ExamDto,
ResourceClient,
type FileParameter,
} from "@/APIClient";
import { useAlertStore } from "@/components/Alert"; import { useAlertStore } from "@/components/Alert";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { useRequiredInjection } from "@/utils/Common"; import { useRequiredInjection } from "@/utils/Common";
@ -618,7 +623,7 @@ const submitCreateExam = async () => {
isUpdating.value = true; isUpdating.value = true;
try { try {
const client = AuthManager.createAuthenticatedExamClient(); const client = AuthManager.createClient(ExamClient);
let exam: ExamInfo; let exam: ExamInfo;
if (mode.value === "create") { if (mode.value === "create") {
@ -671,7 +676,7 @@ const submitCreateExam = async () => {
// //
async function uploadExamResources(examId: string) { async function uploadExamResources(examId: string) {
const client = AuthManager.createAuthenticatedResourceClient(); const client = AuthManager.createClient(ResourceClient);
try { try {
// MD // MD
@ -750,7 +755,7 @@ function close() {
} }
async function editExam(examId: string) { async function editExam(examId: string) {
const client = AuthManager.createAuthenticatedExamClient(); const client = AuthManager.createClient(ExamClient);
const examInfo = await client.getExam(examId); const examInfo = await client.getExam(examId);
editExamInfo.value = { editExamInfo.value = {

View File

@ -250,7 +250,13 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ResourcePurpose, type ExamInfo, type ResourceInfo } from "@/APIClient"; import {
ExamClient,
ResourceClient,
ResourcePurpose,
type ExamInfo,
type ResourceInfo,
} from "@/APIClient";
import { useAlertStore } from "@/components/Alert"; import { useAlertStore } from "@/components/Alert";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { useRequiredInjection } from "@/utils/Common"; import { useRequiredInjection } from "@/utils/Common";
@ -274,7 +280,7 @@ const props = defineProps<{
const commitsList = ref<ResourceInfo[]>(); const commitsList = ref<ResourceInfo[]>();
async function updateCommits() { async function updateCommits() {
const client = AuthManager.createAuthenticatedExamClient(); const client = AuthManager.createClient(ExamClient);
const list = await client.getCommitsByExamId(props.selectedExam.id); const list = await client.getCommitsByExamId(props.selectedExam.id);
commitsList.value = list; commitsList.value = list;
} }
@ -288,7 +294,7 @@ const downloadResources = async () => {
downloadingResources.value = true; downloadingResources.value = true;
try { try {
const resourceClient = AuthManager.createAuthenticatedResourceClient(); const resourceClient = AuthManager.createClient(ResourceClient);
// //
const resourceList = await resourceClient.getResourceList( const resourceList = await resourceClient.getResourceList(

View File

@ -181,7 +181,7 @@
import { ref, onMounted, computed } from "vue"; import { ref, onMounted, computed } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { type ExamInfo } from "@/APIClient"; import { ExamClient, type ExamInfo } from "@/APIClient";
import { formatDate } from "@/utils/Common"; import { formatDate } from "@/utils/Common";
import ExamInfoModal from "./ExamInfoModal.vue"; import ExamInfoModal from "./ExamInfoModal.vue";
import ExamEditModal from "./ExamEditModal.vue"; import ExamEditModal from "./ExamEditModal.vue";
@ -206,7 +206,7 @@ async function refreshExams() {
error.value = ""; error.value = "";
try { try {
const client = AuthManager.createAuthenticatedExamClient(); const client = AuthManager.createClient(ExamClient);
exams.value = await client.getExamList(); exams.value = await client.getExamList();
} catch (err: any) { } catch (err: any) {
error.value = err.message || "获取实验列表失败"; error.value = err.message || "获取实验列表失败";
@ -218,7 +218,7 @@ async function refreshExams() {
async function viewExam(examId: string) { async function viewExam(examId: string) {
try { try {
const client = AuthManager.createAuthenticatedExamClient(); const client = AuthManager.createClient(ExamClient);
selectedExam.value = await client.getExam(examId); selectedExam.value = await client.getExam(examId);
showInfoModal.value = true; showInfoModal.value = true;
} catch (err: any) { } catch (err: any) {
@ -248,7 +248,7 @@ onMounted(async () => {
router.push("/login"); router.push("/login");
} }
isAdmin.value = await AuthManager.verifyAdminAuth(); isAdmin.value = await AuthManager.isAdminAuthenticated();
await refreshExams(); await refreshExams();

View File

@ -266,7 +266,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CaptureMode, ChannelConfig, DebuggerConfig } from "@/APIClient"; import {
CaptureMode,
ChannelConfig,
DebuggerClient,
DebuggerConfig,
} from "@/APIClient";
import { useAlertStore } from "@/components/Alert"; import { useAlertStore } from "@/components/Alert";
import BaseInputField from "@/components/InputField/BaseInputField.vue"; import BaseInputField from "@/components/InputField/BaseInputField.vue";
import type { LogicDataType } from "@/components/WaveformDisplay"; import type { LogicDataType } from "@/components/WaveformDisplay";
@ -421,7 +426,7 @@ async function startCapture() {
} }
isCapturing.value = true; isCapturing.value = true;
const client = AuthManager.createAuthenticatedDebuggerClient(); const client = AuthManager.createClient(DebuggerClient);
// API // API
const channelConfigs = channels.value const channelConfigs = channels.value

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
@layout="handleVerticalSplitterResize" @layout="handleVerticalSplitterResize"
> >
<!-- 使用 v-show 替代 v-if --> <!-- 使用 v-show 替代 v-if -->
<SplitterPanel <SplitterPanel
v-show="!isBottomBarFullscreen" v-show="!isBottomBarFullscreen"
id="splitter-group-v-panel-project" id="splitter-group-v-panel-project"
:default-size="verticalSplitterSize" :default-size="verticalSplitterSize"
@ -60,8 +60,8 @@
v-show="showDocPanel" v-show="showDocPanel"
class="doc-panel overflow-y-auto h-full" class="doc-panel overflow-y-auto h-full"
> >
<MarkdownRenderer <MarkdownRenderer
:content="documentContent" :content="documentContent"
:examId="(route.query.examId as string) || ''" :examId="(route.query.examId as string) || ''"
/> />
</div> </div>
@ -80,11 +80,13 @@
<!-- 功能底栏 --> <!-- 功能底栏 -->
<SplitterPanel <SplitterPanel
id="splitter-group-v-panel-bar" id="splitter-group-v-panel-bar"
:default-size="isBottomBarFullscreen ? 100 : (100 - verticalSplitterSize)" :default-size="
isBottomBarFullscreen ? 100 : 100 - verticalSplitterSize
"
:min-size="isBottomBarFullscreen ? 100 : 15" :min-size="isBottomBarFullscreen ? 100 : 15"
class="w-full overflow-hidden pt-3" class="w-full overflow-hidden pt-3"
> >
<BottomBar <BottomBar
:isFullscreen="isBottomBarFullscreen" :isFullscreen="isBottomBarFullscreen"
@toggle-fullscreen="handleToggleBottomBarFullscreen" @toggle-fullscreen="handleToggleBottomBarFullscreen"
/> />
@ -106,22 +108,48 @@
/> />
<!-- Navbar切换浮动按钮 --> <!-- Navbar切换浮动按钮 -->
<div <div
class="navbar-toggle-btn" class="navbar-toggle-btn"
:class="{ 'with-navbar': navbarControl.showNavbar.value }" :class="{ 'with-navbar': navbarControl.showNavbar.value }"
> >
<button <button
@click="navbarControl.toggleNavbar" @click="navbarControl.toggleNavbar"
class="btn btn-circle btn-primary shadow-lg hover:shadow-xl transition-all duration-300" class="btn btn-circle btn-primary shadow-lg hover:shadow-xl transition-all duration-300"
:class="{ 'btn-outline': navbarControl.showNavbar.value }" :class="{ 'btn-outline': navbarControl.showNavbar.value }"
:title="navbarControl.showNavbar.value ? '隐藏顶部导航栏' : '显示顶部导航栏'" :title="
navbarControl.showNavbar.value ? '隐藏顶部导航栏' : '显示顶部导航栏'
"
> >
<!-- 使用SVG图标表示菜单/关闭状态 --> <!-- 使用SVG图标表示菜单/关闭状态 -->
<svg v-if="navbarControl.showNavbar.value" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> v-if="navbarControl.showNavbar.value"
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg> </svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <svg
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" /> v-else
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg> </svg>
</button> </button>
</div> </div>
@ -131,7 +159,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, watch, inject, type Ref } from "vue"; import { ref, onMounted, watch, inject, type Ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useLocalStorage } from '@vueuse/core'; // VueUse import { useLocalStorage } from "@vueuse/core"; // VueUse
import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from "reka-ui"; import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from "reka-ui";
import DiagramCanvas from "@/components/LabCanvas/DiagramCanvas.vue"; import DiagramCanvas from "@/components/LabCanvas/DiagramCanvas.vue";
import ComponentSelector from "@/components/LabCanvas/ComponentSelector.vue"; import ComponentSelector from "@/components/LabCanvas/ComponentSelector.vue";
@ -143,7 +171,7 @@ import { useProvideComponentManager } from "@/components/LabCanvas";
import { useAlertStore } from "@/components/Alert"; import { useAlertStore } from "@/components/Alert";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { useEquipments } from "@/stores/equipments"; import { useEquipments } from "@/stores/equipments";
import type { Board } from "@/APIClient"; import { DataClient, ResourceClient, type Board } from "@/APIClient";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const route = useRoute(); const route = useRoute();
@ -158,20 +186,29 @@ const equipments = useEquipments();
const alert = useAlertStore(); const alert = useAlertStore();
// --- Navbar --- // --- Navbar ---
const navbarControl = inject('navbar') as { const navbarControl = inject("navbar") as {
showNavbar: Ref<boolean>; showNavbar: Ref<boolean>;
toggleNavbar: () => void; toggleNavbar: () => void;
}; };
// --- 使VueUse --- // --- 使VueUse ---
// 60% // 60%
const horizontalSplitterSize = useLocalStorage('project-horizontal-splitter-size', 60); const horizontalSplitterSize = useLocalStorage(
"project-horizontal-splitter-size",
60,
);
// 80% // 80%
const verticalSplitterSize = useLocalStorage('project-vertical-splitter-size', 80); const verticalSplitterSize = useLocalStorage(
"project-vertical-splitter-size",
80,
);
// //
const isBottomBarFullscreen = useLocalStorage('project-bottom-bar-fullscreen', false); const isBottomBarFullscreen = useLocalStorage(
"project-bottom-bar-fullscreen",
false,
);
// //
const showDocPanel = useLocalStorage('project-show-doc-panel', false); const showDocPanel = useLocalStorage("project-show-doc-panel", false);
function handleToggleBottomBarFullscreen() { function handleToggleBottomBarFullscreen() {
isBottomBarFullscreen.value = !isBottomBarFullscreen.value; isBottomBarFullscreen.value = !isBottomBarFullscreen.value;
@ -216,25 +253,25 @@ async function loadDocumentContent() {
const examId = route.query.examId as string; const examId = route.query.examId as string;
if (examId) { if (examId) {
// IDAPI // IDAPI
console.log('加载实验文档:', examId); console.log("加载实验文档:", examId);
const client = AuthManager.createAuthenticatedResourceClient(); const client = AuthManager.createClient(ResourceClient);
// markdown // markdown
const resources = await client.getResourceList(examId, 'doc', 'template'); const resources = await client.getResourceList(examId, "doc", "template");
if (resources && resources.length > 0) { if (resources && resources.length > 0) {
// markdown // markdown
const markdownResource = resources[0]; const markdownResource = resources[0];
// 使ResourceClient API // 使ResourceClient API
const response = await client.getResourceById(markdownResource.id); const response = await client.getResourceById(markdownResource.id);
if (!response || !response.data) { if (!response || !response.data) {
throw new Error('获取markdown文件失败'); throw new Error("获取markdown文件失败");
} }
const content = await response.data.text(); const content = await response.data.text();
// MarkdownRenderer // MarkdownRenderer
documentContent.value = content; documentContent.value = content;
} else { } else {
@ -279,17 +316,17 @@ function updateComponentDirectProp(
// //
async function checkAndInitializeBoard() { async function checkAndInitializeBoard() {
try { try {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const userInfo = await client.getUserInfo(); const userInfo = await client.getUserInfo();
if (userInfo.boardID && userInfo.boardID.trim() !== '') { if (userInfo.boardID && userInfo.boardID.trim() !== "") {
// equipment // equipment
try { try {
const board = await client.getBoardByID(userInfo.boardID); const board = await client.getBoardByID(userInfo.boardID);
updateEquipmentFromBoard(board); updateEquipmentFromBoard(board);
alert?.show(`实验板 ${board.boardName} 已连接`, "success"); alert?.show(`实验板 ${board.boardName} 已连接`, "success");
} catch (boardError) { } catch (boardError) {
console.error('获取实验板信息失败:', boardError); console.error("获取实验板信息失败:", boardError);
alert?.show("获取实验板信息失败", "error"); alert?.show("获取实验板信息失败", "error");
showRequestBoardDialog.value = true; showRequestBoardDialog.value = true;
} }
@ -298,7 +335,7 @@ async function checkAndInitializeBoard() {
showRequestBoardDialog.value = true; showRequestBoardDialog.value = true;
} }
} catch (error) { } catch (error) {
console.error('检查用户实验板失败:', error); console.error("检查用户实验板失败:", error);
alert?.show("检查用户信息失败", "error"); alert?.show("检查用户信息失败", "error");
showRequestBoardDialog.value = true; showRequestBoardDialog.value = true;
} }
@ -308,12 +345,12 @@ async function checkAndInitializeBoard() {
function updateEquipmentFromBoard(board: Board) { function updateEquipmentFromBoard(board: Board) {
equipments.boardAddr = board.ipAddr; equipments.boardAddr = board.ipAddr;
equipments.boardPort = board.port; equipments.boardPort = board.port;
console.log(`实验板信息已更新到equipment store:`, { console.log(`实验板信息已更新到equipment store:`, {
address: board.ipAddr, address: board.ipAddr,
port: board.port, port: board.port,
boardName: board.boardName, boardName: board.boardName,
boardId: board.id boardId: board.id,
}); });
} }
@ -321,7 +358,7 @@ function updateEquipmentFromBoard(board: Board) {
function handleRequestBoardClose() { function handleRequestBoardClose() {
showRequestBoardDialog.value = false; showRequestBoardDialog.value = false;
// //
router.push('/'); router.push("/");
} }
// //
@ -338,12 +375,12 @@ onMounted(async () => {
const isAuthenticated = await AuthManager.isAuthenticated(); const isAuthenticated = await AuthManager.isAuthenticated();
if (!isAuthenticated) { if (!isAuthenticated) {
// //
router.push('/login'); router.push("/login");
return; return;
} }
} catch (error) { } catch (error) {
console.error('身份验证失败:', error); console.error("身份验证失败:", error);
router.push('/login'); router.push("/login");
return; return;
} }

View File

@ -75,7 +75,7 @@ import { ref, watch } from "vue";
import { CheckCircle } from "lucide-vue-next"; import { CheckCircle } from "lucide-vue-next";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { useAlertStore } from "@/components/Alert"; import { useAlertStore } from "@/components/Alert";
import type { Board } from "@/APIClient"; import { DataClient, type Board } from "@/APIClient";
interface Props { interface Props {
open: boolean; open: boolean;
@ -113,7 +113,7 @@ async function checkUserBoard() {
boardInfo.value = null; boardInfo.value = null;
try { try {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const userInfo = await client.getUserInfo(); const userInfo = await client.getUserInfo();
if (userInfo.boardID && userInfo.boardID.trim() !== "") { if (userInfo.boardID && userInfo.boardID.trim() !== "") {
@ -140,7 +140,7 @@ async function requestBoard() {
requesting.value = true; requesting.value = true;
try { try {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const board = await client.getAvailableBoard(undefined); const board = await client.getAvailableBoard(undefined);
if (board) { if (board) {

View File

@ -433,7 +433,7 @@ const currentVideoSource = ref("");
const logs = ref<Array<{ time: Date; level: string; message: string }>>([]); const logs = ref<Array<{ time: Date; level: string; message: string }>>([]);
// API // API
const videoClient = AuthManager.createAuthenticatedVideoStreamClient(); const videoClient = AuthManager.createClient(VideoStreamClient);
// //
const addLog = (level: string, message: string) => { const addLog = (level: string, message: string) => {

View File

@ -174,7 +174,12 @@
import { ref, reactive, watch } from "vue"; import { ref, reactive, watch } from "vue";
import { AuthManager } from "../../utils/AuthManager"; import { AuthManager } from "../../utils/AuthManager";
import { useAlertStore } from "../../components/Alert"; import { useAlertStore } from "../../components/Alert";
import { BoardStatus, type NetworkConfigDto } from "../../APIClient"; import {
BoardStatus,
DataClient,
NetConfigClient,
type NetworkConfigDto,
} from "../../APIClient";
import { useRequiredInjection } from "@/utils/Common"; import { useRequiredInjection } from "@/utils/Common";
import { useBoardManager } from "@/utils/BoardManager"; import { useBoardManager } from "@/utils/BoardManager";
@ -267,8 +272,7 @@ async function handleSubmit() {
isSubmitting.value = true; isSubmitting.value = true;
try { try {
// AuthManager DataClient const dataClient = AuthManager.createClient(DataClient);
const dataClient = AuthManager.createAuthenticatedDataClient();
// //
const boardId = await dataClient.addBoard(form.name.trim()); const boardId = await dataClient.addBoard(form.name.trim());
@ -293,8 +297,7 @@ async function handleCancelPairing() {
if (!addedBoardId.value) return; if (!addedBoardId.value) return;
try { try {
// AuthManager DataClient const dataClient = AuthManager.createClient(DataClient);
const dataClient = AuthManager.createAuthenticatedDataClient();
// //
await dataClient.deleteBoard(addedBoardId.value); await dataClient.deleteBoard(addedBoardId.value);
@ -317,8 +320,8 @@ async function handlePairingConfirm() {
try { try {
// AuthManager // AuthManager
const dataClient = AuthManager.createAuthenticatedDataClient(); const dataClient = AuthManager.createClient(DataClient);
const netConfigClient = AuthManager.createAuthenticatedNetConfigClient(); const netConfigClient = AuthManager.createClient(NetConfigClient);
// //
const boardInfo = await dataClient.getBoardByID(addedBoardId.value); const boardInfo = await dataClient.getBoardByID(addedBoardId.value);
@ -365,7 +368,7 @@ async function handlePairingConfirm() {
// //
try { try {
const dataClient = AuthManager.createAuthenticatedDataClient(); const dataClient = AuthManager.createClient(DataClient);
await dataClient.deleteBoard(addedBoardId.value); await dataClient.deleteBoard(addedBoardId.value);
} catch (deleteError) { } catch (deleteError) {
console.error("删除板卡失败:", deleteError); console.error("删除板卡失败:", deleteError);

View File

@ -42,12 +42,12 @@ const isAdmin = ref(false);
function setActivePage(event: Event) { function setActivePage(event: Event) {
const target = event.currentTarget as HTMLLinkElement; const target = event.currentTarget as HTMLLinkElement;
const newPage = toNumber(target.id); const newPage = toNumber(target.id);
// 访 // 访
if (newPage === 100 && !isAdmin.value) { if (newPage === 100 && !isAdmin.value) {
return; return;
} }
activePage.value = newPage; activePage.value = newPage;
} }
@ -60,16 +60,16 @@ onMounted(async () => {
// 使 // 使
return; return;
} }
// //
isAdmin.value = await AuthManager.verifyAdminAuth(); isAdmin.value = await AuthManager.isAdminAuthenticated();
// //
if (activePage.value === 100 && !isAdmin.value) { if (activePage.value === 100 && !isAdmin.value) {
activePage.value = 1; activePage.value = 1;
} }
} catch (error) { } catch (error) {
console.error('用户认证检查失败:', error); console.error("用户认证检查失败:", error);
// //
} }
}); });

View File

@ -273,7 +273,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { AuthManager } from "@/utils/AuthManager"; import { AuthManager } from "@/utils/AuthManager";
import { UserInfo, Board, BoardStatus } from "@/APIClient"; import {
UserInfo,
Board,
BoardStatus,
DataClient,
JtagClient,
} from "@/APIClient";
import { Alert, useAlertStore } from "@/components/Alert"; import { Alert, useAlertStore } from "@/components/Alert";
import { import {
User, User,
@ -319,7 +325,7 @@ const loadBoardInfo = async () => {
} }
try { try {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
boardInfo.value = await client.getBoardByID(userInfo.value.boardID); boardInfo.value = await client.getBoardByID(userInfo.value.boardID);
} catch (err) { } catch (err) {
console.error("加载实验板信息失败:", err); console.error("加载实验板信息失败:", err);
@ -335,7 +341,7 @@ const loadUserInfo = async (showSuccessMessage = false) => {
try { try {
await new Promise((resolve) => setTimeout(resolve, 200)); await new Promise((resolve) => setTimeout(resolve, 200));
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
userInfo.value = await client.getUserInfo(); userInfo.value = await client.getUserInfo();
// ID // ID
@ -370,7 +376,7 @@ const applyBoard = async () => {
alertStore?.info("正在申请实验板..."); alertStore?.info("正在申请实验板...");
try { try {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
// //
const availableBoard = await client.getAvailableBoard(undefined); const availableBoard = await client.getAvailableBoard(undefined);
@ -407,7 +413,7 @@ const testBoardConnection = async () => {
alertStore?.info("正在测试连接..."); alertStore?.info("正在测试连接...");
try { try {
const jtagClient = AuthManager.createAuthenticatedJtagClient(); const jtagClient = AuthManager.createClient(JtagClient);
// 使JTAGID Code // 使JTAGID Code
const idCode = await jtagClient.getDeviceIDCode( const idCode = await jtagClient.getDeviceIDCode(
@ -444,7 +450,7 @@ const unbindBoard = async () => {
alertStore?.info("正在解绑实验板..."); alertStore?.info("正在解绑实验板...");
try { try {
const client = AuthManager.createAuthenticatedDataClient(); const client = AuthManager.createClient(DataClient);
const success = await client.unbindBoard(); const success = await client.unbindBoard();
if (success) { if (success) {