diff --git a/bin/serve.js b/bin/serve.js
index f8734632..1db3957b 100644
--- a/bin/serve.js
+++ b/bin/serve.js
@@ -14,7 +14,7 @@ const getFileInfo = (app, file) => {
   if (/^App/.test(app.name)) {
     let {name, label} = app,
         path = app.path.replace(/.+[\\\/]([^\\\/]+)[\\\/]([^\\\/]+)$/g, `/apps/$1/$2`)
-    apps.list.push({id: name, name, label, path, libPath: file.replace(/\\/g, '/').replace(/^src(\/.+)\.vue/, '$1'), type: 'wxwork'})
+    apps.list.push({id: file.replace(/\.\/?(vue)?/g, '')?.replace(/[\\\/]/g,'_'), name, label, path, libPath: file.replace(/\\/g, '/').replace(/^src(\/.+)\.vue/, '$1'), type: 'wxwork'})
   }
 }
 const saveApps = app => {
diff --git a/src/App.vue b/src/App.vue
index 93f592f3..791ae746 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -9,6 +9,8 @@ export default {
   },
   onLaunch: function () {
     this.repairWxSDK()
+    this.initLoginBtn()
+    this.getApps()
   },
   onShow: function () {
     this.initWaterMarker()
@@ -19,7 +21,7 @@ export default {
     ...mapState(['token', 'user']),
   },
   methods: {
-    ...mapMutations(['initWaterMarker', 'logout', 'getConfig']),
+    ...mapMutations(['initWaterMarker', 'logout', 'getConfig', 'setApps']),
     goto(params, cb) {
       let {path: url, query: {app}} = this.$route
       params.query = {app, ...(params.query || {})}
@@ -32,7 +34,28 @@ export default {
     },
     repairWxSDK() {
       wx = jWeixin
-    }
+    },
+    initLoginBtn() {
+      let btn = document.createElement("div")
+      btn.id = "__loginBtn"
+      btn.innerText = "登录"
+      btn.addEventListener("click", () => {
+        if (location.pathname == "/pages/login") {
+          return this.$u.toast("已在登录页!")
+        } else uni.navigateTo({url: "/pages/login?back=" + encodeURIComponent(location.href?.replace(location.origin, ""))})
+      })
+      document.body.appendChild(btn)
+    },
+    getApps() {
+      this.setApps([])
+      this.$http.post("/node/wechatapps/list", null, {
+        params: {size: 999, type: 'wxwork'}
+      }).then(res => {
+        if (res?.data) {
+          this.setApps(res.data.records)
+        }
+      })
+    },
   },
 }
 
@@ -51,13 +74,14 @@ uni-page-body {
   background: #f5f5f5;
   position: relative;
 }
-  .text-hover {
-    opacity: 0.7;
-  }
 
-  .bg-hover {
-    background: #eee;
-  }
+.text-hover {
+  opacity: 0.7;
+}
+
+.bg-hover {
+  background: #eee;
+}
 
 div[bottom] {
   position: fixed;
@@ -153,6 +177,18 @@ uni-button {
   }
 }
 
+#__loginBtn {
+  position: fixed;
+  right: 16px;
+  top: 20px;
+  background-color: $uni-color-primary;
+  color: #fff;
+  padding: 8px 16px;
+  border-radius: 8px;
+  font-size: 24px;
+  box-shadow: 0 0 0.61538462em rgb(0 0 0 / 40%);
+}
+
 @keyframes mapWarn {
   0% {
     transform: scale(.5);
diff --git a/src/common/axios.js b/src/common/axios.js
index d6940e8e..61c0c61e 100644
--- a/src/common/axios.js
+++ b/src/common/axios.js
@@ -13,16 +13,15 @@ instance.interceptors.request.use(config => {
   if (/AppCountryAlbum/.test(location.pathname)) {
     config.baseURL = '/aca'
     config.url = config.url.replace(/(app|auth|admin)\//, "api/")
-  }
-  if (/\/grid\//.test(location.pathname)) {
+  } else if (/\/node\//.test(config.url)) {
+    config.baseURL = '/ns'
+  } else if (/\/grid\//.test(location.pathname)) {
     config.baseURL = '/wangge'
-  }
-  if (/\/project\/police\//.test(location.pathname)) {
+  } else if (/\/project\/police\//.test(location.pathname)) {
     config.baseURL = '/hnjc'
     config.url = config.url.replace(/(app|auth|admin)\//, "api/")
-  }
-  if (sessionStorage.getItem("prj") == "saas") {
-    config.url = config.url.replace(/(app|auth|admin)\//, "api/")
+  } else if (sessionStorage.getItem("prj") == "saas") {
+    config.baseURL = '/online'
   }
   if (!config.withoutToken && store.state.token) {
     config.headers["Authorization"] = store.state.token
@@ -50,7 +49,7 @@ instance.interceptors.response.use(res => {
       return res.data
     } else if (res.data.code == 401) {
       store.commit("logout");
-      uni.navigateTo({url: "/pages/login"})
+      uni.showToast({title: "请登录用户!"})
     } else {
       console.error(res.data.msg || "请求失败!")
       return Promise.reject(res.data.msg)
diff --git a/src/manifest.json b/src/manifest.json
index b0477f7e..9484005e 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -65,6 +65,13 @@
             "^/wangge": "/"
           }
         },
+        "/ns": {
+          "target": "http://192.168.1.87:12525",
+          "changeOrigin": true,
+          "pathRewrite": {
+            "^/ns": "/"
+          }
+        },
         "/hnjc": {
           "target": "http://192.168.1.87:12001/",
           "changeOrigin": true,
diff --git a/src/pages/loading.vue b/src/pages/loading.vue
index c0f630ef..568edbb0 100644
--- a/src/pages/loading.vue
+++ b/src/pages/loading.vue
@@ -5,13 +5,12 @@