feat: 更加完善实验板管理面板,前后端分离

This commit is contained in:
2025-07-12 13:37:02 +08:00
parent e0619eb9a3
commit 50ffd491fe
7 changed files with 1092 additions and 577 deletions

View File

@@ -0,0 +1,251 @@
<template>
<dialog class="modal" :class="{ 'modal-open': visible }">
<div class="modal-box w-96 max-w-md">
<h3 class="text-lg font-bold mb-4">新增实验板</h3>
<form @submit.prevent="handleSubmit" class="space-y-4">
<!-- 实验板名称 -->
<div class="form-control">
<label class="label">
<span class="label-text">实验板名称 <span class="text-error">*</span></span>
</label>
<input
v-model="form.name"
type="text"
placeholder="请输入实验板名称"
class="input input-bordered"
:class="{ 'input-error': errors.name }"
required
/>
<label v-if="errors.name" class="label">
<span class="label-text-alt text-error">{{ errors.name }}</span>
</label>
</div>
<!-- IP 地址 -->
<div class="form-control">
<label class="label">
<span class="label-text">IP 地址 <span class="text-error">*</span></span>
</label>
<input
v-model="form.ipAddr"
type="text"
placeholder="例如192.168.1.100"
class="input input-bordered"
:class="{ 'input-error': errors.ipAddr }"
required
/>
<label v-if="errors.ipAddr" class="label">
<span class="label-text-alt text-error">{{ errors.ipAddr }}</span>
</label>
</div>
<!-- 端口号 -->
<div class="form-control">
<label class="label">
<span class="label-text">端口号 <span class="text-error">*</span></span>
</label>
<input
v-model.number="form.port"
type="number"
placeholder="例如1234"
min="1"
max="65535"
class="input input-bordered"
:class="{ 'input-error': errors.port }"
required
/>
<label v-if="errors.port" class="label">
<span class="label-text-alt text-error">{{ errors.port }}</span>
</label>
</div>
<!-- 操作按钮 -->
<div class="modal-action">
<button
type="button"
class="btn btn-ghost"
@click="handleCancel"
:disabled="isSubmitting"
>
取消
</button>
<button
type="submit"
class="btn btn-primary"
:class="{ 'loading': isSubmitting }"
:disabled="isSubmitting"
>
{{ isSubmitting ? '添加中...' : '确认添加' }}
</button>
</div>
</form>
</div>
<!-- 点击背景关闭 -->
<form method="dialog" class="modal-backdrop">
<button type="button" @click="handleCancel">close</button>
</form>
</dialog>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { useBoardManager } from './BoardManager';
// Props 和 Emits
interface Props {
visible: boolean;
}
interface Emits {
(e: 'update:visible', value: boolean): void;
(e: 'success'): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
// 使用 BoardManager
const boardManager = useBoardManager()!;
// 表单数据
const form = reactive({
name: '',
ipAddr: '',
port: 1234
});
// 表单错误
const errors = reactive({
name: '',
ipAddr: '',
port: ''
});
// 提交状态
const isSubmitting = ref(false);
// IP地址验证正则
const IP_REGEX = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
// 验证表单
function validateForm(): boolean {
// 清空之前的错误
errors.name = '';
errors.ipAddr = '';
errors.port = '';
let isValid = true;
// 验证名称
if (!form.name.trim()) {
errors.name = '请输入实验板名称';
isValid = false;
} else if (form.name.trim().length < 2) {
errors.name = '实验板名称至少需要2个字符';
isValid = false;
} else if (form.name.trim().length > 50) {
errors.name = '实验板名称不能超过50个字符';
isValid = false;
}
// 验证IP地址
if (!form.ipAddr.trim()) {
errors.ipAddr = '请输入IP地址';
isValid = false;
} else if (!IP_REGEX.test(form.ipAddr.trim())) {
errors.ipAddr = '请输入有效的IP地址格式';
isValid = false;
}
// 验证端口号
if (!form.port) {
errors.port = '请输入端口号';
isValid = false;
} else if (form.port < 1 || form.port > 65535) {
errors.port = '端口号必须在1-65535之间';
isValid = false;
} else if (!Number.isInteger(form.port)) {
errors.port = '端口号必须是整数';
isValid = false;
}
return isValid;
}
// 重置表单
function resetForm() {
form.name = '';
form.ipAddr = '';
form.port = 1234;
errors.name = '';
errors.ipAddr = '';
errors.port = '';
}
// 处理取消
function handleCancel() {
if (!isSubmitting.value) {
emit('update:visible', false);
resetForm();
}
}
// 处理提交
async function handleSubmit() {
if (!validateForm()) {
return;
}
isSubmitting.value = true;
try {
const success = await boardManager.addBoard(
form.name.trim(),
form.ipAddr.trim(),
form.port
);
if (success) {
emit('success');
resetForm();
}
} catch (error) {
console.error('添加实验板失败:', error);
} finally {
isSubmitting.value = false;
}
}
// 监听对话框显示状态,重置表单
watch(() => props.visible, (newVisible) => {
if (newVisible) {
resetForm();
}
});
</script>
<style scoped lang="postcss">
@import "@/assets/main.css";
.form-control {
@apply w-full;
}
.label-text {
@apply font-medium;
}
.input-error {
@apply border-error;
}
.text-error {
@apply text-red-500;
}
.loading {
@apply opacity-50 cursor-not-allowed;
}
</style>