bill_lai před 5 roky
rodič
revize
a0e7bef313
39 změnil soubory, kde provedl 1466 přidání a 62 odebrání
  1. 11 1
      package.json
  2. 2 1
      public/index.html
  3. 13 0
      src/index.css
  4. 0 22
      src/App.css
  5. 0 9
      src/App.test.tsx
  6. 0 26
      src/App.tsx
  7. 5 0
      src/http.ts
  8. 17 2
      src/index.tsx
  9. 0 1
      src/logo.svg
  10. 16 0
      src/page/Home/index.module.css
  11. 26 0
      src/page/Home/index.tsx
  12. 78 0
      src/page/List/GeoList.tsx
  13. 124 0
      src/page/List/GrentOper.tsx
  14. 112 0
      src/page/List/ListState/action.ts
  15. 4 0
      src/page/List/ListState/actionType.ts
  16. 20 0
      src/page/List/ListState/index.ts
  17. 43 0
      src/page/List/ListState/reducer.ts
  18. 2 0
      src/page/List/ListState/selector.ts
  19. 12 0
      src/page/List/ListState/state.ts
  20. 25 0
      src/page/List/ListState/type.d.ts
  21. 21 0
      src/page/List/ModelList.tsx
  22. 181 0
      src/page/List/ResterList.tsx
  23. 106 0
      src/page/List/grent.tsx
  24. 58 0
      src/page/List/index.module.css
  25. 11 0
      src/page/StyleEdit/index.tsx
  26. 29 0
      src/page/components/List/index.tsx
  27. 28 0
      src/page/components/Paging/index.module.css
  28. 45 0
      src/page/components/Paging/index.tsx
  29. 51 0
      src/page/components/Tab/index.module.css
  30. 51 0
      src/page/components/Tab/index.tsx
  31. 27 0
      src/page/components/Upload/Item.tsx
  32. 12 0
      src/page/components/Upload/Step.tsx
  33. 4 0
      src/page/components/Upload/constant.ts
  34. 11 0
      src/page/components/Upload/file.d.ts
  35. 89 0
      src/page/components/Upload/index.module.css
  36. 145 0
      src/page/components/Upload/index.tsx
  37. 26 0
      src/page/components/item/index.module.css
  38. 47 0
      src/page/components/item/index.tsx
  39. 14 0
      src/setupProxy.js

+ 11 - 1
package.json

@@ -7,8 +7,14 @@
     "@types/node": "12.12.9",
     "@types/react": "16.9.11",
     "@types/react-dom": "16.9.4",
+    "@types/react-router": "^5.1.3",
+    "@types/react-router-dom": "^5.1.3",
+    "axios": "^0.19.0",
+    "history": "^4.10.1",
     "react": "^16.12.0",
     "react-dom": "^16.12.0",
+    "react-router": "^5.1.2",
+    "react-router-dom": "^5.1.2",
     "react-scripts": "3.2.0",
     "typescript": "3.7.2"
   },
@@ -32,5 +38,9 @@
       "last 1 firefox version",
       "last 1 safari version"
     ]
-  }
+  },
+  "devDependencies": {
+    "http-proxy-middleware": "^0.20.0"
+  },
+  "homepage": "."
 }

+ 2 - 1
public/index.html

@@ -2,6 +2,7 @@
 <html lang="en">
   <head>
     <meta charset="utf-8" />
+    <link rel="stylesheet" href="%PUBLIC_URL%/style.css">
     <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1" />
     <meta name="theme-color" content="#000000" />
@@ -24,7 +25,7 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-    <title>React App</title>
+    <title>文件管理系统</title>
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

+ 13 - 0
src/index.css

@@ -11,3 +11,16 @@ code {
   font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
     monospace;
 }
+
+h1,
+h2,
+h3 {
+  font-weight: 400;
+  color: #1f2f3d;
+}
+
+
+.title {
+  font-size: 28px;
+  text-align: center;
+}

+ 0 - 22
src/App.css

@@ -1,22 +0,0 @@
-.App {
-  text-align: center;
-}
-
-.App-logo {
-  height: 40vmin;
-}
-
-.App-header {
-  background-color: #282c34;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  font-size: calc(10px + 2vmin);
-  color: white;
-}
-
-.App-link {
-  color: #09d3ac;
-}

+ 0 - 9
src/App.test.tsx

@@ -1,9 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './App';
-
-it('renders without crashing', () => {
-  const div = document.createElement('div');
-  ReactDOM.render(<App />, div);
-  ReactDOM.unmountComponentAtNode(div);
-});

+ 0 - 26
src/App.tsx

@@ -1,26 +0,0 @@
-import React from 'react';
-import logo from './logo.svg';
-import './App.css';
-
-const App: React.FC = () => {
-  return (
-    <div className="App">
-      <header className="App-header">
-        <img src={logo} className="App-logo" alt="logo" />
-        <p>
-          Edit <code>src/App.tsx</code> and save to reload.
-        </p>
-        <a
-          className="App-link"
-          href="https://reactjs.org"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Learn React
-        </a>
-      </header>
-    </div>
-  );
-}
-
-export default App;

+ 5 - 0
src/http.ts

@@ -0,0 +1,5 @@
+import axios from 'axios'
+
+axios.defaults.baseURL = '/api/'
+
+export default axios

+ 17 - 2
src/index.tsx

@@ -1,8 +1,23 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
-import './index.css';
-import App from './App';
 import * as serviceWorker from './serviceWorker';
+import {Route, Router, Redirect} from 'react-router'
+import { createHashHistory } from 'history'
+import Home from './page/Home'
+import StyleEdit from './page/StyleEdit'
+
+const history = createHashHistory()
+
+function App() {
+  return (
+    <Router history={history}>
+      <h1 className='title'>文件管理系统</h1>
+      <Route path="/home" component={Home} />
+      <Route path="/style/:id" component={StyleEdit} />
+      <Redirect from="/:a" to="/home" />
+    </Router>
+  )
+}
 
 ReactDOM.render(<App />, document.getElementById('root'));
 

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 1
src/logo.svg


+ 16 - 0
src/page/Home/index.module.css

@@ -0,0 +1,16 @@
+.layer {
+  padding: 15px;
+  width: 100%;
+  max-width: 1200px;
+  margin: 0 auto;
+}
+
+
+.fittitle {
+  font-size: 22px;
+  padding-top: 20px;
+}
+
+.list {
+  margin-top: 20px;
+}

+ 26 - 0
src/page/Home/index.tsx

@@ -0,0 +1,26 @@
+
+import React from 'react';
+import ResterList from '../List/ResterList'
+import ModelList from '../List/ModelList'
+import GeoList from '../List/GeoList'
+import Tab from '../components/Tab'
+import styles from './index.module.css'
+
+
+function Home() {
+  const changeHandle = (index: number) => sessionStorage.setItem('tabIndex', index.toString())
+  let indexStr = sessionStorage.getItem('tabIndex')
+  let index = indexStr ? Number(indexStr) : 1
+
+  return (
+    <div className={styles.layer}>
+      <Tab titles={['栅格数据', '3D模型', '矢量数据']} showIndex={index} changeHandle={changeHandle} >
+        <ResterList className={styles.list} />
+        <ModelList className={styles.list} />
+        <GeoList className={styles.list} />
+      </Tab>
+    </div>
+  )
+}
+
+export default Home

+ 78 - 0
src/page/List/GeoList.tsx

@@ -0,0 +1,78 @@
+import React, { useState } from 'react'
+import GrentReducer from './grent'
+import Upload from '../components/Upload'
+import { Link } from 'react-router-dom'
+import styles from './index.module.css'
+
+const infos = ['x平移米数', 'y平移米数', 'z平移米数', 'rx旋转米数', 'ry旋转米数', 'rz旋转米数', 's缩放',]
+
+
+export default function GeoList({ className }: any) {
+  const { referData, Element, models } = GrentReducer({
+    delUrl: '/vector/delete/',
+    getUrl: '/vector/list/',
+    zipUrl: '/vector/unzip/',
+    sectionUrl: '/vector/command/slice/',
+    transferUrl: '/vector/move/',
+    transformUrl: '/vector/command/geojson/',
+    judgeUrl: '/vector/command/judge/coord/',
+    ItemFn (model: Model) {
+      if (model.status === 8) {
+        return <Link to={"/style/" + model.id}>编辑样式</Link>
+      }
+    }
+  })
+
+  let [dir, setDir] = useState('')
+  let [coor, setCoor] = useState('')
+  let [info, setInfo] = useState('')
+
+  for (let i = 0; i < models.length; i++) {
+    let model = models[i] as Model
+    if (model.status !== 9) continue
+    setTimeout(() => referData(), 1000)
+    break;
+  }
+
+  const changeInput = (ev: React.ChangeEvent<HTMLInputElement>) => {
+    let val = (ev.target.value as string)
+    let args = val.split(',')
+    let i = 0
+    if (args.length > 7) {
+      return setInfo('参数超过限制')
+    }
+
+    if (!args[args.length - 1]) {
+      setInfo('正在输入' + infos[args.length - 1])
+    } else {
+      for (; i < args.length; i++) {
+        if (!args[i] || isNaN(Number(args[i]))) break;
+      }
+      if (i !== args.length) {
+        return setInfo(infos[i] + '格式不正确')
+      } else {
+        setInfo('正在输入' + infos[args.length - 1])
+      }
+    }
+    setCoor(ev.target.value)
+  }
+
+  return (
+    <div className={className}>
+      {Element}
+      <div className={styles.uplayer + ' ' + styles.inuplayer} >
+        <div className={styles.tip}>
+          输入坐标:<input value={coor} placeholder="输入对应坐标" onChange={changeInput} onFocus={changeInput} onBlur={() => setInfo('')} />
+          <div style={{ display: info ? 'block' : 'none' }}>
+            <p>{info}</p>
+            <p>以,(英文符号)结束输入,并输入下一个参数如0,0,0</p>
+          </div>
+        </div>
+        <div>
+          输入目录:<input value={dir} placeholder="输入对应文件夹" onChange={ev => setDir(ev.target.value)} />
+        </div>
+        <Upload api={'/vector/uploadMult/' + dir + '/'} body={{ coord: coor || null }} upHandle={referData} multiple />
+      </div>
+    </div>
+  )
+}

+ 124 - 0
src/page/List/GrentOper.tsx

@@ -0,0 +1,124 @@
+import React, { Fragment, useState } from 'react'
+import { zipItemAction, sectionItemAction, judgeItemAction, transferItemAction } from './ListState'
+import Item from '../components/item'
+
+const JUDGEING = 1, JUGESUCCESS = 2, JUGEERR = 3
+const SECTIONING = 4, SECTIONSUCCESS = 5, SECTIONEERR = 6
+const TRANING = 7, TRANSUCCESS = 8, TRANEERR = 9
+const ZIPING = 10, ZIPSUCCESS = 11, ZIPEERR = 12
+const TRANSFERING = 13, TRANSFERSUCCESS = 14, TRANSFEREERR = 15
+
+
+
+export default function Grent({ setItemStaus, modelDispatch, referData, delHandle, api }: any) {
+  const judge = async (model: Model) => {
+    model = setItemStaus(model, JUDGEING)
+    let data = await judgeItemAction(modelDispatch, api.judge + model.id + '/', model)
+
+    if (data.status !== 200) {
+      alert(data.message)
+      setItemStaus(model, JUGEERR)
+    } else {
+      setItemStaus(model, JUGESUCCESS)
+      referData()
+    }
+  }
+  const zipHandle = async (model: Model) => {
+    model = setItemStaus(model, ZIPING)
+    let data = await zipItemAction(modelDispatch, api.zip + model.id + '/', model)
+    if (data.status !== 200) {
+      alert(data.message)
+      setItemStaus(model, ZIPEERR)
+    } else {
+      setItemStaus(model, ZIPSUCCESS)
+      referData()
+    }
+
+  }
+  const section = async (model: Model) => {
+    model = setItemStaus(model, SECTIONING)
+    sectionItemAction(modelDispatch, api.section + model.id + '/', model)
+      .then(data => {
+        if (data.status !== 200) {
+          model = setItemStaus(model, SECTIONEERR)
+          alert(data.message)
+        } else {
+          model = setItemStaus(model, SECTIONSUCCESS)
+          referData()
+        }
+      });
+  }
+
+  const transform = async (model: Model) => {
+    model = setItemStaus(model, TRANING)
+    sectionItemAction(modelDispatch, api.transform + model.id + '/', model)
+      .then(data => {
+        if (data.status !== 200) {
+          model = setItemStaus(model, TRANEERR)
+          alert(data.message)
+        } else {
+          model = setItemStaus(model, TRANSUCCESS)
+          referData()
+        }
+      });
+  }
+
+  const transfer = async (model: Model) => {
+    model = setItemStaus(model, TRANSFERING)
+    transferItemAction(modelDispatch, api.transfer + model.id + '/', model, { text: text })
+      .then(data => {
+        if (data.status !== 200) {
+          model = setItemStaus(model, TRANSFEREERR)
+          alert(data.message)
+        } else {
+          model = setItemStaus(model, TRANSFERSUCCESS)
+          referData()
+        }
+      });
+  }
+
+  const ItemFn = (model: Model, privItem: Function | void) => {
+    let Zip: any = <b onClick={() => zipHandle(model)} style={{ cursor: 'pointer' }}>解压</b>
+    let Sect: any = <b onClick={() => section(model)} style={{ cursor: 'pointer' }}>切片</b>
+    let Jude: any = <b onClick={() => judge(model)} style={{ cursor: 'pointer' }}>判断</b>
+    let Tran: any = <b onClick={() => transform(model)} style={{ cursor: 'pointer' }}>转geojson</b>
+    let Tf: any = (
+      <Fragment>
+        <input type="text" value={text} onChange={ev => setText(ev.target.value)} placeholder="发布参数" />
+        <b onClick={() => transfer(model)} style={{ cursor: 'pointer' }}>发布</b>
+      </Fragment>
+    )
+
+    Zip = model.ajaxStatue === ZIPING ? '解压中…' : model.ajaxStatue === ZIPSUCCESS ? '成功解压' : Zip
+    Sect = model.ajaxStatue === SECTIONING ? '切片中…' : model.ajaxStatue === SECTIONSUCCESS ? '成功切片' : Sect
+    Jude = model.ajaxStatue === JUDGEING ? '判断中…' : model.ajaxStatue === JUGESUCCESS ? '成功判断' : Jude
+    Tran = model.ajaxStatue === TRANING ? '转换中…' : model.ajaxStatue === TRANSUCCESS ? '成功转换' : Tran
+    Tf = model.ajaxStatue === TRANSFERING ? '移动中…' : model.ajaxStatue === TRANSFEREERR ? '成功移动' : Tf
+
+    if (model.status === 9) {
+      Jude = '判断中…'
+    }
+    return (
+      <Item key={model.id} {...model} >
+        {() => (
+          <Fragment>
+            {api.zip && (model.status === 1 && Zip)}
+            {api.judge && ((model.status === 2 || model.status === 9) && Jude)}
+            {api.transform && ((model.status === 3 || model.status === 7) && Tran)}
+            {api.section && (model.status === 4 && Sect)}
+            {api.transfer && (model.status === 5 && Tf)}
+            <b onClick={() => delHandle(model)} style={{ cursor: 'pointer' }}>删除</b>
+            {privItem && privItem(model)}
+          </Fragment>
+        )}
+      </Item>
+    )
+  }
+
+  let [text, setText] = useState('')
+
+  return {
+    ItemFn,
+    text
+  }
+}

+ 112 - 0
src/page/List/ListState/action.ts

@@ -0,0 +1,112 @@
+import http from '../../../http'
+import { REP_LIST, DEL_ITEM, CHANGE_PAGING, UPDATE_ITEM } from './actionType'
+
+export const updateItemAction = (dispatch: Function, item: Model): Model => {
+  let citem = {...item}
+  dispatch({
+    type: UPDATE_ITEM,
+    plyload: {
+      oldItem: item,
+      newItem: citem
+    }
+  })
+  return citem
+}
+
+/**
+ * 状态
+ * 0:切片失败
+ * 1:未解压
+ * 2:未判断坐标
+ * 3:未转geojson
+ * 4:未切片
+ * 5:切片完成
+ * 6:切片中
+ * 7: 坐标转换失败
+ * 8: 服务已发布
+ * 9:判断中
+ */
+function getStateLocal(item: any) {
+  const map : {[key: string]: Array<string>} = {
+    '0': ['slicePath'],
+    '1': ['coordStrictPath', 'uploadPath'],
+    '2': ['coordStrictPath', 'unZipPath', 'uploadPath'],
+    '3': ['coordStrictPath', 'unZipPath', 'uploadPath'],
+    '4': ['geojsonPath', 'coordStrictPath', 'unZipPath', 'uploadPath'],
+    '5': ['slicePath', 'geojsonPath', 'coordStrictPath', 'unZipPath', 'uploadPath'],
+    '6': ['slicePath', 'geojsonPath', 'coordStrictPath', 'unZipPath', 'uploadPath'],
+    '7': ['geojsonPath'],
+    '8': ['slicePath', 'geojsonPath', 'coordStrictPath', 'unZipPath', 'uploadPath'],
+    '9': ['slicePath', 'geojsonPath', 'coordStrictPath', 'unZipPath', 'uploadPath']
+  }
+
+  let key = map[item.status].find(key => item[key])
+  return key ? item[key] : ''
+}
+
+
+export const getListAction = async (dispatch: Function, url: string, current: number) => {
+  let res = await http.post(url, { "pageNum": current - 1, "pageSize": 10})
+  let list = res.data.data.content
+
+  console.log(res.data.data.content)
+  list = list.map((item: any) => ({
+    ...item,
+    fileUrl: getStateLocal(item)
+  }))
+
+  list.forEach((item: any) => {
+    if (item.status === 6) {
+      item.sectStep = sessionStorage.getItem(item.id) || 0
+    }
+  })
+
+  dispatch({
+    type: REP_LIST,
+    plyload: list
+  })
+
+  dispatch({
+    type: CHANGE_PAGING,
+    plyload: {
+      total: res.data.data.totalPages,
+      current: current
+    }
+  })
+}
+
+export const delItemAction = async (dispatch: Function, url: string, item: Model) => {
+  await http.get(url)
+  dispatch({
+    type: DEL_ITEM,
+    plyload: item
+  })
+}
+
+export const zipItemAction = async (dispatch: Function, url: string, item: Model) => {
+  let res = await http.get(url)
+  return res.data
+}
+
+export const judgeItemAction = async (dispatch: Function, url: string, item: Model) => {
+  let res = await http.get(url)
+  return res.data
+}
+
+export const sectionItemAction = async (dispatch: Function, url: string, item: Model) => {
+  let res = await http.get(url)
+  return res.data
+}
+
+export const sectionStepAction = async (dispatch: Function, url: string, item: Model) => {
+  let res = await http.get(url)
+  if (res.data.data) {
+    sessionStorage.setItem(res.data.data.id, res.data.data.progress)
+  }
+  return res.data
+}
+
+export const transferItemAction = async (dispatch: Function, url: string, item: Model, body: any) => {
+  let res = await http.post(url, body)
+  return res.data
+}

+ 4 - 0
src/page/List/ListState/actionType.ts

@@ -0,0 +1,4 @@
+export const DEL_ITEM = 'DEL_ITEM'
+export const REP_LIST = 'REP_LIST'
+export const CHANGE_PAGING = 'CHANGE_PAGING'
+export const UPDATE_ITEM = 'UPDATE_ITEM'

+ 20 - 0
src/page/List/ListState/index.ts

@@ -0,0 +1,20 @@
+import { initState as initialState } from './state'
+import { reducer } from './reducer'
+import { getList } from './selector'
+
+export {
+  getListAction, 
+  delItemAction, 
+  zipItemAction, 
+  judgeItemAction, 
+  sectionItemAction, 
+  updateItemAction, 
+  sectionStepAction, 
+  transferItemAction
+} from './action'
+
+export {
+  initialState,
+  reducer,
+  getList
+}

+ 43 - 0
src/page/List/ListState/reducer.ts

@@ -0,0 +1,43 @@
+import { DEL_ITEM, REP_LIST, CHANGE_PAGING, UPDATE_ITEM } from "./actionType"
+
+const delArrayItem = <T>(arr: Array<T>, item: T) => {
+  let cArr = [...arr]
+  cArr.splice(arr.indexOf(item), 1)
+  return cArr
+}
+
+export function reducer<T>(state: State<T>, action: Action): State<T> {
+  let cstate
+  switch (action.type) {
+    case DEL_ITEM:
+      cstate = {
+        ...state,
+        list: delArrayItem(state.list, action.plyload)
+      }
+      break;
+    case CHANGE_PAGING:  
+      cstate = {
+        ...state,
+        paging: action.plyload
+      }
+      break
+    case REP_LIST: {
+      cstate = {
+        ...state,
+        list: action.plyload
+      }
+      break
+    }
+    case UPDATE_ITEM: {
+      cstate = {...state, list: state.list}
+      let index = cstate.list.indexOf(action.plyload.oldItem)
+      cstate.list[index] = action.plyload.newItem
+    }
+    default: {
+      cstate = state
+    }
+  }
+
+  sessionStorage.setItem('state', JSON.stringify(cstate))
+  return cstate
+}

+ 2 - 0
src/page/List/ListState/selector.ts

@@ -0,0 +1,2 @@
+
+export const getList = <T>(state: State<T>): Array<T> => state.list

+ 12 - 0
src/page/List/ListState/state.ts

@@ -0,0 +1,12 @@
+
+export const initState = <T>(): State<T>  => {
+  let stateStr = sessionStorage.getItem('state')
+  
+  return stateStr ?JSON.parse(stateStr) : {
+    list: [],
+    paging: {
+      current: 1,
+      total: 0
+    }
+  }
+}

+ 25 - 0
src/page/List/ListState/type.d.ts

@@ -0,0 +1,25 @@
+interface Action {
+  type: string,
+  plyload: any
+}
+
+interface Paging {
+  current: number,
+  total: number
+}
+
+interface State<T> {
+  list: Array<T>,
+  paging: Paging
+}
+
+interface Model extends Object {
+  id: number,
+  fileName: string,
+  type: string,
+  updateTime: string,
+  status: number
+  fileUrl: string,
+  ajaxStatue?: number,
+  sectStep?: number
+}

+ 21 - 0
src/page/List/ModelList.tsx

@@ -0,0 +1,21 @@
+import React from 'react'
+import GrentReducer from './grent'
+import Upload from '../components/Upload'
+import styles from './index.module.css'
+
+export default function ModelList({ className }: any) {
+  const { referData, Element } = GrentReducer({
+    delUrl: '/fdModel/delete/',
+    getUrl: '/fdModel/list/',
+    zipUrl: '/fdModel/unzip/',
+    sectionUrl: '/fdModel/command/osgb/',
+    transferUrl: '/fdModel/move/'
+  })
+
+  return (
+    <div className={className}>
+      {Element}
+      <Upload className={styles.uplayer} api='/fdModel/upload' check='/fdModel/check/' upHandle={referData} />
+    </div>
+  )
+}

+ 181 - 0
src/page/List/ResterList.tsx

@@ -0,0 +1,181 @@
+import React from 'react'
+import GrentReducer from './grent'
+import Upload from '../components/Upload'
+import styles from './index.module.css'
+import { sectionStepAction } from './ListState'
+import Step from '../components/Upload/Step'
+
+const intervals: Array<any> = []
+// const JUDGEING = 1, JUGESUCCESS = 2, JUGEERR = 3
+// const SECTIONING = 4, SECTIONSUCCESS = 5, SECTIONEERR = 6
+// const TRANSFERING = 13, TRANSFERSUCCESS = 14, TRANSFEREERR = 15
+
+
+// export default function ResterList({ className }: any) {
+//   intervals.forEach(clearInterval)
+//   const ItemFn = (model: Model) => {
+//     let Jude: any = <b onClick={() => judge(model)} style={{ cursor: 'pointer' }}>判断</b>
+//     let Sect: any = <b onClick={() => section(model)} style={{ cursor: 'pointer' }}>切片</b>
+//     let Tf: any = (
+//       <Fragment>
+//         <input type="text" value={text} onChange={ev => setText(ev.target.value)} placeholder="发布参数" />
+//         <b onClick={() => transfer(model)} style={{ cursor: 'pointer' }}>发布</b>
+//       </Fragment>
+//     )
+
+//     Jude = model.ajaxStatue === JUDGEING ? '判断中…' : model.ajaxStatue === JUGESUCCESS ? '成功判断' : Jude
+//     Sect = model.ajaxStatue === SECTIONING ? '切片中…' : model.ajaxStatue === SECTIONSUCCESS ? '成功切片' : Sect
+//     Tf = model.ajaxStatue === TRANSFERING ? '移动中…' : model.ajaxStatue === TRANSFEREERR ? '成功移动' : Tf
+
+//     if (model.status === 6) {
+//       Sect = (model.sectStep ? (model.sectStep + '%') : '切片中') 
+//     }
+
+//     if (model.status === 9) {
+//       Jude = '判断中…'
+//     }
+//     return (
+//       <Item key={model.id} {...model}>
+//         {() => (
+//           <Fragment>
+//             {(model.status === 2 || model.status === 9) && Jude}
+//             {(model.status === 4 || model.status === 6 || model.status === 0) && Sect}
+//             {model.status === 5 && Tf}
+//             <b onClick={() => delHandle(model)} style={{ cursor: 'pointer' }}>删除</b>
+//           </Fragment>
+//         )}
+//       </Item>
+//     )
+//   }
+//   const { delHandle, Element, referData, modelDispatch, setItemStaus, referItem, models } = GrentReducer('/raster/list', '/raster/delete/', ItemFn)
+//   let [text, setText] = useState('')
+//   const judge = async (model: Model) => {
+//     model = setItemStaus(model, JUDGEING)
+//     let data = await judgeItemAction(modelDispatch, `/raster/command/judge/coord/${model.id}/`, model)
+    
+//     if (data.status !== 200) {
+//       alert(data.message)
+//       setItemStaus(model, JUGEERR)
+//     } else {
+//       setItemStaus(model, JUGESUCCESS)
+//       referData()
+//     }
+//   }
+//   const section = async (model: Model) => {
+//     model = setItemStaus(model, SECTIONING)
+//     sectionItemAction(modelDispatch, `/raster/command/osgeo/${model.id}/`, model)
+//       .then(data => {
+//         if (data.status !== 200) {
+//           model = setItemStaus(model, SECTIONEERR)
+//           alert(data.message)
+//         } else {
+//           model = setItemStaus(model, SECTIONSUCCESS)
+//           referData()
+//         }
+//       });
+//   }
+//   const transfer = async (model: Model) => {
+//     model = setItemStaus(model, TRANSFERING)
+//     transferItemAction(modelDispatch, `/raster/move/${model.id}/`, model, { text: text })
+//       .then(data => {
+//         if (data.status !== 200) {
+//           model = setItemStaus(model, TRANSFEREERR)
+//           alert(data.message)
+//         } else {
+//           model = setItemStaus(model, TRANSFERSUCCESS)
+//           referData()
+//         }
+//       });
+//   }
+//   async function getStep(model: Model) {
+//     let data = await sectionStepAction(modelDispatch, `/raster/progress/${model.id}/`, model)
+//     return data.data.progress
+//   };
+
+//   models.forEach((model: any) => {
+//     if (model.status !== 6) return;
+
+//     let interval = setInterval(async () => {
+//       let step = await getStep(model)
+//       if (model.sectStep !== step) {
+//         model.sectStep = step
+//         model = referItem(model)
+//         clearInterval(interval)
+
+//         if (model.sectStep === 100) {
+//           setTimeout(() => referData(), 1000)
+//         }
+//       }
+//     }, 1000)
+//     intervals.push(interval)
+//   })
+
+//   for (let i = 0; i < models.length; i++) {
+//     let model = models[i] as Model
+//     if (model.status !== 9) continue
+//     setTimeout(() => referData(), 1000)
+//     break;
+//   }
+
+//   return (
+//     <div className={className}>
+//       {Element}
+//       <Upload className={styles.uplayer} api='/raster/upload' check='/raster/check/' upHandle={referData} />
+//     </div>
+//   )
+// }
+
+
+
+export default function ModelList({ className }: any) {
+  intervals.forEach(interval => clearInterval(interval))
+  const { referData, Element, modelDispatch, models, referItem } = GrentReducer({
+    judgeUrl: '/raster/command/judge/coord/',
+    delUrl: '/raster/delete/',
+    getUrl: '/raster/list',
+    sectionUrl: '/raster/command/osgeo/',
+    transferUrl: '/raster/move/',
+    ItemFn(model: Model) {
+      if (model.status === 6) {
+        return <Step step={model.sectStep ? model.sectStep : 0} />
+      }
+    }
+  })
+
+  async function getStep(model: Model) {
+    let data = await sectionStepAction(modelDispatch, `/raster/progress/${model.id}/`, model)
+    return data.data.progress
+  };
+
+  models.forEach((model: any) => {
+    if (model.status !== 6) return;
+
+    let interval = setInterval(async () => {
+      let step = await getStep(model)
+      if (model.sectStep !== step) {
+        model.sectStep = step
+        model = referItem(model)
+        clearInterval(interval)
+
+        if (model.sectStep === 100) {
+          setTimeout(() => referData(), 1000)
+        }
+      }
+    }, 1000)
+    intervals.push(interval)
+  })
+
+  for (let i = 0; i < models.length; i++) {
+    let model = models[i] as Model
+    if (model.status !== 9) continue
+    setTimeout(() => referData(), 1000)
+    break;
+  }
+
+  return (
+    <div className={className}>
+      {Element}
+      <Upload className={styles.uplayer} api='/raster/upload' check='/raster/check/' upHandle={referData} />
+    </div>
+  )
+}

+ 106 - 0
src/page/List/grent.tsx

@@ -0,0 +1,106 @@
+import React, { useReducer, useEffect, useState, Fragment } from 'react'
+import List from '../components/List'
+import Item from '../components/item'
+import Paging from '../components/Paging'
+import styles from './index.module.css'
+import GrentOper from './GrentOper'
+import {
+  initialState,
+  reducer,
+  getList,
+  getListAction,
+  delItemAction,
+  updateItemAction
+} from './ListState'
+
+interface ItemsProps {
+  list: Array<any>,
+  children: Function,
+  changePage: Function,
+  total: number,
+  current: number
+}
+
+const ListItems = (props: ItemsProps) => {
+  return (
+    <Fragment>
+      <List data={props.list} className={styles.listlayer}>
+        <Item data={['文件名', '路径', '类型', '创建时间', '当前状态', '操作']} />
+        {(model: Model) => props.children(model)}
+      </List>
+      <div className={styles.paging}>
+        <Paging
+          total={props.total}
+          current={props.current}
+          show={5}
+          handleChange={(current: number) => props.changePage(current)} />
+      </div>
+
+    </Fragment>
+  )
+}
+
+
+interface GrentApi {
+  getUrl: string,
+  delUrl: string,
+  zipUrl?: string,
+  sectionUrl?: string,
+  transformUrl?: string,
+  transferUrl?: string,
+  judgeUrl?: string,
+  ItemFn?: Function
+}
+export default function GrentReducer({ getUrl, delUrl, zipUrl, sectionUrl, transformUrl, transferUrl, judgeUrl, ItemFn  }: GrentApi) {
+  let [referCount, setReferCount] = useState(0)
+  let [modelState, modelDispatch] = useReducer(reducer, initialState())
+  const models = getList(modelState)
+  const updateAction = (current: number) => getListAction(modelDispatch, getUrl, current)
+  const referData = () => setReferCount(++referCount)
+  const delHandle = async (model: Model) => {
+    await delItemAction(modelDispatch, delUrl + model.id + '/', model)
+    setReferCount(++referCount)
+  }
+  const referItem = (model: Model): Model => updateItemAction(modelDispatch, model)
+  const setItemStaus = (model: Model, status: number) : Model => {
+    model.ajaxStatue = status
+    return referItem(model)
+  }
+
+  useEffect(() => { updateAction(modelState.paging.current) }, [referCount])
+
+  let { ItemFn: PublicItemFn, text } = GrentOper({
+    setItemStaus,
+    modelDispatch,
+    referData,
+    delHandle,
+    api: { zip: zipUrl, section: sectionUrl, transfer: transferUrl, judge: judgeUrl, transform: transformUrl }
+  })
+
+
+  const Element = (
+    <ListItems
+      list={models}
+      total={modelState.paging.total}
+      current={modelState.paging.current}
+      changePage={(page: number) => updateAction(page)}>
+      {(model: Model) => (
+        <Fragment key={model.id}>
+          {PublicItemFn(model, ItemFn)}
+        </Fragment>
+      )}
+    </ListItems>
+  )
+
+  return {
+    modelDispatch,
+    models,
+    referData,
+    delHandle,
+    updateAction,
+    referItem,
+    Element,
+    setItemStaus,
+    text
+  }
+}

+ 58 - 0
src/page/List/index.module.css

@@ -0,0 +1,58 @@
+.listlayer {
+  display: grid;
+  grid-template-columns: 2fr minmax(100px, 4fr) 1fr 2fr minmax(100px, 2fr) minmax(100px, 2fr);
+  padding: 24px;
+  border: 1px solid #ebebeb;
+  border-radius: 3px;
+}
+
+.uplayer {
+  display: inline-block;
+  margin-top: 20px;
+}
+
+.paging {
+  margin-top: 10px;
+  text-align: center;
+}
+
+.inuplayer {
+  height: 32px;
+  position: relative;
+  box-sizing: border-box;
+  font-size: 12px;
+}
+
+.inuplayer input {
+  width: 201px;
+  height: 100%;;
+  left: 0;
+  top: 0;
+  box-sizing: border-box;
+  padding: 5px 10px;
+}
+
+.inuplayer > div {
+  margin-top: 10px;
+}
+
+.tip {
+  position: relative;
+}
+
+.tip > div {
+  position: absolute;
+  left: 60px;
+  top: 100%;
+  right: 0;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+  background-color: #fff;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
+  box-sizing: border-box;
+  margin-top: 5px;
+  padding: 5px;
+  color: #E6A23C;
+  font-size: 12px;
+  z-index: 3;
+}

+ 11 - 0
src/page/StyleEdit/index.tsx

@@ -0,0 +1,11 @@
+import React from 'react'
+
+function StyleEdit() {
+  return (
+    <div>
+      123
+    </div>
+  )
+}
+
+export default StyleEdit

+ 29 - 0
src/page/components/List/index.tsx

@@ -0,0 +1,29 @@
+import React, { ReactElement } from 'react'
+
+interface ListProps<T> {
+  children: any,
+  data: Array<T>,
+  className?: string
+}
+
+function List(props: ListProps<any>) : ReactElement {
+  let fns = props.children
+  
+  if (!(props.children instanceof Array)) {
+    fns = [props.children]
+  }
+  
+  return (
+    <div className={props.className}>
+      {
+        (fns as Array<any>).map(Fn => (
+          typeof Fn === 'function' ?
+            props.data.map((obj, i) => Fn(obj, i)) :
+            Fn
+        ))
+      }
+    </div>
+  )
+}
+
+export default List

+ 28 - 0
src/page/components/Paging/index.module.css

@@ -0,0 +1,28 @@
+.paginglayer {
+  display: inline-block;
+  vertical-align: top;
+}
+
+.paginglayer > span {
+  display: inline-block;
+  border-color: transparent;
+  height: 22px;
+  min-width: 22px;
+  border-color: transparent;
+  font-size: 12px;
+  line-height: 22px;
+  height: 22px;
+  min-width: 22px;
+  cursor: pointer;
+  margin: 0 5px;
+  background-color: #f4f4f5;
+  color: #606266;
+  min-width: 30px;
+  border-radius: 2px;
+  text-align: center;
+}
+
+.paginglayer > span.active {
+  color: #409eff;
+  cursor: default;
+}

+ 45 - 0
src/page/components/Paging/index.tsx

@@ -0,0 +1,45 @@
+import React from 'react'
+import styles from './index.module.css'
+
+interface PagingProps {
+  current: number,
+  total: number,
+  handleChange: Function,
+  show: number,
+  className?: string
+}
+
+function intercept(current: number, maxT: number, dis: number, minT = 1) {
+  let cdis = Math.floor(dis / 2)
+  let min = current - cdis
+  let max = current + cdis
+
+  if (min < minT) {
+    max = max + (minT - min)
+    min = minT
+  } else if (max > maxT) {
+    min = min - (max - maxT)
+    max = maxT
+  }
+
+  min = min < minT ? minT : min
+  max = max > maxT ? maxT : max
+
+  return { min, max }
+}
+
+function Paging({ current = 1, show = 5, total, handleChange, className = ''} : PagingProps) {
+  const clickHandle = (select: number) => current !== select && handleChange(select)
+  const { min, max } = intercept(current, total, show)
+
+  let items = []
+  for (let i = min; i <= max; i++) {
+    items.push(<span key={i} onClick={() => clickHandle(i)} className={i === current ? styles.active: ''}>{i}</span>)
+  }
+
+  return (
+    <div className={styles.paginglayer + ' ' + className}>{items}</div>
+  )
+}
+
+export default Paging

+ 51 - 0
src/page/components/Tab/index.module.css

@@ -0,0 +1,51 @@
+.headLayer {
+  display: flex;
+  position: relative;
+}
+
+.headLayer > span {
+  padding: 0 20px;
+  height: 40px;
+  box-sizing: border-box;
+  line-height: 40px;
+  display: inline-block;
+  list-style: none;
+  font-size: 14px;
+  font-weight: 500;
+  color: #303133;
+  position: relative;
+  cursor: pointer;
+}
+
+.headLayer::after {
+  content: "";
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 2px;
+  background-color: #e4e7ed;
+  z-index: 1;
+}
+
+.headLayer > span.active {
+  color: #409eff;
+  position: relative;
+  z-index: 2;
+}
+
+.headLayer > span.active::after {
+  content: '';
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  height: 2px;
+  background-color: #409eff;
+  z-index: 1;
+  list-style: none;
+  width: 100%;
+}
+
+.hidelayer {
+  display: none;
+}

+ 51 - 0
src/page/components/Tab/index.tsx

@@ -0,0 +1,51 @@
+import React, { useState } from 'react'
+import styles from './index.module.css'
+
+interface TabProps {
+  titles: Array<string>
+  children: any,
+  showIndex?: number,
+  changeHandle?: Function
+}
+
+function Tab({ children, titles, showIndex = 1, changeHandle }: TabProps) {
+  let [index, setIndex] = useState(showIndex - 1)
+
+  if (!(children instanceof Array)) {
+    children = [children]
+  }
+  if (titles.length < children.length) {
+    let less = children.length - titles.length
+    for (let i = 0; i < less; i++) {
+      titles.push('Tab')
+    }
+  }
+
+  const clickHandle = (i: number) => {
+    setIndex(i)
+    changeHandle && changeHandle(i + 1)
+  }
+
+
+  return (
+    <div className={styles.tabLayer}>
+      <div className={styles.headLayer}>
+        {titles.map((title: string, i: number) => (
+          <span
+            key={i}
+            className={index === i ? styles.active : ''}
+            onClick={() => clickHandle(i)}>
+            {title}
+          </span>
+        ))}
+      </div>
+      {children.map((Fn: any, i: number) => (
+        <div className={index === i ? styles.showlayer : styles.hidelayer} key={i}>
+          {Fn}
+        </div>
+      ))}
+    </div>
+  )
+}
+
+export default Tab

+ 27 - 0
src/page/components/Upload/Item.tsx

@@ -0,0 +1,27 @@
+import React from 'react'
+import Step from './Step'
+import { UPREADY, UPERR, UPSUCCESS, UPING } from './constant'
+import styles from './index.module.css'
+
+
+function UItem(props: UFileC) {
+  let StatusMap: any = {
+    [UPREADY]: <span className={styles.ready}>准备上传</span>,
+    [UPERR]: <span className={styles.err}>上传失败</span>,
+    [UPING]: <span className={styles.ing}>{parseInt(props.percentage.toString())}%</span>,
+    [UPSUCCESS]: <span className={styles.success}>上传成功</span>
+  }
+  let Status = StatusMap[props.status.toString()]
+
+  return (
+    <div className={styles.filelayer}>
+      <div className={styles.fileitem}>
+        <span>{props.name}</span>
+        {Status}
+      </div>
+      <Step step={props.percentage} />
+    </div>
+  )
+}
+
+export default UItem

+ 12 - 0
src/page/components/Upload/Step.tsx

@@ -0,0 +1,12 @@
+import React from 'react'
+import styles from './index.module.css'
+
+function Step(props: {step: number}) {
+  return (
+    <div className={styles.steplayer}>
+      <span style={{width: props.step + '%'}}></span>
+    </div>
+  )
+}
+
+export default Step

+ 4 - 0
src/page/components/Upload/constant.ts

@@ -0,0 +1,4 @@
+export const UPING = 0
+export const UPERR = 1
+export const UPSUCCESS = 2
+export const UPREADY = 3

+ 11 - 0
src/page/components/Upload/file.d.ts

@@ -0,0 +1,11 @@
+
+interface UFile {
+  name: string,
+  size: number,
+  file: Array
+}
+
+interface UFileC extends UFile {
+  percentage: number,
+  status: number
+}

+ 89 - 0
src/page/components/Upload/index.module.css

@@ -0,0 +1,89 @@
+.filebutton {
+  position: relative;
+  display: inline-block;
+  overflow: hidden;
+  cursor: pointer;
+}
+
+.filebutton input {
+  display: none;
+}
+
+.filebutton span {
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  border: 1px solid #dcdfe6;
+  color: #606266;
+  -webkit-appearance: none;
+  text-align: center;
+  box-sizing: border-box;
+  outline: none;
+  margin: 0;
+  transition: .1s;
+  font-weight: 500;
+  color: #fff;
+  background-color: #409eff;
+  border-color: #409eff;
+  padding: 9px 15px;
+  font-size: 12px;
+  border-radius: 3px;
+}
+
+.filebutton span:hover {
+  background: #66b1ff;
+  border-color: #66b1ff;
+  color: #fff;
+}
+
+.steplayer {
+  width: 100%;
+  height: 2px;
+  background-color: #e4e7ed;
+  z-index: 1;
+  position: relative;
+}
+
+.steplayer span {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  height: 2px;
+  background-color: #409eff;
+  z-index: 1;
+  transition: width .3s cubic-bezier(.645, .045, .355, 1);
+  list-style: none;
+}
+
+.filelayer {
+  margin-bottom: 8px;
+}
+
+.fileitem {
+  display: flex;
+  margin-bottom: 5px;
+}
+
+.fileitem span:first-child {
+  flex: 1;
+}
+
+.fileitem span {
+  color: #606266;
+  display: block;
+  overflow: hidden;
+  padding-left: 4px;
+  text-overflow: ellipsis;
+  transition: color .3s;
+  white-space: nowrap;
+  font-size: 12px;
+}
+
+.err {
+  color: #F56C6C !important
+}
+
+.success {
+  color: #67C23A !important
+}

+ 145 - 0
src/page/components/Upload/index.tsx

@@ -0,0 +1,145 @@
+import React, { ReactElement, useRef, MutableRefObject, useState } from 'react'
+import styles from './index.module.css'
+import List from '../List'
+import Item from './Item'
+import { UPREADY, UPSUCCESS, UPING, UPERR} from './constant'
+import http from '../../../http'
+
+
+async function uploadFile({ url, file, body, cb, check }: { url: string, file: Array<File> | File, body: any, cb: Function, check?: string}) {
+  let form = new FormData()
+
+  if (file instanceof Array) {
+    file.forEach(f => form.append('file', f))
+  } else {
+    form.append('file', file)
+  }
+
+  Object.keys(body).forEach((k: string) => {
+    form.append(k, body[k])
+  })
+
+  try {
+    if (check) {
+      let res = await http.get(check)
+      if (res.data.status !== 200) {
+        alert(res.data.message)
+        return cb(0, true)
+      }
+    }
+
+    let res = await http({
+      url: url,
+      method: 'POST',
+      data: form,
+      onUploadProgress(ev) {
+        let step = (ev.loaded / ev.total) * 100
+        if (step !== 100) cb(step)
+      },
+      headers: {
+        'Content-Type': 'multipart/form-data'
+      }
+    })
+    if (res.data.status !== 200) {
+      alert(res.data.message)
+      cb(0, true)  
+    } else {
+      cb(100)
+    }
+  } catch(e) {
+    cb(0, true)
+  }
+}
+
+interface ItemCtrlProps extends UFile {
+  api: string,
+  handleUpSuccess: Function,
+  multiple?: boolean,
+  body: Object,
+  check?: string
+}
+
+function ItemCtrl(props: ItemCtrlProps) : ReactElement {
+  const [status, setStatus] = useState(UPREADY)
+  const [percentage, setPercentage] = useState(status === UPREADY ? 0 : 100)
+
+  if (status === UPREADY) {
+    setStatus(UPING)
+    uploadFile({
+      file: props.multiple ? props.file : props.file[0],
+      url: props.api,
+      body: props.body,
+      check: props.check && (props.check + props.name + '/'),
+      cb(speed: number, err?: boolean) {
+        setPercentage(speed)
+        if (speed === 100) {
+          setStatus(UPSUCCESS)
+          props.handleUpSuccess()
+        } else if (err) {
+          setStatus(UPERR)
+        }
+      }
+    })
+  }
+  
+  return <Item {...props} status={status} percentage={percentage} />
+}
+
+interface UploadProps {
+  multiple?: boolean,
+  className?: string,
+  api: string,
+  upHandle: Function,
+  body?: Object,
+  check?: string
+}
+
+function Upload(props: UploadProps) : ReactElement {
+  let [flist, setFlist] = useState<Array<UFile>>([])
+  const inputfile = (useRef(null) as MutableRefObject<any>)
+  const onClickHandle = () => inputfile.current.click()
+  const onChangeHandle = async () => {
+    let files = [...inputfile.current.files]
+    let newFiles = await Promise.all(
+      files.map(async (file: File) => ({
+        name: file.name,
+        size: file.size,
+        file: file
+      }))
+    )
+    for (let i = 0; i < newFiles.length; i++) {
+      if (escape(newFiles[i].name).indexOf("%u") >= 0) {
+        alert("上传文件文件名不能包含中文!");
+        return false;
+      }
+    }
+    let newFile = {
+      name: newFiles.map(f => f.name).join(' + '),
+      size: newFiles.reduce((previous, current) => previous + current.size, 0),
+      file: newFiles.map(f => f.file)
+    }
+    setFlist(flist.concat(newFile as any))
+  }
+
+  return (
+    <div className={props.className}>
+      <div className={styles.filebutton}>
+        <input type="file" ref={inputfile} multiple={props.multiple} onChange={onChangeHandle}/>
+        <span onClick={onClickHandle}>点击上传</span>
+      </div>
+      <List data={flist} className="uplist">
+        {(file: UFile, i: number, s: string) => (
+          <ItemCtrl
+            handleUpSuccess={props.upHandle}
+            body={props.body ? props.body: {}}
+            api={props.api} {...file}
+            multiple={props.multiple}
+            check={props.check}
+            key={i} />
+        )}
+      </List>
+    </div>
+  )
+}
+
+export default Upload

+ 26 - 0
src/page/components/item/index.module.css

@@ -0,0 +1,26 @@
+.item {
+  flex: 1;
+  text-overflow: ellipsis;
+  white-space: normal;
+  word-break: break-all;
+  line-height: 23px;
+  padding-left: 10px;
+  padding-right: 10px;
+  font-size: 14px;
+  color: #606266;
+  padding: 12px 0;
+  border-bottom: 1px solid #ebebeb;
+}
+
+.item a,
+.item b {
+  color: inherit;
+  text-decoration: none;
+  margin: 0 3px;
+  font-weight:  normal;
+}
+
+.item input {
+  width: 62px;
+  line-height: 25px;
+}

+ 47 - 0
src/page/components/item/index.tsx

@@ -0,0 +1,47 @@
+import React, { ReactElement, Fragment, MouseEventHandler } from 'react'
+import styles from './index.module.css'
+
+interface Header {
+  data: Array<string>
+}
+
+interface ItemProps extends Model {
+  zipHnadle?: MouseEventHandler,
+  children?: Function
+}
+
+const StatusMap : any = {
+  '0':'切片失败',
+  '1':'未解压',
+  '2':'未判断坐标',
+  '3':'未转geojson',
+  '4':'未切片',
+  '5':'切片完成',
+  '6':'切片中',
+  '7': '坐标转换失败',
+  '8':' 服务已发布'
+}
+
+function Item(props: ItemProps | Header) : ReactElement {
+  let data : Array<any> = []
+  let status = (props as Model).status
+  if ((props as Model).fileName !== void 0) {
+    data.push(
+      (props as Model).fileName,
+      (props as Model).fileUrl,
+      (props as Model).type,
+      (props as Model).updateTime,
+      StatusMap[status]
+    );
+    
+    (props as ItemProps).children && data.push(((props as ItemProps).children as Function)())
+  } else {
+    data = (props as Header).data.map(str => <b>{str}</b>)
+  }
+
+  let ls = data.map((str, i) => <span className={styles.item} key={i}>{str}</span>)
+
+  return <Fragment>{ls}</Fragment>
+}
+
+export default Item

+ 14 - 0
src/setupProxy.js

@@ -0,0 +1,14 @@
+const proxy = require('http-proxy-middleware')
+
+module.exports = app => {
+  app.use(
+    proxy('/api', {
+      // target: 'http://39.108.123.31:8082',
+      target: 'http://39.108.123.31:8082',
+      changeOrigin: true,
+      pathRewrite: {
+        "^/api": "/api"
+      }
+    })
+  )
+}