diff --git a/scripts/test-footer.cjs b/scripts/test-footer.cjs new file mode 100644 index 0000000..43f6bcf --- /dev/null +++ b/scripts/test-footer.cjs @@ -0,0 +1,23 @@ +const { Document, Packer } = require('docx'); +const JSZip = require('jszip'); +const { buildManuscriptPageFooter, patchManuscriptPageFootersToXml } = require('../src/utils/exportManuscriptWordFooter.js'); + +(async function () { + const footer = buildManuscriptPageFooter({ + journal: { website: 'https://www.tmrjournals.com/bmec' } + }); + const doc = new Document({ + sections: [ + { + properties: {}, + footers: { default: footer }, + children: [] + } + ] + }); + const buf = await Packer.toBuffer(doc); + let xml = await (await JSZip.loadAsync(buf)).file('word/footer1.xml').async('string'); + console.log('BEFORE PATCH\n', xml); + xml = patchManuscriptPageFootersToXml(xml); + console.log('AFTER PATCH\n', xml); +})(); diff --git a/src/assets/img/tmr-logo.png b/src/assets/img/tmr-logo.png new file mode 100644 index 0000000..665b7db Binary files /dev/null and b/src/assets/img/tmr-logo.png differ diff --git a/src/components/common/langs/en.js b/src/components/common/langs/en.js index bba3675..b130c84 100644 --- a/src/components/common/langs/en.js +++ b/src/components/common/langs/en.js @@ -976,6 +976,13 @@ const en = { sendProgressRunning: 'Sending… {done}/{total} completed', sendProgressAllSuccess: 'All sent successfully ({count})', sendProgressDone: 'Done: {ok} sent, {fail} failed', + sendPreviewTitle: 'Send preview', + sendPreviewSub: 'Review the email each recipient will receive', + sendPreviewCount: '{count} email(s)', + sendPreviewRecipient: 'To', + sendPreviewSubject: 'Subject', + sendPreviewConfirm: 'Confirm send', + sendPreviewRealHint: 'Each recipient will receive a separate email matching the preview above', backToInbox: 'Back to email list', articleContextId: 'Article ID:', articleContextIdPlaceholder: 'Enter article ID', @@ -1018,8 +1025,26 @@ const en = { articleContextRepeatReviewLine: '{n}nd review: {label}', articleContextFinalReviewLine: 'Final decision: {decision}', articleContextReplaceVars: 'Replace template vars', - articleContextReplaceVarsSuccess: 'Replaced {{article_title}} / {{article_sn}}', - articleContextReplaceVarsEmpty: 'Subject or body has no {{article_title}} / {{article_sn}} placeholders', + articleContextReplaceVarsSuccess: 'Replaced template variables (title, SN, name, article_id, final_r_id, etc.)', + articleContextReplaceVarsEmpty: 'Subject or body has no replaceable placeholders (e.g. {{article_title}}, [[name]], {{final_r_id}})', + recipientVarsSendHint: 'Keep placeholders in the body; each recipient gets a separate email with values from the table', + recipientVarsPanelTitle: 'Recipient variables', + recipientVarsPanelSub: 'One email per recipient; placeholders are replaced using the values below when sending', + recipientVarsSharedTitle: 'Shared (same for all recipients on this article)', + recipientVarsPerRecipientTitle: 'Per recipient', + recipientVarsColEmail: 'Recipient', + recipientVarsMissingWarn: '{count} recipient(s) missing name or final_r_id — load article and add from Final tab', + templateVar_name: 'Name [[name]]', + templateVar_article_id: 'Article ID', + templateVar_final_r_id: 'final_r_id', + templateVar_article_title: 'Article title', + templateVar_title: 'Title', + templateVar_manuscript_title: 'Manuscript title', + templateVar_accept_sn: 'SN', + templateVar_article_sn: 'SN', + templateVar_sn: 'SN', + templateVar_journal_name: 'Journal name', + templateVar_journal_url: 'Journal URL', roleFirstAuthor: 'First author', roleCorrespondingAuthor: 'Corresponding author', roleFirstAuthorShort: '1st auth.', diff --git a/src/components/common/langs/zh.js b/src/components/common/langs/zh.js index 05e83dd..f6a89ba 100644 --- a/src/components/common/langs/zh.js +++ b/src/components/common/langs/zh.js @@ -961,6 +961,13 @@ const zh = { sendProgressRunning: '正在发送,已完成 {done}/{total}', sendProgressAllSuccess: '全部发送成功,共 {count} 封', sendProgressDone: '发送完成:成功 {ok} 封,失败 {fail} 封', + sendPreviewTitle: '发送预览', + sendPreviewSub: '请确认每位收件人将收到的邮件内容', + sendPreviewCount: '共 {count} 封', + sendPreviewRecipient: '收件人', + sendPreviewSubject: '主题', + sendPreviewConfirm: '确认发送', + sendPreviewRealHint: '确认后将按上方预览内容,为每位收件人逐封发送', backToInbox: '返回收件箱', articleContextId: '文章 ID:', articleContextIdPlaceholder: '请输入文章 ID', @@ -1003,8 +1010,26 @@ const zh = { articleContextRepeatReviewLine: '第 {n} 次复审:{label}', articleContextFinalReviewLine: '终审:{decision}', articleContextReplaceVars: '替换模板变量', - articleContextReplaceVarsSuccess: '已替换 {{article_title}} / {{article_sn}}', - articleContextReplaceVarsEmpty: '主题或正文不含 {{article_title}}、{{article_sn}} 等占位符', + articleContextReplaceVarsSuccess: '已替换模板变量(标题、SN、name、article_id、final_r_id 等)', + articleContextReplaceVarsEmpty: '主题或正文不含可替换占位符(如 {{article_title}}、[[name]]、{{final_r_id}})', + recipientVarsSendHint: '正文保留占位符,发送时按左侧表格为每人单独替换并发送', + recipientVarsPanelTitle: '收件人变量', + recipientVarsPanelSub: '每人一封邮件,发送时按下列值替换模板中的占位符', + recipientVarsSharedTitle: '公共变量(本稿所有人相同)', + recipientVarsPerRecipientTitle: '每人不同', + recipientVarsColEmail: '收件人', + recipientVarsMissingWarn: '有 {count} 位收件人缺少 name 或 final_r_id,请从终审列表添加或先加载稿件', + templateVar_name: '姓名 [[name]]', + templateVar_article_id: '文章 ID', + templateVar_final_r_id: 'final_r_id', + templateVar_article_title: '稿件标题', + templateVar_title: '标题', + templateVar_manuscript_title: '稿件标题', + templateVar_accept_sn: 'SN', + templateVar_article_sn: 'SN', + templateVar_sn: 'SN', + templateVar_journal_name: '期刊名', + templateVar_journal_url: '期刊网址', roleFirstAuthor: '第一作者', roleCorrespondingAuthor: '通讯作者', roleFirstAuthorShort: '一作', diff --git a/src/components/page/GenerateCharts.vue b/src/components/page/GenerateCharts.vue index 6a93989..71024f6 100644 --- a/src/components/page/GenerateCharts.vue +++ b/src/components/page/GenerateCharts.vue @@ -79,8 +79,10 @@ v-if="Main_List.length > 0" :content="Main_List" :articleId="articleId" + :strippingHeadingNumbers="strippingHeadingNumbers" ref="catalogue" @goToListComment="goToListComment" + @stripHeadingNumbers="stripHeadingNumbersFromOutline" style="width: 100%; height: 100%; padding: 0 0px; box-sizing: border-box; background-color: #fff" > @@ -425,6 +427,22 @@ + + 上标转引用 + + + 引用挪到句号前 + Cancel @@ -447,6 +465,7 @@ import Tinymce from '@/components/page/components/Tinymce'; import bottomTinymce from '@/components/page/components/Tinymce'; import catalogue from '@/components/page/components/table/catalogue.vue'; import { isZyModeEnabled } from '@/utils/zyMode'; +import { collectHeadingNumberStripUpdates } from '@/utils/stripHeadingNumber'; export default { data() { return { @@ -466,6 +485,7 @@ export default { currentId: null, ManuscirptContent: [], mathFormulasList: [], + strippingHeadingNumbers: false, articleId: this.$route.query.id, pArticleId: this.$route.query.p_article_id || '', isShowComment: false, @@ -701,6 +721,34 @@ export default { handleSaveAddContent() { this.$refs.addContent.getTinymceContent('addcontent'); }, + /** 临时:Add Content 内数字上标 → blue 引用标签 */ + handleConvertAddContentSupToBlue() { + const ref = this.$refs.addContent; + if (!ref || typeof ref.convertNumericSuperscriptsToBlue !== 'function') { + this.$message.warning('编辑器未就绪'); + return; + } + const count = ref.convertNumericSuperscriptsToBlue(); + if (count > 0) { + this.$message.success('已转换 ' + count + ' 处数字上标为 blue 引用'); + } else { + this.$message.info('未找到可转换的数字上标(需为上标且内容仅为数字、逗号或连字符)'); + } + }, + /** 临时:Add Content 内 blue 引用挪到句号前 */ + handleMoveAddContentCitationBeforePeriod() { + const ref = this.$refs.addContent; + if (!ref || typeof ref.moveBlueCitationsBeforePeriod !== 'function') { + this.$message.warning('编辑器未就绪'); + return; + } + const count = ref.moveBlueCitationsBeforePeriod(); + if (count > 0) { + this.$message.success('已调整 ' + count + ' 处参考文献位置'); + } else { + this.$message.info('未找到需要调整的 blue 参考文献(句号已在引用之后则不会重复处理)'); + } + }, handleSaveEditProofreadingContent() { this.$refs.addContent.getTinymceContent('addcontent'); }, @@ -991,6 +1039,65 @@ export default { this.$refs.commonWord.goToComment(mainId); }); }, + async stripHeadingNumbersFromOutline(updates) { + const list = updates && updates.length ? updates : collectHeadingNumberStripUpdates(this.Main_List); + if (!list.length) { + this.$message.info('No heading numbers found to remove.'); + return; + } + + try { + await this.$confirm( + 'Remove numbering from ' + list.length + ' heading(s)? (e.g. "1 Introduction" → "Introduction")', + 'Remove Heading Numbers', + { + confirmButtonText: 'Remove', + cancelButtonText: 'Cancel', + type: 'warning' + } + ); + } catch (e) { + return; + } + + this.strippingHeadingNumbers = true; + const loading = this.$loading({ + lock: true, + text: 'Removing heading numbers...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)' + }); + + let successCount = 0; + try { + for (let i = 0; i < list.length; i++) { + const item = list[i]; + let str = String(item.content || '') + .replace(/^

\s*(.*?)\s*<\/p>$/, '$1') + .trim(); + str = str.replace(//gi, ''); + str = await this.$commonJS.decodeHtml(str); + + const res = await this.$api.post(this.urlList.editContent, { + am_id: item.am_id, + content: str + }); + if (res && res.code == 0) { + successCount++; + await this.refreshCurrentContent('content', item.am_id, res.data); + } else { + throw new Error((res && res.msg) || 'Save failed'); + } + } + this.$message.success('Removed numbering from ' + successCount + ' heading(s).'); + } catch (err) { + console.error(err); + this.$message.error((err && err.message) || 'Failed to remove heading numbers.'); + } finally { + loading.close(); + this.strippingHeadingNumbers = false; + } + }, getTables(tables, html) { this.tables = data.map((e, i) => ({ ...e, p_main_table_id: 2141 + i, p_article_id: 2141 })); this.tablesHtml = html; diff --git a/src/components/page/articleAdd.vue b/src/components/page/articleAdd.vue index 543a0f1..5154e07 100644 --- a/src/components/page/articleAdd.vue +++ b/src/components/page/articleAdd.vue @@ -74,29 +74,46 @@ - -

- Upload +
+ +
+ Upload +
+
+ Only Word and compressed files can be uploaded (file format: .docx). +
+
+
+ +

+ Kindly prepare and submit your manuscript in DOCX format using our + + official template + . + Compliance with the template requirements allows us to process your submission more + efficiently and refine the article’s final typesetting to a higher standard. +

-
- Only Word and compressed files can be uploaded (file format: .docx). -
- +
@@ -4365,6 +4382,55 @@ export default { font-size: 13px; } +.manuscript-upload-wrap { + position: relative; + min-height: 32px; +} + +.manuscript-template-notice { + display: flex; + align-items: flex-start; + gap: 8px; + margin-top: 12px; + + padding: 10px 12px; + background: #f5f9fb; + border: 1px solid #e3eef3; + border-left: 3px solid #006699; + border-radius: 4px; +} + +.manuscript-template-notice__icon { + flex-shrink: 0; + margin-top: 2px; + color: #006699; + font-size: 16px; +} + +.manuscript-template-notice p { + margin: 0; + font-size: 13px; + line-height: 1.65; + color: #555; +} + +.template-download-link { + color: #006699; + font-weight: 600; + text-decoration: none; + cursor: pointer; + white-space: nowrap; +} + +.template-download-link:hover { + text-decoration: underline; +} + +.template-download-link .el-icon-download { + font-weight: bold; + margin-right: 2px; +} + .el-collapse-item__content { padding-bottom: 8px !important; } diff --git a/src/components/page/articleEditorialBoard.vue b/src/components/page/articleEditorialBoard.vue index 9ab0578..75b6108 100644 --- a/src/components/page/articleEditorialBoard.vue +++ b/src/components/page/articleEditorialBoard.vue @@ -154,23 +154,40 @@ > - + - + + + + +