Преглед изворни кода

新增统计管理页面文件,以及鉴权方式更改

刘洋 пре 1 година
родитељ
комит
b57e46acd6

+ 3 - 1
package.json

@@ -26,7 +26,9 @@
     "vue": "^2.6.12",
     "vue-awesome": "^4.1.0",
     "vue-router": "^3.5.1",
-    "vuex": "^3.6.2"
+    "vuex": "^3.6.2",
+    "crypto-js": "^4.1.1",
+    "spark-md5": "^3.0.2"
   },
   "devDependencies": {
     "@babel/core": "^7.12.16",

+ 10 - 0
src/modules/statistics/router/index.js

@@ -0,0 +1,10 @@
+export const menuRoutes = [
+  {
+    path: "/statistics/manage",
+    name: "StatisticManage",
+    component: () =>
+      import(
+        /* webpackChunkName: "statistics" */ "../views/StatisticsManage.vue"
+      ),
+  },
+];

+ 104 - 0
src/modules/statistics/views/StatisticsManage.vue

@@ -0,0 +1,104 @@
+<template>
+  <div class="content statistics-manage">
+    <!-- 正文信息 -->
+    <div class="part-box">
+      <h1 class="part-box-title">统计管理</h1>
+      <!-- 搜索 -->
+      <el-form class="part-filter-form" inline :model="searchForm">
+        <el-form-item label="课程">
+          <el-select
+            v-model="searchForm.courseId"
+            :remote-method="getCoursesList"
+            :loading="courseLoading4Search"
+            remote
+            filterable
+            clearable
+            placeholder="请选择"
+            @clear="getCoursesList('')"
+          >
+            <el-option
+              v-for="item in courseList"
+              :key="item.id"
+              :label="item.name + ' - ' + item.code"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="创建时间" style="width: 460px">
+          <el-date-picker
+            v-model="searchForm.createTime"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            value-format="yyyy-MM-dd"
+            align="right"
+            unlink-panels
+          >
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="danger" @click="handleCurrentChange(1)">
+            查询
+          </el-button>
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action"></div>
+    </div>
+  </div>
+</template>
+<script>
+import { courseQueryApi, cardListApi } from "../../card/api";
+import pickerOptions from "@/constants/datePickerOptions";
+export default {
+  name: "StatisticsManage",
+  data() {
+    return {
+      courseList: [],
+      searchForm: {
+        courseId: "",
+        createTime: [],
+      },
+      courseLoading4Search: false,
+      tableData: [],
+      curRow: {},
+      currentPage: 1,
+      pageSize: 10,
+      total: 10,
+      loading: false,
+      pickerOptions,
+    };
+  },
+  created() {
+    this.getCoursesList();
+  },
+  methods: {
+    async search() {
+      if (this.loading) return;
+      this.loading = true;
+
+      const res = await cardListApi({
+        ...this.searchForm,
+        pageNumber: this.currentPage,
+        pageSize: this.pageSize,
+      }).catch(() => {});
+
+      this.loading = false;
+      if (!res) return;
+
+      this.tableData = res.data.content;
+      this.total = res.data.totalElements;
+    },
+    handleCurrentChange(val) {
+      this.currentPage = val;
+      this.search();
+    },
+    async getCoursesList(query) {
+      this.courseLoading4Search = true;
+      const res = await courseQueryApi(query);
+      this.courseList = res.data || [];
+      this.courseLoading4Search = false;
+    },
+  },
+};
+</script>

+ 41 - 13
src/plugins/axios.js

@@ -3,6 +3,28 @@ import axios from "axios";
 import router from "../router";
 import { loadProgressBar } from "axios-progress-bar";
 import networkInformationHint from "./networkInformationHint.js";
+import { initSyncTime, fetchTime } from "./syncServerTime";
+import { getAuthorization } from "./crypto";
+function setAuth(config) {
+  let userSession = sessionStorage.getItem("user");
+  console.log("userSession", userSession);
+  if (userSession && !config.noAuth) {
+    let user = JSON.parse(userSession);
+    const timestamp = fetchTime();
+    const authorization = getAuthorization(
+      {
+        method: config.method,
+        uri: config.url.split("?")[0].trim(),
+        timestamp,
+        sessionId: user.sessionId,
+        token: user.accessToken,
+      },
+      "token"
+    );
+    config.headers["Authorization"] = authorization;
+    config.headers["time"] = timestamp;
+  }
+}
 
 const ERROR_MSG_CONFIG = require("./errorMsgConfig").default;
 
@@ -35,7 +57,7 @@ const noauthUrls = [
  * 4. logout to /login, before send request, invalidate wk_token
  * */
 
-let wk_token, wk_key;
+let wk_token;
 let wk_orgId;
 
 function getRootOrgId() {
@@ -58,6 +80,7 @@ function returnLogin() {
 
 _$httpWith500Msg.interceptors.request.use(
   function (config) {
+    setAuth(config);
     networkInformationHint();
     // Do something before request is sent
     if (!noauthUrls.some((url) => config.url.includes(url))) {
@@ -83,13 +106,13 @@ _$httpWith500Msg.interceptors.request.use(
           }
           return;
         }
-        wk_token = user.token;
-        wk_key = user.key;
+        // wk_token = user.token;
+        // wk_key = user.key;
         wk_orgId = user.rootOrgId;
       }
       if (wk_token && config.headers.common["token"] == null) {
-        config.headers.common["token"] = wk_token;
-        config.headers.common["key"] = wk_key;
+        // config.headers.common["token"] = wk_token;
+        // config.headers.common["key"] = wk_key;
       }
     } else {
       wk_token = null;
@@ -110,6 +133,7 @@ _$httpWith500Msg.interceptors.request.use(
 _$http.interceptors.request.use(
   // no auto 500 error UI
   function (config) {
+    setAuth(config);
     networkInformationHint();
     // Do something before request is sent
     if (!noauthUrls.some((url) => config.url.includes(url))) {
@@ -130,13 +154,13 @@ _$http.interceptors.request.use(
           }
           return;
         }
-        wk_token = user.token;
-        wk_key = user.key;
+        // wk_token = user.token;
+        // wk_key = user.key;
         wk_orgId = user.rootOrgId;
       }
       if (wk_token && config.headers.common["token"] == null) {
-        config.headers.common["token"] = wk_token;
-        config.headers.common["key"] = wk_key;
+        // config.headers.common["token"] = wk_token;
+        // config.headers.common["key"] = wk_key;
       }
     } else {
       wk_token = null;
@@ -178,6 +202,7 @@ const recordRequest = () => {
 // Add a response interceptor
 _$httpWith500Msg.interceptors.response.use(
   (response) => {
+    initSyncTime(new Date(response.headers.date).getTime());
     recordRequest(response);
     return response;
   },
@@ -270,6 +295,7 @@ _$httpWith500Msg.interceptors.response.use(
 _$http.interceptors.response.use(
   // no auto 500 error UI
   (response) => {
+    initSyncTime(new Date(response.headers.date).getTime());
     recordRequest(response);
     return response;
   },
@@ -333,6 +359,7 @@ _$http.interceptors.response.use(
 _$httpWithoutBar.interceptors.request.use(
   // no auto 500 error UI
   function (config) {
+    setAuth(config);
     networkInformationHint();
     // Do something before request is sent
     if (!noauthUrls.some((url) => config.url.includes(url))) {
@@ -353,13 +380,13 @@ _$httpWithoutBar.interceptors.request.use(
           }
           return;
         }
-        wk_token = user.token;
-        wk_key = user.key;
+        // wk_token = user.token;
+        // wk_key = user.key;
         wk_orgId = user.rootOrgId;
       }
       if (wk_token && config.headers.common["token"] == null) {
-        config.headers.common["token"] = wk_token;
-        config.headers.common["key"] = wk_key;
+        // config.headers.common["token"] = wk_token;
+        // config.headers.common["key"] = wk_key;
       }
     } else {
       wk_token = null;
@@ -379,6 +406,7 @@ _$httpWithoutBar.interceptors.request.use(
 _$httpWithoutBar.interceptors.response.use(
   // no auto 500 error UI
   (response) => {
+    initSyncTime(new Date(response.headers.date).getTime());
     recordRequest(response);
     return response;
   },

+ 91 - 0
src/plugins/crypto.js

@@ -0,0 +1,91 @@
+// const CryptoJS = require('crypto-js');
+import Base64 from "crypto-js/enc-base64";
+import Utf8 from "crypto-js/enc-utf8";
+import AES from "crypto-js/aes";
+import SHA1 from "crypto-js/sha1";
+import MD5 from "crypto-js/md5";
+import SparkMD5 from "spark-md5";
+
+export const getBase64 = (content) => {
+  const words = Utf8.parse(content);
+  const base64Str = Base64.stringify(words);
+
+  return base64Str;
+};
+
+export const getAES = (content) => {
+  const KEY = "1234567890123456";
+  const IV = "1234567890123456";
+
+  var key = Utf8.parse(KEY);
+  var iv = Utf8.parse(IV);
+  var encrypted = AES.encrypt(content, key, { iv: iv });
+  return encrypted.toString();
+};
+
+/**
+ * 获取authorisation
+ * @param {Object} infos 相关信息
+ * @param {String} type 类别:secret、token两种
+ */
+export const getAuthorization = (infos, type) => {
+  // {type} {invoker}:base64(sha1(method&uri&timestamp&{secret}))
+  if (type === "secret") {
+    // accessKey | method&uri&timestamp&accessSecret
+    const str = `${infos.method.toLowerCase()}&${infos.uri}&${
+      infos.timestamp
+    }&${infos.accessSecret}`;
+    const sign = Base64.stringify(SHA1(str));
+    return `Secret ${infos.accessKey}:${sign}`;
+  } else if (type === "token") {
+    // userId | method&uri&timestamp&token
+    const str = `${infos.method.toLowerCase()}&${infos.uri}&${
+      infos.timestamp
+    }&${infos.token}`;
+    const sign = Base64.stringify(SHA1(str));
+    return `Token ${infos.sessionId}:${sign}`;
+  }
+};
+
+/**
+ *
+ * @param {any} str 字符串
+ */
+export const getMD5 = (content) => {
+  return MD5(content);
+};
+
+// export const getFileMD5 = (file) => {
+//   return new Promise((resolve, reject) => {
+//     const reader = new FileReader();
+//     reader.onloadend = function () {
+//       const arrayBuffer = reader.result;
+//       resolve(MD5(arrayBuffer).toString());
+//     };
+//     reader.onerror = function (err) {
+//       reject(err);
+//     };
+//     reader.readAsArrayBuffer(file);
+//   });
+// };
+
+export const getFileMD5 = (dataFile) => {
+  return new Promise((rs, rj) => {
+    var fileReader = new FileReader();
+    var spark = new SparkMD5(); //创建md5对象(基于SparkMD5)
+    if (dataFile.size > 1024 * 1024 * 10) {
+      var data1 = dataFile.slice(0, 1024 * 1024 * 10); //将文件进行分块 file.slice(start,length)
+      fileReader.readAsBinaryString(data1); //将文件读取为二进制码
+    } else {
+      fileReader.readAsBinaryString(dataFile);
+    }
+    fileReader.onload = function (e) {
+      spark.appendBinary(e.target.result);
+      var md5 = spark.end();
+      rs(md5);
+    };
+    fileReader.onerror = function (err) {
+      rj(err);
+    };
+  });
+};

+ 28 - 0
src/plugins/syncServerTime.js

@@ -0,0 +1,28 @@
+let initLocalTime = null;
+let initServerTime = null;
+
+function getStorgeTime() {
+  const st = localStorage.getItem("st");
+  const unvalidVals = ["Infinity", "NaN", "null", "undefined"];
+  if (unvalidVals.includes(st + "")) {
+    return [Date.now(), Date.now()];
+  } else {
+    const [s, t] = st.split("_");
+    return [s * 1, t * 1];
+  }
+}
+
+const [serverTime, localTime] = getStorgeTime();
+initSyncTime(serverTime, localTime);
+
+function initSyncTime(serverTime, localTime = Date.now()) {
+  initLocalTime = localTime;
+  initServerTime = serverTime;
+  localStorage.setItem("st", `${initServerTime}_${initLocalTime}`);
+}
+
+function fetchTime() {
+  return Date.now() + initServerTime - initLocalTime;
+}
+
+export { initSyncTime, fetchTime };

+ 8 - 1
src/router/index.js

@@ -16,6 +16,8 @@ import {
   otherRoutes as potherRoutes,
 } from "../modules/paper-export/router";
 
+import { menuRoutes as statisticsMenuRoutes } from "../modules/statistics/router";
+
 // ignore NavigationDuplicated. https://github.com/vuejs/vue-router/issues/2881
 // const originalPush = Router.prototype.push;
 // Router.prototype.push = function push(location, onResolve, onReject) {
@@ -39,7 +41,12 @@ let router = new Router({
       path: "/home", //首页
       meta: { auth: false },
       component: Home,
-      children: [...qmenuRoutes, ...cmenuRoutes, ...pmenuRoutes],
+      children: [
+        ...qmenuRoutes,
+        ...cmenuRoutes,
+        ...pmenuRoutes,
+        ...statisticsMenuRoutes,
+      ],
     },
     ...qotherRoutes,
     ...cotherRoutes,

+ 10 - 0
yarn.lock

@@ -2515,6 +2515,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
     shebang-command "^2.0.0"
     which "^2.0.1"
 
+crypto-js@^4.1.1:
+  version "4.2.0"
+  resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
+  integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
+
 css-declaration-sorter@^6.3.1:
   version "6.4.0"
   resolved "https://registry.npmmirror.com/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz#630618adc21724484b3e9505bce812def44000ad"
@@ -5592,6 +5597,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
   resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
   integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
 
+spark-md5@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.npmmirror.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc"
+  integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==
+
 spdx-correct@^3.0.0:
   version "3.2.0"
   resolved "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"