feat: 完成逻辑分析仪前端设计
This commit is contained in:
parent
b139542c4c
commit
9f25391540
|
@ -1,174 +0,0 @@
|
|||
<template>
|
||||
<div class="space-y-4">
|
||||
<!-- 通道状态概览 -->
|
||||
<div class="stats stats-horizontal bg-base-100 shadow flex justify-between">
|
||||
<div class="stat">
|
||||
<div class="stat-title">总通道数</div>
|
||||
<div class="stat-value text-primary">8</div>
|
||||
<div class="stat-desc">逻辑分析仪通道</div>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-title">启用通道</div>
|
||||
<div class="stat-value text-success">{{ enabledChannelCount }}</div>
|
||||
<div class="stat-desc">当前激活通道</div>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-title">采样率</div>
|
||||
<div class="stat-value text-info">100MHz</div>
|
||||
<div class="stat-desc">最大采样频率</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 通道配置列表 -->
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center justify-between p-2 bg-base-300 rounded-lg">
|
||||
<span class="font-medium">通道</span>
|
||||
<span class="font-medium">启用</span>
|
||||
<span class="font-medium">标签</span>
|
||||
<span class="font-medium">颜色</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-for="(channel, index) in channels"
|
||||
:key="index"
|
||||
class="flex items-center justify-between p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||
>
|
||||
<!-- 通道编号 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-mono font-medium w-12">CH{{ index }}</span>
|
||||
<div
|
||||
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||
:style="{ backgroundColor: channel.color }"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- 启用开关 -->
|
||||
<div class="form-control">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="channel.enabled"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
@change="updateChannelStatus(index)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 通道标签 -->
|
||||
<div class="form-control w-32">
|
||||
<input
|
||||
type="text"
|
||||
v-model="channel.label"
|
||||
:placeholder="`通道 ${index}`"
|
||||
class="input input-sm input-bordered w-full"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 颜色选择 -->
|
||||
<div class="form-control">
|
||||
<input
|
||||
type="color"
|
||||
v-model="channel.color"
|
||||
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 批量操作 -->
|
||||
<div class="flex gap-2 pt-4">
|
||||
<button @click="enableAllChannels" class="btn btn-primary btn-sm">
|
||||
全部启用
|
||||
</button>
|
||||
|
||||
<button @click="disableAllChannels" class="btn btn-outline btn-sm">
|
||||
全部禁用
|
||||
</button>
|
||||
|
||||
<button @click="resetChannelLabels" class="btn btn-outline btn-sm">
|
||||
重置标签
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, reactive } from "vue";
|
||||
|
||||
// 通道接口定义
|
||||
interface Channel {
|
||||
enabled: boolean;
|
||||
label: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
// 预设配置接口
|
||||
interface Preset {
|
||||
name: string;
|
||||
description: string;
|
||||
channels: Partial<Channel>[];
|
||||
}
|
||||
|
||||
// 默认颜色数组
|
||||
const defaultColors = [
|
||||
"#FF5733",
|
||||
"#33FF57",
|
||||
"#3357FF",
|
||||
"#FF33F5",
|
||||
"#F5FF33",
|
||||
"#33FFF5",
|
||||
"#FF8C33",
|
||||
"#8C33FF",
|
||||
];
|
||||
|
||||
// 通道配置
|
||||
const channels = reactive<Channel[]>(
|
||||
Array.from({ length: 8 }, (_, index) => ({
|
||||
enabled: false,
|
||||
label: `CH${index}`,
|
||||
color: defaultColors[index],
|
||||
})),
|
||||
);
|
||||
|
||||
// 计算启用的通道数量
|
||||
const enabledChannelCount = computed(
|
||||
() => channels.filter((channel) => channel.enabled).length,
|
||||
);
|
||||
|
||||
// 更新通道状态
|
||||
const updateChannelStatus = (index: number) => {
|
||||
console.log(`通道 ${index} 状态更新:`, channels[index].enabled);
|
||||
};
|
||||
|
||||
// 启用所有通道
|
||||
const enableAllChannels = () => {
|
||||
channels.forEach((channel) => {
|
||||
channel.enabled = true;
|
||||
});
|
||||
};
|
||||
|
||||
// 禁用所有通道
|
||||
const disableAllChannels = () => {
|
||||
channels.forEach((channel) => {
|
||||
channel.enabled = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 重置通道标签
|
||||
const resetChannelLabels = () => {
|
||||
channels.forEach((channel, index) => {
|
||||
channel.label = `CH${index}`;
|
||||
});
|
||||
};
|
||||
|
||||
// 应用预设配置
|
||||
const applyPreset = (preset: Preset) => {
|
||||
preset.channels.forEach((presetChannel, index) => {
|
||||
if (index < channels.length && presetChannel) {
|
||||
Object.assign(channels[index], presetChannel);
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,224 @@
|
|||
import { createInjectionState } from "@vueuse/core";
|
||||
import { generateTestLogicData, type LogicDataType } from ".";
|
||||
import { shallowRef, reactive, ref, computed } from "vue";
|
||||
import {
|
||||
CaptureConfig,
|
||||
LogicAnalyzerClient,
|
||||
GlobalCaptureMode,
|
||||
SignalOperator,
|
||||
SignalValue,
|
||||
type SignalTriggerConfig,
|
||||
} from "@/APIClient";
|
||||
import { AuthManager } from "@/utils/AuthManager";
|
||||
import { useAlertStore } from "@/components/Alert";
|
||||
|
||||
// 通道接口定义
|
||||
export interface Channel {
|
||||
enabled: boolean;
|
||||
label: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
// 全局模式选项
|
||||
const globalModes = [
|
||||
{
|
||||
value: GlobalCaptureMode.AND,
|
||||
label: "AND",
|
||||
description: "所有条件都满足时触发",
|
||||
},
|
||||
{
|
||||
value: GlobalCaptureMode.OR,
|
||||
label: "OR",
|
||||
description: "任一条件满足时触发",
|
||||
},
|
||||
{ value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" },
|
||||
{ value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" },
|
||||
];
|
||||
|
||||
// 操作符选项
|
||||
const operators = [
|
||||
{ value: SignalOperator.Equal, label: "=" },
|
||||
{ value: SignalOperator.NotEqual, label: "≠" },
|
||||
{ value: SignalOperator.LessThan, label: "<" },
|
||||
{ value: SignalOperator.LessThanOrEqual, label: "≤" },
|
||||
{ value: SignalOperator.GreaterThan, label: ">" },
|
||||
{ value: SignalOperator.GreaterThanOrEqual, label: "≥" },
|
||||
];
|
||||
|
||||
// 信号值选项
|
||||
const signalValues = [
|
||||
{ value: SignalValue.Logic0, label: "0" },
|
||||
{ value: SignalValue.Logic1, label: "1" },
|
||||
{ value: SignalValue.NotCare, label: "X" },
|
||||
{ value: SignalValue.Rise, label: "↑" },
|
||||
{ value: SignalValue.Fall, label: "↓" },
|
||||
{ value: SignalValue.RiseOrFall, label: "↕" },
|
||||
{ value: SignalValue.NoChange, label: "—" },
|
||||
{ value: SignalValue.SomeNumber, label: "#" },
|
||||
];
|
||||
|
||||
// 默认颜色数组
|
||||
const defaultColors = [
|
||||
"#FF5733",
|
||||
"#33FF57",
|
||||
"#3357FF",
|
||||
"#FF33F5",
|
||||
"#F5FF33",
|
||||
"#33FFF5",
|
||||
"#FF8C33",
|
||||
"#8C33FF",
|
||||
];
|
||||
|
||||
const [useProvideLogicAnalyzer, useLogicAnalyzerState] = createInjectionState(
|
||||
() => {
|
||||
const logicData = shallowRef<LogicDataType>();
|
||||
const alert = useAlertStore();
|
||||
|
||||
// 触发设置相关状态
|
||||
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
|
||||
const isApplying = ref(false);
|
||||
|
||||
// 通道配置
|
||||
const channels = reactive<Channel[]>(
|
||||
Array.from({ length: 8 }, (_, index) => ({
|
||||
enabled: false,
|
||||
label: `CH${index}`,
|
||||
color: defaultColors[index],
|
||||
})),
|
||||
);
|
||||
|
||||
// 8个信号通道的配置
|
||||
const signalConfigs = reactive(
|
||||
Array.from({ length: 8 }, (_, index) => ({
|
||||
signalIndex: index,
|
||||
operator: SignalOperator.Equal,
|
||||
value: SignalValue.Logic1,
|
||||
})),
|
||||
);
|
||||
|
||||
// 计算启用的通道数量
|
||||
const enabledChannelCount = computed(
|
||||
() => channels.filter((channel) => channel.enabled).length,
|
||||
);
|
||||
|
||||
const enableAllChannels = () => {
|
||||
channels.forEach((channel) => {
|
||||
channel.enabled = true;
|
||||
});
|
||||
};
|
||||
|
||||
const disableAllChannels = () => {
|
||||
channels.forEach((channel) => {
|
||||
channel.enabled = false;
|
||||
});
|
||||
};
|
||||
|
||||
const setGlobalMode = async (mode: GlobalCaptureMode) => {
|
||||
try {
|
||||
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
||||
const success = await client.setGlobalTrigMode(mode);
|
||||
|
||||
if (success) {
|
||||
currentGlobalMode.value = mode;
|
||||
alert?.success(
|
||||
`全局触发模式已设置为 ${globalModes.find((m) => m.value === mode)?.label}`,
|
||||
3000,
|
||||
);
|
||||
} else {
|
||||
throw new Error("设置失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置全局触发模式失败:", error);
|
||||
alert?.error("设置全局触发模式失败", 3000);
|
||||
}
|
||||
};
|
||||
|
||||
const applyConfiguration = async () => {
|
||||
isApplying.value = true;
|
||||
|
||||
try {
|
||||
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
||||
|
||||
// 准备配置数据 - 只包含启用的通道
|
||||
const enabledSignals = signalConfigs.filter(
|
||||
(signal, index) => channels[index].enabled,
|
||||
);
|
||||
|
||||
const config = new CaptureConfig({
|
||||
globalMode: currentGlobalMode.value,
|
||||
signalConfigs: enabledSignals.map(
|
||||
(signal) =>
|
||||
({
|
||||
signalIndex: signal.signalIndex,
|
||||
operator: signal.operator,
|
||||
value: signal.value,
|
||||
}) as SignalTriggerConfig,
|
||||
),
|
||||
});
|
||||
|
||||
// 发送配置
|
||||
const success = await client.configureCapture(config);
|
||||
|
||||
if (success) {
|
||||
const enabledChannelCount = channels.filter(
|
||||
(ch) => ch.enabled,
|
||||
).length;
|
||||
alert?.success(
|
||||
`配置已成功应用,启用了 ${enabledChannelCount} 个通道和触发条件`,
|
||||
3000,
|
||||
);
|
||||
} else {
|
||||
throw new Error("应用配置失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("应用配置失败:", error);
|
||||
alert?.error("应用配置失败,请检查设备连接", 3000);
|
||||
} finally {
|
||||
isApplying.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const resetConfiguration = () => {
|
||||
currentGlobalMode.value = GlobalCaptureMode.AND;
|
||||
|
||||
channels.forEach((channel, index) => {
|
||||
channel.enabled = false;
|
||||
channel.label = `CH${index}`;
|
||||
channel.color = defaultColors[index];
|
||||
});
|
||||
|
||||
signalConfigs.forEach((signal) => {
|
||||
signal.operator = SignalOperator.Equal;
|
||||
signal.value = SignalValue.Logic1;
|
||||
});
|
||||
|
||||
alert?.info("配置已重置", 2000);
|
||||
};
|
||||
|
||||
return {
|
||||
// 原有的逻辑数据
|
||||
logicData,
|
||||
|
||||
// 触发设置状态
|
||||
currentGlobalMode,
|
||||
isApplying,
|
||||
channels,
|
||||
signalConfigs,
|
||||
enabledChannelCount,
|
||||
|
||||
// 选项数据
|
||||
globalModes,
|
||||
operators,
|
||||
signalValues,
|
||||
|
||||
// 触发设置方法
|
||||
enableAllChannels,
|
||||
disableAllChannels,
|
||||
setGlobalMode,
|
||||
applyConfiguration,
|
||||
resetConfiguration,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export { useProvideLogicAnalyzer, useLogicAnalyzerState };
|
|
@ -1,17 +1,43 @@
|
|||
<template>
|
||||
<div class="w-full h-150">
|
||||
<v-chart
|
||||
v-if="data"
|
||||
class="w-full h-full"
|
||||
:option="option"
|
||||
autoresize
|
||||
<div
|
||||
class="w-full"
|
||||
:class="{
|
||||
'h-48': !analyzer.logicData.value,
|
||||
'h-150': analyzer.logicData.value,
|
||||
}"
|
||||
>
|
||||
<v-chart
|
||||
v-if="analyzer.logicData.value"
|
||||
class="w-full h-full"
|
||||
:option="option"
|
||||
autoresize
|
||||
:update-options="updateOptions"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
class="w-full h-full flex items-center justify-center text-gray-500"
|
||||
class="w-full h-full flex flex-col gap-6 items-center justify-center"
|
||||
>
|
||||
暂无数据
|
||||
<div class="text-center">
|
||||
<h3 class="text-xl font-semibold text-slate-600 mb-2">
|
||||
暂无逻辑分析数据
|
||||
</h3>
|
||||
<p class="text-sm text-slate-500">点击下方按钮生成测试数据用于观察</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="group relative px-8 py-3 bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white font-medium rounded-lg shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-200 ease-in-out focus:outline-none focus:ring-4 focus:ring-blue-300 active:scale-95"
|
||||
@click="handleGenerateTestData"
|
||||
>
|
||||
<span class="flex items-center gap-2">
|
||||
<RefreshCcw
|
||||
class="w-5 h-5 group-hover:rotate-180 transition-transform duration-300"
|
||||
/>
|
||||
生成测试数据
|
||||
</span>
|
||||
<div
|
||||
class="absolute inset-0 bg-white opacity-0 group-hover:opacity-20 rounded-lg transition-opacity duration-200"
|
||||
></div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -19,7 +45,8 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, shallowRef } from "vue";
|
||||
import VChart from "vue-echarts";
|
||||
import type { LogicDataType } from "./index";
|
||||
import { generateTestLogicData } from "./index";
|
||||
import { RefreshCcw } from "lucide-vue-next";
|
||||
|
||||
// Echarts
|
||||
import { use } from "echarts/core";
|
||||
|
@ -45,6 +72,9 @@ import type {
|
|||
XAXisOption,
|
||||
YAXisOption,
|
||||
} from "echarts/types/dist/shared";
|
||||
import { useLogicAnalyzerState } from "./LogicAnalyzerManager";
|
||||
import { useRequiredInjection } from "@/utils/Common";
|
||||
import { isUndefined } from "lodash";
|
||||
|
||||
use([
|
||||
TooltipComponent,
|
||||
|
@ -65,24 +95,19 @@ type EChartsOption = ComposeOption<
|
|||
| LineSeriesOption
|
||||
>;
|
||||
|
||||
// Define props
|
||||
interface Props {
|
||||
data?: LogicDataType;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const analyzer = useRequiredInjection(useLogicAnalyzerState);
|
||||
|
||||
// 添加更新选项来减少重绘
|
||||
const updateOptions = shallowRef({
|
||||
notMerge: false,
|
||||
lazyUpdate: true,
|
||||
silent: false
|
||||
silent: false,
|
||||
});
|
||||
|
||||
const option = computed((): EChartsOption => {
|
||||
if (!props.data) return {};
|
||||
if (isUndefined(analyzer.logicData.value)) return {};
|
||||
|
||||
const channelCount = props.data.y.length;
|
||||
const channelCount = analyzer.logicData.value.y.length;
|
||||
const channelSpacing = 2; // 每个通道之间的间距
|
||||
|
||||
// 使用单个网格
|
||||
|
@ -100,9 +125,12 @@ const option = computed((): EChartsOption => {
|
|||
{
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
data: props.data!.x.map((x) => x.toFixed(3)),
|
||||
data: analyzer.logicData.value.x.map((x) => x.toFixed(3)),
|
||||
axisLabel: {
|
||||
formatter: (value: string) => `${value}${props.data!.xUnit}`,
|
||||
formatter: (value: string) =>
|
||||
analyzer.logicData.value
|
||||
? `${value}${analyzer.logicData.value.xUnit}`
|
||||
: `${value}`,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -117,8 +145,8 @@ const option = computed((): EChartsOption => {
|
|||
axisLabel: {
|
||||
formatter: (value: number) => {
|
||||
const channelIndex = Math.round(value / channelSpacing);
|
||||
return channelIndex < channelCount
|
||||
? props.data!.channelNames[channelIndex]
|
||||
return channelIndex < channelCount && analyzer.logicData.value
|
||||
? analyzer.logicData.value.channelNames[channelIndex]
|
||||
: "";
|
||||
},
|
||||
},
|
||||
|
@ -127,27 +155,33 @@ const option = computed((): EChartsOption => {
|
|||
];
|
||||
|
||||
// 创建系列数据,每个通道有不同的Y偏移
|
||||
const series: LineSeriesOption[] = props.data.y.map((channelData, index) => ({
|
||||
name: props.data!.channelNames[index],
|
||||
type: "line",
|
||||
data: channelData.map((value) => value + index * channelSpacing + 0.2),
|
||||
step: "end",
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
origin: index * channelSpacing,
|
||||
},
|
||||
symbol: "none",
|
||||
// 优化性能配置
|
||||
sampling: "lttb",
|
||||
// large: true,
|
||||
// largeThreshold: 2000,
|
||||
// progressive: 2000,
|
||||
// 减少动画以避免闪烁
|
||||
animation: false,
|
||||
}));
|
||||
const series: LineSeriesOption[] = analyzer.logicData.value.y.map(
|
||||
(channelData: number[], index: number) => ({
|
||||
name:
|
||||
analyzer.logicData.value?.channelNames?.[index] ??
|
||||
`Channel ${index + 1}`,
|
||||
type: "line",
|
||||
data: channelData.map(
|
||||
(value: number) => value + index * channelSpacing + 0.2,
|
||||
),
|
||||
step: "end",
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
origin: index * channelSpacing,
|
||||
},
|
||||
symbol: "none",
|
||||
// 优化性能配置
|
||||
sampling: "lttb",
|
||||
// large: true,
|
||||
// largeThreshold: 2000,
|
||||
// progressive: 2000,
|
||||
// 减少动画以避免闪烁
|
||||
animation: false,
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
// 全局动画配置
|
||||
|
@ -164,16 +198,21 @@ const option = computed((): EChartsOption => {
|
|||
},
|
||||
formatter: (params: any) => {
|
||||
if (Array.isArray(params) && params.length > 0) {
|
||||
const timeValue = props.data!.x[params[0].dataIndex];
|
||||
const timeValue = analyzer.logicData.value!.x[params[0].dataIndex];
|
||||
const dataIndex = params[0].dataIndex;
|
||||
|
||||
let tooltip = `Time: ${timeValue.toFixed(3)}${props.data!.xUnit}<br/>`;
|
||||
let tooltip = `Time: ${timeValue.toFixed(3)}${analyzer.logicData.value!.xUnit}<br/>`;
|
||||
|
||||
// 显示所有通道在当前时间点的原始数值(0或1)
|
||||
props.data!.channelNames.forEach((channelName, index) => {
|
||||
const originalValue = props.data!.y[index][dataIndex];
|
||||
tooltip += `${channelName}: ${originalValue}<br/>`;
|
||||
});
|
||||
if (analyzer.logicData.value) {
|
||||
analyzer.logicData.value.channelNames.forEach(
|
||||
(channelName: string, index: number) => {
|
||||
const originalValue =
|
||||
analyzer.logicData.value!.y[index][dataIndex];
|
||||
tooltip += `${channelName}: ${originalValue}<br/>`;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
@ -207,4 +246,8 @@ const option = computed((): EChartsOption => {
|
|||
series: series,
|
||||
};
|
||||
});
|
||||
|
||||
function handleGenerateTestData() {
|
||||
analyzer.logicData.value = generateTestLogicData();
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,266 +1,376 @@
|
|||
<template>
|
||||
<div class="space-y-4">
|
||||
<!-- 全局触发模式配置 -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">全局触发模式</span>
|
||||
</label>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
<button
|
||||
v-for="mode in globalModes"
|
||||
:key="mode.value"
|
||||
@click="setGlobalMode(mode.value)"
|
||||
:class="[
|
||||
'btn btn-sm',
|
||||
currentGlobalMode === mode.value ? 'btn-primary' : 'btn-outline',
|
||||
]"
|
||||
>
|
||||
{{ mode.label }}
|
||||
</button>
|
||||
<div class="space-y-6">
|
||||
<!-- 通道状态概览 -->
|
||||
<div class="stats stats-horizontal bg-base-100 shadow flex justify-between">
|
||||
<div class="stat">
|
||||
<div class="stat-title">总通道数</div>
|
||||
<div class="stat-value text-primary">8</div>
|
||||
<div class="stat-desc">逻辑分析仪通道</div>
|
||||
</div>
|
||||
<div class="label">
|
||||
<span class="label-text-alt text-gray-500">
|
||||
选择多路信号触发条件的逻辑组合方式
|
||||
</span>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-title">启用通道</div>
|
||||
<div class="stat-value text-success">{{ enabledChannelCount }}</div>
|
||||
<div class="stat-desc">当前激活通道</div>
|
||||
</div>
|
||||
|
||||
<div class="stat">
|
||||
<div class="stat-title">采样率</div>
|
||||
<div class="stat-value text-info">100MHz</div>
|
||||
<div class="stat-desc">最大采样频率</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 信号触发配置 -->
|
||||
<!-- 通道配置 -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text font-medium">信号触发配置</span>
|
||||
</label>
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="(signal, index) in signalConfigs"
|
||||
:key="index"
|
||||
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg"
|
||||
>
|
||||
<span class="text-sm font-medium w-16">CH{{ index }}</span>
|
||||
|
||||
<!-- 操作符选择 -->
|
||||
<!-- 全局触发模式选择 -->
|
||||
<div class="flex flex-row justify-between my-4 mx-2">
|
||||
<div class="flex flex-row gap-4">
|
||||
<label class="label">
|
||||
<span class="label-text text-sm">全局触发逻辑</span>
|
||||
</label>
|
||||
<select
|
||||
v-model="signal.operator"
|
||||
class="select select-sm select-bordered w-32"
|
||||
>
|
||||
<option v-for="op in operators" :key="op.value" :value="op.value">
|
||||
{{ op.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- 信号值选择 -->
|
||||
<select
|
||||
v-model="signal.value"
|
||||
class="select select-sm select-bordered w-32"
|
||||
v-model="currentGlobalMode"
|
||||
@change="setGlobalMode(currentGlobalMode)"
|
||||
class="select select-sm select-bordered w-full"
|
||||
>
|
||||
<option
|
||||
v-for="val in signalValues"
|
||||
:key="val.value"
|
||||
:value="val.value"
|
||||
v-for="mode in globalModes"
|
||||
:key="mode.value"
|
||||
:value="mode.value"
|
||||
>
|
||||
{{ val.label }}
|
||||
{{ mode.label }} - {{ mode.description }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 启用/禁用开关 -->
|
||||
<div class="form-control">
|
||||
<label class="label cursor-pointer gap-2">
|
||||
<span class="label-text text-sm">启用</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="signal.enabled"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
/>
|
||||
</label>
|
||||
<div class="flex flex-row gap-4">
|
||||
<button @click="toggleAllChannels" class="btn btn-primary btn-sm">
|
||||
{{ enabledChannelCount > 0 ? "全部禁用" : "全部启用" }}
|
||||
</button>
|
||||
<button
|
||||
@click="applyConfiguration"
|
||||
:disabled="isApplying"
|
||||
class="btn btn-primary btn-sm"
|
||||
>
|
||||
<span
|
||||
v-if="isApplying"
|
||||
class="loading loading-spinner loading-sm"
|
||||
></span>
|
||||
应用配置
|
||||
</button>
|
||||
|
||||
<button @click="resetConfiguration" class="btn btn-outline btn-sm">
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 通道列表 -->
|
||||
<div class="space-y-2">
|
||||
<!-- 表头 - 小屏幕单列时显示 -->
|
||||
<div
|
||||
class="flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium lg:hidden"
|
||||
>
|
||||
<span class="w-16">通道</span>
|
||||
<span class="w-20">启用/触发</span>
|
||||
<span class="w-32">标签</span>
|
||||
<span class="w-16">颜色</span>
|
||||
<span class="w-32">触发操作</span>
|
||||
<span class="w-32">触发值</span>
|
||||
</div>
|
||||
|
||||
<!-- 通道配置网格 -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<!-- 左列 (CH0-CH3) -->
|
||||
<div class="space-y-2">
|
||||
<!-- 左列表头 - 大屏幕时显示 -->
|
||||
<div
|
||||
class="hidden lg:flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium"
|
||||
>
|
||||
<span class="w-16">通道</span>
|
||||
<span class="w-20">启用</span>
|
||||
<span class="w-32">标签</span>
|
||||
<span class="w-16">颜色</span>
|
||||
<span class="w-32">触发操作</span>
|
||||
<span class="w-32">触发值</span>
|
||||
</div>
|
||||
|
||||
<!-- 左列通道 (0-3) -->
|
||||
<div
|
||||
v-for="(channel, index) in channels.slice(0, 4)"
|
||||
:key="index"
|
||||
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||
>
|
||||
<!-- 通道编号和颜色指示 -->
|
||||
<div class="flex items-center gap-2 w-16">
|
||||
<span class="font-mono font-medium">CH{{ index }}</span>
|
||||
<div
|
||||
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||
:style="{ backgroundColor: channel.color }"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- 通道启用开关(同时控制触发) -->
|
||||
<div class="form-control w-20">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="channel.enabled"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 通道标签 -->
|
||||
<div class="form-control w-32">
|
||||
<input
|
||||
type="text"
|
||||
v-model="channel.label"
|
||||
:placeholder="`通道 ${index}`"
|
||||
class="input input-sm input-bordered w-full"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 颜色选择 -->
|
||||
<div class="form-control w-16">
|
||||
<input
|
||||
type="color"
|
||||
v-model="channel.color"
|
||||
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 触发操作符选择 -->
|
||||
<select
|
||||
v-model="signalConfigs[index].operator"
|
||||
class="select select-sm select-bordered w-32"
|
||||
:disabled="!channel.enabled"
|
||||
>
|
||||
<option
|
||||
v-for="op in operators"
|
||||
:key="op.value"
|
||||
:value="op.value"
|
||||
>
|
||||
{{ op.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- 触发信号值选择 -->
|
||||
<select
|
||||
v-model="signalConfigs[index].value"
|
||||
class="select select-sm select-bordered w-32"
|
||||
:disabled="!channel.enabled"
|
||||
>
|
||||
<option
|
||||
v-for="val in signalValues"
|
||||
:key="val.value"
|
||||
:value="val.value"
|
||||
>
|
||||
{{ val.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右列 (CH4-CH7) - 仅在大屏幕显示 -->
|
||||
<div class="hidden lg:block space-y-2">
|
||||
<!-- 右列表头 -->
|
||||
<div
|
||||
class="flex items-center gap-2 p-2 bg-base-300 rounded-lg text-sm font-medium"
|
||||
>
|
||||
<span class="w-16">通道</span>
|
||||
<span class="w-20">启用/触发</span>
|
||||
<span class="w-32">标签</span>
|
||||
<span class="w-16">颜色</span>
|
||||
<span class="w-32">触发操作</span>
|
||||
<span class="w-32">触发值</span>
|
||||
</div>
|
||||
|
||||
<!-- 右列通道 (4-7) -->
|
||||
<div
|
||||
v-for="(channel, index) in channels.slice(4, 8)"
|
||||
:key="index + 4"
|
||||
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||
>
|
||||
<!-- 通道编号和颜色指示 -->
|
||||
<div class="flex items-center gap-2 w-16">
|
||||
<span class="font-mono font-medium">CH{{ index + 4 }}</span>
|
||||
<div
|
||||
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||
:style="{ backgroundColor: channel.color }"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- 通道启用开关(同时控制触发) -->
|
||||
<div class="form-control w-20">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="channel.enabled"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 通道标签 -->
|
||||
<div class="form-control w-32">
|
||||
<input
|
||||
type="text"
|
||||
v-model="channel.label"
|
||||
:placeholder="`通道 ${index + 4}`"
|
||||
class="input input-sm input-bordered w-full"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 颜色选择 -->
|
||||
<div class="form-control w-16">
|
||||
<input
|
||||
type="color"
|
||||
v-model="channel.color"
|
||||
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 触发操作符选择 -->
|
||||
<select
|
||||
v-model="signalConfigs[index + 4].operator"
|
||||
class="select select-sm select-bordered w-32"
|
||||
:disabled="!channel.enabled"
|
||||
>
|
||||
<option
|
||||
v-for="op in operators"
|
||||
:key="op.value"
|
||||
:value="op.value"
|
||||
>
|
||||
{{ op.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- 触发信号值选择 -->
|
||||
<select
|
||||
v-model="signalConfigs[index + 4].value"
|
||||
class="select select-sm select-bordered w-32"
|
||||
:disabled="!channel.enabled"
|
||||
>
|
||||
<option
|
||||
v-for="val in signalValues"
|
||||
:key="val.value"
|
||||
:value="val.value"
|
||||
>
|
||||
{{ val.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 小屏幕时继续显示 CH4-CH7 -->
|
||||
<div class="lg:hidden space-y-2">
|
||||
<div
|
||||
v-for="(channel, index) in channels.slice(4, 8)"
|
||||
:key="index + 4"
|
||||
class="flex items-center gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
|
||||
>
|
||||
<!-- 通道编号和颜色指示 -->
|
||||
<div class="flex items-center gap-2 w-16">
|
||||
<span class="font-mono font-medium">CH{{ index + 4 }}</span>
|
||||
<div
|
||||
class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
|
||||
:style="{ backgroundColor: channel.color }"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<!-- 通道启用开关(同时控制触发) -->
|
||||
<div class="form-control w-20">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="channel.enabled"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 通道标签 -->
|
||||
<div class="form-control w-32">
|
||||
<input
|
||||
type="text"
|
||||
v-model="channel.label"
|
||||
:placeholder="`通道 ${index + 4}`"
|
||||
class="input input-sm input-bordered w-full"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 颜色选择 -->
|
||||
<div class="form-control w-16">
|
||||
<input
|
||||
type="color"
|
||||
v-model="channel.color"
|
||||
class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
|
||||
:disabled="!channel.enabled"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 触发操作符选择 -->
|
||||
<select
|
||||
v-model="signalConfigs[index + 4].operator"
|
||||
class="select select-sm select-bordered w-32"
|
||||
:disabled="!channel.enabled"
|
||||
>
|
||||
<option
|
||||
v-for="op in operators"
|
||||
:key="op.value"
|
||||
:value="op.value"
|
||||
>
|
||||
{{ op.label }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- 触发信号值选择 -->
|
||||
<select
|
||||
v-model="signalConfigs[index + 4].value"
|
||||
class="select select-sm select-bordered w-32"
|
||||
:disabled="!channel.enabled"
|
||||
>
|
||||
<option
|
||||
v-for="val in signalValues"
|
||||
:key="val.value"
|
||||
:value="val.value"
|
||||
>
|
||||
{{ val.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="flex gap-2 pt-4">
|
||||
<button
|
||||
@click="applyConfiguration"
|
||||
:disabled="isApplying"
|
||||
class="btn btn-primary btn-sm"
|
||||
>
|
||||
<span
|
||||
v-if="isApplying"
|
||||
class="loading loading-spinner loading-sm"
|
||||
></span>
|
||||
应用配置
|
||||
</button>
|
||||
|
||||
<button @click="resetConfiguration" class="btn btn-outline btn-sm">
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 状态指示 -->
|
||||
<div
|
||||
v-if="lastApplyResult"
|
||||
class="alert alert-sm"
|
||||
:class="lastApplyResult.success ? 'alert-success' : 'alert-error'"
|
||||
>
|
||||
<span>{{ lastApplyResult.message }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from "vue";
|
||||
import { useEquipments } from "@/stores/equipments";
|
||||
import {
|
||||
CaptureConfig,
|
||||
LogicAnalyzerClient,
|
||||
GlobalCaptureMode,
|
||||
SignalOperator,
|
||||
SignalValue,
|
||||
type SignalTriggerConfig,
|
||||
} from "@/APIClient";
|
||||
import { AuthManager } from "@/utils/AuthManager";
|
||||
import { useRequiredInjection } from "@/utils/Common";
|
||||
import { useLogicAnalyzerState } from "./LogicAnalyzerManager";
|
||||
|
||||
// 使用设备配置
|
||||
const equipments = useEquipments();
|
||||
const {
|
||||
currentGlobalMode,
|
||||
isApplying,
|
||||
channels,
|
||||
signalConfigs,
|
||||
enabledChannelCount,
|
||||
globalModes,
|
||||
operators,
|
||||
signalValues,
|
||||
enableAllChannels,
|
||||
disableAllChannels,
|
||||
setGlobalMode,
|
||||
applyConfiguration,
|
||||
resetConfiguration,
|
||||
} = useRequiredInjection(useLogicAnalyzerState);
|
||||
|
||||
// 当前全局模式
|
||||
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
|
||||
|
||||
// 加载状态
|
||||
const isApplying = ref(false);
|
||||
const lastApplyResult = ref<{ success: boolean; message: string } | null>(null);
|
||||
|
||||
// 全局模式选项
|
||||
const globalModes = [
|
||||
{
|
||||
value: GlobalCaptureMode.AND,
|
||||
label: "AND",
|
||||
description: "所有条件都满足时触发",
|
||||
},
|
||||
{
|
||||
value: GlobalCaptureMode.OR,
|
||||
label: "OR",
|
||||
description: "任一条件满足时触发",
|
||||
},
|
||||
{ value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" },
|
||||
{ value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" },
|
||||
];
|
||||
|
||||
// 操作符选项
|
||||
const operators = [
|
||||
{ value: SignalOperator.Equal, label: "=" },
|
||||
{ value: SignalOperator.NotEqual, label: "≠" },
|
||||
{ value: SignalOperator.LessThan, label: "<" },
|
||||
{ value: SignalOperator.LessThanOrEqual, label: "≤" },
|
||||
{ value: SignalOperator.GreaterThan, label: ">" },
|
||||
{ value: SignalOperator.GreaterThanOrEqual, label: "≥" },
|
||||
];
|
||||
|
||||
// 信号值选项
|
||||
const signalValues = [
|
||||
{ value: SignalValue.Logic0, label: "0" },
|
||||
{ value: SignalValue.Logic1, label: "1" },
|
||||
{ value: SignalValue.NotCare, label: "X" },
|
||||
{ value: SignalValue.Rise, label: "↑" },
|
||||
{ value: SignalValue.Fall, label: "↓" },
|
||||
{ value: SignalValue.RiseOrFall, label: "↕" },
|
||||
{ value: SignalValue.NoChange, label: "—" },
|
||||
{ value: SignalValue.SomeNumber, label: "#" },
|
||||
];
|
||||
|
||||
// 8个信号通道的配置
|
||||
const signalConfigs = reactive(
|
||||
Array.from({ length: 8 }, (_, index) => ({
|
||||
signalIndex: index,
|
||||
operator: SignalOperator.Equal,
|
||||
value: SignalValue.Logic1,
|
||||
enabled: false,
|
||||
})),
|
||||
);
|
||||
|
||||
// 设置全局触发模式
|
||||
const setGlobalMode = async (mode: GlobalCaptureMode) => {
|
||||
try {
|
||||
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
||||
const success = await client.setGlobalTrigMode(mode);
|
||||
|
||||
if (success) {
|
||||
currentGlobalMode.value = mode;
|
||||
lastApplyResult.value = {
|
||||
success: true,
|
||||
message: `全局触发模式已设置为 ${globalModes.find((m) => m.value === mode)?.label}`,
|
||||
};
|
||||
} else {
|
||||
throw new Error("设置失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置全局触发模式失败:", error);
|
||||
lastApplyResult.value = {
|
||||
success: false,
|
||||
message: "设置全局触发模式失败",
|
||||
};
|
||||
const toggleAllChannels = () => {
|
||||
if (enabledChannelCount.value > 0) {
|
||||
disableAllChannels();
|
||||
} else {
|
||||
enableAllChannels();
|
||||
}
|
||||
};
|
||||
|
||||
// 应用完整配置
|
||||
const applyConfiguration = async () => {
|
||||
isApplying.value = true;
|
||||
lastApplyResult.value = null;
|
||||
|
||||
try {
|
||||
const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
|
||||
|
||||
// 准备配置数据
|
||||
const enabledSignals = signalConfigs.filter((signal) => signal.enabled);
|
||||
const config = new CaptureConfig({
|
||||
globalMode: currentGlobalMode.value,
|
||||
signalConfigs: enabledSignals.map(
|
||||
(signal) =>
|
||||
({
|
||||
signalIndex: signal.signalIndex,
|
||||
operator: signal.operator,
|
||||
value: signal.value,
|
||||
}) as SignalTriggerConfig,
|
||||
),
|
||||
});
|
||||
|
||||
// 发送配置
|
||||
const success = await client.configureCapture(config);
|
||||
|
||||
if (success) {
|
||||
lastApplyResult.value = {
|
||||
success: true,
|
||||
message: `配置已成功应用,启用了 ${enabledSignals.length} 个通道`,
|
||||
};
|
||||
} else {
|
||||
throw new Error("应用配置失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("应用配置失败:", error);
|
||||
lastApplyResult.value = {
|
||||
success: false,
|
||||
message: "应用配置失败,请检查设备连接",
|
||||
};
|
||||
} finally {
|
||||
isApplying.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 重置配置
|
||||
const resetConfiguration = () => {
|
||||
currentGlobalMode.value = GlobalCaptureMode.AND;
|
||||
signalConfigs.forEach((signal) => {
|
||||
signal.operator = SignalOperator.Equal;
|
||||
signal.value = SignalValue.Logic1;
|
||||
signal.enabled = false;
|
||||
});
|
||||
lastApplyResult.value = null;
|
||||
};
|
||||
|
||||
// 清除状态消息
|
||||
setTimeout(() => {
|
||||
if (lastApplyResult.value) {
|
||||
lastApplyResult.value = null;
|
||||
}
|
||||
}, 5000);
|
||||
</script>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { exp } from "mathjs";
|
||||
import LogicalWaveFormDisplay from "./LogicalWaveFormDisplay.vue";
|
||||
|
||||
type LogicDataType = {
|
||||
|
@ -75,4 +76,4 @@ function generateTestLogicData(): LogicDataType {
|
|||
|
||||
export { LogicalWaveFormDisplay, generateTestLogicData, type LogicDataType };
|
||||
export { default as TriggerSettings } from './TriggerSettings.vue'
|
||||
export { default as ChannelConfig } from './ChannelConfig.vue'
|
||||
export { useProvideLogicAnalyzer , useLogicAnalyzerState } from './LogicAnalyzerManager.ts'
|
|
@ -1,18 +1,25 @@
|
|||
<template>
|
||||
<div class="bg-base-100 flex flex-col">
|
||||
<div class="bg-base-100 flex flex-col gap-10 mb-5">
|
||||
<!-- 逻辑信号展示 -->
|
||||
<div class="card bg-base-200 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
<Zap class="w-5 h-5" />
|
||||
逻辑信号分析
|
||||
<h2 class="card-title flex justify-between items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<Zap class="w-5 h-5" />
|
||||
逻辑信号分析
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="btn btn-sm btn-error" @click="handleDeleteData">
|
||||
清空
|
||||
</button>
|
||||
</div>
|
||||
</h2>
|
||||
<LogicalWaveFormDisplay :data="generateTestLogicData()" />
|
||||
<LogicalWaveFormDisplay />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 触发设置 -->
|
||||
<div class="card bg-base-200 shadow-xl mt-4">
|
||||
<div class="card bg-base-200 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
<Settings class="w-5 h-5" />
|
||||
|
@ -21,29 +28,24 @@
|
|||
<TriggerSettings />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 通道配置 -->
|
||||
<div class="card bg-base-200 shadow-xl mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title">
|
||||
<Layers class="w-5 h-5" />
|
||||
通道配置
|
||||
</h2>
|
||||
<ChannelConfig />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Zap, Settings, Layers } from "lucide-vue-next";
|
||||
import { useEquipments } from "@/stores/equipments";
|
||||
import {
|
||||
LogicalWaveFormDisplay,
|
||||
import {
|
||||
LogicalWaveFormDisplay,
|
||||
generateTestLogicData,
|
||||
TriggerSettings,
|
||||
ChannelConfig
|
||||
} from "@/components/LogicAnalyzer";
|
||||
import { useProvideLogicAnalyzer } from "@/components/LogicAnalyzer";
|
||||
|
||||
const analyzer = useProvideLogicAnalyzer();
|
||||
|
||||
function handleDeleteData() {
|
||||
analyzer.logicData.value = undefined;
|
||||
}
|
||||
|
||||
// 使用全局设备配置
|
||||
const equipments = useEquipments();
|
||||
|
|
Loading…
Reference in New Issue