|
@@ -2,7 +2,7 @@
|
|
|
<div class="template-textarea">
|
|
|
<template v-if="isEdit == 1">
|
|
|
<div class="editor-area sticky-editor">
|
|
|
- <ckeditor
|
|
|
+ <!-- <ckeditor
|
|
|
ref="editor"
|
|
|
v-model="com.content"
|
|
|
@focus="onFocus"
|
|
@@ -11,16 +11,16 @@
|
|
|
@ready="onEditorReady"
|
|
|
:config="editorConfig"
|
|
|
:editorUrl="editorUrl"
|
|
|
- ></ckeditor>
|
|
|
- <!-- <CanvasEditor
|
|
|
+ ></ckeditor> -->
|
|
|
+ <CanvasEditor
|
|
|
ref="wordEditor"
|
|
|
:edit-mode="Modetype"
|
|
|
- :html-data="htmlData"
|
|
|
+ :html-data="com.content"
|
|
|
:doc-json="docJson"
|
|
|
:key="keys"
|
|
|
@save="save"
|
|
|
@is-save="getSave"
|
|
|
- ></CanvasEditor> -->
|
|
|
+ ></CanvasEditor>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -30,6 +30,7 @@
|
|
|
ref="richEditor"
|
|
|
v-html="content"
|
|
|
@click="handleImageClick"
|
|
|
+ :class="{'view-mode': isEdit == 2}"
|
|
|
></div>
|
|
|
</template>
|
|
|
<div v-if="loading" class="overlay">
|
|
@@ -85,15 +86,28 @@ export default {
|
|
|
watch: {
|
|
|
isEdit: {
|
|
|
handler(val) {
|
|
|
- console.log(val);
|
|
|
+ console.log("isEdit:",val);
|
|
|
let _this = this;
|
|
|
- if (_this.com != null) return;
|
|
|
- _this.replaceData(_this.com.content).then((res) => {
|
|
|
- _this.content = res;
|
|
|
- _this.$nextTick(() => {
|
|
|
- _this.bindEvents();
|
|
|
+ if (val == '2') {
|
|
|
+ _this.save()
|
|
|
+ /* if (_this.com && _this.com.content) {
|
|
|
+ _this.replaceData(_this.com.content).then((res) => {
|
|
|
+ _this.content = res;
|
|
|
+ _this.htmlData = res;
|
|
|
+ _this.$nextTick(() => {
|
|
|
+ _this.bindEvents();
|
|
|
+ _this.initializeInputWidths();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ } */
|
|
|
+ } else if (_this.com != null) {
|
|
|
+ _this.replaceData(_this.com.content).then((res) => {
|
|
|
+ _this.content = res;
|
|
|
+ _this.$nextTick(() => {
|
|
|
+ _this.bindEvents();
|
|
|
+ });
|
|
|
});
|
|
|
- });
|
|
|
+ }
|
|
|
},
|
|
|
immediate: true,
|
|
|
deep: true,
|
|
@@ -105,7 +119,7 @@ export default {
|
|
|
if (val.content == undefined || val.content == null) return;
|
|
|
try {
|
|
|
let res = await _this.replaceData(val.content);
|
|
|
- /* _this.htmlData=res */
|
|
|
+ _this.htmlData = res;
|
|
|
_this.content = res;
|
|
|
_this.$nextTick(() => {
|
|
|
_this.bindEvents();
|
|
@@ -121,21 +135,87 @@ export default {
|
|
|
insertCmd: {
|
|
|
handler(val) {
|
|
|
if (val == null || this.isEdit != 1) return;
|
|
|
- let data = this.$refs.editor.instance.getSelection().getSelectedText();
|
|
|
- if (val.content.indexOf("Directory", 0) >= 0) {
|
|
|
- //执行的是目录
|
|
|
- this.$emit(
|
|
|
- "onUpdateAttr",
|
|
|
- this.currentIndex,
|
|
|
- this.com.attrs.length - 1,
|
|
|
- data
|
|
|
- );
|
|
|
- this.$refs.editor.instance.execCommand("delete");
|
|
|
- }
|
|
|
- this.$refs.editor.instance.insertHtml(val.content);
|
|
|
+
|
|
|
+ this.$nextTick(() => {
|
|
|
+ try {
|
|
|
+ if (!this.$refs.wordEditor) {
|
|
|
+ console.warn('编辑器未就绪');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const editor = this.$refs.wordEditor;
|
|
|
+
|
|
|
+ // 获取当前内容和新内容
|
|
|
+ let currentContent = this.com.content || '';
|
|
|
+ let insertContent = val.content;
|
|
|
+
|
|
|
+ // 确保变量两侧有空格
|
|
|
+ if (insertContent.includes('{{') && insertContent.includes('}}')) {
|
|
|
+ insertContent = ` ${insertContent} `;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建新内容
|
|
|
+ let newContent;
|
|
|
+
|
|
|
+ // 如果编辑器支持选区
|
|
|
+ if (editor.getSelection) {
|
|
|
+ const selection = editor.getSelection();
|
|
|
+ if (selection) {
|
|
|
+ // 替换选中的内容
|
|
|
+ const start = selection.start || 0;
|
|
|
+ const end = selection.end || start;
|
|
|
+ newContent = currentContent.substring(0, start) +
|
|
|
+ insertContent +
|
|
|
+ currentContent.substring(end);
|
|
|
+ } else {
|
|
|
+ // 在末尾添加
|
|
|
+ newContent = currentContent + insertContent;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 在末尾添加
|
|
|
+ newContent = currentContent + insertContent;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新内容
|
|
|
+ this.com.content = newContent;
|
|
|
+
|
|
|
+ // 更新编辑器显示
|
|
|
+ if (editor.setHtmlData) {
|
|
|
+ editor.setHtmlData(newContent);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 强制重新渲染
|
|
|
+ this.keys = new Date().getTime();
|
|
|
+
|
|
|
+ // 调用保存方法
|
|
|
+ this.save({
|
|
|
+ main: newContent
|
|
|
+ });
|
|
|
+
|
|
|
+ // 确保视图更新
|
|
|
+ this.$forceUpdate();
|
|
|
+
|
|
|
+ // 同步到预览模式
|
|
|
+ this.syncContent();
|
|
|
+
|
|
|
+ // 记录操作日志
|
|
|
+ console.log('内容插入成功:', {
|
|
|
+ 原内容: currentContent,
|
|
|
+ 插入内容: insertContent,
|
|
|
+ 新内容: newContent
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('插入内容时出错:', error);
|
|
|
+ console.error('错误详情:', {
|
|
|
+ 编辑器: this.$refs.wordEditor,
|
|
|
+ 内容: val.content,
|
|
|
+ 当前内容: this.com.content
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
},
|
|
|
- immediate: true,
|
|
|
- deep: true,
|
|
|
+ deep: true
|
|
|
},
|
|
|
},
|
|
|
data() {
|
|
@@ -163,6 +243,14 @@ export default {
|
|
|
mounted() {
|
|
|
this.$nextTick(() => {
|
|
|
this.initializeInputWidths();
|
|
|
+ this.syncContent();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ updated() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.isEdit == '2') {
|
|
|
+ this.syncContent();
|
|
|
+ }
|
|
|
});
|
|
|
},
|
|
|
// 记得在组件销毁时移除事件监听器
|
|
@@ -174,9 +262,18 @@ export default {
|
|
|
methods: {
|
|
|
/*canvas 添加 */
|
|
|
save(data) {
|
|
|
- // 处理保存逻辑
|
|
|
- console.log("保存数据:", data);
|
|
|
- // 这里可以添加具体的保存实现
|
|
|
+ // 如果没有传入data参数,使用当前编辑器的内容
|
|
|
+ const content = data ? data.main : this.com.content;
|
|
|
+ console.log(112);
|
|
|
+ // 更新内容
|
|
|
+ this.com.content = content;
|
|
|
+ this.syncContent(); // 同步到预览模式
|
|
|
+
|
|
|
+ // 触发更新事件
|
|
|
+ this.$emit('onUpdate', this.currentIndex, this.com.content);
|
|
|
+
|
|
|
+ // 返回保存成功状态
|
|
|
+ return true;
|
|
|
},
|
|
|
getSave(isSaved) {
|
|
|
// 处理保存状态
|
|
@@ -1016,6 +1113,49 @@ export default {
|
|
|
//// console.log(' onBlur e',e);
|
|
|
// this.$emit("onUploadAttr",this.dataIndex,this.dataAttr);
|
|
|
}, */
|
|
|
+
|
|
|
+ syncContent() {
|
|
|
+ if (this.isEdit == '2' && this.com && this.com.content) {
|
|
|
+ const formattedContent = this.formatContent(this.com.content);
|
|
|
+ this.replaceData(formattedContent).then((res) => {
|
|
|
+ this.content = res;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.bindEvents();
|
|
|
+ this.initializeInputWidths();
|
|
|
+
|
|
|
+ // 确保变量和空格都正确显示
|
|
|
+ if (this.com.attrs) {
|
|
|
+ this.com.attrs.forEach((attr, index) => {
|
|
|
+ const element = this.$el.querySelector(`#${attr.id}`);
|
|
|
+ if (element) {
|
|
|
+ element.value = attr.content || '';
|
|
|
+ this.adjustInputWidth({ target: element });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ getCursorPosition() {
|
|
|
+ const editor = this.$refs.wordEditor;
|
|
|
+ if (!editor) return 0;
|
|
|
+
|
|
|
+ // 尝试不同的方法获取光标位置
|
|
|
+ if (editor.getCursorPosition) {
|
|
|
+ return editor.getCursorPosition();
|
|
|
+ } else if (editor.getSelection) {
|
|
|
+ const selection = editor.getSelection();
|
|
|
+ return selection ? selection.start || 0 : 0;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ },
|
|
|
+
|
|
|
+ formatContent(content) {
|
|
|
+ // 保留空格和换行
|
|
|
+ return content.replace(/\s+/g, ' ').replace(/\n/g, '<br>');
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
@@ -1109,4 +1249,64 @@ export default {
|
|
|
font-weight: normal;
|
|
|
margin-left: 100px;
|
|
|
}
|
|
|
+
|
|
|
+.rich-editor.view-mode {
|
|
|
+ // 添加与编辑模式一致的样式
|
|
|
+ ::v-deep {
|
|
|
+ // 继承编辑器的基本样式
|
|
|
+ font-family: inherit;
|
|
|
+ line-height: 1.6;
|
|
|
+ color: inherit;
|
|
|
+
|
|
|
+ // 标题样式
|
|
|
+ h1, h2, h3, h4, h5, h6 {
|
|
|
+ margin: 1em 0 0.5em;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 段落样式
|
|
|
+ p {
|
|
|
+ margin: 1em 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 列表样式
|
|
|
+ ul, ol {
|
|
|
+ padding-left: 2em;
|
|
|
+ margin: 1em 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 表格样式
|
|
|
+ table {
|
|
|
+ border-collapse: collapse;
|
|
|
+ width: 100%;
|
|
|
+ margin: 1em 0;
|
|
|
+
|
|
|
+ td, th {
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ padding: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 图片样式
|
|
|
+ img {
|
|
|
+ max-width: 100%;
|
|
|
+ height: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保持输入框样式一致
|
|
|
+ .text-input-box,
|
|
|
+ .text-input-boxs {
|
|
|
+ display: inline-block;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ background: transparent;
|
|
|
+ padding: 2px 4px;
|
|
|
+ min-width: 20px;
|
|
|
+ outline: none;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #ddd;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|