前端模拟文件资源管理器

930 阅读6分钟

类似Xftp这种本地文件传到服务端在网页的实现

需要开发本地应用,可以获取本地的目录文件信息,通过接口通过应用去获取本地的目录文件信息,上传也是通过应用去上传

1.gif

接口

getDir接口  传入path
初始化传入的是空字符串,返回
{
  "fileList": [
    {
      "name": "C",
      "type": "disk",
      "path": "C:/"
    },
    {
      "name": "D",
      "type": "disk",
      "path": "D:/"
    }
  ],
  "msg": "ok",
  "msg-no": 0,
  "system": "windows"
}
如果是硬盘,传的是D:/ ,带后缀斜杆
文件夹,传的是 C:/Users,不带后缀斜杆
传入C:/user,返回
{
  "fileList": [
    {
      "name": "All Users",
      "type": "file",
      "path": "C:/Users/All Users"
    },
    {
      "name": "Default",
      "type": "dir",
      "path": "C:/Users/Default"
    },
    {
      "name": "Default User",
      "type": "file",
      "path": "C:/Users/Default User"
    }
  ],
  "msg": "ok",
  "msg-no": 0,
  "system": "windows"
}

资源管理器

table来实现文件列表,主要是双击,单击有现成的api可以用,挺方便吧,看下面

 <Table
 onRow={(record, index, b) => {
                    return {
                      onDoubleClick:

渲染文件列表

componentDidMount() {
    // 初始化两个表格数据
    this.getFilesFromPath("");
}
 getFilesFromPath = (path, type) => {
    // 去掉 S:/壁纸/ 这种 后面的斜杆 C:/这种不用去
    if (path.endsWith("/") && path.lastIndexOf("/") > 2) {
      path = path.slice(0, -1);
    }
    getDir(path)
      .then((res) => {
        this.setState({ nowChangePath: path });
        if (res.data["msg-no"] !== 0) {
          message.info("没有这个路径!", 2);
          this.setState({ nowChangePath: this.state.nowPath });
          return;
        }
        let fileList = res?.data?.fileList;
        let prePath;
        //这里获取上一层目录路径
        let singleFolder = path.indexOf("/") == path.lastIndexOf("/");
        if (singleFolder) {
          if (path.indexOf("/") + 1 == path.length) {
            prePath = "";
          } else {
            prePath = path.slice(0, path.indexOf("/") + 1);
          }
        } else {
          prePath = path.slice(0, path.lastIndexOf("/"));
        }
        //筛选掉一些文件,只显示需要的类型的文件,
        fileList = fileList.filter((i) => {
          if (i.type == "file") {
            let after = i.name.split(".").pop();
              //allowedFileTypes :['jpg','png']
            if (!this.allowedFileTypes.includes(after.toLowerCase())) {
              return false;
            } else {
              let color = "";
              switch (after.toLowerCase()) {
                case "tif":
                case "tiff":
                  color = "#91BE89";
                  break;
                      //。。。
                default:
                  break;
              }

              i.icon = <PictureOutlined style={{ ...this.iconStyle, color }} />;
              return true;
            }
          } else if (i.type == "disk") {
            i.icon = (
              <Icon component={disk} name="disk" style={this.iconStyle} />
            );
          } else if (i.type == "dir") {
            i.icon = (
              <FolderFilled style={{ ...this.iconStyle, color: "#f8b700" }} />
            );
          }
          return true;
        });
	//如果不是在disk,要有个双击可以返回上一层的文件夹显示
        if (!fileList[0] || fileList[0].type !== "disk") {
          fileList.unshift({
            name: "..",
            type: "dir",
            path: prePath,
          });
        }
        this.setState({ fileList, nowPath: path });
      })
      .catch((e) => {
        console.log({ e });
      });
  };

<Table
                  sticky={true}
                  columns={columns}
                  dataSource={fileList}
                  pagination={false}
                  rowClassName="rowStyle"
                  rowKey="path"

ctrl,shift+单击选文件

表格rowClassName="rowStyle"

文件选中后样式改为pathSelected,获取文件直接通过dom选择器得到选中的文件

至于为什么不用变量数组存,我觉得用dom上存的挺好呀,进入上下层文件夹也不用清空数组,样式变的也挺快

用数组存的话也要搞样式,那不如只搞样式呗

逻辑最复杂的应当是shift+click多选

单击选中,其他全不选

ctrl多选,选中的改为不选,不选的改为选

shift的多选,从nowSelected选中元素到当前元素,如果nowSelected为空,从最前面到当前元素

 <Table
                  sticky={true}
                  columns={columns}
                  dataSource={fileList}
                  pagination={false}
                  rowClassName="rowStyle"
                  rowKey="path"
                  onRow={(record, index) => {
                    return {
                      onDoubleClick: (event) => {
                        if (record.name == "..") {
                          this.setState({ nowSelected: "" });
                        }
                        // console.log({ record }, 233);
                        if (record.type !== "file") {
                          this.getFilesFromPath(record.path);
                        }
                      },
                      onClick: (event) => {
        
                        if (record.name == "..") return;
                        //   分三种情况,单点
                        let status = "click";
                        if (event.ctrlKey) {
                          status = "ctrlKey";
                        }
                        if (event.shiftKey) {
                          status = "shiftKey";
                        }
                        if (status == "click") {
                          this.setState({
                            nowSelected: event.target.parentNode,
                          });
                          document
                            .querySelectorAll(".pathSelected")
                            .forEach((i) => (i.className = ""));
                          event.target.className = "pathSelected";
                        } else if (status == "ctrlKey") {
                          this.setState({
                            nowSelected: event.target.parentNode,
                          });
                          event.target.className === "pathSelected"
                            ? (event.target.className = "")
                            : (event.target.className = "pathSelected");
                        } else if (status == "shiftKey") {
                          //   所有的已选
                          let selected = Array.from(
                            document.querySelectorAll(".pathSelected")
                          );
                          // 所有的列表
                          let row = Array.from(
                            document.querySelectorAll(".rowStyle")
                          );
                          // 去掉上一级的这个文件夹
                          if (row[0].innerText == "..") {
                            row = row.slice(1);
                          }
                          console.log({ selected, row });
                          //   一个都么有
                          if (selected.length == 0) {
                            //   console.log("??");
                            for (let i = 0; i < index; i++) {
                              row[i].childNodes[0].className = "pathSelected";
                            }
                          } else if (selected.length >= 1) {
                            document
                              .querySelectorAll(".pathSelected")
                              .forEach((i) => (i.className = ""));
                            // 只有一个
                            // 有多个
                            let firstIndex = row.indexOf(
                              this.state.nowSelected
                            );
                            if (firstIndex >= index) {
                              for (let i = index - 1; i < firstIndex + 1; i++) {
                                row[i].childNodes[0].className = "pathSelected";
                              }
                            } else {
                              for (let i = firstIndex; i < index; i++) {
                                row[i].childNodes[0].className = "pathSelected";
                              }
                            }
                          }
                        }
                      }, // 点击行
                    };
                  }}
                />

双击进入子文件夹

具体参考上面的

onDoubleClick: (event) => {
                        if (record.name == "..") {
                          this.setState({ nowSelected: "" });
                        }
                        // console.log({ record }, 233);
                        if (record.type !== "file") {
                          this.getFilesFromPath(record.path);
                        }
                      },

ctrl+a全选文件

document.onkeydown = function (e) {
      var keyCode = e.keyCode || e.which || e.charCode;
      var ctrlKey = e.ctrlKey;
      // 拦截 ctrl+a ,把第一个表格的文件都改样式
      if (ctrlKey && keyCode == 65) {
        let row = Array.from(document.querySelectorAll(".table1 .rowStyle"));
        if (row[0].innerText == "..") {
          row = row.slice(1);
        }
        row.forEach((i) => (i.childNodes[0].className = "pathSelected"));
        e.preventDefault();
      }
    };

计算父文件夹路径

   path:当前路径
   prePath:上层路径
   //如果只有一个斜杆,说明是硬盘,上层就是空
   //如果多个斜杆,截取最后一个斜杆前的字符串
   let singleFolder = path.indexOf("/") == path.lastIndexOf("/");
        if (singleFolder) {
          if (path.indexOf("/") + 1 == path.length) {
            prePath = "";
          } else {
          //忘记为啥这样做了
            prePath = path.slice(0, path.indexOf("/") + 1);
          }
        } else {
          prePath = path.slice(0, path.lastIndexOf("/"));
        }

支持通过输入修改路径

<Input
                  style={{ margin: "0 10px" }}
                  size="small"
                  value={nowChangePath}
                  onChange={this.nowPathChange}
                  onPressEnter={(e) =>
                    this.getFilesFromPath(e.target.value)
                  }
                />
  nowPathChange = (e, type) => {
    let value = e.target.value;
    let path = type ? "nowRemoteChangePath" : "nowChangePath";
    this.setState({ [path]: value });
  };
getFilesFromPath:参考 渲染文件列表

跳转后路径焦点聚焦到最后面

this.remoteInputRef.current.focus({
          cursor: "end",
        });

样式

主要是边距,字体,文件选中的样式。

# index.scss
.uploadModal {
  .ant-modal-body {
    padding: 24px 24px 0;
  }
  .ant-table-thead {
    line-height: 0;
  }
  .rowStyle {
      //rowStyle嵌pathSelected,选中的时候容易选错地方,所以要设user-select: none;
    line-height: 0;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    .ant-table-cell {
      padding: 0 !important;
      border: none;
    }
  }
  .ant-table-tbody > tr > td {
    padding: 0 !important;
    border: none;
  }
  .pathSelected {
    background-color: #cce8ff !important;
    padding: 0 !important;
  }
  .progressText {
    position: absolute;
    left: 60px;
    z-index: 999;
  }
  .ant-progress-success-bg,
  .ant-progress-bg {
    border-radius: 0;
  }
  .ant-progress-inner {
    border-radius: 0;
  }
}

全代码

import React, { Component } from "react";
import { Modal, Input, Button, Table, message } from "antd";
import Icon, {
  UndoOutlined,
  PictureOutlined,
  FolderFilled,
  FileFilled,
  ArrowUpOutlined,
} from "@ant-design/icons";
import { ReactComponent as disk } from "../../../shared/img/files/disk.svg";
import axios from "axios";
import { getDir, uploadFile } from "./file.js";
export default class UploadModal extends Component {
  state = {
    fileList: [], //第一个表格的数据
    remoteFileList: [],
    nowPath: "", //本地当前路径
    nowChangePath: "", //本地路径更改
    nowRemoteChangePath: "", //远程更改路径
    nowSelected: "", //当前点击选中元素
    remotePath: window.localStorage.getItem("remotePath") || "/datasets", //远程当前路径
  };
  remoteInputRef = React.createRef();
    //第一个表格文件里要筛选展示的文件类型,其他的不要
  allowedFileTypes = [
    "tif",
    "tiff",
    "tmap",
    "kfb",
    "mrxs",
    "svs",
    "sdpc",
    "zyp",
    "czi",
    "png",
    "jpg",
    // 下面很少见,可以搞掉
    "svslide",
    "vms",
    "ndpi",
    "scn",
    "bif",
    "ini",
    "dat",
  ];
  iconStyle = { marginRight: "5px", pointerEvents: "none" };
  orgForm = React.createRef();
  componentDidMount() {
    // 初始化两个表格数据
    this.getFilesFromPath("");
    this.getFilesFromRemotePath(this.state.remotePath);
    document.onkeydown = function (e) {
      var keyCode = e.keyCode || e.which || e.charCode;
      var ctrlKey = e.ctrlKey;
      // 拦截 ctrl+a ,把第一个表格的文件都改样式
      if (ctrlKey && keyCode == 65) {
        let row = Array.from(document.querySelectorAll(".table1 .rowStyle"));
        if (row[0].innerText == "..") {
          row = row.slice(1);
        }
        row.forEach((i) => (i.childNodes[0].className = "pathSelected"));
        e.preventDefault();
      }
    };
    // xiao
  }
  componentWillUnmount() {
    document.onkeydown = null;
  }
  // 传入路径,得到对应的文件列表
  getFilesFromPath = (path, type) => {
    // 去掉 S:/壁纸/ 这种 后面的斜杆 C:/这种不用去
    if (path.endsWith("/") && path.lastIndexOf("/") > 2) {
      path = path.slice(0, -1);
      console.log({ path });
    }
    getDir(path)
      .then((res) => {
        this.setState({ nowChangePath: path });
        if (res.data["msg-no"] !== 0) {
          message.info("没有这个路径!", 2);
          this.setState({ nowChangePath: this.state.nowPath });
          return;
        }
        let fileList = res?.data?.fileList;
        let prePath;
        let singleFolder = path.indexOf("/") == path.lastIndexOf("/");
        if (singleFolder) {
          if (path.indexOf("/") + 1 == path.length) {
            prePath = "";
          } else {
            prePath = path.slice(0, path.indexOf("/") + 1);
          }
        } else {
          prePath = path.slice(0, path.lastIndexOf("/"));
        }
        //这一条是筛选出allowedFileTypes包含类型的文件,并赋予相应的特殊图标颜色
        fileList = fileList.filter((i) => {
          if (i.type == "file") {
            let after = i.name.split(".").pop();
            if (!this.allowedFileTypes.includes(after.toLowerCase())) {
              // if (!this.allowedFileTypes.includes(after)) {
              return false;
            } else {
              let color = "";
              switch (after.toLowerCase()) {
                case "tif":
                case "tiff":
                  color = "#91BE89";
                  break;
                case "tmap":
                  color = "#184C0E";
                  break;
                case "kfb":
                  color = "#E2FF85";
                  break;
                case "mrxs":
                  color = "#92BA0F";
                  break;
                case "svs":
                  color = "#8FA058";
                  break;
                case "sdpc":
                  color = "#757703";
                  break;
                case "zyp":
                  color = "#989A40";
                  break;
                case "czi":
                  color = "#F2DD92";
                  break;
                case "png":
                  color = "#0c7d9d";
                  break;
                case "jpg":
                  color = "#0c7d9d";
                  break;
                default:
                  break;
              }

              i.icon = <PictureOutlined style={{ ...this.iconStyle, color }} />;
              return true;
            }
          } else if (i.type == "disk") {
            i.icon = (
              <Icon component={disk} name="disk" style={this.iconStyle} />
            );
          } else if (i.type == "dir") {
            i.icon = (
              <FolderFilled style={{ ...this.iconStyle, color: "#f8b700" }} />
            );
          }
          return true;
        });

        if (!fileList[0] || fileList[0].type !== "disk") {
          fileList.unshift({
            name: "..",
            type: "dir",
            path: prePath,
          });
        }
        // if(!this.state.ifRunSoftware){this.setState({ifRunSoftware:true})}
        this.setState({ fileList, nowPath: path });
        //   console.log({ fileList });
      })
      .catch((e) => {
        console.log({ e });
      });
  };
  getFilesFromRemotePath = (remotePath) => {
    if (!remotePath.startsWith("/datasets")) {
      message.info("只能访问以 /datasets 开头的文件夹");
      return;
    }
    if (remotePath.endsWith("/")) {
      remotePath = remotePath.slice(0, -1);
    }
    axios
      .get(
        `${process.env.REACT_APP_BASE_APP.slice(
          0,
          -4
        )}/client_api/content?path=${remotePath}`
      )
      .then((res) => {
        this.setState({ nowRemoteChangePath: remotePath });
        if (res.data["msg-no"] !== 0) {
          message.info("没有这个路径!", 2);
          this.setState({ nowRemoteChangePath: this.state.remotePath });
          return;
        }
        window.localStorage.setItem("remotePath", remotePath);
        this.remoteInputRef.current.focus({
          cursor: "end",
        });
        let fileList = res?.data?.fileList;
        let prePath = remotePath.slice(0, remotePath.lastIndexOf("/"));
        fileList = fileList.filter((i) => {
          if (i.type == "file") {
            let after = i.name.split(".").pop();
            //   console.log({ after });
            if (!this.allowedFileTypes.includes(after.toLowerCase())) {
              i.icon = (
                <FileFilled style={{ ...this.iconStyle, color: "#aaa" }} />
              );
              //   return false;
              return true;
            } else {
              let color = "";
              switch (after.toLowerCase()) {
                case "tif":
                case "tiff":
                  color = "#91BE89";
                  break;
                case "tmap":
                  color = "#184C0E";
                  break;
                case "kfb":
                  color = "#E2FF85";
                  break;
                case "mrxs":
                  color = "#92BA0F";
                  break;
                case "svs":
                  color = "#8FA058";
                  break;
                case "sdpc":
                  color = "#757703";
                  break;
                case "zyp":
                  color = "#989A40";
                  break;
                case "czi":
                  color = "#F2DD92";
                  break;
                case "png":
                  color = "#0c7d9d";
                  break;
                case "jpg":
                  color = "#0c7d9d";
                  break;
                case "svslide":
                case "dat":
                case "vms":
                case "ndpi":
                case "scn":
                case "bif":
                case "ini":
                  color = "#aaa";
                  break;
                default:
                  break;
              }
              i.icon = <PictureOutlined style={{ ...this.iconStyle, color }} />;
              return true;
            }
          } else if (i.type == "disk") {
            i.icon = (
              <Icon component={disk} name="disk" style={this.iconStyle} />
            );
          } else if (i.type == "dir") {
            i.icon = (
              <FolderFilled style={{ ...this.iconStyle, color: "#f8b700" }} />
            );
          }
          return true;
        });
        if (remotePath !== "/datasets") {
          fileList.unshift({
            name: "..",
            type: "dir",
            path: prePath,
          });
        }
        this.setState({ remoteFileList: fileList, remotePath });
      });
  };
  upDir = (type) => {
    let { fileList, remoteFileList } = this.state;
    let list = type == "remote" ? remoteFileList : fileList;
    if (list[0].name == "..") {
      let fun =
        type == "remote" ? this.getFilesFromRemotePath : this.getFilesFromPath;
      fun(list[0].path);
    } else {
      message.info("不能再上一层了", 2);
    }
  };
  upload = async () => {
    let selected = Array.from(document.querySelectorAll(".pathSelected"));
    if (selected.length == 0) {
      message.info("请选择至少一个文件", 2);
      return;
    }
    try {
      await this.orgForm.current.validateFields();
      let value = this.orgForm.current.getFieldsValue();
      value.slide_type = value.slide_type?.[0];
      selected = selected.map((i) => i.parentNode.getAttribute("data-row-key"));
      document
        .querySelectorAll(".pathSelected")
        .forEach((i) => (i.className = ""));
      let upload_folder = this.state.remotePath;
      let { user_id } = this.state;
      let file_list = selected.map((i) => ({
        path: i,
        upload_folder,
        user_id,
        ...value,
      }));
      console.log({ file_list });
      uploadFile({ file_list }).then((res) => {
        if (res.data.data.failList.length > 0) {
          message.info(res.data.data.failList[0].errMsg, 2);
        } else {
          message.success("操作成功", 2);
        }
      });
      console.log({ file_list });
      setTimeout(
        () => this.getFilesFromRemotePath(this.state.remotePath),
        1000
      );
    } catch (err) {
      message.error("上面的选项要填才可以上传喔", 2);
    }
  };
  nowPathChange = (e, type) => {
    let value = e.target.value;
    let path = type ? "nowRemoteChangePath" : "nowChangePath";
    this.setState({ [path]: value });
  };
  render() {
    const {
      fileList,
      diseases,
      origins,
      nowChangePath,
      remoteFileList,
      nowRemoteChangePath,
      createPathLoading,
    } = this.state;
    const { visible, onCancel } = this.props;
    const columns = [
      {
        title: "名字",
        dataIndex: "name",
        render: (text, record) => (
          <div style={{ padding: "4px", height: 20, pointerEvents: "none" }}>
            {record.icon}
            <span
              style={{
                fontSite: "12px",
                fontWeight: "normal",
                pointerEvents: "none",
              }}
            >
              {text}
            </span>
          </div>
        ),
      },
    ];
    return (
      <Modal
        className="uploadModal"
        title="上传"
        visible={visible}
        footer={null}
        width="90%"
        onCancel={onCancel}
        centered={true}
        destroyOnClose
      >
        <div style={{ display: "flex", height: 400 }}>
          <div
            style={{
              flex: 1,
              height: "100%",
              flexDirection: "column",
              display: "flex",
            }}
          >
            <div
              style={{
                display: "flex",
                justifyContent: "space-between",
                background: "#eee",
              }}
            >
              <div style={{ display: "flex", height: 32, flex: 1 }}>
                <span
                  style={{ padding: 5, background: "#aaa", cursor: "pointer" }}
                  onClick={this.upDir.bind(this, "local")}
                >
                  <ArrowUpOutlined />
                </span>

                <span
                  style={{
                    padding: 5,
                    width: 50,
                    marginLeft: 10,
                    // marginRight: 10,
                  }}
                >
                  本地
                </span>
                <Input
                  style={{ margin: "0 10px" }}
                  size="small"
                  value={nowChangePath}
                  onChange={this.nowPathChange}
                  onPressEnter={(e) =>
                    this.getFilesFromPath(e.target.value, "change")
                  }
                />
              </div>
              <span
                style={{ background: "#aaa", padding: 5, cursor: "pointer" }}
                onClick={() => this.getFilesFromPath(this.state.nowPath)}
              >
                <UndoOutlined />
              </span>
            </div>
            <div style={{ flex: 1, overflow: "auto" }} className="table1">
              {fileList.length > 0 ? (
                <Table
                  sticky={true}
                  columns={columns}
                  dataSource={fileList}
                  pagination={false}
                  rowClassName="rowStyle"
                  rowKey="path"
                  onRow={(record, index, b) => {
                    return {
                      onDoubleClick: (event) => {
                        if (record.name == "..") {
                          this.setState({ nowSelected: "" });
                        }
                        // console.log({ record }, 233);
                        if (record.type !== "file") {
                          this.getFilesFromPath(record.path);
                        }
                      },
                      onClick: (event) => {
                        //   console.log(
                        //     event.target.parentNode.getAttribute("data-row-key")
                        //   );
                        if (record.name == "..") return;
                        //   分三种情况,单点
                        let status = "click";
                        if (event.ctrlKey) {
                          status = "ctrlKey";
                        }
                        if (event.shiftKey) {
                          status = "shiftKey";
                        }
                        if (status == "click") {
                          this.setState({
                            nowSelected: event.target.parentNode,
                          });
                          document
                            .querySelectorAll(".pathSelected")
                            .forEach((i) => (i.className = ""));
                          event.target.className = "pathSelected";
                        } else if (status == "ctrlKey") {
                          this.setState({
                            nowSelected: event.target.parentNode,
                          });
                          event.target.className === "pathSelected"
                            ? (event.target.className = "")
                            : (event.target.className = "pathSelected");
                        } else if (status == "shiftKey") {
                          //   所有的已选
                          let selected = Array.from(
                            document.querySelectorAll(".pathSelected")
                          );
                          // 所有的列表
                          let row = Array.from(
                            document.querySelectorAll(".rowStyle")
                          );
                          // 去掉上一级的这个文件夹
                          if (row[0].innerText == "..") {
                            row = row.slice(1);
                          }
                          console.log({ selected, row });
                          //   一个都么有
                          if (selected.length == 0) {
                            //   console.log("??");
                            for (let i = 0; i < index; i++) {
                              row[i].childNodes[0].className = "pathSelected";
                            }
                          } else if (selected.length >= 1) {
                            document
                              .querySelectorAll(".pathSelected")
                              .forEach((i) => (i.className = ""));
                            // 只有一个
                            // 有多个
                            let firstIndex = row.indexOf(
                              this.state.nowSelected
                            );
                            if (firstIndex >= index) {
                              for (let i = index - 1; i < firstIndex + 1; i++) {
                                row[i].childNodes[0].className = "pathSelected";
                              }
                            } else {
                              for (let i = firstIndex; i < index; i++) {
                                row[i].childNodes[0].className = "pathSelected";
                              }
                            }
                          }
                        }
                      }, // 点击行
                    };
                  }}
                />
              ) : (
                <div>
                  插件不能正常运行,尝试下载最新的插件,
                  <a
                    href="/cvs_client/CVSClient_Setup_x64_1.0.0.8.exe"
                    target="_blank"
                    style={{ color: "blue" }}
                  >
                    点此下载插件
                  </a>
                </div>
              )}
            </div>
          </div>
          <div
            style={{
              width: 100,
              height: "100%",
              background: "#eee",
              display: "flex",
              justifyContent: "center",
              alignItems: "center",
              flexDirection: "column",
            }}
          >
            {/* <Button type="primary" onClick={this.upload}> */}
            <Button type="primary" onClick={this.upload}>
              2、上传
            </Button>
          </div>
          <div
            style={{
              flex: 1,
              height: "100%",
              flexDirection: "column",
              display: "flex",
            }}
          >
            <div
              style={{
                // marginLeft: 10,
                background: "#eee",
                display: "flex",
                justifyContent: "space-between",
              }}
            >
              <div style={{ display: "flex", height: 32, flex: 1 }}>
                <span
                  style={{ padding: 5, background: "#aaa", cursor: "pointer" }}
                  onClick={this.upDir.bind(this, "remote")}
                >
                  <ArrowUpOutlined />
                </span>
                <span
                  style={{
                    padding: 5,
                    width: 50,
                    marginLeft: 10,
                  }}
                >
                  远程
                </span>
                <Input
                  style={{ margin: "0 10px" }}
                  size="small"
                  ref={this.remoteInputRef}
                  value={nowRemoteChangePath}
                  onChange={(e) => this.nowPathChange(e, "remote")}
                  onPressEnter={(e) =>
                    this.getFilesFromRemotePath(e.target.value)
                  }
                />
              </div>
              <span
                style={{
                  background: "#aaa",
                  padding: 5,
                  cursor: "pointer",
                }}
                onClick={() =>
                  this.getFilesFromRemotePath(this.state.remotePath)
                }
              >
                <UndoOutlined />
              </span>
            </div>
            <div style={{ flex: 1, overflow: "auto" }}>
              <Table
                columns={columns}
                dataSource={remoteFileList}
                pagination={false}
                sticky={true}
                rowClassName="rowStyle"
                rowKey="path"
                onRow={(record, index, b) => {
                  return {
                    onDoubleClick: (event) => {
                      if (record.name == "..") {
                        this.setState({ nowSelected: "" });
                      }
                      console.log({ record }, 233);
                      if (record.type !== "file") {
                        this.getFilesFromRemotePath(record.path, record.name);
                      }
                    },
                  };
                }}
              />
            </div>
          </div>
        </div>
      </Modal>
    );
  }
}