refactor(前端): 集中管理设计令牌和工具函数

This commit is contained in:
zhang1106
2026-03-10 15:49:02 +08:00
parent 196dc4ae41
commit 7f007f5010
17 changed files with 158 additions and 663 deletions
+60 -142
View File
@@ -2,21 +2,10 @@ import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Modal, Form, Select, Input, Button, message, Space, Spin } from 'antd';
import { SwapOutlined } from '@ant-design/icons';
import axios from 'axios';
import { debounce } from '../utils/common';
const { Option } = Select;
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
@@ -50,7 +39,6 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
[fetchDevices]
);
// Initialize when visible changes from false to true
useEffect(() => {
if (visible && !prevVisibleRef.current) {
form.resetFields();
@@ -101,13 +89,11 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
const values = await form.validateFields();
setLoading(true);
// Logic to ensure Switch is always Source if possible (for Cable Management view consistency)
const sourceDev = devices.find(d => d.deviceId === values.sourceDeviceId);
const targetDev = devices.find(d => d.deviceId === values.targetDeviceId);
let payload = { ...values };
// If Source is NOT Switch AND Target IS Switch, swap them
if (sourceDev && targetDev && sourceDev.type !== 'switch' && targetDev.type === 'switch') {
payload = {
...values,
@@ -148,135 +134,67 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
maskClosable={false}
>
<Form form={form} layout="vertical">
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
{/* Source Side */}
<div style={{ padding: '12px', background: '#f9f9f9', borderRadius: '8px' }}>
<div style={{ marginBottom: 12, fontWeight: 500, color: '#666' }}>源设备 (起点)</div>
<Form.Item
name="sourceDeviceId"
label="设备"
rules={[{ required: true, message: '请选择源设备' }]}
>
<Select
placeholder="输入关键词搜索源设备"
showSearch
filterOption={false}
onSearch={handleDeviceSearch}
onDropdownVisibleChange={open => {
if (open && devices.length === 0) {
fetchDevices();
}
}}
onChange={handleSourceDeviceChange}
loading={fetchingDevices}
disabled={!!sourceDevice}
>
{devices.map(d => (
<Option key={d.deviceId} value={d.deviceId}>
{d.name}
</Option>
))}
</Select>
</Form.Item>
<Form.Item
name="sourcePort"
label="端口"
rules={[{ required: true, message: '请选择源端口' }]}
>
<Select placeholder="选择源端口" showSearch>
{sourcePorts.map(p => (
<Option key={p.portId} value={p.portName}>
{p.portName} ({p.portType})
</Option>
))}
</Select>
</Form.Item>
</div>
<Form.Item label="源设备" name="sourceDeviceId" rules={[{ required: true, message: '请选择源设备' }]}>
<Select
showSearch
filterOption={false}
placeholder="搜索设备..."
onSearch={handleDeviceSearch}
onChange={handleSourceDeviceChange}
>
{devices.map(device => (
<Option key={device.deviceId} value={device.deviceId}>
{device.name} ({device.deviceId})
</Option>
))}
</Select>
</Form.Item>
{/* Target Side */}
<div style={{ padding: '12px', background: '#f9f9f9', borderRadius: '8px' }}>
<div style={{ marginBottom: 12, fontWeight: 500, color: '#666' }}>目标设备 (终点)</div>
<Form.Item
name="targetDeviceId"
label="设备"
rules={[{ required: true, message: '请选择目标设备' }]}
>
<Select
placeholder="输入关键词搜索目标设备"
showSearch
filterOption={false}
onSearch={handleDeviceSearch}
onDropdownVisibleChange={open => {
if (open && devices.length === 0) {
fetchDevices();
}
}}
onChange={handleTargetDeviceChange}
loading={fetchingDevices}
>
{devices
.filter(d => d.deviceId !== form.getFieldValue('sourceDeviceId'))
.map(d => (
<Option key={d.deviceId} value={d.deviceId}>
{d.name}
</Option>
))}
</Select>
</Form.Item>
<Form.Item
name="targetPort"
label="端口"
rules={[{ required: true, message: '请选择目标端口' }]}
>
<Select
placeholder="选择目标端口"
showSearch
disabled={!form.getFieldValue('targetDeviceId')}
>
{targetPorts.map(p => (
<Option key={p.portId} value={p.portName}>
{p.portName} ({p.portType})
</Option>
))}
</Select>
</Form.Item>
</div>
</div>
<Form.Item label="源端口" name="sourcePort" rules={[{ required: true, message: '请选择源端口' }]}>
<Select
placeholder="请先选择设备"
disabled={!sourcePorts.length}
>
{sourcePorts.map(port => (
<Option key={port.portId} value={port.portName}>
{port.portName}
</Option>
))}
</Select>
</Form.Item>
<div style={{ marginTop: 16 }}>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 16 }}>
<Form.Item
name="cableType"
label="线缆类型"
initialValue="ethernet"
rules={[{ required: true }]}
>
<Select>
<Option value="ethernet">网线</Option>
<Option value="fiber">光纤</Option>
<Option value="copper">铜缆</Option>
</Select>
</Form.Item>
<Form.Item
name="status"
label="状态"
initialValue="normal"
rules={[{ required: true }]}
>
<Select>
<Option value="normal">正常</Option>
<Option value="fault">故障</Option>
<Option value="disconnected">未连接</Option>
</Select>
</Form.Item>
<Form.Item name="cableLength" label="长度 (米)">
<Input type="number" min={0} />
</Form.Item>
</div>
<Form.Item name="description" label="描述">
<Input.TextArea rows={2} />
</Form.Item>
</div>
<Form.Item label="目标设备" name="targetDeviceId" rules={[{ required: true, message: '请选择目标设备' }]}>
<Select
showSearch
filterOption={false}
placeholder="搜索设备..."
onSearch={handleDeviceSearch}
onChange={handleTargetDeviceChange}
>
{devices.map(device => (
<Option key={device.deviceId} value={device.deviceId}>
{device.name} ({device.deviceId})
</Option>
))}
</Select>
</Form.Item>
<Form.Item label="目标端口" name="targetPort" rules={[{ required: true, message: '请选择目标端口' }]}>
<Select
placeholder="请先选择设备"
disabled={!targetPorts.length}
>
{targetPorts.map(port => (
<Option key={port.portId} value={port.portName}>
{port.portName}
</Option>
))}
</Select>
</Form.Item>
<Form.Item label="备注" name="notes">
<Input.TextArea placeholder="接线备注信息" rows={2} />
</Form.Item>
</Form>
</Modal>
);