This commit is contained in:
2026-04-10 15:53:15 +08:00
parent 0a56b16fe4
commit d613aa7d0d
10 changed files with 796 additions and 139 deletions

View File

@@ -102,6 +102,22 @@ export default {
})
},
/**
* POST x-www-form-urlencoded数组字段序列化为 list[]=a&list[]=b兼容 PHP 批量接口)
*/
postFormBracket(url, params) {
return new Promise((resolve, reject) => {
service
.post(url, qs.stringify(params, { arrayFormat: 'brackets' }))
.then((res) => {
resolve(res.data)
})
.catch((err) => {
reject(err)
})
})
},
/**
* post方法对应post请求
* @param {String} url [请求的url地址]

View File

@@ -1164,6 +1164,7 @@ colTitle: 'Template title',
notFoundById: 'No reference found for citation ID {id}',
selectRef: 'Select Reference',
reference: 'Reference',
originalOrder: 'Original order',
uncited: 'Uncited',
cancel: 'Cancel',
confirm: 'Confirm',
@@ -1178,7 +1179,10 @@ colTitle: 'Template title',
removeRefNeedClickCite: 'Click a citation in the text first, then choose Reference remove.',
quickPickPlaceholder: 'Enter e.g. [5, 6, 10-15] to auto-select',
quickPickApply: 'Link References',
quickPickClear: 'Clear selection'
quickPickClear: 'Clear selection',
currentCiteNo: 'Current',
locateInBody: 'Click to scroll to citation in text',
locateInRefHint: 'Highlight this entry in the list below'
}

View File

@@ -1149,6 +1149,7 @@ const zh = {
notFoundById: '未查询到编号{id}相关参考文献',
selectRef: '选择参考文献',
reference: '参考文献',
originalOrder: '原排序',
uncited: '未引用',
cancel: '取消',
confirm: '确认',
@@ -1163,7 +1164,10 @@ const zh = {
removeRefNeedClickCite: '请先在正文中点击要删除的引用角标,再点「移除参考文献」。',
quickPickPlaceholder: '输入如 [5, 6, 10-15] 自动勾选对应参考文献',
quickPickApply: '链接参考文献',
quickPickClear: '清空勾选'
quickPickClear: '清空勾选',
currentCiteNo: '当前序号',
locateInBody: '点击定位正文角标',
locateInRefHint: '在下方列表中高亮该条'
}

View File

@@ -136,16 +136,7 @@
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
</div>
</div>
<div class="content_box mt20 stepbox">
<!-- 文章引用 -->
<div class="con">
<h4 class="con-title">{{ this.$t('PreAccept.step2') }}</h4>
<p style="color: #505050; font-size: 14px; padding: 20px; box-sizing: border-box">
<el-button @click="goGenerateCharts(thisArtcleId)" icon="el-icon-edit" type="text">Edit</el-button>
</p>
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
</div>
</div>
<div class="content_box mt20 stepbox">
<!-- 文章引用 -->
<div class="con">
@@ -170,7 +161,16 @@
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
</div>
</div>
<div class="content_box mt20 stepbox">
<!-- 文章引用 -->
<div class="con">
<h4 class="con-title">{{ this.$t('PreAccept.step2') }}</h4>
<p style="color: #505050; font-size: 14px; padding: 20px; box-sizing: border-box">
<el-button @click="goGenerateCharts(thisArtcleId)" icon="el-icon-edit" type="text">Edit</el-button>
</p>
<!-- <div v-else style="padding: 20px; box-sizing: border-box"></div> -->
</div>
</div>
<!-- 答疑 -->
<div class="mt20 helpcontent">
<div class="flexbox">

View File

@@ -595,6 +595,17 @@
</p>
</template>
</el-table-column>
<el-table-column :label="$t('wordCite.originalOrder')" width="120" align="center">
<template slot-scope="scope">
<span>{{
scope.row.old_index != null && scope.row.old_index !== ''
? scope.row.old_index+1
: scope.row.old_index != null && scope.row.old_index !== ''
? scope.row.old_index+1
: '—'
}}</span>
</template>
</el-table-column>
<el-table-column align="center" :width="'200'">
<div slot-scope="scope">
<div class="operation" style="">
@@ -890,6 +901,8 @@ export default {
refSelectorSource: 'commonContent',
/** 表格抽屉内合并稿防抖:按全文首次出现顺序更新 articleCiteIdOrder避免角标停留在列表序号 [38] */
_tableReorderTimer: null,
/** 最近一次 getReferList 返回的 p_refer_id 顺序;与当前 chanFerForm 不一致时回写 batchUpdateRefer */
_lastReferListApiOrder: null,
/** 打开选择器时若带 currentRefIds编辑已有引用排序用「传值计算的顺序」关闭后清空 */
refSelectorContextIds: [],
/** 选择参考文献弹窗:按 # 序号快速勾选,如 [5, 6, 10-15] */
@@ -1496,6 +1509,7 @@ export default {
p_article_id: this.p_article_id
})
.then((res) => {
this._lastReferListApiOrder = this.referIdOrderSnapshot(res.data && res.data.refers).slice();
this.chanFerForm = res.data.refers;
this.chanFerFormRepeatList = Object.values(res.data.repeat || {});
for (let i = 0; i < this.chanFerForm.length; i++) {
@@ -1522,6 +1536,8 @@ export default {
}
/** getReferList 会整表覆盖 chanFerForm需再按正文首次出现顺序对齐否则下方列表与 [n] 脱节 */
this.applyRefOrderAfterFetchReferList();
/** 正文序与接口序不一致时回写Main_List 未就绪时可能无变化getDate 后会再比一次) */
this.scheduleTryBatchSyncReferOrderIfOutOfSync();
});
})
.catch((err) => {
@@ -1774,6 +1790,69 @@ export default {
if (sig(next) === sig(refs)) return;
this.chanFerForm = next;
},
/**
* 将当前 chanFerForm 全文同步到后端(顺序 + 各字段内容与 getReferList 行结构一致)。
* 接口api/References/batchUpdateReferp_article_id + listJSON 字符串,文献对象数组,顺序即保存序)
*/
syncBatchReferenceOrderToServer() {
const pid = this.p_article_id;
if (pid == null || pid === '') return Promise.resolve();
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
if (refs.length === 0) return Promise.resolve();
let listJson;
try {
listJson = JSON.stringify(JSON.parse(JSON.stringify(refs)));
} catch (e) {
return Promise.resolve();
}
return this.$api
.post('api/References/batchUpdateRefer', {
p_article_id: String(pid),
list: listJson
})
.then((res) => {
const ok = res && (res.code === 0 || res.code === 1 || res.status === 1);
if (ok) {
this._lastReferListApiOrder = this.referIdOrderSnapshot(this.chanFerForm).slice();
}
if (!ok && res && (res.msg || res.message)) {
console.warn('[batchUpdateRefer]', res.msg || res.message);
}
return res;
})
.catch((err) => {
console.warn('[batchUpdateRefer] request failed', err);
});
},
/** 从 getReferList 原始 refers 提取 p_refer_id 顺序(字符串,便于比较) */
referIdOrderSnapshot(refs) {
return (Array.isArray(refs) ? refs : [])
.map((r) => (r && r.p_refer_id != null ? String(r.p_refer_id) : ''))
.filter(Boolean);
},
/** 当前 chanFerForm 顺序与 _lastReferListApiOrder 不一致则调用 batchUpdateRefer */
tryBatchSyncReferOrderIfOutOfSync() {
if (this._lastReferListApiOrder == null) return;
const track = this._lastReferListApiOrder.map(String);
const cur = this.referIdOrderSnapshot(this.chanFerForm);
if (cur.length === 0) return;
const same = track.length === cur.length && track.every((id, i) => id === cur[i]);
if (!same) {
this.syncBatchReferenceOrderToServer();
}
},
/**
* 等 applyRefOrder / syncRefOrder / 表格抽屉内 nextTick 跑完后再比对顺序。
*/
scheduleTryBatchSyncReferOrderIfOutOfSync() {
this.$nextTick(() => {
this.$nextTick(() => {
this.$nextTick(() => {
this.tryBatchSyncReferOrderIfOutOfSync();
});
});
});
},
extractBracketCiteNumbersFromText(raw) {
const out = [];
if (!raw || typeof raw !== 'string') return out;
@@ -2278,6 +2357,9 @@ export default {
/** 以接口回写后的 Main_List 再对齐一次;稿面 word 会由 contentList 监听触发 syncRefOrder */
this.$nextTick(() => {
this.reorderReferencesFromMainListBody(null, null);
this.$nextTick(() => {
this.syncBatchReferenceOrderToServer();
});
});
} else {
loading.close();
@@ -3294,6 +3376,8 @@ export default {
/** 正文加载后按 Main_List 扫出全文首次出现顺序,写入 articleCiteIdOrder弹窗角标与稿面一致 */
this.$nextTick(() => {
this.reorderReferencesFromMainListBody(null, null);
/** getReferList 早于 Main_List 时在此才完成正文序重排,与接口序不一致则回写 */
this.scheduleTryBatchSyncReferOrderIfOutOfSync();
});
loading.close();
});
@@ -3519,6 +3603,9 @@ export default {
if (w && typeof w.syncRefOrder === 'function') {
w.syncRefOrder();
}
this.$nextTick(() => {
this.syncBatchReferenceOrderToServer();
});
});
} else {
this.$message.error(res.msg);
@@ -3571,6 +3658,9 @@ export default {
if (w && typeof w.syncRefOrder === 'function') {
w.syncRefOrder();
}
this.$nextTick(() => {
this.syncBatchReferenceOrderToServer();
});
});
} else {
this.$message.error(res.msg);

View File

@@ -332,11 +332,11 @@ export default {
// refName: 'setFiveRef',
// rongCont: 'Modify the article body.'
// },
{
name: 'Text Proofread',
refName: 'setThreeRef',
rongCont: 'HTML layout.'
}
// {
// name: 'Text Proofread',
// refName: 'setThreeRef',
// rongCont: 'HTML layout.'
// }
// {
// name: 'Create Build',
// refName: 'setSevenRef',

View File

@@ -218,6 +218,8 @@ export default {
refSelectorIsEdit: false,
refSelectedRows: [],
refSelectorSource: 'commonContent',
/** 最近一次 getReferList 返回的 p_refer_id 顺序;与当前 chanFerForm 不一致时回写 batchUpdateRefer */
_lastReferListApiOrder: null,
/** 打开选择器时若带 currentRefIds编辑已有引用排序用「传值计算的顺序」关闭后清空 */
refSelectorContextIds: [],
/** 选择参考文献弹窗:按 # 序号快速勾选,如 [5, 6, 10-15] */
@@ -448,6 +450,7 @@ export default {
p_article_id: this.p_article_id
})
.then((res) => {
this._lastReferListApiOrder = this.referIdOrderSnapshot(res.data && res.data.refers).slice();
this.chanFerForm = res.data.refers;
this.chanFerFormRepeatList = Object.values(res.data.repeat || {});
for (let i = 0; i < this.chanFerForm.length; i++) {
@@ -474,6 +477,7 @@ export default {
}
/** getReferList 会整表覆盖 chanFerForm需再按正文首次出现顺序对齐否则下方列表与 [n] 脱节 */
this.applyRefOrderAfterFetchReferList();
this.scheduleTryBatchSyncReferOrderIfOutOfSync();
});
})
.catch((err) => {
@@ -647,6 +651,64 @@ export default {
if (sig(next) === sig(refs)) return;
this.chanFerForm = next;
},
/**
* 将当前 chanFerForm 全文同步到后端(顺序 + 各字段)。
* 接口api/References/batchUpdateReferp_article_id + listJSON 字符串,文献对象数组)
*/
syncBatchReferenceOrderToServer() {
const pid = this.p_article_id;
if (pid == null || pid === '') return Promise.resolve();
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
if (refs.length === 0) return Promise.resolve();
let listJson;
try {
listJson = JSON.stringify(JSON.parse(JSON.stringify(refs)));
} catch (e) {
return Promise.resolve();
}
return this.$api
.post('api/References/batchUpdateRefer', {
p_article_id: String(pid),
list: listJson
})
.then((res) => {
const ok = res && (res.code === 0 || res.code === 1 || res.status === 1);
if (ok) {
this._lastReferListApiOrder = this.referIdOrderSnapshot(this.chanFerForm).slice();
}
if (!ok && res && (res.msg || res.message)) {
console.warn('[batchUpdateRefer]', res.msg || res.message);
}
return res;
})
.catch((err) => {
console.warn('[batchUpdateRefer] request failed', err);
});
},
referIdOrderSnapshot(refs) {
return (Array.isArray(refs) ? refs : [])
.map((r) => (r && r.p_refer_id != null ? String(r.p_refer_id) : ''))
.filter(Boolean);
},
tryBatchSyncReferOrderIfOutOfSync() {
if (this._lastReferListApiOrder == null) return;
const track = this._lastReferListApiOrder.map(String);
const cur = this.referIdOrderSnapshot(this.chanFerForm);
if (cur.length === 0) return;
const same = track.length === cur.length && track.every((id, i) => id === cur[i]);
if (!same) {
this.syncBatchReferenceOrderToServer();
}
},
scheduleTryBatchSyncReferOrderIfOutOfSync() {
this.$nextTick(() => {
this.$nextTick(() => {
this.$nextTick(() => {
this.tryBatchSyncReferOrderIfOutOfSync();
});
});
});
},
/** 编辑弹窗内正文一变立即按全文合并稿重排参考文献(不再防抖,选中/输入后列表马上跟正文一致) */
scheduleReorderFromEditModal(html) {
if (!this.editVisible || !this.currentContent || this.currentContent.am_id == null) return;
@@ -1066,6 +1128,9 @@ export default {
/** 以接口回写后的 Main_List 再对齐一次;稿面 word 会由 contentList 监听触发 syncRefOrder */
this.$nextTick(() => {
this.reorderReferencesFromMainListBody(null, null);
this.$nextTick(() => {
this.syncBatchReferenceOrderToServer();
});
});
} else {
loading.close();
@@ -2078,6 +2143,10 @@ export default {
if (this.$refs.catalogue) {
await this.$refs.catalogue.getCatalogueList();
}
this.$nextTick(() => {
this.reorderReferencesFromMainListBody(null, null);
this.scheduleTryBatchSyncReferOrderIfOutOfSync();
});
loading.close();
});
// }, 1000);
@@ -2304,6 +2373,9 @@ export default {
if (w && typeof w.syncRefOrder === 'function') {
w.syncRefOrder();
}
this.$nextTick(() => {
this.syncBatchReferenceOrderToServer();
});
});
} else {
this.$message.error(res.msg);
@@ -2356,6 +2428,9 @@ export default {
if (w && typeof w.syncRefOrder === 'function') {
w.syncRefOrder();
}
this.$nextTick(() => {
this.syncBatchReferenceOrderToServer();
});
});
} else {
this.$message.error(res.msg);

View File

@@ -134,6 +134,37 @@ export default {
hasReferencesForAutoLink() {
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
return refs.some((r) => r && r.p_refer_id != null && String(r.p_refer_id).trim() !== '');
},
/**
* 表格编辑器专用:接口文献行的 old_index0 起)+1 = 单元格里 [n] 对应的全局显示序号,再映射到 p_refer_id。
* 无 old_index 时返回空对象,自动匹配回退为正文 citeMap。
*/
tableBracketNumToRefIdMap() {
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
const map = {};
refs.forEach((r) => {
if (!r || r.p_refer_id == null) return;
const oi = r.old_index != null && r.old_index !== '' ? r.old_index : r.oldIndex;
if (oi == null || oi === '') return;
const n = Number(oi);
if (Number.isNaN(n)) return;
map[n + 1] = String(r.p_refer_id);
});
return map;
},
/** p_refer_id → 表格角标序号old_index+1用于表格内渲染 [n] 与排序 */
tableRefIdToBracketNum() {
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
const m = {};
refs.forEach((r) => {
if (!r || r.p_refer_id == null) return;
const oi = r.old_index != null && r.old_index !== '' ? r.old_index : r.oldIndex;
if (oi == null || oi === '') return;
const num = Number(oi);
if (Number.isNaN(num)) return;
m[String(r.p_refer_id)] = num + 1;
});
return m;
}
},
data() {
@@ -271,7 +302,7 @@ export default {
.map((s) => s.trim())
.filter(Boolean);
},
/** 与 word.vue renderCiteLabelstooltip 行按引用序号排序 */
/** 与 word.vue renderCiteLabels合并角标 id 按 citeMap 序号排序 */
sortAutociteIdsByCiteNumber(ids) {
const uniq = [...new Set(ids.map(String))];
const map = this.citeMap || {};
@@ -316,10 +347,62 @@ export default {
});
return map;
},
/** 解析 [1]、[1,2]、[14] 等括号内数字列表(不含方括号) */
/** 自动匹配 [n]:表格内用 old_index+1 映射mytable 之后段落仍用全局 citeMap */
_getBracketNumToIdMaps() {
const globalMap = this.buildNumToRefIdMap();
if (this.type !== 'table') {
return { primary: globalMap, afterTable: globalMap };
}
const tm = this.tableBracketNumToRefIdMap || {};
const has = Object.keys(tm).length > 0;
return {
primary: has ? tm : globalMap,
afterTable: globalMap
};
},
sortAutociteIdsByTableBracketNumber(ids) {
const uniq = [...new Set(ids.map(String))];
const numById = this.tableRefIdToBracketNum || {};
return uniq.sort((a, b) => {
const na = numById[a];
const nb = numById[b];
const ha = na != null && na !== '' && !Number.isNaN(Number(na));
const hb = nb != null && nb !== '' && !Number.isNaN(Number(nb));
if (ha && hb) return Number(na) - Number(nb);
if (ha) return -1;
if (hb) return 1;
return String(a).localeCompare(String(b));
});
},
_sortAutociteIdsForDisplay(ids) {
if (this.type === 'table' && Object.keys(this.tableBracketNumToRefIdMap || {}).length > 0) {
return this.sortAutociteIdsByTableBracketNumber(ids);
}
return this.sortAutociteIdsByCiteNumber(ids);
},
_sortIdsAfterBracketMatch(ids, tableOffset) {
if (
this.type === 'table' &&
tableOffset === 0 &&
Object.keys(this.tableBracketNumToRefIdMap || {}).length > 0
) {
return this.sortAutociteIdsByTableBracketNumber(ids);
}
return this.sortAutociteIdsByCiteNumber(ids);
},
/** 解析 [1]、[1,2]、[14]、[1, 23, 4] 等括号内数字列表(不含方括号) */
parseBracketInnerToNumbers(inner) {
if (!inner || typeof inner !== 'string') return [];
const t = inner.trim().replace(//g, ',');
// 先按逗号拆段,再对每段解析单号或区间;避免 parseInt('41-42') 只得到 41
if (/[,]/.test(t)) {
const parts = t.split(/[,]/).map((s) => String(s).trim()).filter(Boolean);
const out = [];
parts.forEach((part) => {
out.push(...this.parseBracketInnerToNumbers(part));
});
return out;
}
const range = t.match(/^(\d+)\s*[-–—]\s*(\d+)$/);
if (range) {
const a = Number(range[1]);
@@ -331,12 +414,6 @@ export default {
for (let i = lo; i <= hi; i++) out.push(i);
return out;
}
if (/[,]/.test(t)) {
return t
.split(/[,]/)
.map((x) => parseInt(String(x).trim(), 10))
.filter((n) => !Number.isNaN(n));
}
const n = parseInt(t, 10);
return Number.isNaN(n) ? [] : [n];
},
@@ -352,8 +429,8 @@ export default {
this.$message.warning(this.$t('wordCite.noRefs'));
return { replaced: 0 };
}
const numToId = this.buildNumToRefIdMap();
if (Object.keys(numToId).length === 0) {
const maps = this._getBracketNumToIdMaps();
if (Object.keys(maps.primary).length === 0) {
this.$message.warning(this.$t('wordCite.noRefs'));
return { replaced: 0 };
}
@@ -362,7 +439,7 @@ export default {
if (!body) return { replaced: 0 };
let replaced = 0;
ed.undoManager.transact(() => {
replaced = this._replaceBracketCitesInDocOrder(body, doc, numToId, { tableOffset: 0 });
replaced = this._replaceBracketCitesInDocOrder(body, doc, maps, { tableOffset: 0 });
});
this.renderAutociteInEditor(ed);
ed.fire('change');
@@ -377,8 +454,8 @@ export default {
return;
}
const refs = Array.isArray(this.chanFerForm) ? this.chanFerForm : [];
const numToId = this.buildNumToRefIdMap();
if (refs.length && Object.keys(numToId).length) {
const maps = this._getBracketNumToIdMaps();
if (refs.length && Object.keys(maps.primary).length) {
this.$message.info(this.$t('wordCite.matchBracketRefsNone'));
}
},
@@ -418,9 +495,9 @@ export default {
* 按文档顺序遍历,使「表格链接」后任意后续段落里的 [n] 都能用上该表的最大全局序号偏移。
* 旧实现只在同一父节点下、MYTABLE 与后续文本为兄弟时才生效MYTABLE 在上一段、角标在下一段时会失效。
*/
_replaceBracketCitesInDocOrder(node, doc, numToId, state) {
_replaceBracketCitesInDocOrder(node, doc, maps, state) {
if (node.nodeType === 3) {
return this._processTextNodeForBracketCites(node, doc, numToId, state.tableOffset);
return this._processTextNodeForBracketCites(node, doc, maps, state.tableOffset);
}
if (node.nodeType !== 1) return 0;
const name = node.nodeName;
@@ -431,7 +508,7 @@ export default {
if (isMytable) {
let total = 0;
Array.from(node.childNodes).forEach((c) => {
total += this._replaceBracketCitesInDocOrder(c, doc, numToId, state);
total += this._replaceBracketCitesInDocOrder(c, doc, maps, state);
});
const tid = (node.getAttribute && node.getAttribute('data-id')) || '';
const map = this.tableLinkCiteMaxMap || {};
@@ -443,11 +520,12 @@ export default {
}
let total = 0;
Array.from(node.childNodes).forEach((c) => {
total += this._replaceBracketCitesInDocOrder(c, doc, numToId, state);
total += this._replaceBracketCitesInDocOrder(c, doc, maps, state);
});
return total;
},
_processTextNodeForBracketCites(textNode, doc, numToId, tableOffset = 0) {
_processTextNodeForBracketCites(textNode, doc, maps, tableOffset = 0) {
const numToId = tableOffset > 0 ? maps.afterTable : maps.primary;
const text = textNode.textContent;
const re = /\[([\d\s,\-–—]+)\]/g;
let m;
@@ -465,11 +543,24 @@ export default {
skippedSpecial++;
continue;
}
// 任一序号在参考文献中无对应含超出列表、tableOffset 后仍无效)则整段不转换,避免部分匹配
const mapNo = (n) => (n > 0 && tableOffset > 0 ? n + tableOffset - 1 : n);
if (
!nums.length ||
nums.some((n) => {
const mappedNo = mapNo(n);
return !numToId[mappedNo];
})
) {
pieces.push({ type: 'text', s: text.slice(lastIndex, m.index) });
pieces.push({ type: 'text', s: m[0] });
lastIndex = m.index + m[0].length;
continue;
}
const ids = [];
const seen = new Set();
nums.forEach((n) => {
// 表格链接后的局部序号从 tableMax+1 开始接续1->max+1, 2->max+2 ...
const mappedNo = n > 0 && tableOffset > 0 ? n + tableOffset - 1 : n;
const mappedNo = mapNo(n);
const id = numToId[mappedNo];
if (id && !seen.has(id)) {
seen.add(id);
@@ -478,7 +569,7 @@ export default {
});
pieces.push({ type: 'text', s: text.slice(lastIndex, m.index) });
if (ids.length > 0) {
const sorted = this.sortAutociteIdsByCiteNumber(ids);
const sorted = this._sortIdsAfterBracketMatch(ids, tableOffset);
pieces.push({ type: 'cite', ids: sorted });
replaced++;
} else {
@@ -517,8 +608,8 @@ export default {
if (!body) return;
const allAutocites = Array.from(
ed.dom && typeof ed.dom.select === 'function'
? ed.dom.select('mycite', body)
: body.querySelectorAll('mycite')
? ed.dom.select('mycite,autocite', body)
: body.querySelectorAll('mycite, autocite')
);
if (!allAutocites.length) return;
@@ -530,23 +621,30 @@ export default {
});
const citeMap = this.citeMap || {};
const tableNums = this.tableRefIdToBracketNum || {};
const useTableBracketNums = this.type === 'table' && Object.keys(this.tableBracketNumToRefIdMap || {}).length > 0;
allAutocites.forEach((el) => {
ed.dom.setAttrib(el, 'contenteditable', 'false');
el.style.display = '';
const sortedAll = this.sortAutociteIdsByCiteNumber(
this.parseAutociteDataIds(el.getAttribute('data-id'))
);
const sortedAll = this._sortAutociteIdsForDisplay(this.parseAutociteDataIds(el.getAttribute('data-id')));
const validIds = sortedAll.filter((id) => refMap[String(id)]);
if (validIds.length < sortedAll.length) {
ed.dom.setAttrib(el, 'data-id', validIds.length ? validIds.join(',') : '');
}
const sortedIds = validIds.length ? this.sortAutociteIdsByCiteNumber(validIds) : [];
const sortedIds = validIds.length ? this._sortAutociteIdsForDisplay(validIds) : [];
const parts = sortedIds.map((id) => {
const ref = refMap[String(id)];
const no = ref ? citeMap[String(id)] : null;
const num = no != null && no !== '' ? String(no) : null;
const noCite = ref ? citeMap[String(id)] : null;
const noTable =
useTableBracketNums && tableNums[String(id)] != null ? tableNums[String(id)] : null;
const num =
noTable != null && noTable !== '' && !Number.isNaN(Number(noTable))
? String(noTable)
: noCite != null && noCite !== ''
? String(noCite)
: null;
return { id, ref, num };
});
@@ -556,22 +654,6 @@ export default {
.map(Number);
const label = numsForLabel.length > 0 ? this.formatCiteNumbers(numsForLabel) : '';
const lines = parts
.filter((p) => p.ref)
.map((p) => {
const ref = p.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 numLabel = p.num;
if (numLabel) {
return `[${numLabel}] ${content}\nDOI: ${doi}`;
}
return `${content}\nDOI: ${doi}`;
});
if (!label) {
ed.dom.remove(el);
return;
@@ -579,8 +661,18 @@ export default {
el.textContent = `[${label}]`;
el.style.display = '';
ed.dom.setAttrib(el, 'title', lines.join('\n'));
if (el.removeAttribute) el.removeAttribute('title');
ed.dom.setAttrib(el, 'data-cite-missing', null);
if (String(el.tagName || '').toLowerCase() === 'autocite') {
const doc = ed.getDoc();
const nu = doc.createElement('mycite');
nu.setAttribute('data-id', el.getAttribute('data-id') || '');
nu.setAttribute('contenteditable', 'false');
const st = el.getAttribute('style');
if (st) nu.setAttribute('style', st);
nu.textContent = el.textContent;
el.parentNode.replaceChild(nu, el);
}
});
this.padAutociteCaretPlaceholder(ed);
},
@@ -589,7 +681,7 @@ export default {
const doc = ed.getDoc();
const body = doc.body;
if (!body) return;
body.querySelectorAll('mycite').forEach((el) => {
body.querySelectorAll('mycite, autocite').forEach((el) => {
const next = el.nextSibling;
if (next === null) {
el.parentNode.appendChild(doc.createTextNode('\u200b'));
@@ -658,8 +750,10 @@ export default {
/** TinyMCE 会剔除「空」的行内标签;空 mycite 必须在入编辑器前占位,否则合并引用 [13] 等整段消失 */
normalizeAutociteHtmlForEditor(html) {
if (!html || typeof html !== 'string') return html;
// 历史库/表格里可能为 <autocite>,与 mycite 统一,否则 renderAutociteInEditor 扫不到、无效 id 会残留
let out = html.replace(/<\/autocite>/gi, '</mycite>').replace(/<autocite\b/gi, '<mycite');
/** 角标显示一律由 renderAutociteInEditor 根据 data-id 生成,禁止保留库内遗留的 [1-4]、[14] 等旧文案 */
let out = html.replace(/<mycite([^>]*)>[\s\S]*?<\/mycite>/gi, '<mycite$1>&#8203;</mycite>');
out = out.replace(/<mycite([^>]*)>[\s\S]*?<\/mycite>/gi, '<mycite$1>&#8203;</mycite>');
// 外侧:连续空格 / &nbsp; 合并为单个 &nbsp;,避免「普通空格 + &nbsp;」叠成大缝
out = out.replace(/(?:\s|&nbsp;|&#160;)+(?=<mycite\b)/gi, '&nbsp;');
out = out.replace(/(?<=<\/mycite>)(?:\s|&nbsp;|&#160;)+/gi, '&nbsp;');
@@ -1018,7 +1112,7 @@ export default {
valid_elements:
this.type == 'table'
? '*[*]'
: `img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,myfigure,mytable,wmath,mycite[data-id|contenteditable|title|data-cite-missing|style]${this.valid_elements}`, // 允许的标签和属性
: `img[src|alt|width|height],strong,em,sub,sup,blue,table,b,i,myfigure,mytable,wmath,mycite[data-id|contenteditable|data-cite-missing|style]${this.valid_elements}`, // 允许的标签和属性mycite 不使用 title 悬停)
// valid_elements: '*[*]', // 允许所有 HTML 标签
noneditable_editable_class: 'MathJax',
height: this.height,
@@ -1205,7 +1299,7 @@ export default {
});
ed.on('click', function (e) {
const autociteEl = e.target.closest('mycite');
const autociteEl = e.target.closest('mycite') || e.target.closest('autocite');
if (autociteEl) {
const dataIds = _this.parseAutociteDataIds(autociteEl.getAttribute('data-id'));
_this._refBookmark = ed.selection.getBookmark(2);

View File

@@ -997,23 +997,9 @@
</div>
<div
class="row-divider"
v-if="(currentData.type == 0 || currentData.type == 1) && (isEditComment || manuscriptAutociteContext)"
v-if="(currentData.type == 0 || currentData.type == 1) && isEditComment"
></div>
<template
v-if="
manuscriptAutociteContext &&
currentData &&
(currentData.type == 0 || currentData.type == 1 || currentData.type == 2)
"
>
<div class="menu-item menu-autocite-ref" @click.stop="menuAction('editRefCite')">
<i class="el-icon-edit-outline"></i><span>{{ $t('wordCite.modifyRef') }}</span>
</div>
<div class="menu-item danger" @click.stop="menuAction('removeRefCite')">
<i class="el-icon-remove-outline"></i><span>{{ $t('wordCite.removeRefTag') }}</span>
</div>
</template>
<div
class="menu-item menu-link"
v-if="currentData.type == 0 && !['figure', 'table'].includes(currentTag) && !manuscriptAutociteContext"
@@ -1064,15 +1050,72 @@
>
<div class="cite-preview-head">
<span>{{ $t('wordCite.reference') }}</span>
<i class="el-icon-close" @click="hideCitePreview"></i>
<div>
<span
class="cite-preview-action-btn"
:title="$t('wordCite.modifyRef')"
@click.stop="menuAction('editRefCite')"
>
<i class="el-icon-edit-outline"></i>Edit citation
</span>
<span style="margin-left: 20px"
class="cite-preview-action-btn cite-preview-action-danger"
:title="$t('wordCite.removeRefTag')"
@click.stop="menuAction('removeRefCite')"
>
<i class="el-icon-remove-outline"></i>Remove citation
</span>
<i class="el-icon-close" @click="hideCitePreview" style="margin-left: 20px"></i>
</div>
</div>
<div class="cite-preview-body">
<div v-for="(it, idx) in citePreviewItems" :key="`${it.id}-${idx}`" class="cite-preview-item">
<div class="cite-preview-title">
[{{ it.no }}] {{ it.title }}
<div v-if="citePreviewSortedItems.length" class="cite-preview-toolbar">
<div class="cite-preview-nums-wrap">
<span
v-for="(it, idx) in citePreviewSortedItems"
:key="`chip-${it.id}-${idx}`"
:class="['cite-num-chip', { active: idx === citePreviewActiveIndex }]"
:title="$t('wordCite.locateInRefHint')"
@click.stop="onCitePreviewChipClick(idx)"
>{{ it.no }}</span>
</div>
<div v-if="citePreviewSortedItems.length > 1" class="cite-preview-pager">
<span class="cite-preview-pager-text">{{ citePreviewActiveIndex + 1 }} / {{ citePreviewSortedItems.length }}</span>
<i
class="el-icon-arrow-left cite-preview-pager-btn"
:class="{ disabled: citePreviewActiveIndex <= 0 }"
@click.stop="citePreviewStep(-1)"
></i>
<i
class="el-icon-arrow-right cite-preview-pager-btn"
:class="{ disabled: citePreviewActiveIndex >= citePreviewSortedItems.length - 1 }"
@click.stop="citePreviewStep(1)"
></i>
</div>
</div>
<div ref="citePreviewBody" class="cite-preview-body">
<div
v-for="(it, idx) in citePreviewSortedItems"
:key="`body-${it.id}-${idx}`"
:class="['cite-preview-item', { 'is-active': idx === citePreviewActiveIndex }]"
>
<div class="cite-preview-line cite-preview-num-auth">
<span class="cite-preview-num">{{ it.no }}.</span>
<span v-if="it.author" class="cite-preview-auth">{{ it.author }}</span>
</div>
<div class="cite-preview-meta">
{{ it.meta }}
<div v-if="it.title && it.title !== '-'" class="cite-preview-line cite-preview-article-title">
{{ it.title }}
</div>
<div
v-if="it.joura || it.dateno"
class="cite-preview-line cite-preview-journal-row"
>
<em v-if="it.joura" class="cite-preview-journal">{{ it.joura }}</em>
<span v-if="it.joura && it.dateno">&nbsp;</span>
<span v-if="it.dateno" class="cite-preview-dateno">{{ it.dateno }}</span>
</div>
<a v-if="it.doi" class="cite-preview-doi" :href="it.doi" target="_blank">{{ it.doi }}</a>
</div>
@@ -1235,10 +1278,15 @@ export default {
manuscriptAutociteContext: null,
citePreviewVisible: false,
citePreviewItems: [],
/** 合并引用多文献时,顶部序号条当前高亮项(与分页箭头同步) */
citePreviewActiveIndex: 0,
citePreviewStyle: {
position: 'fixed',
left: '0px',
top: '0px',
bottom: 'auto',
width: '',
maxHeight: '',
zIndex: 10001
},
/** 正文 DOM 中 mycite 首次出现顺序(唯一 p_refer_id驱动 citeMap 与参考文献列表排序 */
@@ -1408,6 +1456,24 @@ export default {
});
return map;
},
/** 弹窗内文献按全局序号排序,与稿面角标顺序一致 */
citePreviewSortedItems() {
const items = this.citePreviewItems || [];
return items.slice().sort((a, b) => {
const na = Number(a.no);
const nb = Number(b.no);
if (!Number.isNaN(na) && !Number.isNaN(nb)) return na - nb;
if (!Number.isNaN(na)) return -1;
if (!Number.isNaN(nb)) return 1;
return String(a.no || '').localeCompare(String(b.no || ''));
});
},
citePreviewActiveItem() {
const arr = this.citePreviewSortedItems;
if (!arr.length) return null;
const i = Math.max(0, Math.min(this.citePreviewActiveIndex, arr.length - 1));
return arr[i];
},
sortedProofreadingList() {
const order = [2, 1, 3];
const rank = { 2: 0, 1: 1, 3: 2 };
@@ -1599,22 +1665,6 @@ renderCiteLabels(html) {
const label =
numsForLabel.length > 0 ? this.formatCiteNumbers(numsForLabel) : '';
const lines = parts
.filter((p) => p.ref)
.map((p) => {
const ref = p.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 numLabel = p.num;
if (numLabel) {
return `[${numLabel}] ${content}\nDOI: ${doi}`;
}
return `${content}\nDOI: ${doi}`;
});
const escAttr = (s) =>
String(s || '')
.replace(/&/g, '&amp;')
@@ -1624,8 +1674,7 @@ renderCiteLabels(html) {
return '';
}
const dataIdAttr = escAttr(sortedIds.join(','));
const titleAttr = escAttr(lines.join('\n'));
return `<mycite data-id="${dataIdAttr}" title="${titleAttr}">[${label}]</mycite>`;
return `<mycite data-id="${dataIdAttr}">[${label}]</mycite>`;
})
/** 库内遗留:空 data-id 或仅零宽字符的 mycite 整段去掉 */
.replace(/<mycite[^>]*data-id=""[^>]*>[\s\S]*?<\/mycite>/gi, '');
@@ -1765,6 +1814,7 @@ renderCiteLabels(html) {
if (!hasSelection && !isClickOnParagraph) {
this.bubbleVisible = false;
this.isMenuVisible = false;
this.citePreviewVisible = false;
this.currentData = {};
this.currentId = '';
@@ -2222,8 +2272,67 @@ renderCiteLabels(html) {
hideCitePreview() {
this.citePreviewVisible = false;
this.citePreviewItems = [];
this.citePreviewActiveIndex = 0;
this._citePreviewMyciteEl = null;
this.citePreviewStyle = {
position: 'fixed',
left: '0px',
top: '0px',
bottom: 'auto',
width: '',
maxHeight: '',
zIndex: 10001
};
},
/** 按视口与角标位置计算弹窗 maxHeight、贴下或贴上避免靠页底时裁切 */
placeCitePreviewNear(triggerEl) {
if (!triggerEl || typeof triggerEl.getBoundingClientRect !== 'function') return;
const rect = triggerEl.getBoundingClientRect();
const pad = 12;
const gap = 8;
const popW = 640;
const widthPx = Math.min(popW, Math.max(280, window.innerWidth - pad * 2));
/** 略限制首选高度,避免弹窗占满屏;列表区靠更紧凑的样式展示更多条 */
const maxPref = Math.min(440, window.innerHeight - pad * 2);
const minReadable = 120;
const spaceBelow = window.innerHeight - rect.bottom - pad;
const spaceAbove = rect.top - pad;
let useAbove = false;
let maxH;
if (spaceBelow >= minReadable) {
maxH = Math.min(maxPref, spaceBelow - gap);
} else if (spaceAbove >= minReadable) {
useAbove = true;
maxH = Math.min(maxPref, spaceAbove - gap);
} else {
useAbove = spaceAbove > spaceBelow;
maxH = Math.min(maxPref, (useAbove ? spaceAbove : spaceBelow) - gap);
}
maxH = Math.floor(Math.max(72, maxH));
const left = Math.max(pad, Math.min(rect.left, window.innerWidth - widthPx - pad));
const next = {
position: 'fixed',
left: `${left}px`,
zIndex: 10001,
width: `${widthPx}px`,
maxHeight: `${maxH}px`
};
if (useAbove) {
next.bottom = `${window.innerHeight - rect.top + gap}px`;
next.top = 'auto';
} else {
next.top = `${rect.bottom + gap}px`;
next.bottom = 'auto';
}
this.citePreviewStyle = next;
},
showCitePreviewByAutocite(el, dataId) {
this._citePreviewMyciteEl = el || null;
this.citePreviewActiveIndex = 0;
const ids = String(dataId || '')
.split(',')
.map((s) => s.trim())
@@ -2243,26 +2352,77 @@ renderCiteLabels(html) {
const ref = refMap[String(id)];
if (!ref) return null;
const no = citeMap[String(id)] || '?';
// 标题优先走 Crossref 解析出的 title兜底 refer_frag
const title = (ref.title || ref.refer_frag || '').toString().trim() || '-';
const meta = [ref.author, ref.joura, ref.dateno].filter(Boolean).join(' ').trim();
const author = (ref.author || '').toString().trim();
const title =
(ref.title || '').toString().trim() ||
(ref.refer_frag || '').toString().trim() ||
'-';
const joura = (ref.joura || '').toString().trim();
const dateno = (ref.dateno || '').toString().trim();
const doi = (ref.doilink || ref.doi || ref.isbn || '').toString().trim();
return { id: String(id), no, title, meta, doi };
return { id: String(id), no, author, title, joura, dateno, doi };
})
.filter(Boolean);
if (!items.length) {
this.hideCitePreview();
return;
}
const rect = el.getBoundingClientRect();
this.citePreviewStyle = {
position: 'fixed',
left: `${Math.max(12, Math.min(rect.left, window.innerWidth - 460))}px`,
top: `${Math.min(rect.bottom + 8, window.innerHeight - 220)}px`,
zIndex: 10001
};
this.citePreviewItems = items;
this.citePreviewVisible = true;
this.$nextTick(() => {
this.placeCitePreviewNear(el);
});
},
scrollCitePreviewToBody() {
const el = this._citePreviewMyciteEl;
const sc = this.$refs.scrollDiv;
if (!el || !sc) return;
const top = this.topInScroll(el, sc) - 80;
sc.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
if (el._citeFlashTimer) {
clearTimeout(el._citeFlashTimer);
el._citeFlashTimer = null;
}
el.classList.remove('cite-mycite-flash');
void el.offsetWidth;
el.classList.add('cite-mycite-flash');
el._citeFlashTimer = setTimeout(() => {
el.classList.remove('cite-mycite-flash');
el._citeFlashTimer = null;
}, 1000);
},
scrollCitePreviewToRefRow(pReferId) {
if (pReferId == null || pReferId === '') return;
const target = document.querySelector(`[data-id="ref-${pReferId}"]`);
if (!target) return;
const sc = this.$refs.scrollDiv;
if (!sc) {
this.scrollContainerTo(target, 80);
return;
}
const top = this.topInScroll(target, sc) - 80;
sc.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
},
onCitePreviewChipClick(idx) {
this.citePreviewActiveIndex = idx;
this.$nextTick(() => this.scrollCitePreviewItemIntoView());
},
citePreviewStep(delta) {
const list = this.citePreviewSortedItems;
if (!list.length) return;
let i = this.citePreviewActiveIndex + delta;
i = Math.max(0, Math.min(list.length - 1, i));
if (i === this.citePreviewActiveIndex) return;
this.citePreviewActiveIndex = i;
this.$nextTick(() => this.scrollCitePreviewItemIntoView());
},
scrollCitePreviewItemIntoView() {
const body = this.$refs.citePreviewBody;
if (!body) return;
const row = body.querySelector('.cite-preview-item.is-active');
if (row && typeof row.scrollIntoView === 'function') {
row.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
}
},
escapeHtmlAttr(val) {
return String(val == null ? '' : val).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
@@ -3628,6 +3788,11 @@ renderCiteLabels(html) {
if (Math.abs(newScrollTop - (this.lastScrollTop || 0)) < 10) return;
this.lastScrollTop = newScrollTop;
// 与段落工具栏一致:主稿滚动时关闭 Reference 预览浮层
if (this.citePreviewVisible) {
this.hideCitePreview();
}
this.clearHighlight();
if (!this.isPreview) {
@@ -5204,56 +5369,265 @@ font-weight: bold !important;
}
.cite-preview-pop {
width: 440px;
max-height: 220px;
width: 640px;
max-width: calc(100vw - 24px);
/* max-height 由 placeCitePreviewNear 按视口与角标位置内联计算,避免贴底裁切 */
background: #fff;
border: 1px solid #dcdfe6;
border-radius: 6px;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
overflow: hidden;
display: flex;
flex-direction: column;
font-size: 10px;
}
.cite-preview-head {
height: 32px;
padding: 0 10px;
flex-shrink: 0;
height: 28px;
padding: 0 8px;
border-bottom: 1px solid #ebeef5;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 12px;
color: #606266;
font-size: 11px;
font-weight: 600;
color: #303133;
background: #f8f9fb;
}
.cite-preview-head i {
cursor: pointer;
font-size: 12px;
padding: 2px;
}
.cite-preview-toolbar {
flex-shrink: 0;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 6px;
padding: 4px 8px;
border-bottom: 1px solid #ebeef5;
background: #fafbfc;
}
.cite-preview-nums-wrap {
display: flex;
flex-wrap: wrap;
align-content: flex-start;
align-items: center;
gap: 3px 4px;
flex: 1;
min-width: 0;
max-height: 52px;
overflow-x: hidden;
overflow-y: auto;
padding: 1px 0;
-webkit-overflow-scrolling: touch;
}
.cite-preview-nums-wrap::-webkit-scrollbar {
width: 5px;
height: 5px;
}
.cite-preview-nums-wrap::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
.cite-num-chip {
display: inline-block;
padding: 2px 5px;
font-size: 10px;
line-height: 14px;
min-width: 20px;
text-align: center;
color: #303133;
background: #fff;
border: 1px solid #dcdfe6;
border-radius: 3px;
cursor: pointer;
user-select: none;
}
.cite-num-chip:hover {
border-color: #409eff;
color: #409eff;
}
.cite-num-chip.active {
background: #ecf5ff;
border-color: #409eff;
color: #409eff;
font-weight: 600;
}
.cite-preview-ref-actions {
display: flex;
align-items: center;
gap: 2px;
flex-shrink: 0;
padding-left: 6px;
margin-left: 2px;
border-left: 1px solid #e4e7ed;
align-self: center;
}
.cite-preview-action-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: auto;
height: 22px;
border-radius: 3px;
cursor: pointer;
color: #606266;
font-size: 11px;background: #ecf5ff;
color: #006699;
transition: background 0.15s ease, color 0.15s ease;
}
.cite-preview-action-btn.cite-preview-action-danger {
background: #fef0f0;
color: red;
}
.cite-preview-pager {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
align-self: center;
}
.cite-preview-pager-text {
font-size: 10px;
color: #606266;
min-width: 28px;
text-align: center;
}
.cite-preview-pager-btn {
cursor: pointer;
font-size: 12px;
color: #303133;
padding: 1px;
}
.cite-preview-pager-btn.disabled {
color: #c0c4cc;
cursor: not-allowed;
}
.cite-preview-current {
flex-shrink: 0;
padding: 10px 12px;
border-bottom: 1px solid #ebeef5;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 8px;
cursor: pointer;
user-select: none;
transition: background 0.15s ease;
}
.cite-preview-current:hover {
background: #f5f7fa;
}
.cite-preview-current-label {
font-size: 13px;
color: #606266;
}
.cite-preview-current-no {
font-size: 20px;
font-weight: 700;
color: #303133;
letter-spacing: 0.02em;
}
.cite-preview-locate-tip {
font-size: 12px;
color: #409eff;
}
.cite-preview-body {
max-height: 188px;
flex: 1;
min-height: 0;
overflow: auto;
padding: 8px 10px;
padding: 4px 6px 6px;
scrollbar-width: thin;
}
.cite-preview-body::-webkit-scrollbar {
width: 6px;
}
.cite-preview-body::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
.cite-preview-item {
font-size: 12px;
line-height: 18px;
font-size: 11px;
line-height: 1.35;
color: #303133;
margin-bottom: 8px;
margin-bottom: 2px;
padding: 3px 5px;
border-radius: 3px;
border: 1px solid transparent;
}
.cite-preview-item.is-active {
background: #e8f4ff;
border-color: #a0cfff;
}
.cite-preview-item:last-child {
margin-bottom: 0;
}
.cite-preview-title {
font-weight: 600;
/* 与稿末参考文献列表一致:序号(蓝) + 作者 → 题名 → 斜体期刊 + 年卷期 → DOI 独行 */
.cite-preview-line {
word-break: break-word;
margin-bottom: 2px;
}
.cite-preview-meta {
color: #606266;
word-break: break-word;
.cite-preview-line:last-of-type {
margin-bottom: 0;
}
.cite-preview-num-auth {
line-height: 1.4;
}
.cite-preview-num {
font-weight: 700;
color: #006699;
margin-right: 4px;
}
.cite-preview-auth {
color: #303133;
font-weight: 400;
}
.cite-preview-article-title {
color: #303133;
font-weight: 400;
line-height: 1.4;
}
.cite-preview-journal-row {
color: #303133;
font-size: 10px;
line-height: 1.35;
}
.cite-preview-journal {
font-style: italic;
font-weight: 400;
}
.cite-preview-dateno {
font-style: normal;
font-weight: 400;
}
.cite-preview-doi {
display: block;
margin-top: 4px;
font-size: 10px;
line-height: 1.3;
color: #006699;
text-decoration: none;
word-break: break-all;
}
::v-deep mycite.cite-mycite-flash {
outline: 2px solid #409eff;
outline-offset: 2px;
animation: citeMyciteFlash 0.95s ease;
}
@keyframes citeMyciteFlash {
0%,
100% {
outline-color: #409eff;
}
50% {
outline-color: #67c23a;
}
}
@keyframes blueGlow {
0%,
100% {

View File

@@ -96,11 +96,11 @@
<div class="body-editor-container">
<div class="subject-label" style="margin-bottom: 10px;">{{ $t('mailboxMouldDetail.emailBody') }}:</div>
<TmrEmailEditor
<!-- <TmrEmailEditor
v-model="form.body"
placeholder=""
/>
<!-- <CkeditorMail v-model="form.body" /> -->
/> -->
<CkeditorMail v-model="form.body" />
</div>
</el-card>
</section>