NEZ-3174 feat:notebook 页面开发

This commit is contained in:
zyh
2023-09-20 18:19:32 +08:00
parent 600fa76954
commit 2d38b5b632
11 changed files with 142 additions and 79 deletions

View File

@@ -18,6 +18,14 @@
background: $--color-primary; background: $--color-primary;
border: none; border: none;
} }
.notebook-datasource-tab{
.el-tabs__nav{
width: 100%;
> div{
width: 33.33%;
}
}
}
} }
.right-box__container{ .right-box__container{
.chart-config{ .chart-config{

View File

@@ -108,13 +108,14 @@
box-sizing: border-box; box-sizing: border-box;
height: 100%; height: 100%;
padding: 10px; padding: 10px;
padding-top: 0;
.markdownEditor { .markdownEditor {
height: 100% !important; height: 100% !important;
} }
.notebook-editor-btn{ .notebook-editor-btn{
height: 41px; height: 41px;
position: absolute; position: absolute;
top: 10px; top: 0px;
right: 20px; right: 20px;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="mt-10 rich-text-container" v-cloak style="height: 100%;width: 100%;"> <div class="mt-10 rich-text-container" v-cloak style="height: 100%;width: 100%;">
<div class="notebook-editor" v-if="from==='notebook'&&chartInfo.param.isEdit" > <div class="notebook-editor" v-if="from==='notebook'&&chartInfo.param.isEdit" >
<markdownEditor :edit-data="chartInfo.param.text" @textChange="textChange"></markdownEditor> <markdownEditor :edit-data="text" @textChange="textChange"></markdownEditor>
<div class="notebook-editor-btn"> <div class="notebook-editor-btn">
<button class="nz-btn nz-btn-size-normal nz-btn-style-light margin-r-10" @click="cancel"> <button class="nz-btn nz-btn-size-normal nz-btn-style-light margin-r-10" @click="cancel">
<span>{{$t('overall.cancel')}}</span> <span>{{$t('overall.cancel')}}</span>
@@ -37,19 +37,24 @@ export default {
text: '' text: ''
} }
}, },
created () {
if (this.from === 'notebook') {
this.chartInfo.param.oldText = this.text
}
},
methods: { methods: {
save () { save () {
this.chartInfo.param.oldText = this.chartInfo.param.text
this.chartInfo.param.isEdit = false this.chartInfo.param.isEdit = false
}, },
cancel () { cancel () {
this.chartInfo.param.text = this.chartInfo.param.oldText
this.chartInfo.param.isEdit = false this.chartInfo.param.isEdit = false
}, },
textChange (val) { textChange (val) {
console.log(val) this.chartInfo.param.text = val
}, },
resize () { resize () {}
}
}, },
watch: { watch: {
chartInfo: { chartInfo: {

View File

@@ -1,3 +1,4 @@
import bus from '@/libs/bus'
export default { export default {
props: { props: {
chartInfo: Object, chartInfo: Object,
@@ -51,6 +52,10 @@ export default {
this.$emit('refresh') this.$emit('refresh')
}, },
editChart () { editChart () {
if (this.chartInfo.type === 'text' && this.from === 'notebook') {
this.$set(this.chartInfo.param, 'isEdit', true)
return
}
// this.$emit('edit-chart', this.chartInfo) // this.$emit('edit-chart', this.chartInfo)
this.$store.dispatch('dispatchEditChart', { this.$store.dispatch('dispatchEditChart', {
chart: this.chartInfo, chart: this.chartInfo,
@@ -66,6 +71,10 @@ export default {
this.dropdownMenuShow = false this.dropdownMenuShow = false
}, },
duplicate () { duplicate () {
if (this.chartInfo.type === 'text' && this.from === 'notebook') {
bus.$emit('copyChartText', this.chartInfo)
return
}
const obj = this.$lodash.cloneDeep(this.chartInfo) const obj = this.$lodash.cloneDeep(this.chartInfo)
obj.elements = obj.oldElements obj.elements = obj.oldElements
delete obj.oldElements delete obj.oldElements

View File

@@ -20,18 +20,18 @@
<span>{{$t('notebook.done')}}</span> <span>{{$t('notebook.done')}}</span>
</button> </button>
<pick-time ref="pickTime" v-model="searchTime" :refresh-data-func="dateChange" :show-locked="true" :use-chart-unit="false" :sign="'notebook' + obj.id"></pick-time> <pick-time ref="pickTime" v-model="searchTime" :refresh-data-func="dateChange" :show-locked="true" :use-chart-unit="false" :sign="'notebook' + obj.id"></pick-time>
<el-dropdown v-has="['dashboard_view']" trigger="click" size="medium" class="nz-el-dropdown"> <el-dropdown v-has="['notebook_view']" trigger="click" size="medium" class="nz-el-dropdown">
<button class="top-tool-btn" :title="$t('overall.download')"> <button class="top-tool-btn" :title="$t('overall.download')">
<i class="nz-icon nz-icon-download1"></i> <i class="nz-icon nz-icon-download1"></i>
</button> </button>
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top nz-el-dropdown-menu"> <el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top nz-el-dropdown-menu">
<el-dropdown-item v-has="'dashboard_view'"> <el-dropdown-item v-has="'notebook_view'">
<div @click="download('pdf')">{{$t('notebook.downloadAs',{format:'PDF'})}}</div> <div @click="download('pdf')">{{$t('notebook.downloadAs',{format:'PDF'})}}</div>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-has="'dashboard_view'"> <el-dropdown-item v-has="'notebook_view'">
<div @click="download('html')">{{$t('notebook.downloadAs',{format:'markdown'})}}</div> <div @click="download('html')">{{$t('notebook.downloadAs',{format:'markdown'})}}</div>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item v-has="'dashboard_view'"> <el-dropdown-item v-has="'notebook_view'">
<div @click="downloadJson()">{{$t('notebook.downloadNotebook')}} JSON</div> <div @click="downloadJson()">{{$t('notebook.downloadNotebook')}} JSON</div>
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
@@ -93,6 +93,7 @@
</template> </template>
<script> <script>
import Vue from 'vue'
import axios from 'axios' import axios from 'axios'
import bus from '../../../../libs/bus' import bus from '../../../../libs/bus'
import subDataListMixin from '@/components/common/mixin/subDataList' import subDataListMixin from '@/components/common/mixin/subDataList'
@@ -168,6 +169,12 @@ export default {
}, },
methods: { methods: {
done () { done () {
this.$refs.notebookList.copyDataList.forEach(item => {
if (item.type === 'text') {
Vue.delete(item.param, 'isEdit')
Vue.delete(item.param, 'oldText')
}
})
let charts = this.$lodash.cloneDeep(this.$refs.notebookList.copyDataList) let charts = this.$lodash.cloneDeep(this.$refs.notebookList.copyDataList)
charts = charts.filter(item => item.name !== 'groupTemp') charts = charts.filter(item => item.name !== 'groupTemp')
const params = { const params = {
@@ -216,6 +223,14 @@ export default {
addNotebook (position) { addNotebook (position) {
this.addChartBefore({ type: 'line', datasource: 'metrics', position }) this.addChartBefore({ type: 'line', datasource: 'metrics', position })
}, },
copyChartText (data) {
const chart = JSON.parse(JSON.stringify(data))
chart.y = chart.y + 0.01
chart.id = this.getMaxId(this.$refs.notebookList.copyDataList) + 1
chart.param.isEdit = false
this.$refs.notebookList.copyDataList.push(chart)
this.$refs.notebookList.onScroll(this.scrollbarWrap.scrollTop)
},
// 编辑图表信息,打开编辑弹窗 // 编辑图表信息,打开编辑弹窗
editChart (data, copy) { editChart (data, copy) {
if (copy) { if (copy) {
@@ -282,8 +297,10 @@ export default {
}) })
}, },
addText () { addText () {
const timestamp = Math.floor(new Date().getTime() / 1000)
const name = `text-[${timestamp}]`
const chart = { const chart = {
name: '', name,
type: 'text', type: 'text',
unit: 2, unit: 2,
datasource: 'misc', datasource: 'misc',
@@ -473,10 +490,10 @@ export default {
return param return param
}, },
addChartBefore (chart) { addChartBefore (chart) {
// if (chart.type === 'text') { if (chart.type === 'text') {
// this.addText() this.addText()
// return false return false
// } }
this.$store.dispatch('dispatchEditChart', { this.$store.dispatch('dispatchEditChart', {
chart: chart, chart: chart,
type: 'add' type: 'add'
@@ -617,6 +634,7 @@ export default {
this.scrollbarWrap = this.$refs.scrollbar this.scrollbarWrap = this.$refs.scrollbar
this.scrollbarWrap.addEventListener('scroll', this.onScroll) this.scrollbarWrap.addEventListener('scroll', this.onScroll)
bus.$on('addNotebook', this.addNotebook) bus.$on('addNotebook', this.addNotebook)
bus.$on('copyChartText', this.copyChartText)
}, },
beforeDestroy () { beforeDestroy () {
this.$store.dispatch('dispatchPanelTime', { this.$store.dispatch('dispatchPanelTime', {
@@ -627,6 +645,7 @@ export default {
this.scrollbarWrap.removeEventListener('scroll', this.onScroll) this.scrollbarWrap.removeEventListener('scroll', this.onScroll)
} }
bus.$off('addNotebook', this.addNotebook) bus.$off('addNotebook', this.addNotebook)
bus.$off('copyChartText', this.copyChartText)
}, },
watch: { watch: {
obj: { obj: {
@@ -647,6 +666,7 @@ export default {
immediate: false, immediate: false,
deep: true, deep: true,
handler (n) { handler (n) {
console.log(n)
if (n) { if (n) {
this.disposeChart() this.disposeChart()
} else { } else {

View File

@@ -141,6 +141,7 @@
value-key="chartType" value-key="chartType"
@change="chartTypeChange"> @change="chartTypeChange">
<el-option <el-option
v-show="from!=='notebook'||item.id!=='log'"
v-for="item in chartTypeList" v-for="item in chartTypeList"
:key="item.id" :key="item.id"
:disabled="item.id==='group' && chartConfig.isGroup" :disabled="item.id==='group' && chartConfig.isGroup"

View File

@@ -72,17 +72,17 @@
<div class="form__sub-title"> <div class="form__sub-title">
<span>{{$t('dashboard.dashboard.chartForm.dataConfig')}}</span> <span>{{$t('dashboard.dashboard.chartForm.dataConfig')}}</span>
</div> </div>
<el-tabs v-model="editChart.datasource" @tab-click="datasourceChange" type="card"> <el-tabs v-model="editChart.datasource" @tab-click="datasourceChange" type="card" :class="{'notebook-datasource-tab':from==='notebook'}">
<el-tab-pane :label="$t('overall.metrics')" name="metrics"> <el-tab-pane :label="$t('overall.metrics')" name="metrics">
<chart-config :from="from" :variables="variables" ref="childrenFrommetrics" :type="'metrics'" v-if="editChart.datasource == 'metrics'" :params.sync="editChart" @change="editChartChange"/> <chart-config :from="from" :variables="variables" ref="childrenFrommetrics" :type="'metrics'" v-if="editChart.datasource == 'metrics'" :params.sync="editChart" @change="editChartChange"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('overall.logs')" name="logs" :disabled="from==='notebook'"> <el-tab-pane :label="$t('overall.logs')" name="logs">
<chart-config :from="from" :variables="variables" ref="childrenFromlogs" :type="'log'" v-if="editChart.datasource == 'logs'" :params.sync="editChart" @change="editChartChange" class="datasource-log"/> <chart-config :from="from" :variables="variables" ref="childrenFromlogs" :type="'log'" v-if="editChart.datasource == 'logs'" :params.sync="editChart" @change="editChartChange" class="datasource-log"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('overall.system')" name="system"> <el-tab-pane :label="$t('overall.system')" name="system">
<system-chart-config :from="from" :variables="variables" ref="childrenFromsystem" v-if="editChart.datasource == 'system'" :params.sync="editChart" @change="editChartChange"/> <system-chart-config :from="from" :variables="variables" ref="childrenFromsystem" v-if="editChart.datasource == 'system'" :params.sync="editChart" @change="editChartChange"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('overall.misc')" name="misc"> <el-tab-pane :label="$t('overall.misc')" name="misc" v-if="from!=='notebook'">
<other-chart-config :from="from" :variables="variables" ref="childrenFrommisc" v-if="editChart.datasource == 'misc'" :params.sync="editChart" @change="editChartChange"/> <other-chart-config :from="from" :variables="variables" ref="childrenFrommisc" v-if="editChart.datasource == 'misc'" :params.sync="editChart" @change="editChartChange"/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@@ -424,6 +424,49 @@ export default {
} }
} }
if (this.editChart.datasource == 'logs') { if (this.editChart.datasource == 'logs') {
if (this.from === 'notebook') {
this.editChart = {
...this.editChart,
span: 6,
height: 2,
unit: 2,
type: 'line',
elements: [{ expression: '', legend: '', type: 'expert', id: '', name: 'A', state: 1, step: undefined }],
param: {
stack: 0,
nullType: 'null',
legend: { placement: 'bottom', values: [] },
enable: {
thresholds: false,
legend: true,
valueMapping: false,
visibility: false
},
thresholds: [{ id: s8(), value: undefined, color: '#eeeeeeff' }],
showHeader: this.editChart.param.showHeader,
visibility: {
varName: '',
operator: 'equal',
varValue: '',
result: 'show'
},
rightYAxis: {
elementNames: [],
style: 'line',
unit: 2,
label: '',
min: undefined,
max: undefined
},
dataLink: [],
tooltip: {
mode: 'all',
sort: 'none'
},
option: this.lineOption
}
}
} else {
this.editChart = { this.editChart = {
...this.editChart, ...this.editChart,
span: 6, span: 6,
@@ -450,6 +493,7 @@ export default {
} }
} }
} }
}
if (this.editChart.datasource == 'system') { if (this.editChart.datasource == 'system') {
this.editChart = { this.editChart = {
...this.editChart, ...this.editChart,
@@ -493,30 +537,7 @@ export default {
} }
delete this.editChart.elements delete this.editChart.elements
} }
if (this.editChart.datasource == 'misc' && this.from === 'notebook') { if (this.editChart.datasource == 'misc') {
this.editChart = {
...this.editChart,
span: 12,
height: 4,
type: 'text',
param: {
text: '',
enable: {
visibility: false
},
showHeader: this.editChart.param.showHeader,
visibility: {
varName: '',
operator: 'equal',
varValue: '',
result: 'show'
},
editorType: 'markdown',
isEdit: true
}
}
delete this.editChart.elements
} else if (this.editChart.datasource == 'misc') {
this.editChart = { this.editChart = {
...this.editChart, ...this.editChart,
span: 6, span: 6,

View File

@@ -30,7 +30,6 @@
value-key="chartType" value-key="chartType"
@change="chartTypeChange"> @change="chartTypeChange">
<el-option <el-option
v-show="from!=='notebook'||item.id==='text'"
v-for="item in chartTypeList" v-for="item in chartTypeList"
:key="item.id" :key="item.id"
:disabled="item.id==='group' && !!chartConfig.groupId" :disabled="item.id==='group' && !!chartConfig.groupId"
@@ -63,7 +62,6 @@
popper-class="right-box-select-top prevent-clickoutside" popper-class="right-box-select-top prevent-clickoutside"
size="small" size="small"
@change="editorTypeChange" @change="editorTypeChange"
:disabled="from==='notebook'"
> >
<el-option :label="$t('dashboard.dashboard.chartForm.richText')" value="richText"></el-option> <el-option :label="$t('dashboard.dashboard.chartForm.richText')" value="richText"></el-option>
<el-option :label="$t('dashboard.dashboard.chartForm.markDown')" value="markdown"></el-option> <el-option :label="$t('dashboard.dashboard.chartForm.markDown')" value="markdown"></el-option>
@@ -98,7 +96,7 @@
</el-form-item> </el-form-item>
</div> </div>
<!--content--> <!--content-->
<div v-if="contentShow(chartConfig.type)&&from!=='notebook'" class="form__sub-title"> <div v-if="contentShow(chartConfig.type)" class="form__sub-title">
<span>{{$t('dashboard.dashboard.chartForm.content')}}</span> <span>{{$t('dashboard.dashboard.chartForm.content')}}</span>
<span style="cursor: pointer" v-if="isDiagram(chartConfig.type)"><i class="nz-icon nz-icon-edit" @click="topologyDialogChange(true)"></i></span> <span style="cursor: pointer" v-if="isDiagram(chartConfig.type)"><i class="nz-icon nz-icon-edit" @click="topologyDialogChange(true)"></i></span>
</div> </div>
@@ -130,7 +128,7 @@
:isChart="true" :isChart="true"
/> />
<!--text--> <!--text-->
<el-form-item v-if="isText(chartConfig.type)&&from!=='notebook'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change' }" prop="param.text"> <el-form-item v-if="isText(chartConfig.type)" :rules="{ required: true, message: $t('validate.required'), trigger: 'change' }" prop="param.text">
<markdownEditor v-if="chartConfig.param.editorType==='markdown'" :edit-data="chartConfig.param.text" @textChange="textChange"></markdownEditor> <markdownEditor v-if="chartConfig.param.editorType==='markdown'" :edit-data="chartConfig.param.text" @textChange="textChange"></markdownEditor>
<rich-text-editor v-else ref="richTextEditor" :edit-data="chartConfig.param.text" @textChange="textChange"></rich-text-editor> <rich-text-editor v-else ref="richTextEditor" :edit-data="chartConfig.param.text" @textChange="textChange"></rich-text-editor>
</el-form-item> </el-form-item>

View File

@@ -56,14 +56,14 @@
<div slot="header" class="table-operation-title">{{$t('overall.option')}}</div> <div slot="header" class="table-operation-title">{{$t('overall.option')}}</div>
<div slot-scope="scope" class="table-operation-items"> <div slot-scope="scope" class="table-operation-items">
<button class="table-operation-item" @click="showBottomBox('notebookTab', scope.row)" :title="$t('overall.view')"><i class="nz-icon nz-icon-view1"></i></button> <button class="table-operation-item" @click="showBottomBox('notebookTab', scope.row)" :title="$t('overall.view')"><i class="nz-icon nz-icon-view1"></i></button>
<el-dropdown size="medium" v-has="['role_add','role_edit','role_delete']" trigger="click" @command="tableOperation"> <el-dropdown size="medium" v-has="['notebook_add','notebook_edit','notebook_delete']" trigger="click" @command="tableOperation">
<div class="table-operation-item table-operation-item--more" :title="$t('overall.moreOperations')"> <div class="table-operation-item table-operation-item--more" :title="$t('overall.moreOperations')">
<i class="nz-icon nz-icon-more3"></i> <i class="nz-icon nz-icon-more3"></i>
</div> </div>
<el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top"> <el-dropdown-menu slot="dropdown" class="right-box-select-top right-public-box-dropdown-top">
<el-dropdown-item v-has="'role_edit'" :command="['notebookTab', scope.row]"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item> <el-dropdown-item v-has="'notebook_edit'" :command="['notebookTab', scope.row]"><i class="nz-icon nz-icon-edit"></i><span class="operation-dropdown-text">{{$t('overall.edit')}}</span></el-dropdown-item>
<el-dropdown-item v-has="'role_add'" :command="['copy', scope.row]"><i class="nz-icon nz-icon-override"></i><span class="operation-dropdown-text">{{$t('overall.duplicate')}}</span></el-dropdown-item> <el-dropdown-item v-has="'notebook_add'" :command="['copy', scope.row]"><i class="nz-icon nz-icon-override"></i><span class="operation-dropdown-text">{{$t('overall.duplicate')}}</span></el-dropdown-item>
<el-dropdown-item v-has="'role_delete'" :command="['delete-rel', scope.row, {forceDeleteShow:false, single:true,from:'notebook'}]"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item> <el-dropdown-item v-has="'notebook_delete'" :command="['delete-rel', scope.row, {forceDeleteShow:false, single:true,from:'notebook'}]"><i class="nz-icon nz-icon-delete"></i><span class="operation-dropdown-text">{{$t('overall.delete')}}</span></el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
</div> </div>

View File

@@ -18,7 +18,7 @@
<template v-slot:top-tool-left> <template v-slot:top-tool-left>
</template> </template>
<template v-slot:top-tool-right> <template v-slot:top-tool-right>
<button id="asset-create-asset" v-has="'role_add'" :title="$t('asset.createAsset')" class="top-tool-btn" @click.stop="add"> <button id="asset-create-asset" v-has="'notebook_add'" :title="$t('asset.createAsset')" class="top-tool-btn" @click.stop="add">
<i class="nz-icon nz-icon-create-square"></i> <i class="nz-icon nz-icon-create-square"></i>
</button> </button>
<top-tool-more-options <top-tool-more-options
@@ -37,7 +37,7 @@
import-url="/visual/notebook/import" import-url="/visual/notebook/import"
:only-json="true" :only-json="true"
@afterImport="getTableData" @afterImport="getTableData"
v-has="['role_add','role_edit']" v-has="['notebook_add','notebook_edit']"
> >
</top-tool-more-options> </top-tool-more-options>
</template> </template>
@@ -86,7 +86,7 @@
@getTableData="getTableData" @getTableData="getTableData"
> >
<template v-slot:top-tool-right> <template v-slot:top-tool-right>
<button v-has="'role_add'" :title="$t('overall.createDatacenter')" class="top-tool-btn margin-r-10" type="button" @click="add"> <button v-has="'notebook_add'" :title="$t('overall.createDatacenter')" class="top-tool-btn margin-r-10" type="button" @click="add">
<i class="nz-icon-create-square nz-icon"></i> <i class="nz-icon-create-square nz-icon"></i>
</button> </button>
<top-tool-more-options <top-tool-more-options
@@ -104,7 +104,7 @@
import-url="/visual/notebook/import" import-url="/visual/notebook/import"
:only-json="true" :only-json="true"
@afterImport="getTableData" @afterImport="getTableData"
v-has="['role_add','role_edit','role_delete']" v-has="['notebook_add','notebook_edit','notebook_delete']"
> >
<template v-slot:before> <template v-slot:before>
<div> <div>
@@ -118,7 +118,7 @@
:type="'link'" :type="'link'"
:title="$t('overall.batchDel')" :title="$t('overall.batchDel')"
id="account-list-batch-delete" id="account-list-batch-delete"
v-has="'role_delete'" v-has="'notebook_delete'"
:delete-objs="batchDeleteObjs" :delete-objs="batchDeleteObjs"
api="visual/notebook" api="visual/notebook"
@after="getTableData" @after="getTableData"

View File

@@ -8,7 +8,7 @@ import VueResource from 'vue-resource'
import bus from '@/libs/bus' import bus from '@/libs/bus'
Vue.use(VueResource) Vue.use(VueResource)
const loginWhiteList = ['/setup', '/sys/license/upload', '/sys/license/state', '/sys/appearance', '/i18n', '/terminal', '/notebook'] // 免登陆白名单 const loginWhiteList = ['/setup', '/sys/license/upload', '/sys/license/state', '/sys/appearance', '/i18n', '/terminal'] // 免登陆白名单
export const permissionWhiteList = ['/profile', '/menu', ...loginWhiteList] // 权限白名单 export const permissionWhiteList = ['/profile', '/menu', ...loginWhiteList] // 权限白名单
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (window.entrance) { if (window.entrance) {