弹窗组件封装

827 阅读1分钟

弹窗组件封装

  • 某一段代码过于庞大则需要进行抽离封装处理
  • TS 类型推断写的时候需要格外注意一一对应,否则会报类型错误(一片红很不舒服)

index.tsx

const bindTags = async (data: IProdCategories) => {
    try {
        const { pasResult: tags } = await pluto.get(`/api/params/tagtree/${data.prodCatId}`);
        const { pasResult: selectedTagIds } = await pluto.get(
            `/api/front_category/product_tag/ids?category_id=${store.selectItem.categoryId}&prod_category_id=${data.prodCatId}`
        );
        openBindTagDialog(data.prodCatId, tags, selectedTagIds);
    } catch (e) {
        toast.error(e.message);
    }
};

// 表格的一列
render: (data: IProdCategories) => <Link onClick={() => bindTags(data)}>设置</Link>

bind-pro-tag.tsx

import * as React from 'react';
import pluto from '@/common/libs/pluto';
import styled from 'styled-components';
import { Button, toast, Dialog, Checkbox, Result } from '@qunhe/muya-ui';
import { useStores } from '../../hooks/useStore';
import { IProduct, ITag } from '../../store/root';
import { observer } from 'mobx-react-lite';
import ReactDOM from 'react-dom';

const StyledDetailDiv = styled.div`
    .dialog-title-right {
        color: #a4a8ae;
        font-size: 12px;
        margin-left: 10px;
    }

    .tags-checkbox {
        margin-right: 20px;
    }

    .dialog-hr {
        height: 2px;
        background-color: #f3f4f5;
        border: none;
    }
`;

interface IProps {
    handleClose: () => void;
    proCatId: number;
    tags: IProduct[];
    selectedTagIds: number[];
}

const BindProdTag: React.FunctionComponent<IProps> = observer(props => {
    const store = useStores();
    const { proCatId, tags } = props;
    const [visibleBind, setVisibleBind] = React.useState<boolean>(true);
    const [selectedTagIds, setSelectedTagIds] = React.useState<Array<Number>>([]);

    React.useEffect(() => {
        setSelectedTagIds(props.selectedTagIds);
    }, [proCatId, tags, props.selectedTagIds]);

    const handleBindClose = () => {
        setVisibleBind(false);
    };

    const handleBindChange = (id: number) => {
        let arr = Array.from(selectedTagIds);
        const index = selectedTagIds.findIndex(item => item === id);
        if (index !== -1) {
            arr.splice(index, 1);
        } else {
            arr.push(id);
        }
        setSelectedTagIds(arr);
    };

    const onBindConfirm = () => {
        return pluto
            .post(`/api/front_category/product_tag/bind`, selectedTagIds, {
                params: {
                    category_id: store.selectItem.categoryId,
                    prod_category_id: proCatId
                }
            })
            .then(() => {
                handleBindClose();
                toast.success('保存成功!');
            })
            .catch(e => {
                toast.error(e.message);
            });
    };

    return (
        <StyledDetailDiv>
            <Dialog.Base
                disablePortal
                destroyOnClose={true}
                open={visibleBind}
                onClose={handleBindClose}
                width={562}
                height={400}
            >
                <Dialog.Title onClose={handleBindClose}>
                    <span>标签值绑定</span>
                    <span className="dialog-title-right">真分类关联的标签类型和标签值</span>
                </Dialog.Title>
                {tags.length ? (
                    <>
                        <Dialog.Content>
                            {tags.map((item: IProduct) => {
                                return (
                                    <div key={item.localeId}>
                                        <h5>{item.tagTypeName}</h5>
                                        {item.productTags.map((items: ITag) => {
                                            return (
                                                <Checkbox
                                                    className="tags-checkbox"
                                                    key={items.tagId}
                                                    checked={selectedTagIds.includes(items.tagId)}
                                                    onChange={() => handleBindChange(items.tagId)}
                                                >
                                                    <span>{items.tagName}</span>
                                                </Checkbox>
                                            );
                                        })}
                                        <hr className="dialog-hr" />
                                    </div>
                                );
                            })}
                        </Dialog.Content>
                        <Dialog.Actions>
                            <Button onClick={handleBindClose}>取消</Button>
                            <Button htmlType="submit" type="primary" onClick={onBindConfirm}>
                                保存
                            </Button>
                        </Dialog.Actions>
                    </>
                ) : (
                    <Result type="empty" />
                )}
            </Dialog.Base>
        </StyledDetailDiv>
    );
});

const openBindTagDialog = (proCatId: number, tags: IProduct[], selectedTagIds: number[]) => {
    const mountElement = document.createElement('div');
    document.body.appendChild(mountElement);

    const handleClose = () => {
        ReactDOM.unmountComponentAtNode(mountElement);
        document.body.removeChild(mountElement);
    };

    ReactDOM.render(
        <BindProdTag
            handleClose={handleClose}
            proCatId={proCatId}
            tags={tags}
            selectedTagIds={selectedTagIds}
        />,
        mountElement
    );
};

export default openBindTagDialog;