|
@@ -18,6 +18,30 @@
|
|
|
<SvgIcon icon-class="close-circle" size="16" @click="deleteFill" />
|
|
|
<span class="button" @click="deleteFill">删除填空</span>
|
|
|
</div>
|
|
|
+
|
|
|
+ <el-dialog
|
|
|
+ title="输入公式"
|
|
|
+ :visible.sync="isViewMathDialog"
|
|
|
+ width="400px"
|
|
|
+ top="20vh"
|
|
|
+ :show-close="false"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ @close="isViewMathDialog = false"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-model="mathData.math"
|
|
|
+ type="textarea"
|
|
|
+ :autosize="{ minRows: 4, maxRows: 8 }"
|
|
|
+ resize="none"
|
|
|
+ placeholder="请输入公式"
|
|
|
+ />
|
|
|
+ <div ref="mathContainer" v-data-h="mathData.math" class="formula-render" v-html="mathData.math"></div>
|
|
|
+ <template slot="footer">
|
|
|
+ <el-button size="medium" @click="isViewMathDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" size="medium" @click="mathConfirm">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -50,6 +74,7 @@ import { getRandomNumber } from '@/utils';
|
|
|
import { isNodeType } from '@/utils/validate';
|
|
|
import { fileUpload } from '@/api/app';
|
|
|
import { addTone, handleToneValue } from '@/utils/common';
|
|
|
+import { getMathData } from '@/views/book/courseware/data/math';
|
|
|
|
|
|
export default {
|
|
|
name: 'RichText',
|
|
@@ -82,7 +107,7 @@ export default {
|
|
|
type: [String, Boolean],
|
|
|
/* eslint-disable max-len */
|
|
|
default:
|
|
|
- 'fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright | bullist numlist | image media | link blockquote hr',
|
|
|
+ 'fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright | bullist numlist | image media | link blockquote hr mathjax',
|
|
|
},
|
|
|
wordlimitNum: {
|
|
|
type: [Number, Boolean],
|
|
@@ -107,6 +132,11 @@ export default {
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
+ mathData: getMathData(),
|
|
|
+ isViewMathDialog: false,
|
|
|
+ dialogMathValidate: false,
|
|
|
+ mathEleIsInit: true,
|
|
|
+ math: '',
|
|
|
isShow: false,
|
|
|
contentmenu: {
|
|
|
top: 0,
|
|
@@ -114,6 +144,14 @@ export default {
|
|
|
},
|
|
|
id: getRandomNumber(),
|
|
|
init: {
|
|
|
+ content_style: `
|
|
|
+ mjx-container, mjx-container * {
|
|
|
+ font-size: 16px !important; /* 强制固定字体 */
|
|
|
+ line-height: 1.2 !important; /* 避免行高影响 */
|
|
|
+ } `, // 解决公式每点击一次字体就变大
|
|
|
+ valid_elements: '*[*]', // 允许所有标签和属性
|
|
|
+ valid_children: '+body[style]', // 允许 MathJax 的样式
|
|
|
+ extended_valid_elements: 'span[*],mjx-container[*],svg[*],path[*]', // 明确允许 MathJax 标签
|
|
|
inline: this.inline,
|
|
|
font_size: this.fontSize,
|
|
|
language_url: `${process.env.BASE_URL}tinymce/langs/zh_CN.js`,
|
|
@@ -130,7 +168,8 @@ export default {
|
|
|
menubar: false, // 菜单栏
|
|
|
branding: false, // 品牌
|
|
|
statusbar: false, // 状态栏
|
|
|
- setup(editor) {
|
|
|
+ setup: (editor) => {
|
|
|
+ let isRendered = false; // 标记是否已渲染
|
|
|
editor.on('init', () => {
|
|
|
editor.getBody().style.fontSize = `${this.font_size}pt`; // 设置默认字体大小
|
|
|
editor.getBody().style.fontFamily = 'Arial'; // 设置默认字体
|
|
@@ -140,7 +179,23 @@ export default {
|
|
|
if (editor?.queryCommandState('ToggleToolbarDrawer')) {
|
|
|
editor.execCommand('ToggleToolbarDrawer');
|
|
|
}
|
|
|
+ if (!isRendered && window.MathJax) {
|
|
|
+ isRendered = true;
|
|
|
+ window.MathJax.typesetPromise([editor.getBody()]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 添加 MathJax 按钮
|
|
|
+ editor.ui.registry.addButton('mathjax', {
|
|
|
+ text: '∑',
|
|
|
+ tooltip: '插入公式',
|
|
|
+ onAction: () => {
|
|
|
+ this.isViewMathDialog = true;
|
|
|
+ },
|
|
|
});
|
|
|
+
|
|
|
+ // 内容变化时重新渲染公式
|
|
|
+ editor.on('change', () => this.renderMath());
|
|
|
},
|
|
|
font_formats:
|
|
|
'楷体=楷体,微软雅黑;' +
|
|
@@ -174,6 +229,21 @@ export default {
|
|
|
},
|
|
|
};
|
|
|
},
|
|
|
+ watch: {
|
|
|
+ // 监听数据变化,重新渲染 MathJax
|
|
|
+ 'mathData.math': {
|
|
|
+ handler(n, o) {
|
|
|
+ if (n) this.renderMathDialog();
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ },
|
|
|
+ isViewMathDialog: {
|
|
|
+ handler() {
|
|
|
+ this.dialogMathValidate = false;
|
|
|
+ this.mathData.math = '';
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
created() {
|
|
|
window.addEventListener('click', this.hideToolbarDrawer);
|
|
|
if (this.isFill) {
|
|
@@ -464,6 +534,54 @@ export default {
|
|
|
top: `${pixelsFromTop - 18}px`,
|
|
|
};
|
|
|
},
|
|
|
+
|
|
|
+ mathConfirm() {
|
|
|
+ if (!this.dialogMathValidate) return;
|
|
|
+
|
|
|
+ let editor = tinymce.get(this.id);
|
|
|
+ let tmpId = getRandomNumber();
|
|
|
+ let tmpMathData = this.mathData.math;
|
|
|
+ editor.insertContent(`
|
|
|
+ <span id="${tmpId}" contenteditable="false" class="mathjax-container editor-math">
|
|
|
+ ${tmpMathData}
|
|
|
+ </span>
|
|
|
+ `);
|
|
|
+ // editor.insertContent(`${latex}`);
|
|
|
+ this.mathEleIsInit = false;
|
|
|
+ this.renderMath(tmpId);
|
|
|
+ this.isViewMathDialog = false;
|
|
|
+ },
|
|
|
+ // 渲染公式
|
|
|
+ async renderMath(id) {
|
|
|
+ if (this.mathEleIsInit) return; // 如果公式已经渲染过,返回
|
|
|
+ if (window.MathJax) {
|
|
|
+ let editor = tinymce.get(this.id);
|
|
|
+ let eleMathArs = [];
|
|
|
+ if (id) {
|
|
|
+ // 插入的时候,会传递ID,执行单个渲染
|
|
|
+ let ele = editor.dom.select(`#${id}`)[0];
|
|
|
+ eleMathArs = [ele];
|
|
|
+ } else {
|
|
|
+ // 否则,查询编辑器里面所有的公式
|
|
|
+ eleMathArs = editor.dom.select(`.editor_math`);
|
|
|
+ }
|
|
|
+ if (eleMathArs.length === 0) return;
|
|
|
+ await this.$nextTick();
|
|
|
+ window.MathJax.typesetPromise(eleMathArs).catch((err) => console.error('MathJax error:', err));
|
|
|
+ this.mathEleIsInit = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async renderMathDialog() {
|
|
|
+ this.dialogMathValidate = false;
|
|
|
+ await this.$nextTick();
|
|
|
+ try {
|
|
|
+ await window.MathJax.typesetPromise([this.$refs.mathContainer]);
|
|
|
+ let mathRes = this.$refs.mathContainer.innerHTML;
|
|
|
+ if (mathRes && mathRes.indexOf('merror') === -1) this.dialogMathValidate = true;
|
|
|
+ } catch (err) {
|
|
|
+ console.error('公式渲染失败:', err);
|
|
|
+ }
|
|
|
+ },
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
@@ -524,4 +642,8 @@ export default {
|
|
|
margin: 0 4px;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+mjx-container {
|
|
|
+ font-size: 16px !important;
|
|
|
+}
|
|
|
</style>
|