feat: add remote update function
This commit is contained in:
@@ -1,11 +1,20 @@
|
||||
<template>
|
||||
<div class="bg-base-200 min-h-screen p-6">
|
||||
<h1 class="text-3xl font-bold mb-6">FPGA 设备管理</h1>
|
||||
|
||||
<div class="flex flex-row align-middle">
|
||||
<h1 class="text-3xl font-bold mb-6">FPGA 设备管理</h1>
|
||||
<button class="btn btn-ghost self-end" @click="
|
||||
() => {
|
||||
isEditMode = !isEditMode;
|
||||
}
|
||||
">
|
||||
编辑
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title mb-4">IP 地址列表</h2>
|
||||
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<!-- 表头 -->
|
||||
@@ -14,89 +23,86 @@
|
||||
<th>IP 地址</th>
|
||||
<th>版本号</th>
|
||||
<th>默认启动位流</th>
|
||||
<th>黄金位流</th>
|
||||
<th>应用位流1</th>
|
||||
<th>应用位流2</th>
|
||||
<th>应用位流3</th>
|
||||
<th class="w-80">黄金位流</th>
|
||||
<th class="w-80">应用位流1</th>
|
||||
<th class="w-80">应用位流2</th>
|
||||
<th class="w-80">应用位流3</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
||||
<!-- 表格内容 -->
|
||||
<tbody>
|
||||
<tr class="hover">
|
||||
<td class="font-medium">192.168.1.100</td>
|
||||
<td class="font-medium">
|
||||
<input v-if="isEditMode" type="text" placeholder="Type here" class="input" />
|
||||
<span v-else>{{ devAddr }}</span>
|
||||
</td>
|
||||
<td>v1.2.3</td>
|
||||
<td>
|
||||
<select class="select select-bordered w-full max-w-xs">
|
||||
<select class="select select-bordered w-full max-w-xs" v-model="selectBitstream">
|
||||
<option selected>黄金位流</option>
|
||||
<option>应用位流1</option>
|
||||
<option>应用位流2</option>
|
||||
<option>应用位流3</option>
|
||||
</select>
|
||||
</td>
|
||||
<!-- 黄金位流上传区 -->
|
||||
<!-- 黄金位流上传区 -->
|
||||
<td>
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<label class="btn btn-outline btn-primary">
|
||||
<svg 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="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<input type="file" class="hidden" @change="handleFileChange($event, goldBitstreamFile)" />
|
||||
</label>
|
||||
<span class="text-xs text-primary truncate max-w-32" v-if="goldBitstreamFile">{{ goldBitstreamFile }}</span>
|
||||
<input type="file" class="file-input file-input-primary"
|
||||
@change="handleFileChange($event, goldBitstreamFile)" />
|
||||
</div>
|
||||
</td>
|
||||
<!-- 应用位流1上传区 -->
|
||||
<!-- 应用位流1上传区 -->
|
||||
<td>
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<label class="btn btn-outline btn-secondary">
|
||||
<svg 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="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<input type="file" class="hidden" @change="handleFileChange($event, appBitstream1File)" />
|
||||
</label>
|
||||
<span class="text-xs text-secondary truncate max-w-32" v-if="appBitstream1File">{{ appBitstream1File }}</span>
|
||||
<input type="file" class="file-input file-input-secondary"
|
||||
@change="handleFileChange($event, appBitstream1File)" />
|
||||
</div>
|
||||
</td>
|
||||
<!-- 应用位流2上传区 -->
|
||||
<!-- 应用位流2上传区 -->
|
||||
<td>
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<label class="btn btn-outline btn-accent">
|
||||
<svg 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="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<input type="file" class="hidden" @change="handleFileChange($event, appBitstream2File)" />
|
||||
</label>
|
||||
<span class="text-xs text-accent truncate max-w-32" v-if="appBitstream2File">{{ appBitstream2File }}</span>
|
||||
<input type="file" class="file-input file-input-accent"
|
||||
@change="handleFileChange($event, appBitstream2File)" />
|
||||
</div>
|
||||
</td>
|
||||
<!-- 应用位流3上传区 -->
|
||||
<!-- 应用位流3上传区 -->
|
||||
<td>
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<label class="btn btn-outline btn-info">
|
||||
<svg 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="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<input type="file" class="hidden" @change="handleFileChange($event, appBitstream3File)" />
|
||||
</label>
|
||||
<span class="text-xs text-info truncate max-w-32" v-if="appBitstream3File">{{ appBitstream3File }}</span>
|
||||
<input type="file" class="file-input file-input-info"
|
||||
@change="handleFileChange($event, appBitstream3File)" />
|
||||
</div>
|
||||
</td>
|
||||
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<td class="flex gap-2">
|
||||
<button class="btn btn-sm btn-warning">固化</button>
|
||||
<button class="btn btn-sm btn-success">切换并热启动</button>
|
||||
<button class="btn grow btn-warning" @click="
|
||||
uploadAndDownloadBitstreams(
|
||||
devAddr,
|
||||
goldBitstreamFile,
|
||||
appBitstream1File,
|
||||
appBitstream2File,
|
||||
appBitstream3File,
|
||||
)
|
||||
">
|
||||
固化
|
||||
</button>
|
||||
<button class="btn grow btn-success" @click="
|
||||
hotresetBitstream(devAddr, getSelectedBitstreamNum())
|
||||
">
|
||||
切换并热启动
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-6 bg-base-300 p-4 rounded-lg">
|
||||
<p class="text-sm opacity-80">
|
||||
<span class="font-semibold text-warning">提示:</span>
|
||||
<span class="font-semibold text-error">提示:</span>
|
||||
请谨慎操作FPGA固化和热启动功能,确保上传的位流文件无误,以避免设备损坏。
|
||||
</p>
|
||||
</div>
|
||||
@@ -106,21 +112,122 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
import { ref } from "vue";
|
||||
import { RemoteUpdaterClient } from "@/APIClient";
|
||||
import { useDialogStore } from "@/stores/dialog";
|
||||
import { Common } from "@/Common";
|
||||
|
||||
const dialog = useDialogStore();
|
||||
|
||||
// 编辑状态
|
||||
const isEditMode = ref(false);
|
||||
|
||||
// 选择热切换的比特流
|
||||
const selectBitstream = ref("黄金位流");
|
||||
|
||||
// 存储上传文件的信息
|
||||
const goldBitstreamFile = ref<string>('');
|
||||
const appBitstream1File = ref<string>('');
|
||||
const appBitstream2File = ref<string>('');
|
||||
const appBitstream3File = ref<string>('');
|
||||
const goldBitstreamFile = ref<File>();
|
||||
const appBitstream1File = ref<File>();
|
||||
const appBitstream2File = ref<File>();
|
||||
const appBitstream3File = ref<File>();
|
||||
|
||||
// 远程升级相关参数
|
||||
const devAddr = ref("192.168.1.100");
|
||||
const devPort = 1234;
|
||||
const remoteUpdater = new RemoteUpdaterClient();
|
||||
|
||||
// 处理文件上传
|
||||
function handleFileChange(event: Event, fileRef: any) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const file = target.files?.[0];
|
||||
|
||||
if (file) {
|
||||
fileRef.value = file.name;
|
||||
const file = target.files?.[0]; // 获取选中的第一个文件
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isUndefined(fileRef)) {
|
||||
fileRef.value = file;
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedBitstreamNum(): number {
|
||||
if (selectBitstream.value == "黄金位流") {
|
||||
return 0;
|
||||
} else if (selectBitstream.value == "应用位流1") {
|
||||
return 1;
|
||||
} else if (selectBitstream.value == "应用位流2") {
|
||||
return 2;
|
||||
} else if (selectBitstream.value == "应用位流3") {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
async function uploadAndDownloadBitstreams(
|
||||
devAddr: string,
|
||||
goldBitstream?: File,
|
||||
appBitstream1?: File,
|
||||
appBitstream2?: File,
|
||||
appBitstream3?: File,
|
||||
) {
|
||||
let cnt = 0;
|
||||
if (isUndefined(goldBitstream)) cnt++;
|
||||
if (isUndefined(appBitstream1)) cnt++;
|
||||
if (isUndefined(appBitstream2)) cnt++;
|
||||
if (isUndefined(appBitstream3)) cnt++;
|
||||
if ((cnt = 0)) {
|
||||
dialog.error("未选择比特流");
|
||||
}
|
||||
|
||||
try {
|
||||
{
|
||||
const ret = await remoteUpdater.uploadBitstreams(
|
||||
devAddr,
|
||||
Common.toFileParameterOrNull(goldBitstream),
|
||||
Common.toFileParameterOrNull(appBitstream1),
|
||||
Common.toFileParameterOrNull(appBitstream2),
|
||||
Common.toFileParameterOrNull(appBitstream3),
|
||||
);
|
||||
if (ret) {
|
||||
dialog.warn("上传比特流出错");
|
||||
} else {
|
||||
dialog.info("上传比特流成功");
|
||||
}
|
||||
}
|
||||
{
|
||||
const ret = await remoteUpdater.downloadMultiBitstreams(
|
||||
devAddr,
|
||||
devPort,
|
||||
getSelectedBitstreamNum(),
|
||||
);
|
||||
if (ret != cnt) {
|
||||
dialog.warn("固化比特流出错");
|
||||
} else {
|
||||
dialog.info("固化比特流成功");
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
dialog.error("比特流上传错误");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async function hotresetBitstream(devAddr: string, bitstreamNum: number) {
|
||||
try {
|
||||
const ret = await remoteUpdater.hotResetBitstream(
|
||||
devAddr,
|
||||
devPort,
|
||||
bitstreamNum,
|
||||
);
|
||||
if (ret) {
|
||||
dialog.info("切换比特流成功");
|
||||
} else {
|
||||
dialog.error("切换比特流失败");
|
||||
}
|
||||
} catch (e) {
|
||||
dialog.error("切换比特流失败");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,77 +1,88 @@
|
||||
<template> <div class="bg-base-200 min-h-screen">
|
||||
<template>
|
||||
<div class="bg-base-200 min-h-screen">
|
||||
<main class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content flex-col lg:flex-row-reverse gap-8 lg:gap-12 py-10 px-4">
|
||||
<!-- 图片容器 -->
|
||||
<div class="image-container relative w-full max-w-sm hover:scale-105 hover:-rotate-1 transition-transform duration-500 ease-in-out">
|
||||
<img src="https://placehold.co/600x400" class="w-full rounded-2xl shadow-2xl border-4 border-base-300 transition-shadow duration-300 hover:shadow-primary" />
|
||||
<div
|
||||
class="image-container relative w-full max-w-sm hover:scale-105 hover:-rotate-1 transition-transform duration-500 ease-in-out">
|
||||
<img src="https://placehold.co/600x400"
|
||||
class="w-full rounded-2xl shadow-2xl border-4 border-base-300 transition-shadow duration-300 hover:shadow-primary" />
|
||||
<!-- 这里使用relative定位,限制覆盖层只在图片容器内 -->
|
||||
<div class="absolute inset-0 bg-primary opacity-10 rounded-2xl pointer-events-none"></div>
|
||||
</div>
|
||||
<!-- 内容容器 -->
|
||||
<!-- 内容容器 -->
|
||||
<div class="content-container max-w-md lg:max-w-2xl transform transition-all duration-500 ease-in-out">
|
||||
<h1 class="text-4xl md:text-5xl font-bold mb-3 relative group">
|
||||
<span class="relative z-10 bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent">
|
||||
Welcome to
|
||||
Welcome to
|
||||
</span>
|
||||
<span class="text-base-content">FPGA Web Lab!</span>
|
||||
<span class="absolute bottom-0 left-0 w-0 h-1 bg-primary transition-all duration-500 ease-in-out group-hover:w-3/4"></span>
|
||||
<span
|
||||
class="absolute bottom-0 left-0 w-0 h-1 bg-primary transition-all duration-500 ease-in-out group-hover:w-3/4"></span>
|
||||
</h1>
|
||||
|
||||
|
||||
<p class="py-6 text-lg opacity-80 leading-relaxed">
|
||||
Prototype and simulate electronic circuits in your browser with our modern, intuitive interface. Create, test, and share your FPGA designs seamlessly.
|
||||
Prototype and simulate electronic circuits in your browser with our
|
||||
modern, intuitive interface. Create, test, and share your FPGA
|
||||
designs seamlessly.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-4 actions-container">
|
||||
<router-link to="/project" class="btn btn-primary text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<div class="flex flex-wrap gap-4 actions-container">
|
||||
<router-link to="/project"
|
||||
class="btn btn-primary text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2">
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
|
||||
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
|
||||
</svg>
|
||||
进入工程界面
|
||||
</router-link>
|
||||
|
||||
<router-link to="/login" class="btn btn-secondary text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
|
||||
<router-link to="/login"
|
||||
class="btn btn-secondary text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
||||
</svg>
|
||||
登录
|
||||
</router-link>
|
||||
|
||||
<router-link to="/user" class="btn btn-accent text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
|
||||
<router-link to="/user"
|
||||
class="btn btn-accent text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>
|
||||
用户中心
|
||||
</router-link>
|
||||
<router-link to="/test" class="btn btn-info text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<router-link to="/test"
|
||||
class="btn btn-info text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2">
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path>
|
||||
<polyline points="17 21 17 13 7 13 7 21"></polyline>
|
||||
<polyline points="7 3 7 8 15 8"></polyline>
|
||||
</svg>
|
||||
测试功能
|
||||
</router-link>
|
||||
<router-link to="/test/jtag" class="btn btn-warning text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
|
||||
<line x1="8" y1="21" x2="16" y2="21"></line>
|
||||
<line x1="12" y1="17" x2="12" y2="21"></line>
|
||||
</svg>
|
||||
JTAG测试
|
||||
</router-link>
|
||||
|
||||
<router-link to="/admin" class="btn btn-error text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5z"></path>
|
||||
|
||||
<router-link to="/admin"
|
||||
class="btn btn-error text-base-100 shadow-lg transform transition-all duration-300 hover:scale-105 hover:shadow-xl hover:-translate-y-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5z">
|
||||
</path>
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
</svg>
|
||||
管理控制台
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="mt-8 p-4 bg-base-300 rounded-lg shadow-inner opacity-80 transition-all duration-300 hover:opacity-100 hover:shadow-md">
|
||||
<div
|
||||
class="mt-8 p-4 bg-base-300 rounded-lg shadow-inner opacity-80 transition-all duration-300 hover:opacity-100 hover:shadow-md">
|
||||
<p class="text-sm">
|
||||
<span class="font-semibold text-primary">提示:</span> 您可以在工程界面中创建、编辑和测试您的FPGA项目,使用我们简洁直观的界面轻松进行硬件设计。
|
||||
<span class="font-semibold text-primary">提示:</span>
|
||||
您可以在工程界面中创建、编辑和测试您的FPGA项目,使用我们简洁直观的界面轻松进行硬件设计。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user