diff --git a/src/api/audit.js b/src/api/audit.js index 6929042cd07e5214b42071050c69a9a663261d46..c3f994a4c76d074130deefeb42a6b4eda5a65db8 100644 --- a/src/api/audit.js +++ b/src/api/audit.js @@ -1,9 +1,10 @@ -import request from '@/utils/request' - -export function getAuditList(params) { - return request({ - url: '/minisyslog/queryLogByCondition', - method: 'get', - params - }) -} +import request from './config' + +// 获取审计日志列表和系统日志列表 +export function getAuditList(params) { + return request({ + url: '/minisyslog/queryLogByCondition', + method: 'get', + params + }) +} diff --git a/src/utils/request.js b/src/api/config.js similarity index 76% rename from src/utils/request.js rename to src/api/config.js index 9fa5d4dce15bf8ffd7fe00c96752ccae5541cf77..6feb50d576a5c83785675c15de33c467b284e8b1 100644 --- a/src/utils/request.js +++ b/src/api/config.js @@ -1,164 +1,186 @@ -import Vue from 'vue' -import axios from 'axios' -import Qs from 'qs' -import store from '../store' -import router from '../router' -import { NO_NOTIFY_KEY, NO_LOADING_KEY, TOKEN_HEADER_KEY } from './const' -import { refreshToken } from '../api/user' -import { notification } from 'ant-design-vue' - -// 静态全局baseUrl -const serverIp = window.localStorage.getItem('mini_serverIp') -axios.defaults.baseURL = serverIp ? `http://${serverIp}:2122` : process.env.VUE_APP_BASE_API -if (!serverIp) { - let url = process.env.VUE_APP_BASE_API - let ip = url.split(':')[1].slice(2) - localStorage.setItem('mini_serverIp', ip) -} -let $global_loading -let startTime -var delTimeout = 20 * 1000 -var apiTimeout = window.apiTimeout === '' ? delTimeout : window.apiTimeout -const request = axios.create({ - timeout: apiTimeout || delTimeout, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', - loading: 'no' - }, - responseType: 'json' -}) - -// request interceptors -request.interceptors.request.use( - (config) => { - // 如果 headers 里面配置了 loading: no 就不用 loading - if (!config.headers[NO_LOADING_KEY]) { - $global_loading = Vue.prototype.$loading.service({ - lock: true, - text: '加载数据中,请稍候...', - spinner: 'el-icon-loading', - background: 'rgba(0, 0, 0, 0.7)' - }) - startTime = new Date().getTime() - } - // 处理数据 - if (window.routerBase) { - // 防止 url 出现 // - config.url = (window.routerBase + config.url).replace(new RegExp('//', 'gm'), '/') - } - if (config.headers['Content-Type'].indexOf('application/x-www-form-urlencoded') !== -1) { - config.data = Qs.stringify(config.data) - } - config.headers[TOKEN_HEADER_KEY] = store.getters.getToken - return config - }, - (error) => { - return Promise.reject(error) - } -) - -// response interceptors -request.interceptors.response.use( - (response) => { - // 如果 headers 里面配置了 loading: no 就不用 loading - if (!response.config?.headers[NO_LOADING_KEY]) { - const endTime = new Date().getTime() - if (endTime - startTime < 1000) { - setTimeout(() => { - $global_loading && $global_loading.close() - }, 300) - } else { - $global_loading && $global_loading.close() - } - } - // 如果 responseType 是 blob 表示是下载文件 - if (response.request.responseType === 'blob') { - return response.data - } - // 判断返回值,权限等... - const res = response.data - - // 先判断 jwt token 状态 - if (res.code === 800 || res.code === 801) { - return checkJWTToken(res, response) - } - - // 其他情况 - if (res.code !== 200) { - // 如果 headers 里面配置了 tip: no 就不用弹出提示信息 - if (!response.config.headers[NO_NOTIFY_KEY]) { - notification.error({ - message: res.msg, - duration: 2 - }) - } - } - - return res - }, - (error) => { - if (!error.response) { - // NETWORK ERR - $global_loading && $global_loading.close() - notification.error({ - message: '网络错误', - description: '网络开了小差,请检查服务器IP后重试...', - duration: 2 - }) - // for debug - return Promise.reject(error) - } - if (!error.response.config.headers[NO_LOADING_KEY]) { - $global_loading && $global_loading.close() - } - if (!error.response.config.headers[NO_NOTIFY_KEY]) { - const { status, statusText, data } = error.response - if (!status) { - notification.error({ - message: '网络错误', - description: '网络开了小差,请检查服务器IP后重试...', - duration: 2 - }) - } else { - notification.error({ - message: status, - description: (statusText || '') + (data || ''), - duration: 2 - }) - } - } - return Promise.reject(error) - } -) - -function checkJWTToken(res, response) { - // 如果是登录信息失效 - if (res.code === 800 || res.code === 801) { - notification.warn({ - message: res.msg, - // description: response.config.url, - duration: 3 - }) - store.dispatch('logOut').then(() => { - router.push('/login') - location.reload() - }) - return false - } - -} - -function redoRequest(config) { - return new Promise((resolve) => { - Promise.resolve(refreshToken()).then((result) => { - if (result.code === 200) { - store.dispatch('login', result.data) - resolve() - } - }) - }).then(() => { - return request(config) - }) -} - -export default request +import Vue from 'vue' +import axios from 'axios' +import Qs from 'qs' +import store from '../store' +import router from '../router' +import { NO_NOTIFY_KEY, NO_LOADING_KEY, TOKEN_HEADER_KEY } from '../utils/const' +import { refreshToken } from './user' +import { notification } from 'ant-design-vue' + +// 静态全局baseUrl +const serverIp = window.localStorage.getItem('mini_serverIp') +axios.defaults.baseURL = serverIp ? `http://${serverIp}:2124` : process.env.VUE_APP_BASE_API +if (!serverIp) { + let url = process.env.VUE_APP_BASE_API + let ip = url.split(':')[1].slice(2) + localStorage.setItem('mini_serverIp', ip) +} +let $global_loading +let startTime +var delTimeout = 20 * 1000 +var apiTimeout = window.apiTimeout === '' ? delTimeout : window.apiTimeout +const request = axios.create({ + timeout: apiTimeout || delTimeout, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + loading: 'no' + }, + responseType: 'json' +}) + +// 请求拦截器 +request.interceptors.request.use( + (config) => { + // 如果 headers 里面配置了 loading: no 就不用 loading + if (!config.headers[NO_LOADING_KEY]) { + $global_loading = Vue.prototype.$loading.service({ + lock: true, + text: '加载数据中,请稍候...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }) + startTime = new Date().getTime() + } + // 处理数据 + if (window.routerBase) { + // 防止 url 出现 // + config.url = (window.routerBase + config.url).replace(new RegExp('//', 'gm'), '/') + } + if (config.headers['Content-Type'].indexOf('application/x-www-form-urlencoded') !== -1) { + config.data = Qs.stringify(config.data) + } + config.headers[TOKEN_HEADER_KEY] = store.getters.getToken + + // 版本获取时,不带请求头 + if (config.url === '/version') delete config.headers[TOKEN_HEADER_KEY] + + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 +request.interceptors.response.use( + (response) => { + // 如果 headers 里面配置了 loading: no 就不用 loading + if (!response.config?.headers[NO_LOADING_KEY]) { + const endTime = new Date().getTime() + if (endTime - startTime < 1000) { + setTimeout(() => { + $global_loading && $global_loading.close() + }, 300) + } else { + $global_loading && $global_loading.close() + } + } + // 如果 responseType 是 blob 表示是下载文件 + if (response.request.responseType === 'blob') { + return response.data + } + // 判断返回值,权限等... + const res = response.data + + // 先判断 jwt token 状态 + if (res.code === 800 || res.code === 801) { + return checkJWTToken(res, response) + } + + // 其他情况 + if (res.code !== 200) { + // 如果 headers 里面配置了 tip: no或者响应体里没有msg字段 就不用弹出提示信息 + if (!response.config.headers[NO_NOTIFY_KEY] && res.msg) { + notification.error({ + message: res.msg, + // description: response.config.url, + duration: 2 + }) + } + } + + return res + }, + (error) => { + if (!error.response) { + // 网络异常 + $global_loading && $global_loading.close() + notification.error({ + message: '网络错误', + description: '网络开了小差,请检查服务器IP后重试...', + duration: 2 + }) + // for debug + return Promise.reject(error) + } + // 如果 headers 里面配置了 loading: no 就不用 loading + if (!error.response.config.headers[NO_LOADING_KEY]) { + $global_loading && $global_loading.close() + } + // 如果 headers 里面配置了 tip: no 就不用弹出提示信息 + if (!error.response.config.headers[NO_NOTIFY_KEY]) { + const { status, statusText, data } = error.response + if (!status) { + notification.error({ + message: '网络错误', + description: '网络开了小差,请检查服务器IP后重试...', + duration: 2 + }) + } else { + notification.error({ + message: status, + description: (statusText || '') + (data || ''), + duration: 2 + }) + } + } + return Promise.reject(error) + } +) + +// 判断 jwt token 状态 +function checkJWTToken(res, response) { + console.log('checkJWTToken----------', res, res.code) + // 如果是登录信息失效 + if (res.code === 800) { + notification.warn({ + message: res.msg, + // description: response.config.url, + duration: 3 + }) + store.dispatch('logOut').then(() => { + router.push('/login') + location.reload() + }) + return false + } + // 如果 jwt token 还可以续签 + if (res.code === 801) { + notification.close() + notification.info({ + message: '登录信息过期,尝试自动续签...', + description: '如果不需要自动续签,请修改配置文件。该续签将不会影响页面。', + duration: 3 + }) + // 续签且重试请求 + return redoRequest(response.config) + } +} + +// 刷新 jwt token 并且重试上次请求 +function redoRequest(config) { + return new Promise((resolve) => { + Promise.resolve(refreshToken()).then((result) => { + if (result.code === 200) { + // 调用 store action 存储当前登录的用户名和 token + store.dispatch('login', result.data) + resolve() + } + }) + }).then(() => { + // 重试原来的请求 + return request(config) + }) +} + +export default request diff --git a/src/api/install.js b/src/api/install.js index 7af2a05a2652ffd59ca3f57d25d3a4b4991f12f4..7aa66ed5d341a5d0d4cf6c98c6d7de6c9cac3114 100644 --- a/src/api/install.js +++ b/src/api/install.js @@ -1,4 +1,4 @@ -import axios from '@/utils/request' +import axios from './config' export function checkSystem() { return axios({ diff --git a/src/api/menu.js b/src/api/menu.js index 003ab2537ff03b245be178f590a9efa8ae325c36..8df6b8b765ca4292c19753c2e095eea7967fb60b 100644 --- a/src/api/menu.js +++ b/src/api/menu.js @@ -1,4 +1,4 @@ -import request from '@/utils/request' +import request from './config' export function getSystemMenu() { return request({ diff --git a/src/api/node_package.js b/src/api/node_package.js index c692b1392350c8cc44da0beeac686a13d4eba33d..cfbb59c68a2e3ddbf0e328be582af2c882344c82 100644 --- a/src/api/node_package.js +++ b/src/api/node_package.js @@ -1,4 +1,4 @@ -import request from '../utils/request' +import request from './config' // import qs from 'qs' export function addPackageTask(data) { diff --git a/src/api/node_source.js b/src/api/node_source.js index a9ba2687101c2b83b6a1747a9872450bdffb4454..0863e409a163b3f0d36b22280cfb91695ed164c3 100644 --- a/src/api/node_source.js +++ b/src/api/node_source.js @@ -1,4 +1,4 @@ -import request from '../utils/request' +import request from './config' export function getSource(data) { return request({ diff --git a/src/api/user.js b/src/api/user.js index 0ac6b281944c1d31a974a11f43767c043e0f5155..ca432e6bd7e87e93b213e251446aa38eb0165062 100644 --- a/src/api/user.js +++ b/src/api/user.js @@ -1,4 +1,4 @@ -import axios from '../utils/request' +import axios from './config' // login export function login(params) { diff --git a/src/pages/node/list/node-layout/welcome.vue b/src/pages/node/list/node-layout/welcome.vue index 8bb5f2e4ee1f1ebf5d8e4bccb3d34573274fe1bc..9196ffaf6ff232f89cbb60177fef2a1c58ab479f 100644 --- a/src/pages/node/list/node-layout/welcome.vue +++ b/src/pages/node/list/node-layout/welcome.vue @@ -150,11 +150,13 @@ export default { this.tableHeight = (this.$refs.welcome.clientHeight - 144) / 2 await this.loadNodeProcess() this.$nextTick(() => { + this.getScroller() }) }, beforeDestroy() { clearInterval(this.topChartTimer) this.topChart && this.topChart.dispose() + this.cancelScroll() }, methods: { // 初始化页面 @@ -283,6 +285,12 @@ export default { start: this.start, end: this.end } + // 用于X轴坐标范围修改,但是存在问题(会出现资源监控曲线图异常的情况) + // { + // type: 'slider', + // start: this.start, + // end: this.end + // } ], series: series, color: ['#dc3545', '#377bc9', '#E3AA75'] @@ -405,6 +413,75 @@ export default { const start = (pageNum - 1) * pageSize const end = start + pageSize this.processList = this.allProcessList?.slice(start, end) + }, + // 设置监听滚动元素 + getScroller() { + // 获取表格可视区域高度 + let tableBody = document.querySelector('.node-table .ant-table-body') + let lastScrollTop = 0 + // 初始索引 + let start = 0 + let end = 20 + this.scrollListener = throttle(this.handleScroll.bind(null, { + el: tableBody, + lastScrollTop, + start, + end + }), 300) + + tableBody.addEventListener('scroll', this.scrollListener) + }, + handleScroll(opt, e) { + // 滚动进度 + let process = e.target.scrollTop / (opt.el.scrollHeight - opt.el.clientHeight) + + if (e.target.scrollTop < opt.lastScrollTop) { + // 向上滚动 + // 滚动到0%时加载上一页数据,始终渲染20条数据 + if (process === 0) { + // 判断是否还在第一页数据 + if (opt.start === 0 || opt.start < 0 || opt.start - 10 < 0) { + this.processList = this.allProcessList?.slice(0, 20) + opt.start = 0 + opt.end = 20 + } else { + this.processList = this.allProcessList?.slice(opt.start - 10, opt.end - 10) + opt.start -= 10 + opt.end -= 10 + e.target.scrollTop = opt.el.scrollHeight / 2 + } + } + } else if (e.target.scrollTop > opt.lastScrollTop) { + // 向下滚动 + // 滚动到100%时加载下一页数据,始终渲染20条数据 + if (process === 1) { + // 滚动到最后一页 + if (opt.end >= this.allProcessList.length) { + this.processList = this.allProcessList?.slice(opt.start, this.allProcessList.length) + opt.start = this.allProcessList.length - 20 + opt.end = this.allProcessList.length + } else { + this.processList = this.allProcessList?.slice(opt.start + 10, opt.end + 10) + opt.start += 10 + opt.end += 10 + e.target.scrollTop = opt.el.scrollHeight / 2 - opt.el.clientHeight + } + } + } + + // 记录最后一次滚动的位置 + opt.lastScrollTop = e.target.scrollTop + }, + // 取消滚动监听 + cancelScroll() { + try { + // 在使用动态组件components时,会出现先切换组件,再执行beforeDestory;即使is属性发生变化,beforeDestory可能也不会立即执行,组件的销毁和挂载能可会在下一次的dom更新周期中执行 + // 此时切换组件,在beforeDestory获取到的dom为下一个页面的dom,但是当前组件的实例还可以使用,所以使用this获取dom + let tableBody = this.$el.querySelector('.node-table .ant-table-body') + tableBody.removeEventListener('scroll', this.scrollListener) + } catch (error) { + console.warn(error) + } } } }