#
luxiaotao1123
2024-02-20 4d2b6e57ad8afac8e7c314f5e88de3abe952f99c
#
1个文件已修改
7个文件已添加
924 ■■■■■ 已修改文件
zy-asrs-flow/src/components/IconSelector/Category.tsx 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/CopyableIcon.tsx 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/IconPicSearcher.tsx 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/fields.ts 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/index.tsx 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/style.less 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/themeIcons.tsx 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/pages/system/menu/components/edit.jsx 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-flow/src/components/IconSelector/Category.tsx
New file
@@ -0,0 +1,63 @@
import * as React from 'react';
import CopyableIcon from './CopyableIcon';
import type { ThemeType } from './index';
import type { CategoriesKeys } from './fields';
import { useIntl } from '@umijs/max';
import styles from './style.less';
interface CategoryProps {
  title: CategoriesKeys;
  icons: string[];
  theme: ThemeType;
  newIcons: string[];
  onSelect: (type: string, name: string) => any;
}
const Category: React.FC<CategoryProps> = props => {
  const { icons, title, newIcons, theme } = props;
  const intl = useIntl();
  const [justCopied, setJustCopied] = React.useState<string | null>(null);
  const copyId = React.useRef<NodeJS.Timeout | null>(null);
  const onSelect = React.useCallback((type: string, text: string) => {
    const { onSelect } = props;
    if (onSelect) {
      onSelect(type, text);
    }
    setJustCopied(type);
    copyId.current = setTimeout(() => {
      setJustCopied(null);
    }, 2000);
  }, []);
  React.useEffect(
    () => () => {
      if (copyId.current) {
        clearTimeout(copyId.current);
      }
    },
    [],
  );
  return (
    <div>
      <h4>{intl.formatMessage({
        id: `app.docs.components.icon.category.${title}`,
        defaultMessage: '信息',
      })}</h4>
      <ul className={styles.anticonsList}>
        {icons.map(name => (
          <CopyableIcon
            key={name}
            name={name}
            theme={theme}
            isNew={newIcons.includes(name)}
            justCopied={justCopied}
            onSelect={onSelect}
          />
        ))}
      </ul>
    </div>
  );
};
export default Category;
zy-asrs-flow/src/components/IconSelector/CopyableIcon.tsx
New file
@@ -0,0 +1,47 @@
import * as React from 'react';
import { Tooltip } from 'antd';
import classNames from 'classnames';
import * as AntdIcons from '@ant-design/icons';
import type { ThemeType } from './index';
import styles from './style.less';
const allIcons: {
  [key: string]: any;
} = AntdIcons;
export interface CopyableIconProps {
  name: string;
  isNew: boolean;
  theme: ThemeType;
  justCopied: string | null;
  onSelect: (type: string, text: string) => any;
}
const CopyableIcon: React.FC<CopyableIconProps> = ({
  name,
  justCopied,
  onSelect,
  theme,
}) => {
  const className = classNames({
    copied: justCopied === name,
    [theme]: !!theme,
  });
  return (
    <li className={className}
      onClick={() => {
        if (onSelect) {
          onSelect(theme, name);
        }
      }}>
      <Tooltip title={name}>
        {React.createElement(allIcons[name], { className: styles.anticon })}
      </Tooltip>
      {/* <span className={styles.anticonClass}>
          <Badge dot={isNew}>{name}</Badge>
        </span> */}
    </li>
  );
};
export default CopyableIcon;
zy-asrs-flow/src/components/IconSelector/IconPicSearcher.tsx
New file
@@ -0,0 +1,233 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Upload, Tooltip, Popover, Modal, Progress, Spin, Result } from 'antd';
import * as AntdIcons from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import './style.less';
const allIcons: { [key: string]: any } = AntdIcons;
const { Dragger } = Upload;
interface AntdIconClassifier {
  load: () => void;
  predict: (imgEl: HTMLImageElement) => void;
}
declare global {
  interface Window {
    antdIconClassifier: AntdIconClassifier;
  }
}
interface PicSearcherState {
  loading: boolean;
  modalOpen: boolean;
  popoverVisible: boolean;
  icons: iconObject[];
  fileList: any[];
  error: boolean;
  modelLoaded: boolean;
}
interface iconObject {
  type: string;
  score: number;
}
const PicSearcher: React.FC = () => {
  const intl = useIntl();
  const {formatMessage} = intl;
  const [state, setState] = useState<PicSearcherState>({
    loading: false,
    modalOpen: false,
    popoverVisible: false,
    icons: [],
    fileList: [],
    error: false,
    modelLoaded: false,
  });
  const predict = (imgEl: HTMLImageElement) => {
    try {
      let icons: any[] = window.antdIconClassifier.predict(imgEl);
      if (gtag && icons.length) {
        gtag('event', 'icon', {
          event_category: 'search-by-image',
          event_label: icons[0].className,
        });
      }
      icons = icons.map(i => ({ score: i.score, type: i.className.replace(/\s/g, '-') }));
      setState(prev => ({ ...prev, loading: false, error: false, icons }));
    } catch {
      setState(prev => ({ ...prev, loading: false, error: true }));
    }
  };
  // eslint-disable-next-line class-methods-use-this
  const toImage = (url: string) =>
    new Promise(resolve => {
      const img = new Image();
      img.setAttribute('crossOrigin', 'anonymous');
      img.src = url;
      img.onload = () => {
        resolve(img);
      };
    });
  const uploadFile = useCallback((file: File) => {
    setState(prev => ({ ...prev, loading: true }));
    const reader = new FileReader();
    reader.onload = () => {
      toImage(reader.result as string).then(predict);
      setState(prev => ({
        ...prev,
        fileList: [{ uid: 1, name: file.name, status: 'done', url: reader.result }],
      }));
    };
    reader.readAsDataURL(file);
  }, []);
  const onPaste = useCallback((event: ClipboardEvent) => {
    const items = event.clipboardData && event.clipboardData.items;
    let file = null;
    if (items && items.length) {
      for (let i = 0; i < items.length; i++) {
        if (items[i].type.includes('image')) {
          file = items[i].getAsFile();
          break;
        }
      }
    }
    if (file) {
      uploadFile(file);
    }
  }, []);
  const toggleModal = useCallback(() => {
    setState(prev => ({
      ...prev,
      modalOpen: !prev.modalOpen,
      popoverVisible: false,
      fileList: [],
      icons: [],
    }));
    if (!localStorage.getItem('disableIconTip')) {
      localStorage.setItem('disableIconTip', 'true');
    }
  }, []);
  useEffect(() => {
    const script = document.createElement('script');
    script.onload = async () => {
      await window.antdIconClassifier.load();
      setState(prev => ({ ...prev, modelLoaded: true }));
      document.addEventListener('paste', onPaste);
    };
    script.src = 'https://cdn.jsdelivr.net/gh/lewis617/antd-icon-classifier@0.0/dist/main.js';
    document.head.appendChild(script);
    setState(prev => ({ ...prev, popoverVisible: !localStorage.getItem('disableIconTip') }));
    return () => {
      document.removeEventListener('paste', onPaste);
    };
  }, []);
  return (
    <div className="iconPicSearcher">
      <Popover
        content={formatMessage({id: 'app.docs.components.icon.pic-searcher.intro'})}
        open={state.popoverVisible}
      >
        <AntdIcons.CameraOutlined className="icon-pic-btn" onClick={toggleModal} />
      </Popover>
      <Modal
        title={intl.formatMessage({
          id: 'app.docs.components.icon.pic-searcher.title',
          defaultMessage: '信息',
        })}
        open={state.modalOpen}
        onCancel={toggleModal}
        footer={null}
      >
        {state.modelLoaded || (
          <Spin
            spinning={!state.modelLoaded}
            tip={formatMessage({
              id: 'app.docs.components.icon.pic-searcher.modelloading',
            })}
          >
            <div style={{ height: 100 }} />
          </Spin>
        )}
        {state.modelLoaded && (
          <Dragger
            accept="image/jpeg, image/png"
            listType="picture"
            customRequest={o => uploadFile(o.file as File)}
            fileList={state.fileList}
            showUploadList={{ showPreviewIcon: false, showRemoveIcon: false }}
          >
            <p className="ant-upload-drag-icon">
              <AntdIcons.InboxOutlined />
            </p>
            <p className="ant-upload-text">
              {formatMessage({id: 'app.docs.components.icon.pic-searcher.upload-text'})}
            </p>
            <p className="ant-upload-hint">
              {formatMessage({id: 'app.docs.components.icon.pic-searcher.upload-hint'})}
            </p>
          </Dragger>
        )}
        <Spin
          spinning={state.loading}
          tip={formatMessage({id: 'app.docs.components.icon.pic-searcher.matching'})}
        >
          <div className="icon-pic-search-result">
            {state.icons.length > 0 && (
              <div className="result-tip">
                {formatMessage({id: 'app.docs.components.icon.pic-searcher.result-tip'})}
              </div>
            )}
            <table>
              {state.icons.length > 0 && (
                <thead>
                  <tr>
                    <th className="col-icon">
                      {formatMessage({id: 'app.docs.components.icon.pic-searcher.th-icon'})}
                    </th>
                    <th>{formatMessage({id: 'app.docs.components.icon.pic-searcher.th-score'})}</th>
                  </tr>
                </thead>
              )}
              <tbody>
                {state.icons.map(icon => {
                  const { type } = icon;
                  const iconName = `${type
                    .split('-')
                    .map(str => `${str[0].toUpperCase()}${str.slice(1)}`)
                    .join('')}Outlined`;
                  return (
                    <tr key={iconName}>
                      <td className="col-icon">
                          <Tooltip title={icon.type} placement="right">
                            {React.createElement(allIcons[iconName])}
                          </Tooltip>
                      </td>
                      <td>
                        <Progress percent={Math.ceil(icon.score * 100)} />
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            {state.error && (
              <Result
                status="500"
                title="503"
                subTitle={formatMessage({id: 'app.docs.components.icon.pic-searcher.server-error'})}
              />
            )}
          </div>
        </Spin>
      </Modal>
    </div>
  );
};
export default PicSearcher;
zy-asrs-flow/src/components/IconSelector/fields.ts
New file
@@ -0,0 +1,223 @@
import * as AntdIcons from '@ant-design/icons/lib/icons';
const all = Object.keys(AntdIcons)
  .map(n => n.replace(/(Outlined|Filled|TwoTone)$/, ''))
  .filter((n, i, arr) => arr.indexOf(n) === i);
const direction = [
  'StepBackward',
  'StepForward',
  'FastBackward',
  'FastForward',
  'Shrink',
  'ArrowsAlt',
  'Down',
  'Up',
  'Left',
  'Right',
  'CaretUp',
  'CaretDown',
  'CaretLeft',
  'CaretRight',
  'UpCircle',
  'DownCircle',
  'LeftCircle',
  'RightCircle',
  'DoubleRight',
  'DoubleLeft',
  'VerticalLeft',
  'VerticalRight',
  'VerticalAlignTop',
  'VerticalAlignMiddle',
  'VerticalAlignBottom',
  'Forward',
  'Backward',
  'Rollback',
  'Enter',
  'Retweet',
  'Swap',
  'SwapLeft',
  'SwapRight',
  'ArrowUp',
  'ArrowDown',
  'ArrowLeft',
  'ArrowRight',
  'PlayCircle',
  'UpSquare',
  'DownSquare',
  'LeftSquare',
  'RightSquare',
  'Login',
  'Logout',
  'MenuFold',
  'MenuUnfold',
  'BorderBottom',
  'BorderHorizontal',
  'BorderInner',
  'BorderOuter',
  'BorderLeft',
  'BorderRight',
  'BorderTop',
  'BorderVerticle',
  'PicCenter',
  'PicLeft',
  'PicRight',
  'RadiusBottomleft',
  'RadiusBottomright',
  'RadiusUpleft',
  'RadiusUpright',
  'Fullscreen',
  'FullscreenExit',
];
const suggestion = [
  'Question',
  'QuestionCircle',
  'Plus',
  'PlusCircle',
  'Pause',
  'PauseCircle',
  'Minus',
  'MinusCircle',
  'PlusSquare',
  'MinusSquare',
  'Info',
  'InfoCircle',
  'Exclamation',
  'ExclamationCircle',
  'Close',
  'CloseCircle',
  'CloseSquare',
  'Check',
  'CheckCircle',
  'CheckSquare',
  'ClockCircle',
  'Warning',
  'IssuesClose',
  'Stop',
];
const editor = [
  'Edit',
  'Form',
  'Copy',
  'Scissor',
  'Delete',
  'Snippets',
  'Diff',
  'Highlight',
  'AlignCenter',
  'AlignLeft',
  'AlignRight',
  'BgColors',
  'Bold',
  'Italic',
  'Underline',
  'Strikethrough',
  'Redo',
  'Undo',
  'ZoomIn',
  'ZoomOut',
  'FontColors',
  'FontSize',
  'LineHeight',
  'Dash',
  'SmallDash',
  'SortAscending',
  'SortDescending',
  'Drag',
  'OrderedList',
  'UnorderedList',
  'RadiusSetting',
  'ColumnWidth',
  'ColumnHeight',
];
const data = [
  'AreaChart',
  'PieChart',
  'BarChart',
  'DotChart',
  'LineChart',
  'RadarChart',
  'HeatMap',
  'Fall',
  'Rise',
  'Stock',
  'BoxPlot',
  'Fund',
  'Sliders',
];
const logo = [
  'Android',
  'Apple',
  'Windows',
  'Ie',
  'Chrome',
  'Github',
  'Aliwangwang',
  'Dingding',
  'WeiboSquare',
  'WeiboCircle',
  'TaobaoCircle',
  'Html5',
  'Weibo',
  'Twitter',
  'Wechat',
  'Youtube',
  'AlipayCircle',
  'Taobao',
  'Skype',
  'Qq',
  'MediumWorkmark',
  'Gitlab',
  'Medium',
  'Linkedin',
  'GooglePlus',
  'Dropbox',
  'Facebook',
  'Codepen',
  'CodeSandbox',
  'CodeSandboxCircle',
  'Amazon',
  'Google',
  'CodepenCircle',
  'Alipay',
  'AntDesign',
  'AntCloud',
  'Aliyun',
  'Zhihu',
  'Slack',
  'SlackSquare',
  'Behance',
  'BehanceSquare',
  'Dribbble',
  'DribbbleSquare',
  'Instagram',
  'Yuque',
  'Alibaba',
  'Yahoo',
  'Reddit',
  'Sketch',
  'WhatsApp',
  'Dingtalk',
];
const datum = [...direction, ...suggestion, ...editor, ...data, ...logo];
const other = all.filter(n => !datum.includes(n));
export const categories = {
  direction,
  suggestion,
  editor,
  data,
  logo,
  other,
};
export default categories;
export type Categories = typeof categories;
export type CategoriesKeys = keyof Categories;
zy-asrs-flow/src/components/IconSelector/index.tsx
New file
@@ -0,0 +1,142 @@
import * as React from 'react';
import Icon, * as AntdIcons from '@ant-design/icons';
import { Radio, Input, Empty } from 'antd';
import type { RadioChangeEvent } from 'antd/es/radio/interface';
import debounce from 'lodash/debounce';
import Category from './Category';
import IconPicSearcher from './IconPicSearcher';
import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons';
import type { CategoriesKeys } from './fields';
import { categories } from './fields';
// import { useIntl } from '@umijs/max';
export enum ThemeType {
  Filled = 'Filled',
  Outlined = 'Outlined',
  TwoTone = 'TwoTone',
}
const allIcons: { [key: string]: any } = AntdIcons;
interface IconSelectorProps {
  //intl: any;
  onSelect: any;
}
interface IconSelectorState {
  theme: ThemeType;
  searchKey: string;
}
const IconSelector: React.FC<IconSelectorProps> = (props) => {
  // const intl = useIntl();
  // const { messages } = intl;
  const { onSelect } = props;
  const [displayState, setDisplayState] = React.useState<IconSelectorState>({
    theme: ThemeType.Outlined,
    searchKey: '',
  });
  const newIconNames: string[] = [];
  const handleSearchIcon = React.useCallback(
    debounce((searchKey: string) => {
      setDisplayState(prevState => ({ ...prevState, searchKey }));
    }),
    [],
  );
  const handleChangeTheme = React.useCallback((e: RadioChangeEvent) => {
    setDisplayState(prevState => ({ ...prevState, theme: e.target.value as ThemeType }));
  }, []);
  const renderCategories = React.useMemo<React.ReactNode | React.ReactNode[]>(() => {
    const { searchKey = '', theme } = displayState;
    const categoriesResult = Object.keys(categories)
      .map((key: CategoriesKeys) => {
        let iconList = categories[key];
        if (searchKey) {
          const matchKey = searchKey
            // eslint-disable-next-line prefer-regex-literals
            .replace(new RegExp(`^<([a-zA-Z]*)\\s/>$`, 'gi'), (_, name) => name)
            .replace(/(Filled|Outlined|TwoTone)$/, '')
            .toLowerCase();
          iconList = iconList.filter((iconName:string) => iconName.toLowerCase().includes(matchKey));
        }
        // CopyrightCircle is same as Copyright, don't show it
        iconList = iconList.filter((icon:string) => icon !== 'CopyrightCircle');
        return {
          category: key,
          icons: iconList.map((iconName:string) => iconName + theme).filter((iconName:string) => allIcons[iconName]),
        };
      })
      .filter(({ icons }) => !!icons.length)
      .map(({ category, icons }) => (
        <Category
          key={category}
          title={category as CategoriesKeys}
          theme={theme}
          icons={icons}
          newIcons={newIconNames}
          onSelect={(type, name) => {
            if (onSelect) {
              onSelect(name, allIcons[name]);
            }
          }}
        />
      ));
    return categoriesResult.length === 0 ? <Empty style={{ margin: '2em 0' }} /> : categoriesResult;
  }, [displayState.searchKey, displayState.theme]);
  return (
    <>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <Radio.Group
          value={displayState.theme}
          onChange={handleChangeTheme}
          size="large"
          optionType="button"
          buttonStyle="solid"
          options={[
            {
              label:  <Icon component={OutlinedIcon} />,
              value: ThemeType.Outlined
            },
            {
              label: <Icon component={FilledIcon} />,
              value: ThemeType.Filled
            },
            {
              label: <Icon component={TwoToneIcon} />,
              value: ThemeType.TwoTone
            },
          ]}
        >
          {/* <Radio.Button value={ThemeType.Outlined}>
            <Icon component={OutlinedIcon} /> {messages['app.docs.components.icon.outlined']}
          </Radio.Button>
          <Radio.Button value={ThemeType.Filled}>
            <Icon component={FilledIcon} /> {messages['app.docs.components.icon.filled']}
          </Radio.Button>
          <Radio.Button value={ThemeType.TwoTone}>
            <Icon component={TwoToneIcon} /> {messages['app.docs.components.icon.two-tone']}
          </Radio.Button> */}
        </Radio.Group>
        <Input.Search
          // placeholder={messages['app.docs.components.icon.search.placeholder']}
          style={{ margin: '0 10px', flex: 1 }}
          allowClear
          onChange={e => handleSearchIcon(e.currentTarget.value)}
          size="large"
          autoFocus
          suffix={<IconPicSearcher />}
        />
      </div>
      {renderCategories}
    </>
  );
};
export default IconSelector
zy-asrs-flow/src/components/IconSelector/style.less
New file
@@ -0,0 +1,137 @@
.iconPicSearcher {
  display: inline-block;
  margin: 0 8px;
  .icon-pic-btn {
    color: @text-color-secondary;
    cursor: pointer;
    transition: all 0.3s;
    &:hover {
      color: @input-icon-hover-color;
    }
  }
}
.icon-pic-preview {
  width: 30px;
  height: 30px;
  margin-top: 10px;
  padding: 8px;
  text-align: center;
  border: 1px solid @border-color-base;
  border-radius: 4px;
  > img {
    max-width: 50px;
    max-height: 50px;
  }
}
.icon-pic-search-result {
  min-height: 50px;
  padding: 0 10px;
  > .result-tip {
    padding: 10px 0;
    color: @text-color-secondary;
  }
  > table {
    width: 100%;
    .col-icon {
      width: 80px;
      padding: 10px 0;
      > .anticon {
        font-size: 30px;
        :hover {
          color: @link-hover-color;
        }
      }
    }
  }
}
ul.anticonsList {
  margin: 2px 0;
  overflow: hidden;
  direction: ltr;
  list-style: none;
  li {
    position: relative;
    float: left;
    width: 48px;
    height: 48px;
    margin: 3px 0;
    padding: 2px 0 0;
    overflow: hidden;
    color: #555;
    text-align: center;
    list-style: none;
    background-color: inherit;
    border-radius: 4px;
    cursor: pointer;
    transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out;
    .rtl & {
      margin: 3px 0;
      padding: 2px 0 0;
    }
    .anticon {
      margin: 4px 0 2px;
      font-size: 24px;
      transition: transform 0.3s ease-in-out;
      will-change: transform;
    }
    .anticonClass {
      display: block;
      font-family: 'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
      white-space: nowrap;
      text-align: center;
      transform: scale(0.83);
      .ant-badge {
        transition: color 0.3s ease-in-out;
      }
    }
    &:hover {
      color: #fff;
      background-color: @primary-color;
      .anticon {
        transform: scale(1.4);
      }
      .ant-badge {
        color: #fff;
      }
    }
    &.TwoTone:hover {
      background-color: #8ecafe;
    }
    &.copied:hover {
      color: rgba(255, 255, 255, 0.2);
    }
    &.copied::after {
      top: -2px;
      opacity: 1;
    }
  }
}
.copied-code {
  padding: 2px 4px;
  font-size: 12px;
  background: #f5f5f5;
  border-radius: 2px;
}
zy-asrs-flow/src/components/IconSelector/themeIcons.tsx
New file
@@ -0,0 +1,41 @@
import * as React from 'react';
export const FilledIcon: React.FC = props => {
  const path =
    'M864 64H160C107 64 64 107 64 160v' +
    '704c0 53 43 96 96 96h704c53 0 96-43 96-96V16' +
    '0c0-53-43-96-96-96z';
  return (
    <svg {...props} viewBox="0 0 1024 1024">
      <path d={path} />
    </svg>
  );
};
export const OutlinedIcon: React.FC = props => {
  const path =
    'M864 64H160C107 64 64 107 64 160v7' +
    '04c0 53 43 96 96 96h704c53 0 96-43 96-96V160c' +
    '0-53-43-96-96-96z m-12 800H172c-6.6 0-12-5.4-' +
    '12-12V172c0-6.6 5.4-12 12-12h680c6.6 0 12 5.4' +
    ' 12 12v680c0 6.6-5.4 12-12 12z';
  return (
    <svg {...props} viewBox="0 0 1024 1024">
      <path d={path} />
    </svg>
  );
};
export const TwoToneIcon: React.FC = props => {
  const path =
    'M16 512c0 273.932 222.066 496 496 49' +
    '6s496-222.068 496-496S785.932 16 512 16 16 238.' +
    '066 16 512z m496 368V144c203.41 0 368 164.622 3' +
    '68 368 0 203.41-164.622 368-368 368z';
  return (
    <svg {...props} viewBox="0 0 1024 1024">
      <path d={path} />
    </svg>
  );
};
zy-asrs-flow/src/pages/system/menu/components/edit.jsx
@@ -7,12 +7,17 @@
    ProFormDateTimePicker,
    ProFormTreeSelect
} from '@ant-design/pro-components';
import { Form, Modal } from 'antd';
import { Form, Modal, Col } from 'antd';
import moment from 'moment';
import Http from '@/utils/http';
import { createIcon } from '@/utils/icon-util'
import IconSelector from '@/components/IconSelector';
const Edit = (props) => {
    const [menuType, setMenuType] = useState(0);
    const [menuIconName, setMenuIconName] = useState();
    const [iconSelectorOpen, setIconSelectorOpen] = useState(false);
    const [form] = Form.useForm();
    const { } = props;
@@ -32,7 +37,7 @@
    }
    const handleFinish = async (values) => {
        props.onSubmit({ ...values });
        console.log(values);
    }
    return (
@@ -99,7 +104,7 @@
                        <ProFormSelect
                            name="type"
                            label="类型"
                            colProps={{ md: 12, xl: 12 }}
                            colProps={{ md: 10, xl: 610 }}
                            placeholder="请选择"
                            options={[
                                { label: '菜单', value: 0 },
@@ -119,12 +124,19 @@
                            colProps={{ md: 12, xl: 12 }}
                            placeholder="请输入"
                        />
                        <ProFormText
                        <ProFormSelect
                            name="icon"
                            label="菜单图标"
                            hidden={menuType !== 0}
                            colProps={{ md: 12, xl: 12 }}
                            placeholder="请输入"
                            valueEnum={{}}
                            addonBefore={createIcon(menuIconName)}
                            fieldProps={{
                                onClick: () => {
                                    setIconSelectorOpen(true);
                                },
                            }}
                        />
                    </ProForm.Group>
                    <ProForm.Group>
@@ -147,7 +159,23 @@
                        />
                    </ProForm.Group>
                </ProForm>
            </Modal>
                <Modal
                    width={800}
                    open={iconSelectorOpen}
                    onCancel={() => {
                        setIconSelectorOpen(false);
                    }}
                    footer={null}
                >
                    <IconSelector
                        onSelect={(name) => {
                            form.setFieldsValue({ icon: name });
                            setMenuIconName(name);
                            setIconSelectorOpen(false);
                        }}
                    />
                </Modal>
            </Modal >
        </>
    )
}