feat: 后端添加获取空闲实验板,继续修改前端界面使其更加合理
This commit is contained in:
@@ -649,6 +649,54 @@ export class DataClient {
|
||||
return Promise.resolve<boolean>(null as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个空闲的实验板(普通用户权限)
|
||||
*/
|
||||
getAvailableBoard(): Promise<Board> {
|
||||
let url_ = this.baseUrl + "/api/Data/GetAvailableBoard";
|
||||
url_ = url_.replace(/[?&]$/, "");
|
||||
|
||||
let options_: RequestInit = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
};
|
||||
|
||||
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||
return this.processGetAvailableBoard(_response);
|
||||
});
|
||||
}
|
||||
|
||||
protected processGetAvailableBoard(response: Response): Promise<Board> {
|
||||
const status = response.status;
|
||||
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||
if (status === 200) {
|
||||
return response.text().then((_responseText) => {
|
||||
let result200: any = null;
|
||||
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||
result200 = Board.fromJS(resultData200);
|
||||
return result200;
|
||||
});
|
||||
} else if (status === 404) {
|
||||
return response.text().then((_responseText) => {
|
||||
let result404: any = null;
|
||||
let resultData404 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
|
||||
result404 = ProblemDetails.fromJS(resultData404);
|
||||
return throwException("A server side error occurred.", status, _responseText, _headers, result404);
|
||||
});
|
||||
} else if (status === 500) {
|
||||
return response.text().then((_responseText) => {
|
||||
return throwException("A server side error occurred.", status, _responseText, _headers);
|
||||
});
|
||||
} else if (status !== 200 && status !== 204) {
|
||||
return response.text().then((_responseText) => {
|
||||
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||
});
|
||||
}
|
||||
return Promise.resolve<Board>(null as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增板子(管理员权限)
|
||||
* @param name (optional)
|
||||
@@ -2721,13 +2769,13 @@ export class Board implements IBoard {
|
||||
id!: string;
|
||||
/** FPGA 板子的名称 */
|
||||
boardName!: string;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的IP地址 */
|
||||
ipAddr!: string;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的通信端口 */
|
||||
port!: number;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的当前状态 */
|
||||
status!: BoardStatus;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的固件版本号 */
|
||||
firmVersion!: string;
|
||||
|
||||
constructor(data?: IBoard) {
|
||||
@@ -2775,17 +2823,17 @@ export interface IBoard {
|
||||
id: string;
|
||||
/** FPGA 板子的名称 */
|
||||
boardName: string;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的IP地址 */
|
||||
ipAddr: string;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的通信端口 */
|
||||
port: number;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的当前状态 */
|
||||
status: BoardStatus;
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子的固件版本号 */
|
||||
firmVersion: string;
|
||||
}
|
||||
|
||||
/** [TODO:description] */
|
||||
/** FPGA 板子状态枚举 */
|
||||
export enum BoardStatus {
|
||||
Busy = 0,
|
||||
Available = 1,
|
||||
|
||||
@@ -34,55 +34,9 @@
|
||||
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>
|
||||
<BookOpen class="h-5 w-5 mr-2" />
|
||||
进入工程界面
|
||||
</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"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
<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>
|
||||
</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"
|
||||
@@ -101,6 +55,7 @@
|
||||
<script lang="ts" setup>
|
||||
import "@/router";
|
||||
import TutorialCarousel from "@/components/TutorialCarousel.vue";
|
||||
import { BookOpen } from "lucide-vue-next";
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
:min-size="15"
|
||||
class="w-full overflow-hidden"
|
||||
>
|
||||
<FunctionBar class="mx-4 mt-1" />
|
||||
<BottomBar class="mx-4 mt-1" />
|
||||
</SplitterPanel>
|
||||
</SplitterGroup>
|
||||
</div>
|
||||
@@ -89,18 +89,21 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from "reka-ui";
|
||||
import DiagramCanvas from "@/components/LabCanvas/DiagramCanvas.vue";
|
||||
import ComponentSelector from "@/components/LabCanvas/ComponentSelector.vue";
|
||||
import PropertyPanel from "@/components/PropertyPanel.vue";
|
||||
import MarkdownRenderer from "@/components/MarkdownRenderer.vue";
|
||||
import FunctionBar from "@/views/Project/BottomBar.vue";
|
||||
import BottomBar from "@/views/Project/BottomBar.vue";
|
||||
import { useProvideComponentManager } from "@/components/LabCanvas";
|
||||
import type { DiagramData } from "@/components/LabCanvas";
|
||||
import { useAlertStore } from "@/components/Alert";
|
||||
import { AuthManager } from "@/utils/AuthManager";
|
||||
|
||||
import { useRoute } from "vue-router";
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
// 提供组件管理服务
|
||||
const componentManager = useProvideComponentManager();
|
||||
@@ -207,6 +210,20 @@ function updateComponentDirectProp(
|
||||
|
||||
// --- 生命周期钩子 ---
|
||||
onMounted(async () => {
|
||||
// 验证用户身份
|
||||
try {
|
||||
const isAuthenticated = await AuthManager.isAuthenticated();
|
||||
if (!isAuthenticated) {
|
||||
// 验证失败,跳转到登录页面
|
||||
router.push('/login');
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('身份验证失败:', error);
|
||||
router.push('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有例程参数,如果有则自动打开文档面板
|
||||
if (route.query.tutorial) {
|
||||
showDocPanel.value = true;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="min-h-screen bg-base-100 flex flex-col mx-auto p-6 space-y-6 container"
|
||||
class="min-h-screen bg-base-100 flex flex-col p-6 space-y-6 "
|
||||
>
|
||||
<!-- 设置 -->
|
||||
<div class="card bg-base-200 shadow-xl">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-base-100">
|
||||
<div class="container mx-auto p-6 space-y-6">
|
||||
<div class="p-6">
|
||||
<!-- 控制面板 -->
|
||||
<div class="card bg-base-200 shadow-xl">
|
||||
<div class="card-body">
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { useBoardManager } from './BoardManager';
|
||||
import { useBoardManager } from '../../utils/BoardManager';
|
||||
|
||||
// Props 和 Emits
|
||||
interface Props {
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
import { FlexRender } from "@tanstack/vue-table";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { RefreshCw, Edit, Plus, Trash2 } from "lucide-vue-next";
|
||||
import { useProvideBoardManager } from "./BoardManager";
|
||||
import { useProvideBoardManager } from "../../utils/BoardManager";
|
||||
import { useProvideBoardTableManager } from "./BoardTableManager";
|
||||
import AddBoardDialog from "./AddBoardDialog.vue";
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
} from "@tanstack/vue-table";
|
||||
import { h, ref, computed, version } from "vue";
|
||||
import { createInjectionState } from "@vueuse/core";
|
||||
import type { BoardData } from "./BoardManager";
|
||||
import { useBoardManager } from "./BoardManager";
|
||||
import type { BoardData } from "../../utils/BoardManager";
|
||||
import { useBoardManager } from "../../utils/BoardManager";
|
||||
import { useDialogStore } from "@/stores/dialog";
|
||||
|
||||
const [useProvideBoardTableManager, useBoardTableManager] =
|
||||
|
||||
Reference in New Issue
Block a user