fix: remote update failed and template not found

This commit is contained in:
2025-05-15 20:23:48 +08:00
parent 00ce79fa7b
commit 1eded97c76
11 changed files with 394 additions and 296 deletions

View File

@@ -5,10 +5,13 @@
<input id="component-drawer" type="checkbox" class="drawer-toggle" v-model="showComponentsMenu" />
<div class="drawer-side">
<label for="component-drawer" aria-label="close sidebar" class="drawer-overlay !bg-opacity-50"></label>
<div class="menu p-0 w-[460px] min-h-full bg-base-100 shadow-xl flex flex-col"> <!-- 菜单头部 -->
<div class="menu p-0 w-[460px] min-h-full bg-base-100 shadow-xl flex flex-col">
<!-- 菜单头部 -->
<div class="p-6 border-b border-base-300 flex justify-between items-center">
<h3 class="text-xl font-bold text-primary flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="text-primary">
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 8v8"></path>
<path d="M8 12h8"></path>
@@ -16,55 +19,53 @@
添加元器件
</h3>
<label for="component-drawer" class="btn btn-ghost btn-sm btn-circle" @click="closeMenu">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</label>
</div>
<!-- 导航栏 -->
<div class="tabs tabs-boxed bg-base-200 mx-6 mt-4 rounded-box">
<a class="tab" :class="{ 'tab-active': activeTab === 'components' }" @click="activeTab = 'components'">元器件</a>
<a class="tab" :class="{ 'tab-active': activeTab === 'components' }"
@click="activeTab = 'components'">元器件</a>
<a class="tab" :class="{ 'tab-active': activeTab === 'templates' }" @click="activeTab = 'templates'">模板</a>
<a class="tab" :class="{ 'tab-active': activeTab === 'virtual' }" @click="activeTab = 'virtual'">虚拟外设</a>
</div>
<!-- 搜索框 -->
<div class="px-6 py-4 border-b border-base-300">
<div class="join w-full">
<div class="join-item flex-1 relative">
<input
type="text"
placeholder="搜索..."
class="input input-bordered input-sm w-full pl-10"
v-model="searchQuery"
@keyup.enter="searchComponents"
/>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute left-3 top-1/2 -translate-y-1/2 text-base-content opacity-60">
<input type="text" placeholder="搜索..." class="input input-bordered input-sm w-full pl-10"
v-model="searchQuery" @keyup.enter="searchComponents" />
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="absolute left-3 top-1/2 -translate-y-1/2 text-base-content opacity-60">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
</div>
<button class="btn btn-sm join-item" @click="searchComponents">搜索</button>
<button class="btn btn-sm join-item" @click="searchComponents">
搜索
</button>
</div>
</div>
<!-- 元器件列表 (组件选项卡) -->
<div v-if="activeTab === 'components'" class="px-6 py-4 overflow-auto flex-1">
<div v-if="filteredComponents.length > 0" class="grid grid-cols-2 gap-4">
<div v-for="(component, index) in filteredComponents" :key="index"
class="card bg-base-200 hover:bg-base-300 transition-all duration-300 hover:shadow-md cursor-pointer"
@click="addComponent(component)">
class="card bg-base-200 hover:bg-base-300 transition-all duration-300 hover:shadow-md cursor-pointer"
@click="addComponent(component)">
<div class="card-body p-3 items-center text-center">
<div class="bg-base-100 rounded-lg w-full h-[90px] flex items-center justify-center overflow-hidden p-2">
<div
class="bg-base-100 rounded-lg w-full h-[90px] flex items-center justify-center overflow-hidden p-2">
<!-- 直接使用组件作为预览 -->
<component
v-if="componentModules[component.type]"
:is="componentModules[component.type].default"
class="component-preview"
:size="getPreviewSize(component.type)"
/>
<component v-if="componentModules[component.type]" :is="componentModules[component.type].default"
class="component-preview" :size="getPreviewSize(component.type)" />
<!-- 加载中状态 -->
<span v-else class="text-xs text-gray-400">加载中...</span>
</div>
@@ -75,7 +76,9 @@
</div>
<!-- 无搜索结果 -->
<div v-else class="py-16 text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="mx-auto text-base-300 mb-3">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"
class="mx-auto text-base-300 mb-3">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
@@ -86,25 +89,31 @@
</button>
</div>
</div>
<!-- 模板列表 (模板选项卡) -->
<div v-if="activeTab === 'templates'" class="px-6 py-4 overflow-auto flex-1">
<div v-if="filteredTemplates.length > 0" class="grid grid-cols-2 gap-4">
<div v-for="(template, index) in filteredTemplates" :key="index"
class="card bg-base-200 hover:bg-base-300 transition-all duration-300 hover:shadow-md cursor-pointer"
@click="addTemplate(template)">
class="card bg-base-200 hover:bg-base-300 transition-all duration-300 hover:shadow-md cursor-pointer"
@click="addTemplate(template)">
<div class="card-body p-3 items-center text-center">
<div class="bg-base-100 rounded-lg w-full h-[90px] flex items-center justify-center overflow-hidden p-2">
<img :src="template.thumbnailUrl || '/placeholder-template.png'" alt="Template thumbnail" class="max-h-full max-w-full object-contain" />
<div
class="bg-base-100 rounded-lg w-full h-[90px] flex items-center justify-center overflow-hidden p-2">
<img :src="template.thumbnailUrl || '/placeholder-template.png'
" alt="Template thumbnail" class="max-h-full max-w-full object-contain" />
</div>
<h3 class="card-title text-sm mt-2">{{ template.name }}</h3>
<p class="text-xs opacity-70">{{ template.description || '模板' }}</p>
<p class="text-xs opacity-70">
{{ template.description || "模板" }}
</p>
</div>
</div>
</div>
<!-- 无搜索结果 -->
<div v-else class="py-16 text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="mx-auto text-base-300 mb-3">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"
class="mx-auto text-base-300 mb-3">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
@@ -115,21 +124,18 @@
</button>
</div>
</div>
<!-- 虚拟外设列表 (虚拟外设选项卡) -->
<!-- 虚拟外设列表 (虚拟外设选项卡) -->
<div v-if="activeTab === 'virtual'" class="px-6 py-4 overflow-auto flex-1">
<div v-if="filteredVirtualDevices.length > 0" class="grid grid-cols-2 gap-4">
<div v-for="(device, index) in filteredVirtualDevices" :key="index"
class="card bg-base-200 hover:bg-base-300 transition-all duration-300 hover:shadow-md cursor-pointer"
@click="addComponent(device)">
class="card bg-base-200 hover:bg-base-300 transition-all duration-300 hover:shadow-md cursor-pointer"
@click="addComponent(device)">
<div class="card-body p-3 items-center text-center">
<div class="bg-base-100 rounded-lg w-full h-[90px] flex items-center justify-center overflow-hidden p-2">
<div
class="bg-base-100 rounded-lg w-full h-[90px] flex items-center justify-center overflow-hidden p-2">
<!-- 直接使用组件作为预览 -->
<component
v-if="componentModules[device.type]"
:is="componentModules[device.type].default"
class="component-preview"
:size="getPreviewSize(device.type)"
/>
<component v-if="componentModules[device.type]" :is="componentModules[device.type].default"
class="component-preview" :size="getPreviewSize(device.type)" />
<!-- 加载中状态 -->
<span v-else class="text-xs text-gray-400">加载中...</span>
</div>
@@ -140,7 +146,9 @@
</div>
<!-- 无搜索结果 -->
<div v-else class="py-16 text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="mx-auto text-base-300 mb-3">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"
class="mx-auto text-base-300 mb-3">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
@@ -151,11 +159,12 @@
</button>
</div>
</div>
<!-- 底部操作区 -->
<div class="p-4 border-t border-base-300 bg-base-200 flex justify-between">
<label for="component-drawer" class="btn btn-sm btn-ghost" @click="closeMenu">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1">
<path d="M19 12H5M12 19l-7-7 7-7"></path>
</svg>
返回
@@ -171,7 +180,8 @@
</template>
<script setup lang="ts">
import { ref, computed, shallowRef, onMounted } from 'vue';
import { ref, computed, shallowRef, onMounted } from "vue";
import motherboardSvg from "../components/equipments/svg/motherboard.svg";
// Props 定义
interface Props {
@@ -181,51 +191,54 @@ interface Props {
const props = defineProps<Props>();
// 定义组件发出的事件
const emit = defineEmits(['close', 'add-component', 'add-template', 'update:open']);
const emit = defineEmits([
"close",
"add-component",
"add-template",
"update:open",
]);
// 当前激活的选项卡
const activeTab = ref('components');
const activeTab = ref("components");
// --- 搜索功能 ---
const searchQuery = ref('');
const searchQuery = ref("");
// --- 可用元器件列表 ---
const availableComponents = [
{ type: 'MechanicalButton', name: '机械按钮' },
{ type: 'Switch', name: '开关' },
{ type: 'Pin', name: '引脚' },
{ type: 'SMT_LED', name: '贴片LED' },
{ type: 'SevenSegmentDisplay', name: '数码管' },
{ type: 'HDMI', name: 'HDMI接口' },
{ type: 'DDR', name: 'DDR内存' },
{ type: 'ETH', name: '以太网接口' },
{ type: 'SD', name: 'SD卡插槽' },
{ type: 'SFP', name: 'SFP光纤模块' },
{ type: 'SMA', name: 'SMA连接器' },
{ type: 'MotherBoard', name: '主板' },
{ type: 'PG2L100H_FBG676', name: 'PG2L100H FBG676芯片' }
{ type: "MechanicalButton", name: "机械按钮" },
{ type: "Switch", name: "开关" },
{ type: "Pin", name: "引脚" },
{ type: "SMT_LED", name: "贴片LED" },
{ type: "SevenSegmentDisplay", name: "数码管" },
{ type: "HDMI", name: "HDMI接口" },
{ type: "DDR", name: "DDR内存" },
{ type: "ETH", name: "以太网接口" },
{ type: "SD", name: "SD卡插槽" },
{ type: "SFP", name: "SFP光纤模块" },
{ type: "SMA", name: "SMA连接器" },
{ type: "MotherBoard", name: "主板" },
{ type: "PG2L100H_FBG676", name: "PG2L100H FBG676芯片" },
];
// --- 可用虚拟外设列表 ---
const availableVirtualDevices = [
{ type: 'DDS', name: '信号发生器' }
];
const availableVirtualDevices = [{ type: "DDS", name: "信号发生器" }];
// --- 可用模板列表 ---
const availableTemplates = ref([
{
name: 'PG2L100H 基础开发板',
id: 'PG2L100H_Pango100pro',
description: '包含主板和两个LED的基本设置',
path: '/src/components/equipments/templates/PG2L100H_Pango100pro.json',
thumbnailUrl: '/src/components/equipments/svg/motherboard.svg'
}
{
name: "PG2L100H 基础开发板",
id: "PG2L100H_Pango100pro",
description: "包含主板和两个LED的基本设置",
path: "/public/EquipmentTemplates/PG2L100H_Pango100pro.json",
thumbnailUrl: motherboardSvg,
},
]);
// 显示/隐藏组件菜单
const showComponentsMenu = computed({
get: () => props.open,
set: (value) => emit('update:open', value)
set: (value) => emit("update:open", value),
});
// 组件模块缓存
@@ -237,13 +250,13 @@ async function loadComponentModule(type: string) {
try {
// 假设组件都在 src/components/equipments/ 目录下,且文件名与 type 相同
const module = await import(`../components/equipments/${type}.vue`);
// 将模块添加到缓存中
componentModules.value = {
...componentModules.value,
[type]: module
[type]: module,
};
console.log(`Loaded module for ${type}:`, module);
} catch (error) {
console.error(`Failed to load component module ${type}:`, error);
@@ -263,7 +276,7 @@ async function preloadComponentModules() {
console.error(`Failed to preload component ${component.type}:`, error);
}
}
// 加载虚拟外设组件
for (const device of availableVirtualDevices) {
try {
@@ -278,21 +291,21 @@ async function preloadComponentModules() {
function getPreviewSize(componentType: string): number {
// 根据组件类型返回适当的预览尺寸
const previewSizes: Record<string, number> = {
'MechanicalButton': 0.4, // 按钮较大,需要更小尺寸
'Switch': 0.35, // 开关较大,需要更小尺寸
'Pin': 0.8, // 引脚较小,可以大一些
'SMT_LED': 0.7, // LED可以保持适中
'SevenSegmentDisplay': 0.4, // 数码管较大,需要较小尺寸
'HDMI': 0.5, // HDMI接口较大
'DDR': 0.5, // DDR内存较大
'ETH': 0.5, // 以太网接口较大
'SD': 0.6, // SD卡插槽适中
'SFP': 0.4, // SFP光纤模块较大
'SMA': 0.7, // SMA连接器可以适中
'MotherBoard': 0.13, // 主板最大,需要最小尺寸
'DDS': 0.3 // 信号发生器较大,需要较小尺寸
MechanicalButton: 0.4, // 按钮较大,需要更小尺寸
Switch: 0.35, // 开关较大,需要更小尺寸
Pin: 0.8, // 引脚较小,可以大一些
SMT_LED: 0.7, // LED可以保持适中
SevenSegmentDisplay: 0.4, // 数码管较大,需要较小尺寸
HDMI: 0.5, // HDMI接口较大
DDR: 0.5, // DDR内存较大
ETH: 0.5, // 以太网接口较大
SD: 0.6, // SD卡插槽适中
SFP: 0.4, // SFP光纤模块较大
SMA: 0.7, // SMA连接器可以适中
MotherBoard: 0.13, // 主板最大,需要最小尺寸
DDS: 0.3, // 信号发生器较大,需要较小尺寸
};
// 返回对应尺寸如果没有特定配置则返回默认值0.5
return previewSizes[componentType] || 0.5;
}
@@ -306,7 +319,7 @@ function searchComponents() {
// 关闭菜单
function closeMenu() {
showComponentsMenu.value = false;
emit('close');
emit("close");
}
// 添加新元器件
@@ -316,25 +329,28 @@ async function addComponent(componentTemplate: { type: string; name: string }) {
let defaultProps: Record<string, any> = {};
// 尝试直接调用组件导出的getDefaultProps方法
if(moduleRef){
if (typeof moduleRef.getDefaultProps === 'function') {
if (moduleRef) {
if (typeof moduleRef.getDefaultProps === "function") {
defaultProps = moduleRef.getDefaultProps();
console.log(`Got default props from ${componentTemplate.type}:`, defaultProps);
console.log(
`Got default props from ${componentTemplate.type}:`,
defaultProps,
);
} else {
// 回退到配置文件
console.log(`No getDefaultProps found for ${componentTemplate.type}`);
}
} else{
} else {
console.log(`Failed to load module for ${componentTemplate.type}`);
}
// 发送添加组件事件给父组件
emit('add-component', {
emit("add-component", {
type: componentTemplate.type,
name: componentTemplate.name,
props: defaultProps
props: defaultProps,
});
// 关闭菜单
closeMenu();
}
@@ -347,58 +363,62 @@ async function addTemplate(template: any) {
if (!response.ok) {
throw new Error(`Failed to load template: ${response.statusText}`);
}
const templateData = await response.json();
console.log('加载模板:', templateData);
console.log("加载模板:", templateData);
// 发出事件,将模板数据传递给父组件
emit('add-template', {
emit("add-template", {
id: template.id,
name: template.name,
template: templateData
template: templateData,
});
// 关闭菜单
closeMenu();
} catch (error) {
console.error('加载模板出错:', error);
alert('无法加载模板文件,请检查控制台错误信息');
console.error("加载模板出错:", error);
alert("无法加载模板文件,请检查控制台错误信息");
}
}
// 过滤后的元器件列表 (用于菜单)
const filteredComponents = computed(() => {
if (!searchQuery.value || activeTab.value !== 'components') {
if (!searchQuery.value || activeTab.value !== "components") {
return availableComponents;
}
const query = searchQuery.value.toLowerCase();
return availableComponents.filter(component =>
component.name.toLowerCase().includes(query) ||
component.type.toLowerCase().includes(query)
return availableComponents.filter(
(component) =>
component.name.toLowerCase().includes(query) ||
component.type.toLowerCase().includes(query),
);
});
// 过滤后的模板列表 (用于菜单)
const filteredTemplates = computed(() => {
if (!searchQuery.value || activeTab.value !== 'templates') {
if (!searchQuery.value || activeTab.value !== "templates") {
return availableTemplates.value;
}
const query = searchQuery.value.toLowerCase();
return availableTemplates.value.filter(template =>
template.name.toLowerCase().includes(query) ||
(template.description && template.description.toLowerCase().includes(query))
return availableTemplates.value.filter(
(template) =>
template.name.toLowerCase().includes(query) ||
(template.description &&
template.description.toLowerCase().includes(query)),
);
});
// 过滤后的虚拟外设列表 (用于菜单)
const filteredVirtualDevices = computed(() => {
if (!searchQuery.value || activeTab.value !== 'virtual') {
if (!searchQuery.value || activeTab.value !== "virtual") {
return availableVirtualDevices;
}
const query = searchQuery.value.toLowerCase();
return availableVirtualDevices.filter(device =>
device.name.toLowerCase().includes(query) ||
device.type.toLowerCase().includes(query)
return availableVirtualDevices.filter(
(device) =>
device.name.toLowerCase().includes(query) ||
device.type.toLowerCase().includes(query),
);
});
@@ -427,6 +447,7 @@ onMounted(() => {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);