import React, { useState, useEffect, useMemo, useLayoutEffect } from 'react'; import { Spin, Radio, Button, message, Tooltip } from 'antd'; import { ReloadOutlined, PlusOutlined } from '@ant-design/icons'; import { IUiApi } from 'umi-types'; import { stringify, parse } from 'qs'; import { Clear } from './icon'; import { Resource, Block, AddBlockParams } from '../../data.d'; import BlockList from './BlockList'; import GlobalSearch from './GlobalSearch'; import useCallData from './hooks/useCallData'; import styles from './BlocksViewer.module.less'; import Adder from './Adder'; import AssetsMenu from './AssetsMenu'; import { ModelState, namespace } from './model'; import Container from './Container'; /** * get substr from url */ const getQueryConfig = () => parse(window.location.search.substr(1)); /** * 更新 search * @param params */ const updateUrlQuery = (params: { type: string; resource?: string }) => { const defaultParas = getQueryConfig(); window.history.pushState( {}, '', `?${stringify({ ...defaultParas, ...params, })}`, ); }; const clearCache = async (api: IUiApi) => { try { const hide = message.loading('缓存清理中!'); const { data } = (await api.callRemote({ type: 'org.umi.block.clear', })) as { data: string; }; // 用户记忆的参数 localStorage.removeItem('umi-ui-block-removeLocale'); hide(); // 等动画播放完 setTimeout(() => { message.success(data); }, 30); } catch (e) { message.error(e.message); } }; const openUmiBlocks = () => { window.open('https://github.com/umijs/umi-blocks'); }; /** * 从 id 的 dom 滚动到 target 的 dom * @param id * @param target */ export const scrollToById = (id: string, target: string) => { const dom = document.getElementById(id); const targetDom = document.getElementById(target); if (dom && targetDom) { const axis = dom.getBoundingClientRect(); targetDom.scrollTop = axis.top + axis.height / 2; } }; interface Props { dispatch: (params: any) => {}; loading: boolean; block: ModelState; } /** * 渲染 数据源选择器 * @param param0 */ const renderActiveResourceTag = ({ type, matchedResources = [], current = { id: '' }, setActiveResource, }: { type: string; current: Resource; matchedResources: Resource[]; setActiveResource: (value: Resource) => void; }) => { if (matchedResources.length > 1) { return ( { const resource = matchedResources.find(r => r.id === e.target.value); setActiveResource(resource); updateUrlQuery({ type, resource: resource.id }); }} > {matchedResources.map(r => ( {r.name} ))} ); } if (matchedResources.length === 1) { return (

{matchedResources[0].name}

); } return null; }; const BlocksViewer: React.FC = props => { const { dispatch, block, loading: fetchDataLoading } = props; const { api, type, setType, activeResource, setActiveResource } = Container.useContainer(); const { callRemote, intl } = api; /** * 是不是umi */ const isMini = api.isMini(); /** * 用到的各种状态 */ const [willAddBlock, setWillAddBlock] = useState(null); const [addingBlock, setAddBlock] = useState(null); const [addModalVisible, setAddModalVisible] = useState(false); const [blockParams, setBlockParams] = useState(null); const [searchValue, setSearchValue] = useState(''); const [selectedTag, setSelectedTag] = useState(''); /** * 获取 query 中的设置 */ useLayoutEffect(() => { // 更新一下url,让他们同步一下 if (type) { updateUrlQuery({ type }); } }, []); // 获取数据源 const { data: resources } = useCallData( () => callRemote({ type: 'org.umi.block.resource', }) as any, [], { defaultData: [], }, ); // 当前的数据源列表 const current = useMemo( () => { return activeResource || resources.filter(item => item.blockType === type)[0]; }, [resources, activeResource, type], ); // 计算选中的区块 const blocks = useMemo( () => { return current && block.blockData[current.id] ? block.blockData[current.id] : []; }, [block, current], ); // 初始化 block dva model data useEffect( () => { if (current && current.id) { dispatch({ type: `${namespace}/fetch`, payload: { resourceId: current.id, }, }); } }, [current], ); useEffect(() => { /** * 获取上次的安装的区块 url * 成功之后会被清除 */ callRemote({ type: 'org.umi.block.get-adding-block-url', }).then(({ data }: { data: string }) => { if (data) { setAddBlock({ url: data }); } }); }, []); // 如果区块不在屏幕范围内,滚动过去 useEffect( () => { if (willAddBlock) { // 我把每个 item 都加了一个 id,就是他的 url scrollToById(willAddBlock.url, 'block-list-view'); } }, [fetchDataLoading], ); // 区块右上角的区域 三个按钮 useEffect(() => { const buttonPadding = isMini ? '0 4px' : '0 8px'; const handleSearchChange = (v: string) => { setSearchValue(v.toLocaleLowerCase()); }; if (api.setActionPanel) { api.setActionPanel(() => [ , (node ? (node.parentNode as HTMLElement) : document.body)} placement="bottom" > , (node ? (node.parentNode as HTMLElement) : document.body)} placement="bottom" > , (node ? (node.parentNode as HTMLElement) : document.body)} placement="bottom" > , ]); } }, []); const matchedResources = resources.filter(r => r.blockType === type); return ( <>
{current ? (
{matchedResources.length > 0 ? ( { setAddModalVisible(true); setWillAddBlock(currentBlock); setBlockParams(option); }} loading={fetchDataLoading} /> ) : (
没有找到数据源
)}
) : (
)}
setAddBlock(addBlock)} onHideModal={() => { setAddModalVisible(false); setWillAddBlock(undefined); setBlockParams(undefined); }} /> ); }; export default BlocksViewer;