mirror of
https://github.com/dataease/dataease.git
synced 2026-05-23 13:58:26 +08:00
feat(视图): 新增富文本视图
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<div class="rich-main-class" @dblclick="setEdit">
|
||||
<Editor
|
||||
v-if="editShow"
|
||||
:id="tinymceId"
|
||||
v-model="myValue"
|
||||
style="width: 100%;height: 100%"
|
||||
:init="init"
|
||||
:disabled="!canEdit"
|
||||
@onClick="onClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tinymce from 'tinymce/tinymce' // tinymce默认hidden,不引入不显示
|
||||
import Editor from '@tinymce/tinymce-vue'// 编辑器引入
|
||||
import 'tinymce/themes/silver/theme'// 编辑器主题
|
||||
import 'tinymce/icons/default' // 引入编辑器图标icon,不引入则不显示对应图标
|
||||
// 引入编辑器插件(基本免费插件都在这儿了)
|
||||
import 'tinymce/plugins/advlist' // 高级列表
|
||||
import 'tinymce/plugins/autolink' // 自动链接
|
||||
import 'tinymce/plugins/link' // 超链接
|
||||
import 'tinymce/plugins/image' // 插入编辑图片
|
||||
import 'tinymce/plugins/lists' // 列表插件
|
||||
import 'tinymce/plugins/charmap' // 特殊字符
|
||||
import 'tinymce/plugins/media' // 插入编辑媒体
|
||||
import 'tinymce/plugins/wordcount'// 字数统计
|
||||
import 'tinymce/plugins/table'// 表格
|
||||
import 'tinymce/plugins/contextmenu'// contextmenu
|
||||
import 'tinymce/plugins/directionality'
|
||||
import 'tinymce/plugins/nonbreaking'
|
||||
import 'tinymce/plugins/pagebreak'
|
||||
import { mapState } from 'vuex'
|
||||
import bus from '@/utils/bus'
|
||||
export default {
|
||||
name: 'DeRichTextView',
|
||||
components: {
|
||||
Editor
|
||||
},
|
||||
props: {
|
||||
element: {
|
||||
type: Object
|
||||
},
|
||||
dataRowSelect: {
|
||||
type: Object
|
||||
},
|
||||
dataRowNameSelect: {
|
||||
type: Object
|
||||
},
|
||||
editMode: {
|
||||
type: String,
|
||||
require: false,
|
||||
default: 'preview'
|
||||
},
|
||||
active: {
|
||||
type: Boolean,
|
||||
require: false,
|
||||
default: false
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editShow: true,
|
||||
canEdit: false,
|
||||
// 初始化配置
|
||||
tinymceId: 'tinymce-view-' + this.element.id,
|
||||
myValue: '',
|
||||
init: {
|
||||
selector: '#tinymce-view-' + this.element.id,
|
||||
toolbar_items_size: 'small',
|
||||
language_url: '/tinymce/langs/zh_CN.js', // 汉化路径是自定义的,一般放在public或static里面
|
||||
language: 'zh_CN',
|
||||
skin_url: '/tinymce/skins/ui/oxide', // 皮肤
|
||||
content_css: '/tinymce/skins/content/default/content.css',
|
||||
plugins: 'advlist autolink link image lists charmap media wordcount table contextmenu directionality pagebreak', // 插件
|
||||
// 工具栏
|
||||
toolbar: 'undo redo |fontselect fontsizeselect |forecolor backcolor bold italic |underline strikethrough link| formatselect |' +
|
||||
'alignleft aligncenter alignright | bullist numlist |' +
|
||||
' blockquote subscript superscript removeformat | table image media | fullscreen ' +
|
||||
'| bdmap indent2em lineheight formatpainter axupimgs',
|
||||
toolbar_location: '/',
|
||||
font_formats: '微软雅黑=Microsoft YaHei;宋体=SimSun;黑体=SimHei;仿宋=FangSong;华文黑体=STHeiti;华文楷体=STKaiti;华文宋体=STSong;华文仿宋=STFangsong;Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings',
|
||||
fontsize_formats: '12px 14px 16px 18px 20px 22px 24px 28px 32px 36px 48px 56px 72px', // 字体大小
|
||||
menubar: false,
|
||||
placeholder: '双击输入文字',
|
||||
inline: true, // 开启内联模式
|
||||
branding: false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editStatus() {
|
||||
return this.editMode === 'edit' && !this.mobileLayoutStatus
|
||||
},
|
||||
...mapState([
|
||||
'mobileLayoutStatus'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
// 监听内容变化
|
||||
active(val) {
|
||||
const _this = this
|
||||
if (!val) {
|
||||
this.canEdit = false
|
||||
this.reShow()
|
||||
this.$nextTick(() => {
|
||||
_this.element.propValue.textValue = _this.myValue
|
||||
_this.myValue = _this.assignment(_this.myValue)
|
||||
})
|
||||
}
|
||||
},
|
||||
myValue(newValue) {
|
||||
console.log('myValue===' + newValue)
|
||||
// this.element.propValue.textValue = newValue
|
||||
// this.$store.state.styleChangeTimes++
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
bus.$on('fieldSelect-' + this.element.propValue.viewId, this.fieldSelect)
|
||||
tinymce.init({})
|
||||
this.myValue = this.assignment(this.element.propValue.textValue)
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off('fieldSelect-' + this.element.propValue.viewId)
|
||||
},
|
||||
methods: {
|
||||
assignment(content) {
|
||||
const on = content.match(/\[(.+?)\]/g)
|
||||
if (on) {
|
||||
on.forEach(itm => {
|
||||
const ele = itm.slice(1, -1)
|
||||
content = content.replace(itm, this.dataRowNameSelect[ele])
|
||||
})
|
||||
}
|
||||
return content
|
||||
},
|
||||
fieldSelect(field) {
|
||||
const value = '[' + field.name + ']'
|
||||
const ed = tinymce.get('tinymce-view-' + this.element.id)
|
||||
const range = ed.selection.getRng()
|
||||
const divNode = ed.getDoc().createElement('span')
|
||||
divNode.innerHTML = value
|
||||
range.insertNode(divNode)
|
||||
},
|
||||
onClick(e) {
|
||||
this.$emit('onClick', e, tinymce)
|
||||
},
|
||||
setEdit() {
|
||||
if (this.editStatus) {
|
||||
const _this = this
|
||||
this.canEdit = true
|
||||
this.element['editing'] = true
|
||||
this.reShow()
|
||||
this.$nextTick(() => {
|
||||
_this.myValue = _this.element.propValue.textValue
|
||||
})
|
||||
}
|
||||
},
|
||||
reShow() {
|
||||
this.editShow = false
|
||||
this.$nextTick(() => {
|
||||
this.editShow = true
|
||||
})
|
||||
},
|
||||
chartResize() {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rich-main-class {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto!important;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0px!important;
|
||||
height: 0px!important;
|
||||
}
|
||||
::v-deep ol {
|
||||
display: block!important;
|
||||
list-style-type: decimal;
|
||||
margin-block-start: 1em!important;
|
||||
margin-block-end: 1em!important;
|
||||
margin-inline-start: 0px!important;
|
||||
margin-inline-end: 0px!important;
|
||||
padding-inline-start: 40px!important;
|
||||
}
|
||||
::v-deep ul {
|
||||
display: block!important;
|
||||
list-style-type: disc;
|
||||
margin-block-start: 1em!important;
|
||||
margin-block-end: 1em!important;
|
||||
margin-inline-start: 0px!important;
|
||||
margin-inline-end: 0px!important;
|
||||
padding-inline-start: 40px!important;
|
||||
}
|
||||
::v-deep li {
|
||||
display: list-item!important;
|
||||
text-align: -webkit-match-parent!important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -41,6 +41,16 @@
|
||||
@onJumpClick="jumpClick"
|
||||
@trigger-edit-click="pluginEditHandler"
|
||||
/>
|
||||
<de-rich-text-view
|
||||
v-else-if="richTextViewShowFlag"
|
||||
:ref="element.propValue.id"
|
||||
:element="element"
|
||||
:prop-value="element.propValue.textValue"
|
||||
:active="active"
|
||||
:edit-mode="editMode"
|
||||
:data-row-select="dataRowSelect"
|
||||
:data-row-name-select="dataRowNameSelect"
|
||||
/>
|
||||
<chart-component
|
||||
v-else-if="charViewShowFlag"
|
||||
:ref="element.propValue.id"
|
||||
@@ -129,10 +139,12 @@ import PluginCom from '@/views/system/plugin/PluginCom'
|
||||
import LabelNormalText from '@/views/chart/components/normal/LabelNormalText'
|
||||
import { viewPropsSave } from '@/api/chart/chart'
|
||||
import { checkAddHttp } from '@/utils/urlUtils'
|
||||
import DeRichTextView from '@/components/canvas/custom-component/DeRichTextView'
|
||||
import Vue from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'UserView',
|
||||
components: { LabelNormalText, PluginCom, ChartComponentS2, EditBarView, ChartComponent, TableNormal, LabelNormal, DrillPath, ChartComponentG2 },
|
||||
components: { DeRichTextView, LabelNormalText, PluginCom, ChartComponentS2, EditBarView, ChartComponent, TableNormal, LabelNormal, DrillPath, ChartComponentG2 },
|
||||
props: {
|
||||
element: {
|
||||
type: Object,
|
||||
@@ -188,10 +200,18 @@ export default {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'NotProvided'
|
||||
},
|
||||
editMode: {
|
||||
type: String,
|
||||
require: false,
|
||||
default: 'preview'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataRowNameSelect: {},
|
||||
dataRowSelect: {},
|
||||
curFields: [],
|
||||
isFirstLoad: true, // 是否是第一次加载
|
||||
refId: null,
|
||||
chart: BASE_CHART_STRING,
|
||||
@@ -240,6 +260,9 @@ export default {
|
||||
editBarViewShowFlag() {
|
||||
return (this.active && this.inTab && !this.mobileLayoutStatus) && !this.showPosition.includes('multiplexing') || this.showPosition.includes('email-task')
|
||||
},
|
||||
richTextViewShowFlag() {
|
||||
return this.httpRequest.status && this.chart.type && this.chart.type === 'richTextView'
|
||||
},
|
||||
charViewShowFlag() {
|
||||
return this.httpRequest.status && this.chart.type && !this.chart.type.includes('table') && !this.chart.type.includes('text') && this.chart.type !== 'label' && this.renderComponent() === 'echarts'
|
||||
},
|
||||
@@ -570,6 +593,7 @@ export default {
|
||||
this.drillFields = JSON.parse(JSON.stringify(response.data.drillFields))
|
||||
this.requestStatus = 'merging'
|
||||
this.mergeScale()
|
||||
this.initCurFields(this.chart)
|
||||
this.requestStatus = 'success'
|
||||
this.httpRequest.status = true
|
||||
} else {
|
||||
@@ -596,6 +620,30 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
initCurFields(chartDetails) {
|
||||
this.curFields = []
|
||||
const checkAllAxisStr = chartDetails.xaxis + chartDetails.xaxisExt + chartDetails.yaxis + chartDetails.yaxisExt + chartDetails.drillFields
|
||||
chartDetails.data.sourceFields.forEach(field => {
|
||||
if (checkAllAxisStr.indexOf(field.id) > -1) {
|
||||
this.curFields.push(field)
|
||||
}
|
||||
})
|
||||
// Get the corresponding relationship between id and value
|
||||
const nameIdMap = chartDetails.data.fields.reduce((pre, next) => {
|
||||
pre[next['dataeaseName']] = next['id']
|
||||
return pre
|
||||
}, {})
|
||||
const sourceFieldNameIdMap = chartDetails.data.fields.reduce((pre, next) => {
|
||||
pre[next['dataeaseName']] = next['name']
|
||||
return pre
|
||||
}, {})
|
||||
const rowData = chartDetails.data.tableRow[0]
|
||||
for (const key in rowData) {
|
||||
this.dataRowSelect[nameIdMap[key]] = rowData[key]
|
||||
this.dataRowNameSelect[sourceFieldNameIdMap[key]] = rowData[key]
|
||||
}
|
||||
Vue.set(this.element.propValue, 'innerType', chartDetails.type)
|
||||
},
|
||||
viewIdMatch(viewIds, viewId) {
|
||||
return !viewIds || viewIds.length === 0 || viewIds.includes(viewId)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user