From 7527a6ef5402036f8affa1426402f2d094e5e5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=8B=E4=BA=8E=E5=88=9D=E8=A7=81?= <752204717@qq.com> Date: Thu, 9 Apr 2026 09:39:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=82=E8=80=83=E6=96=87=E7=8C=AE=E7=9A=84?= =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/page/GenerateCharts.vue | 111 +++++++++++++++++- .../page/components/Tinymce/index.vue | 52 ++++++-- .../page/components/table/content.vue | 6 + src/components/page/editPublicRefRdit.vue | 54 +++++---- 4 files changed, 188 insertions(+), 35 deletions(-) diff --git a/src/components/page/GenerateCharts.vue b/src/components/page/GenerateCharts.vue index 51deaeb..48b9f85 100644 --- a/src/components/page/GenerateCharts.vue +++ b/src/components/page/GenerateCharts.vue @@ -412,6 +412,7 @@ @openRefSelector="handleOpenRefSelector" :chanFerForm="chanFerForm" :body-cite-id-order="editModalBodyCiteOrder" + :table-link-cite-max-map="tableLinkCiteMaxMap" @editorInput="onEditModalEditorInput" v-if="editVisible" ref="commonContent" @@ -1032,6 +1033,49 @@ export default { const order = this.extractAutociteOrderFromMainList(this.Main_List, this.currentContent.am_id, draft); return order.length > 0 ? order : this.articleCiteIdOrder; }, + /** + * mytable(data-id) -> 该表格中已出现引用的最大全局序号 + * 用于正文链接表格后,后续 [2,3] 按“表内最大序号之后”继续映射(如 33,34) + */ + tableLinkCiteMaxMap() { + const out = {}; + const list = Array.isArray(this.Main_List) ? this.Main_List : []; + if (!list.length) return out; + const order = Array.isArray(this.editModalBodyCiteOrder) ? this.editModalBodyCiteOrder : this.articleCiteIdOrder; + const citeMap = this.buildDisplayCiteMap(order || []); + list.forEach((p) => { + if (!p || Number(p.type) !== 2) return; + const candidates = this.collectCiteHtmlSourcesForMainListItem(p); + const ids = []; + candidates.forEach((raw) => { + extractAutociteIdsFromHtmlString(raw).forEach((id) => { + if (!ids.includes(id)) ids.push(id); + }); + }); + const numsFromIds = ids + .map((id) => Number(citeMap[String(id)])) + .filter((n) => !Number.isNaN(n) && n > 0); + // 兜底:有些表格仍是纯文本 [34](未转 mycite),这里直接取括号数字最大值参与 max + const numsFromPlain = []; + candidates.forEach((raw) => { + this.extractBracketCiteNumbersFromText(raw).forEach((n) => numsFromPlain.push(n)); + }); + const nums = [...numsFromIds, ...numsFromPlain]; + const max = nums.length ? Math.max(...nums) : 0; + if (max <= 0) return; + if (p.am_id != null) out[String(p.am_id)] = max; + if (p.amt_id != null) out[String(p.amt_id)] = max; + if (p.p_main_table_id != null) out[String(p.p_main_table_id)] = max; + if (p.table) { + if (p.table.amt_id != null) out[String(p.table.amt_id)] = max; + if (p.table.am_id != null) out[String(p.table.am_id)] = max; + if (p.table.p_main_table_id != null) out[String(p.table.p_main_table_id)] = max; + if (p.table.table_id != null) out[String(p.table.table_id)] = max; + } + }); + console.log('[tableLinkCiteMaxMap]', out); + return out; + }, /** 表格抽屉内角标:与 Edit Content 同源,按 Main_List + Title/表/Note 合并稿做全文首次出现排序,避免仍用 articleCiteIdOrder 列表下标 [38] */ tableModalBodyCiteOrder() { if (!this.threeVisible || !this.lineStyle || this.lineStyle.am_id == null) { @@ -1728,6 +1772,8 @@ export default { pushRows(t.tableContent); } if (typeof t.note === 'string' && t.note.trim()) out.push(t.note); + // 兜底:不同接口版本的表体字段名不一致,深度扫描 table 对象里所有可能含引用的字符串字段。 + this.collectCiteStringsDeep(t, out); return out; } if (typ === 1 && p.image) { @@ -1744,6 +1790,58 @@ export default { if (p && typeof p.content === 'string' && p.content.trim()) out.push(p.content); return out; }, + /** + * 递归收集对象中的字符串字段,覆盖 html/text/content 等异构字段名。 + * 仅保留看起来可能包含引用信息的片段,避免噪音过大。 + */ + collectCiteStringsDeep(source, out, depth = 0) { + if (!source || depth > 6) return; + if (typeof source === 'string') { + const s = source.trim(); + if (!s) return; + const maybeCite = /<(?:mycite|autocite)\b/i.test(s) || /\[[\d\s,,\-–—]+\]/.test(s); + if (maybeCite) out.push(s); + return; + } + if (Array.isArray(source)) { + source.forEach((item) => this.collectCiteStringsDeep(item, out, depth + 1)); + return; + } + if (typeof source === 'object') { + Object.keys(source).forEach((k) => { + const v = source[k]; + this.collectCiteStringsDeep(v, out, depth + 1); + }); + } + }, + extractBracketCiteNumbersFromText(raw) { + const out = []; + if (!raw || typeof raw !== 'string') return out; + const text = raw.replace(/<[^>]+>/g, ' '); + const re = /\[([\d\s,,\-–—]+)\]/g; + let m; + while ((m = re.exec(text)) !== null) { + const inner = String(m[1] || '').trim().replace(/,/g, ','); + if (!inner) continue; + const range = inner.match(/^(\d+)\s*[-–—]\s*(\d+)$/); + if (range) { + const a = Number(range[1]); + const b = Number(range[2]); + if (!Number.isNaN(a) && !Number.isNaN(b)) { + const lo = Math.min(a, b); + const hi = Math.max(a, b); + for (let i = lo; i <= hi; i++) out.push(i); + } + continue; + } + inner + .split(',') + .map((x) => parseInt(String(x).trim(), 10)) + .filter((n) => !Number.isNaN(n) && n > 0) + .forEach((n) => out.push(n)); + } + return out; + }, /** 与 word.vue 一致:从各段 HTML 中按出现顺序收集 autocite(含表格单元格、表题、表注、图题图注) */ extractAutociteOrderFromMainList(mainList, draftAmId, draftHtml) { const list = Array.isArray(mainList) ? mainList : []; @@ -2172,12 +2270,21 @@ export default { this.saveContent(newContent, mainId); }, handleConfirmLink(selectedMedia) { - const targetId = selectedMedia.select.amt_id || selectedMedia.select.ami_id; + const select = (selectedMedia && selectedMedia.select) || {}; + // 不同列表来源字段不一致:表可能是 amt_id / am_id,图可能是 ami_id / am_id + const targetId = + select.amt_id || + select.ami_id || + select.am_id || + select.p_main_table_id || + select.table_id || + (select.table && + (select.table.amt_id || select.table.am_id || select.table.p_main_table_id || select.table.table_id)); const type = selectedMedia.type; const tagName = `my${type}`; let originalContent = selectedMedia.linkData.content; const label = selectedMedia.linkData.label; - if (!label || !originalContent) return; + if (!label || !originalContent || targetId == null || targetId === '') return; const isAlreadyTagged = label.startsWith(''); let newContent = ''; if (isAlreadyTagged) { diff --git a/src/components/page/components/Tinymce/index.vue b/src/components/page/components/Tinymce/index.vue index e4166c5..96382c7 100644 --- a/src/components/page/components/Tinymce/index.vue +++ b/src/components/page/components/Tinymce/index.vue @@ -84,6 +84,11 @@ export default { type: Array, default: () => [] }, + /** mytable(data-id) -> 该表内已出现引用的最大全局序号(由父组件计算) */ + tableLinkCiteMaxMap: { + type: Object, + default: () => ({}) + }, /** 为 false 时不显示 Ref 工具栏按钮,也不自动在 LateX 后注入 insertRef(用于图表标题等) */ showRefButton: { type: Boolean, @@ -357,7 +362,7 @@ export default { if (!body) return { replaced: 0 }; let replaced = 0; ed.undoManager.transact(() => { - replaced = this._replaceBracketCitesInNode(body, doc, numToId); + replaced = this._replaceBracketCitesInDocOrder(body, doc, numToId, { tableOffset: 0 }); }); this.renderAutociteInEditor(ed); ed.fire('change'); @@ -409,23 +414,41 @@ export default { /* ignore */ } }, - _replaceBracketCitesInNode(node, doc, numToId) { + /** + * 按文档顺序遍历,使「表格链接」后任意后续段落里的 [n] 都能用上该表的最大全局序号偏移。 + * 旧实现只在同一父节点下、MYTABLE 与后续文本为兄弟时才生效,MYTABLE 在上一段、角标在下一段时会失效。 + */ + _replaceBracketCitesInDocOrder(node, doc, numToId, state) { if (node.nodeType === 3) { - return this._processTextNodeForBracketCites(node, doc, numToId); + return this._processTextNodeForBracketCites(node, doc, numToId, state.tableOffset); } if (node.nodeType !== 1) return 0; const name = node.nodeName; - if (name === 'AUTOCITE' || name === 'WMATH' || name === 'SCRIPT' || name === 'STYLE') { + if (name === 'AUTOCITE' || name === 'MYCITE' || name === 'WMATH' || name === 'SCRIPT' || name === 'STYLE') { return 0; } - let total = 0; - const children = Array.from(node.childNodes); - for (let i = 0; i < children.length; i++) { - total += this._replaceBracketCitesInNode(children[i], doc, numToId); + const isMytable = name === 'MYTABLE' || (node.tagName && String(node.tagName).toLowerCase() === 'mytable'); + if (isMytable) { + let total = 0; + Array.from(node.childNodes).forEach((c) => { + total += this._replaceBracketCitesInDocOrder(c, doc, numToId, state); + }); + const tid = (node.getAttribute && node.getAttribute('data-id')) || ''; + const map = this.tableLinkCiteMaxMap || {}; + const tableMax = Number(map[String(tid)]); + console.log('[autolink/mytable]', { tid, tableMax, map }); + if (!Number.isNaN(tableMax) && tableMax > 0) { + state.tableOffset = tableMax; + } + return total; } + let total = 0; + Array.from(node.childNodes).forEach((c) => { + total += this._replaceBracketCitesInDocOrder(c, doc, numToId, state); + }); return total; }, - _processTextNodeForBracketCites(textNode, doc, numToId) { + _processTextNodeForBracketCites(textNode, doc, numToId, tableOffset = 0) { const text = textNode.textContent; const re = /\[([\d\s,,\-–—]+)\]/g; let m; @@ -446,7 +469,16 @@ export default { const ids = []; const seen = new Set(); nums.forEach((n) => { - const id = numToId[n]; + // 表格链接后的局部序号从 tableMax+1 开始接续:1->max+1, 2->max+2 ... + const mappedNo = n > 0 && tableOffset > 0 ? n + tableOffset - 1 : n; + const id = numToId[mappedNo]; + console.log('[autolink/map]', { + rawBracket: m[0], + n, + tableOffset, + mappedNo, + id + }); if (id && !seen.has(id)) { seen.add(id); ids.push(id); diff --git a/src/components/page/components/table/content.vue b/src/components/page/components/table/content.vue index d3ece76..fc1f8a9 100644 --- a/src/components/page/components/table/content.vue +++ b/src/components/page/components/table/content.vue @@ -19,6 +19,7 @@ :value="value" :chanFerForm="chanFerForm" :bodyCiteIdOrder="bodyCiteIdOrder" + :tableLinkCiteMaxMap="tableLinkCiteMaxMap" :typesettingType="typesettingType" class="paste-area text-container" :toolbar="toolbarConfig" @@ -52,6 +53,11 @@ export default { type: Array, default: () => [] }, + /** mytable(data-id) 对应表格内已出现引用的最大全局序号,用于正文中 “See Table X. And see [2,3]” 的偏移映射 */ + tableLinkCiteMaxMap: { + type: Object, + default: () => ({}) + }, /** false:标题等场景不显示 Ref */ showRefButton: { type: Boolean, diff --git a/src/components/page/editPublicRefRdit.vue b/src/components/page/editPublicRefRdit.vue index 4f37032..5cab124 100644 --- a/src/components/page/editPublicRefRdit.vue +++ b/src/components/page/editPublicRefRdit.vue @@ -71,6 +71,7 @@ Special note: If the number of authors is 6 or fewer, all authors should be listed. -
+
Select all Select none @@ -173,7 +173,9 @@

- {{ scope.row.author }} .  {{ scope.row.joura }}.  {{ + scope.row.joura + }}{{ scope.row.dateno }}.

@@ -181,13 +183,16 @@
-

{{ scope.row.author }} . {{ scope.row.dateno }}. 

+

+ {{ scope.row.author }} . {{ + scope.row.dateno + }}. 
+

{{ scope.row.isbn }}

-

@@ -242,7 +247,7 @@
-
+
Select all Select none { - return `${match}`; - }); - } -, + getCurrentRoute() { + this.canDelete = !['/articleListEditor_B1'].includes(this.$route.path); + }, + formatTitle(title) { + if (!title) return ''; + // 使用正则匹配,'gi' 表示全局匹配且不区分大小写 + // \b 确保是完整单词匹配,防止误伤含有这些字母的其他单词 + const reg = /\b(Retracted|Retraction)\b/gi; + + return title.replace(reg, (match) => { + return `${match}`; + }); + }, getJournalDateno(dateno, type) { if (dateno && typeof dateno === 'string') { const hasInvalidColon = !dateno.includes(':') || (dateno.includes(':') && dateno.split(':').pop().trim() === ''); @@ -682,7 +689,7 @@ export default { .then((res) => { if (res.status == 1) { return res.data; - } + } throw res.msg; }) .catch((err) => { @@ -697,6 +704,7 @@ export default { return {}; }, init(e) { + this.getCurrentRoute(); this.chanFerForm = e; this.bijiao(); ////console.log('更新更新')