Merge branch 'feature/error-collection' into develop

# Conflicts:
#	src/layout/header-aside/components/contextmenu/components/contentmenuList/index.vue


Former-commit-id: a16df8b09110f3deec7c33dae7aed5599b8c3862 [formerly 5c7bca544286ef7a358983d233e9896b2ca6da7a] [formerly a16df8b09110f3deec7c33dae7aed5599b8c3862 [formerly 5c7bca544286ef7a358983d233e9896b2ca6da7a] [formerly a16df8b09110f3deec7c33dae7aed5599b8c3862 [formerly 5c7bca544286ef7a358983d233e9896b2ca6da7a] [formerly 5c7bca544286ef7a358983d233e9896b2ca6da7a [formerly 1f27799438509890c390866f6a08350b69784203 [formerly 56c0f3b550c89c0d0b9e363e157533c1e88b1b8a]]]]]
Former-commit-id: 8a1b5fba72c1e99b10e3051ace49ff669e195b11
Former-commit-id: 658e36a5af1185c8ab28c37824d4b7f8439ae71a
Former-commit-id: 3e0ae29967cd9cd24d183ec4efd5ed5f820917e9 [formerly 0d1450a0f05f903a57ede770c1dc3a9e0ec710d2]
Former-commit-id: 8a6020f844a854d6e4765e53c9477a9eabf061d1
Former-commit-id: 0dff2e0795f8025ca961e18b1c2fcd65dc9e3bc3
Former-commit-id: 02294aee8f5ae27ece66ff3dabf27a65258e1f3c
Former-commit-id: a66c0fe86850814ca44800db473687ec3f4705b2
Former-commit-id: 75ec5153bc6a9227404abda6b88f74355289ac85
This commit is contained in:
liyang
2018-08-07 16:08:25 +08:00
18 changed files with 482 additions and 36 deletions

View File

@@ -1,5 +1,9 @@
# 更新日志
## v1.1.6
* [ 新增 ] 新增加了多页控制组件 tab 按钮上的右键操作菜单,现在你可以在 D2Admin 中像使用浏览器一样操作多标签页
## v1.1.5
* [ 修改 ] vue-cli3 项目重构,目录调整

View File

@@ -22,10 +22,12 @@
"echarts": "^4.1.0",
"element-ui": "^2.4.4",
"file-saver": "^1.3.3",
"flex.css": "^1.1.7",
"github-markdown-css": "^2.10.0",
"highlight.js": "^9.12.0",
"js-cookie": "^2.2.0",
"lodash.clonedeep": "^4.5.0",
"lodash.get": "^4.4.2",
"lodash.sortby": "^4.7.0",
"lodash.uniqueid": "^4.0.1",
"lowdb": "^1.0.0",
@@ -46,8 +48,7 @@
"vue-router": "^3.0.1",
"vue-splitpane": "^1.0.2",
"vuex": "^3.0.1",
"xlsx": "^0.12.0",
"flex.css": "^1.1.7"
"xlsx": "^0.12.0"
},
"devDependencies": {
"@kazupon/vue-i18n-loader": "^0.3.0",

View File

@@ -0,0 +1,30 @@
<template>
<div
class="d2-error-log-list__expand"
:class="className">
<p class="d2-error-log-list__expand-title">{{title}}</p>
<p class="d2-error-log-list__expand-value">{{value === '' ? '无数据' : value}}</p>
<slot/>
</div>
</template>
<script>
export default {
props: {
type: {
default: 'log'
},
title: {
default: ''
},
value: {
default: ''
}
},
computed: {
className () {
return this.type === 'log' ? 'd2-error-log-list__expand--log' : 'd2-error-log-list__expand--error'
}
}
}
</script>

View File

@@ -0,0 +1,195 @@
<template>
<el-table
:data="logReverse"
border
stripe
style="width: 100%"
size="mini">
<el-table-column type="expand">
<div slot-scope="props" class="d2-error-log-list__expand-group">
<expand-item
:type="props.row.type"
title="类型"
:value="props.row.type === 'log' ? '日志' : '异常'"/>
<expand-item
:type="props.row.type"
title="内容"
:value="props.row.info"/>
<expand-item
v-if="props.row.type === 'error'"
type="error"
title="报错组件"
:value="get(props.row.vm, '$vnode.tag', '')"/>
<expand-item
v-if="props.row.type === 'error'"
type="error"
title="错误名称"
:value="get(props.row.err, 'name', '')"/>
<expand-item
v-if="props.row.type === 'error'"
type="error"
title="错误信息"
:value="get(props.row.err, 'message', '')"/>
<expand-item
v-if="props.row.type === 'error'"
type="error"
title="错误堆栈"
value="见下">
<div style="overflow: auto;">
<pre>{{stackBeautify(props.row.err)}}</pre>
</div>
</expand-item>
<expand-item
:type="props.row.type"
title="用户名"
:value="get(props.row.user, 'name', '')"/>
<expand-item
:type="props.row.type"
title="uuid"
:value="props.row.uuid"/>
<expand-item
:type="props.row.type"
title="token"
:value="props.row.token"/>
<expand-item
:type="props.row.type"
title="页面地址"
:value="props.row.url"/>
<expand-item
:type="props.row.type"
title="时间"
:value="props.row.time"/>
</div>
</el-table-column>
<el-table-column
prop="type"
label="类型"
width="80px"
align="center"
:filters="[
{ text: '日志', value: 'log' },
{ text: '异常', value: 'error' }
]"
:filter-multiple="false"
:filter-method="filterType"
filter-placement="bottom">
<template slot-scope="scope">
<el-tag
v-if="scope.row.type === 'error'"
size="mini"
type="danger">
<d2-icon name="bug"/> Bug
</el-tag>
<el-tag
v-else
size="mini"
type="info">
<d2-icon name="dot-circle-o"/> Log
</el-tag>
</template>
</el-table-column>
<el-table-column
label="地址"
prop="url"
width="140px"
:show-overflow-tooltip="true">
</el-table-column>
<el-table-column
label="内容"
prop="info"
:show-overflow-tooltip="true">
</el-table-column>
<el-table-column
label="错误类型"
width="140px"
:show-overflow-tooltip="true">
<template
slot-scope="scope">
{{get(scope.row.err, 'name', '')}}
</template>
</el-table-column>
<el-table-column
label="错误信息"
width="140px">
<template
slot-scope="scope">
{{get(scope.row.err, 'message', '')}}
</template>
</el-table-column>
</el-table>
</template>
<script>
import { mapState } from 'vuex'
import get from 'lodash.get'
import ExpandItem from './components/ExpandItem'
export default {
name: 'd2-error-log-list',
components: {
ExpandItem
},
computed: {
...mapState({
log: state => state.d2admin.log
}),
logReverse () {
// 直接 reverse 的话有点问题
const res = []
const loglength = this.log.length
this.log.forEach((log, index) => {
res.push(this.log[loglength - 1 - index])
})
return res
}
},
methods: {
get,
filterType (value, row) {
return row.type === value
},
stackBeautify (err) {
if (!err) {
return ''
}
return err.stack
}
}
}
</script>
<style lang="scss">
@import '~@/assets/style/public.scss';
.d2-error-log-list__expand-group {
.d2-error-log-list__expand {
padding-left: 20px;
margin-bottom: 10px;
&:last-child {
margin-bottom: 0px;
}
.d2-error-log-list__expand-title {
font-size: 16px;
font-weight: bold;
margin-top: 0px;
margin-bottom: 10px;
}
.d2-error-log-list__expand-value {
font-size: 12px;
margin-top: 0px;
margin-bottom: 0px;
}
}
.d2-error-log-list__expand--log {
border-left: 4px solid $color-info;
}
.d2-error-log-list__expand--error {
border-left: 4px solid $color-danger;
}
}
</style>

View File

@@ -16,6 +16,7 @@ Vue.component('d2-container', d2Container)
Vue.component('d2-link-btn', d2LinkBtn)
Vue.component('d2-page-cover', () => import('./d2-page-cover'))
Vue.component('d2-count-up', () => import('./d2-count-up'))
Vue.component('d2-error-log-list', () => import('./d2-error-log-list'))
Vue.component('d2-highlight', () => import('./d2-highlight'))
Vue.component('d2-icon', () => import('./d2-icon'))
Vue.component('d2-icon-select', () => import('./d2-icon-select/index.vue'))

View File

@@ -32,17 +32,10 @@ export default {
methods: {
rowClick (event) {
let target = event.target
try {
let count = 0
while (!target.dataset.value && count < 6) {
target = target.parentNode
count++
}
this.$emit('rowClick', target.dataset.value)
} catch (error) {
// 不做任何处理
console.log(error)
while (!target.dataset.value) {
target = target.parentNode
}
this.$emit('rowClick', target.dataset.value)
}
}
}

View File

@@ -0,0 +1,65 @@
<template>
<div>
<el-tooltip
effect="dark"
:content="tooltipContent"
placement="bottom">
<el-button
class="d2-ml-0 d2-mr btn-text can-hover"
type="text"
@click="handleClick">
<el-badge
v-if="d2adminLogLength > 0"
:max="99"
:value="d2adminLogErrorLength"
:is-dot="d2adminLogErrorLength === 0">
<d2-icon
:name="d2adminLogErrorLength === 0 ? 'dot-circle-o' : 'bug'"
style="font-size: 20px"/>
</el-badge>
<d2-icon
v-else
name="dot-circle-o"
style="font-size: 20px"/>
</el-button>
</el-tooltip>
<el-dialog
:title="tooltipContent"
:fullscreen="true"
:visible.sync="dialogVisible"
:append-to-body="true">
<d2-error-log-list/>
</el-dialog>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data () {
return {
dialogVisible: false
}
},
computed: {
...mapGetters([
'd2adminLogLength',
'd2adminLogErrorLength'
]),
tooltipContent () {
return this.d2adminLogLength === 0
? '没有日志或异常'
: `${this.d2adminLogLength} 条日志${this.d2adminLogErrorLength > 0
? ` | 包含 ${this.d2adminLogErrorLength} 个异常`
: ''}`
}
},
methods: {
handleClick () {
if (this.d2adminLogLength > 0) {
this.dialogVisible = true
}
}
}
}
</script>

View File

@@ -5,7 +5,11 @@
<d2-icon name="question-circle" style="font-size: 20px"/>
</el-button>
</el-tooltip>
<el-dialog title="帮助" width="600px" :visible.sync="dialogVisible">
<el-dialog
title="帮助"
width="600px"
:visible.sync="dialogVisible"
:append-to-body="true">
<div style="margin-top: -25px; margin-bottom: -25px;">
<el-button-group class="d2-mb">
<el-button @click="$open('https://github.com/d2-projects/d2-admin')">

View File

@@ -19,6 +19,8 @@
<d2-menu-header/>
<!-- 顶栏右侧 -->
<div class="d2-header-right">
<!-- 如果你只想在开发环境显示这个按钮请添加 v-if="$env === 'development'" -->
<d2-header-error-log/>
<d2-header-help/>
<d2-header-fullscreen/>
<d2-header-theme/>
@@ -55,23 +57,17 @@
<script>
import { mapState, mapGetters, mapMutations } from 'vuex'
import menuSide from './components/menu-side'
import menuHeader from './components/menu-header'
import tabs from './components/tabs'
import headerFullscreen from './components/header-fullscreen'
import headerTheme from './components/header-theme'
import headerUser from './components/header-user'
import headerHelp from './components/header-help'
export default {
name: 'd2-layout-header-aside',
components: {
'd2-menu-side': menuSide,
'd2-menu-header': menuHeader,
'd2-tabs': tabs,
'd2-header-fullscreen': headerFullscreen,
'd2-header-theme': headerTheme,
'd2-header-user': headerUser,
'd2-header-help': headerHelp
'd2-menu-side': () => import('./components/menu-side'),
'd2-menu-header': () => import('./components/menu-header'),
'd2-tabs': () => import('./components/tabs'),
'd2-header-fullscreen': () => import('./components/header-fullscreen'),
'd2-header-theme': () => import('./components/header-theme'),
'd2-header-user': () => import('./components/header-user'),
'd2-header-help': () => import('./components/header-help'),
'd2-header-error-log': () => import('./components/header-error-log')
},
data () {
return {

View File

@@ -5,7 +5,8 @@ import UaParser from 'ua-parser-js'
import { version } from '../../package.json'
let util = {
cookies: {}
cookies: {},
log: {}
}
/**
@@ -73,20 +74,76 @@ util.isOneOf = function (ele, targetArr) {
}
}
/**
* @description 返回这个样式的颜色值
* @param {String} type 样式名称 [ primary | success | warning | danger | text ]
*/
util.typeColor = function (type = 'default') {
let color = ''
switch (type) {
case 'default': color = '35495E'; break
case 'primary': color = '#3488ff'; break
case 'success': color = '#43B883'; break
case 'warning': color = '#e6a23c'; break
case 'danger': color = '#f56c6c'; break
default:; break
}
return color
}
/**
* @description 打印一个 “胶囊” 样式的信息
* @param {String} title title text
* @param {String} info info text
* @param {String} type style
*/
util.logCapsule = function (title, info) {
util.log.capsule = function (title, info, type = 'primary') {
console.log(
`%c ${title} %c ${info} %c`,
'background:#29384b; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
'background:#3488ff; padding: 1px; border-radius: 0 3px 3px 0; color: #fff',
'background:#35495E; padding: 1px; border-radius: 3px 0 0 3px; color: #fff;',
`background:${util.typeColor(type)}; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;`,
'background:transparent'
)
}
/**
* @description 打印彩色文字
*/
util.log.colorful = function (textArr) {
console.log(
`%c ${textArr.map(t => t.text).join(' %c ')}`,
...textArr.map(t => `color: ${util.typeColor(t.type)};`)
)
}
/**
* @description 打印 primary 样式的文字
*/
util.log.primary = function (text) {
util.log.colorful([{ text, type: 'primary' }])
}
/**
* @description 打印 success 样式的文字
*/
util.log.success = function (text) {
util.log.colorful([{ text, type: 'success' }])
}
/**
* @description 打印 warning 样式的文字
*/
util.log.warning = function (text) {
util.log.colorful([{ text, type: 'warning' }])
}
/**
* @description 打印 danger 样式的文字
*/
util.log.danger = function (text) {
util.log.colorful([{ text, type: 'danger' }])
}
/**
* @description 检查版本更新
* @param {Object} vm vue
@@ -100,7 +157,7 @@ util.checkUpdate = function (vm) {
let versionGet = res.tag_name
const update = semver.lt(version, versionGet)
if (update) {
util.logCapsule('D2Admin', `New version ${res.name}`)
util.log.capsule('D2Admin', `New version ${res.name}`)
console.log(`版本号: ${res.tag_name} | 详情${res.html_url}`)
vm.$store.commit('d2adminReleasesUpdateSet', true)
}
@@ -115,7 +172,7 @@ util.checkUpdate = function (vm) {
* @description 显示版本信息
*/
util.showInfo = function showInfo () {
util.logCapsule('D2Admin', `v${version}`)
util.log.capsule('D2Admin', `v${version}`)
console.log('Github https://github.com/d2-projects/d2-admin')
console.log('Doc http://d2admin.fairyever.com/zh/')
}

View File

@@ -15,8 +15,10 @@ import util from '@/libs/util.js'
import store from '@/store/index'
import '@/assets/svg-icons'
import '@/components'
import '@/plugin/axios'
import '@/mock/register'
import '@/plugin/axios'
import pluginLog from '@/plugin/log'
import pluginError from '@/plugin/error'
import pluginImport from '@/plugin/import'
import pluginExport from '@/plugin/export'
import pluginOpen from '@/plugin/open'
@@ -29,6 +31,8 @@ import { frameInRoutes } from '@/router/routes'
Vue.use(ElementUI)
Vue.use(VCharts)
Vue.use(contentmenu)
Vue.use(pluginLog)
Vue.use(pluginError)
Vue.use(pluginImport)
Vue.use(pluginExport)
Vue.use(pluginOpen)

View File

@@ -45,6 +45,15 @@ export default {
{ path: `${pre}db/public`, title: '公用数据', icon: 'users' }
]
},
{
path: `${pre}log`,
title: '日志',
icon: 'bullseye',
children: [
{ path: `${pre}log/log`, title: '日志记录', icon: 'dot-circle-o' },
{ path: `${pre}log/error`, title: '错误捕捉', icon: 'bug' }
]
},
{ path: `${pre}env`, title: '环境信息', icon: 'exclamation-circle' }
])('/demo/playground/')
}

View File

@@ -0,0 +1,17 @@
<template>
<d2-container>
<template slot="header">捕获错误信息</template>
<p class="d2-mt-0">请打开浏览器控制台然后点击下面的按钮</p>
<el-button type="danger" @click="handleNewError">触发一个错误</el-button>
</d2-container>
</template>
<script>
export default {
methods: {
handleNewError () {
console.log(a) // eslint-disable-line
}
}
}
</script>

View File

@@ -0,0 +1,27 @@
<template>
<d2-container>
<template slot="header">记录日志内容</template>
<p class="d2-mt-0">在下方输入你要记录的日志然后点击记录按钮</p>
<el-input
v-model="text"
placeholder="日志内容"
class="d2-mr-10"
style="width: 200px;"/>
<el-button type="primary" @click="handleAdd">记录</el-button>
</d2-container>
</template>
<script>
export default {
data () {
return {
text: 'D2Admin log info'
}
},
methods: {
handleAdd () {
this.$logAdd(this.text)
}
}
}
</script>

27
src/plugin/error/index.js Normal file
View File

@@ -0,0 +1,27 @@
import store from '@/store'
import util from '@/libs/util'
export default {
install (Vue, options) {
Vue.config.errorHandler = function (err, vm, info) {
Vue.nextTick(() => {
store.commit('d2adminLogAdd', {
type: 'error',
err,
vm,
info
})
// 只在开发模式下打印 log
if (process.env.NODE_ENV === 'development') {
util.log.capsule('D2Admin', 'ErrorHandler', 'danger')
util.log.danger('>>>>>> 错误信息 >>>>>>')
console.log(info)
util.log.danger('>>>>>> Vue 实例 >>>>>>')
console.log(vm)
util.log.danger('>>>>>> Error >>>>>>')
console.log(err)
}
})
}
}
}

16
src/plugin/log/index.js Normal file
View File

@@ -0,0 +1,16 @@
import store from '@/store'
import util from '@/libs/util'
export default {
install (Vue, options) {
// 快速打印 log
Vue.prototype.$log = util.log
// 快速记录日志
Vue.prototype.$logAdd = function (info) {
store.commit('d2adminLogAdd', {
type: 'log',
info
})
}
}
}

View File

@@ -1 +1 @@
b3aa52d67ec41a212ff824829e2d713f2c21111c
ca12a11b6d9d0552250eb2da1e7bac555902f68d

View File

@@ -1 +1 @@
f6b747b5dbf484da5c8b5876c9d54212c90c3550
082feab1bf6e53d7b8e4b5ec8fc6e0198453af65