Info.js 11.1 KB
/**
 * Author: llw
 * Date: 2020.7.20
 * Description: [应用详情]
 */
import React, { useEffect } from 'react';
import { connect, Link } from 'umi';
import { Modal, Card, Breadcrumb, Form, Input, Button, Tree, message, Spin } from 'antd';
import { IconFontConfig } from '@/common';
import { EditOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
import ModalSetAuth from './ModalSetAuth';
import { getAuthData, getAllMenuParams, getPermissionList, getDelAuthData, getDragData } from '@/utils/utils';

const { TreeNode } = Tree;
const layout = {labelCol: { span: 3 }, wrapperCol: { span: 12 }};

const ApplicationInfo = props => {
  const [form] = Form.useForm();

  let { 
    loading,
    isRepeat,
    dispatch, 
    dataModal,
    oldInfo = {},
    dataAuth = [],
    dataMenuList = [],
    dataExpandedKeys = [],
    location: { query: { id } },
  } = props;

  /* 获取应用详情 */
  useEffect(() => {
    if (id) {
      dispatch({type: 'Application/getApplicationInfo', payload: {id}}).then(res => {
        const { name, url, code, apiDomain } = res.data || {};
        form.setFieldsValue({
          name, url, code, apiDomain
        });
      });
    }
    return (() => {
      dispatch({type: 'Application/changeState', payload: {
        dataMenuList: [], 
        dataAuth: [],
        dataExpandedKeys: [], 
        dataApplicationInfo: {}
      }})
    })
  }, []);

  /* 添加权限 */
  const handleAddTemp = () => {
    dispatch({type: 'Application/changeState', payload: {
      dataModal: {
        modalType: 'AUTH_SET_MODAL',
        modalShow: true,
        modalData: {isEdit: false}
      }
    }})
  };

  /* 关闭弹框 */
  const handleCancelModal = () => {
    dispatch({type: 'Application/changeState', payload: {oldInfo: {}}});
    dispatch({type: 'Application/cancelModal'});
  };

  /* 保存权限配置 */
  const handleAuthSetOk = (values) => {
    const { isEdit } = values;
    const { allCode = [], allMenuName = [] } = getAllMenuParams(dataAuth);
    
    if (oldInfo.name !== values.name && allMenuName.includes(values.name)) {
      message.warning("菜单名称不能重复~")
      return false;
    }
    if (oldInfo.code !== values.code && allCode.includes(values.code)) {
      message.warning("code不能重复~")
      return false;
    }

    /* 上述条件不成立时才会走下面生成tree */
    let params = {
      subPermissionList: [], 
      ...values, 
      isEdit: undefined, 
      key: values.code,
      oldCode: (oldInfo.parentCode && oldInfo.parentCode !== values.parentCode) ? oldInfo.parentCode : undefined
    };
    let dataSetAuth = 
      !isEdit 
        ? 
      getAuthData(dataAuth, params)
        :
      getDelAuthData(dataAuth, params, 'EDIT');
    const { data, dataMenu, dataExpandedKeys } = dataSetAuth;
    handleCancelModal();
    dispatch({type: 'Application/changeState', payload: { 
      dataAuth: JSON.parse(JSON.stringify(data)),
      dataMenuList: JSON.parse(JSON.stringify(dataMenu)),
      dataExpandedKeys: JSON.parse(JSON.stringify(dataExpandedKeys))
    }});
  };

  // TreeNode的DOM
  const renderTreeNode = (data) => {
    return data.map((item) => {
      if (item.subPermissionList && item.subPermissionList.length) {
        return (
          <TreeNode 
            title={
              <>
                {item.name}
                <EditOutlined title="编辑" className="ml-10" onClick={() => handleTreeNode(item, "INFO")} />
                <DeleteOutlined title="删除" className="ml-10" onClick={() => handleTreeNode(item, "DEL")} />
              </>
            } 
            key={item.code} 
            icon={<IconFontConfig type={(item.type === 3 || item.type === "BTN") ? "icon-btn" : "icon-menu"} style={{fontSize: '14px'}} />}
          >
            {renderTreeNode(item.subPermissionList)}
          </TreeNode>
        )
      }
      return (
        <TreeNode 
          title={
            <>
              {item.name}
              <EditOutlined title="编辑" className="ml-10" onClick={() => handleTreeNode(item, "INFO")} />
              <DeleteOutlined title="删除" className="ml-10" onClick={() => handleTreeNode(item, "DEL")} />
            </>
          } 
          key={item.code} 
          icon={<IconFontConfig type={(item.type === 3 || item.type === "BTN") ? "icon-btn" : "icon-menu"} style={{fontSize: '14px'}} />} 
        /> 
      )
    })
  };

  // 点击TreeNode
  const handleTreeNode = (item, type) => {
    if (type === "INFO") {
      dispatch({type: 'Application/changeState', payload: {
        oldInfo: {...item},
        dataModal: {
          modalType: 'AUTH_SET_MODAL',
          modalShow: true,
          modalData: {...item, isEdit: true}
        }
      }})
    } else if (type === "DEL") {
      const { data, dataMenu, dataExpandedKeys } = getDelAuthData(dataAuth, item, 'DEL');
      Modal.confirm({
        title: '确定删除吗?',
        icon: <ExclamationCircleOutlined />,
        okText: '确定',
        cancelText: '取消',
        onOk() {
          dispatch({type: 'Application/changeState', payload: { 
            dataAuth: JSON.parse(JSON.stringify(data)),
            dataMenuList: JSON.parse(JSON.stringify(dataMenu)),
            dataExpandedKeys: JSON.parse(JSON.stringify(dataExpandedKeys))
          }});
        }
      });
    }
  };

  // 点击Tree
  const handleOnExpand = (expandedKeys) => {
    dispatch({type: 'Application/changeState', payload: { 
      dataExpandedKeys: expandedKeys
    }});
  };

  // 保存应用
  const handleSaveApplication = () => {
    let permissionList = getPermissionList(dataAuth);
    form.validateFields().then(values => {
      dispatch({type: 'Application/updateApplication', payload: {
        ...values,
        id,
        permissionList
      }})
    })
  };

  /* 拖拽排序 */
  const onDrop = info => {
    const dropKey = info.node.props.eventKey;
    const dragKey = info.dragNode.props.eventKey;
    const dropPos = info.node.props.pos.split('-');
    const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);

    const loop = (data, key, callback) => {
      for (let i = 0; i < data.length; i++) {
        if (data[i].key === key) {
          return callback(data[i], i, data);
        }
        if (data[i].subPermissionList) {
           loop(data[i].subPermissionList, key, callback);
        }
      }
    };
    let dataStateAuth = JSON.parse(JSON.stringify(dataAuth));
    const data = [...dataStateAuth];

    // Find dragObject
    let dragObj;
    loop(data, dragKey, (item, index, arr) => {
      arr.splice(index, 1);
      dragObj = item;
    });

    if (!info.dropToGap) {
      // Drop on the content
      loop(data, dropKey, item => {
        item.subPermissionList = item.subPermissionList || [];
        // where to insert 示例添加到尾部,可以是随意位置
        item.subPermissionList.push(dragObj);
      });
    } else if (
      (info.node.props.subPermissionList || []).length > 0 && 
      info.node.props.expanded && 
      dropPosition === 1 
    ) {
      loop(data, dropKey, item => {
        item.subPermissionList = item.subPermissionList || [];
        // where to insert 示例添加到头部,可以是随意位置
        item.subPermissionList.unshift(dragObj);
      });
    } else {
      let ar;
      let i;
      loop(data, dropKey, (item, index, arr) => {
        ar = arr;
        i = index;
      });
      if (dropPosition === -1) {
        ar.splice(i, 0, dragObj);
      } else {
        ar.splice(i + 1, 0, dragObj);
      }
    }
    let { dataDragAuth, dataMenu, dataExpandedKeys } = getDragData(data);
    dispatch({type: 'Application/changeState', payload: { 
      dataAuth: JSON.parse(JSON.stringify(dataDragAuth.length > 0 ? dataDragAuth : dataAuth)),
      dataMenuList: JSON.parse(JSON.stringify(dataMenu)),
      dataExpandedKeys: JSON.parse(JSON.stringify(dataExpandedKeys))
    }});
  };

  /* 清空所有权限 */
  const handleRemoveAuth = () => {
    Modal.confirm({
      title: '确定清空该应用权限的相关数据吗?',
      icon: <ExclamationCircleOutlined />,
      okText: '确定',
      cancelText: '取消',
      onOk() {
        dispatch({type: 'Application/changeState', payload: { 
          dataAuth: [],
          dataMenuList: [],
          dataExpandedKeys: []
        }});
      }
    });
  }; 

  return (
    <div className="box-info">
      <Breadcrumb>
        <Breadcrumb.Item><Link to="/appliction">应用列表</Link></Breadcrumb.Item>
        <Breadcrumb.Item>{!id ? '新建应用' : '编辑应用'}</Breadcrumb.Item>
      </Breadcrumb>
      <Spin spinning={id ? loading : false}>
        <Card bordered={false} className="mt-15">
          <Form
            {...layout}
            form={form}
            name="applicationInfo"
          >
            <Form.Item
              label="应用名称"
              name="name"
              rules={[{ required: true, message: '请输入应用名称' }]}
            >
              <Input placeholder="请输入应用名称" />
            </Form.Item>
            <Form.Item
              label="应用标识码"
              name="code"
            >
              <Input placeholder="请输入应用标识码" />
            </Form.Item>
            <Form.Item
              label="应用Api域名地址"
              name="apiDomain"
            >
              <Input placeholder="请输入应用api域名地址" />
            </Form.Item>
            <Form.Item
              label="应用链接地址"
              name="url"
            >
              <Input placeholder="请输入应用链接地址" />
            </Form.Item>
            <Form.Item label="权限服务模板">
              <Button onClick={handleAddTemp}>添加</Button>
            </Form.Item>
            <Form.Item label="权限预览" className="view-tree-auth">
              {
                dataAuth.length > 0 ? 
                (
                  <Tree
                    showLine
                    showIcon
                    draggable
                    selectedKeys={[]}
                    className="info-tree"
                    onExpand={handleOnExpand}
                    expandedKeys={dataExpandedKeys}
                    onDrop={onDrop}
                  >
                    {renderTreeNode(dataAuth)}
                  </Tree>
                )
                :
                <span>暂无数据</span>
              }
            </Form.Item>
            <Form.Item className="footer-btn" wrapperCol={{span: 24}}>
              <Button disabled={!dataAuth.length} onClick={handleRemoveAuth} className="mr-10">清空权限</Button>
              <Button loading={isRepeat} onClick={handleSaveApplication} type="primary" className="ml-10">保存应用</Button>
            </Form.Item>
          </Form>
        </Card>
        {/* 设置权限抽屉 */}
        <ModalSetAuth 
          dataModal={dataModal}
          dataMenuList={dataMenuList}
          handleAuthSetOk={handleAuthSetOk}
          handleCancelModal={handleCancelModal}
        />
      </Spin>
    </div>
  )
};

export default connect(({ Application, loading }) => ({
  ...Application,
  isRepeat: loading.effects["Application/updateApplication"],
  loading: loading.effects["Application/getApplicationInfo"]
}))(ApplicationInfo);