master
parent
3d2934e04f
commit
1c43b46293
@ -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
|
||||
})
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 740 B |
|
After Width: | Height: | Size: 1.8 KiB |
@ -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)
|
||||
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<card-container>
|
||||
<vxe-toolbar>
|
||||
<template #buttons>
|
||||
<el-button icon="el-icon-search" type="primary" plain size="small" @click="getDatas">搜索</el-button>
|
||||
<el-button icon="el-icon-delete-solid" type="danger" plain size="small" @click="deleteDatas">清除记录</el-button>
|
||||
</template>
|
||||
</vxe-toolbar>
|
||||
<vxe-table
|
||||
ref="table"
|
||||
stripe
|
||||
style="margin-top: 10px;"
|
||||
show-overflow
|
||||
:scroll-y="{ enabled: true, gt: 0 }"
|
||||
:row-config="{isHover: true}"
|
||||
:column-config="{ resizable: true }"
|
||||
:data="datas"
|
||||
max-height="800"
|
||||
>
|
||||
<vxe-column field="id" title="id" width="60" />
|
||||
<vxe-column field="msg" title="信息" min-width="200" show-overflow="title" />
|
||||
<vxe-column field="stack" title="栈" min-width="240" show-overflow="title" />
|
||||
<vxe-column field="data" title="数据" min-width="240" show-overflow="title" :formatter="({ cellValue }) => formatterData(cellValue)" />
|
||||
<vxe-column field="create_at" title="时间" width="220" align="center" />
|
||||
</vxe-table>
|
||||
</card-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ErrorDBManager } from '@/error-handle'
|
||||
const errorDbManager = new ErrorDBManager()
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
datas: []
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getDatas()
|
||||
},
|
||||
methods: {
|
||||
formatterData(data) {
|
||||
try {
|
||||
return JSON.stringify(data)
|
||||
} catch (err) {
|
||||
return data
|
||||
}
|
||||
},
|
||||
getDatas() {
|
||||
errorDbManager.getErrors().then(res => {
|
||||
this.datas = res
|
||||
})
|
||||
},
|
||||
deleteDatas() {
|
||||
errorDbManager.clearError().then(_ => {
|
||||
this.getDatas()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<div>
|
||||
<card-container>
|
||||
<el-button type="primary" icon="el-icon-caret-right" size="small" @click="submit">执行</el-button>
|
||||
<el-input
|
||||
v-model="sql"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3 }"
|
||||
clearable
|
||||
style="margin-top: 10px;"
|
||||
/>
|
||||
<div class="result">
|
||||
<h4>执行结果</h4>
|
||||
<el-input
|
||||
v-model="result"
|
||||
readonly
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 3, maxRows: 10 }"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="history">
|
||||
<h4>历史记录</h4>
|
||||
|
||||
<vxe-toolbar>
|
||||
<template #buttons>
|
||||
<el-button icon="el-icon-search" type="primary" plain size="small" @click="getHistories">搜索</el-button>
|
||||
<el-button icon="el-icon-delete-solid" type="danger" plain size="small" @click="deleteHistories">清除记录</el-button>
|
||||
</template>
|
||||
</vxe-toolbar>
|
||||
<vxe-table
|
||||
ref="table"
|
||||
stripe
|
||||
style="margin-top: 10px;"
|
||||
show-overflow
|
||||
:scroll-y="{ enabled: true, gt: 0 }"
|
||||
:row-config="{isHover: true}"
|
||||
:column-config="{ resizable: true }"
|
||||
:data="histories"
|
||||
max-height="800"
|
||||
>
|
||||
<vxe-column field="id" title="id" width="60" />
|
||||
<vxe-column type="expand" width="60" align="center">
|
||||
<template #content="{ row }">
|
||||
<p style="word-break: break-word;white-space: pre-wrap;">{{ row.result }}</p>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="sql" title="sql" min-width="200" show-overflow="title" />
|
||||
<vxe-column field="result" title="结果" min-width="240" show-overflow="title" :formatter="({ cellValue }) => formatterData(cellValue)" />
|
||||
<vxe-column field="create_at" title="时间" width="220" align="center" />
|
||||
</vxe-table>
|
||||
</div>
|
||||
</card-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { execSql } from '@/api/sql'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
sql: '',
|
||||
result: '',
|
||||
histories: []
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs['table'] && this.$refs['toolbar']) {
|
||||
this.$refs['table'].connect(this.$refs['toolbar'])
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
const request = indexedDB.open('SqlDatabase')
|
||||
request.onsuccess = e => {
|
||||
const db = e.target.result
|
||||
db.close()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatterData(data) {
|
||||
try {
|
||||
return JSON.stringify(data)
|
||||
} catch (err) {
|
||||
return data
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
try {
|
||||
await this.$confirm('确认执行?', '提示')
|
||||
const res = await execSql({
|
||||
sql: this.sql
|
||||
})
|
||||
this.result = JSON.stringify(res)
|
||||
const request = indexedDB.open('SqlDatabase')
|
||||
request.onsuccess = e => {
|
||||
const db = e.target.result
|
||||
const transaction = db.transaction(['SqlLogs'], 'readwrite')
|
||||
const objectStore = transaction.objectStore('SqlLogs')
|
||||
objectStore.add({
|
||||
sql: this.sql,
|
||||
result: res,
|
||||
create_at: this.$moment().format('YYYY-MM-DD HH:mm:ss')
|
||||
})
|
||||
|
||||
this.getHistories()
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
getHistories() {
|
||||
const request = indexedDB.open('SqlDatabase')
|
||||
request.onsuccess = e => {
|
||||
const db = e.target.result
|
||||
const transaction = db.transaction(['SqlLogs'], 'readonly')
|
||||
const objectStore = transaction.objectStore('SqlLogs')
|
||||
const getAllRequest = objectStore.getAll()
|
||||
getAllRequest.onsuccess = (event) => {
|
||||
this.histories = event.target.result
|
||||
}
|
||||
getAllRequest.onerror = (event) => {
|
||||
console.error('获取历史记录失败', event)
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteHistories() {
|
||||
this.$confirm('确认删除?', '提示').then(_ => {
|
||||
const request = indexedDB.open('SqlDatabase')
|
||||
request.onsuccess = e => {
|
||||
const db = e.target.result
|
||||
const transaction = db.transaction(['SqlLogs'], 'readwrite')
|
||||
const objectStore = transaction.objectStore('SqlLogs')
|
||||
const clear = objectStore.clear()
|
||||
clear.onsuccess = e => {
|
||||
this.getHistories()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
init() {
|
||||
if (!indexedDB) {
|
||||
console.log('浏览器不支持indexedDB')
|
||||
}
|
||||
const request = indexedDB.open('SqlDatabase')
|
||||
request.onerror = function(event) {
|
||||
console.log('error', event)
|
||||
}
|
||||
request.onupgradeneeded = e => {
|
||||
const db = e.target.result
|
||||
if (!db.objectStoreNames.contains('SqlLogs')) {
|
||||
const objectStore = db.createObjectStore('SqlLogs', { keyPath: 'id', autoIncrement: true }) // 创建表
|
||||
// 创建索引
|
||||
objectStore.createIndex('sql', 'sql', { unique: false })
|
||||
objectStore.createIndex('result', 'result', { unique: false })
|
||||
objectStore.createIndex('create_at', 'create_at', { unique: false })
|
||||
}
|
||||
}
|
||||
this.getHistories()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.result {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.history {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in new issue