From a4cbce2db7e3190904cf5972a67db45c2fc14832 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: Wed, 29 Apr 2026 09:20:47 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Header.vue | 1 + src/components/common/Header2.vue | 1 + src/components/common/langs/en.js | 2 + src/components/common/langs/zh.js | 2 + src/components/page/Login.vue | 4 + src/components/page/autoPromotion.vue | 21 +- .../PromotionFactoryTaskDialog.vue | 807 +++++++++++++++--- src/components/page/editorBorder.vue | 61 +- src/components/page/partyListCorr.vue | 46 +- src/components/page/reviewerList.vue | 45 +- src/components/page/youthList.vue | 43 +- 11 files changed, 917 insertions(+), 116 deletions(-) diff --git a/src/components/common/Header.vue b/src/components/common/Header.vue index 07fbaac..dfb8064 100644 --- a/src/components/common/Header.vue +++ b/src/components/common/Header.vue @@ -176,6 +176,7 @@ export default { localStorage.removeItem('U_role'); localStorage.removeItem('U_id'); localStorage.removeItem('U_name'); + localStorage.removeItem('U_email'); localStorage.removeItem('U_status'); localStorage.removeItem('ms_journal_alias'); localStorage.removeItem('journalTypeData'); diff --git a/src/components/common/Header2.vue b/src/components/common/Header2.vue index e9dcd42..6102e0b 100644 --- a/src/components/common/Header2.vue +++ b/src/components/common/Header2.vue @@ -174,6 +174,7 @@ export default { localStorage.removeItem('U_role'); localStorage.removeItem('U_id'); localStorage.removeItem('U_name'); + localStorage.removeItem('U_email'); localStorage.removeItem('U_status'); localStorage.removeItem('ms_journal_alias'); localStorage.removeItem('journalTypeData'); diff --git a/src/components/common/langs/en.js b/src/components/common/langs/en.js index 1496380..8de3fff 100644 --- a/src/components/common/langs/en.js +++ b/src/components/common/langs/en.js @@ -1217,6 +1217,8 @@ colTitle: 'Template title', factoryExpertYoungBoard: 'Young editorial board', factoryExpertAuthor: 'Author', factoryExpertDb: 'Expert database', + factoryExpertJump: 'View', + factoryOfficialEmailTip: 'For this type, the system uses the official sender email by default. No account selection is required.', factoryScenario: 'Scenario', factoryScenarioPlaceholder: 'Select scenario', factoryScenarioSolicit: 'Invite Submission', diff --git a/src/components/common/langs/zh.js b/src/components/common/langs/zh.js index 08dc441..91bd8a5 100644 --- a/src/components/common/langs/zh.js +++ b/src/components/common/langs/zh.js @@ -1202,6 +1202,8 @@ const zh = { factoryExpertYoungBoard: '青年编委', factoryExpertAuthor: '作者', factoryExpertDb: 'expert库', + factoryExpertJump: '查看', + factoryOfficialEmailTip: '此类型默认使用系统官方邮箱发送,无需选择邮箱账号。', factoryScenario: '场景', factoryScenarioPlaceholder: '请选择场景', factoryScenarioSolicit: '约稿', diff --git a/src/components/page/Login.vue b/src/components/page/Login.vue index bb61d01..e50785d 100644 --- a/src/components/page/Login.vue +++ b/src/components/page/Login.vue @@ -215,6 +215,8 @@ localStorage.setItem('U_role', 'superadmin'); localStorage.setItem('U_name', res.userinfo.account); localStorage.setItem('U_id', res.userinfo.user_id); + localStorage.setItem('U_email', ''); + this.$router.push('/'); } else if (res.data.roles.includes('editor')) { @@ -222,6 +224,7 @@ localStorage.setItem('U_role', res.data.roles); localStorage.setItem('U_name', res.data.userinfo.account); localStorage.setItem('U_id', res.data.userinfo.user_id); + localStorage.setItem('U_email', res.data.userinfo.email); this.$router.push('/'); } else { localStorage.setItem('U_status', '2'); //其余的身份 @@ -229,6 +232,7 @@ localStorage.setItem('U_name', res.data.userinfo.account); localStorage.setItem('U_id', res.data.userinfo.user_id); localStorage.setItem('U_relname', res.data.userinfo.realname); + localStorage.setItem('U_email', res.data.userinfo.email); this.$router.push('/'); // this.roleVisible = true; // this.user_cap = res.data.roles; diff --git a/src/components/page/autoPromotion.vue b/src/components/page/autoPromotion.vue index 77c0a8c..aebbe41 100644 --- a/src/components/page/autoPromotion.vue +++ b/src/components/page/autoPromotion.vue @@ -82,6 +82,12 @@ > {{ taskCard.templateName || 'No Template Configured' }} +
+ Type : + {{ taskCard.expertTypeLabel || '-' }} +
-
+
Country : @@ -385,6 +391,8 @@ export default { const journalId = item.journal_id || item.id; let journalObj = { journal_id: journalId, + abbr: item.abbr || '', + journal_icon: item.journal_icon || '', title: item.title || item.journal_title || item.name || `Journal ${journalId}`, solicit: { enabled: false, @@ -450,6 +458,8 @@ export default { taskId: task.promotion_factory_id || '', type: type, typeLabel: this.mapFactoryTaskTypeLabel(type), + expertType: task && task.expert_type != null ? String(task.expert_type) : '', + expertTypeLabel: this.mapFactoryExpertTypeLabel(task && task.expert_type != null ? String(task.expert_type) : ''), enabled: enabled, switchLoading: false, initialized: true, @@ -567,6 +577,15 @@ export default { if (t === '4') return this.$t('autoPromotion.autoSolicit'); return this.$t('autoPromotion.autoSolicit'); }, + mapFactoryExpertTypeLabel(expertType) { + const t = String(expertType || '').trim(); + if (t === '1') return this.$t('autoPromotion.factoryExpertChief'); + if (t === '2') return this.$t('autoPromotion.factoryExpertBoard'); + if (t === '3') return this.$t('autoPromotion.factoryExpertYoungBoard'); + if (t === '4') return this.$t('autoPromotion.factoryExpertAuthor'); + if (t === '5') return this.$t('autoPromotion.factoryExpertDb'); + return '-'; + }, getJournalDisplayTasks(journal) { const list = journal && Array.isArray(journal.factoryTasks) ? journal.factoryTasks : []; return list; diff --git a/src/components/page/components/autoPromotion/PromotionFactoryTaskDialog.vue b/src/components/page/components/autoPromotion/PromotionFactoryTaskDialog.vue index 5275d6e..3d649fb 100644 --- a/src/components/page/components/autoPromotion/PromotionFactoryTaskDialog.vue +++ b/src/components/page/components/autoPromotion/PromotionFactoryTaskDialog.vue @@ -35,30 +35,62 @@

1. {{ $t('autoPromotion.factoryJournal') }}1. {{ $t('autoPromotion.factoryJournal') }} & {{ $t('autoPromotion.factoryExpertType') }}

-
-
- +
+ +
+
- - +
+ +
+
+
+ +
+
+
{{ j.abbr || j.title }}
+
-
+ +
+
{{ $t('autoPromotion.factoryExpertType') }}
+
+
+ + {{ opt.label }} + + ({{ opt.count }}) + + + {{ $t('autoPromotion.factoryExpertJump') }} + + +
+
+
+
@@ -80,6 +112,8 @@
+ +

@@ -93,17 +127,18 @@

@@ -140,25 +175,34 @@
-
- - - - - - - - + + +
+

+ + + 4. {{ $t('autoPromotion.selectPromotionCountry') }} + +

+
+ +
+ + {{ $t('autoPromotion.countryQuickZone1') }} + {{ $t('autoPromotion.countryQuickZone2') }} + {{ $t('autoPromotion.countryQuickZone3') }} + {{ $t('autoPromotion.countryQuickChina') }} + {{ $t('autoPromotion.countryQuickIndia') }} + +
-
+

- 4. {{ $t('autoPromotion.selectPromotionFields') }} + 5. {{ $t('autoPromotion.selectPromotionFields') }} {{ $t('autoPromotion.selectedCount', { count: factoryFieldIds.length }) }} @@ -184,10 +228,10 @@
{{ label }}
-
+
{{ $t('autoPromotion.factoryPromotionFieldsBlockTip') }} @@ -195,27 +239,6 @@

-
-

- - - 5. {{ $t('autoPromotion.selectPromotionCountry') }} - -

-
- -
- - {{ $t('autoPromotion.countryQuickZone1') }} - {{ $t('autoPromotion.countryQuickZone2') }} - {{ $t('autoPromotion.countryQuickZone3') }} - {{ $t('autoPromotion.countryQuickChina') }} - {{ $t('autoPromotion.countryQuickIndia') }} - -
-
-
-
@@ -327,6 +350,16 @@ sendLimitFromApi: false, factoryType: '1', expertType: '5', + expertTypeCounts: { + chief: null, + board: null, + young: null, + author: null, + reviewer: null, + expertDb: null + }, + expertTypeCountsLoading: false, + expertTypeCountsReqSeq: 0, factoryStartPromotion: true, factoryConfig: { defaultTemplateId: '', defaultStyleId: '' }, factoryTemplateName: '', @@ -355,13 +388,72 @@ } }, factorySteps() { - return [ + const steps = [ { title: this.$t('autoPromotion.factoryStepNav1Title'), desc: this.$t('autoPromotion.factoryStepNav1Desc') }, { title: this.$t('autoPromotion.factoryStepNav2Title'), desc: this.$t('autoPromotion.factoryStepNav2Desc') }, - { title: this.$t('autoPromotion.factoryStepNav3Title'), desc: this.$t('autoPromotion.factoryStepNav3Desc') }, - { title: this.$t('autoPromotion.factoryStepNav4Title'), desc: this.$t('autoPromotion.factoryStepNav4Desc') }, - { title: this.$t('autoPromotion.factoryStepNav5Title'), desc: this.$t('autoPromotion.factoryStepNav5Desc') } + // { title: this.$t('autoPromotion.factoryExpertType'), desc: this.$t('autoPromotion.factoryExpertTypePlaceholder') }, + { title: this.$t('autoPromotion.factoryStepNav3Title'), desc: this.$t('autoPromotion.factoryStepNav3Desc') } ]; + if (this.isExpertDatabaseType) { + steps.push( + { title: this.$t('autoPromotion.factoryStepNav4Title'), desc: this.$t('autoPromotion.factoryStepNav4Desc') }, + { title: this.$t('autoPromotion.factoryStepNav5Title'), desc: this.$t('autoPromotion.factoryStepNav5Desc') } + ); + } + return steps; + }, + isExpertDatabaseType() { + return String(this.expertType || '') === '5'; + }, + expertOptions() { + const counts = this.expertTypeCounts || {}; + return [ + { + value: '1', + label: this.$t('autoPromotion.factoryExpertChief'), + desc: this.$t('autoPromotion.factoryExpertChief'), + icon: 'el-icon-s-custom', + count: counts.chief, + jump: { path: '/editorBorder', queryKey: 'journal_id' } + }, + { + value: '2', + label: this.$t('autoPromotion.factoryExpertBoard'), + desc: this.$t('autoPromotion.factoryExpertBoard'), + icon: 'el-icon-user-solid', + count: counts.board, + jump: { path: '/editorBorder', queryKey: 'journal_id' } + }, + { + value: '3', + label: this.$t('autoPromotion.factoryExpertYoungBoard'), + desc: this.$t('autoPromotion.factoryExpertYoungBoard'), + icon: 'el-icon-user', + count: counts.young, + jump: { path: '/youthList', queryKey: 'journal_id' } + }, + { + value: '4', + label: this.$t('autoPromotion.factoryExpertAuthor'), + desc: this.$t('autoPromotion.factoryExpertAuthor'), + icon: 'el-icon-edit', + count: counts.author, + jump: { path: '/partyListCorr', queryKey: 'journal_id' } + }, + { + value: '5', + label: this.$t('autoPromotion.factoryExpertDb'), + desc: this.$t('autoPromotion.factoryExpertDb'), + icon: 'el-icon-collection', + count: counts.expertDb, + jump: { path: '/expertDatabase', queryKey: 'journal_id' } + } + ]; + }, + visibleExpertOptions() { + if (!this.isEditMode) return this.expertOptions; + const current = String(this.expertType || '').trim(); + return this.expertOptions.filter((opt) => String(opt.value) === current); }, isEditMode() { const task = this.initialTask; @@ -440,6 +532,10 @@ } }, methods: { + handleExpertTypeClick(v) { + if (this.isEditMode) return; + this.expertType = v; + }, handleDialogOpen() { this.initDialogState(); }, @@ -472,7 +568,11 @@ await this.loadAccounts(this.selectedJournalId); const initialSeed = await this.loadInitialTaskSeed(); await this.applyInitialTaskSeed(initialSeed); - await Promise.all([this.loadAvailableFields(this.selectedJournalId), this.refreshSendCountMax()]); + await Promise.all([ + this.loadAvailableFields(this.selectedJournalId), + this.isExpertDatabaseType ? this.refreshSendCountMax() : Promise.resolve() + ]); + this.fetchExpertTypeCounts(); this.syncActiveStep(); } else { await this.onJournalChange(this.selectedJournalId); @@ -697,22 +797,23 @@ s = 1; } if ( - this.selectedEmailIds && - this.selectedEmailIds.length > 0 && String(this.factoryType || '').trim() !== '' && String(this.expertType || '').trim() !== '' && this.sendCount != null && - this.sendCount >= 1 + this.sendCount >= 1 && + this.selectedEmailIds && + this.selectedEmailIds.length > 0 ) { s = 2; } - if (this.factoryFieldIds && this.factoryFieldIds.length > 0) { + if (this.isExpertDatabaseType && this.factoryZoneCountryIds && this.factoryZoneCountryIds.length > 0) { s = 3; } - if (this.factoryZoneCountryIds && this.factoryZoneCountryIds.length > 0) { + if (this.isExpertDatabaseType && this.factoryFieldIds && this.factoryFieldIds.length > 0) { s = 4; } - if (s >= 4) s = 4; + var maxIdx = (this.factorySteps && this.factorySteps.length ? this.factorySteps.length : 1) - 1; + if (s > maxIdx) s = maxIdx; this.activeStep = s; }, async loadJournalList() { @@ -721,7 +822,9 @@ this.journalList = externalList.map(function (item) { return { journal_id: item.journal_id != null ? item.journal_id : item.id, - title: item.title || item.journal_title || item.name || '' + title: item.title || item.journal_title || item.name || '', + journal_icon: item.journal_icon || '', + abbr: item.abbr || '' }; }); return; @@ -737,9 +840,12 @@ list = res; } this.journalList = list.map(function (item) { + return { journal_id: item.journal_id != null ? item.journal_id : item.id, - title: item.title || item.name || '' + title: item.title || item.name || '', + journal_icon: item.journal_icon || '', + abbr: item.abbr || '' }; }); } catch (e) { @@ -749,19 +855,151 @@ this.journalLoading = false; } }, + async handleSelect(id) { + if (this.isEditMode) return; + + // 如果点击的是当前已选中的,则置空(实现取消选中功能) + const newValue = this.selectedJournalId === id ? null : id; + + // 更新 v-model 绑定的变量 + this.selectedJournalId = newValue; + + // 调用你原有的业务逻辑方法 + await this.onJournalChange(newValue); + }, async onJournalChange(val) { if (!val) { this.accountList = []; this.availableFields = []; this.factoryFieldIds = []; this.selectedEmailIds = []; + this.expertTypeCounts = { chief: null, board: null, young: null, author: null, reviewer: null, expertDb: null }; this.syncActiveStep(); return; } + // 切换期刊时:先清空旧人数并立即触发 loading + this.expertTypeCounts = { chief: null, board: null, young: null, author: null, reviewer: null, expertDb: null }; + this.fetchExpertTypeCounts(); await this.loadAccounts(val); - await Promise.all([this.loadAvailableFields(val), this.refreshSendCountMax()]); + await Promise.all([ + this.loadAvailableFields(val), + this.refreshSendCountMax() + ]); this.syncActiveStep(); }, + openExpertTypeJump(opt) { + const jump = opt && opt.jump; + if (!jump || !jump.path) return; + const journalId = this.selectedJournalId; + // 不使用 query(会污染地址栏 + Tags fullPath);改用 sessionStorage 传参,目标页读取一次后即销毁 + try { + const payload = { + from: 'promotionFactory', + journal_id: journalId != null && journalId !== '' ? String(journalId) : '', + ts: Date.now(), + targetPath: String(jump.path || '') + }; + sessionStorage.setItem('promotionFactoryJump', JSON.stringify(payload)); + } catch (e) {} + // 跳转前先关闭并销毁弹窗(destroy-on-close),避免“中间态”残留 + this.innerVisible = false; + this.$nextTick(() => { + this.$router.push({ path: jump.path }); + }); + }, + async fetchExpertTypeCounts() { + const journalId = this.selectedJournalId; + if (!journalId) return; + const reqId = ++this.expertTypeCountsReqSeq; + this.expertTypeCountsLoading = true; + try { + const safeCount = (v) => (v == null || isNaN(Number(v)) ? 0 : Number(v)); + const countBoardMembers = (member) => { + if (!member) return 0; + if (Array.isArray(member)) return member.length; + let sum = 0; + Object.keys(member).forEach((k) => { + const v = member[k]; + if (Array.isArray(v)) sum += v.length; + else if (v && typeof v === 'object' && Array.isArray(v.list)) sum += v.list.length; + else if (v && typeof v === 'object' && Array.isArray(v.data)) sum += v.data.length; + else if (v && typeof v === 'object') sum += 1; + }); + return sum; + }; + + const [boardRes, youngRes, authorRes, reviewerRes, expertDbRes] = await Promise.all([ + this.$api.post('api/Board/getBoards', { journal_id: journalId }).catch(() => null), + this.$api + .post('api/User/getYboardlist', { + journal_id: journalId, + type: 1, + year: 0, + pageIndex: 1, + pageSize: 1, + keywords: '', + fieldkey: '', + order_remark: 0 + }) + .catch(() => null), + this.$api + .post('api/User/authorDatabase', { + journal_id: journalId, + keywords: '', + page: 1, + limit: 1 + }) + .catch(() => null), + this.$api + .post('api/Reviewer/getReviewerListByJournal', { + username: localStorage.getItem('U_name'), + journalId: journalId, + class: 0, + pageIndex: 1, + pageSize: 1 + }) + .catch(() => null), + this.$api + .post('api/expert_manage/getList', { + pageIndex: 1, + pageSize: 1 + }) + .catch(() => null) + ]); + + const next = { chief: null, board: null, young: null, author: null, reviewer: null, expertDb: null }; + + if (boardRes && boardRes.code === 0 && boardRes.data && boardRes.data.boards) { + const b = boardRes.data.boards || {}; + const chief = Array.isArray(b.main) ? b.main.length : 0; + const remain = Array.isArray(b.remain) ? b.remain.length : 0; + const member = countBoardMembers(b.member); + next.chief = safeCount(chief); + next.board = safeCount(remain + member); + } + if (youngRes && youngRes.code === 0) { + next.young = safeCount(youngRes.data && youngRes.data.count); + } + if (authorRes && authorRes.code === 0) { + next.author = safeCount(authorRes.data && authorRes.data.count); + } + if (reviewerRes && reviewerRes.code === 0) { + next.reviewer = safeCount(reviewerRes.total); + } + if (expertDbRes && expertDbRes.code === 0) { + const total = (expertDbRes.data && (expertDbRes.data.total || expertDbRes.data.count)) || expertDbRes.total; + next.expertDb = safeCount(total); + } + + // 防止快速切换期刊导致旧请求覆盖新请求 + if (reqId !== this.expertTypeCountsReqSeq) return; + this.expertTypeCounts = next; + } finally { + if (reqId === this.expertTypeCountsReqSeq) { + this.expertTypeCountsLoading = false; + } + } + }, async loadAccounts(id) { this.accountsLoading = true; try { @@ -879,18 +1117,18 @@ let fromApi = false; try { if (this.selectedEmailIds && this.selectedEmailIds.length > 0) { + // 优先走后端限制接口:api/promotion_factory/getCountForPromotionEmailIds const emailCap = await this.loadSendCountMaxFromEmailIds(); if (emailCap.max > 0) { max = emailCap.max; fromApi = emailCap.fromApi; } } + // 没有选账号或接口不可用时:回退为邮箱额度合计(或默认上限) if (!max || max < 1) { const fallbackCap = this.loadSendCountMaxFallback(); max = fallbackCap.max; - if (!fromApi && fallbackCap.fromApi) { - fromApi = true; - } + fromApi = false; } } catch (e) { console.error(e); @@ -994,11 +1232,19 @@ this.$message.warning(this.$t('autoPromotion.factoryNeedExpertType')); return; } - if (!this.factoryFieldIds || !this.factoryFieldIds.length) { + if (!String(this.factoryType || '').trim()) { + this.$message.warning(this.$t('autoPromotion.factoryNeedExpertType')); + return; + } + if (this.sendCount == null || Number(this.sendCount) < 1) { + this.$message.warning(this.$t('autoPromotion.factoryFillRequired')); + return; + } + if (this.isExpertDatabaseType && (!this.factoryFieldIds || !this.factoryFieldIds.length)) { this.$message.warning(this.$t('autoPromotion.factoryNeedPromotionFields')); return; } - if (!this.factoryZoneCountryIds || !this.factoryZoneCountryIds.length) { + if (this.isExpertDatabaseType && (!this.factoryZoneCountryIds || !this.factoryZoneCountryIds.length)) { this.$message.warning(this.$t('autoPromotion.factoryNeedPromotionCountry')); return; } @@ -1011,9 +1257,9 @@ send_count: String(this.sendCount), template_id: String(this.factoryConfig.defaultTemplateId), style_id: String(this.factoryConfig.defaultStyleId), - fetch_ids: (this.factoryFieldIds || []).join(','), - target_partitions: pc.target_partitions, - target_country_ids: pc.target_country_ids, + fetch_ids: this.isExpertDatabaseType ? (this.factoryFieldIds || []).join(',') : '', + target_partitions: this.isExpertDatabaseType ? pc.target_partitions : '', + target_country_ids: this.isExpertDatabaseType ? pc.target_country_ids : '', start_promotion: '0' }; const endpoint = this.isEditMode ? API_FACTORY_EDIT : API_FACTORY_ADD; @@ -1098,10 +1344,10 @@ /* 左侧步骤条样式 (模仿图一) */ .step-navigation { - width: 240px; + width: 230px; background: #fafbfc; border-right: 1px solid #edf0f5; - padding: 10px 20px 30px 10px; + padding: 10px 20px 30px 0px; } .step-item { @@ -1300,10 +1546,10 @@ .click-card { border: 1px dashed #dcdfe6; border-radius: 6px; - padding: 15px; + padding: 4px 20px; cursor: pointer; transition: all 0.2s; - min-height: 50px; + min-height: 30px; display: flex; align-items: center; } @@ -1325,21 +1571,69 @@ } .account-grid-layout { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); - gap: 8px; - } - - .acc-box { - background: #fff; - border: 1px solid #e4e7ed; - padding: 4px 10px; - border-radius: 4px; - } - - .acc-info { display: flex; flex-direction: column; margin-left: 5px; } - .acc-info .u { font-size: 12px; font-weight: 500; color: #333; } - .acc-info .m { font-size: 11px; color: #999; } + display: grid; + /* 如果希望固定 3 个一行:repeat(3, 1fr);如果自适应:repeat(auto-fill, minmax(280px, 1fr)) */ + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 8px; +} + +/* 账号外框:大幅缩小内边距和高度 */ +.acc-box { + border: 1px solid #e4e7ed; + border-radius: 4px; + padding: 4px 10px; /* 极窄内边距 */ + background: #fff; + transition: all 0.2s; + display: flex; + align-items: center; + height: 32px; /* 强制固定一行的高度 */ +} + +.acc-box:hover { + border-color: #409eff; + background-color: #f0f7ff; +} + +/* 内部信息:改为横向 Flex */ +.acc-info-inline { + display: flex; + align-items: center; + gap: 10px; + font-size: 12px; +} + +.acc-info-inline .u { + color: #333; + font-weight: 500; + max-width: 180px; /* 防止邮箱过长撑破布局 */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.acc-info-inline .m { + color: #909399; + font-size: 11px; +} + +.divider { + color: #dcdfe6; + margin: 0 4px; +} + +/* 深度选择器:去除 Element 默认的间距 */ +.acc-box /deep/ .el-checkbox { + display: flex; + align-items: center; + height: 100%; + margin-right: 0; +} + +.acc-box /deep/ .el-checkbox__label { + padding-left: 8px; + line-height: 1; + display: flex; +} /* 底部参数栏:白底 + 左侧蓝边;标签与控件同一行横向排布 */ .parameter-bar { @@ -1483,4 +1777,301 @@ padding-top:15px !important; padding-bottom:15px !important; } - \ No newline at end of file + .journal-grid { + display: flex; + flex-wrap: wrap; + gap: 16px; + padding: 10px 0; +} + +.journal-card { + width: 80px; /* 根据实际需求调整宽度 */ + cursor: pointer; + position: relative; + transition: all 0.3s; + border: 2px solid transparent; + border-radius: 4px; + padding: 4px; + text-align: center; + background: #f8f9fa; + + &:hover { + transform: translateY(-5px); + box-shadow: 0 4px 12px rgba(0,0,0,0.1); + } + + &.is-active { + border-color: #409eff; /* ElementUI 主题色 */ + background: #ecf5ff; + .journal-abbreviation { + color: #409eff; + font-weight: bold; + } + } + + &.is-disabled { + pointer-events: none; + opacity: 0.6; + filter: grayscale(1); + } +} + +.journal-cover { + width: 100%; + height: 110px; /* 保持期刊封面比例 */ + margin-bottom: 8px; + border-radius: 4px; + overflow: hidden; + box-shadow: 0 2px 8px rgba(0,0,0,0.15); + + .el-image { + width: 100%; + height: 100%; + } +} + +.journal-abbreviation { + font-size: 13px; + color: #606266; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.active-badge { + position: absolute; + top: -5px; + right: -5px; + background: #409eff; + color: white; + border-radius: 50%; + width: 20px; + height: 20px; + font-size: 12px; + display: flex; + align-items: center; + justify-content: center; +} +/* 3. 核心美化区块:期刊+专家合并 */ +.combined-selector-container { + display: flex; + gap: 30px; /* 期刊和专家类型之间的间距 */ + background: #f8fafc; + border-radius: 8px; + padding: 16px; + border: 1px solid #ebf0f5; + align-items: flex-start; /* 顶部对齐 */ +} + +/* 左侧期刊区域:由内容撑开,不收缩 */ +.journal-selection-side { + flex-shrink: 0; + max-width:450px; + + /* 如果你想让左侧也稍微宽点,可以设置 min-width: 300px; */ +} + + +.mini-label { + font-size: 12px; + color: #909399; + font-weight: bold; + margin-bottom: 12px; + +} + +/* 左侧期刊:更紧凑的列表 */ +.journal-selection-side { + flex: 1; + border-right: 1px solid #e4e7ed; + padding-right: 20px; +} + +.journal-grid-compact { + + display: flex; + flex-wrap: wrap; + gap: 12px; +} + +.journal-card-mini { + width: 70px; + position: relative; + cursor: pointer; + text-align: center; +} + +.mini-cover { + width: 70px; + height: 90px; + border-radius: 4px; + box-shadow: 0 2px 6px rgba(0,0,0,0.1); + border: 2px solid transparent; + transition: 0.2s; +} + +.journal-card-mini.is-active .mini-cover { + border-color: #409eff; + transform: scale(1.05); +} + +.mini-abbr { + font-size: 11px; + margin-top: 5px; + color: #606266; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +/* 期刊网格微调 */ +.journal-grid-compact { display: flex; flex-wrap: wrap; gap: 12px; } +.journal-card-mini { width: 70px; text-align: center; cursor: pointer; } +.mini-cover-wrapper { position: relative; width: 70px; height: 95px; } +.mini-cover { + width: 100%; height: 100%; border-radius: 4px; border: 2px solid transparent; + box-shadow: 0 2px 6px rgba(0,0,0,0.1); transition: 0.3s; +} +.journal-card-mini.is-active .mini-cover { border-color: #409eff; transform: translateY(-3px); } +.mini-badge { + position: absolute; top: -6px; right: -6px; background: #67c23a; color: #fff; + width: 18px; height: 18px; border-radius: 50%; font-size: 10px; + display: flex; align-items: center; justify-content: center; z-index: 2; +} +.mini-abbr { font-size: 11px; color: #606266; margin-top: 6px; overflow: hidden; text-overflow: ellipsis; } +.mini-abbr.is-active { + color: #409eff; + font-weight: 600; +} + +.expert-type-side { + flex: 1; /* 核心代码:占据剩余空间 */ + min-width: 0; /* 防止 Flex 子项溢出 */ + display: flex; + flex-direction: column; + +} + +.mini-label { + font-size: 12px; + color: #909399; + margin-bottom: 8px; /* 紧凑间距 */ + font-weight: 600; +} + + +.expert-tile-group { + display: flex; + flex-wrap: wrap; + gap: 8px; + width: 100%; +} + +.expert-tile-mini { + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 12px; + background: #fff; + border: 1px solid #e4e7ed; + border-radius: 4px; + cursor: pointer; + + /* --- 关键修改:不强制占满 --- */ + flex: 0 0 auto; /* 不放大,不缩小,根据内容定宽度 */ + min-width: 140px; /* 给一个最小宽度,保证整齐度 */ + max-width: 300px; /* 限制最大宽度,防止太长 */ + /* ------------------------ */ + + height: 34px; + box-sizing: border-box; + transition: all 0.2s; +} + +.expert-tile-mini.is-disabled { + cursor: not-allowed; + opacity: 0.75; +} + +.expert-tile-mini.is-disabled:hover { + background: #fff; +} + +.tile-text { + font-size: 12px; + color: #606266; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-right: 8px; +} + +.tile-count { + margin-left: 4px; + color: #909399; + font-weight: 400; +} +.tile-count--loading { + opacity: 0.7; +} +.tile-link-btn { + padding: 0; + margin-left: auto; + line-height: 1; + font-size: 12px; +} + +.tile-spinner { + margin-left: 6px; + color: #409eff; + font-size: 12px; +} + +/* 选中状态 */ +.expert-tile-mini.is-active { + border-color: #409eff; + background-color: #f0f7ff; +} + +.expert-tile-mini:hover { + background-color: #f5f7fa; +} + + + + + +.expert-tile-mini.is-active .tile-text { + color: #409eff; + font-weight: 500; +} + +/* 选中图标微型化 */ +.expert-tile-mini i { + font-size: 14px; + color: #409eff; +} + +/* 隐藏横向滚动条,美化纵向滚动条 */ +.custom-scrollbar::-webkit-scrollbar { + width: 4px; +} +.custom-scrollbar::-webkit-scrollbar-thumb { + background: #e4e7ed; + border-radius: 4px; +} + +/* 激活状态左侧的小指示条(可选,增加精致感) */ +.expert-tile-mini.is-active { + position: relative; +} +.expert-tile-mini.is-active::before { + content: ""; + position: absolute; + left: 0; + top: 4px; + bottom: 4px; + width: 2px; + background: #409eff; +} + + \ No newline at end of file diff --git a/src/components/page/editorBorder.vue b/src/components/page/editorBorder.vue index 4b5f927..4accd3a 100644 --- a/src/components/page/editorBorder.vue +++ b/src/components/page/editorBorder.vue @@ -771,6 +771,7 @@