自学内容网 自学内容网

React 配置小组件

  • DeviceConfig/index.tsx 
import React, { useState, useEffect } from 'react';
import { Form, Input, Select, Radio, Button } from 'antd';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
import './index.css';

interface DeviceOption {
  ua: string;
  name: string;
}

interface Device {
  device_type: string;
  version_type: string;
  version_start: string;
  version_end: string;
  version_list: string;
  version_exc: string;
}

interface DeviceConfigProps {
  deviceTypeOptions: DeviceOption[];
  deviceList: Device[];
  disabledDeviceOptions?: boolean;
  maxCount?: number;
  onDeviceTypeListDataChange?: (data: Device[]) => void;
}

const DeviceConfig: React.FC<DeviceConfigProps> = ({
                                                     deviceTypeOptions = [],
                                                     deviceList = [],
                                                     disabledDeviceOptions = false,
                                                     maxCount = 1,
                                                     onDeviceTypeListDataChange,
                                                   }) => {
  const [deviceTypeListData, setDeviceTypeListData] = useState<Device[]>(deviceList);

  // 添加 useEffect,当 deviceList 变化时更新 deviceTypeListData
  useEffect(() => {
    setDeviceTypeListData(deviceList);
  }, [deviceList]);

  useEffect(() => {
    if (onDeviceTypeListDataChange) {
      onDeviceTypeListDataChange(deviceTypeListData);
    }
  }, [deviceTypeListData, onDeviceTypeListDataChange]);

  const deviceStruct: Device = {
    device_type: '',
    version_type: '0',
    version_start: '',
    version_end: '',
    version_list: '',
    version_exc: '',
  };

  const haveAbleChoice = deviceTypeOptions.some(
    option => !deviceTypeListData.some(device => device.device_type === option.ua)
  );

  const getAvailableDeviceOptions = (index: number) => {
    const selectedTypes = deviceTypeListData
      .map((device, idx) => (idx !== index ? device.device_type : null))
      .filter(type => type !== null);
    return deviceTypeOptions.filter(option => !selectedTypes.includes(option.ua));
  };

  const addDevice = () => {
    const selectedTypes = deviceTypeListData.map(device => device.device_type);
    const firstAvailableType = deviceTypeOptions.find(
      option => !selectedTypes.includes(option.ua)
    );
    if (firstAvailableType) {
      const deviceData = { ...deviceStruct, device_type: firstAvailableType.ua };
      setDeviceTypeListData([...deviceTypeListData, deviceData]);
    }
  };

  const deleteDevice = (index: number) => {
    const newData = [...deviceTypeListData];
    newData.splice(index, 1);
    setDeviceTypeListData(newData);
  };

  const handleChange = (index: number, field: string, value: any) => {
    const newData = [...deviceTypeListData];
    (newData[index] as any)[field] = value;
    setDeviceTypeListData(newData);
  };

  const getVersionPlaceholder = (deviceType: string) =>
    '输入示例:' + (deviceType === 'pc_exe_template' ? '5123400' : '5.12.34');

  const getMultiVersionPlaceholder = (deviceType: string) =>
    '输入示例:' + (deviceType === 'pc_exe_template' ? '5123400,5123411' : '5.12.34,5.12.35');

  return (
    <div>
      {deviceTypeListData.map((device, index) => (
        <div key={index} className="device-item">
          <div className="group-row">
            <Form layout="vertical" style={{ width: '100%' }}>
              <Form.Item label="下发终端" required>
                <Select
                  value={device.device_type}
                  placeholder="请选择"
                  allowClear
                  style={{ width: 200 }}
                  onChange={value => handleChange(index, 'device_type', value)}
                >
                  {getAvailableDeviceOptions(index).map(item => (
                    <Select.Option key={item.ua} value={item.ua}>
                      {item.name}
                    </Select.Option>
                  ))}
                </Select>
              </Form.Item>
              <Form.Item label="指定版本" required>
                <Radio.Group
                  value={device.version_type}
                  onChange={e => handleChange(index, 'version_type', e.target.value)}
                >
                  <Radio value="0">全部</Radio>
                  <Radio value="1">范围</Radio>
                  <Radio value="2">包含</Radio>
                </Radio.Group>
              </Form.Item>
              {device.version_type === '1' && (
                <div style={{ display: 'flex', flexDirection: 'row' }}>
                  <Form.Item label="开始版本">
                    <Input
                      value={device.version_start}
                      placeholder={getVersionPlaceholder(device.device_type)}
                      onChange={e => handleChange(index, 'version_start', e.target.value)}
                    />
                  </Form.Item>
                  <Form.Item label="结束版本" style={{ marginLeft: 0 }}>
                    <Input
                      value={device.version_end}
                      placeholder={getVersionPlaceholder(device.device_type)}
                      onChange={e => handleChange(index, 'version_end', e.target.value)}
                    />
                  </Form.Item>
                </div>
              )}
              {device.version_type === '2' && (
                <Form.Item label="指定版本号">
                  <Input.TextArea
                    value={device.version_list}
                    placeholder={getMultiVersionPlaceholder(device.device_type)}
                    onChange={e => handleChange(index, 'version_list', e.target.value)}
                  />
                </Form.Item>
              )}
              <Form.Item label="剔除版本号">
                <Input.TextArea
                  value={device.version_exc}
                  placeholder={getMultiVersionPlaceholder(device.device_type)}
                  onChange={e => handleChange(index, 'version_exc', e.target.value)}
                />
                <span className="extra-info">若输入多个版本号,请使用英文逗号分隔</span>
              </Form.Item>
            </Form>
            <Button
              icon={<DeleteOutlined />}
              type="text"
              style={{ marginLeft: 10 }}
              onClick={() => deleteDevice(index)}
            />
          </div>
        </div>
      ))}
      {haveAbleChoice && (
        <div className="device-btn" onClick={addDevice}>
          <PlusOutlined style={{ fontWeight: 'bold', marginRight: 5 }} /> 增加终端
        </div>
      )}
    </div>
  );
};

export default DeviceConfig;
  • DeviceConfig/index.css
/* DeviceConfig.css */
.device-btn {
  width: 138px;
  height: 32px;
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px dashed #d9d9d9;
  background: #ffffff;
  padding: 4px 15px;
}

.device-btn:hover {
  cursor: pointer;
  color: #409EFF;
  border: 1px dashed #409EFF;
}

.device-btn:active {
  background: #f2f0f7;
}

.device-item {
  margin: 0 0 24px;
  background-color: #f4f5ffda;
  padding: 16px;
  border-radius: 8px;
}

.group-row {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
}

.extra-info {
  color: rgba(0, 0, 0, 0.45);
  font-size: 14px;
  line-height: 1.5715;
  transition: color 0.3s cubic-bezier(.215, .61, .355, 1);
}

index.tsx

import React, { useState } from 'react';
import { useModel } from 'umi';
import { PageContainer } from '@ant-design/pro-layout';
import { Button, Modal, Form } from 'antd';
import DeviceConfig from './DeviceConfig'; // 请根据实际路径调整

const IndexPage: React.FC = () => {
  const { initialState } = useModel('@@initialState');
  const appConfigOption = initialState?.appConfigOption;

  const [visible, setVisible] = useState(false);
  const [modalType, setModalType] = useState<'modify' | 'open'>('open');
  const [deviceList, setDeviceList] = useState([
    { device_type: 'pc_exe_template', version_type: '0', version_exc: '5123400' },
  ]);

  const [form] = Form.useForm();

  const deviceTypeOptions = [
    { ua: 'pc_exe_template', name: 'PC EXE' },
    { ua: 'mobile_app', name: '移动应用' },
    // 添加更多设备类型选项
  ];

  const checkDeviceConfig = (rule: any, value: any) => {
    return new Promise<void>((resolve, reject) => {
      if (!value || value.length === 0) {
        reject('请至少配置一条下发的终端');
      } else {
        for (let item of value) {
          if (
            (item.version_type === '1' &&
              (!item.version_start || item.version_start.length === 0) &&
              (!item.version_end || item.version_end.length === 0)) ||
            (item.version_type === '2' && (!item.version_list || item.version_list.length === 0))
          ) {
            reject('请完善终端版本配置');
            return;
          }

          let regex = /^\d+\.\d+\.\d+$/;
          if (item.device_type === 'pc_exe_template') {
            regex = /^\d{7}$/;
          }

          if (item.version_type === '0') {
            if (
              item.version_exc &&
              item.version_exc.length !== 0 &&
              !item.version_exc
                .split(',')
                .every((segment: string) => segment.length === 0 || regex.test(segment))
            ) {
              reject('剔除版本号输入不合法');
              return;
            }
          } else if (item.version_type === '1') {
            if (item.version_start && item.version_start.length !== 0 && !regex.test(item.version_start)) {
              reject('开始版本输入不合法');
              return;
            }
            if (item.version_end && item.version_end.length !== 0 && !regex.test(item.version_end)) {
              reject('结束版本输入不合法');
              return;
            }
            if (
              item.version_exc &&
              item.version_exc.length !== 0 &&
              !item.version_exc
                .split(',')
                .every((segment: string) => segment.length === 0 || regex.test(segment))
            ) {
              reject('剔除版本号输入不合法');
              return;
            }
          } else {
            if (
              item.version_list &&
              item.version_list.length !== 0 &&
              !item.version_list
                .split(',')
                .every((segment: string) => segment.length === 0 || regex.test(segment))
            ) {
              reject('指定版本号输入不合法');
              return;
            }
            if (
              item.version_exc &&
              item.version_exc.length !== 0 &&
              !item.version_exc
                .split(',')
                .every((segment: string) => segment.length === 0 || regex.test(segment))
            ) {
              reject('剔除版本号输入不合法');
              return;
            }
          }
        }
        resolve();
      }
    });
  };

  const showModal = (type: 'modify' | 'open') => {
    setModalType(type);
    form.resetFields();
    if (type === 'modify') {
      form.setFieldsValue({ deviceList: deviceList });
    } else {
      form.setFieldsValue({
        deviceList: [{ device_type: 'pc_exe_template', version_type: '0', version_exc: '' }],
      });
    }
    setVisible(true);
  };

  const handleOk = () => {
    form
      .validateFields()
      .then((values) => {
        if (modalType === 'modify') {
          setDeviceList(values.deviceList); // 更新 deviceList
        }
        setVisible(false);
      })
      .catch((errorInfo) => {
        console.log('校验失败:', errorInfo);
      });
  };

  const handleCancel = () => {
    setVisible(false);
  };

  return (
    <PageContainer title={false}>
      <Button type="primary" onClick={() => showModal('modify')}>
        修改
      </Button>
      <Button type="default" onClick={() => showModal('open')} style={{ marginLeft: 8 }}>
        打开
      </Button>
      <Modal
        title="终端设置"
        visible={visible}
        onOk={handleOk}
        onCancel={handleCancel}
        destroyOnClose
        width={800}
      >
        <Form form={form}>
          <Form.Item
            label="终端设置"
            name="deviceList"
            rules={[{ validator: checkDeviceConfig }]}
          >
            <DeviceConfig
              deviceTypeOptions={deviceTypeOptions}
              deviceList={form.getFieldValue('deviceList')}
              onDeviceTypeListDataChange={(data) => {
                form.setFieldsValue({ deviceList: data });
              }}
            />
          </Form.Item>
        </Form>
      </Modal>
    </PageContainer>
  );
};

export default IndexPage;


原文地址:https://blog.csdn.net/weixin_41987016/article/details/145183374

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!