umi#useModel TypeScript Examples

The following examples show how to use umi#useModel. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: BaseConfig.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
App = () => {
  const { pageSchema, selectComponent, setStateByObjectKeys } = useModel('bridge');

  // @ts-expect-error
  const form = useForm(selectComponent?.containerProps ?? {});

  return (
    <FormRender
      form={form}
      schema={componentBaseConfig}
      displayType="row"
      onFinish={() => { console.log(); }}
    />
  );
}
Example #2
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function() {
  const { setStateByObjectKeys, selectPage } = useModel('bridge');

  useEffect(()=>{
    const handshake = new Postmate.Model({
      [childrenModel.SYNC_STATE]: (message: any)=>{
        setStateByObjectKeys(message, false);
      },
      [childrenModel.CAPTURE]: async()=>{
        const captureDom = window.document.getElementById('snapshot-container');
        if(captureDom){
          const canvas = await html2canvas(captureDom, {
            useCORS: true,
            scale: 1,
          });
          return canvas.toDataURL('image/png');
        }
      },
    });
    handshake.then((parent) => {
      window.postmate_parent = parent;
    });
  }, []);

  return (
    <div
      className="h5-canvas"
      style={{backgroundColor: selectPage?.props?.backgroundColor}}
    >
      <div id="snapshot-container">
        <DragContainer />
      </div>
    </div>
  );
}
Example #3
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function() {
  const { pageSchema, setStateByObjectKeys, selectComponent } = useModel('bridge');
  const form = useForm();

  useEffect(() => {
    form.setValues(pageSchema[0].components[0].props || {});
  }, [pageSchema[0].components[0].props]);

  const watch = {
    '#': (values: any) => {
      pageSchema[0].components[0].props = values;
      setStateByObjectKeys({
        pageSchema: [...pageSchema],
      });
    },
  };

  return (
    <div className="manage-component-detail-form">
      <FormRenderWithWidgets
        form={form}
        watch={watch}
        {...selectComponent.generatorSchema}
      />
    </div>
  );
}
Example #4
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function() {
  const { selectComponent, selectPage } = useModel('bridge');

  return (
    <Tabs defaultActiveKey="componentConfig" type="card" className="config-tabs">
      <TabPane tab="页面配置" key="pageConfig">
        {selectPage ? <PageConfig /> : <Empty description="请新建一个页面后配置" /> }
      </TabPane>
      <TabPane tab="组件配置" key="componentConfig">
        {selectComponent ? <ComponentConfig /> : <Empty description="请选取组件后配置组件" /> }
      </TabPane>
      <TabPane tab="外层容器配置" key="containerConfig">
        {selectComponent ? <BaseLayoutConfig /> : <Empty description="请选取组件后配置外层容器" /> }
      </TabPane>
      <TabPane tab="事件" key="3">
        开发中...
      </TabPane>
    </Tabs>
  );
}
Example #5
Source File: PageConfig.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
App = () => {
  const { pageSchema, setStateByObjectKeys, selectPage } = useModel('bridge');
  const form = useForm();
  const { generatorSchema, props } = selectPage;

  useEffect(() => {
    form.setValues(props);
  }, [props]);

  const watch = {
    '#': (values: any) => {
      selectPage.props = values;
      setStateByObjectKeys({
        pageSchema: [...pageSchema],
      });
    },
  };

  return (
    <FormRenderWithWidgets
      form={form}
      watch={watch}
      {...generatorSchema}
    />
  );
}
Example #6
Source File: ComponentConfig.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
App = () => {
  const { pageSchema, selectComponent, setStateByObjectKeys } = useModel('bridge');
  const component = selectComponent as IComponentSchema;
  const { generatorSchema, props } = component;
  const form = useForm();

  useEffect(() => {
    form.setValues(props);
  }, [props]);

  const watch = {
    '#': (values: any) => {
      component.props = values;
      setStateByObjectKeys({
        pageSchema: [...pageSchema],
      });
    },
  };

  return (
    // @ts-expect-error
    <FormRenderWithWidgets
      form={form}
      watch={watch}
      {...generatorSchema}
    />
  );
}
Example #7
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function() {
  const { openCreatePageDrawer } = useModel('page');
  const { pageSchema, selectPageIndex } = useModel('bridge');

  return (
    <div className="page">
      {
        pageSchema.length === 0 ? (
          <>
            <div className="page-empty">
              <div className="page-empty-center">
                <Empty description="请先创建一个页面吧" />
                <Button type="primary" className="page-empty-new-btn" onClick={openCreatePageDrawer}>新增页面</Button>
              </div>
            </div>
          </>
        ) : (
          pageSchema.map((item, index)=>(
            <div
              key={item.props.path}
              className={classnames('page-card', {select: selectPageIndex === index})}
            >
              <img
                className="page-card-cover"
                src={item.coverSnapshot ?? item.cover ?? 'https://carpooling-1256959311.cos.ap-chengdu.myqcloud.com/d6bc039b-04ea-49ca-8ee9-a006aec7c443.png'}
              />
              <div className="title">{item.props.title}</div>
            </div>
          ))
        )
      }
      <CreatePage />
      <PageConfig />
    </div>
  );
}
Example #8
Source File: index.tsx    From ant-design-pro-V5-multitab with MIT License 6 votes vote down vote up
SortableList = SortableContainer(() => {
    const tabsRef = useRef<any>()
    const { tabList, tarnslateX } = useModel("system");
    return (
        <div className={`${styles.tabList}`} ref={tabsRef}  >
            {/* <div className={styles.linkTabs} style={{ transform: `translateX(-${tarnslateX}px)` }}> */}
            <div className={styles.linkTabs} style={{ transform: `translateX(-${tarnslateX}px)` }}>
                {
                    tabList.map((value, index: number) => (
                        <Tab key={`item-${index}`} index={index} value={value} tabIndex={index} />
                    ))
                }
            </div>
        </div >
    );
})
Example #9
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function(props:IProps) {
  const ref = useRef<HTMLDivElement>(null);
  const size = useSize(ref);
  const { setStateByObjectKeys } = useModel('bridge');
  useEffect(()=>{
    if(history.location.pathname === '/manage/component/detail' && !props.loading){
      setStateByObjectKeys({
        showSelectComponentBorder: false,
      });
    }
  }, [props.loading]);

  return (
    <div className="mobile-simulator-container">
      {(history.location.pathname !== '/manage/component/detail' && !props.loading) && <SelectArea size={size} loading={props.loading}/>}
      <div className="mobile-simulator">
        <div className="mobile-head-bar"></div>
        <div className="mobile-content" id="mobile-content" ref={ref} />
      </div>
    </div>
  );
}
Example #10
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function Font() {
  const { selectComponent, changeContainerPropsState } = useModel('bridge');
  const { color, fontSize, fontWeight } = selectComponent?.containerProps ?? {};

  return (
    <Descriptions column={1}>
      <Descriptions.Item label="颜色">
        <div className="font-color-input">
          <ColorPicker onChange={(value: string) => { changeContainerPropsState('color', value); }} value={color ?? '#fff'} />
        </div>
      </Descriptions.Item>
      <Descriptions.Item label="字号">
        <div className="font-size-weight">
          <Select
            value={fontWeight ?? 100}
            style={{ width: 120 }}
            onChange={(value) => { changeContainerPropsState('fontWeight', value); }}
          >
            <Select.Option value={100}>普通</Select.Option>
            <Select.Option value={800}>粗体</Select.Option>
          </Select>
          <InputNumber
            formatter={(value) => `${value}px`}
            parser={(value) => Number((value ?? '').replace('px', ''))}
            value={fontSize ?? 30}
            onChange={(value) => { changeContainerPropsState('fontSize', value); }}
          />
        </div>
      </Descriptions.Item>
    </Descriptions>
  );
}
Example #11
Source File: AvatarDropdown.tsx    From anew-server with MIT License 5 votes vote down vote up
AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
  const { initialState, setInitialState } = useModel('@@initialState');

  const onMenuClick = useCallback(
    (event: MenuInfo) => {
      const { key } = event;
      if (key === 'logout' && initialState) {
        setInitialState({ ...initialState, currentUser: undefined });
        loginOut();
        return;
      }
      history.push('/account/settings');
    },
    [initialState, setInitialState],
  );

  const loading = (
    <span className={`${styles.action} ${styles.account}`}>
      <Spin
        size="small"
        style={{
          marginLeft: 8,
          marginRight: 8,
        }}
      />
    </span>
  );

  if (!initialState) {
    return loading;
  }

  const { currentUser } = initialState;

  if (!currentUser || !currentUser.name) {
    return loading;
  }

  const menuHeaderDropdown = (
    <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
      {menu && (
        <Menu.Item key="settings">
          <SettingOutlined />
          个人设置
        </Menu.Item>
      )}
      {menu && <Menu.Divider />}

      <Menu.Item key="logout">
        <LogoutOutlined />
        退出登录
      </Menu.Item>
    </Menu>
  );
  return (
    <HeaderDropdown overlay={menuHeaderDropdown}>
      <span className={`${styles.action} ${styles.account}`}>
        <Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
        <span className={`${styles.name} anticon`}>{currentUser.name}</span>
      </span>
    </HeaderDropdown>
  );
}
Example #12
Source File: index.tsx    From anew-server with MIT License 5 votes vote down vote up
NoticeIconView = () => {
  const { initialState } = useModel('@@initialState');
  const { currentUser } = initialState || {};
  const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);

  useEffect(() => {
    getNotices().then(({ data }) => setNotices(data || []));
  }, []);

  const noticeData = getNoticeData(notices);
  const unreadMsg = getUnreadData(noticeData || {});

  const changeReadState = (id: string) => {
    setNotices(
      notices.map((item) => {
        const notice = { ...item };
        if (notice.id === id) {
          notice.read = true;
        }
        return notice;
      }),
    );
  };

  const clearReadState = (title: string, key: string) => {
    setNotices(
      notices.map((item) => {
        const notice = { ...item };
        if (notice.type === key) {
          notice.read = true;
        }
        return notice;
      }),
    );
    message.success(`${'清空了'} ${title}`);
  };

  return (
    <NoticeIcon
      className={styles.action}
      count={currentUser && currentUser.unreadCount}
      onItemClick={(item) => {
        changeReadState(item.id!);
      }}
      onClear={(title: string, key: string) => clearReadState(title, key)}
      loading={false}
      clearText="清空"
      viewMoreText="查看更多"
      onViewMore={() => message.info('Click on view more')}
      clearClose
    >
      <NoticeIcon.Tab
        tabKey="notification"
        count={unreadMsg.notification}
        list={noticeData.notification}
        title="通知"
        emptyText="你已查看所有通知"
        showViewMore
      />
      <NoticeIcon.Tab
        tabKey="message"
        count={unreadMsg.message}
        list={noticeData.message}
        title="消息"
        emptyText="您已读完所有消息"
        showViewMore
      />
      <NoticeIcon.Tab
        tabKey="event"
        title="待办"
        emptyText="你已完成所有待办"
        count={unreadMsg.event}
        list={noticeData.event}
        showViewMore
      />
    </NoticeIcon>
  );
}
Example #13
Source File: index.tsx    From ant-design-pro-V5-multitab with MIT License 5 votes vote down vote up
GlobalHeaderRight: React.FC = () => {
  const { initialState } = useModel('@@initialState');

  if (!initialState || !initialState.settings) {
    return null;
  }

  const { navTheme, layout } = initialState.settings;
  let className = styles.right;

  if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
    className = `${styles.right}  ${styles.dark}`;
  }
  return (
    <Space className={className}>
      <HeaderSearch
        className={`${styles.action} ${styles.search}`}
        placeholder="站内搜索"
        defaultValue="umi ui"
        options={[
          { label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>, value: 'umi ui' },
          {
            label: <a href="next.ant.design">Ant Design</a>,
            value: 'Ant Design',
          },
          {
            label: <a href="https://protable.ant.design/">Pro Table</a>,
            value: 'Pro Table',
          },
          {
            label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
            value: 'Pro Layout',
          },
        ]}
        // onSearch={value => {
        //   console.log('input', value);
        // }}
      />
      <HeaderDropdown
        overlay={
          <Menu>
            <Menu.Item
              onClick={() => {
                window.open('/~docs');
              }}
            >
              组件文档
            </Menu.Item>
            <Menu.Item
              onClick={() => {
                window.open('https://pro.ant.design/docs/getting-started');
              }}
            >
              Ant Design Pro 文档
            </Menu.Item>
          </Menu>
        }
      >
        <span className={styles.action}>
          <QuestionCircleOutlined />
        </span>
      </HeaderDropdown>
      <Avatar />
      {REACT_APP_ENV && (
        <span>
          <Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
        </span>
      )}
      <SelectLang className={styles.action} />
    </Space>
  );
}
Example #14
Source File: index.tsx    From anew-server with MIT License 5 votes vote down vote up
GlobalHeaderRight: React.FC = () => {
  const { initialState } = useModel('@@initialState');

  if (!initialState || !initialState.settings) {
    return null;
  }

  const { navTheme, layout } = initialState.settings;
  let className = styles.right;

  if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
    className = `${styles.right}  ${styles.dark}`;
  }

  return (
    <Space className={className}>
      <HeaderSearch
        className={`${styles.action} ${styles.search}`}
        placeholder="站内搜索"
        defaultValue="umi ui"
        options={[
          {
            label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>,
            value: 'umi ui',
          },
          {
            label: <a href="next.ant.design">Ant Design</a>,
            value: 'Ant Design',
          },
          {
            label: <a href="https://protable.ant.design/">Pro Table</a>,
            value: 'Pro Table',
          },
          {
            label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
            value: 'Pro Layout',
          },
        ]} // onSearch={value => {
        //   console.log('input', value);
        // }}
      />
      <span
        className={styles.action}
        onClick={() => {
          window.open('https://pro.ant.design/docs/getting-started');
        }}
      >
        <QuestionCircleOutlined />
      </span>
      {/* <NoticeIconView /> */}
      <Avatar menu />
    </Space>
  );
}
Example #15
Source File: AvatarDropdown.tsx    From ant-design-pro-V5-multitab with MIT License 5 votes vote down vote up
AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
  const { initialState, setInitialState } = useModel('@@initialState');

  const onMenuClick = useCallback(
    (event: {
      key: React.Key;
      keyPath: React.Key[];
      item: React.ReactInstance;
      domEvent: React.MouseEvent<HTMLElement>;
    }) => {
      const { key } = event;
      if (key === 'logout' && initialState) {
        setInitialState({ ...initialState, currentUser: undefined });
        loginOut();
        return;
      }
      history.push(`/account/${key}`);
    },
    [initialState, setInitialState],
  );

  const loading = (
    <span className={`${styles.action} ${styles.account}`}>
      <Spin
        size="small"
        style={{
          marginLeft: 8,
          marginRight: 8,
        }}
      />
    </span>
  );

  if (!initialState) {
    return loading;
  }

  const { currentUser } = initialState;

  if (!currentUser || !currentUser.name) {
    return loading;
  }

  const menuHeaderDropdown = (
    <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
      {menu && (
        <Menu.Item key="center">
          <UserOutlined />
          个人中心
        </Menu.Item>
      )}
      {menu && (
        <Menu.Item key="settings">
          <SettingOutlined />
          个人设置
        </Menu.Item>
      )}
      {menu && <Menu.Divider />}

      <Menu.Item key="logout">
        <LogoutOutlined />
        退出登录
      </Menu.Item>
    </Menu>
  );
  return (
    <HeaderDropdown overlay={menuHeaderDropdown}>
      <span className={`${styles.action} ${styles.account}`}>
        <Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
        <span className={`${styles.name} anticon`}>{currentUser.name}</span>
      </span>
    </HeaderDropdown>
  );
}
Example #16
Source File: BaseForm.tsx    From anew-server with MIT License 5 votes vote down vote up
BaseForm: React.FC<BaseFormProps> = (props) => {
    const { values } = props;
    const { initialState, setInitialState } = useModel('@@initialState');

    return (
        <ProForm
            onFinish={async (v: API.UserInfo) => {
                await updateUserInfo(v, values?.id).then((res) => {
                    if (res.code === 200 && res.status === true) {
                        message.success(res.message);
                        let userInfo = {};
                        Object.assign(userInfo, initialState?.currentUser);
                        (userInfo as API.UserInfo).name = v.name;
                        (userInfo as API.UserInfo).mobile = v.mobile;
                        (userInfo as API.UserInfo).email = v.email
                        setInitialState({ ...initialState, currentUser: userInfo as API.UserInfo });
                    }
                });
            }}
        >
            <ProForm.Group>
                <ProFormText
                    name="name"
                    label="姓名"
                    width="md"
                    rules={[{ required: true }]}
                    initialValue={values?.name}
                />
                <ProFormText
                    name="mobile"
                    label="手机"
                    width="md"
                    rules={[
                        {
                            pattern: /^1(?:70\d|(?:9[89]|8[0-24-9]|7[135-8]|66|5[0-35-9])\d|3(?:4[0-8]|[0-35-9]\d))\d{7}$/,
                            message: '请输入正确的手机号码',
                        },
                    ]}
                    initialValue={values?.mobile}
                />
                <ProFormText
                    name="email"
                    label="邮箱"
                    width="md"
                    rules={[
                        {
                            type: 'email',
                            message: '请输入正确的邮箱地址',
                        },
                    ]}
                    initialValue={values?.email}
                />
            </ProForm.Group>
        </ProForm>
    );
}
Example #17
Source File: CreateForm.tsx    From anew-server with MIT License 5 votes vote down vote up
CreateForm: React.FC<CreateFormProps> = (props) => {
    const { actionRef, modalVisible, handleChange } = props;
    const [treeData, setTreeData] = useState<API.DictList[]>([]);
    const { initialState, setInitialState } = useModel('@@initialState');

    useEffect(() => {
        queryDicts().then((res) => {
            const top: API.DictList = { id: 0, dict_value: '暂无所属', dict_key: '' };
            res.data.unshift(top)
            const dicts = loopTreeItem(res.data);
            setTreeData(dicts);
        });
    }, []);

    return (
        <ModalForm
            title="新建字典"
            visible={modalVisible}
            onVisibleChange={handleChange}
            onFinish={async (v) => {
                createDict(v as API.DictParams).then((res) => {
                    if (res.code === 200 && res.status === true) {
                        message.success(res.message);
                        queryDictsByAllType().then((res) => setInitialState({ ...initialState, DictObj: res.data }));
                        if (actionRef.current) {
                            actionRef.current.reload();
                        }
                    }
                });
                return true;
            }}
        >
            <ProForm.Group>
                <ProFormText name="dict_key" label="字典标签" width="md" rules={[{ required: true }]} />
                <ProFormText name="dict_value" label="字典键值" width="md" rules={[{ required: true }]} />
            </ProForm.Group>
            <ProForm.Group>
                <ProFormDigit name="sort" label="排序" width="md" fieldProps={{ precision: 0 }} />
                <ProFormText name="desc" label="说明" width="md" />
            </ProForm.Group>
            <ProForm.Group>
                <Form.Item label="上级字典" name="parent_id">
                    <TreeSelect
                        style={{ width: 330 }}
                        dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                        treeData={treeData}
                        placeholder="请选择字典"
                    />
                </Form.Item>
            </ProForm.Group>
        </ModalForm >
    );
}
Example #18
Source File: index.tsx    From ant-design-pro-V5-multitab with MIT License 5 votes vote down vote up
NoticeIconView = () => {
  const { initialState } = useModel('@@initialState');
  const { currentUser } = initialState || {};
  const [notices, setNotices] = useState<API.NoticeIconData[]>([]);

  useEffect(() => {
    queryNotices().then(({ data }) => setNotices(data));
  }, []);

  const noticeData = getNoticeData(notices);
  const unreadMsg = getUnreadData(noticeData || {});

  const changeReadState = (id: string) => {
    setNotices(
      notices.map((item) => {
        const notice = { ...item };
        if (notice.id === id) {
          notice.read = true;
        }
        return notice;
      }),
    );
  };

  const clearReadState = (title: string, key: string) => {
    setNotices(
      notices.map((item) => {
        const notice = { ...item };
        if (notice.type === key) {
          notice.read = true;
        }
        return notice;
      }),
    );
    message.success(`${'清空了'} ${title}`);
  };

  return (
    <NoticeIcon
      className={styles.action}
      count={currentUser && currentUser.unreadCount}
      onItemClick={(item) => {
        changeReadState(item.id);
      }}
      onClear={(title: string, key: string) => clearReadState(title, key)}
      loading={false}
      clearText="清空"
      viewMoreText="查看更多"
      onViewMore={() => message.info('Click on view more')}
      clearClose
    >
      <NoticeIcon.Tab
        tabKey="notification"
        count={unreadMsg.notification}
        list={noticeData.notification}
        title="通知"
        emptyText="你已查看所有通知"
        showViewMore
      />
      <NoticeIcon.Tab
        tabKey="message"
        count={unreadMsg.message}
        list={noticeData.message}
        title="消息"
        emptyText="您已读完所有消息"
        showViewMore
      />
      <NoticeIcon.Tab
        tabKey="event"
        title="待办"
        emptyText="你已完成所有待办"
        count={unreadMsg.event}
        list={noticeData.event}
        showViewMore
      />
    </NoticeIcon>
  );
}
Example #19
Source File: index.tsx    From ant-design-pro-V5-multitab with MIT License 5 votes vote down vote up
export default function KeepAlivePage(props: any) {
    const intl = useIntl()
    const { dispatch, tabList, showTabs, tarnslateX, tabsWidth, tabWidth } = useModel("system")
    useEffect(() => {
        // 去重
        const localTablist = JSON.parse(JSON.stringify(tabList));
        const isExit = localTablist.findIndex((item: any) => item.pathname === props.location.pathname);
        // 需要计算translateX
        if (isExit < 0) {
            const obj = { ...props.location, title: intl.formatMessage({ id: props.route.keepAliveName }), keepAliveName: props.route.keepAliveName }
            localTablist.push(obj);
            let x = 0;
            if (localTablist.length >= showTabs) {
                const isBeyondDistance = ((showTabs as number) * (tabWidth as number)) - (tabsWidth as number) + 100;
                x = isBeyondDistance + (localTablist.length - showTabs) * tabWidth
            }
            dispatch({ type: 'CHANGESTATE', payload: { tabList: localTablist, active: localTablist.length - 1, tarnslateX: x } });
        } else {
            const isBeyondDistance = ((showTabs as number) * (tabWidth as number)) - (tabsWidth as number) + 100;
            const curClickIndex = tabList.findIndex(item => item.pathname === props.location.pathname) as number;
            // 能展示多少个
            const totalShowIndex = (showTabs as number) - 1;
            if (curClickIndex > totalShowIndex) {
                // 计算移动的距离
                const x = (curClickIndex - totalShowIndex) * (tabWidth as number) + isBeyondDistance
                dispatch({ type: 'CHANGESTATE', payload: { tarnslateX: x, active: isExit } })
            } else {
                // 计算隐藏了多少个
                const transNum = Math.ceil(tarnslateX / tabWidth);
                if (isExit < transNum) {
                    dispatch({ type: 'CHANGESTATE', payload: { tarnslateX: tabWidth * curClickIndex, active: isExit } })
                } else {
                    dispatch({ type: 'CHANGESTATE', payload: { active: isExit } })
                }
            }
        }
    }, [])

    if (props.route.keppAlive) {
        return (
            <KeepAlive saveScrollPosition={props.route.saveScrollPosition ?? "screen"} name={props.route.keepAliveName}>
                {props.children}
            </KeepAlive>
        )
    }
    return props.children
}
Example #20
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function Background() {
  const { selectComponent, changeContainerPropsState } = useModel('bridge');
  const { backgroundImage, backgroundColor, backgroundSize, backgroundRepeat } = selectComponent?.containerProps ?? {};

  const [backgroundFillType, setBackgroundFillType] = useState(FILL_TYPE.color);

  return (
    <Descriptions column={1}>
      <Descriptions.Item label="填充">
        <div className="background">
          <Radio.Group
            size="small"
            options={[
              { label: '颜色填充', value: FILL_TYPE.color },
              { label: '背景图片', value: FILL_TYPE.image },
            ]}
            onChange={(e) => { setBackgroundFillType(e.target.value); }}
            value={backgroundFillType}
            optionType="button"
            buttonStyle="solid"
          />
        </div>
      </Descriptions.Item>
      {backgroundFillType === FILL_TYPE.color && (
        <Descriptions.Item label="填充颜色">
          <ColorPicker
            className="background-color"
            onChange={(value: string) => { changeContainerPropsState('backgroundColor', value); }}
            value={backgroundColor}
          />
        </Descriptions.Item>
      )}
      {backgroundFillType === FILL_TYPE.image && (
        <>
          <Descriptions.Item label="图片">
            <ImageUpload
              value={backgroundImage}
              onChange={(value) => { changeContainerPropsState('backgroundImage', value); }}
            />
          </Descriptions.Item>
          <Descriptions.Item label="尺寸">
            <Radio.Group
              style={{ marginTop: 4 }}
              size="small"
              options={[
                { label: '默认', value: 'initial' },
                { label: '充满', value: '100% 100%' },
                { label: '等比填充', value: 'contain' },
                { label: '等比覆盖', value: 'cover' },
              ]}
              onChange={(e) => { changeContainerPropsState('backgroundSize', e.target.value); }}
              value={backgroundSize ?? 'initial'}
              optionType="button"
              buttonStyle="solid"
            />
          </Descriptions.Item>
          <Descriptions.Item label="重复">
            <Radio.Group
              style={{ marginTop: 4 }}
              size="small"
              options={[
                { label: '默认', value: 'initial' },
                { label: '水平重复', value: 'repeat-x' },
                { label: '垂直重复', value: 'repeat-y' },
                { label: '不重复', value: 'no-repeat' },
              ]}
              onChange={(e) => { changeContainerPropsState('backgroundRepeat', e.target.value); }}
              value={backgroundRepeat ?? 'initial'}
              optionType="button"
              buttonStyle="solid"
            />
          </Descriptions.Item>
        </>
      )}
    </Descriptions>
  );
}
Example #21
Source File: index.tsx    From plugin-layout with MIT License 5 votes vote down vote up
BasicLayout = (props: any) => {
  const { children, userConfig, location } = props;
  const { initialState, loading } = (useModel && useModel('@@initialState')) || {
    initialState: undefined,
    loading: false,
  }; // plugin-initial-state 未开启
  const _routes = require('@@/router').routes;
  const rightContentRender = useRightContent(userConfig, loading, initialState);
  const layoutConfig = getLayoutConfigFromRoute(_routes);
  const patchMenus: (ms: MenuItem[]) => MenuItem[] =
    userConfig.patchMenus || ((ms: MenuItem[]): MenuItem[] => ms);
  const menus = patchMenus(getMenuDataFromRoutes(_routes[0].routes));

  // layout 是否渲染相关
  const pathName = location.pathname;
  const layoutRender: any = {};

  // 动态路由匹配
  const currentMatchPaths = Object.keys(layoutConfig).filter(item =>
    pathToRegexp(`${item}(.*)`).test(pathName),
  );

  const currentPathConfig = currentMatchPaths.length
    ? layoutConfig[currentMatchPaths[currentMatchPaths.length - 1]]
    : undefined;

  if (currentPathConfig && currentPathConfig.hideMenu) {
    layoutRender.menuRender = false;
  }

  if (currentPathConfig && currentPathConfig.hideNav) {
    layoutRender.headerRender = false;
  }

  return (
    <ProLayout
      title={userConfig.name || userConfig.title}
      className="umi-plugin-layout-main"
      navTheme="dark"
      siderWidth={256}
      onMenuHeaderClick={e => {
        e.stopPropagation();
        e.preventDefault();
        history.push('/');
      }}
      menu={{ locale: userConfig.locale }}
      menuDataRender={() => menus}
      formatMessage={formatMessage}
      logo={initialState?.avatar || logo}
      menuItemRender={(menuItemProps, defaultDom) => {
        if (menuItemProps.isUrl || menuItemProps.children) {
          return defaultDom;
        }
        return <Link to={menuItemProps.path || ''}>{defaultDom}</Link>;
      }}
      disableContentMargin
      rightContentRender={rightContentRender}
      fixSiderbar
      fixedHeader
      {...userConfig}
      {...props}
      {...layoutRender}
    >
      <ErrorBoundary>
        <WithExceptionOpChildren currentPathConfig={currentPathConfig}>
          {userConfig.childrenRender
            ? userConfig.childrenRender(children)
            : children}
        </WithExceptionOpChildren>
      </ErrorBoundary>
    </ProLayout>
  );
}
Example #22
Source File: UpdateForm.tsx    From anew-server with MIT License 5 votes vote down vote up
UpdateForm: React.FC<UpdateFormProps> = (props) => {
    const { actionRef, modalVisible, handleChange, values } = props;
    const [treeData, setTreeData] = useState<API.DictList[]>([]);
    const { initialState, setInitialState } = useModel('@@initialState');

    useEffect(() => {
        queryDicts().then((res) => {
            const top: API.DictList = { id: 0, dict_value: '暂无所属', dict_key: '' };
            res.data.unshift(top)
            const dicts = loopTreeItem(res.data);
            setTreeData(dicts);
        });
    }, []);

    return (
        <ModalForm
            title="更新字典"
            visible={modalVisible}
            onVisibleChange={handleChange}
            onFinish={async (v) => {
                updateDict(v as API.DictParams, values?.id).then((res) => {
                    if (res.code === 200 && res.status === true) {
                        message.success(res.message);
                        queryDictsByAllType().then((res) => setInitialState({ ...initialState, DictObj: res.data }));
                        if (actionRef.current) {
                            actionRef.current.reload();
                        }
                    }
                });
                return true;
            }}
        >
            <ProForm.Group>
                <ProFormText
                    name="dict_key"
                    label="字典标签"
                    width="md"
                    rules={[{ required: true }]}
                    initialValue={values?.dict_key}
                />
                <ProFormText
                    name="dict_value"
                    label="字典键值"
                    width="md"
                    rules={[{ required: true }]}
                    initialValue={values?.dict_value}
                />
            </ProForm.Group>
            <ProForm.Group>
                <ProFormDigit name="sort" label="排序" width="md" initialValue={values?.sort} fieldProps={{ precision: 0 }} />
                <ProFormText name="desc" label="说明" initialValue={values?.desc} width="md" />
            </ProForm.Group>
            <ProForm.Group>
                <Form.Item label="上级字典" name="parent_id" initialValue={values?.parent_id}>
                    <TreeSelect
                        style={{ width: 330 }}
                        dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                        treeData={treeData}
                        placeholder="请选择字典"
                    />
                </Form.Item>
            </ProForm.Group>
        </ModalForm>
    );
}
Example #23
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
Components = function() {

  const { onDragStart, onDragEnd, pageSchema } = useModel('bridge');
  const { queryAllWithComponent } = Model.useContainer();

  const dragStart = function(item: IComponentSchema) {
    if (pageSchema.length === 0) {
      notification.error({
        message: '请先创建一个页面',
        description: '创建页面后再进行组件拖拽操作!',
      });
    } else {
      onDragStart(item);
    }
  };

  const componentTree = queryAllWithComponent.data;

  return (
    <div className="components">
      <Tabs tabPosition="left">
        {
          componentTree && componentTree.map((category: any) => (
            <TabPane tab={category.name} key={category._id}>
              <Row gutter={10}>
                {
                  category.components.map((component: any) => (
                    <Col span={12} key={component._id}>
                      <div
                        className="components-item"
                        draggable
                        onDragStart={() => { dragStart(component); }}
                        onDragEnd={onDragEnd}
                      >
                        <div className="components-item-img">
                          <img src={component.cover} />
                        </div>
                        <div className="components-name">{component.name}</div>
                      </div>
                    </Col>
                  ))
                }
              </Row>
            </TabPane>
          ))
        }
      </Tabs>
    </div>
  );
}
Example #24
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function Border() {
  const { selectComponent, changeContainerPropsState } = useModel('bridge');
  const { borderColor, borderWidth, borderStyle, borderRadius } = selectComponent?.containerProps ?? {};

  return (
    <Descriptions column={1}>
      <Descriptions.Item label="圆角">
        <InputNumber
          formatter={(value) => `${value}px`}
          parser={(value) => Number((value ?? '').replace('px', ''))}
          value={borderRadius ?? 0}
          onChange={(value) => { changeContainerPropsState('borderRadius', value); }}
        />
      </Descriptions.Item>
      <Descriptions.Item label="样式">
        <Radio.Group
          size="small"
          options={[
            { label: '无边框', value: 'none' },
            { label: '实线', value: 'solid' },
            { label: '虚线', value: 'dashed' },
            { label: '点线', value: 'dotted' },
          ]}
          onChange={(e) => { changeContainerPropsState('borderStyle', e.target.value); }}
          value={borderStyle ?? 'none'}
          optionType="button"
          buttonStyle="solid"
        />
      </Descriptions.Item>
      <Descriptions.Item label="宽度">
        <InputNumber
          formatter={(value) => `${value}px`}
          parser={(value) => (value ?? '').replace('px', '')}
          value={borderWidth ?? 0}
          onChange={(value) => { changeContainerPropsState('borderWidth', value); }}
        />
      </Descriptions.Item>
      <Descriptions.Item label="颜色">
        <ColorPicker
          onChange={(value: string) => { changeContainerPropsState('borderColor', value); }}
          value={borderColor}
        />
      </Descriptions.Item>
    </Descriptions>
  );
}
Example #25
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function() {
  const { selectComponent, pageSchema, setStateByObjectKeys} = useModel('bridge');
  const { containerProps } = selectComponent || {};
  const handleChange = function(value: string, key1: 'margin' | 'padding', key2: 'top' | 'right' | 'bottom' | 'left') {
    if(!selectComponent)return;
    if(!selectComponent.containerProps){
      selectComponent.containerProps = {
        margin: {},
        padding: {},
      };
    }
    if(!selectComponent.containerProps.margin){
      selectComponent.containerProps.margin = {};
    }
    if(!selectComponent.containerProps.padding){
      selectComponent.containerProps.padding = {};
    }
    // @ts-expect-error
    selectComponent.containerProps[key1][key2] = value;
    setStateByObjectKeys({
      pageSchema: [...pageSchema],
    });
  };

  return (
    <div className="layout-config">
      <div className="margin-top">
        <input value={containerProps?.margin?.top} onChange={(e) => { handleChange(e.target.value, 'margin', 'top'); }} />
      </div>
      <div className="margin-right">
        <input value={containerProps?.margin?.right} onChange={(e) => { handleChange(e.target.value, 'margin', 'right'); }} />
      </div>
      <div className="margin-bottom">
        <input value={containerProps?.margin?.bottom} onChange={(e) => { handleChange(e.target.value, 'margin', 'bottom'); }} />
      </div>
      <div className="margin-left">
        <input value={containerProps?.margin?.left} onChange={(e) => { handleChange(e.target.value, 'margin', 'left'); }} />
      </div>
      <div className="padding-top">
        <input value={containerProps?.padding?.top} onChange={(e) => { handleChange(e.target.value, 'padding', 'top'); }} />
      </div>
      <div className="padding-right">
        <input value={containerProps?.padding?.right} onChange={(e) => { handleChange(e.target.value, 'padding', 'right'); }} />
      </div>
      <div className="padding-bottom">
        <input value={containerProps?.padding?.bottom} onChange={(e) => { handleChange(e.target.value, 'padding', 'bottom'); }} />
      </div>
      <div className="padding-left">
        <input value={containerProps?.padding?.left} onChange={(e) => { handleChange(e.target.value, 'padding', 'left'); }} />
      </div>
    </div>
  );
}
Example #26
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function Shadow() {
  const { selectComponent, changeContainerPropsState } = useModel('bridge');
  const { containerProps } = selectComponent || {};
  const { boxShadow } = containerProps ?? {};

  let computedBoxShadow = boxShadow as string;
  if (!boxShadow) {
    computedBoxShadow = 'rgba(255,255,255,0) 0px 0px 0px 0px';
  }
  const arrayBoxShadow = computedBoxShadow.split(' ') as string[];
  const boxShadowType = /inset/.test(boxShadow as string) ? BOX_SHADOW_TYPE.inset : BOX_SHADOW_TYPE.outside;
  const [color, boxShadowX, boxShadowY, boxShadowRadius] = arrayBoxShadow;

  const onBoxShadowTypeChange = function(type: BOX_SHADOW_TYPE) {
    let changedBoxShadow;
    if (type === BOX_SHADOW_TYPE.outside) {
      changedBoxShadow = arrayBoxShadow.slice(0, 4).join(' ');
    }
    if (type === BOX_SHADOW_TYPE.inset) {
      changedBoxShadow = `${arrayBoxShadow.slice(0, 4).join(' ')} inset`;
    }
    changeContainerPropsState('boxShadow', changedBoxShadow);
  };

  const changeShadowState = function(index: number, value: string | number | undefined) {
    // @ts-expect-error
    arrayBoxShadow[index] = index === 0 ? value : `${value ?? 0}px`;
    changeContainerPropsState('boxShadow', arrayBoxShadow.join(' '));
  };

  return (
    <Descriptions column={1}>
      <Descriptions.Item label="类型">
        <Radio.Group
          size="small"
          options={[
            { label: '外阴影', value: BOX_SHADOW_TYPE.outside },
            { label: '内阴影', value: BOX_SHADOW_TYPE.inset },
          ]}
          onChange={(e) => { onBoxShadowTypeChange(e.target.value); }}
          value={boxShadowType}
          optionType="button"
          buttonStyle="solid"
        />
      </Descriptions.Item>
      <Descriptions.Item label="颜色">
        <ColorPicker
          className="background-color"
          onChange={(value: string) => { changeShadowState(0, value); }}
          value={color}
        />
      </Descriptions.Item>
      <Descriptions.Item label="X轴">
        <InputNumber
          formatter={(value) => `${value}px`}
          parser={(value) => (value ?? '').replace('px', '')}
          value={boxShadowX.replace('px', '')}
          onChange={(value) => { changeShadowState(1, value); }}
        />
      </Descriptions.Item>
      <Descriptions.Item label="Y轴">
        <InputNumber
          formatter={(value) => `${value}px`}
          parser={(value) => (value ?? '').replace('px', '')}
          value={boxShadowY.replace('px', '')}
          onChange={(value) => { changeShadowState(2, value); }}
        />
      </Descriptions.Item>
      <Descriptions.Item label="半径">
        <InputNumber
          formatter={(value) => `${value}px`}
          parser={(value) => (value ?? '').replace('px', '')}
          value={boxShadowRadius.replace('px', '')}
          onChange={(value) => { changeShadowState(3, value); }}
        />
      </Descriptions.Item>
    </Descriptions>
  );
}
Example #27
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function() {
  const { page, closeCreatePageDrawer, openConfigPageDrawer, onCreatePage } = useModel('page');
  const { queryPageListReq } = Model.useContainer();
  const templateList = queryPageListReq.data;

  const useTemplate = function(template:any){
    onCreatePage({
      ...template.pageSchema[0],
    });
  };

  return (
    <Drawer
      className="page-add"
      title="新增页面-选择页面模板"
      placement="left"
      onClose={closeCreatePageDrawer}
      visible={page.createModalVisible}
      getContainer={false}
      style={{ position: 'absolute' }}
      width={430}
    >
      <Row gutter={16}>
        <Col
          className="gutter-row"
          span={12}
          onClick={()=>{
            // onCreatePage(pageSchema);
            openConfigPageDrawer();
          }}
        >
          <Card
            className="page-add-card"
            cover={
              <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description=""/>
            }
          >
            <div className="title">空白页面</div>
          </Card>
        </Col>
        {
          templateList && templateList.list.map((template: any) => (
            <Col className="gutter-row" span={12} key={template._id}>
              <Card
                className="page-add-card"
                cover={
                  <img
                    className="page-add-card-img"
                    alt="example"
                    src={template.pageSchema[0].cover}
                  />
                }
                onClick={()=>{useTemplate(template);}}
              >
                <div className="title">{template.pageSchema[0].config.title}</div>
              </Card>
            </Col>
          ))
        }
      </Row>
    </Drawer>
  );
}
Example #28
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function() {
  const { pageSchema } = useModel('bridge');
  const { page, closeConfigPageDrawer, onCreatePage } = useModel('page');
  useEffect(() => {
    if (page.configModalVisible) {
      form.setValues({
        title: `页面-${pageSchema.length + 1}`,
        path: uuidv4(),
      });
    }
  }, [page.configModalVisible]);
  const form = useForm();

  const onFinish = function(formData: Record<string, unknown>, errors:any[]) {
    if (errors.length === 0) {
      onCreatePage({
        config: formData,
        generatorSchema: page_generatorSchema,
        props: {
          ...formData,
          isHome: true,
          backgroundColor: '#fff',
        },
        components: [],
      });
    }
  };

  return (
    <Drawer
      className="page-config"
      title="页面配置"
      placement="left"
      onClose={closeConfigPageDrawer}
      visible={page.configModalVisible}
      getContainer={false}
      style={{ position: 'absolute' }}
      width={420}
      footer={
        <div
          style={{
            textAlign: 'right',
          }}
        >
          <Button onClick={closeConfigPageDrawer} style={{ marginRight: 8 }}>
            取消
          </Button>
          <Button onClick={form.submit} type="primary">
            确定
          </Button>
        </div>
      }
    >
      <FormRenderWithWidgets
        form={form}
        schema={schema}
        onFinish={onFinish}
      />
    </Drawer>
  );
}
Example #29
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
SlideLeft = function()  {

  const { side, setSide } = useModel('layout');
  const menus = [{
    title: '页面',
    menuType: SIDES_MENU.page,
    component: Pages,
    icon: 'icon-yemian1',
  }, {
    title: '组件',
    menuType: SIDES_MENU.component,
    component: Components,
    icon: 'icon-zujian',
  }, {
    title: '结构',
    menuType: SIDES_MENU.structure,
    component: Construct,
    icon: 'icon-shuxingjiegou',
  }];

  const currentMenu = menus.find((item)=>item.menuType === side.menu);

  return (
    <>
      <div className="side-left-nav">
        <ul className="side-left-nav-list">
          {
            menus.map((item) => (
              <li
                className={classnames({ active: side.menu === item.menuType })}
                onClick={() => { setSide({ menu: item.menuType }); }}
                key={item.menuType}
              >
                <i className={`iconfont ${item.icon}`} />
                <div className="title">{item.title}</div>
              </li>
            ))
          }
        </ul>
      </div>
      <div className="side-left-content">
        {currentMenu && <currentMenu.component/ >}
      </div>
    </>
  );
}