diff --git a/src/api/sql.js b/src/api/sql.js
new file mode 100644
index 0000000..9f32aa8
--- /dev/null
+++ b/src/api/sql.js
@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+export function execSql(data) {
+ return request({
+ method: 'post',
+ url: '/api/backend/user/sql',
+ data,
+ isLoading: true
+ })
+}
diff --git a/src/error-handle.js b/src/error-handle.js
new file mode 100644
index 0000000..486b98f
--- /dev/null
+++ b/src/error-handle.js
@@ -0,0 +1,97 @@
+import Vue from 'vue'
+import { MessageBox } from 'element-ui'
+import moment from 'moment'
+export class ErrorDBManager {
+ db
+ request
+ name = 'Errors'
+ constructor() {
+ this.init()
+ }
+ init() {
+ if (!indexedDB) {
+ console.log('浏览器不支持indexedDB')
+ return
+ }
+ this.request = indexedDB.open('ErrorDatabase')
+ this.request.onerror = function(event) {
+ console.log('error', event)
+ }
+ this.request.onupgradeneeded = e => {
+ this.db = e.target.result
+ if (!this.db.objectStoreNames.contains('Errors')) {
+ const objectStore = this.db.createObjectStore('Errors', { keyPath: 'id', autoIncrement: true }) // 创建表
+ objectStore.createIndex('msg', 'msg', { unique: false })
+ objectStore.createIndex('stack', 'stack', { unique: false })
+ objectStore.createIndex('data', 'data', { unique: false })
+ objectStore.createIndex('create_at', 'create_at', { unique: false })
+ }
+ }
+ this.request.onsuccess = e => {
+ this.db = e.target.result
+ Vue.config.errorHandler = (err, vm, info) => {
+ this.addError(err.message, err.stack)
+ console.error(err)
+ }
+ }
+ }
+ getErrors() {
+ if (!indexedDB) {
+ console.log('浏览器不支持indexedDB')
+ return Promise.reject('浏览器不支持indexedDB')
+ }
+ return new Promise((resolve, reject) => {
+ const transaction = this.db.transaction(['Errors'], 'readonly')
+ const objectStore = transaction.objectStore('Errors')
+ const getAllRequest = objectStore.getAll()
+ getAllRequest.onsuccess = (event) => {
+ resolve(event.target.result)
+ }
+ getAllRequest.onerror = (event) => {
+ reject(event)
+ }
+ })
+ }
+ addError(msg, stack, data = '') {
+ if (!indexedDB) {
+ console.log('浏览器不支持indexedDB')
+ return Promise.reject('浏览器不支持indexedDB')
+ }
+ return new Promise((resolve, reject) => {
+ const transaction = this.db.transaction(['Errors'], 'readwrite')
+ const objectStore = transaction.objectStore('Errors')
+ objectStore.add({
+ msg,
+ stack,
+ data,
+ create_at: moment().format('YYYY-MM-DD HH:mm:ss')
+ })
+ objectStore.onsuccess = e => {
+ resolve(e)
+ }
+ objectStore.onerror = err => {
+ reject(err)
+ }
+ })
+ }
+ clearError() {
+ if (!indexedDB) {
+ console.log('浏览器不支持indexedDB')
+ return Promise.reject('浏览器不支持indexedDB')
+ }
+ return new Promise((resolve, reject) => {
+ MessageBox.confirm('确认删除?', '提示').then(_ => {
+ const transaction = this.db.transaction(['Errors'], 'readwrite')
+ const objectStore = transaction.objectStore('Errors')
+ const clear = objectStore.clear()
+ clear.onsuccess = e => {
+ resolve(e)
+ }
+ clear.onerror = err => {
+ reject(err)
+ }
+ })
+ })
+ }
+}
+
diff --git a/src/icons/svg/database.svg b/src/icons/svg/database.svg
new file mode 100644
index 0000000..6e092f8
--- /dev/null
+++ b/src/icons/svg/database.svg
@@ -0,0 +1 @@
+
diff --git a/src/icons/svg/debugger.svg b/src/icons/svg/debugger.svg
new file mode 100644
index 0000000..2946cb0
--- /dev/null
+++ b/src/icons/svg/debugger.svg
@@ -0,0 +1 @@
+
diff --git a/src/layout/components/Navbar/index.vue b/src/layout/components/Navbar/index.vue
index b1745e1..7d551ec 100644
--- a/src/layout/components/Navbar/index.vue
+++ b/src/layout/components/Navbar/index.vue
@@ -76,6 +76,10 @@
修改密码
+
+
+ 错误日志
+
退出
@@ -265,6 +269,9 @@ export default {
case 'attendance':
this.$router.push('/oa/?to=/attendance')
break
+ case 'debugger':
+ this.$router.push('/error')
+ break
case 'password':
this.$router.push('/info')
break
diff --git a/src/main.js b/src/main.js
index db3ad90..00dddd3 100644
--- a/src/main.js
+++ b/src/main.js
@@ -4,7 +4,7 @@ import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
-//import locale from 'element-ui/lib/locale/lang/en' // lang i18n
+// import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import '@/styles/index.scss' // global css
@@ -14,7 +14,9 @@ import router from './router'
import '@/icons' // icon
import '@/permission' // permission control
-
+import { ErrorDBManager } from '@/error-handle'
+new ErrorDBManager()
+import '@/provide'
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
@@ -69,9 +71,6 @@ Vue.component('CardContainer', CardContainer)
// exec: true,
// });
Vue.config.productionTip = false
-Vue.config.errorHandler = (err, vm, info) => {
- console.error(info, err)
-}
new Vue({
el: '#app',
diff --git a/src/permission.js b/src/permission.js
index 3af3012..dd8c1aa 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -8,7 +8,7 @@ import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
-const whiteList = ['/login','/preview'] // no redirect whitelist
+const whiteList = ['/login', '/preview'] // no redirect whitelist
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
@@ -48,16 +48,23 @@ router.beforeEach(async(to, from, next) => {
}
if (store.state.permission.addRoutes && store.state.permission.addRoutes instanceof Array && store.state.permission.addRoutes.length > 0) {
+ if (to.path === '/sql/index' && store.state.user.name !== '管理员') {
+ next(from.path)
+ return
+ }
next()
} else {
try {
// get user info
- const { roles } = await store.dispatch('user/getInfo')
+ const { roles, username } = await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
-
+ if (to.path === '/sql/index' && username !== '管理员') {
+ next(from.path)
+ return
+ }
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
diff --git a/src/provide.js b/src/provide.js
new file mode 100644
index 0000000..0170145
--- /dev/null
+++ b/src/provide.js
@@ -0,0 +1,10 @@
+import store from '@/store'
+import { ErrorDBManager } from './error-handle'
+
+window._logout = () => {
+ store.dispatch('user/resetToken').then(() => {
+ location.reload()
+ })
+}
+const errorDBManager = new ErrorDBManager()
+window._addError = errorDBManager.addError.bind(errorDBManager)
diff --git a/src/router/index.js b/src/router/index.js
index 355a69d..6160efd 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -47,6 +47,36 @@ export const constantRoutes = [
component: () => import('@/views/preview'),
hidden: true
},
+ {
+ path: '/sql',
+ component: Layout,
+ redirect: '/sql/index',
+ children: [{
+ path: 'index',
+ component: () => import('@/views/sql'),
+ name: '编辑',
+ meta: {
+ title: '编辑',
+ icon: 'database'
+ }
+ }],
+ hidden: true
+ },
+ {
+ path: '/error',
+ component: Layout,
+ redirect: '/error/index',
+ children: [{
+ path: 'index',
+ component: () => import('@/views/error'),
+ name: '错误日志',
+ meta: {
+ title: '错误日志',
+ icon: 'debugger'
+ }
+ }],
+ hidden: true
+ },
{
path: '/',
component: Layout,
diff --git a/src/utils/request.js b/src/utils/request.js
index c4866d9..add8cdf 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -3,8 +3,10 @@ import { MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import { throttle } from '@/utils'
+import { ErrorDBManager } from '@/error-handle'
import Vue from 'vue'
+const errorDBManager = new ErrorDBManager()
let loadingInstance
const loading = throttle(() => {
loadingInstance = Loading.service({
@@ -41,6 +43,7 @@ service.interceptors.request.use(
// do something with request error
console.log(error) // for debug
Vue.prototype.$nextTick().then(r => loadingInstance?.close())
+ errorDBManager.addError(error, 'axios-request', error.config.params || error.config.data)
return Promise.reject(error)
}
)
@@ -89,6 +92,7 @@ service.interceptors.response.use(
})
})
}
+ errorDBManager.addError(res.msg, `axios-response ${response.config.url}`, response.config.params || response.config.data)
return Promise.reject(new Error(res.msg || 'Error'))
} else {
return res.data
@@ -97,13 +101,14 @@ service.interceptors.response.use(
error => {
loadingInstance?.close()
console.error('err' + error) // for debug
- if (!response.config.notShowError) {
+ if (!error.config.notShowError) {
Message({
- message: /Network Error/g.test(error) ? '网络错误' : '系统错误',
+ message: /Network Error/g.test(error) ? "网络错误" : (/timeout/g.test(error) ? "网络超时" : "系统错误"),
type: 'error',
duration: 5 * 1000
})
}
+ errorDBManager.addError(error.toString(), `axios-request ${error.config.url}`, error.config.params || error.config.data)
return Promise.reject(error)
}
)
diff --git a/src/views/dashboard/index.vue b/src/views/dashboard/index.vue
index 5ad69e0..c3ff70b 100644
--- a/src/views/dashboard/index.vue
+++ b/src/views/dashboard/index.vue
@@ -36,6 +36,7 @@
+
+
diff --git a/src/views/sql/index.vue b/src/views/sql/index.vue
new file mode 100644
index 0000000..5a78dc0
--- /dev/null
+++ b/src/views/sql/index.vue
@@ -0,0 +1,177 @@
+
+
+
+ 执行
+
+
+
执行结果
+
+
+
+
历史记录
+
+
+
+ 搜索
+ 清除记录
+
+
+
+
+
+
+ {{ row.result }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/system/components/ModuleAuth.vue b/src/views/system/components/ModuleAuth.vue
index 5ef7f9f..bbf3eb5 100644
--- a/src/views/system/components/ModuleAuth.vue
+++ b/src/views/system/components/ModuleAuth.vue
@@ -4,7 +4,7 @@
title="设置模块权限"
:visible.sync="visible"
direction="rtl"
- size="72%"
+ size="78%"
append-to-body
@close="$emit('update:isShow',false)"
>
@@ -110,15 +110,16 @@
>
-
+
{{ item.name }}
+
-
+
保存
@@ -127,7 +128,7 @@
绑定用户
授权
- 编辑
+ 编辑
删除
@@ -276,7 +277,8 @@ export default {
id: '',
module_id: '',
name: '',
- sortnumber: 0
+ sortnumber: 0,
+ allow_level: 0
},
isShowBindPermissions: false,
diff --git a/src/views/system/components/ModuleAuthAddRole.vue b/src/views/system/components/ModuleAuthAddRole.vue
index b640194..ecf71cc 100644
--- a/src/views/system/components/ModuleAuthAddRole.vue
+++ b/src/views/system/components/ModuleAuthAddRole.vue
@@ -15,6 +15,11 @@
+
+
+
+
+
@@ -45,6 +50,7 @@ export default {
loading: false,
form: {
name: '',
+ allow_level: 0,
sortnumber: 0
},
rules: {
diff --git a/src/views/wujie/index.vue b/src/views/wujie/index.vue
index c216a7a..891c37a 100644
--- a/src/views/wujie/index.vue
+++ b/src/views/wujie/index.vue
@@ -30,7 +30,7 @@