From 96c705e7c0eb114695c04a0500a4abc815739cf6 Mon Sep 17 00:00:00 2001
From: 康凯 <kangk26@foxmail.com>
Date: Sun, 12 Dec 2021 10:16:24 +0800
Subject: [PATCH] 开发完成 版本1.0

---
 src/views/personage/list.vue        |  190 +
 src/views/layout/listIndex.vue      |  155 +
 vue.config.js                       |   14 
 src/assets/icon/iconfont.woff2      |    0 
 src/assets/home_background@1x.png   |    0 
 src/assets/nav_memory@1x.png        |    0 
 src/assets/icon/iconfont.woff       |    0 
 src/assets/datalist/datalist@1x.png |    0 
 src/components/CustomSearch3.vue    |  183 +
 src/views/memory/detailImage.vue    |  133 +
 src/views/search/index.vue          |  175 +
 src/views/spirit/detailvideo.vue    |  121 
 src/views/memory/detail.vue         |  510 ++++
 src/assets/icon/demo.css            |  539 ++++
 src/views/personage/detailvideo.vue |  121 
 src/api/jsonlint.js                 |  673 +++++
 src/assets/icon/iconfont.json       |   16 
 src/assets/icon/iconfont.js         |    1 
 src/components/CustomSearch1.vue    |   77 
 src/views/layout/searchIndex.vue    |   75 
 .env.development                    |    5 
 src/views/spirit/detail.vue         |  510 ++++
 src/main.js                         |  142 +
 .env.production                     |    6 
 src/views/home.vue                  |  191 +
 src/components/CustomSearch2.vue    |  201 +
 package-lock.json                   |  121 
 src/assets/nav_scenery@1x.png       |    0 
 src/assets/icon/iconfont.css        |   19 
 src/views/scenery/detailvideo.vue   |  121 
 src/assets/search/search@1x.png     |    0 
 src/assets/nav_personage@1x.png     |    0 
 src/api/apilist.js                  |  259 ++
 src/views/spirit/list.vue           |  153 +
 src/views/memory/list.vue           |  154 +
 src/views/scenery/detailImage.vue   |  133 +
 src/views/search/results.vue        |  268 ++
 src/assets/icon/iconfont.ttf        |    0 
 src/api/request.js                  |   74 
 src/views/personage/detailImage.vue |  133 +
 src/views/personage/detail.vue      |  510 ++++
 src/views/scenery/detail.vue        |  510 ++++
 src/assets/nav_spirit@1x.png        |    0 
 src/views/memory/detailvideo.vue    |  121 
 src/assets/icon/demo_index.html     |  211 +
 /dev/null                           |   58 
 src/assets/datadetail/detail@1x.png |    0 
 package.json                        |    7 
 src/views/scenery/list.vue          |  190 +
 src/views/spirit/detailImage.vue    |  133 +
 src/App.vue                         |   52 
 51 files changed, 7,194 insertions(+), 71 deletions(-)

diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..8245922
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,5 @@
+# just a flag
+ENV = 'development'
+
+# base api
+VUE_APP_BASE_API = '/'
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..14da59c
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,6 @@
+# just a flag
+ENV = 'production'
+
+# base api
+VUE_APP_BASE_API = '/'
+
diff --git a/package-lock.json b/package-lock.json
index 6395a37..3725035 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2201,6 +2201,11 @@
       "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
       "dev": true
     },
+    "array-find-index": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
+    },
     "array-flatten": {
       "version": "1.1.1",
       "resolved": "https://registry.nlark.com/array-flatten/download/array-flatten-1.1.1.tgz",
@@ -2323,6 +2328,14 @@
       "integrity": "sha1-3TeelPDbgxCwgpH51kwyCXZmF/0=",
       "dev": true
     },
+    "async-validator": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz",
+      "integrity": "sha512-tXBM+1m056MAX0E8TL2iCjg8WvSyXu0Zc8LNtYqrVeyoL3+esHRZ4SieE9fKQyyU09uONjnMEjrNBMqT0mbvmA==",
+      "requires": {
+        "babel-runtime": "6.x"
+      }
+    },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.nlark.com/asynckit/download/asynckit-0.4.0.tgz",
@@ -2370,6 +2383,14 @@
       "integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
       "dev": true
     },
+    "axios": {
+      "version": "0.24.0",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
+      "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
+      "requires": {
+        "follow-redirects": "^1.14.4"
+      }
+    },
     "babel-eslint": {
       "version": "10.1.0",
       "resolved": "https://registry.npmmirror.com/babel-eslint/download/babel-eslint-10.1.0.tgz",
@@ -2383,6 +2404,11 @@
         "eslint-visitor-keys": "^1.0.0",
         "resolve": "^1.12.0"
       }
+    },
+    "babel-helper-vue-jsx-merge-props": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
+      "integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg=="
     },
     "babel-loader": {
       "version": "8.2.3",
@@ -2433,6 +2459,27 @@
       "dev": true,
       "requires": {
         "@babel/helper-define-polyfill-provider": "^0.3.0"
+      }
+    },
+    "babel-runtime": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+      "requires": {
+        "core-js": "^2.4.0",
+        "regenerator-runtime": "^0.11.0"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "2.6.12",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
+          "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
+        },
+        "regenerator-runtime": {
+          "version": "0.11.1",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+          "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+        }
       }
     },
     "balanced-match": {
@@ -4064,8 +4111,7 @@
     "deepmerge": {
       "version": "1.5.2",
       "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz?cache=0&sync_timestamp=1606805746825&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeepmerge%2Fdownload%2Fdeepmerge-1.5.2.tgz",
-      "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M=",
-      "dev": true
+      "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M="
     },
     "default-gateway": {
       "version": "5.0.5",
@@ -4513,6 +4559,19 @@
       "resolved": "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.4.12.tgz",
       "integrity": "sha512-zjfhG9Us/hIy8AlQ5OzfbR/C4aBv1Dg/ak4GX35CELYlJ4tDAtoEcQivXvyBdqdNQ+R6PhlgQqV8UNPJmhkJog==",
       "dev": true
+    },
+    "element-ui": {
+      "version": "2.15.6",
+      "resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.6.tgz",
+      "integrity": "sha512-rcYXEKd/j2G0AgficAOk1Zd1AsnHRkhmrK4yLHmNOiimU2JfsywgfKUjMoFuT6pQx0luhovj8lFjpE4Fnt58Iw==",
+      "requires": {
+        "async-validator": "~1.8.1",
+        "babel-helper-vue-jsx-merge-props": "^2.0.0",
+        "deepmerge": "^1.2.0",
+        "normalize-wheel": "^1.0.1",
+        "resize-observer-polyfill": "^1.5.0",
+        "throttle-debounce": "^1.0.1"
+      }
     },
     "elliptic": {
       "version": "6.5.4",
@@ -5401,8 +5460,7 @@
     "follow-redirects": {
       "version": "1.14.5",
       "resolved": "https://registry.npmmirror.com/follow-redirects/download/follow-redirects-1.14.5.tgz?cache=0&sync_timestamp=1635857764332&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.14.5.tgz",
-      "integrity": "sha1-8JpYSJgdPHcrU5Iwl3hSP42Fw4E=",
-      "dev": true
+      "integrity": "sha1-8JpYSJgdPHcrU5Iwl3hSP42Fw4E="
     },
     "for-in": {
       "version": "1.0.2",
@@ -7358,6 +7416,16 @@
         }
       }
     },
+    "mint-ui": {
+      "version": "2.2.13",
+      "resolved": "https://registry.npmjs.org/mint-ui/-/mint-ui-2.2.13.tgz",
+      "integrity": "sha512-Xz1SFagHSzKOprwQv3fcekXT5RJvhh939zwZHcWeazk1OJrCjsD4I2qm49AEUCfT1AoYzC+rsZIwGP/J6LwVVw==",
+      "requires": {
+        "array-find-index": "^1.0.2",
+        "raf.js": "0.0.4",
+        "vue-lazyload": "^1.0.1"
+      }
+    },
     "mississippi": {
       "version": "3.0.0",
       "resolved": "https://registry.nlark.com/mississippi/download/mississippi-3.0.0.tgz",
@@ -7610,6 +7678,11 @@
       "resolved": "https://registry.nlark.com/normalize-url/download/normalize-url-3.3.0.tgz",
       "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=",
       "dev": true
+    },
+    "normalize-wheel": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
+      "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
     },
     "npm-run-path": {
       "version": "2.0.2",
@@ -8952,6 +9025,11 @@
       "integrity": "sha1-M0WUG0FTy50ILY7uTNogFqmu9/Y=",
       "dev": true
     },
+    "raf.js": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/raf.js/-/raf.js-0.0.4.tgz",
+      "integrity": "sha1-8Vr0RdJBsn+nExpXRQtn75xAL+w="
+    },
     "randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.nlark.com/randombytes/download/randombytes-2.1.0.tgz",
@@ -9274,6 +9352,11 @@
       "resolved": "https://registry.npm.taobao.org/requires-port/download/requires-port-1.0.0.tgz",
       "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
       "dev": true
+    },
+    "resize-observer-polyfill": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+      "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
     },
     "resolve": {
       "version": "1.20.0",
@@ -10484,6 +10567,11 @@
         "neo-async": "^2.6.0"
       }
     },
+    "throttle-debounce": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz",
+      "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg=="
+    },
     "through": {
       "version": "2.3.8",
       "resolved": "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz",
@@ -11048,6 +11136,11 @@
       "integrity": "sha1-UylVzB6yCKPZkLOp+acFdGV+CPI=",
       "dev": true
     },
+    "vue-lazyload": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.3.tgz",
+      "integrity": "sha512-uHnq0FTEeNmqnbBC2aRKlmtd9LofMZ6Q3mWvgfLa+i9vhxU8fDK+nGs9c1iVT85axSua/AUnMttIq3xPaU9G3A=="
+    },
     "vue-loader": {
       "version": "15.9.8",
       "resolved": "https://registry.npmmirror.com/vue-loader/download/vue-loader-15.9.8.tgz?cache=0&sync_timestamp=1636034570924&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fvue-loader%2Fdownload%2Fvue-loader-15.9.8.tgz",
@@ -11150,6 +11243,26 @@
         }
       }
     },
+    "vue-meta": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/vue-meta/-/vue-meta-2.4.0.tgz",
+      "integrity": "sha512-XEeZUmlVeODclAjCNpWDnjgw+t3WA6gdzs6ENoIAgwO1J1d5p1tezDhtteLUFwcaQaTtayRrsx7GL6oXp/m2Jw==",
+      "requires": {
+        "deepmerge": "^4.2.2"
+      },
+      "dependencies": {
+        "deepmerge": {
+          "version": "4.2.2",
+          "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+          "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
+        }
+      }
+    },
+    "vue-router": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.3.tgz",
+      "integrity": "sha512-FUlILrW3DGitS2h+Xaw8aRNvGTwtuaxrRkNSHWTizOfLUie7wuYwezeZ50iflRn8YPV5kxmU2LQuu3nM/b3Zsg=="
+    },
     "vue-style-loader": {
       "version": "4.1.3",
       "resolved": "https://registry.nlark.com/vue-style-loader/download/vue-style-loader-4.1.3.tgz",
diff --git a/package.json b/package.json
index 806eec0..d852662 100644
--- a/package.json
+++ b/package.json
@@ -8,8 +8,13 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "axios": "^0.24.0",
     "core-js": "^3.6.5",
-    "vue": "^2.6.11"
+    "element-ui": "^2.15.6",
+    "mint-ui": "^2.2.13",
+    "vue": "^2.6.11",
+    "vue-meta": "^2.4.0",
+    "vue-router": "^3.5.3"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "~4.5.0",
diff --git a/src/App.vue b/src/App.vue
index 55df315..771fde0 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,28 +1,66 @@
 <template>
   <div id="app">
-    <img alt="Vue logo" src="./assets/logo.png">
-    <HelloWorld msg="Welcome to Your Vue.js App"/>
+    <router-view></router-view>
   </div>
 </template>
 
 <script>
-import HelloWorld from './components/HelloWorld.vue'
-
 export default {
   name: 'App',
-  components: {
-    HelloWorld
+  components: {},
+  metaInfo: {
+    meta: [
+      {
+        name: "viewport",
+        content: "width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1, maximum-scale=1;"
+      }
+    ]
+  },
+  created() {
+    document.title = "吉林红色旅游";
   }
 }
 </script>
 
 <style>
+body{
+  margin: 1px;
+}
 #app {
   font-family: Avenir, Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
   text-align: center;
   color: #2c3e50;
-  margin-top: 60px;
+}
+@media only screen and (min-width: 320px) {
+  html {
+    font-size: 6px !important;
+  }
+}
+
+
+@media only screen and (min-width: 375px) {
+  html {
+    font-size: 8px !important;
+  }
+}
+
+@media only screen and (min-width: 480px) {
+  html {
+    font-size: 12px !important;
+  }
+}
+
+@media only screen and (min-width: 640px) {
+  html {
+    font-size: 14px !important;
+  }
+}
+
+@media only screen and (min-width: 750px) {
+  html {
+    font-size: 16px !important;
+  }
 }
 </style>
diff --git a/src/api/apilist.js b/src/api/apilist.js
new file mode 100644
index 0000000..13fb47d
--- /dev/null
+++ b/src/api/apilist.js
@@ -0,0 +1,259 @@
+import request from "@/api/request";
+
+export function GetHomeQuickNav() {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/index")
+            .then(res => {
+                if (res.Code == "1") {
+                    let hsjq = {
+                        tab_pane_label: "红色景区",
+                        tab_pane_content: res.Data.list.hsjq.map(a => {
+                            return {id: a.id, type: a.type, title: a.title}
+                        })
+                    };
+                    let hsjs = {
+                        tab_pane_label: "红色精神",
+                        tab_pane_content: res.Data.list.hsjs.map(a => {
+                            return {id: a.id, type: a.type, title: a.title}
+                        })
+                    };
+                    let hsjy = {
+                        tab_pane_label: "红色记忆",
+                        tab_pane_content: res.Data.list.hsjy.map(a => {
+                            return {id: a.id, type: a.type, title: a.title}
+                        })
+                    };
+                    let hsrw = {
+                        tab_pane_label: "红色人物",
+                        tab_pane_content: res.Data.list.hsrw.map(a => {
+                            return {id: a.id, type: a.type, title: a.title}
+                        })
+                    };
+                    resolve([hsjq, hsjs, hsjy, hsrw]);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetSearchInfo(searchType, searchName) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/search?searchType=" + searchType + "&searchName=" + searchName)
+            .then(res => {
+                if (res.Code == "1") {
+                    let hsjq = {
+                        title: "红色景区",
+                        data: res.Data.list.hsjq.map(a => {
+                            return {id: a.id, type: a.type, name: a.title, keyWord: a.keywords, img: a.cover_path}
+                        })
+                    };
+                    let hsjs = {
+                        title: "红色精神",
+                        data: res.Data.list.hsjs.map(a => {
+                            return {id: a.id, type: a.type, name: a.title, keyWord: a.keywords, img: a.cover_path}
+                        })
+                    };
+                    let hsjy = {
+                        title: "红色记忆",
+                        data: res.Data.list.hsjy.map(a => {
+                            return {id: a.id, type: a.type, name: a.title, keyWord: a.keywords, img: a.cover_path}
+                        })
+                    };
+                    let hsrw = {
+                        title: "红色人物",
+                        data: res.Data.list.hsrw.map(a => {
+                            return {id: a.id, type: a.type, name: a.title, keyWord: a.keywords, img: a.cover_path}
+                        })
+                    };
+                    resolve({hsjq, hsjs, hsjy, hsrw});
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetSearchHomeInfo() {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/searchPage")
+            .then(res => {
+                if (res.Code == "1") {
+                    let tjss = res.Data.tjss.map(a => {
+                        return {id: a.id, title: a.title, type: a.type}
+                    });
+                    let rmtj = res.Data.rmtj.map(a => {
+                        return {id: a.id, title: a.title, type: a.type, coverPath: a.cover_path}
+                    });
+                    resolve({tjss: tjss, rmtj: rmtj});
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+//dataType(类型): 1=红色记忆,2=红色精神,3=红色景区,4,红色人物
+export function GetDataList(dataType, searchType, searchName, pageIndex, pageSize) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/list?type=" + dataType + "&searchType=" + searchType + "&searchName=" + searchName + "&page=" + pageIndex + "&rows=" + pageSize)
+            .then(res => {
+                if (res.Code == "1") {
+                    console.log(res, "请求响应")
+                    let sceneryTabel = {
+                        currentPage: Number(res.Data.list.current_page),
+                        pageSize: Number(res.Data.list.per_page),
+                        total: res.Data.list.total,
+                        data: res.Data.list.data.map(t => {
+                            return {
+                                id: t.id,
+                                name: t.title,
+                                keyWord: t.keywords,
+                                img: t.cover_path,
+                            };
+                        }),
+                    }
+                    resolve(sceneryTabel);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetDataDetail(id) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/deails?id=" + id)
+            .then(res => {
+                if (res.Code == "1") {
+                    let detail = {
+                        id: res.Data.list.id,
+                        keyWord: res.Data.list.keywords,
+                        introduction: res.Data.list.description,
+                        file: res.Data.list.file,
+                    }
+                    resolve(detail);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetDataDetailImages(id, searchType, searchName, page, pageSize) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/picList?id=" + id + "&searchType=" + searchType + "&searchName=" + searchName + "&page=" + page + "&rows=" + pageSize)
+            .then(res => {
+                if (res.Code == "1") {
+                    let images = {
+                        pageSize: Number(res.Data.list.per_page),
+                        currentPage: Number(res.Data.list.current_page),
+                        total: res.Data.list.total,
+                        data: res.Data.list.data.map(d => {
+                            return {
+                                id: d.id,
+                                name: d.title,
+                                path: d.cover_path,
+                            }
+                        }),
+                    }
+                    resolve(images);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetDataDetailVideos(id, searchType, searchName, page, pageSize) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/videoList?id=" + id + "&searchType=" + searchType + "&searchName=" + searchName + "&page=" + page + "&rows=" + pageSize)
+            .then(res => {
+                if (res.Code == "1") {
+                    let videos = {
+                        pageSize: Number(res.Data.list.per_page),
+                        currentPage: Number(res.Data.list.current_page),
+                        total: res.Data.list.total,
+                        data: res.Data.list.data.map(d => {
+                            return {
+                                id: d.id,
+                                name: d.title,
+                                path: d.cover_path,
+                                description: d.description,
+                            }
+                        }),
+                    }
+                    resolve(videos);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetImageDetail(id, page, pid, rows) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/picDeails?id=" + id + "&page=" + page + "&pid=" + pid + "&rows=" + rows)
+            .then(res => {
+                if (res.Code == "1") {
+                    let detail = {
+                        pageSize: res.Data.list.per_page,
+                        currentPage: res.Data.list.current_page,
+                        total: res.Data.list.total,
+                        data: res.Data.list.data.map(d => {
+                            return {
+                                id: d.id,
+                                name: d.title,
+                                path: d.cover_path,
+                                keyWord: d.keywords,
+                                introduction: d.description,
+                            }
+                        }),
+                    }
+                    resolve(detail);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+export function GetVideoDetail(id) {
+    return new Promise((resolve, reject) => {
+        request.get("/index.php/index/videoDeails?id=" + id)
+            .then(res => {
+                if (res.Code == "1") {
+                    let detail = {
+                        id: res.Data.list.id,
+                        title: res.Data.list.title,
+                        patch: res.Data.list.cover_path,
+                        keyWord: res.Data.list.keywords,
+                        introduction: res.Data.list.description,
+                    }
+                    resolve(detail);
+                } else {
+                    reject(res.Message);
+                }
+            }).catch(err => {
+            throw err;
+        });
+    });
+}
+
+
diff --git a/src/api/jsonlint.js b/src/api/jsonlint.js
new file mode 100644
index 0000000..19760cd
--- /dev/null
+++ b/src/api/jsonlint.js
@@ -0,0 +1,673 @@
+/* parser generated by jison 0.4.18 */
+/*
+  Returns a Parser object of the following structure:
+
+  Parser: {
+    yy: {}
+  }
+
+  Parser.prototype: {
+    yy: {},
+    trace: function(),
+    symbols_: {associative list: name ==> number},
+    terminals_: {associative list: number ==> name},
+    productions_: [...],
+    performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
+    table: [...],
+    defaultActions: {...},
+    parseError: function(str, hash),
+    parse: function(input),
+
+    lexer: {
+        EOF: 1,
+        parseError: function(str, hash),
+        setInput: function(input),
+        input: function(),
+        unput: function(str),
+        more: function(),
+        less: function(n),
+        pastInput: function(),
+        upcomingInput: function(),
+        showPosition: function(),
+        test_match: function(regex_match_array, rule_index),
+        next: function(),
+        lex: function(),
+        begin: function(condition),
+        popState: function(),
+        _currentRules: function(),
+        topState: function(),
+        pushState: function(condition),
+
+        options: {
+            ranges: boolean           (optional: true ==> token location info will include a .range[] member)
+            flex: boolean             (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
+            backtrack_lexer: boolean  (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
+        },
+
+        performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
+        rules: [...],
+        conditions: {associative list: name ==> set},
+    }
+  }
+
+
+  token location info (@$, _$, etc.): {
+    first_line: n,
+    last_line: n,
+    first_column: n,
+    last_column: n,
+    range: [start_number, end_number]       (where the numbers are indexes into the input string, regular zero-based)
+  }
+
+
+  the parseError function receives a 'hash' object with these members for lexer and parser errors: {
+    text:        (matched text)
+    token:       (the produced terminal token, if any)
+    line:        (yylineno)
+  }
+  while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
+    loc:         (yylloc)
+    expected:    (string describing the set of expected tokens)
+    recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
+  }
+*/
+var jsonlint = (function(){
+    var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,12],$V1=[1,13],$V2=[1,9],$V3=[1,10],$V4=[1,11],$V5=[1,14],$V6=[1,15],$V7=[14,18,22,24],$V8=[18,22],$V9=[22,24];
+    var parser = {trace: function trace () { },
+        yy: {},
+        symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1},
+        terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},
+        productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],
+        performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
+            /* this == yyval */
+
+            var $0 = $$.length - 1;
+            switch (yystate) {
+                case 1:
+                    // replace escaped characters with actual character
+                    this.$ = yytext.replace(/\\(\\|")/g, "$"+"1")
+                        .replace(/\\n/g,'\n')
+                        .replace(/\\r/g,'\r')
+                        .replace(/\\t/g,'\t')
+                        .replace(/\\v/g,'\v')
+                        .replace(/\\f/g,'\f')
+                        .replace(/\\b/g,'\b');
+
+                    break;
+                case 2:
+                    this.$ = yytext == String(Number(yytext))? Number(yytext): yytext;
+                    break;
+                case 3:
+                    this.$ = null;
+                    break;
+                case 4:
+                    this.$ = true;
+                    break;
+                case 5:
+                    this.$ = false;
+                    break;
+                case 6:
+                    return this.$ = $$[$0-1];
+                    break;
+                case 13:
+                    this.$ = {};
+                    break;
+                case 14: case 19:
+                    this.$ = $$[$0-1];
+                    break;
+                case 15:
+                    this.$ = [$$[$0-2], $$[$0]];
+                    break;
+                case 16:
+                    this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
+                    break;
+                case 17:
+                    this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1];
+                    break;
+                case 18:
+                    this.$ = [];
+                    break;
+                case 20:
+                    this.$ = [$$[$0]];
+                    break;
+                case 21:
+                    this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
+                    break;
+            }
+        },
+        table: [{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,12:1,13:2,15:7,16:8,17:$V5,23:$V6},{1:[3]},{14:[1,16]},o($V7,[2,7]),o($V7,[2,8]),o($V7,[2,9]),o($V7,[2,10]),o($V7,[2,11]),o($V7,[2,12]),o($V7,[2,3]),o($V7,[2,4]),o($V7,[2,5]),o([14,18,21,22,24],[2,1]),o($V7,[2,2]),{3:20,4:$V0,18:[1,17],19:18,20:19},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:23,15:7,16:8,17:$V5,23:$V6,24:[1,21],25:22},{1:[2,6]},o($V7,[2,13]),{18:[1,24],22:[1,25]},o($V8,[2,16]),{21:[1,26]},o($V7,[2,18]),{22:[1,28],24:[1,27]},o($V9,[2,20]),o($V7,[2,14]),{3:20,4:$V0,20:29},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:30,15:7,16:8,17:$V5,23:$V6},o($V7,[2,19]),{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:31,15:7,16:8,17:$V5,23:$V6},o($V8,[2,17]),o($V8,[2,15]),o($V9,[2,21])],
+        defaultActions: {16:[2,6]},
+        parseError: function parseError (str, hash) {
+            if (hash.recoverable) {
+                this.trace(str);
+            } else {
+                var error = new Error(str);
+                error.hash = hash;
+                throw error;
+            }
+        },
+        parse: function parse(input) {
+            var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
+            var args = lstack.slice.call(arguments, 1);
+            var lexer = Object.create(this.lexer);
+            var sharedState = { yy: {} };
+            for (var k in this.yy) {
+                if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
+                    sharedState.yy[k] = this.yy[k];
+                }
+            }
+            lexer.setInput(input, sharedState.yy);
+            sharedState.yy.lexer = lexer;
+            sharedState.yy.parser = this;
+            if (typeof lexer.yylloc == 'undefined') {
+                lexer.yylloc = {};
+            }
+            var yyloc = lexer.yylloc;
+            lstack.push(yyloc);
+            var ranges = lexer.options && lexer.options.ranges;
+            if (typeof sharedState.yy.parseError === 'function') {
+                this.parseError = sharedState.yy.parseError;
+            } else {
+                this.parseError = Object.getPrototypeOf(this).parseError;
+            }
+            function popStack(n) {
+                stack.length = stack.length - 2 * n;
+                vstack.length = vstack.length - n;
+                lstack.length = lstack.length - n;
+            }
+            _token_stack:
+                var lex = function () {
+                    var token;
+                    token = lexer.lex() || EOF;
+                    if (typeof token !== 'number') {
+                        token = self.symbols_[token] || token;
+                    }
+                    return token;
+                };
+            var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
+            while (true) {
+                state = stack[stack.length - 1];
+                if (this.defaultActions[state]) {
+                    action = this.defaultActions[state];
+                } else {
+                    if (symbol === null || typeof symbol == 'undefined') {
+                        symbol = lex();
+                    }
+                    action = table[state] && table[state][symbol];
+                }
+                if (typeof action === 'undefined' || !action.length || !action[0]) {
+                    var errStr = '';
+                    expected = [];
+                    for (p in table[state]) {
+                        if (this.terminals_[p] && p > TERROR) {
+                            expected.push('\'' + this.terminals_[p] + '\'');
+                        }
+                    }
+                    if (lexer.showPosition) {
+                        errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
+                    } else {
+                        errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
+                    }
+                    this.parseError(errStr, {
+                        text: lexer.match,
+                        token: this.terminals_[symbol] || symbol,
+                        line: lexer.yylineno,
+                        loc: yyloc,
+                        expected: expected
+                    });
+                }
+                if (action[0] instanceof Array && action.length > 1) {
+                    throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
+                }
+                switch (action[0]) {
+                    case 1:
+                        stack.push(symbol);
+                        vstack.push(lexer.yytext);
+                        lstack.push(lexer.yylloc);
+                        stack.push(action[1]);
+                        symbol = null;
+                        if (!preErrorSymbol) {
+                            yyleng = lexer.yyleng;
+                            yytext = lexer.yytext;
+                            yylineno = lexer.yylineno;
+                            yyloc = lexer.yylloc;
+                            if (recovering > 0) {
+                                recovering--;
+                            }
+                        } else {
+                            symbol = preErrorSymbol;
+                            preErrorSymbol = null;
+                        }
+                        break;
+                    case 2:
+                        len = this.productions_[action[1]][1];
+                        yyval.$ = vstack[vstack.length - len];
+                        yyval._$ = {
+                            first_line: lstack[lstack.length - (len || 1)].first_line,
+                            last_line: lstack[lstack.length - 1].last_line,
+                            first_column: lstack[lstack.length - (len || 1)].first_column,
+                            last_column: lstack[lstack.length - 1].last_column
+                        };
+                        if (ranges) {
+                            yyval._$.range = [
+                                lstack[lstack.length - (len || 1)].range[0],
+                                lstack[lstack.length - 1].range[1]
+                            ];
+                        }
+                        r = this.performAction.apply(yyval, [
+                            yytext,
+                            yyleng,
+                            yylineno,
+                            sharedState.yy,
+                            action[1],
+                            vstack,
+                            lstack
+                        ].concat(args));
+                        if (typeof r !== 'undefined') {
+                            return r;
+                        }
+                        if (len) {
+                            stack = stack.slice(0, -1 * len * 2);
+                            vstack = vstack.slice(0, -1 * len);
+                            lstack = lstack.slice(0, -1 * len);
+                        }
+                        stack.push(this.productions_[action[1]][0]);
+                        vstack.push(yyval.$);
+                        lstack.push(yyval._$);
+                        newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
+                        stack.push(newState);
+                        break;
+                    case 3:
+                        return true;
+                }
+            }
+            return true;
+        }};
+    /* generated by jison-lex 0.3.4 */
+    var lexer = (function(){
+        var lexer = ({
+
+            EOF:1,
+
+            parseError:function parseError(str, hash) {
+                if (this.yy.parser) {
+                    this.yy.parser.parseError(str, hash);
+                } else {
+                    throw new Error(str);
+                }
+            },
+
+// resets the lexer, sets new input
+            setInput:function (input, yy) {
+                this.yy = yy || this.yy || {};
+                this._input = input;
+                this._more = this._backtrack = this.done = false;
+                this.yylineno = this.yyleng = 0;
+                this.yytext = this.matched = this.match = '';
+                this.conditionStack = ['INITIAL'];
+                this.yylloc = {
+                    first_line: 1,
+                    first_column: 0,
+                    last_line: 1,
+                    last_column: 0
+                };
+                if (this.options.ranges) {
+                    this.yylloc.range = [0,0];
+                }
+                this.offset = 0;
+                return this;
+            },
+
+// consumes and returns one char from the input
+            input:function () {
+                var ch = this._input[0];
+                this.yytext += ch;
+                this.yyleng++;
+                this.offset++;
+                this.match += ch;
+                this.matched += ch;
+                var lines = ch.match(/(?:\r\n?|\n).*/g);
+                if (lines) {
+                    this.yylineno++;
+                    this.yylloc.last_line++;
+                } else {
+                    this.yylloc.last_column++;
+                }
+                if (this.options.ranges) {
+                    this.yylloc.range[1]++;
+                }
+
+                this._input = this._input.slice(1);
+                return ch;
+            },
+
+// unshifts one char (or a string) into the input
+            unput:function (ch) {
+                var len = ch.length;
+                var lines = ch.split(/(?:\r\n?|\n)/g);
+
+                this._input = ch + this._input;
+                this.yytext = this.yytext.substr(0, this.yytext.length - len);
+                //this.yyleng -= len;
+                this.offset -= len;
+                var oldLines = this.match.split(/(?:\r\n?|\n)/g);
+                this.match = this.match.substr(0, this.match.length - 1);
+                this.matched = this.matched.substr(0, this.matched.length - 1);
+
+                if (lines.length - 1) {
+                    this.yylineno -= lines.length - 1;
+                }
+                var r = this.yylloc.range;
+
+                this.yylloc = {
+                    first_line: this.yylloc.first_line,
+                    last_line: this.yylineno + 1,
+                    first_column: this.yylloc.first_column,
+                    last_column: lines ?
+                        (lines.length === oldLines.length ? this.yylloc.first_column : 0)
+                        + oldLines[oldLines.length - lines.length].length - lines[0].length :
+                        this.yylloc.first_column - len
+                };
+
+                if (this.options.ranges) {
+                    this.yylloc.range = [r[0], r[0] + this.yyleng - len];
+                }
+                this.yyleng = this.yytext.length;
+                return this;
+            },
+
+// When called from action, caches matched text and appends it on next action
+            more:function () {
+                this._more = true;
+                return this;
+            },
+
+// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
+            reject:function () {
+                if (this.options.backtrack_lexer) {
+                    this._backtrack = true;
+                } else {
+                    return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
+                        text: "",
+                        token: null,
+                        line: this.yylineno
+                    });
+
+                }
+                return this;
+            },
+
+// retain first n characters of the match
+            less:function (n) {
+                this.unput(this.match.slice(n));
+            },
+
+// displays already matched input, i.e. for error messages
+            pastInput:function () {
+                var past = this.matched.substr(0, this.matched.length - this.match.length);
+                return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
+            },
+
+// displays upcoming input, i.e. for error messages
+            upcomingInput:function () {
+                var next = this.match;
+                if (next.length < 20) {
+                    next += this._input.substr(0, 20-next.length);
+                }
+                return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
+            },
+
+// displays the character position where the lexing error occurred, i.e. for error messages
+            showPosition:function () {
+                var pre = this.pastInput();
+                var c = new Array(pre.length + 1).join("-");
+                return pre + this.upcomingInput() + "\n" + c + "^";
+            },
+
+// test the lexed token: return FALSE when not a match, otherwise return token
+            test_match:function(match, indexed_rule) {
+                var token,
+                    lines,
+                    backup;
+
+                if (this.options.backtrack_lexer) {
+                    // save context
+                    backup = {
+                        yylineno: this.yylineno,
+                        yylloc: {
+                            first_line: this.yylloc.first_line,
+                            last_line: this.last_line,
+                            first_column: this.yylloc.first_column,
+                            last_column: this.yylloc.last_column
+                        },
+                        yytext: this.yytext,
+                        match: this.match,
+                        matches: this.matches,
+                        matched: this.matched,
+                        yyleng: this.yyleng,
+                        offset: this.offset,
+                        _more: this._more,
+                        _input: this._input,
+                        yy: this.yy,
+                        conditionStack: this.conditionStack.slice(0),
+                        done: this.done
+                    };
+                    if (this.options.ranges) {
+                        backup.yylloc.range = this.yylloc.range.slice(0);
+                    }
+                }
+
+                lines = match[0].match(/(?:\r\n?|\n).*/g);
+                if (lines) {
+                    this.yylineno += lines.length;
+                }
+                this.yylloc = {
+                    first_line: this.yylloc.last_line,
+                    last_line: this.yylineno + 1,
+                    first_column: this.yylloc.last_column,
+                    last_column: lines ?
+                        lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
+                        this.yylloc.last_column + match[0].length
+                };
+                this.yytext += match[0];
+                this.match += match[0];
+                this.matches = match;
+                this.yyleng = this.yytext.length;
+                if (this.options.ranges) {
+                    this.yylloc.range = [this.offset, this.offset += this.yyleng];
+                }
+                this._more = false;
+                this._backtrack = false;
+                this._input = this._input.slice(match[0].length);
+                this.matched += match[0];
+                token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
+                if (this.done && this._input) {
+                    this.done = false;
+                }
+                if (token) {
+                    return token;
+                } else if (this._backtrack) {
+                    // recover context
+                    for (var k in backup) {
+                        this[k] = backup[k];
+                    }
+                    return false; // rule action called reject() implying the next rule should be tested instead.
+                }
+                return false;
+            },
+
+// return next match in input
+            next:function () {
+                if (this.done) {
+                    return this.EOF;
+                }
+                if (!this._input) {
+                    this.done = true;
+                }
+
+                var token,
+                    match,
+                    tempMatch,
+                    index;
+                if (!this._more) {
+                    this.yytext = '';
+                    this.match = '';
+                }
+                var rules = this._currentRules();
+                for (var i = 0; i < rules.length; i++) {
+                    tempMatch = this._input.match(this.rules[rules[i]]);
+                    if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
+                        match = tempMatch;
+                        index = i;
+                        if (this.options.backtrack_lexer) {
+                            token = this.test_match(tempMatch, rules[i]);
+                            if (token !== false) {
+                                return token;
+                            } else if (this._backtrack) {
+                                match = false;
+                                continue; // rule action called reject() implying a rule MISmatch.
+                            } else {
+                                // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
+                                return false;
+                            }
+                        } else if (!this.options.flex) {
+                            break;
+                        }
+                    }
+                }
+                if (match) {
+                    token = this.test_match(match, rules[index]);
+                    if (token !== false) {
+                        return token;
+                    }
+                    // else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
+                    return false;
+                }
+                if (this._input === "") {
+                    return this.EOF;
+                } else {
+                    return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
+                        text: "",
+                        token: null,
+                        line: this.yylineno
+                    });
+                }
+            },
+
+// return next match that has a token
+            lex:function lex () {
+                var r = this.next();
+                if (r) {
+                    return r;
+                } else {
+                    return this.lex();
+                }
+            },
+
+// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
+            begin:function begin (condition) {
+                this.conditionStack.push(condition);
+            },
+
+// pop the previously active lexer condition state off the condition stack
+            popState:function popState () {
+                var n = this.conditionStack.length - 1;
+                if (n > 0) {
+                    return this.conditionStack.pop();
+                } else {
+                    return this.conditionStack[0];
+                }
+            },
+
+// produce the lexer rule set which is active for the currently active lexer condition state
+            _currentRules:function _currentRules () {
+                if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
+                    return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
+                } else {
+                    return this.conditions["INITIAL"].rules;
+                }
+            },
+
+// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
+            topState:function topState (n) {
+                n = this.conditionStack.length - 1 - Math.abs(n || 0);
+                if (n >= 0) {
+                    return this.conditionStack[n];
+                } else {
+                    return "INITIAL";
+                }
+            },
+
+// alias for begin(condition)
+            pushState:function pushState (condition) {
+                this.begin(condition);
+            },
+
+// return the number of states currently on the stack
+            stateStackSize:function stateStackSize() {
+                return this.conditionStack.length;
+            },
+            options: {},
+            performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
+                var YYSTATE=YY_START;
+                switch($avoiding_name_collisions) {
+                    case 0:/* skip whitespace */
+                        break;
+                    case 1:return 6
+                        break;
+                    case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
+                        break;
+                    case 3:return 17
+                        break;
+                    case 4:return 18
+                        break;
+                    case 5:return 23
+                        break;
+                    case 6:return 24
+                        break;
+                    case 7:return 22
+                        break;
+                    case 8:return 21
+                        break;
+                    case 9:return 10
+                        break;
+                    case 10:return 11
+                        break;
+                    case 11:return 8
+                        break;
+                    case 12:return 14
+                        break;
+                    case 13:return 'INVALID'
+                        break;
+                }
+            },
+            rules: [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/],
+            conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}}
+        });
+        return lexer;
+    })();
+    parser.lexer = lexer;
+    function Parser () {
+        this.yy = {};
+    }
+    Parser.prototype = parser;parser.Parser = Parser;
+    return new Parser;
+})();
+
+
+if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
+    exports.parser = jsonlint;
+    exports.Parser = jsonlint.Parser;
+    exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); };
+    exports.main = function commonjsMain (args) {
+        if (!args[1]) {
+            console.log('Usage: '+args[0]+' FILE');
+            process.exit(1);
+        }
+        var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
+        return exports.parser.parse(source);
+    };
+    if (typeof module !== 'undefined' && require.main === module) {
+        exports.main(process.argv.slice(1));
+    }
+}
diff --git a/src/api/request.js b/src/api/request.js
new file mode 100644
index 0000000..6896ae9
--- /dev/null
+++ b/src/api/request.js
@@ -0,0 +1,74 @@
+import axios from 'axios'
+import {Message} from 'element-ui'
+import jsonlint from "@/api/jsonlint.js"
+
+const service = axios.create({
+    baseURL: process.env.VUE_APP_BASE_API,
+    timeout: 60000, // request timeout
+    headers: {},
+    transformResponse: [function (data) {
+        if (typeof data == "string") {
+            try {
+                data = jsonlint.parse((data));
+            } catch (e) {
+                console.log(e, 'axios:transformResponse异常');
+            }
+        }
+        return data;
+    }]
+})
+
+service.interceptors.request.use(
+    config => {
+        return config
+    },
+    error => {
+        return Promise.reject(error)
+    })
+
+service.interceptors.response.use(
+    response => {
+        if (response.status == 200) {
+            const resData = response.data;
+            return resData;
+        } else {
+            return Promise.reject(response)
+        }
+    },
+    error => {
+        Message({message: error.response.data.msg || '系统错误', type: 'error', duration: 2 * 1000})
+        return Promise.reject(error)
+    })
+
+export default {
+    //get请求
+    get(url, param) {
+        return new Promise(resolve => {
+            service({
+                method: 'get',
+                url,
+                params: param,
+            }).then(res => {
+                resolve(res);
+            }).catch(err => {
+                console.log(err, 'axios异常');
+                throw err;
+            });
+        });
+    },
+    //post请求
+    post(url, param) {
+        return new Promise(resolve => {
+            service({
+                method: 'post',
+                url,
+                data: param,
+            }).then(res => {
+                resolve(res);
+            }).catch(err => {
+                console.log(err, 'axios异常');
+                throw err;
+            });
+        });
+    },
+}
diff --git a/src/assets/datadetail/detail@1x.png b/src/assets/datadetail/detail@1x.png
new file mode 100644
index 0000000..508f6d2
--- /dev/null
+++ b/src/assets/datadetail/detail@1x.png
Binary files differ
diff --git a/src/assets/datalist/datalist@1x.png b/src/assets/datalist/datalist@1x.png
new file mode 100644
index 0000000..882abec
--- /dev/null
+++ b/src/assets/datalist/datalist@1x.png
Binary files differ
diff --git a/src/assets/home_background@1x.png b/src/assets/home_background@1x.png
new file mode 100644
index 0000000..6fcb834
--- /dev/null
+++ b/src/assets/home_background@1x.png
Binary files differ
diff --git a/src/assets/icon/demo.css b/src/assets/icon/demo.css
new file mode 100644
index 0000000..a67054a
--- /dev/null
+++ b/src/assets/icon/demo.css
@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}
diff --git a/src/assets/icon/demo_index.html b/src/assets/icon/demo_index.html
new file mode 100644
index 0000000..0e9f7a8
--- /dev/null
+++ b/src/assets/icon/demo_index.html
@@ -0,0 +1,211 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>iconfont Demo</title>
+  <link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico" type="image/x-icon"/>
+  <link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+  <style>
+    .main .logo {
+      margin-top: 0;
+      height: auto;
+    }
+
+    .main .logo a {
+      display: flex;
+      align-items: center;
+    }
+
+    .main .logo .sub-title {
+      margin-left: 0.5em;
+      font-size: 22px;
+      color: #fff;
+      background: linear-gradient(-45deg, #3967FF, #B500FE);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  </style>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
+      <img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
+      
+    </a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2997242" target="_blank" class="nav-more">查看项目</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe82e;</span>
+                <div class="name">search</div>
+                <div class="code-name">&amp;#xe82e;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.woff2?t=1638945390871') format('woff2'),
+       url('iconfont.woff?t=1638945390871') format('woff'),
+       url('iconfont.ttf?t=1638945390871') format('truetype');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont icon-search"></span>
+            <div class="name">
+              search
+            </div>
+            <div class="code-name">.icon-search
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont icon-xxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <div class="content symbol">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#icon-search"></use>
+                </svg>
+                <div class="name">search</div>
+                <div class="code-name">#icon-search</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>
diff --git a/src/assets/icon/iconfont.css b/src/assets/icon/iconfont.css
new file mode 100644
index 0000000..0061006
--- /dev/null
+++ b/src/assets/icon/iconfont.css
@@ -0,0 +1,19 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 2997242 */
+  src: url('iconfont.woff2?t=1638945390871') format('woff2'),
+       url('iconfont.woff?t=1638945390871') format('woff'),
+       url('iconfont.ttf?t=1638945390871') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-search:before {
+  content: "\e82e";
+}
+
diff --git a/src/assets/icon/iconfont.js b/src/assets/icon/iconfont.js
new file mode 100644
index 0000000..b99950c
--- /dev/null
+++ b/src/assets/icon/iconfont.js
@@ -0,0 +1 @@
+!function(e){var t,n,o,i,c,d='<svg><symbol id="icon-search" viewBox="0 0 1024 1024"><path d="M1005.312 914.752l-198.528-198.464A448 448 0 1 0 0 448a448 448 0 0 0 716.288 358.784l198.4 198.4a64 64 0 1 0 90.624-90.432zM448 767.936A320 320 0 1 1 448 128a320 320 0 0 1 0 640z" fill="#262626" ></path></symbol></svg>',a=(a=document.getElementsByTagName("script"))[a.length-1].getAttribute("data-injectcss"),l=function(e,t){t.parentNode.insertBefore(e,t)};if(a&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("<style>.svgfont {display: inline-block;width: 1em;height: 1em;fill: currentColor;vertical-align: -0.1em;font-size:16px;}</style>")}catch(e){console&&console.log(e)}}function s(){c||(c=!0,o())}function r(){try{i.documentElement.doScroll("left")}catch(e){return void setTimeout(r,50)}s()}t=function(){var e,t;(t=document.createElement("div")).innerHTML=d,d=null,(e=t.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",t=e,(e=document.body).firstChild?l(t,e.firstChild):e.appendChild(t))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(t,0):(n=function(){document.removeEventListener("DOMContentLoaded",n,!1),t()},document.addEventListener("DOMContentLoaded",n,!1)):document.attachEvent&&(o=t,i=e.document,c=!1,r(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,s())})}(window);
\ No newline at end of file
diff --git a/src/assets/icon/iconfont.json b/src/assets/icon/iconfont.json
new file mode 100644
index 0000000..7ae7f94
--- /dev/null
+++ b/src/assets/icon/iconfont.json
@@ -0,0 +1,16 @@
+{
+  "id": "2997242",
+  "name": "name",
+  "font_family": "iconfont",
+  "css_prefix_text": "icon-",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "6151301",
+      "name": "search",
+      "font_class": "search",
+      "unicode": "e82e",
+      "unicode_decimal": 59438
+    }
+  ]
+}
diff --git a/src/assets/icon/iconfont.ttf b/src/assets/icon/iconfont.ttf
new file mode 100644
index 0000000..fded390
--- /dev/null
+++ b/src/assets/icon/iconfont.ttf
Binary files differ
diff --git a/src/assets/icon/iconfont.woff b/src/assets/icon/iconfont.woff
new file mode 100644
index 0000000..c955146
--- /dev/null
+++ b/src/assets/icon/iconfont.woff
Binary files differ
diff --git a/src/assets/icon/iconfont.woff2 b/src/assets/icon/iconfont.woff2
new file mode 100644
index 0000000..02c10a9
--- /dev/null
+++ b/src/assets/icon/iconfont.woff2
Binary files differ
diff --git a/src/assets/nav_memory@1x.png b/src/assets/nav_memory@1x.png
new file mode 100644
index 0000000..aeedcd7
--- /dev/null
+++ b/src/assets/nav_memory@1x.png
Binary files differ
diff --git a/src/assets/nav_personage@1x.png b/src/assets/nav_personage@1x.png
new file mode 100644
index 0000000..dd3b123
--- /dev/null
+++ b/src/assets/nav_personage@1x.png
Binary files differ
diff --git a/src/assets/nav_scenery@1x.png b/src/assets/nav_scenery@1x.png
new file mode 100644
index 0000000..f9be825
--- /dev/null
+++ b/src/assets/nav_scenery@1x.png
Binary files differ
diff --git a/src/assets/nav_spirit@1x.png b/src/assets/nav_spirit@1x.png
new file mode 100644
index 0000000..0b83fc3
--- /dev/null
+++ b/src/assets/nav_spirit@1x.png
Binary files differ
diff --git a/src/assets/search/search@1x.png b/src/assets/search/search@1x.png
new file mode 100644
index 0000000..08c7c5a
--- /dev/null
+++ b/src/assets/search/search@1x.png
Binary files differ
diff --git a/src/components/CustomSearch1.vue b/src/components/CustomSearch1.vue
new file mode 100644
index 0000000..ef601dd
--- /dev/null
+++ b/src/components/CustomSearch1.vue
@@ -0,0 +1,77 @@
+<template>
+  <div class="custom-search1">
+    <input class="input-inner" type="text" autocapitalize="off" placeholder="请输入检索词" v-model="searchName"/>
+    <div class="input-append" v-on:click="$emit('search',searchName)">
+      <svg t="1638943404588" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+           p-id="6664" width="200" height="200">
+        <path
+            d="M469.333 192c153.174 0 277.334 124.16 277.334 277.333 0 68.054-24.534 130.411-65.216 178.688L846.336 818.24l-48.341 49.877L630.4 695.125a276.053 276.053 0 0 1-161.067 51.542C316.16 746.667 192 622.507 192 469.333S316.16 192 469.333 192z m0 64C351.51 256 256 351.51 256 469.333s95.51 213.334 213.333 213.334 213.334-95.51 213.334-213.334S587.157 256 469.333 256z"
+            p-id="6665"></path>
+      </svg>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "CustomSearch1",
+  data() {
+    return {
+      searchName: ""
+    }
+  }
+}
+</script>
+
+<style scoped>
+.icon {
+  fill: currentColor;
+  color: #EFC587;
+}
+
+.custom-search1 {
+  width: 99%;
+  height: 8vh;
+  border: 4px solid #EFC587;
+  box-sizing: border-box;
+  border-radius: 200px;
+  background-color: rgba(0, 0, 0, 0.23);
+
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+}
+
+.custom-search1 .input-inner {
+  width: 80%;
+  height: 95%;
+  border: 0;
+  border-radius: 200px;
+  background-color: rgba(0, 0, 0, 0);
+
+  font-size: 1.75rem;
+  font-family: Microsoft YaHei;
+  font-weight: 400;
+  line-height: 1.25rem;
+  color: #EFC587;
+  opacity: 1;
+}
+
+.custom-search1 .input-inner:focus {
+  outline: none;
+}
+
+.custom-search1 .input-append {
+  width: 9%;
+  height: 95%;
+  cursor: pointer;
+}
+
+.custom-search1 .input-append svg {
+  max-width: 2.68rem;
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/CustomSearch2.vue b/src/components/CustomSearch2.vue
new file mode 100644
index 0000000..724c7c0
--- /dev/null
+++ b/src/components/CustomSearch2.vue
@@ -0,0 +1,201 @@
+<template>
+  <div class="custom-search2">
+    <div class="custom-search-before" @click="ActionSheet">
+      <input class="input-inner" type="text" readonly="readonly" autocomplete="off" placeholder="请选择"
+             v-model="searchType.text">
+      <span class="input-append">
+        <svg t="1638954207837" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+             p-id="6664" width="128" height="128"><path
+            d="M500.8 604.779L267.307 371.392l-45.227 45.27 278.741 278.613L779.307 416.66l-45.248-45.248z" p-id="6665"
+            fill="#EFC587"></path></svg>
+      </span>
+    </div>
+    <div class="custom-search-after">
+      <input class="input-inner" type="text" autocapitalize="off" placeholder="请输入检索词" v-model="searchName"  v-on:focus="Focus"/>
+      <div class="input-append" v-on:click="Search">
+        <svg t="1638943404588" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+             p-id="6664" width="200" height="200">
+          <path
+              d="M469.333 192c153.174 0 277.334 124.16 277.334 277.333 0 68.054-24.534 130.411-65.216 178.688L846.336 818.24l-48.341 49.877L630.4 695.125a276.053 276.053 0 0 1-161.067 51.542C316.16 746.667 192 622.507 192 469.333S316.16 192 469.333 192z m0 64C351.51 256 256 351.51 256 469.333s95.51 213.334 213.333 213.334 213.334-95.51 213.334-213.334S587.157 256 469.333 256z"
+              p-id="6665"></path>
+        </svg>
+      </div>
+    </div>
+    <actionsheet
+        :actions="searchTypeItems"
+        v-model="actionsheet">
+    </actionsheet>
+  </div>
+</template>
+
+<script>
+import {Actionsheet} from 'mint-ui';
+
+export default {
+  name: "CustomSearch2",
+  components: {Actionsheet},
+  data() {
+    return {
+      actionsheet: false,
+      searchType: {
+        text: "名称",
+        value: "title",
+      },
+      searchName: "",
+      searchTypeItems: [{
+        name: "名称",
+        value: "title",
+        method: this.SearchTypeItem
+      }, {
+        name: "关键字",
+        value: "keywords",
+        method: this.SearchTypeItem
+      }, {
+        name: "简介",
+        value: "descriprion",
+        method: this.SearchTypeItem
+      }],
+    }
+  },
+  methods: {
+    ActionSheet: function () {
+      this.actionsheet = true;
+    },
+    SearchTypeItem: function (obj) {
+      this.searchType = {
+        text: obj.name,
+        value: obj.value,
+      }
+    },
+    Search: function () {
+      if (this.searchName != "") {
+        if (localStorage.searchHistory) {
+          let hisArray = eval(localStorage.searchHistory);
+          hisArray.push({
+            searchType: this.searchType.value,
+            searchName: this.searchName,
+          });
+          localStorage.searchHistory = JSON.stringify(hisArray);
+        } else {
+          let hisArray = [{
+            searchType: this.searchType.value,
+            searchName: this.searchName,
+          }];
+          localStorage.searchHistory = JSON.stringify(hisArray);
+        }
+      }
+      this.$emit('search', this.searchType.value, this.searchName)
+    },
+    Focus: function () {
+      this.$emit('focus')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.icon {
+  fill: currentColor;
+  color: #EFC587;
+}
+
+.custom-search2 {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+}
+
+.custom-search-before {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+
+  width: 30%;
+  height: 4vh;
+  background: rgba(0, 0, 0, 0.46);
+  border: 2px solid #EFC587;
+  border-radius: 6px;
+  margin-right: 1rem;
+}
+
+.custom-search-before .input-inner {
+  width: 70%;
+  height: 100%;
+  border: 0;
+  background-color: rgba(0, 0, 0, 0);
+
+  font-size: 1.6rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2rem;
+  color: #EFC587;
+  cursor: pointer
+}
+
+.custom-search-before .input-inner:focus {
+  outline: none;
+}
+
+.custom-search-before .input-append {
+  width: 30%;
+  height: 100%;
+  cursor: pointer;
+}
+
+.custom-search-before .input-append svg {
+  max-width: 1.6rem;
+  width: 100%;
+  height: 100%;
+}
+
+
+.custom-search-after {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+
+  width: 99%;
+  height: 4vh;
+  background: rgba(0, 0, 0, 0.59);
+  border: 2px solid #EFC587;
+  opacity: 1;
+  border-radius: 6px;
+}
+
+.custom-search-after .input-inner {
+  width: 90%;
+  height: 95%;
+  border: 0;
+  border-radius: 200px;
+  background-color: rgba(0, 0, 0, 0);
+
+  font-size: 1.31rem;
+  font-family: Microsoft YaHei;
+  font-weight: 400;
+  line-height: 3.33rem;
+  color: rgba(239, 197, 135, 0.6);
+  opacity: 1;
+}
+
+.custom-search-after .input-inner:focus {
+  outline: none;
+}
+
+.custom-search-after .input-append {
+  width: 9%;
+  height: 95%;
+  cursor: pointer;
+}
+
+.custom-search-after .input-append svg {
+  max-width: 1.6rem;
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/CustomSearch3.vue b/src/components/CustomSearch3.vue
new file mode 100644
index 0000000..8b65e18
--- /dev/null
+++ b/src/components/CustomSearch3.vue
@@ -0,0 +1,183 @@
+<template>
+  <div class="custom-search3">
+    <div class="custom-search-before" @click="ActionSheet">
+      <input class="input-inner" type="text" readonly="readonly" autocomplete="off" placeholder="请选择"
+             v-model="searchType.text">
+      <span class="input-append">
+        <svg t="1638954207837" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+             p-id="6664" width="128" height="128"><path
+            d="M500.8 604.779L267.307 371.392l-45.227 45.27 278.741 278.613L779.307 416.66l-45.248-45.248z" p-id="6665"
+            fill="#606060"></path></svg>
+      </span>
+    </div>
+    <div class="custom-search-after">
+      <input class="input-inner" type="text" autocapitalize="off" placeholder="请输入检索词" v-model="searchName"/>
+      <div class="input-append" v-on:click="Search">
+        <svg t="1638943404588" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+             p-id="6664" width="200" height="200">
+          <path
+              d="M469.333 192c153.174 0 277.334 124.16 277.334 277.333 0 68.054-24.534 130.411-65.216 178.688L846.336 818.24l-48.341 49.877L630.4 695.125a276.053 276.053 0 0 1-161.067 51.542C316.16 746.667 192 622.507 192 469.333S316.16 192 469.333 192z m0 64C351.51 256 256 351.51 256 469.333s95.51 213.334 213.333 213.334 213.334-95.51 213.334-213.334S587.157 256 469.333 256z"
+              p-id="6665" fill="#BC0000"></path>
+        </svg>
+      </div>
+    </div>
+    <actionsheet
+        :actions="searchTypeItems"
+        v-model="actionsheet">
+    </actionsheet>
+  </div>
+</template>
+
+<script>
+import {Actionsheet} from 'mint-ui';
+
+export default {
+  name: "CustomSearch3",
+  components: {Actionsheet},
+  data() {
+    return {
+      actionsheet: false,
+      searchType: {
+        text: "名称",
+        value: "title",
+      },
+      searchName: "",
+      searchTypeItems: [{
+        name: "名称",
+        value: "title",
+        method: this.SearchTypeItem
+      }, {
+        name: "关键字",
+        value: "keywords",
+        method: this.SearchTypeItem
+      }, {
+        name: "简介",
+        value: "descriprion",
+        method: this.SearchTypeItem
+      }],
+    }
+  },
+  methods: {
+    ActionSheet: function () {
+      this.actionsheet = true;
+    },
+    SearchTypeItem: function (obj) {
+      this.searchType = {
+        text: obj.name,
+        value: obj.value,
+      }
+    },
+    Search: function () {
+      this.$emit('search', this.searchType.value, this.searchName)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.icon {
+  fill: currentColor;
+  color: #EFC587;
+}
+
+.custom-search3 {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+
+  width: 100%;
+}
+
+.custom-search-before {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+
+  width: 25%;
+  height: 4vh;
+  background: #FAFAFA;
+  border: 2px solid #EAEAEA;
+  border-radius: 6px;
+  margin-right: 1rem;
+}
+
+.custom-search-before .input-inner {
+  width: 70%;
+  height: 100%;
+  border: 0;
+  background-color: rgba(0, 0, 0, 0);
+
+  font-size: 1.5rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 1.5rem;
+  color: #606060;
+  cursor: pointer
+}
+
+.custom-search-before .input-inner:focus {
+  outline: none;
+}
+
+.custom-search-before .input-append {
+  width: 30%;
+  height: 100%;
+  cursor: pointer;
+}
+
+.custom-search-before .input-append svg {
+  max-width: 2rem;
+  width: 100%;
+  height: 100%;
+}
+
+
+.custom-search-after {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: center;
+  align-items: center;
+
+  width: 75%;
+  height: 4vh;
+  background: white;
+  border: 2px solid #BC0000;
+  opacity: 1;
+  border-radius: 6px;
+}
+
+.custom-search-after .input-inner {
+  width: 90%;
+  height: 3vh;
+  border: 0;
+  border-radius: 200px;
+
+  font-size: 1.4rem;
+  font-family: Microsoft YaHei;
+  font-weight: 400;
+  line-height: 1.4rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.custom-search-after .input-inner:focus {
+  outline: none;
+}
+
+.custom-search-after .input-append {
+  width: 9%;
+  height: 95%;
+  cursor: pointer;
+}
+
+.custom-search-after .input-append svg {
+  max-width: 2rem;
+  width: 100%;
+  height: 100%;
+}
+</style>
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
deleted file mode 100644
index 879051a..0000000
--- a/src/components/HelloWorld.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<template>
-  <div class="hello">
-    <h1>{{ msg }}</h1>
-    <p>
-      For a guide and recipes on how to configure / customize this project,<br>
-      check out the
-      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
-    </p>
-    <h3>Installed CLI Plugins</h3>
-    <ul>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
-      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
-    </ul>
-    <h3>Essential Links</h3>
-    <ul>
-      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
-      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
-      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
-      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
-      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
-    </ul>
-    <h3>Ecosystem</h3>
-    <ul>
-      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
-      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
-      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
-      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
-      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
-    </ul>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'HelloWorld',
-  props: {
-    msg: String
-  }
-}
-</script>
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped>
-h3 {
-  margin: 40px 0 0;
-}
-ul {
-  list-style-type: none;
-  padding: 0;
-}
-li {
-  display: inline-block;
-  margin: 0 10px;
-}
-a {
-  color: #42b983;
-}
-</style>
diff --git a/src/main.js b/src/main.js
index 63eb05f..8cacbb0 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,8 +1,148 @@
 import Vue from 'vue'
+import VueRouter from 'vue-router'
+import MintUI from 'mint-ui'
+import 'mint-ui/lib/style.css'
+import '../src/assets/icon/iconfont.css'
+
+import Meta from "vue-meta";
+
 import App from './App.vue'
+import LayoutList from './views/layout/listIndex'
+import LayoutSearch from './views/layout/searchIndex'
+
+import HomePage from './views/home'
+import SearchIndex from './views/search/index'
+import SearchResults from './views/search/results'
+
+import SceneryList from './views/scenery/list'
+import SceneryDetail from './views/scenery/detail'
+import SceneryDetailImage from './views/scenery/detailImage'
+import SceneryDetailVideo from './views/scenery/detailvideo'
+
+import MemoryList from './views/memory/list'
+import MemoryDetail from './views/memory/detail'
+import MemoryDetailImage from './views/memory/detailImage'
+import MemoryDetailVideo from './views/memory/detailvideo'
+
+import SpiritList from './views/spirit/list'
+import SpiritDetail from './views/spirit/detail'
+import SpiritDetailImage from './views/spirit/detailImage'
+import SpiritDetailVideo from './views/spirit/detailvideo'
+
+import PersonageList from './views/personage/list'
+import PersonageDetail from './views/personage/detail'
+import PersonageDetailImage from './views/personage/detailImage'
+import PersonageDetailVideo from './views/personage/detailvideo'
 
 Vue.config.productionTip = false
 
+const routes = [
+    {
+        name: 'default', path: '/', redirect: '/home', meta: {
+            title: '首页'
+        }
+    },
+    {name: 'home', path: '/home', component: HomePage},
+    {
+        name: 'search', path: '/search', component: LayoutSearch,
+        meta: {
+            title: '数据检索'
+        },
+        children: [
+            {name: 'search-index', path: 'index', component: SearchIndex},
+            {name: 'search-results', path: 'results', component: SearchResults},
+        ]
+    },
+    {
+        name: 'scenery', path: '/scenery', component: LayoutList,
+        meta: {
+            title: '红色景区库'
+        },
+        children: [
+            {name: 'scenery-list', path: 'list', component: SceneryList},
+        ],
+    },
+    {
+        name: 'scenery', path: '/scenery', component: App,
+        meta: {
+            title: '红色景区库'
+        },
+        children: [
+            {name: 'scenery-detail', path: 'detail', component: SceneryDetail},
+            {name: 'scenery-detail-image', path: 'detail/image', component: SceneryDetailImage},
+            {name: 'scenery-detail-video', path: 'detail/video', component: SceneryDetailVideo},
+        ],
+    },
+    {
+        name: 'memory', path: '/memory', component: LayoutList,
+        meta: {
+            title: '红色记忆库'
+        },
+        children: [
+            {name: 'memory-list', path: 'list', component: MemoryList},
+        ],
+    },
+    {
+        name: 'memory', path: '/memory', component: App,
+        meta: {
+            title: '红色记忆库'
+        },
+        children: [
+            {name: 'memory-detail', path: 'detail', component: MemoryDetail},
+            {name: 'memory-detail-image', path: 'detail/image', component: MemoryDetailImage},
+            {name: 'memory-detail-video', path: 'detail/video', component: MemoryDetailVideo},
+        ],
+    },
+    {
+        name: 'spirit', path: '/spirit', component: LayoutList,
+        meta: {
+            title: '红色精神库'
+        },
+        children: [
+            {name: 'spirit-list', path: 'list', component: SpiritList},
+        ],
+    },
+    {
+        name: 'spirit', path: '/spirit', component: App,
+        meta: {
+            title: '红色精神库'
+        },
+        children: [
+            {name: 'spirit-detail', path: 'detail', component: SpiritDetail},
+            {name: 'spirit-detail-image', path: 'detail/image', component: SpiritDetailImage},
+            {name: 'spirit-detail-video', path: 'detail/video', component: SpiritDetailVideo},
+        ],
+    },
+    {
+        name: 'personage', path: '/personage', component: LayoutList,
+        meta: {
+            title: '红色人物库'
+        },
+        children: [
+            {name: 'personage-list', path: 'list', component: PersonageList},
+        ],
+    },
+    {
+        name: 'personage', path: '/personage', component: App,
+        meta: {
+            title: '红色人物库'
+        },
+        children: [
+            {name: 'personage-detail', path: 'detail', component: PersonageDetail},
+            {name: 'personage-detail-image', path: 'detail/image', component: PersonageDetailImage},
+            {name: 'personage-detail-video', path: 'detail/video', component: PersonageDetailVideo},
+        ],
+    },
+];
+const router = new VueRouter({
+    routes
+});
+
+Vue.use(VueRouter);
+Vue.use(MintUI);
+Vue.use(Meta);
+
 new Vue({
-  render: h => h(App),
+    render: h => h(App),
+    router
 }).$mount('#app')
diff --git a/src/views/home.vue b/src/views/home.vue
new file mode 100644
index 0000000..4288a96
--- /dev/null
+++ b/src/views/home.vue
@@ -0,0 +1,191 @@
+<template>
+  <div class="home">
+    <h1>吉林省红色旅游数据库</h1>
+    <div class="search-div">
+      <div class="search-type">
+        <ul>
+          <li :class="searchType=='title'?'selected':''" @click="SwitchSearchType('title')">名称</li>
+          <li :class="searchType=='keywords'?'selected':''" @click="SwitchSearchType('keywords')">关键词</li>
+          <li :class="searchType=='description'?'selected':''" @click="SwitchSearchType('description')">简介</li>
+        </ul>
+      </div>
+      <div class="search-name">
+        <CustomSearch1 v-on:search="Search"></CustomSearch1>
+      </div>
+    </div>
+    <div class="navigation-div">
+      <div class="nav-div nav-memory" @click="NavigationGo(1)">
+        红色记忆
+      </div>
+      <div class="nav-div nav-personage" @click="NavigationGo(4)">
+        红色人物
+      </div>
+      <div class="nav-div nav-scenery" @click="NavigationGo(3)">
+        红色景区
+      </div>
+      <div class="nav-div nav-spirit" @click="NavigationGo(2)">
+        红色精神
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch1 from '../components/CustomSearch1'
+
+export default {
+  name: "home",
+  components: {
+    CustomSearch1
+  },
+  data() {
+    return {
+      searchType: "title",
+    }
+  },
+  methods: {
+    Search: function (searchName) {
+      this.$router.push({name: "search-results", query: {searchType: this.searchType, searchName: searchName}});
+    },
+    SwitchSearchType: function (searchType) {
+      this.searchType = searchType;
+    },
+    NavigationGo(type) {
+      switch (type) {
+        case 1:
+          this.$router.push({name: "memory-list", query: {}});
+          break;
+        case 2:
+          this.$router.push({name: "spirit-list", query: {}});
+          break;
+        case 3:
+          this.$router.push({name: "scenery-list", query: {}});
+          break;
+        case 4:
+          this.$router.push({name: "personage-list", query: {}});
+          break;
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.home {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+
+  width: 100%;
+  height: 99vh;
+  background: url("../assets/home_background@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+}
+
+h1 {
+  width: 70%;
+
+  font-size: 4.5rem;
+  font-family: FZZhengHeiS-DB-GB;
+  font-weight: 400;
+  line-height: 6.87rem;
+  color: #FFFFFF;
+}
+
+.search-div {
+  width: 90%;
+  padding-bottom: 3.8vh;
+}
+
+.search-div ul {
+  text-align: left;
+}
+
+.search-div ul li {
+  cursor: pointer;
+  display: inline-block;
+  list-style-type: none;
+  padding-right: 5vw;
+
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  color: #FFFFFF;
+}
+
+.search-div ul li.selected {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  color: #EFC587;
+}
+
+.navigation-div {
+  width: 90%;
+}
+
+.navigation-div .nav-div {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+
+  width: 100%;
+  height: 10vh;
+  border-radius: 10px;
+  margin-bottom: 3vh;
+  cursor: pointer;
+}
+
+.navigation-div .nav-memory {
+  background: url("../assets/nav_memory@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+
+  font-size: 3.37rem;
+  font-family: FZDaBiaoSong-B06S;
+  font-weight: 400;
+  line-height: 1.93rem;
+  color: #BC0000;
+  text-shadow: 0px 3px 6px rgba(255, 255, 255, 0.16);
+  opacity: 1;
+}
+
+.navigation-div .nav-personage {
+  background: url("../assets/nav_personage@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+
+  font-size: 3.37rem;
+  font-family: FZDaBiaoSong-B06S;
+  font-weight: 400;
+  line-height: 1.93rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.navigation-div .nav-scenery {
+  background: url("../assets/nav_scenery@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+
+  font-size: 3.37rem;
+  font-family: FZDaBiaoSong-B06S;
+  font-weight: 400;
+  line-height: 1.93rem;
+  color: #FFE36C;
+  text-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+}
+
+.navigation-div .nav-spirit {
+  background: url("../assets/nav_spirit@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+
+  font-size: 3.37rem;
+  font-family: FZDaBiaoSong-B06S;
+  font-weight: 400;
+  line-height: 1.93rem;
+  color: #FFE36C;
+  text-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+}
+</style>
diff --git a/src/views/layout/listIndex.vue b/src/views/layout/listIndex.vue
new file mode 100644
index 0000000..f450b0c
--- /dev/null
+++ b/src/views/layout/listIndex.vue
@@ -0,0 +1,155 @@
+<template>
+  <div class="datalist">
+    <div class="data-title">
+      <div @click="ToHome">吉林省红色旅游数据库</div>
+      <div @click="ToHome">红色景点库</div>
+    </div>
+    <div class="data-content">
+      <transition name="fade-transform" mode="out-in">
+        <router-view :key="key"/>
+      </transition>
+    </div>
+    <mt-tabbar v-model="dataType" :fixed="true">
+      <mt-tab-item id="1">红色记忆</mt-tab-item>
+      <mt-tab-item id="2">红色精神</mt-tab-item>
+      <mt-tab-item id="3">红色景区</mt-tab-item>
+      <mt-tab-item id="4">红色人物</mt-tab-item>
+    </mt-tabbar>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "listIndex",
+  data() {
+    return {
+      dataType: ""
+    }
+  },
+  methods: {
+    ToHome: function () {
+      this.$router.push({name: "home"});
+    }
+  },
+  watch: {
+    dataType: function () {
+      switch (this.dataType) {
+        case "1":
+          this.$router.push({name: "memory-list"});
+          break;
+        case "2":
+          this.$router.push({name: "spirit-list"});
+          break;
+        case "3":
+          this.$router.push({name: "scenery-list"});
+          break;
+        case "4":
+          this.$router.push({name: "personage-list"});
+          break;
+      }
+    },
+  },
+  computed: {
+    key() {
+      return this.$route.path
+    }
+  },
+  created() {
+    if (this.dataType == "") {
+      switch (this.$route.name) {
+        case "memory-list":
+          this.dataType = "1";
+          break;
+        case "spirit-list":
+          this.dataType = "2"
+          break;
+        case "scenery-list":
+          this.dataType = "3";
+          break;
+        case "personage-list":
+          this.dataType = "4";
+          break;
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.datalist {
+  width: 100%;
+  height: 100vh;
+}
+
+.data-title {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+
+  width: 100%;
+  height: 16vh;
+  background: url("../../assets/datalist/datalist@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+}
+
+.data-title > div {
+  width: 100%;
+  text-align: left;
+  font-size: 2.87rem;
+  font-family: FZZhengHeiS-DB-GB;
+  font-weight: 400;
+  line-height: 4.37rem;
+  color: #FFFFFF;
+  opacity: 1;
+  padding-left: 2rem;
+}
+
+.data-content {
+  width: 100%;
+  height: 75vh;
+  background: #FFFFFF;
+  border-radius: 10px 10px 0px 0px;
+
+  position: relative;
+  z-index: 5;
+}
+
+.data-content .list-root{
+  height: 100%;
+  width: 100%;
+}
+
+.mint-tabbar {
+  height: 10vh;
+  background: white;
+  z-index: 9;
+}
+
+.mint-tabbar /deep/ .mint-tab-item {
+  padding: 20px 0;
+}
+
+.mint-tabbar /deep/ .mint-tab-item-label {
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 1.93rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-tabbar /deep/ .is-selected {
+  background-color: white;
+  border-top: 0.5vh solid #BC0000;
+}
+
+.mint-tabbar /deep/ .is-selected .mint-tab-item-label {
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 1.93rem;
+  color: #BC0000;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/layout/searchIndex.vue b/src/views/layout/searchIndex.vue
new file mode 100644
index 0000000..975aa60
--- /dev/null
+++ b/src/views/layout/searchIndex.vue
@@ -0,0 +1,75 @@
+<template>
+  <div class="search">
+    <div class="search-input">
+      <custom-search2 v-on:search="Search" v-on:focus="Focus"></custom-search2>
+    </div>
+    <div class="search-content">
+      <transition name="fade-transform" mode="out-in">
+        <router-view :key="key"/>
+      </transition>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch2 from "@/components/CustomSearch2";
+
+export default {
+  name: "searchIndex",
+  components: {CustomSearch2},
+  methods: {
+    Search: function (searchType, searchName) {
+      this.$router.push({
+        name: 'search-results',
+        query: {
+          searchType: searchType,
+          searchName: searchName
+        }
+      });
+
+    },
+    Focus: function () {
+      this.$router.push({
+        name: 'search-index'
+      });
+    }
+  },
+  computed: {
+    key() {
+      return this.$route.path
+    }
+  }
+}
+</script>
+
+<style scoped>
+.search {
+  width: 100%;
+}
+
+.search .search-input {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+
+  width: 100%;
+  height: 10vh;
+  background: url("../../assets/search/search@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+}
+
+.search .search-input .custom-search2 {
+  width: 90%;
+}
+
+.search .search-content {
+  width: 100%;
+  background: #FFFFFF;
+  border-radius: 10px 10px 0px 0px;
+
+  position: relative;
+  top: -10px;
+  z-index: 10;
+}
+</style>
diff --git a/src/views/memory/detail.vue b/src/views/memory/detail.vue
new file mode 100644
index 0000000..800f60b
--- /dev/null
+++ b/src/views/memory/detail.vue
@@ -0,0 +1,510 @@
+<template>
+  <div class="data-detail">
+    <div class="title">
+      <div class="title-left">
+        <div class="title-name" @click="ToListPage">{{ titleName }}</div>
+        <div class="title-introduce">{{ titleIntroduce }}</div>
+      </div>
+      <div class="title-right">
+        <div class="online-preview" @click="OnlinePreview(basisInfo.file)">在线浏览</div>
+      </div>
+    </div>
+    <div class="content">
+      <mt-navbar ref="navbar" v-model="navbarIndex">
+        <mt-tab-item id="1" data-type="1">基本信息</mt-tab-item>
+        <mt-tab-item id="2" data-type="2">相关图片</mt-tab-item>
+        <mt-tab-item id="3" data-type="3">相关视频</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navbarIndex">
+        <mt-tab-container-item id="1">
+          <div class="content-keyword">
+            <div class="item-name">关键字</div>
+            {{ basisInfo.keyWord }}
+          </div>
+          <div class="content-introduction">
+            <div class="item-name">简介</div>
+            {{ basisInfo.introduction }}
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          <CustomSearch3 v-on:search="SearchImages"></CustomSearch3>
+          <div class="content-images"
+               v-infinite-scroll="NextImages"
+               :infinite-scroll-disabled="images.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in images.data"
+                 :key="item.id"
+                 @click="ToImageDetail(item.id)">
+              <div class="img-div">
+                <img :src="item.path"/>
+              </div>
+              <div class="item-name">{{ item.name }}</div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="3">
+          <CustomSearch3 v-on:search="SearchVideos"></CustomSearch3>
+          <div class="content-videos"
+               v-infinite-scroll="NextVideos"
+               :infinite-scroll-disabled="videos.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in videos.data"
+                 :key="item.id"
+                 @click="ToVideoDetail(item.id)">
+              <div class="item-left">
+                <img :src="item.cover"/>
+              </div>
+              <div class="item-right">
+                <div class="item-name">{{ item.name }}</div>
+                <div class="item-introduce">{{ item.description }}</div>
+              </div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {
+  GetDataDetail as Api_GetDataDetail,
+  GetDataDetailImages as Api_GetDataDetailImages,
+  GetDataDetailVideos as Api_GetDataDetailVideos,
+} from "@/api/apilist";
+
+export default {
+  name: "detail",
+  components: {CustomSearch3},
+  data() {
+    return {
+      titleName: "",
+      titleIntroduce: "",
+      navbarIndex: "1",
+      basisInfo: {
+        id: "",
+        keyWord: "",
+        introduction: "",
+        file: "",
+      },
+      images: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+      videos: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+    }
+  },
+  methods: {
+    OnlinePreview: function (fileUrl) {
+      if (fileUrl) {
+        if (fileUrl.replace(/\\/g, '').toLowerCase().indexOf('.pdf') >= 0) {
+          window.open(fileUrl);
+        } else {
+          //https://view.officeapps.live.com/op/view.aspx?src=
+          window.open("http://www.xdocin.com/xdoc?_func=to&_format=html&_cache=1&_xdoc=" + fileUrl.replace(/\\/g, ''));
+        }
+      }
+    },
+    SearchBasisInfo: function (id) {
+      Api_GetDataDetail(id).then(res => {
+        this.basisInfo = res;
+        this.titleIntroduce = res.keyWord;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchImages: function (searchType, searchName) {
+      this.images.searchType = searchType;
+      this.images.searchName = searchName;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.images.currentPage = res.currentPage;
+        this.images.pageSize = res.pageSize;
+        this.images.total = res.total;
+        this.images.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextImages: function () {
+      let searchType = this.images.searchType;
+      let searchName = this.images.searchName;
+      let currentPage = this.images.currentPage + 1;
+      let pageSize = this.images.pageSize;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.images.total = res.total;
+          this.images.currentPage = res.currentPage;
+          this.images.data = this.images.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchVideos: function (searchType, searchName) {
+      this.videos.searchType = searchType;
+      this.videos.searchName = searchName;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.videos.currentPage = res.currentPage;
+        this.videos.pageSize = res.pageSize;
+        this.videos.total = res.total;
+        this.videos.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextVideos: function () {
+      let searchType = this.videos.searchType;
+      let searchName = this.videos.searchName;
+      let currentPage = this.videos.currentPage + 1;
+      let pageSize = this.videos.pageSize;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.videos.total = res.total;
+          this.videos.currentPage = res.currentPage;
+          this.videos.data = this.videos.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    ToImageDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "memory-detail-image", query: {id: id, objId: objId}});
+    },
+    ToVideoDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "memory-detail-video", query: {id: id, objId: objId}});
+    },
+    ToListPage: function () {
+      this.$router.push({name: "memory-list"})
+    },
+  },
+  watch: {
+    navbarIndex: function () {
+      switch (this.navbarIndex) {
+        case 1:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = true;
+          break;
+        case 2:
+          this.images.scrollDisabled = false;
+          this.videos.scrollDisabled = true;
+          break;
+        case 3:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = false;
+          break;
+      }
+    }
+  },
+  created() {
+    let id = this.$route.query.id;
+    this.titleName = this.$route.query.name;
+    this.SearchBasisInfo(id);
+    this.SearchImages("title", "");
+    this.SearchVideos("title", "");
+  }
+}
+</script>
+
+<style scoped>
+.data-detail {
+  width: 100%;
+}
+
+.data-detail .title {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+
+  width: 100%;
+  height: 15.9vh;
+  background: url("../../assets/datadetail/detail@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+  border-radius: 10px 10px 0 0;
+}
+
+.data-detail .title .title-left {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 60%;
+  height: 100%;
+  padding-left: 2vh;
+}
+
+.data-detail .title .title-name {
+  width: 100%;
+  text-align: left;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2.62rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.24rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-introduce {
+  width: 100%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3.37rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-right {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 30%;
+  height: 100%;
+}
+
+.data-detail .title .online-preview {
+  width: 80%;
+  background: #EFC587;
+  opacity: 1;
+  border-radius: 60px;
+
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 3.87vh;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.data-detail .content {
+  width: 90%;
+  height: 84.1vh;
+  margin-left: 5%;
+  border-radius: 30px;
+}
+
+.mint-navbar /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 2rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar /deep/ .is-selected {
+  color: #BC0000;
+  border-bottom: 0.3vh solid #BC0000;
+}
+
+.mint-navbar /deep/ .is-selected .mint-tab-item-label {
+  color: #BC0000;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(1) {
+  padding-top: 5vh;
+}
+
+.content-keyword {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-keyword .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-introduction {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-introduction .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(2) {
+  padding-top: 2vh;
+}
+
+.custom-search3 {
+  margin-bottom: 2vh;
+}
+
+.content-images {
+  display: flex;
+  flex-wrap: wrap;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+
+.content-images .content-item {
+  width: 50%;
+  height: 25vh;
+}
+
+.content-images .content-item .img-div {
+  width: 90%;
+  height: 80%;
+  border-radius: 10px;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+}
+
+.content-images .content-item .img-div img {
+  width: 100%;
+  height: 100%;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.content-images .content-item .item-name {
+  width: 90%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2em;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 2em;
+  color: #333333;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(3) {
+  padding-top: 2vh;
+}
+
+.content-videos {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+}
+
+.content-videos .content-item {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-start;
+  align-items: center;
+
+  height: 10vh;
+  margin: 2vh auto;
+}
+
+.content-videos .item-left {
+  width: 30%;
+  height: 100%;
+}
+
+.content-videos .item-left img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content-videos .item-right {
+  width: 70%;
+  height: 100%;
+  padding-left: 2vw;
+}
+
+.content-videos .item-name {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-videos .item-introduce {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  text-align: left;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/memory/detailImage.vue b/src/views/memory/detailImage.vue
new file mode 100644
index 0000000..07a9a97
--- /dev/null
+++ b/src/views/memory/detailImage.vue
@@ -0,0 +1,133 @@
+<template>
+  <div class="data-detail-image">
+    <div class="images">
+      <mt-swipe :show-indicators="false" :auto="0" :continuous="false" @change="ChangeImage">
+        <mt-swipe-item v-for="item in images.data" :key="item.key">
+          <img :src="item.path"/>
+        </mt-swipe-item>
+      </mt-swipe>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ image.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ image.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetImageDetail as Api_GetImageDetail} from "@/api/apilist";
+
+export default {
+  name: "detailImage",
+  data() {
+    return {
+      navIndex: "1",
+      images: {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: []
+      },
+      image: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      }
+    }
+  },
+  methods: {
+    ChangeImage: function (index) {
+      this.image = this.images.data[index];
+    },
+  },
+  created() {
+    let imageId = this.$route.query.id;
+    let objId = this.$route.query.objId;
+    Api_GetImageDetail(imageId, 1, objId, 999).then(res => {
+      this.images = res;
+      this.image = res.data[0];
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-image {
+  width: 100%;
+}
+
+.images {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.images img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/memory/detailvideo.vue b/src/views/memory/detailvideo.vue
new file mode 100644
index 0000000..f755c4c
--- /dev/null
+++ b/src/views/memory/detailvideo.vue
@@ -0,0 +1,121 @@
+<template>
+  <div class="data-detail-video">
+    <div class="videos">
+      <video poster="" :src="video.patch" controls="controls">
+        您的浏览器不支持 video 标签。
+      </video>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ video.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ video.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetVideoDetail as Api_GetVideoDetail} from "@/api/apilist";
+
+export default {
+  name: "detailVideo",
+  data() {
+    return {
+      navIndex: "1",
+      video: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      },
+    }
+  },
+  methods: {
+
+  },
+  created() {
+    let id = this.$route.query.id;
+    Api_GetVideoDetail(id).then(res => {
+      this.video = res;
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-video {
+  width: 100%;
+}
+
+.videos {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.videos video {
+  width: 100%;
+  height: 100%;
+  background: black;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/memory/list.vue b/src/views/memory/list.vue
new file mode 100644
index 0000000..ea48633
--- /dev/null
+++ b/src/views/memory/list.vue
@@ -0,0 +1,154 @@
+<template>
+  <div class="list-root">
+    <div class="search">
+      <CustomSearch3 v-on:search="Search"></CustomSearch3>
+    </div>
+    <div class="line"></div>
+    <div class="data-list"
+         v-infinite-scroll="loadBottom"
+         :infinite-scroll-disabled="allLoaded"
+         :infinite-scroll-distance="10">
+      <template v-for="item in data.data">
+        <div class="text-item" :key="item.key" @click="ToDetail(item.id, item.name)">
+          <div class="item-title">{{ item.name }}</div>
+          <div class="item-context">{{ item.keyWord }}</div>
+        </div>
+        <div class="line" :key="item.key"></div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {GetDataList as Api_GetDataList} from "@/api/apilist";
+
+export default {
+  name: "list",
+  components: {CustomSearch3},
+  data() {
+    return {
+      dataType: 1,
+      searchType: "title",
+      searchName: "",
+      data: {
+        currentPage: 1,
+        pageSize: 5,
+        total: 0,
+        data: []
+      },
+      allLoaded: false
+    };
+  },
+  methods: {
+    Search: function (searchType, searchName) {
+      this.searchType = searchType;
+      this.searchName = searchName;
+      Api_GetDataList(this.dataType, searchType, searchName, 1, this.data.pageSize).then(res => {
+        this.currentPage = res.currentPage;
+        this.pageSize = res.pageSize;
+        this.total = res.total;
+        this.data = res;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    loadBottom: function () {
+      Api_GetDataList(this.dataType, this.searchType, this.searchName, this.data.currentPage + 1, this.data.pageSize).then(res => {
+        this.data.currentPage = res.currentPage;
+        this.data.pageSize = res.pageSize;
+        this.data.total = res.total;
+        if (res.data.length > 0) {
+          this.data.data = this.data.data.concat(res.data);
+        }
+        else{
+          this.allLoaded = true;
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    ToDetail: function (id, name) {
+      this.$router.push({name: "memory-detail", query: {id: id, name: name}})
+    }
+  },
+  created() {
+    this.Search("title", "");
+  }
+}
+</script>
+
+<style scoped>
+li {
+  list-style-type: none;
+}
+
+.list-root {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  width: 100%;
+}
+
+.search {
+  width: 100%;
+  margin-top: 3vh;
+}
+
+.search .custom-search3 {
+  width: 90%;
+  margin-left: 5%;
+}
+
+.line {
+  width: 100%;
+  border: 1px solid #EEEEEE;
+  margin-top: 3vh;
+  margin-bottom: 3vh;
+  opacity: 1;
+}
+
+.data-list {
+  width: 90%;
+  height: 65vh;
+  margin-left: 5%;
+  overflow: scroll;
+}
+
+.data-list .line {
+  width: 100%;
+  margin-bottom: 2vh;
+}
+
+
+.data-list /deep/ .text-item {
+  width: 90%;
+  margin-bottom: 2vh;
+}
+
+.data-list /deep/ .text-item .item-title {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+}
+
+.data-list /deep/ .text-item .item-context {
+  text-align: left;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2rem;
+  color: #767676;
+  text-align: left;
+}
+</style>
diff --git a/src/views/personage/detail.vue b/src/views/personage/detail.vue
new file mode 100644
index 0000000..9205178
--- /dev/null
+++ b/src/views/personage/detail.vue
@@ -0,0 +1,510 @@
+<template>
+  <div class="data-detail">
+    <div class="title">
+      <div class="title-left">
+        <div class="title-name" @click="ToListPage">{{ titleName }}</div>
+        <div class="title-introduce">{{ titleIntroduce }}</div>
+      </div>
+      <div class="title-right">
+        <div class="online-preview" @click="OnlinePreview(basisInfo.file)">在线浏览</div>
+      </div>
+    </div>
+    <div class="content">
+      <mt-navbar ref="navbar" v-model="navbarIndex">
+        <mt-tab-item id="1" data-type="1">基本信息</mt-tab-item>
+        <mt-tab-item id="2" data-type="2">相关图片</mt-tab-item>
+        <mt-tab-item id="3" data-type="3">相关视频</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navbarIndex">
+        <mt-tab-container-item id="1">
+          <div class="content-keyword">
+            <div class="item-name">关键字</div>
+            {{ basisInfo.keyWord }}
+          </div>
+          <div class="content-introduction">
+            <div class="item-name">简介</div>
+            {{ basisInfo.introduction }}
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          <CustomSearch3 v-on:search="SearchImages"></CustomSearch3>
+          <div class="content-images"
+               v-infinite-scroll="NextImages"
+               :infinite-scroll-disabled="images.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in images.data"
+                 :key="item.id"
+                 @click="ToImageDetail(item.id)">
+              <div class="img-div">
+                <img :src="item.path"/>
+              </div>
+              <div class="item-name">{{ item.name }}</div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="3">
+          <CustomSearch3 v-on:search="SearchVideos"></CustomSearch3>
+          <div class="content-videos"
+               v-infinite-scroll="NextVideos"
+               :infinite-scroll-disabled="videos.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in videos.data"
+                 :key="item.id"
+                 @click="ToVideoDetail(item.id)">
+              <div class="item-left">
+                <img :src="item.cover"/>
+              </div>
+              <div class="item-right">
+                <div class="item-name">{{ item.name }}</div>
+                <div class="item-introduce">{{ item.description }}</div>
+              </div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {
+  GetDataDetail as Api_GetDataDetail,
+  GetDataDetailImages as Api_GetDataDetailImages,
+  GetDataDetailVideos as Api_GetDataDetailVideos,
+} from "@/api/apilist";
+
+export default {
+  name: "detail",
+  components: {CustomSearch3},
+  data() {
+    return {
+      titleName: "",
+      titleIntroduce: "",
+      navbarIndex: "1",
+      basisInfo: {
+        id: "",
+        keyWord: "",
+        introduction: "",
+        file: "",
+      },
+      images: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+      videos: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+    }
+  },
+  methods: {
+    OnlinePreview: function (fileUrl) {
+      if (fileUrl) {
+        if (fileUrl.replace(/\\/g, '').toLowerCase().indexOf('.pdf') >= 0) {
+          window.open(fileUrl);
+        } else {
+          //https://view.officeapps.live.com/op/view.aspx?src=
+          window.open("http://www.xdocin.com/xdoc?_func=to&_format=html&_cache=1&_xdoc=" + fileUrl.replace(/\\/g, ''));
+        }
+      }
+    },
+    SearchBasisInfo: function (id) {
+      Api_GetDataDetail(id).then(res => {
+        this.basisInfo = res;
+        this.titleIntroduce = res.keyWord;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchImages: function (searchType, searchName) {
+      this.images.searchType = searchType;
+      this.images.searchName = searchName;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.images.currentPage = res.currentPage;
+        this.images.pageSize = res.pageSize;
+        this.images.total = res.total;
+        this.images.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextImages: function () {
+      let searchType = this.images.searchType;
+      let searchName = this.images.searchName;
+      let currentPage = this.images.currentPage + 1;
+      let pageSize = this.images.pageSize;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.images.total = res.total;
+          this.images.currentPage = res.currentPage;
+          this.images.data = this.images.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchVideos: function (searchType, searchName) {
+      this.videos.searchType = searchType;
+      this.videos.searchName = searchName;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.videos.currentPage = res.currentPage;
+        this.videos.pageSize = res.pageSize;
+        this.videos.total = res.total;
+        this.videos.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextVideos: function () {
+      let searchType = this.videos.searchType;
+      let searchName = this.videos.searchName;
+      let currentPage = this.videos.currentPage + 1;
+      let pageSize = this.videos.pageSize;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.videos.total = res.total;
+          this.videos.currentPage = res.currentPage;
+          this.videos.data = this.videos.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    ToImageDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "personage-detail-image", query: {id: id, objId: objId}});
+    },
+    ToVideoDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "personage-detail-video", query: {id: id, objId: objId}});
+    },
+    ToListPage: function () {
+      this.$router.push({name: "personage-list"})
+    },
+  },
+  watch: {
+    navbarIndex: function () {
+      switch (this.navbarIndex) {
+        case 1:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = true;
+          break;
+        case 2:
+          this.images.scrollDisabled = false;
+          this.videos.scrollDisabled = true;
+          break;
+        case 3:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = false;
+          break;
+      }
+    }
+  },
+  created() {
+    let id = this.$route.query.id;
+    this.titleName = this.$route.query.name;
+    this.SearchBasisInfo(id);
+    this.SearchImages("title", "");
+    this.SearchVideos("title", "");
+  }
+}
+</script>
+
+<style scoped>
+.data-detail {
+  width: 100%;
+}
+
+.data-detail .title {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+
+  width: 100%;
+  height: 15.9vh;
+  background: url("../../assets/datadetail/detail@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+  border-radius: 10px 10px 0 0;
+}
+
+.data-detail .title .title-left {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 60%;
+  height: 100%;
+  padding-left: 2vh;
+}
+
+.data-detail .title .title-name {
+  width: 100%;
+  text-align: left;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2.62rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.24rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-introduce {
+  width: 100%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3.37rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-right {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 30%;
+  height: 100%;
+}
+
+.data-detail .title .online-preview {
+  width: 80%;
+  background: #EFC587;
+  opacity: 1;
+  border-radius: 60px;
+
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 3.87vh;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.data-detail .content {
+  width: 90%;
+  height: 84.1vh;
+  margin-left: 5%;
+  border-radius: 30px;
+}
+
+.mint-navbar /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 2rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar /deep/ .is-selected {
+  color: #BC0000;
+  border-bottom: 0.3vh solid #BC0000;
+}
+
+.mint-navbar /deep/ .is-selected .mint-tab-item-label {
+  color: #BC0000;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(1) {
+  padding-top: 5vh;
+}
+
+.content-keyword {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-keyword .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-introduction {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-introduction .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(2) {
+  padding-top: 2vh;
+}
+
+.custom-search3 {
+  margin-bottom: 2vh;
+}
+
+.content-images {
+  display: flex;
+  flex-wrap: wrap;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+
+.content-images .content-item {
+  width: 50%;
+  height: 25vh;
+}
+
+.content-images .content-item .img-div {
+  width: 90%;
+  height: 80%;
+  border-radius: 10px;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+}
+
+.content-images .content-item .img-div img {
+  width: 100%;
+  height: 100%;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.content-images .content-item .item-name {
+  width: 90%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2em;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 2em;
+  color: #333333;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(3) {
+  padding-top: 2vh;
+}
+
+.content-videos {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+}
+
+.content-videos .content-item {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-start;
+  align-items: center;
+
+  height: 10vh;
+  margin: 2vh auto;
+}
+
+.content-videos .item-left {
+  width: 30%;
+  height: 100%;
+}
+
+.content-videos .item-left img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content-videos .item-right {
+  width: 70%;
+  height: 100%;
+  padding-left: 2vw;
+}
+
+.content-videos .item-name {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-videos .item-introduce {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  text-align: left;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/personage/detailImage.vue b/src/views/personage/detailImage.vue
new file mode 100644
index 0000000..07a9a97
--- /dev/null
+++ b/src/views/personage/detailImage.vue
@@ -0,0 +1,133 @@
+<template>
+  <div class="data-detail-image">
+    <div class="images">
+      <mt-swipe :show-indicators="false" :auto="0" :continuous="false" @change="ChangeImage">
+        <mt-swipe-item v-for="item in images.data" :key="item.key">
+          <img :src="item.path"/>
+        </mt-swipe-item>
+      </mt-swipe>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ image.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ image.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetImageDetail as Api_GetImageDetail} from "@/api/apilist";
+
+export default {
+  name: "detailImage",
+  data() {
+    return {
+      navIndex: "1",
+      images: {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: []
+      },
+      image: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      }
+    }
+  },
+  methods: {
+    ChangeImage: function (index) {
+      this.image = this.images.data[index];
+    },
+  },
+  created() {
+    let imageId = this.$route.query.id;
+    let objId = this.$route.query.objId;
+    Api_GetImageDetail(imageId, 1, objId, 999).then(res => {
+      this.images = res;
+      this.image = res.data[0];
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-image {
+  width: 100%;
+}
+
+.images {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.images img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/personage/detailvideo.vue b/src/views/personage/detailvideo.vue
new file mode 100644
index 0000000..f755c4c
--- /dev/null
+++ b/src/views/personage/detailvideo.vue
@@ -0,0 +1,121 @@
+<template>
+  <div class="data-detail-video">
+    <div class="videos">
+      <video poster="" :src="video.patch" controls="controls">
+        您的浏览器不支持 video 标签。
+      </video>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ video.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ video.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetVideoDetail as Api_GetVideoDetail} from "@/api/apilist";
+
+export default {
+  name: "detailVideo",
+  data() {
+    return {
+      navIndex: "1",
+      video: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      },
+    }
+  },
+  methods: {
+
+  },
+  created() {
+    let id = this.$route.query.id;
+    Api_GetVideoDetail(id).then(res => {
+      this.video = res;
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-video {
+  width: 100%;
+}
+
+.videos {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.videos video {
+  width: 100%;
+  height: 100%;
+  background: black;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/personage/list.vue b/src/views/personage/list.vue
new file mode 100644
index 0000000..c9eaa76
--- /dev/null
+++ b/src/views/personage/list.vue
@@ -0,0 +1,190 @@
+<template>
+  <div class="list-root">
+    <div class="search">
+      <CustomSearch3 v-on:search="Search"></CustomSearch3>
+    </div>
+    <div class="line"></div>
+    <div class="data-list"
+         v-infinite-scroll="loadBottom"
+         :infinite-scroll-disabled="allLoaded"
+         :infinite-scroll-distance="10">
+      <template v-for="item in data.data">
+        <div class="image-item"
+             :key="item.key"
+             @click="ToDetail(item.id,item.name)">
+          <div class="item-left">
+            <img :src="item.img"/>
+          </div>
+          <div class="item-right">
+            <div class="item-title">{{ item.name }}</div>
+            <div class="item-context">{{ item.keyWord }}</div>
+          </div>
+        </div>
+        <div :key="item.key" class="line"></div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {GetDataList as Api_GetDataList} from "@/api/apilist";
+
+export default {
+  name: "list",
+  components: {CustomSearch3},
+  data() {
+    return {
+      dataType: 4,
+      searchType: "title",
+      searchName: "",
+      data: {
+        currentPage: 1,
+        pageSize: 5,
+        total: 0,
+        data: []
+      },
+      allLoaded: false
+    };
+  },
+  methods: {
+    Search: function (searchType, searchName) {
+      this.searchType = searchType;
+      this.searchName = searchName;
+      Api_GetDataList(this.dataType, searchType, searchName, 1, this.data.pageSize).then(res => {
+        this.currentPage = res.currentPage;
+        this.pageSize = res.pageSize;
+        this.total = res.total;
+        this.data = res;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    loadBottom: function () {
+      Api_GetDataList(this.dataType, this.searchType, this.searchName, this.data.currentPage + 1, this.data.pageSize).then(res => {
+        this.data.currentPage = res.currentPage;
+        this.data.pageSize = res.pageSize;
+        this.data.total = res.total;
+        if (res.data.length > 0) {
+          this.data.data = this.data.data.concat(res.data);
+        } else {
+          this.allLoaded = true;
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    ToDetail: function (id, name) {
+      this.$router.push({name: "personage-detail", query: {id: id, name: name}})
+    }
+  },
+  created() {
+    this.Search("title", "");
+  }
+}
+</script>
+
+<style scoped>
+li {
+  list-style-type: none;
+}
+
+.list-root {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  width: 100%;
+}
+
+.search {
+  width: 100%;
+  margin-top: 3vh;
+}
+
+.search .custom-search3 {
+  width: 90%;
+  margin-left: 5%;
+}
+
+.line {
+  width: 100%;
+  border: 1px solid #EEEEEE;
+  margin-top: 3vh;
+  margin-bottom: 3vh;
+  opacity: 1;
+}
+
+.data-list {
+  width: 90%;
+  height: 65vh;
+  margin-left: 5%;
+  overflow: scroll;
+}
+
+.data-list .line {
+  width: 100%;
+  margin-bottom: 2vh;
+}
+
+.data-list /deep/ .image-item {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+
+  width: 100%;
+  margin-bottom: 2vh;
+}
+
+.data-list /deep/ .image-item .item-left {
+  width: 30%;
+}
+
+.data-list /deep/ .image-item .item-left img {
+  width: 100%;
+  height: 12vh;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.data-list /deep/ .image-item .item-right {
+  width: 70%;
+}
+
+.data-list /deep/ .image-item .item-title {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  padding-left: 2rem;
+
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+}
+
+.data-list /deep/ .image-item .item-context {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  padding-left: 2rem;
+
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2rem;
+  color: #767676;
+  text-align: left;
+}
+</style>
diff --git a/src/views/scenery/detail.vue b/src/views/scenery/detail.vue
new file mode 100644
index 0000000..7ff3e7b
--- /dev/null
+++ b/src/views/scenery/detail.vue
@@ -0,0 +1,510 @@
+<template>
+  <div class="data-detail">
+    <div class="title">
+      <div class="title-left">
+        <div class="title-name" @click="ToListPage">{{ titleName }}</div>
+        <div class="title-introduce">{{ titleIntroduce }}</div>
+      </div>
+      <div class="title-right">
+        <div class="online-preview" @click="OnlinePreview(basisInfo.file)">在线浏览</div>
+      </div>
+    </div>
+    <div class="content">
+      <mt-navbar ref="navbar" v-model="navbarIndex">
+        <mt-tab-item id="1" data-type="1">基本信息</mt-tab-item>
+        <mt-tab-item id="2" data-type="2">相关图片</mt-tab-item>
+        <mt-tab-item id="3" data-type="3">相关视频</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navbarIndex">
+        <mt-tab-container-item id="1">
+          <div class="content-keyword">
+            <div class="item-name">关键字</div>
+            {{ basisInfo.keyWord }}
+          </div>
+          <div class="content-introduction">
+            <div class="item-name">简介</div>
+            {{ basisInfo.introduction }}
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          <CustomSearch3 v-on:search="SearchImages"></CustomSearch3>
+          <div class="content-images"
+               v-infinite-scroll="NextImages"
+               :infinite-scroll-disabled="images.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in images.data"
+                 :key="item.id"
+                 @click="ToImageDetail(item.id)">
+              <div class="img-div">
+                <img :src="item.path"/>
+              </div>
+              <div class="item-name">{{ item.name }}</div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="3">
+          <CustomSearch3 v-on:search="SearchVideos"></CustomSearch3>
+          <div class="content-videos"
+               v-infinite-scroll="NextVideos"
+               :infinite-scroll-disabled="videos.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in videos.data"
+                 :key="item.id"
+                 @click="ToVideoDetail(item.id)">
+              <div class="item-left">
+                <img :src="item.cover"/>
+              </div>
+              <div class="item-right">
+                <div class="item-name">{{ item.name }}</div>
+                <div class="item-introduce">{{ item.description }}</div>
+              </div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {
+  GetDataDetail as Api_GetDataDetail,
+  GetDataDetailImages as Api_GetDataDetailImages,
+  GetDataDetailVideos as Api_GetDataDetailVideos,
+} from "@/api/apilist";
+
+export default {
+  name: "detail",
+  components: {CustomSearch3},
+  data() {
+    return {
+      titleName: "",
+      titleIntroduce: "",
+      navbarIndex: "1",
+      basisInfo: {
+        id: "",
+        keyWord: "",
+        introduction: "",
+        file: "",
+      },
+      images: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+      videos: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+    }
+  },
+  methods: {
+    OnlinePreview: function (fileUrl) {
+      if (fileUrl) {
+        if (fileUrl.replace(/\\/g, '').toLowerCase().indexOf('.pdf') >= 0) {
+          window.open(fileUrl);
+        } else {
+          //https://view.officeapps.live.com/op/view.aspx?src=
+          window.open("http://www.xdocin.com/xdoc?_func=to&_format=html&_cache=1&_xdoc=" + fileUrl.replace(/\\/g, ''));
+        }
+      }
+    },
+    SearchBasisInfo: function (id) {
+      Api_GetDataDetail(id).then(res => {
+        this.basisInfo = res;
+        this.titleIntroduce = res.keyWord;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchImages: function (searchType, searchName) {
+      this.images.searchType = searchType;
+      this.images.searchName = searchName;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.images.currentPage = res.currentPage;
+        this.images.pageSize = res.pageSize;
+        this.images.total = res.total;
+        this.images.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextImages: function () {
+      let searchType = this.images.searchType;
+      let searchName = this.images.searchName;
+      let currentPage = this.images.currentPage + 1;
+      let pageSize = this.images.pageSize;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.images.total = res.total;
+          this.images.currentPage = res.currentPage;
+          this.images.data = this.images.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchVideos: function (searchType, searchName) {
+      this.videos.searchType = searchType;
+      this.videos.searchName = searchName;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.videos.currentPage = res.currentPage;
+        this.videos.pageSize = res.pageSize;
+        this.videos.total = res.total;
+        this.videos.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextVideos: function () {
+      let searchType = this.videos.searchType;
+      let searchName = this.videos.searchName;
+      let currentPage = this.videos.currentPage + 1;
+      let pageSize = this.videos.pageSize;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.videos.total = res.total;
+          this.videos.currentPage = res.currentPage;
+          this.videos.data = this.videos.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    ToImageDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "scenery-detail-image", query: {id: id, objId: objId}});
+    },
+    ToVideoDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "scenery-detail-video", query: {id: id, objId: objId}});
+    },
+    ToListPage: function () {
+      this.$router.push({name: "scenery-list"})
+    },
+  },
+  watch: {
+    navbarIndex: function () {
+      switch (this.navbarIndex) {
+        case 1:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = true;
+          break;
+        case 2:
+          this.images.scrollDisabled = false;
+          this.videos.scrollDisabled = true;
+          break;
+        case 3:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = false;
+          break;
+      }
+    }
+  },
+  created() {
+    let id = this.$route.query.id;
+    this.titleName = this.$route.query.name;
+    this.SearchBasisInfo(id);
+    this.SearchImages("title", "");
+    this.SearchVideos("title", "");
+  }
+}
+</script>
+
+<style scoped>
+.data-detail {
+  width: 100%;
+}
+
+.data-detail .title {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+
+  width: 100%;
+  height: 15.9vh;
+  background: url("../../assets/datadetail/detail@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+  border-radius: 10px 10px 0 0;
+}
+
+.data-detail .title .title-left {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 60%;
+  height: 100%;
+  padding-left: 2vh;
+}
+
+.data-detail .title .title-name {
+  width: 100%;
+  text-align: left;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2.62rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.24rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-introduce {
+  width: 100%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3.37rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-right {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 30%;
+  height: 100%;
+}
+
+.data-detail .title .online-preview {
+  width: 80%;
+  background: #EFC587;
+  opacity: 1;
+  border-radius: 60px;
+
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 3.87vh;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.data-detail .content {
+  width: 90%;
+  height: 84.1vh;
+  margin-left: 5%;
+  border-radius: 30px;
+}
+
+.mint-navbar /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 2rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar /deep/ .is-selected {
+  color: #BC0000;
+  border-bottom: 0.3vh solid #BC0000;
+}
+
+.mint-navbar /deep/ .is-selected .mint-tab-item-label {
+  color: #BC0000;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(1) {
+  padding-top: 5vh;
+}
+
+.content-keyword {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-keyword .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-introduction {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-introduction .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(2) {
+  padding-top: 2vh;
+}
+
+.custom-search3 {
+  margin-bottom: 2vh;
+}
+
+.content-images {
+  display: flex;
+  flex-wrap: wrap;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+
+.content-images .content-item {
+  width: 50%;
+  height: 25vh;
+}
+
+.content-images .content-item .img-div {
+  width: 90%;
+  height: 80%;
+  border-radius: 10px;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+}
+
+.content-images .content-item .img-div img {
+  width: 100%;
+  height: 100%;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.content-images .content-item .item-name {
+  width: 90%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2em;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 2em;
+  color: #333333;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(3) {
+  padding-top: 2vh;
+}
+
+.content-videos {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+}
+
+.content-videos .content-item {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-start;
+  align-items: center;
+
+  height: 10vh;
+  margin: 2vh auto;
+}
+
+.content-videos .item-left {
+  width: 30%;
+  height: 100%;
+}
+
+.content-videos .item-left img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content-videos .item-right {
+  width: 70%;
+  height: 100%;
+  padding-left: 2vw;
+}
+
+.content-videos .item-name {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-videos .item-introduce {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  text-align: left;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/scenery/detailImage.vue b/src/views/scenery/detailImage.vue
new file mode 100644
index 0000000..07a9a97
--- /dev/null
+++ b/src/views/scenery/detailImage.vue
@@ -0,0 +1,133 @@
+<template>
+  <div class="data-detail-image">
+    <div class="images">
+      <mt-swipe :show-indicators="false" :auto="0" :continuous="false" @change="ChangeImage">
+        <mt-swipe-item v-for="item in images.data" :key="item.key">
+          <img :src="item.path"/>
+        </mt-swipe-item>
+      </mt-swipe>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ image.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ image.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetImageDetail as Api_GetImageDetail} from "@/api/apilist";
+
+export default {
+  name: "detailImage",
+  data() {
+    return {
+      navIndex: "1",
+      images: {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: []
+      },
+      image: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      }
+    }
+  },
+  methods: {
+    ChangeImage: function (index) {
+      this.image = this.images.data[index];
+    },
+  },
+  created() {
+    let imageId = this.$route.query.id;
+    let objId = this.$route.query.objId;
+    Api_GetImageDetail(imageId, 1, objId, 999).then(res => {
+      this.images = res;
+      this.image = res.data[0];
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-image {
+  width: 100%;
+}
+
+.images {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.images img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/scenery/detailvideo.vue b/src/views/scenery/detailvideo.vue
new file mode 100644
index 0000000..f755c4c
--- /dev/null
+++ b/src/views/scenery/detailvideo.vue
@@ -0,0 +1,121 @@
+<template>
+  <div class="data-detail-video">
+    <div class="videos">
+      <video poster="" :src="video.patch" controls="controls">
+        您的浏览器不支持 video 标签。
+      </video>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ video.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ video.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetVideoDetail as Api_GetVideoDetail} from "@/api/apilist";
+
+export default {
+  name: "detailVideo",
+  data() {
+    return {
+      navIndex: "1",
+      video: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      },
+    }
+  },
+  methods: {
+
+  },
+  created() {
+    let id = this.$route.query.id;
+    Api_GetVideoDetail(id).then(res => {
+      this.video = res;
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-video {
+  width: 100%;
+}
+
+.videos {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.videos video {
+  width: 100%;
+  height: 100%;
+  background: black;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/scenery/list.vue b/src/views/scenery/list.vue
new file mode 100644
index 0000000..275e07b
--- /dev/null
+++ b/src/views/scenery/list.vue
@@ -0,0 +1,190 @@
+<template>
+  <div class="list-root">
+    <div class="search">
+      <CustomSearch3 v-on:search="Search"></CustomSearch3>
+    </div>
+    <div class="line"></div>
+    <div class="data-list"
+         v-infinite-scroll="loadBottom"
+         :infinite-scroll-disabled="allLoaded"
+         :infinite-scroll-distance="10">
+      <template v-for="item in data.data">
+        <div class="image-item"
+             :key="item.key"
+             @click="ToDetail(item.id,item.name)">
+          <div class="item-left">
+            <img :src="item.img"/>
+          </div>
+          <div class="item-right">
+            <div class="item-title">{{ item.name }}</div>
+            <div class="item-context">{{ item.keyWord }}</div>
+          </div>
+        </div>
+        <div :key="item.key" class="line"></div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {GetDataList as Api_GetDataList} from "@/api/apilist";
+
+export default {
+  name: "list",
+  components: {CustomSearch3},
+  data() {
+    return {
+      dataType: 3,
+      searchType: "title",
+      searchName: "",
+      data: {
+        currentPage: 1,
+        pageSize: 10,
+        total: 0,
+        data: []
+      },
+      allLoaded: false
+    };
+  },
+  methods: {
+    Search: function (searchType, searchName) {
+      this.searchType = searchType;
+      this.searchName = searchName;
+      Api_GetDataList(this.dataType, searchType, searchName, 1, this.data.pageSize).then(res => {
+        this.currentPage = res.currentPage;
+        this.pageSize = res.pageSize;
+        this.total = res.total;
+        this.data = res;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    loadBottom: function () {
+      Api_GetDataList(this.dataType, this.searchType, this.searchName, this.data.currentPage + 1, this.data.pageSize).then(res => {
+        this.data.currentPage = res.currentPage;
+        this.data.pageSize = res.pageSize;
+        this.data.total = res.total;
+        if (res.data.length > 0) {
+          this.data.data = this.data.data.concat(res.data);
+        } else {
+          //加载完全部数据,上拉加载事件将不再执行
+          this.allLoaded = false;
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    ToDetail: function (id, name) {
+      this.$router.push({name: "scenery-detail", query: {id: id, name: name}})
+    }
+  },
+  created() {
+    this.Search("title", "");
+  }
+}
+</script>
+
+<style scoped>
+li {
+  list-style-type: none;
+}
+
+.list-root {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  width: 100%;
+}
+
+.search {
+  width: 100%;
+  margin-top: 3vh;
+}
+
+.search .custom-search3 {
+  width: 90%;
+  margin-left: 5%;
+}
+
+.line {
+  width: 100%;
+  border: 1px solid #EEEEEE;
+  margin-top: 3vh;
+  margin-bottom: 3vh;
+  opacity: 1;
+}
+
+.data-list {
+  width: 90%;
+  margin-left: 5%;
+  overflow: scroll;
+}
+
+.data-list .line {
+  width: 100%;
+  margin-bottom: 2vh;
+}
+
+.data-list /deep/ .image-item {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+
+  width: 100%;
+  margin-bottom: 2vh;
+}
+
+.data-list /deep/ .image-item .item-left {
+  width: 30%;
+}
+
+.data-list /deep/ .image-item .item-left img {
+  width: 100%;
+  height: 12vh;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.data-list /deep/ .image-item .item-right {
+  width: 70%;
+}
+
+.data-list /deep/ .image-item .item-title {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  padding-left: 2rem;
+
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+}
+
+.data-list /deep/ .image-item .item-context {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  padding-left: 2rem;
+
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2rem;
+  color: #767676;
+  text-align: left;
+}
+</style>
diff --git a/src/views/search/index.vue b/src/views/search/index.vue
new file mode 100644
index 0000000..ca43210
--- /dev/null
+++ b/src/views/search/index.vue
@@ -0,0 +1,175 @@
+<template>
+  <div class="search-index">
+    <div class="index-title1">热门搜索</div>
+    <div class="index-hot">
+      <div v-for="item in hotList" :key="item.id" @click="SearchHot(item)">
+        {{ item.title }}
+      </div>
+    </div>
+    <div class="index-title2">
+      历史搜索
+      <span class="remove-btn" @click="ClearHis">清除</span>
+    </div>
+    <div class="index-history">
+      <template v-for="item in historyList">
+        <div class="search-msg" :key="item.key" @click="SearchHis(item)">
+          <svg t="1639023179293" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
+               p-id="6665" width="200" height="200">
+            <path
+                d="M512 160c194.410667 0 352 157.589333 352 352S706.410667 864 512 864l-2.538667-0.106667c-91.477333-7.274667-165.738667-38.08-221.44-91.989333L288 842.666667h-64V640H405.333333v64h-92.842666c46.250667 56.917333 112.490667 88.725333 200.768 96l6.677333-0.106667C675.328 795.690667 800 668.394667 800 512c0-159.061333-128.938667-288-288-288S224 352.938667 224 512h-64c0-194.410667 157.589333-352 352-352zM469.333333 320h64v160h160v64H469.333333V320z"
+                p-id="6666" fill="#C7C7C7"></path>
+          </svg>
+          <span>{{ item.searchName }}</span>
+        </div>
+        <div class="line" :key="item.key"></div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  GetSearchHomeInfo as Api_GetSearchHomeInfo,
+} from '@/api/apilist'
+
+export default {
+  name: "index",
+  data() {
+    return {
+      hotList: [],
+      historyList: [],
+    }
+  },
+  methods: {
+    SearchHot(item) {
+      console.log(item);
+      this.$router.push({
+        name: "search-results",
+        query: {searchType: "title", searchName: item.title, type: item.type}
+      });
+    },
+    SearchHis(item) {
+      this.$router.push({
+        name: "search-results",
+        query: {searchType: item.searchType, searchName: item.searchName}
+      });
+    },
+    ClearHis() {
+      localStorage.clear();
+      this.historyList = [];
+    }
+  },
+  created() {
+    Api_GetSearchHomeInfo().then(res => {
+      this.hotList = res.rmtj;
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert("请求错误!");
+    });
+
+    if (localStorage.searchHistory) {
+      this.historyList = eval(localStorage.searchHistory).reverse();
+    }
+  }
+}
+</script>
+
+<style scoped>
+.search-index {
+  width: 90%;
+  margin-left: 5%;
+}
+
+.index-title1 {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.87rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.index-hot {
+  display: flex;
+  flex-wrap: wrap;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+
+.index-hot > div {
+  width: 30%;
+  border: 1px solid #999999;
+  border-radius: 140px;
+  margin-right: 3%;
+  margin-bottom: 2vh;
+  cursor: pointer;
+
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3.37rem;
+  color: #767676;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+.index-hot > div:first-child {
+  border: 0;
+  color: #FFFFFF;
+  background: #BC0000;
+}
+
+.index-title2 {
+  text-align: left;
+  font-size: 1.75rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.87rem;
+  color: #333333;
+}
+
+.index-title2 .remove-btn {
+  float: right;
+  font-size: 1.5rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 5.87rem;
+  color: #767676;
+  cursor: pointer;
+}
+
+.index-history .search-msg {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: center;
+
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3.37rem;
+  color: #999999;
+}
+
+.search-msg span {
+  cursor: pointer;
+}
+
+.search-msg svg {
+  width: 3vh;
+  height: 3vh;
+  margin-right: 1vh;
+  cursor: pointer;
+}
+
+.index-history .line {
+  border: 1px solid #E4E4E4;
+  margin-top: 1vh;
+  margin-bottom: 1vh;
+}
+</style>
diff --git a/src/views/search/results.vue b/src/views/search/results.vue
new file mode 100644
index 0000000..bcc0e4d
--- /dev/null
+++ b/src/views/search/results.vue
@@ -0,0 +1,268 @@
+<template>
+  <div class="search-results">
+    <div class="results-title">搜索结果</div>
+    <div class="results-list">
+      <navbar ref="navbar" v-model="type">
+        <tab-item id="1" data-type="1">红色记忆</tab-item>
+        <tab-item id="2" data-type="2">红色精神</tab-item>
+        <tab-item id="3" data-type="3">红色景区</tab-item>
+        <tab-item id="4" data-type="4">红色人物</tab-item>
+      </navbar>
+      <tab-container v-model="type">
+        <tab-container-item id="1">
+          <template v-for="item in searchItems.hsjy.data">
+            <div class="text-item" :key="item.key" @click="ToMemoryDetail(item.id,item.name)">
+              <div class="item-title">{{ item.name }}</div>
+              <div class="item-context">{{ item.keyWord }}</div>
+            </div>
+            <div class="line" :key="item.key"></div>
+          </template>
+        </tab-container-item>
+        <tab-container-item id="2">
+          <template v-for="item in searchItems.hsjs.data">
+            <div class="text-item" :key="item.key" @click="ToSpiritDetail(item.id,item.name)">
+              <div class="item-title">{{ item.name }}</div>
+              <div class="item-context">{{ item.keyWord }}</div>
+            </div>
+            <div class="line" :key="item.key"></div>
+          </template>
+        </tab-container-item>
+        <tab-container-item id="3">
+          <template v-for="item in searchItems.hsjq.data">
+            <div class="image-item" :key="item.key" @click="ToSceneryDetail(item.id,item.name)">
+              <div class="item-left">
+                <img :src="item.img"/>
+              </div>
+              <div class="item-right">
+                <div class="item-title">{{ item.name }}</div>
+                <div class="item-context">{{ item.keyWord }}</div>
+              </div>
+            </div>
+            <div class="line" :key="item.key"></div>
+          </template>
+        </tab-container-item>
+        <tab-container-item id="4">
+          <template v-for="item in searchItems.hsrw.data">
+            <div class="image-item" :key="item.key" @click="ToPersonageDetail(item.id,item.name)">
+              <div class="item-left">
+                <img :src="item.img"/>
+              </div>
+              <div class="item-right">
+                <div class="item-title">{{ item.name }}</div>
+                <div class="item-context">{{ item.keyWord }}</div>
+              </div>
+            </div>
+            <div class="line" :key="item.key"></div>
+          </template>
+        </tab-container-item>
+      </tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {Navbar, TabItem, TabContainer, TabContainerItem} from 'mint-ui';
+import {
+  GetSearchInfo as Api_GetSearchInfo,
+} from '@/api/apilist'
+
+export default {
+  name: "results",
+  components: {Navbar, TabItem, TabContainer, TabContainerItem},
+  data() {
+    return {
+      type: "1",
+      searchItems: [],
+    };
+  },
+  methods: {
+    ToMemoryDetail: function (id, name) {
+      this.$router.push({name: "memory-detail", query: {id: id, name: name}});
+    },
+    ToPersonageDetail: function (id, name) {
+      this.$router.push({name: "personage-detail", query: {id: id, name: name}});
+    },
+    ToSceneryDetail: function (id, name) {
+      this.$router.push({name: "scenery-detail", query: {id: id, name: name}});
+    },
+    ToSpiritDetail: function (id, name) {
+      this.$router.push({name: "spirit-detail", query: {id: id, name: name}});
+    },
+  },
+  watch: {},
+  created: function () {
+    let searchType = this.$route.query.searchType;
+    let searchName = this.$route.query.searchName;
+    let type = this.$route.query.type;
+    if (type) {
+      this.type = type.toString();
+    }
+
+    Api_GetSearchInfo(searchType, searchName).then(res => {
+      this.searchItems = res;
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert("请求错误!");
+    });
+  },
+  beforeRouteUpdate(to, from, next) {
+    if (to.fullPath != from.fullPath) {
+      let searchType = to.query.searchType
+      let searchName = to.query.searchName;
+      let type = to.query.type;
+      if (type) {
+        this.type = type.toString();
+      }
+
+      Api_GetSearchInfo(searchType, searchName).then(res => {
+        this.searchItems = [];
+        this.searchItems = res;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("请求错误!");
+      });
+    }
+    next();
+  },
+}
+</script>
+
+<style scoped>
+.search-results {
+  width: 90%;
+  margin-left: 5%;
+}
+
+.results-title {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.87rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.search-results .mint-navbar {
+  margin-bottom: 2vh;
+}
+
+.search-results .mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 1.93rem;
+  color: #767676;
+  opacity: 1;
+  cursor: pointer
+}
+
+.search-results .mint-navbar .is-selected {
+  border-bottom: 2px solid #BC0000;
+}
+
+.search-results .mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+}
+
+.search-results .mint-tab-container {
+}
+
+.search-results .mint-tab-container .mint-tab-container-item {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .line {
+  width: 100%;
+  border: 1px solid #EEEEEE;
+  margin-bottom: 2vh;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .text-item {
+  width: 90%;
+  margin-bottom: 2vh;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .text-item .item-title {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 4rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .text-item .item-context {
+  text-align: left;
+  font-size: 1.5rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2.5rem;
+  color: #9B9B9B;
+  opacity: 1;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .image-item {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+
+  width: 90%;
+  margin-bottom: 2vh;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .image-item .item-left {
+  width: 30%;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .image-item .item-left img {
+  width: 100%;
+  height: 10vh;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .image-item .item-right {
+  width: 70%;
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .image-item .item-title {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  padding-left: 4vw;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+  text-align: left;
+
+}
+
+.search-results .mint-tab-container .mint-tab-container-item .image-item .item-context {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+
+  padding-left: 4vw;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2rem;
+  color: #767676;
+  text-align: left;
+}
+</style>
diff --git a/src/views/spirit/detail.vue b/src/views/spirit/detail.vue
new file mode 100644
index 0000000..ca2c8d2
--- /dev/null
+++ b/src/views/spirit/detail.vue
@@ -0,0 +1,510 @@
+<template>
+  <div class="data-detail">
+    <div class="title">
+      <div class="title-left">
+        <div class="title-name" @click="ToListPage">{{ titleName }}</div>
+        <div class="title-introduce">{{ titleIntroduce }}</div>
+      </div>
+      <div class="title-right">
+        <div class="online-preview" @click="OnlinePreview(basisInfo.file)">在线浏览</div>
+      </div>
+    </div>
+    <div class="content">
+      <mt-navbar ref="navbar" v-model="navbarIndex">
+        <mt-tab-item id="1" data-type="1">基本信息</mt-tab-item>
+        <mt-tab-item id="2" data-type="2">相关图片</mt-tab-item>
+        <mt-tab-item id="3" data-type="3">相关视频</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navbarIndex">
+        <mt-tab-container-item id="1">
+          <div class="content-keyword">
+            <div class="item-name">关键字</div>
+            {{ basisInfo.keyWord }}
+          </div>
+          <div class="content-introduction">
+            <div class="item-name">简介</div>
+            {{ basisInfo.introduction }}
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          <CustomSearch3 v-on:search="SearchImages"></CustomSearch3>
+          <div class="content-images"
+               v-infinite-scroll="NextImages"
+               :infinite-scroll-disabled="images.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in images.data"
+                 :key="item.id"
+                 @click="ToImageDetail(item.id)">
+              <div class="img-div">
+                <img :src="item.path"/>
+              </div>
+              <div class="item-name">{{ item.name }}</div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+        <mt-tab-container-item id="3">
+          <CustomSearch3 v-on:search="SearchVideos"></CustomSearch3>
+          <div class="content-videos"
+               v-infinite-scroll="NextVideos"
+               :infinite-scroll-disabled="videos.scrollDisabled"
+               :infinite-scroll-distance="10">
+            <div class="content-item"
+                 v-for="item in videos.data"
+                 :key="item.id"
+                 @click="ToVideoDetail(item.id)">
+              <div class="item-left">
+                <img :src="item.cover"/>
+              </div>
+              <div class="item-right">
+                <div class="item-name">{{ item.name }}</div>
+                <div class="item-introduce">{{ item.description }}</div>
+              </div>
+            </div>
+          </div>
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {
+  GetDataDetail as Api_GetDataDetail,
+  GetDataDetailImages as Api_GetDataDetailImages,
+  GetDataDetailVideos as Api_GetDataDetailVideos,
+} from "@/api/apilist";
+
+export default {
+  name: "detail",
+  components: {CustomSearch3},
+  data() {
+    return {
+      titleName: "",
+      titleIntroduce: "",
+      navbarIndex: "1",
+      basisInfo: {
+        id: "",
+        keyWord: "",
+        introduction: "",
+        file: "",
+      },
+      images: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+      videos: {
+        searchType: "title",
+        searchName: "",
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: [],
+        scrollDisabled: false,
+      },
+    }
+  },
+  methods: {
+    OnlinePreview: function (fileUrl) {
+      if (fileUrl) {
+        if (fileUrl.replace(/\\/g, '').toLowerCase().indexOf('.pdf') >= 0) {
+          window.open(fileUrl);
+        } else {
+          //https://view.officeapps.live.com/op/view.aspx?src=
+          window.open("http://www.xdocin.com/xdoc?_func=to&_format=html&_cache=1&_xdoc=" + fileUrl.replace(/\\/g, ''));
+        }
+      }
+    },
+    SearchBasisInfo: function (id) {
+      Api_GetDataDetail(id).then(res => {
+        this.basisInfo = res;
+        this.titleIntroduce = res.keyWord;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchImages: function (searchType, searchName) {
+      this.images.searchType = searchType;
+      this.images.searchName = searchName;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.images.currentPage = res.currentPage;
+        this.images.pageSize = res.pageSize;
+        this.images.total = res.total;
+        this.images.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextImages: function () {
+      let searchType = this.images.searchType;
+      let searchName = this.images.searchName;
+      let currentPage = this.images.currentPage + 1;
+      let pageSize = this.images.pageSize;
+      Api_GetDataDetailImages(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.images.total = res.total;
+          this.images.currentPage = res.currentPage;
+          this.images.data = this.images.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    SearchVideos: function (searchType, searchName) {
+      this.videos.searchType = searchType;
+      this.videos.searchName = searchName;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, 1, 10).then(res => {
+        this.videos.currentPage = res.currentPage;
+        this.videos.pageSize = res.pageSize;
+        this.videos.total = res.total;
+        this.videos.data = res.data;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    NextVideos: function () {
+      let searchType = this.videos.searchType;
+      let searchName = this.videos.searchName;
+      let currentPage = this.videos.currentPage + 1;
+      let pageSize = this.videos.pageSize;
+      Api_GetDataDetailVideos(this.$route.query.id, searchType, searchName, currentPage, pageSize).then(res => {
+        if (res.data.length > 0) {
+          this.videos.total = res.total;
+          this.videos.currentPage = res.currentPage;
+          this.videos.data = this.videos.data.concat(res.data);
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert('错误的请求!');
+      });
+    },
+    ToImageDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "spirit-detail-image", query: {id: id, objId: objId}});
+    },
+    ToVideoDetail: function (id) {
+      let objId = this.$route.query.id;
+      this.$router.push({name: "spirit-detail-video", query: {id: id, objId: objId}});
+    },
+    ToListPage: function () {
+      this.$router.push({name: "spirit-list"})
+    },
+  },
+  watch: {
+    navbarIndex: function () {
+      switch (this.navbarIndex) {
+        case 1:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = true;
+          break;
+        case 2:
+          this.images.scrollDisabled = false;
+          this.videos.scrollDisabled = true;
+          break;
+        case 3:
+          this.images.scrollDisabled = true;
+          this.videos.scrollDisabled = false;
+          break;
+      }
+    }
+  },
+  created() {
+    let id = this.$route.query.id;
+    this.titleName = this.$route.query.name;
+    this.SearchBasisInfo(id);
+    this.SearchImages("title", "");
+    this.SearchVideos("title", "");
+  }
+}
+</script>
+
+<style scoped>
+.data-detail {
+  width: 100%;
+}
+
+.data-detail .title {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  align-items: center;
+
+  width: 100%;
+  height: 15.9vh;
+  background: url("../../assets/datadetail/detail@1x.png") no-repeat 100% 100%;
+  background-size: cover;
+  border-radius: 10px 10px 0 0;
+}
+
+.data-detail .title .title-left {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 60%;
+  height: 100%;
+  padding-left: 2vh;
+}
+
+.data-detail .title .title-name {
+  width: 100%;
+  text-align: left;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2.62rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 5.24rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-introduce {
+  width: 100%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3.37rem;
+  color: #FFFFFF;
+  opacity: 1;
+}
+
+.data-detail .title .title-right {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: flex-start;
+
+  width: 30%;
+  height: 100%;
+}
+
+.data-detail .title .online-preview {
+  width: 80%;
+  background: #EFC587;
+  opacity: 1;
+  border-radius: 60px;
+
+  font-size: 1.75rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 3.87vh;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.data-detail .content {
+  width: 90%;
+  height: 84.1vh;
+  margin-left: 5%;
+  border-radius: 30px;
+}
+
+.mint-navbar /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 2rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar /deep/ .is-selected {
+  color: #BC0000;
+  border-bottom: 0.3vh solid #BC0000;
+}
+
+.mint-navbar /deep/ .is-selected .mint-tab-item-label {
+  color: #BC0000;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(1) {
+  padding-top: 5vh;
+}
+
+.content-keyword {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-keyword .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-introduction {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.content-introduction .item-name {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: bold;
+  line-height: 6rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(2) {
+  padding-top: 2vh;
+}
+
+.custom-search3 {
+  margin-bottom: 2vh;
+}
+
+.content-images {
+  display: flex;
+  flex-wrap: wrap;
+  flex-direction: row;
+  justify-content: flex-start;
+  align-items: flex-start;
+}
+
+.content-images .content-item {
+  width: 50%;
+  height: 25vh;
+}
+
+.content-images .content-item .img-div {
+  width: 90%;
+  height: 80%;
+  border-radius: 10px;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+}
+
+.content-images .content-item .img-div img {
+  width: 100%;
+  height: 100%;
+  border-radius: 10px;
+  object-fit: cover;
+}
+
+.content-images .content-item .item-name {
+  width: 90%;
+
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+
+  font-size: 2em;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 2em;
+  color: #333333;
+  opacity: 1;
+}
+
+.mint-tab-container /deep/ .mint-tab-container-item:nth-child(3) {
+  padding-top: 2vh;
+}
+
+.content-videos {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+}
+
+.content-videos .content-item {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: nowrap;
+  justify-content: flex-start;
+  align-items: center;
+
+  height: 10vh;
+  margin: 2vh auto;
+}
+
+.content-videos .item-left {
+  width: 30%;
+  height: 100%;
+}
+
+.content-videos .item-left img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content-videos .item-right {
+  width: 70%;
+  height: 100%;
+  padding-left: 2vw;
+}
+
+.content-videos .item-name {
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+  opacity: 1;
+}
+
+.content-videos .item-introduce {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  text-align: left;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/spirit/detailImage.vue b/src/views/spirit/detailImage.vue
new file mode 100644
index 0000000..07a9a97
--- /dev/null
+++ b/src/views/spirit/detailImage.vue
@@ -0,0 +1,133 @@
+<template>
+  <div class="data-detail-image">
+    <div class="images">
+      <mt-swipe :show-indicators="false" :auto="0" :continuous="false" @change="ChangeImage">
+        <mt-swipe-item v-for="item in images.data" :key="item.key">
+          <img :src="item.path"/>
+        </mt-swipe-item>
+      </mt-swipe>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ image.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ image.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetImageDetail as Api_GetImageDetail} from "@/api/apilist";
+
+export default {
+  name: "detailImage",
+  data() {
+    return {
+      navIndex: "1",
+      images: {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+        data: []
+      },
+      image: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      }
+    }
+  },
+  methods: {
+    ChangeImage: function (index) {
+      this.image = this.images.data[index];
+    },
+  },
+  created() {
+    let imageId = this.$route.query.id;
+    let objId = this.$route.query.objId;
+    Api_GetImageDetail(imageId, 1, objId, 999).then(res => {
+      this.images = res;
+      this.image = res.data[0];
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-image {
+  width: 100%;
+}
+
+.images {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.images img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/spirit/detailvideo.vue b/src/views/spirit/detailvideo.vue
new file mode 100644
index 0000000..f755c4c
--- /dev/null
+++ b/src/views/spirit/detailvideo.vue
@@ -0,0 +1,121 @@
+<template>
+  <div class="data-detail-video">
+    <div class="videos">
+      <video poster="" :src="video.patch" controls="controls">
+        您的浏览器不支持 video 标签。
+      </video>
+    </div>
+    <div class="content">
+      <mt-navbar v-model="navIndex">
+        <mt-tab-item id="1">关键词</mt-tab-item>
+        <mt-tab-item id="2">简介</mt-tab-item>
+      </mt-navbar>
+      <mt-tab-container v-model="navIndex">
+        <mt-tab-container-item id="1">
+          {{ video.keyWord }}
+        </mt-tab-container-item>
+        <mt-tab-container-item id="2">
+          {{ video.introduction }}
+        </mt-tab-container-item>
+      </mt-tab-container>
+    </div>
+  </div>
+</template>
+
+<script>
+import {GetVideoDetail as Api_GetVideoDetail} from "@/api/apilist";
+
+export default {
+  name: "detailVideo",
+  data() {
+    return {
+      navIndex: "1",
+      video: {
+        id: "",
+        name: "",
+        path: "",
+        keyWord: "",
+        introduction: "",
+      },
+    }
+  },
+  methods: {
+
+  },
+  created() {
+    let id = this.$route.query.id;
+    Api_GetVideoDetail(id).then(res => {
+      this.video = res;
+    }, rej => {
+      alert(rej);
+    }).catch(err => {
+      console.log(err);
+      alert('错误的请求!');
+    });
+  }
+}
+</script>
+
+<style scoped>
+.data-detail-video {
+  width: 100%;
+}
+
+.videos {
+  width: 100%;
+  height: 31.5vh;
+}
+
+.videos video {
+  width: 100%;
+  height: 100%;
+  background: black;
+}
+
+.content {
+  width: 100%;
+  height: 66vh;
+  box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
+  opacity: 1;
+  border-radius: 10px;
+
+  padding-top: 1vh;
+}
+
+.content > div{
+  width: 90%;
+  margin-left: 5%;
+}
+
+.mint-navbar{
+  margin-bottom: 4vh;
+}
+
+.mint-navbar .mint-tab-item /deep/ .mint-tab-item-label {
+  font-size: 2rem;
+  font-family: Source Han Sans CN;
+  font-weight: 500;
+  line-height: 3rem;
+  color: #767676;
+  opacity: 1;
+}
+
+.mint-navbar .is-selected {
+  border-bottom: 0.3rem solid #BC0000;
+}
+
+.mint-navbar .is-selected /deep/ .mint-tab-item-label {
+  color: #BC0000;
+  font-weight: bold;
+}
+
+.mint-tab-container {
+  text-align: left;
+  font-size: 1.87rem;
+  font-family: Source Han Serif CN;
+  font-weight: 400;
+  line-height: 3rem;
+  color: #585858;
+  opacity: 1;
+}
+</style>
diff --git a/src/views/spirit/list.vue b/src/views/spirit/list.vue
new file mode 100644
index 0000000..06e36f1
--- /dev/null
+++ b/src/views/spirit/list.vue
@@ -0,0 +1,153 @@
+<template>
+  <div class="list-root">
+    <div class="search">
+      <CustomSearch3 v-on:search="Search"></CustomSearch3>
+    </div>
+    <div class="line"></div>
+    <div class="data-list"
+         v-infinite-scroll="loadBottom"
+         :infinite-scroll-disabled="allLoaded"
+         :infinite-scroll-distance="10">
+      <template v-for="item in data.data">
+        <div class="text-item" :key="item.key" @click="ToDetail(item.id, item.name)">
+          <div class="item-title">{{ item.name }}</div>
+          <div class="item-context">{{ item.keyWord }}</div>
+        </div>
+        <div class="line" :key="item.key"></div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script>
+import CustomSearch3 from "@/components/CustomSearch3";
+import {GetDataList as Api_GetDataList} from "@/api/apilist";
+
+export default {
+  name: "list",
+  components: {CustomSearch3},
+  data() {
+    return {
+      dataType: 2,
+      searchType: "title",
+      searchName: "",
+      data: {
+        currentPage: 1,
+        pageSize: 5,
+        total: 0,
+        data: []
+      },
+      allLoaded: false
+    };
+  },
+  methods: {
+    Search: function (searchType, searchName) {
+      this.searchType = searchType;
+      this.searchName = searchName;
+      Api_GetDataList(this.dataType, searchType, searchName, 1, this.data.pageSize).then(res => {
+        this.currentPage = res.currentPage;
+        this.pageSize = res.pageSize;
+        this.total = res.total;
+        this.data = res;
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    loadBottom: function () {
+      Api_GetDataList(this.dataType, this.searchType, this.searchName, this.data.currentPage + 1, this.data.pageSize).then(res => {
+        this.data.currentPage = res.currentPage;
+        this.data.pageSize = res.pageSize;
+        this.data.total = res.total;
+        if (res.data.length > 0) {
+          this.data.data = this.data.data.concat(res.data);
+        }else{
+          this.allLoaded = true;
+        }
+      }, rej => {
+        alert(rej);
+      }).catch(err => {
+        console.log(err);
+        alert("错误的请求!");
+      });
+    },
+    ToDetail: function (id, name) {
+      this.$router.push({name: "spirit-detail", query: {id: id, name: name}})
+    }
+  },
+  created() {
+    this.Search("title", "");
+  }
+}
+</script>
+
+<style scoped>
+li {
+  list-style-type: none;
+}
+
+.list-root {
+  display: flex;
+  flex-direction: column;
+  justify-content: flex-start;
+  align-items: center;
+  width: 100%;
+}
+
+.search {
+  width: 100%;
+  margin-top: 3vh;
+}
+
+.search .custom-search3 {
+  width: 90%;
+  margin-left: 5%;
+}
+
+.line {
+  width: 100%;
+  border: 1px solid #EEEEEE;
+  margin-top: 3vh;
+  margin-bottom: 3vh;
+  opacity: 1;
+}
+
+.data-list {
+  width: 90%;
+  height: 65vh;
+  margin-left: 5%;
+  overflow: scroll;
+}
+
+.data-list .line {
+  width: 100%;
+  margin-bottom: 2vh;
+}
+
+
+data-list /deep/ .text-item {
+  width: 90%;
+  margin-bottom: 2vh;
+}
+
+data-list /deep/ .text-item .item-title {
+  text-align: left;
+  font-size: 2rem;
+  font-family: Source Han Serif CN;
+  font-weight: bold;
+  line-height: 4rem;
+  color: #BC0000;
+}
+
+data-list /deep/ .text-item .item-context {
+  text-align: left;
+  font-size: 1.62rem;
+  font-family: Source Han Sans CN;
+  font-weight: 400;
+  line-height: 2rem;
+  color: #767676;
+  text-align: left;
+}
+</style>
diff --git a/vue.config.js b/vue.config.js
new file mode 100644
index 0000000..56d969d
--- /dev/null
+++ b/vue.config.js
@@ -0,0 +1,14 @@
+module.exports = {
+    publicPath:'./',
+    devServer: {
+        proxy: {
+            '/api': {
+                target: 'http://hsly.xingyao100.com/',
+                changeOrigin: true,
+                pathRewrite: {
+                    '^/api': '/'
+                }
+            }
+        }
+    },
+}

--
Gitblit v1.9.3