feat: 更加完善实验板管理面板,前后端分离
This commit is contained in:
251
src/views/User/AddBoardDialog.vue
Normal file
251
src/views/User/AddBoardDialog.vue
Normal 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>
|
||||
Reference in New Issue
Block a user