Browse Source

完善基础架构的axios

yellowtaotao 3 years ago
parent
commit
8a3e0a1105

+ 2 - 0
.env.development

@@ -0,0 +1,2 @@
+API_LIST_NORMAL_URL = "http://8.141.68.219:8080"
+BASE_URL = "http://8.141.68.219:8080"

+ 2 - 0
.env.production

@@ -0,0 +1,2 @@
+API_LIST_NORMAL_URL = "http://8.141.68.219:8080"
+BASE_URL = "http://8.141.68.219:8080"

+ 2 - 0
.env.test

@@ -0,0 +1,2 @@
+API_LIST_NORMAL_URL = "http://8.141.68.219:8080"
+BASE_URL = "http://8.141.68.219:8080"

+ 100 - 83
package-lock.json

@@ -1782,12 +1782,50 @@
           "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
           "dev": true
         },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1618995547052&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
+          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
         "camelcase": {
           "version": "5.3.1",
           "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-5.3.1.tgz?cache=0&sync_timestamp=1603921882890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-5.3.1.tgz",
           "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=",
           "dev": true
         },
+        "chalk": {
+          "version": "4.1.1",
+          "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.1.tgz?cache=0&sync_timestamp=1618995354302&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.1.tgz",
+          "integrity": "sha1-yAs/qyi/Y3HmhjMl7uZ+YYt35q0=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
+          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
+          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
+          "dev": true,
+          "optional": true
+        },
         "css-loader": {
           "version": "3.6.0",
           "resolved": "https://registry.nlark.com/css-loader/download/css-loader-3.6.0.tgz?cache=0&sync_timestamp=1621865230592&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcss-loader%2Fdownload%2Fcss-loader-3.6.0.tgz",
@@ -1809,6 +1847,13 @@
             "semver": "^6.3.0"
           }
         },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz",
+          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
+          "dev": true,
+          "optional": true
+        },
         "icss-utils": {
           "version": "4.1.1",
           "resolved": "https://registry.npm.taobao.org/icss-utils/download/icss-utils-4.1.1.tgz?cache=0&sync_timestamp=1605801297051&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficss-utils%2Fdownload%2Ficss-utils-4.1.1.tgz",
@@ -1867,6 +1912,42 @@
           "requires": {
             "minipass": "^3.1.1"
           }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1618561008172&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
+          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "vue-loader-v16": {
+          "version": "npm:vue-loader@16.2.0",
+          "resolved": "https://registry.nlark.com/vue-loader/download/vue-loader-16.2.0.tgz?cache=0&sync_timestamp=1620717857145&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue-loader%2Fdownload%2Fvue-loader-16.2.0.tgz",
+          "integrity": "sha1-BGpTMI3Ufljv4g3ewe3sAnzjtG4=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "chalk": "^4.1.0",
+            "hash-sum": "^2.0.0",
+            "loader-utils": "^2.0.0"
+          },
+          "dependencies": {
+            "loader-utils": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
+              "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
+              "dev": true,
+              "optional": true,
+              "requires": {
+                "big.js": "^5.2.2",
+                "emojis-list": "^3.0.0",
+                "json5": "^2.1.2"
+              }
+            }
+          }
         }
       }
     },
@@ -2513,6 +2594,14 @@
       "integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk=",
       "dev": true
     },
+    "axios": {
+      "version": "0.21.1",
+      "resolved": "https://registry.npm.taobao.org/axios/download/axios-0.21.1.tgz?cache=0&sync_timestamp=1608609188013&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.21.1.tgz",
+      "integrity": "sha1-IlY0gZYvTWvemnbVFu8OXTwJsrg=",
+      "requires": {
+        "follow-redirects": "^1.10.0"
+      }
+    },
     "babel-eslint": {
       "version": "10.1.0",
       "resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz",
@@ -5678,8 +5767,7 @@
     "follow-redirects": {
       "version": "1.14.1",
       "resolved": "https://registry.nlark.com/follow-redirects/download/follow-redirects-1.14.1.tgz?cache=0&sync_timestamp=1620555300559&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.14.1.tgz",
-      "integrity": "sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M=",
-      "dev": true
+      "integrity": "sha1-2RFN7Qoc/dM04WTmZirQK/2R/0M="
     },
     "for-in": {
       "version": "1.0.2",
@@ -7014,6 +7102,11 @@
       "integrity": "sha1-J8dlOb4U2L0Sghmi1zGwkzeQTnk=",
       "dev": true
     },
+    "js-cookie": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npm.taobao.org/js-cookie/download/js-cookie-2.2.1.tgz",
+      "integrity": "sha1-aeEG3F1YBolFYpAqpbrsN0Tpsrg="
+    },
     "js-message": {
       "version": "1.0.7",
       "resolved": "https://registry.npm.taobao.org/js-message/download/js-message-1.0.7.tgz",
@@ -8047,6 +8140,11 @@
         "path-key": "^2.0.0"
       }
     },
+    "nprogress": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npm.taobao.org/nprogress/download/nprogress-0.2.0.tgz",
+      "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
+    },
     "nth-check": {
       "version": "1.0.2",
       "resolved": "https://registry.npm.taobao.org/nth-check/download/nth-check-1.0.2.tgz",
@@ -11494,87 +11592,6 @@
         }
       }
     },
-    "vue-loader-v16": {
-      "version": "npm:vue-loader@16.2.0",
-      "resolved": "https://registry.nlark.com/vue-loader/download/vue-loader-16.2.0.tgz?cache=0&sync_timestamp=1620717857145&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue-loader%2Fdownload%2Fvue-loader-16.2.0.tgz",
-      "integrity": "sha1-BGpTMI3Ufljv4g3ewe3sAnzjtG4=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "chalk": "^4.1.0",
-        "hash-sum": "^2.0.0",
-        "loader-utils": "^2.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1618995547052&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
-          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "4.1.1",
-          "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.1.tgz?cache=0&sync_timestamp=1618995354302&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.1.tgz",
-          "integrity": "sha1-yAs/qyi/Y3HmhjMl7uZ+YYt35q0=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
-          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
-          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
-          "dev": true,
-          "optional": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz",
-          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
-          "dev": true,
-          "optional": true
-        },
-        "loader-utils": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
-          "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^2.1.2"
-          }
-        },
-        "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1618561008172&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
-          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
     "vue-ref": {
       "version": "2.0.0",
       "resolved": "https://registry.npm.taobao.org/vue-ref/download/vue-ref-2.0.0.tgz",

+ 3 - 0
package.json

@@ -9,9 +9,12 @@
   },
   "dependencies": {
     "ant-design-vue": "^1.7.5",
+    "axios": "^0.21.1",
     "core-js": "^3.6.5",
+    "js-cookie": "^2.2.1",
     "less": "^4.1.1",
     "less-loader": "^6.0.0",
+    "nprogress": "^0.2.0",
     "vue": "^2.6.11",
     "vue-router": "^3.5.1",
     "vuex": "^3.6.2",

+ 44 - 0
src/api/index.js

@@ -0,0 +1,44 @@
+"use strict";
+
+/* eslint-disable no-unused-vars */
+
+import Vue from "vue";
+
+// name 子系统名称
+// url 子系统使用的环境变量(请求地址)
+const subList = [
+  {
+    name: "API_LIST_NORMAL",
+    url: "API_LIST_NORMAL_URL"
+  }
+];
+
+// 所有api子系统
+let API_LIST = {};
+const moduleFiles = require.context("./modules", true, /\.js$/);
+moduleFiles.keys().forEach(modulePath => {
+  API_LIST = { ...API_LIST, ...moduleFiles(modulePath).default };
+});
+
+// 合成API地址集合
+let apiList = {};
+subList.forEach(it => {
+  console.log(API_LIST)
+  let subApi = Object.entries(API_LIST[it.name]).reduce((target, [key, value]) => {
+    console.log(process.env)
+    // target[key] = process.env[it.url].replace(/\W*$/, "") + "/" + value.replace(/^\W*/, "");
+    target[key] = 'http://8.141.68.219:8080' + "/" + value.replace(/^\W*/, "");
+    return target;
+  }, {});
+  // console.log(it)
+  apiList = { ...apiList, ...subApi };
+});
+console.log(apiList)
+
+// 注册所有API地址
+Object.defineProperty(Vue.prototype, "$_API", {
+  get() {
+    return apiList;
+  }
+});
+export default apiList;

+ 7 - 0
src/api/modules/user.js

@@ -0,0 +1,7 @@
+// JTXT系统相关api
+export default {
+  API_LIST_NORMAL: {
+    //  admin获取所有用户
+    INTERFACE_GET_USER_ADMIN_USERS: "admin/users"
+  }
+};

+ 36 - 0
src/common/Constant.js

@@ -0,0 +1,36 @@
+// 网络连接错误提示信息
+export const HTTP_ERROR_MESSAGE = "系统出小差了,请联系管理员处理 ≧﹏≦";
+// 提示信息停留时间
+export const ELEMENT_MESSAGE_DURATION = 3000;
+// 前台存储的token字段名
+export const AUTH_TOKEN_FRONT = "TOKEN_STRING";
+// 后台存储的token字段名
+export const AUTH_TOKEN_END = "Token";
+// 允许的图片类型列表
+export const UPLOAD_IMAGE_TYPE = [
+  "bmp",
+  "jpg",
+  "jpeg",
+  "png",
+  "tif",
+  "gif",
+  "pcx",
+  "tga",
+  "exif",
+  "fpx",
+  "svg",
+  "psd",
+  "cdr",
+  "pcd",
+  "dxf",
+  "ufo",
+  "eps,",
+  "ai,",
+  "raw",
+  ",WMF",
+  "webp"
+];
+// 上传图片的最大大小,单位:MB
+export const UPLOAD_IMAGE_MAX_SIZE = 10;
+// 正则表达式:身份证号
+export const REGULAR_EXPRESSION_IDNUMBER = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/;

+ 7 - 0
src/common/index.js

@@ -0,0 +1,7 @@
+// 注册所有api地址为全局变量
+import "@/api";
+
+// 引入所有modules下的js
+let moduleFiles = require.context("./modules", true, /\.js$/);
+const requireAll = context => context.keys().map(context);
+requireAll(moduleFiles);

+ 39 - 0
src/common/modules/globalEvent.js

@@ -0,0 +1,39 @@
+// import Vue from "vue";
+
+// render
+// const h = new Vue().$createElement;
+
+/**
+ * 存储全局事件类
+ */
+var events = {};
+export default class globalEvent {
+  static set(key, value) {
+    events[key] = value;
+  }
+  static get(key) {
+    return events[key];
+  }
+}
+
+/**
+ * 网络断开
+ */
+window.onoffline = () => {
+  if (globalEvent.get("offline")) {
+    return;
+  }
+  let instance = this.$message.error("网络连接异常,请检查网络!");
+  globalEvent.set("offline", instance);
+};
+
+/**
+ * 网络重新连接
+ */
+window.ononline = () => {
+  const notify = globalEvent.get("offline");
+  if (notify) {
+    notify.close();
+  }
+  this.$message.error("网络已重新连接");
+};

+ 39 - 0
src/common/modules/permission.js

@@ -0,0 +1,39 @@
+import router from "@/router";
+// 进度条
+import NProgress from "nprogress";
+// 进度条样式
+import "nprogress/nprogress.css";
+import { getCookie } from "@/utils/cookie";
+import { AUTH_TOKEN_FRONT } from "@/common/Constant";
+
+NProgress.configure({ showSpinner: false });
+
+// 不需要token的白名单
+const whiteList = ["/login"];
+
+// 注册路由跳转的权限控制
+router.beforeEach(async (to, from, next) => {
+  NProgress.start();
+
+  const hasToken = getCookie(AUTH_TOKEN_FRONT);
+  if (hasToken) {
+    if (to.path === "/login") {
+      next({ path: "/" });
+      console.log('回到登录了')
+      NProgress.done();
+    } else {
+      next();
+    }
+  } else {
+    if (whiteList.includes(to.path)) {
+      next();
+    } else {
+      next("/login");
+      NProgress.done();
+    }
+  }
+});
+
+router.afterEach(() => {
+  NProgress.done();
+});

+ 130 - 0
src/filters/index.js

@@ -0,0 +1,130 @@
+import moment from "moment";
+import { isDataType } from "@/utils/tools";
+
+const SEX_LIST = ["", "男", "女"];
+
+// 验证是否是数字或字符串
+function validateToNumber(val) {
+  return typeof val === "string" || typeof val === "number";
+}
+
+// 验证日期是否合理
+function validateDate(val) {
+  let date = val;
+  // Invalid Date
+  if (!date || !date.getTime()) {
+    return "";
+  }
+  let day = moment(date).format("YYYY-MM-DD");
+  if (day === "1970-01-01" || day === "1900-01-01") {
+    return false;
+  }
+  return true;
+}
+
+// 格式化性别
+export function formatSex(sex) {
+  return SEX_LIST[sex] || "";
+}
+
+// 格式化年龄
+export function formatAge(age) {
+  if (!age) return "";
+  // 纯数字
+  if (/^\d+$/.test(age)) return `${age}岁`;
+  return age;
+}
+
+// 格式化金额
+export function formatMoney(money) {
+  if (!validateToNumber(money)) {
+    return "";
+  }
+  let num = parseFloat(money);
+  if (num === 0) {
+    return 0;
+  }
+  if (!num) {
+    return "";
+  }
+  return (num / 100).toFixed(2);
+}
+
+// 格式化金额,带符号
+export function formatMoneyWithSymbol(money) {
+  if (!validateToNumber(money)) {
+    return "";
+  }
+  let num = parseFloat(money);
+  if (num === 0) {
+    return "¥0";
+  }
+  if (!num) {
+    return "";
+  }
+  return "¥" + (num / 100).toFixed(2);
+}
+
+// 格式化日期+时间
+export function formatDateTime(date) {
+  let temp = date;
+  if (!isDataType(date, "Date")) {
+    temp = new Date(date);
+  }
+  if (!validateDate(temp)) {
+    return "";
+  }
+  return moment(date).format("YYYY-MM-DD HH:mm:ss");
+}
+
+// 格式化日期
+export function formatDate(date) {
+  let temp = date;
+  if (!isDataType(date, "Date")) {
+    temp = new Date(date);
+  }
+  if (!validateDate(temp)) {
+    return "";
+  }
+  return moment(date).format("YYYY-MM-DD");
+}
+
+// 格式化日期
+export function formatMonth(date) {
+  let temp = date;
+  if (!isDataType(date, "Date")) {
+    temp = new Date(date);
+  }
+  if (!validateDate(temp)) {
+    return "";
+  }
+  return moment(date).format("YYYY-MM");
+}
+
+// 升序排序
+export function objKeySort(obj) {
+  if (!obj || Array.isArray(obj)) {
+    return "";
+  }
+  // 升序
+  let newkey = Object.keys(obj).sort(); // 先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获取的属性名进行排序,newkey是一个数组
+  // 倒序
+  // var newkey = Object.keys(obj).sort().reverse();
+  let newObj = {}; // 创建一个新的对象,用于存放排好序的键值对
+  for (let i = 0; i < newkey.length; i++) { // 遍历newkey数组
+    newObj[newkey[i]] = obj[newkey[i]]; // 向新创建的对象中按照排好的顺序依次增加键值对
+  }
+  let objValuesString = "";
+  Object.values(newObj).forEach(item => {
+    if (!Array.isArray(item) && !(item instanceof Object)) {
+      objValuesString = objValuesString + item;
+    }
+  });
+  return objValuesString; // 返回排好序的新对象的值拼接起来的字符窜
+}
+
+// 转换当前时间为时间戳
+export function dateChange() {
+  let date = Date.parse(new Date());
+  return date;
+}

+ 6 - 0
src/main.js

@@ -17,6 +17,12 @@ import Antd from 'ant-design-vue';
 import 'ant-design-vue/dist/antd.css';
 Vue.use(Antd);
 
+// 注册自定义插件
+import './plugins'
+// 调用共通js
+import './common'
+
+
 Vue.config.productionTip = false;
 
 new Vue({

+ 7 - 0
src/plugins/index.js

@@ -0,0 +1,7 @@
+import Vue from "vue";
+
+// 全局注册所有插件
+let moduleFiles = require.context("./modules", true, /\.js$/);
+moduleFiles.keys().forEach(modulePath => {
+  Vue.use(moduleFiles(modulePath).default);
+});

+ 141 - 0
src/plugins/modules/axios.js

@@ -0,0 +1,141 @@
+"use strict";
+
+import axios from "axios";
+import store from "@/store";
+import { getCookie } from "@/utils/cookie";
+import { AUTH_TOKEN_FRONT, AUTH_TOKEN_END } from "@/common/Constant";
+import { getAllPromise } from "@/utils/tools";
+import { message } from "ant-design-vue"
+import { triggerEvent } from "@/utils/events";
+
+// 完整配置参考:  https://github.com/axios/axios#request-config
+axios.defaults.headers.post["Content-Type"] = "application/json;charset=utf-8";
+
+let config = {
+  baseURL: process.env.BASE_URL || process.env.apiUrl || "",
+  // baseURL: "http://8.141.68.219:8080",
+  timeout: 60 * 1000,
+  withCredentials: false,
+  crossDomain: true,
+  transformRequest: [
+    data => {
+      if (!data || typeof data === "string") {
+        return data;
+      }
+      if (data instanceof FormData) {
+        return data;
+      }
+      // 对Blob对象进行处理
+      let hasBlob = Object.values(data).some(it => {
+        return it instanceof Blob;
+      });
+      if (!hasBlob) {
+        return JSON.stringify(data);
+      }
+      const formData = new FormData();
+      Object.entries(data).forEach(([key, value]) => {
+        formData.append(key, value);
+      });
+      return formData;
+    }
+  ]
+};
+
+const _axios = axios.create(config);
+
+// 注册all方法,执行多个并发请求
+// 可传入Promise、包含Promise的数组、返回值为Promise的方法
+_axios.all = (...requsets) => {
+  // 获取所有Promise对象
+  let promiseList = getAllPromise(requsets);
+  return new Promise((resolve, reject) => {
+    axios.all(promiseList)
+      .then(axios.spread((...response) => {
+        // 两个请求现在都执行完成
+        resolve(response);
+      }))
+      .catch(error => {
+        reject(error);
+      });
+  });
+};
+
+_axios.interceptors.request.use(
+  config => {
+    const token = getCookie(AUTH_TOKEN_FRONT);
+    config.headers.common[AUTH_TOKEN_END] = token;
+    return config;
+  },
+  error => {
+    return Promise.reject(error);
+  }
+);
+
+// 拦截响应
+_axios.interceptors.response.use(
+  response => {
+    // 用来判断是否请求成功
+    const success = response.status === 200 && response.data.code === 0;
+    let messages = "";
+    if (!success) {
+      if (typeof response.data === "string") {
+        messages = "服务器错误,未获取到响应数据";
+      } else {
+        if (response.status === 200 && response.data.code === 0) {
+          return Promise.reject(response);
+        }
+        // 请求成功,但在业务上为失败
+        messages = response.data.message || response.data.errorData || "操作执行失败";
+      }
+      message.error(messages);
+      return Promise.reject(response);
+    }
+    return {
+      data: response.data.data,
+      success,
+      messages
+    };
+  },
+  error => {
+    if (!navigator.onLine) {
+      triggerEvent(window, "offline");
+      return Promise.reject(error);
+    }
+    if (!error.response) {
+      message.error("连接服务器失败");
+      return Promise.reject(error);
+    }
+    let status = error.response.status;
+    if (status === 401) {
+      message.error("您的登录已过期,请重新登录");
+      window.location.reload();
+      store.dispatch("user/logout");
+      return Promise.reject(error);
+    }
+    if (status < 200) {
+      message.warning(`未处理的消息响应,状态码:${status}`);
+    } else if (status >= 300 && status < 400) {
+      message.warning(`未处理的重定向响应,状态码:${status}`);
+    } else if (status >= 400 && status < 500) {
+      message.error(`客户端错误,状态码:${status}`);
+    } else if (status >= 500) {
+      message.error(`服务器错误,状态码:${status}`);
+    }
+    // 系统请求失败
+    return Promise.reject(error);
+  }
+);
+
+export default {
+  install: Vue => {
+    Vue.$_http = _axios;
+    window.$_http = _axios;
+    Object.defineProperties(Vue.prototype, {
+      $_http: {
+        get() {
+          return _axios;
+        }
+      }
+    });
+  }
+};

+ 99 - 0
src/plugins/modules/loop_axios.js

@@ -0,0 +1,99 @@
+"use strict";
+
+import axios from "axios";
+import { getCookie } from "@/utils/cookie";
+import { AUTH_TOKEN_FRONT, AUTH_TOKEN_END } from "@/common/Constant";
+import { getAllPromise } from "@/utils/tools";
+
+// 完整配置参考:  https://github.com/axios/axios#request-config
+axios.defaults.headers.post["Content-Type"] = "application/json;charset=utf-8";
+
+let config = {
+  baseURL: process.env.BASE_URL || process.env.apiUrl || "",
+  // baseURL: "http://8.141.68.219:8080",
+  timeout: 60 * 1000,
+  withCredentials: false,
+  crossDomain: true,
+  transformRequest: [
+    data => {
+      if (!data || typeof data === "string") {
+        return data;
+      }
+      if (data instanceof FormData) {
+        return data;
+      }
+      // 对Blob对象进行处理
+      let hasBlob = Object.values(data).some(it => {
+        return it instanceof Blob;
+      });
+      if (!hasBlob) {
+        return JSON.stringify(data);
+      }
+      const formData = new FormData();
+      Object.entries(data).forEach(([key, value]) => {
+        formData.append(key, value);
+      });
+      return formData;
+    }
+  ]
+};
+
+const _axios = axios.create(config);
+
+// 注册all方法,执行多个并发请求
+// 可传入Promise、包含Promise的数组、返回值为Promise的方法
+_axios.all = (...requsets) => {
+  // 获取所有Promise对象
+  let promiseList = getAllPromise(requsets);
+  return new Promise((resolve, reject) => {
+    axios.all(promiseList)
+      .then(axios.spread((...response) => {
+        // 两个请求现在都执行完成
+        resolve(response);
+      }))
+      .catch(error => {
+        reject(error);
+      });
+  });
+};
+
+_axios.interceptors.request.use(
+  config => {
+    const token = getCookie(AUTH_TOKEN_FRONT);
+    config.headers.common[AUTH_TOKEN_END] = token;
+    return config;
+  },
+  error => {
+    return Promise.reject(error);
+  }
+);
+
+// 拦截响应
+_axios.interceptors.response.use(
+  response => {
+    const success = response.status === 200 && response.data.code === 0;
+    let message = "";
+    return {
+      data: response.data.data,
+      success,
+      message
+    };
+  },
+  error => {
+    return Promise.reject(error);
+  }
+);
+
+export default {
+  install: Vue => {
+    Vue.$_loop_http = _axios;
+    window.$_loop_http = _axios;
+    Object.defineProperties(Vue.prototype, {
+      $_loop_http: {
+        get() {
+          return _axios;
+        }
+      }
+    });
+  }
+};

+ 10 - 2
src/router/index.js

@@ -1,8 +1,15 @@
 import Vue from "vue";
 import Router from "vue-router";
+import Login from "@/views/login";
 Vue.use(Router);
 
-let routes = [];
+let routes = [
+  {
+    path: "/login",
+    name: "login",
+    component: Login
+  }
+];
 // 菜单路由
 const moduleFiles = require.context("./modules", true, /\.js$/);
 moduleFiles.keys().forEach(modulePath => {
@@ -16,6 +23,7 @@ commonFiles.keys().forEach(modulePath => {
 
 export default new Router({
   mode: "history",
-  // base: process.env.BASE_URL,
+  base: process.env.BASE_URL,
+  // base: "http://8.141.68.219:8080",
   routes
 });

+ 18 - 2
src/store/modules/user.js

@@ -1,4 +1,6 @@
 import router from "@/router";
+import { setCookie, removeCookie } from "@/utils/cookie";
+import { AUTH_TOKEN_FRONT } from "@/common/Constant";
 
 const state = {
   userInfo: {},
@@ -7,8 +9,10 @@ const state = {
 };
 
 const mutations = {
-  updateUserItem: (state, fieldName, data) => {
-    state[fieldName] = data
+  // 登录状态保存
+  SET_LOGIN: (state, user) => {
+    state.userInfo = user;
+    setCookie(AUTH_TOKEN_FRONT, user.token);
   },
   // 添加userInfo信息
   ADD_USERINFO: (state, addInfo) => {
@@ -16,6 +20,18 @@ const mutations = {
     for (let i = 0; i < keys.length; i++) {
       state.userInfo[keys[i]] = addInfo[keys[i]];
     }
+  },
+  // 角色状态保存
+  SET_ROLE(state, roles) {
+    state.roles = roles;
+  },
+  // 注销登录状态
+  SET_LOGOUT(state) {
+    state.userInfo = {};
+    state.menus = [];
+    state.roles = [];
+    sessionStorage.removeItem("online");
+    removeCookie(AUTH_TOKEN_FRONT);
   }
 };
 

+ 37 - 0
src/utils/events.js

@@ -0,0 +1,37 @@
+// 浏览器中的事件管理
+
+/**
+ * 触发一个DOM事件
+ * @param  {Element} node 事件发生的节点元素
+ * @param  {String} name 事件名称,不含前缀:on
+ * @param  {...any} options 可选的事件配置项
+ */
+export function triggerEvent(node, name, ...options) {
+  if (node.fireEvent) {
+    return node.fireEvent('on' + name);
+  }
+  let eventName;
+  let evt;
+  if (/^mouse|click/.test(name)) {
+    eventName = 'MouseEvents';
+    evt = document.createEvent(eventName);
+    evt.initMouseEvent(name, ...options);
+  } else if (['DOMActivate', 'DOMFocusIn', 'DOMFocusOut'].includes(name)) {
+    eventName = 'UIEvents';
+    evt = document.createEvent(eventName);
+    evt.initUIEvent(name, ...options);
+  } else if (/^key/.test(name)) {
+    eventName = 'KeyboardEvent';
+    evt = document.createEvent(eventName);
+    evt.initKeyboardEvent(name, ...options);
+  } else if (name.startsWith('DOM')) {
+    eventName = 'MutationEvents';
+    evt = document.createEvent(eventName);
+    evt.initMutationEvent(name, ...options);
+  } else {
+    eventName = 'HTMLEvents';
+    evt = document.createEvent(eventName);
+    evt.initEvent(name, ...options);
+  }
+  return node.dispatchEvent(evt);
+}

+ 234 - 0
src/utils/tools.js

@@ -0,0 +1,234 @@
+/* eslint-disable */
+// 工具包:普通js常用方法
+
+/**
+ * 复制对象,除去数组noNeedFileds中的字段
+ * @param {*} from 源对象
+ * @param  {...any} noNeedFileds 不复制的字段
+ */
+ export function optionalCopy (from, ...noNeedFileds) {
+  if (!from) {
+    return {};
+  }
+  return Object.entries(from).reduce((ret, [key, value]) => {
+    if (!flat(noNeedFileds).includes(key)) {
+      ret[key] = value;
+    }
+    return ret;
+  }, {});
+}
+
+/**
+ * 设置缓存
+ * @param {*} key 
+ * @param {*} value 
+ */
+export function setSesssion (key, value) {
+  if (key && value) {
+    sessionStorage.setItem(key, JSON.stringify(value))
+  }
+}
+
+/**
+ * 获取缓存
+ * @param {}} key 
+ */
+export function getSession (key) {
+  if (key) {
+    let str = sessionStorage.getItem(key)
+    if (str) {
+      return JSON.parse(str)
+    } else {
+      return null
+    }
+  }
+  return null
+}
+
+/**
+ * 拖动窗口的方法
+ */
+export function drag (dom) {
+  var drag = document.querySelector(dom);
+  console.log(drag)
+  if (!drag) return false;
+  // //点击某物体时,用drag对象即可,move和up是全局区域,
+  // 也就是整个文档通用,应该使用document对象而不是drag对象(否则,采用drag对象时物体只能往右方或下方移动)
+  drag.onmousedown = function (event) {
+    event = event || window.event; // 兼容IE浏览器
+    //    鼠标点击物体那一刻相对于物体左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
+    var diffX = event.clientX - drag.offsetLeft;
+    var diffY = event.clientY - drag.offsetTop;
+    if (typeof drag.setCapture !== "undefined") {
+      drag.setCapture();
+    }
+    document.onmousemove = function (event) {
+      event = event || window.event;
+      var moveX = event.clientX - diffX;
+      var moveY = event.clientY - diffY;
+      if (moveX < 0) {
+        moveX = 0;
+      } else if (moveX > window.innerWidth - drag.offsetWidth) {
+        moveX = window.innerWidth - drag.offsetWidth;
+      }
+      if (moveY < 0) {
+        moveY = 0;
+      } else if (moveY > window.innerHeight - drag.offsetHeight) {
+        moveY = window.innerHeight - drag.offsetHeight;
+      }
+      drag.style.left = moveX + "px";
+      drag.style.top = moveY + "px";
+    };
+    document.onmouseup = function (event) {
+      this.onmousemove = null;
+      this.onmouseup = null;
+      // 修复低版本ie bug
+      if (typeof drag.releaseCapture !== "undefined") {
+        drag.releaseCapture();
+      }
+    };
+  };
+}
+
+/**
+ * 复制from表单对象,空值不复制
+ * @param {*} from 源对象
+ * @param  {...any} noNeedFileds 不复制的字段
+ */
+export function optionalFormCopy (from, ...noNeedFileds) {
+  if (!from) {
+    return {};
+  }
+  return Object.entries(from).reduce((ret, [key, value]) => {
+    if (isDataType(value, "null", "undefined")) {
+      return ret;
+    }
+    if (!flat(noNeedFileds).includes(key)) {
+      ret[key] = value;
+    }
+    return ret;
+  }, {});
+}
+
+/**
+ * 判断数据的类型是否符合预期
+ * 只传一个参数data,则返回数据的类型;
+ * 传入多个参数,则判断数据是否属于该类型(或属于类型数组中的一个)
+ * @param {*} data 需要判断类型的数据
+ * @param  {...any} typeList 字符串或字符串数组,可不传
+ */
+export function isDataType (data, ...typeList) {
+  let dataType = Object.prototype.toString.call(data)
+    .replace(/^\[object/, "")
+    .replace(/\]$/, "")
+    .replace(/\s/, "");
+  typeList = flat(typeList);
+  let hasType = typeList.some(it => {
+    return it && isDataType(it) === "String";
+  });
+  if (!hasType) {
+    return dataType;
+  }
+  if (typeList.includes(dataType) || typeList.includes(dataType.toLowerCase())) {
+    return true;
+  }
+  return false;
+}
+
+/**
+ * 从参数中获取所有Promise对象,组成数组并返回
+ * @param  {...any} datas 待解析数据
+ */
+export function getAllPromise (...datas) {
+  let promiseList = [];
+  datas.forEach(it => {
+    if (isDataType(it, "Promise")) {
+      promiseList.push(it);
+      return;
+    }
+    // 是方法则获取执行的结果
+    if (isDataType(it, "Function")) {
+      promiseList.push(...getAllPromise(it()));
+      return;
+    }
+    if (isDataType(it, "Array")) {
+      promiseList.push(...getAllPromise(...it));
+    }
+  });
+  return promiseList;
+}
+
+/**
+ * 获取指定月的天数;传入多个月份,则返回所有月天数之和
+ * @param  {...any} monthList 月份
+ */
+export function getDayCount (...monthList) {
+  let allMonthDay = [31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30];
+  let now = new Date();
+  return flat(monthList).reduce((total, current) => {
+    let m = ~~current;
+    if (m % 12 === -10 || m % 12 === 2) {
+      // 2月份天数单独算
+      let year = now.getFullYear() + ~~(m / 12);
+      let day = year % 4 === 0 ? 29 : 28;
+      return total + day;
+    }
+    if (m < 0) {
+      return total + allMonthDay[12 + m % 12];
+    }
+    return total + allMonthDay[m % 12];
+  }, 0);
+}
+
+/**
+ * Array.flat在app和Trident内核上会报错,重写
+ * @param {Array} list 目标数组
+ */
+export function flat (list) {
+  if (Array.prototype.flat) {
+    return list.flat(Infinity);
+  }
+  let retArr = [];
+  if (!Array.isArray(list)) {
+    throw new Error(`Invalid parameter: type check failed for parameter 'list'. Expected Array, But got ${typeof list} with value ${list}`);
+  }
+  list.forEach(it => {
+    if (!Array.isArray(it)) {
+      retArr.push(it);
+      return;
+    }
+    retArr.push(...flat(it));
+  });
+  return retArr;
+}
+/**
+ * 将数组from组装到数组to中去,存在字段field下
+ * 参数是一个配置对象
+ * @param {Array} from 增量数组
+ * @param {Array} to 最终获得的数组
+ * @param {String} keyFrom 增量数组的键值
+ * @param {String} keyTo 数组to的键值对应数组from中的keyFrom
+ * @param {String} field 保存的字段名
+ */
+export function mixArray ({ from, to, keyFrom, keyTo, field }) {
+  to.forEach(item => {
+    const target = from.find(it => item[keyTo] === it[keyFrom]);
+    item[field] = target;
+  });
+}
+/**
+ * 将数组from组装到数组to中去,存在字段field下
+ * 参数是一个配置对象
+ * @param object owner 调用页this对象
+ * @param {Array} from 增量数组
+ * @param {Array} to 最终获得的数组
+ * @param {String} keyFrom 增量数组的键值
+ * @param {String} keyTo 数组to的键值对应数组from中的keyFrom
+ * @param {String} field 保存的字段名
+ */
+export function mixArray4Page (owner, { from, to, keyFrom, keyTo, field }) {
+  to.forEach(item => {
+    const target = from.find(it => item[keyTo] === it[keyFrom]);
+    owner.$set(item, field, target);
+  });
+}

+ 2 - 6
src/views/Home.vue

@@ -24,11 +24,7 @@ export default {
   },
   mounted() {},
   beforeDestroy() {},
-  watch: {
-    userInfo(val) {
-      console.log(val);
-    },
-  },
+  watch: {},
   computed: {
     ...mapGetters(['userInfo']),
   },
@@ -36,7 +32,7 @@ export default {
     // 初始化数据
     initDataFun() {},
     clickFun() {
-      this.$message.success('1111');
+      this.$store.commit('user/ADD_USERINFO', { name: 'aaaa' });
     },
   },
 };

+ 47 - 0
src/views/login/index.vue

@@ -0,0 +1,47 @@
+<template>
+  <div class="">
+    这里是登录
+    <a-button type="primary" @click="clickFun">Primary</a-button>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'login',
+  props: {},
+  components: {
+    // components: resolve => {
+    //   require([''], resolve)
+    // }
+  },
+  data() {
+    return {};
+  },
+  created() {
+    this.initDataFun(); // 初始化数据
+  },
+  mounted() {},
+  beforeDestroy() {},
+  watch: {},
+  computed: {},
+  methods: {
+    // 初始化数据
+    initDataFun() {},
+    clickFun() {
+      this.$_http
+        .get(this.$_API.JTXT_GET_USER_ADMIN_USERS)
+        .then((res) => {
+          // 自己的操作
+          console.log(res.data[0]);
+        })
+        .catch((res) => {
+          console.log(res);
+        });
+    },
+  },
+};
+</script>
+
+<style lang="less"></style>
+
+<style lang="less" scoped></style>