This commit is contained in:
2026-04-02 10:56:37 +08:00
parent 1f29fb5baf
commit 95b52b4d06
5 changed files with 234 additions and 21 deletions

View File

@@ -1152,7 +1152,12 @@ colTitle: 'Template title',
placeholder: 'Please enter email content' placeholder: 'Please enter email content'
}, },
wordCite: { wordCite: {
notFoundById: 'No reference found for citation ID {id}' notFoundById: 'No reference found for citation ID {id}',
selectRef: 'Select Reference',
reference: 'Reference',
cancel: 'Cancel',
confirm: 'Confirm',
remove: 'Remove'
} }

View File

@@ -1137,7 +1137,12 @@ const zh = {
placeholder: '请输入邮件内容' placeholder: '请输入邮件内容'
}, },
wordCite: { wordCite: {
notFoundById: '未查询到编号{id}相关参考文献' notFoundById: '未查询到编号{id}相关参考文献',
selectRef: '选择参考文献',
reference: '参考文献',
cancel: '取消',
confirm: '确认',
remove: '移除'
} }

View File

@@ -388,6 +388,8 @@
:value="currentContent.content" :value="currentContent.content"
@getContent="getContent" @getContent="getContent"
@openLatexEditor="openLatexEditor" @openLatexEditor="openLatexEditor"
@openRefSelector="handleOpenRefSelector"
:chanFerForm="chanFerForm"
v-if="editVisible" v-if="editVisible"
ref="commonContent" ref="commonContent"
style="margin-left: -115px" style="margin-left: -115px"
@@ -422,6 +424,8 @@
@getContent="getContent" @getContent="getContent"
type="content" type="content"
@openLatexEditor="openLatexEditor" @openLatexEditor="openLatexEditor"
@openRefSelector="handleOpenRefSelector"
:chanFerForm="chanFerForm"
v-if="addContentVisible" v-if="addContentVisible"
ref="addContent" ref="addContent"
style="margin-left: -115px" style="margin-left: -115px"
@@ -439,6 +443,40 @@
</el-dialog> </el-dialog>
<common-late-x v-if="showLateX" @close="showLateX = false" @save="saveLateX" :LateXInfo="LateXInfo"></common-late-x> <common-late-x v-if="showLateX" @close="showLateX = false" @save="saveLateX" :LateXInfo="LateXInfo"></common-late-x>
<el-dialog
:title="$t('wordCite.selectRef')"
:visible.sync="refSelectorVisible"
width="860px"
append-to-body
:close-on-click-modal="false"
>
<el-table
:data="chanFerForm"
highlight-current-row
@current-change="handleRefCurrentChange"
style="width: 100%"
max-height="400"
size="small"
>
<el-table-column type="index" :label="'#'" width="60" :index="idx => idx + 1"></el-table-column>
<el-table-column :label="$t('wordCite.reference')">
<template slot-scope="scope">
{{ scope.row.refer_frag || [scope.row.author, scope.row.title, scope.row.joura, scope.row.dateno].filter(Boolean).join(' ') || '-' }}
</template>
</el-table-column>
<el-table-column label="DOI" width="200">
<template slot-scope="scope">
{{ scope.row.doilink || scope.row.doi || scope.row.isbn || '-' }}
</template>
</el-table-column>
</el-table>
<span slot="footer" class="dialog-footer">
<el-button @click="refSelectorVisible = false">{{ $t('wordCite.cancel') }}</el-button>
<el-button type="danger" v-if="refSelectorCurrentRefId" @click="handleRemoveRefCite">{{ $t('wordCite.remove') }}</el-button>
<el-button type="primary" :disabled="!refSelectedRow" @click="handleConfirmRefCite">{{ $t('wordCite.confirm') }}</el-button>
</span>
</el-dialog>
</div> </div>
</template> </template>
@@ -576,7 +614,11 @@ export default {
exegesis: "The following contents'<b></b>,<i></i>'are necessary for the generation phase, please do not delete them!!!", exegesis: "The following contents'<b></b>,<i></i>'are necessary for the generation phase, please do not delete them!!!",
p_article_id: null, p_article_id: null,
chanFerForm: [], chanFerForm: [],
chanFerFormRepeatList: [] chanFerFormRepeatList: [],
refSelectorVisible: false,
refSelectorCurrentRefId: null,
refSelectedRow: null,
refSelectorSource: 'commonContent'
}; };
}, },
components: { components: {
@@ -685,6 +727,36 @@ export default {
console.log(err); console.log(err);
}); });
}, },
handleOpenRefSelector(data) {
this.refSelectorCurrentRefId = data && data.currentRefId ? data.currentRefId : null;
this.refSelectedRow = null;
if (this.editVisible) {
this.refSelectorSource = 'commonContent';
} else if (this.addContentVisible) {
this.refSelectorSource = 'addContent';
}
this.refSelectorVisible = true;
},
handleRefCurrentChange(row) {
this.refSelectedRow = row;
},
handleConfirmRefCite() {
if (!this.refSelectedRow) return;
const ref = this.$refs[this.refSelectorSource];
if (ref) {
ref.insertAutocite(this.refSelectedRow.p_refer_id);
}
this.refSelectorVisible = false;
this.refSelectedRow = null;
},
handleRemoveRefCite() {
const ref = this.$refs[this.refSelectorSource];
if (ref) {
ref.removeAutocite();
}
this.refSelectorVisible = false;
this.refSelectedRow = null;
},
ChanFerMashUp(e) { ChanFerMashUp(e) {
this.$api this.$api
.post('api/Production/referHB', e) .post('api/Production/referHB', e)

View File

@@ -63,6 +63,21 @@ export default {
}, },
articleId: { articleId: {
default: '' default: ''
},
chanFerForm: {
type: Array,
default: () => []
}
},
computed: {
citeMap() {
const map = {};
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
refs.forEach((row, idx) => {
const key = row && row.p_refer_id != null ? String(row.p_refer_id) : '';
if (key) map[key] = idx + 1;
});
return map;
} }
}, },
data() { data() {
@@ -129,17 +144,22 @@ export default {
}, },
watch: { watch: {
value: { value: {
handler(val) { handler(val) {
if (!this.hasChange && this.hasInit) {
this.$nextTick(() => {
if (!this.hasChange && this.hasInit) { window.tinymce.get(this.tinymceId).setContent(val);
this.$nextTick(() => { });
window.tinymce.get(this.tinymceId).setContent(val); }
}); },
} immediate: true
}, },
immediate: true chanFerForm: {
handler() {
if (this.editorInstance) {
this.renderAutociteInEditor(this.editorInstance);
}
},
deep: true
} }
}, },
mounted() { mounted() {
@@ -163,6 +183,60 @@ export default {
this.destroyTinymce(); this.destroyTinymce();
}, },
methods: { methods: {
renderAutociteInEditor(ed) {
const body = ed.getBody();
if (!body) return;
const autocites = body.querySelectorAll('autocite');
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
const refMap = {};
refs.forEach((item) => {
const key = item && item.p_refer_id != null ? String(item.p_refer_id) : '';
if (key) refMap[key] = item;
});
autocites.forEach((el) => {
ed.dom.setAttrib(el, 'contenteditable', 'false');
const dataId = el.getAttribute('data-id');
const num = this.citeMap[String(dataId)];
el.textContent = num != null ? `[${num}]` : '[?]';
const ref = refMap[String(dataId)];
if (ref) {
const content = ref.refer_frag || [ref.author, ref.title, ref.joura, ref.dateno].filter(Boolean).join(' ').trim() || '';
const doi = ref.doilink || ref.isbn || ref.doi || '';
const tip = `[${num || '?'}] ${content}${doi ? '\nDOI: ' + doi : ''}`;
ed.dom.setAttrib(el, 'title', tip);
} else {
ed.dom.setAttrib(el, 'title', this.$t('wordCite.notFoundById', { id: num != null ? num : dataId }));
}
});
},
insertAutocite(refId) {
const ed = this.editorInstance;
if (!ed) return;
if (this._editingAutocite) {
this._editingAutocite.setAttribute('data-id', refId);
const num = this.citeMap[String(refId)];
this._editingAutocite.textContent = num != null ? `[${num}]` : '[?]';
this._editingAutocite = null;
ed.fire('change');
} else {
if (this._refBookmark) {
ed.selection.moveToBookmark(this._refBookmark);
}
const num = this.citeMap[String(refId)];
const label = num != null ? `[${num}]` : '[?]';
const html = `<autocite data-id="${refId}" contenteditable="false">${label}</autocite>`;
ed.insertContent(html);
}
},
removeAutocite() {
const ed = this.editorInstance;
if (!ed || !this._editingAutocite) return;
ed.dom.remove(this._editingAutocite);
this._editingAutocite = null;
ed.fire('change');
},
handleSetContent(val) { handleSetContent(val) {
if (!this.editorInstance) return; if (!this.editorInstance) return;
@@ -497,9 +571,9 @@ export default {
window.tinymce.init({ window.tinymce.init({
..._this.tinymceOtherInit, ..._this.tinymceOtherInit,
trim_span_elements: false, // 禁止修剪内联标签周围的空格 trim_span_elements: false, // 禁止修剪内联标签周围的空格
extended_valid_elements: 'blue[*]', extended_valid_elements: 'blue[*],autocite[*]',
custom_elements: 'blue', custom_elements: 'blue,autocite',
valid_children: '+blue[#text|i|em|b|strong|span],+body[blue],+p[blue]', valid_children: '+blue[#text|i|em|b|strong|span],+body[blue|autocite],+p[blue|autocite]',
inline: false, // 使用 iframe 模式 inline: false, // 使用 iframe 模式
selector: `#${this.tinymceId}`, selector: `#${this.tinymceId}`,
@@ -509,7 +583,7 @@ export default {
valid_elements: valid_elements:
this.type == 'table' this.type == 'table'
? '*[*]' ? '*[*]'
: `img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,myfigure,mytable,wmath${this.valid_elements}`, // 允许的标签和属性 : `img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,myfigure,mytable,wmath,autocite[data-id|contenteditable|title]${this.valid_elements}`, // 允许的标签和属性
// valid_elements: '*[*]', // 允许所有 HTML 标签 // valid_elements: '*[*]', // 允许所有 HTML 标签
noneditable_editable_class: 'MathJax', noneditable_editable_class: 'MathJax',
height: this.height, height: this.height,
@@ -541,6 +615,22 @@ export default {
font-weight: bold !important; font-weight: bold !important;
} }
autocite {
display: inline-block;
color: rgb(0, 130, 170);
font-weight: bold;
cursor: pointer;
padding: 0 2px;
border-radius: 3px;
background-color: rgba(0, 130, 170, 0.08);
user-select: all;
font-size: 12px;
}
autocite:hover {
background-color: rgba(0, 130, 170, 0.2);
text-shadow: 0 0 3px rgba(0, 130, 170, 0.3);
}
@keyframes blueGlow { @keyframes blueGlow {
0%, 0%,
100% { 100% {
@@ -626,7 +716,27 @@ export default {
let currentPasteImages = []; let currentPasteImages = [];
_this.$commonJS.initEditorButton(_this, ed); _this.$commonJS.initEditorButton(_this, ed);
var currentWmathElement = null; var currentWmathElement = null;
ed.ui.registry.addButton('insertRef', {
text: 'Ref',
tooltip: 'Insert Reference',
onAction: function () {
_this._refBookmark = ed.selection.getBookmark(2);
_this._editingAutocite = null;
_this.$emit('openRefSelector', { currentRefId: null });
}
});
ed.on('click', function (e) { ed.on('click', function (e) {
const autociteEl = e.target.closest('autocite');
if (autociteEl) {
const dataId = autociteEl.getAttribute('data-id');
_this._refBookmark = ed.selection.getBookmark(2);
_this._editingAutocite = autociteEl;
_this.$emit('openRefSelector', { currentRefId: dataId });
return;
}
const wmathElement = e.target.closest('wmath'); const wmathElement = e.target.closest('wmath');
if (wmathElement) { if (wmathElement) {
currentWmathElement = wmathElement; // 保存当前点击的元素 currentWmathElement = wmathElement; // 保存当前点击的元素
@@ -791,14 +901,15 @@ export default {
const editorBody = ed.getBody(); const editorBody = ed.getBody();
ed.dom.select('wmath', editorBody).forEach(function (wmathElement) { ed.dom.select('wmath', editorBody).forEach(function (wmathElement) {
ed.dom.setAttrib(wmathElement, 'contenteditable', 'false'); ed.dom.setAttrib(wmathElement, 'contenteditable', 'false');
// ed.dom.addClass(wmathElement, 'non-editable-wmath');
}); });
_this.renderAutociteInEditor(ed);
e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>'); e.content = e.content.replace(/<strong>/g, '<b>').replace(/<\/strong>/g, '</b>');
e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>'); e.content = e.content.replace(/<em>/g, '<i>').replace(/<\/em>/g, '</i>');
}); });
ed.on('GetContent', function (e) { ed.on('GetContent', function (e) {
e.content = e.content.replace(/<b>/g, '<strong>').replace(/<\/b>/g, '</strong>'); e.content = e.content.replace(/<b>/g, '<strong>').replace(/<\/b>/g, '</strong>');
e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/i>/g, '</em>'); e.content = e.content.replace(/<i>/g, '<em>').replace(/<\/em>/g, '</em>');
e.content = e.content.replace(/<autocite([^>]*)>[^<]*<\/autocite>/gi, '<autocite$1></autocite>');
}); });
}, },
paste_preprocess: function (plugin, args) { paste_preprocess: function (plugin, args) {

View File

@@ -12,11 +12,13 @@
:isAutomaticUpdate="isAutomaticUpdate" :isAutomaticUpdate="isAutomaticUpdate"
@getContent="getContent" @getContent="getContent"
@openLatexEditor="openLatexEditor" @openLatexEditor="openLatexEditor"
@openRefSelector="openRefSelector"
@updateChange="updateChange" @updateChange="updateChange"
:value="value" :value="value"
:chanFerForm="chanFerForm"
:typesettingType="typesettingType" :typesettingType="typesettingType"
class="paste-area text-container" class="paste-area text-container"
:toolbar="!isAutomaticUpdate?['bold italic |customBlue removeBlue|LateX| myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton|searchreplace']:['bold italic |customBlue removeBlue| myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton|searchreplace']" :toolbar="toolbarConfig"
style=" style="
/* white-space: pre-line; */ /* white-space: pre-line; */
line-height: 12px; line-height: 12px;
@@ -36,10 +38,20 @@
<script> <script>
import Tinymce from '@/components/page/components/Tinymce'; import Tinymce from '@/components/page/components/Tinymce';
export default { export default {
props: ['value','isAutomaticUpdate','height','id'], props: ['value', 'isAutomaticUpdate', 'height', 'id', 'chanFerForm'],
components: { components: {
Tinymce Tinymce
}, },
computed: {
toolbarConfig() {
const hasRefs = Array.isArray(this.chanFerForm) && this.chanFerForm.length > 0;
const refBtn = hasRefs ? ' insertRef' : '';
if (!this.isAutomaticUpdate) {
return [`bold italic |customBlue removeBlue|LateX${refBtn}| myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton|searchreplace`];
}
return [`bold italic |customBlue removeBlue${refBtn}| myuppercase myuppercasea Line MoreSymbols|subscript superscript|clearButton|searchreplace`];
}
},
watch: { watch: {
lineStyle() {} lineStyle() {}
}, },
@@ -85,8 +97,16 @@ export default {
this.$refs.tinymceChild1.getContent(type); this.$refs.tinymceChild1.getContent(type);
}, },
getContent(type, content) { getContent(type, content) {
this.$emit('getContent', type, content); this.$emit('getContent', type, content);
},
openRefSelector(data) {
this.$emit('openRefSelector', data);
},
insertAutocite(refId) {
this.$refs.tinymceChild1.insertAutocite(refId);
},
removeAutocite() {
this.$refs.tinymceChild1.removeAutocite();
} }
} }
}; };