提交
This commit is contained in:
@@ -1069,6 +1069,8 @@ colTitle: 'Template title',
|
|||||||
autoSolicit: 'Auto Solicitation',
|
autoSolicit: 'Auto Solicitation',
|
||||||
editConfig: 'Edit Configuration',
|
editConfig: 'Edit Configuration',
|
||||||
running: 'Running',
|
running: 'Running',
|
||||||
|
stopped: 'Stopped',
|
||||||
|
configure: 'Configure',
|
||||||
emailTemplate: 'Email Template',
|
emailTemplate: 'Email Template',
|
||||||
emailStyle: 'Email Style',
|
emailStyle: 'Email Style',
|
||||||
notStarted: 'Auto solicitation plan is not enabled',
|
notStarted: 'Auto solicitation plan is not enabled',
|
||||||
@@ -1179,6 +1181,7 @@ colTitle: 'Template title',
|
|||||||
factoryScenarioSolicit: 'Invite Submission',
|
factoryScenarioSolicit: 'Invite Submission',
|
||||||
factoryScenarioPromoteCitation: 'Promote Citation',
|
factoryScenarioPromoteCitation: 'Promote Citation',
|
||||||
factoryScenarioGeneralThanks: 'General Thanks',
|
factoryScenarioGeneralThanks: 'General Thanks',
|
||||||
|
createdAt: 'Created at',
|
||||||
noFactoryTask: 'No tasks',
|
noFactoryTask: 'No tasks',
|
||||||
factoryCreateNow: 'Create now'
|
factoryCreateNow: 'Create now'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1054,6 +1054,8 @@ const zh = {
|
|||||||
autoSolicit: '自动约稿',
|
autoSolicit: '自动约稿',
|
||||||
editConfig: '修改配置',
|
editConfig: '修改配置',
|
||||||
running: '运行中',
|
running: '运行中',
|
||||||
|
stopped: '已停止',
|
||||||
|
configure: '配置',
|
||||||
emailTemplate: '邮件模板',
|
emailTemplate: '邮件模板',
|
||||||
emailStyle: '邮件风格',
|
emailStyle: '邮件风格',
|
||||||
notStarted: '未开启自动约稿计划',
|
notStarted: '未开启自动约稿计划',
|
||||||
@@ -1164,6 +1166,7 @@ const zh = {
|
|||||||
factoryScenarioSolicit: '约稿',
|
factoryScenarioSolicit: '约稿',
|
||||||
factoryScenarioPromoteCitation: '推广引用',
|
factoryScenarioPromoteCitation: '推广引用',
|
||||||
factoryScenarioGeneralThanks: '常规感谢',
|
factoryScenarioGeneralThanks: '常规感谢',
|
||||||
|
createdAt: '创建时间',
|
||||||
noFactoryTask: '没有任务',
|
noFactoryTask: '没有任务',
|
||||||
factoryCreateNow: '立即创建'
|
factoryCreateNow: '立即创建'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,13 +62,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="status-tag">
|
<div class="status-tag">
|
||||||
<span class="dot"></span>
|
<span class="dot"></span>
|
||||||
{{ taskCard.enabled ? $t('autoPromotion.running').toUpperCase() : 'STOPPED' }}
|
{{ taskCard.enabled ? $t('autoPromotion.running') : $t('autoPromotion.stopped') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-switch
|
<el-switch
|
||||||
:value="taskCard.enabled"
|
:value="taskCard.enabled"
|
||||||
size="small"
|
size="small"
|
||||||
active-color="#409EFF"
|
active-color="#3DBB6A"
|
||||||
:disabled="!taskCard.taskId || !!taskCard.switchLoading"
|
:disabled="!taskCard.taskId || !!taskCard.switchLoading"
|
||||||
@change="onFactoryTaskSwitchChange(journal, taskCard, $event)"
|
@change="onFactoryTaskSwitchChange(journal, taskCard, $event)"
|
||||||
/>
|
/>
|
||||||
@@ -76,21 +76,21 @@
|
|||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<div class="template-preview-box">
|
<div class="template-preview-box">
|
||||||
<div>
|
<div class="meta-row">
|
||||||
<i class="el-icon-message"
|
<i class="el-icon-message"
|
||||||
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Template :</span></i
|
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Template :</span></i
|
||||||
>
|
>
|
||||||
<span class="tpl-name">{{ taskCard.templateName || 'No Template Configured' }}</span>
|
<span class="tpl-name tpl-name-single-line">{{ taskCard.templateName || 'No Template Configured' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="meta-row">
|
||||||
<i class="el-icon-collection-tag"
|
<i class="el-icon-collection-tag"
|
||||||
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Promotion Fields :</span></i
|
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Promotion Fields :</span></i
|
||||||
>
|
>
|
||||||
<span class="tpl-name">{{ taskCard.fieldCountText }}</span>
|
<span class="tpl-name">{{ taskCard.fieldCountText }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="meta-row">
|
||||||
<i class="el-icon-location-outline"
|
<i class="el-icon-location-outline"
|
||||||
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Country :</span></i
|
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Country :</span></i
|
||||||
>
|
>
|
||||||
@@ -112,18 +112,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<button class="action-main-btn" @click="openDetail(journal)">
|
|
||||||
<span v-if="promotionUpdating && String(promotionUpdatingJournalId) === String(journal.journal_id)">
|
<button class="action-main-btn" @click="handleFactoryTaskAction(journal, taskCard)">
|
||||||
|
<span
|
||||||
|
v-if="
|
||||||
|
promotionUpdating &&
|
||||||
|
String(promotionUpdatingJournalId) === String(journal.journal_id) &&
|
||||||
|
String(promotionUpdatingTaskId) === String(taskCard.taskId || '')
|
||||||
|
"
|
||||||
|
>
|
||||||
<i class="el-icon-loading"></i>
|
<i class="el-icon-loading"></i>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>CONFIGURE</span>
|
<span v-else>{{ getFactoryTaskActionText(taskCard) }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<div v-if="taskCard.createdAtText" class="task-create-time">
|
||||||
|
{{ $t('autoPromotion.createdAt') }}: {{ taskCard.createdAtText }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="no-task-tip">
|
<div v-else class="no-task-tip">
|
||||||
<span>{{ $t('autoPromotion.noFactoryTask') }}</span>
|
<span>{{ $t('autoPromotion.noFactoryTask') }}</span>
|
||||||
<el-button type="text" size="mini" @click="openFactoryTaskDialogForJournal(journal)">
|
<el-button type="text" size="mini" class="no-task-create-btn" @click="openFactoryTaskDialogForJournal(journal)">
|
||||||
|
<i class="el-icon-plus"></i>
|
||||||
{{ $t('autoPromotion.factoryCreateNow') }}
|
{{ $t('autoPromotion.factoryCreateNow') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -196,6 +207,7 @@ export default {
|
|||||||
saving: false,
|
saving: false,
|
||||||
promotionUpdating: false,
|
promotionUpdating: false,
|
||||||
promotionUpdatingJournalId: '',
|
promotionUpdatingJournalId: '',
|
||||||
|
promotionUpdatingTaskId: '',
|
||||||
wizardJournal: null,
|
wizardJournal: null,
|
||||||
wizardStartDate: '',
|
wizardStartDate: '',
|
||||||
wizardConfig: {
|
wizardConfig: {
|
||||||
@@ -215,6 +227,7 @@ export default {
|
|||||||
templateDialogInitialStyleId: '',
|
templateDialogInitialStyleId: '',
|
||||||
templateDialogInitialTemplateId: '',
|
templateDialogInitialTemplateId: '',
|
||||||
templateNameMap: {},
|
templateNameMap: {},
|
||||||
|
factoryTemplateNameMap: {},
|
||||||
allJournals: [],
|
allJournals: [],
|
||||||
showFactoryTaskDialog: false,
|
showFactoryTaskDialog: false,
|
||||||
factoryDialogInitialJournalId: '',
|
factoryDialogInitialJournalId: '',
|
||||||
@@ -225,6 +238,9 @@ export default {
|
|||||||
this.fetchPromotionJournals();
|
this.fetchPromotionJournals();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
savePromotionCountriesNow(){
|
||||||
|
|
||||||
|
},
|
||||||
// --- 逻辑部分完全保留你原有的实现 ---
|
// --- 逻辑部分完全保留你原有的实现 ---
|
||||||
openTemplateSelector() {
|
openTemplateSelector() {
|
||||||
this.templateDialogInitialStyleId =
|
this.templateDialogInitialStyleId =
|
||||||
@@ -279,6 +295,38 @@ export default {
|
|||||||
this.$set(taskCard, 'switchLoading', false);
|
this.$set(taskCard, 'switchLoading', false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getFactoryTaskActionText(taskCard) {
|
||||||
|
return taskCard && taskCard.enabled ? this.$t('autoPromotion.goManagePlan') : this.$t('autoPromotion.startPlan');
|
||||||
|
},
|
||||||
|
async handleFactoryTaskAction(journal, taskCard) {
|
||||||
|
if (!journal || !taskCard) return;
|
||||||
|
const taskId = taskCard.taskId != null ? String(taskCard.taskId) : '';
|
||||||
|
this.promotionUpdating = true;
|
||||||
|
this.promotionUpdatingJournalId = journal.journal_id;
|
||||||
|
this.promotionUpdatingTaskId = taskId;
|
||||||
|
try {
|
||||||
|
if (!taskCard.enabled && taskId) {
|
||||||
|
const res = await this.$api.post('api/promotion_factory/changePromotionAct', {
|
||||||
|
promotion_factory_id: taskId,
|
||||||
|
start_promotion: '1'
|
||||||
|
});
|
||||||
|
if (!res || Number(res.code) !== 0) {
|
||||||
|
this.$message.error((res && res.msg) || this.$t('autoPromotion.saveFailed'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$set(taskCard, 'enabled', true);
|
||||||
|
if (taskCard.rawTask) {
|
||||||
|
this.$set(taskCard.rawTask, 'state', '1');
|
||||||
|
this.$set(taskCard.rawTask, 'start_promotion', '1');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.openDetail(journal, taskCard);
|
||||||
|
} finally {
|
||||||
|
this.promotionUpdating = false;
|
||||||
|
this.promotionUpdatingJournalId = '';
|
||||||
|
this.promotionUpdatingTaskId = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
_parseJournalDetail(data) {
|
_parseJournalDetail(data) {
|
||||||
const journalInfo = data.journal || data || {};
|
const journalInfo = data.journal || data || {};
|
||||||
const tpl = journalInfo.template || data.template || {};
|
const tpl = journalInfo.template || data.template || {};
|
||||||
@@ -356,6 +404,7 @@ export default {
|
|||||||
async loadFactoryTaskSummaryByJournal(journal, userId) {
|
async loadFactoryTaskSummaryByJournal(journal, userId) {
|
||||||
if (!journal || !journal.journal_id) return;
|
if (!journal || !journal.journal_id) return;
|
||||||
try {
|
try {
|
||||||
|
await this.loadFactoryTemplateNamesByJournal(journal.journal_id);
|
||||||
const res = await this.$api.post('api/promotion_factory/getList', {
|
const res = await this.$api.post('api/promotion_factory/getList', {
|
||||||
journal_id: String(journal.journal_id),
|
journal_id: String(journal.journal_id),
|
||||||
user_id: String(userId || ''),
|
user_id: String(userId || ''),
|
||||||
@@ -375,7 +424,12 @@ export default {
|
|||||||
const normalizedTasks = (Array.isArray(list) ? list : []).map((task, idx) => {
|
const normalizedTasks = (Array.isArray(list) ? list : []).map((task, idx) => {
|
||||||
const type = task && task.type != null ? String(task.type) : '';
|
const type = task && task.type != null ? String(task.type) : '';
|
||||||
const fieldCount = this.getFactoryTaskFieldCount(task);
|
const fieldCount = this.getFactoryTaskFieldCount(task);
|
||||||
const enabled = String(task && task.state != null ? task.state : '0') === '1';
|
const startPromotion =
|
||||||
|
task && task.start_promotion != null && String(task.start_promotion).trim() !== ''
|
||||||
|
? String(task.start_promotion)
|
||||||
|
: null;
|
||||||
|
const state = task && task.state != null && String(task.state).trim() !== '' ? String(task.state) : null;
|
||||||
|
const enabled = String(startPromotion != null ? startPromotion : state != null ? state : '0') === '1';
|
||||||
return {
|
return {
|
||||||
cardKey: `${journal.journal_id}_${task.promotion_factory_id || idx}`,
|
cardKey: `${journal.journal_id}_${task.promotion_factory_id || idx}`,
|
||||||
taskId: task.promotion_factory_id || '',
|
taskId: task.promotion_factory_id || '',
|
||||||
@@ -384,10 +438,11 @@ export default {
|
|||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
switchLoading: false,
|
switchLoading: false,
|
||||||
initialized: true,
|
initialized: true,
|
||||||
templateName: task.template_name || (task.template_id ? `Template #${task.template_id}` : 'No Template Configured'),
|
templateName: this.getFactoryTemplateName(task, journal.journal_id),
|
||||||
fieldCount: fieldCount,
|
fieldCount: fieldCount,
|
||||||
fieldCountText: String(fieldCount),
|
fieldCountText: String(fieldCount),
|
||||||
countryScopeLabel: task.country_scope_label || '-',
|
countryScopeLabel: task.country_scope_label || '-',
|
||||||
|
createdAtText: this.formatTaskCreateTime(task),
|
||||||
totalCount: total,
|
totalCount: total,
|
||||||
showCount: idx === 0 && total > 0,
|
showCount: idx === 0 && total > 0,
|
||||||
rawTask: task
|
rawTask: task
|
||||||
@@ -411,6 +466,37 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async loadFactoryTemplateNamesByJournal(journalId) {
|
||||||
|
const key = String(journalId || '');
|
||||||
|
if (!key) return {};
|
||||||
|
if (this.factoryTemplateNameMap[key]) {
|
||||||
|
return this.factoryTemplateNameMap[key];
|
||||||
|
}
|
||||||
|
let map = {};
|
||||||
|
try {
|
||||||
|
const res = await this.$api.post('api/mail_template/listTemplatesAll', { journal_id: key });
|
||||||
|
const payload = (res && res.data) || {};
|
||||||
|
const list = this.findArray(payload) || this.findArray(res) || [];
|
||||||
|
map = (Array.isArray(list) ? list : []).reduce((acc, item) => {
|
||||||
|
const id = item && (item.template_id != null ? item.template_id : item.id);
|
||||||
|
if (id == null) return acc;
|
||||||
|
const name = item.title || item.name || '';
|
||||||
|
if (name) acc[String(id)] = name;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
} catch (e) {
|
||||||
|
map = {};
|
||||||
|
}
|
||||||
|
this.$set(this.factoryTemplateNameMap, key, map);
|
||||||
|
return map;
|
||||||
|
},
|
||||||
|
getFactoryTemplateName(task, journalId) {
|
||||||
|
const tplId = task && task.template_id != null ? String(task.template_id) : '';
|
||||||
|
const journalMap = this.factoryTemplateNameMap[String(journalId || '')] || {};
|
||||||
|
if (tplId && journalMap[tplId]) return journalMap[tplId];
|
||||||
|
if (task && task.template_name) return task.template_name;
|
||||||
|
return tplId ? `Template #${tplId}` : 'No Template Configured';
|
||||||
|
},
|
||||||
getFactoryTaskFieldCount(task) {
|
getFactoryTaskFieldCount(task) {
|
||||||
if (!task) return 0;
|
if (!task) return 0;
|
||||||
if (task.fetch_fields && typeof task.fetch_fields === 'object') {
|
if (task.fetch_fields && typeof task.fetch_fields === 'object') {
|
||||||
@@ -423,6 +509,23 @@ export default {
|
|||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
return fetchIds.length;
|
return fetchIds.length;
|
||||||
},
|
},
|
||||||
|
formatTaskCreateTime(task) {
|
||||||
|
if (!task || typeof task !== 'object') return '';
|
||||||
|
const raw = task.ctime || task.create_time || task.created_at || task.time || '';
|
||||||
|
if (raw == null || String(raw).trim() === '') return '';
|
||||||
|
const n = Number(raw);
|
||||||
|
let dt = null;
|
||||||
|
if (!isNaN(n) && n > 0) {
|
||||||
|
dt = new Date(n > 1e12 ? n : n * 1000);
|
||||||
|
} else {
|
||||||
|
dt = new Date(String(raw));
|
||||||
|
}
|
||||||
|
if (!dt || isNaN(dt.getTime())) return String(raw);
|
||||||
|
const pad = (v) => String(v).padStart(2, '0');
|
||||||
|
return `${dt.getFullYear()}-${pad(dt.getMonth() + 1)}-${pad(dt.getDate())} ${pad(dt.getHours())}:${pad(
|
||||||
|
dt.getMinutes()
|
||||||
|
)}:${pad(dt.getSeconds())}`;
|
||||||
|
},
|
||||||
mapFactoryTaskTypeLabel(type) {
|
mapFactoryTaskTypeLabel(type) {
|
||||||
const t = String(type || '');
|
const t = String(type || '');
|
||||||
if (t === '1') return this.$t('autoPromotion.factoryScenarioSolicit');
|
if (t === '1') return this.$t('autoPromotion.factoryScenarioSolicit');
|
||||||
@@ -443,6 +546,7 @@ export default {
|
|||||||
},
|
},
|
||||||
async refreshAll() {
|
async refreshAll() {
|
||||||
this.templateNameMap = {};
|
this.templateNameMap = {};
|
||||||
|
this.factoryTemplateNameMap = {};
|
||||||
this.allJournals = [];
|
this.allJournals = [];
|
||||||
await this.fetchPromotionJournals();
|
await this.fetchPromotionJournals();
|
||||||
},
|
},
|
||||||
@@ -512,34 +616,7 @@ export default {
|
|||||||
country_fetch_ids: (this.selectedCountryIds || []).join(',')
|
country_fetch_ids: (this.selectedCountryIds || []).join(',')
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async handleSolicitAction(journal) {
|
|
||||||
if (!this.isSolicitConfigured(journal)) {
|
|
||||||
this.openWizardForJournal(journal);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!journal.solicit.enabled) {
|
|
||||||
this.promotionUpdating = true;
|
|
||||||
this.promotionUpdatingJournalId = journal.journal_id;
|
|
||||||
try {
|
|
||||||
await this.$api.post('api/email_client/setDefaultPromotion', {
|
|
||||||
journal_id: String(journal.journal_id),
|
|
||||||
default_template_id: String(journal.solicit.templateId),
|
|
||||||
default_style_id: String(journal.solicit.styleId),
|
|
||||||
start_promotion: '1',
|
|
||||||
user_id: localStorage.getItem('U_id')
|
|
||||||
});
|
|
||||||
await this.refreshJournalByDetail(journal);
|
|
||||||
this.openDetail(journal);
|
|
||||||
} catch (e) {
|
|
||||||
this.$message.error('Update failed');
|
|
||||||
} finally {
|
|
||||||
this.promotionUpdating = false;
|
|
||||||
this.promotionUpdatingJournalId = '';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.openDetail(journal);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openWizardForJournal(journal) {
|
openWizardForJournal(journal) {
|
||||||
this.wizardJournal = journal;
|
this.wizardJournal = journal;
|
||||||
const s = journal.solicit || {};
|
const s = journal.solicit || {};
|
||||||
@@ -575,8 +652,15 @@ export default {
|
|||||||
this.saving = false;
|
this.saving = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openDetail(journal) {
|
openDetail(journal,taskCard) {
|
||||||
this.$router.push({ path: '/autoPromotionLogs', query: { journal_id: String(journal.journal_id) } });
|
const taskId = taskCard && taskCard.taskId != null ? String(taskCard.taskId) : '';
|
||||||
|
this.$router.push({
|
||||||
|
path: '/autoPromotionLogs',
|
||||||
|
query: {
|
||||||
|
journal_id: String(journal.journal_id),
|
||||||
|
promotion_factory_id: taskId
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
async handleSwitch(journal, type, nextVal) {
|
async handleSwitch(journal, type, nextVal) {
|
||||||
if (!this.isSolicitConfigured(journal)) {
|
if (!this.isSolicitConfigured(journal)) {
|
||||||
@@ -713,6 +797,13 @@ export default {
|
|||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-task-create-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
/* 统计卡片基础样式 */
|
/* 统计卡片基础样式 */
|
||||||
.stat-card {
|
.stat-card {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
@@ -732,7 +823,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stat-card.is-active {
|
.stat-card.is-active {
|
||||||
border-top: 3px solid #409eff;
|
border-top: 3px solid #67c23a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card.is-stopped {
|
.stat-card.is-stopped {
|
||||||
@@ -839,6 +930,12 @@ export default {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.meta-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.template-preview-box.is-empty {
|
.template-preview-box.is-empty {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@@ -852,6 +949,11 @@ export default {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tpl-name-single-line {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* 统计项 */
|
/* 统计项 */
|
||||||
.stats-container {
|
.stats-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -896,24 +998,46 @@ export default {
|
|||||||
/* 底部按钮区 */
|
/* 底部按钮区 */
|
||||||
.card-actions {
|
.card-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task-create-time {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #909399;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
.action-main-btn {
|
.action-main-btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 30px;
|
height: 24px;
|
||||||
background: #006699;
|
background: #eaf3ff;
|
||||||
color: white;
|
color: #409eff;
|
||||||
border: none;
|
border: 1px solid #d7e7ff;
|
||||||
border-radius: 6px;
|
border-radius: 4px;
|
||||||
font-weight: 700;
|
font-weight: 600;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
line-height: 22px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-main-btn:hover {
|
.action-main-btn:hover {
|
||||||
background: #006699;
|
background: #dcecff;
|
||||||
|
border-color: #c4ddff;
|
||||||
|
color: #2f89ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-active .action-main-btn {
|
||||||
|
background: #3dbb6a;
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: #3dbb6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-active .action-main-btn:hover {
|
||||||
|
background: #31a85b;
|
||||||
|
border-color: #31a85b;
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-main-btn.secondary {
|
.action-main-btn.secondary {
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ export default {
|
|||||||
showFactoryTaskDialog: false,
|
showFactoryTaskDialog: false,
|
||||||
factoryDialogInitialJournalId: '',
|
factoryDialogInitialJournalId: '',
|
||||||
factoryDialogInitialTask: null,
|
factoryDialogInitialTask: null,
|
||||||
|
routePromotionFactoryId: '',
|
||||||
previewForm: {
|
previewForm: {
|
||||||
id: '',
|
id: '',
|
||||||
email: '',
|
email: '',
|
||||||
@@ -485,6 +486,11 @@ export default {
|
|||||||
async initPage() {
|
async initPage() {
|
||||||
this.hidePage = false;
|
this.hidePage = false;
|
||||||
var journal_id = (this.$route.query && this.$route.query.journal_id) || '';
|
var journal_id = (this.$route.query && this.$route.query.journal_id) || '';
|
||||||
|
var pfid =
|
||||||
|
(this.$route.query && this.$route.query.promotion_factory_id) ||
|
||||||
|
(this.$route.query && this.$route.query.taskId) ||
|
||||||
|
'';
|
||||||
|
this.routePromotionFactoryId = String(pfid || '');
|
||||||
this.selectedJournalId = String(journal_id);
|
this.selectedJournalId = String(journal_id);
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
@@ -675,7 +681,29 @@ export default {
|
|||||||
},
|
},
|
||||||
openFactoryTaskDialogFromLogs() {
|
openFactoryTaskDialogFromLogs() {
|
||||||
this.factoryDialogInitialJournalId = this.selectedJournalId ? String(this.selectedJournalId) : '';
|
this.factoryDialogInitialJournalId = this.selectedJournalId ? String(this.selectedJournalId) : '';
|
||||||
this.factoryDialogInitialTask = this.list && this.list.length ? { ...this.list[0] } : null;
|
const targetTaskId = String(this.routePromotionFactoryId || '').trim();
|
||||||
|
const first = this.list && this.list.length ? this.list[0] : null;
|
||||||
|
const matched = targetTaskId
|
||||||
|
? (this.list || []).find((row) => {
|
||||||
|
const pid = row && row.promotion_factory_id != null ? String(row.promotion_factory_id) : '';
|
||||||
|
const rid = row && row.id != null ? String(row.id) : '';
|
||||||
|
const tid = row && row.task_id != null ? String(row.task_id) : '';
|
||||||
|
return pid === targetTaskId || rid === targetTaskId || tid === targetTaskId;
|
||||||
|
}) || first
|
||||||
|
: first;
|
||||||
|
this.factoryDialogInitialTask = matched
|
||||||
|
? {
|
||||||
|
...matched,
|
||||||
|
promotion_factory_id:
|
||||||
|
matched.promotion_factory_id != null
|
||||||
|
? String(matched.promotion_factory_id)
|
||||||
|
: matched.id != null
|
||||||
|
? String(matched.id)
|
||||||
|
: matched.task_id != null
|
||||||
|
? String(matched.task_id)
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
: null;
|
||||||
this.showFactoryTaskDialog = true;
|
this.showFactoryTaskDialog = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -811,8 +839,15 @@ export default {
|
|||||||
this.list = rawList.map((item, idx) => {
|
this.list = rawList.map((item, idx) => {
|
||||||
const runAt = item.run_at || item.run_time || item.plan_time || item.execute_time || item.send_date || '';
|
const runAt = item.run_at || item.run_time || item.plan_time || item.execute_time || item.send_date || '';
|
||||||
const state = String(item.state != null ? item.state : '');
|
const state = String(item.state != null ? item.state : '');
|
||||||
|
const promotionFactoryId =
|
||||||
|
item.promotion_factory_id != null
|
||||||
|
? item.promotion_factory_id
|
||||||
|
: item.id != null
|
||||||
|
? item.id
|
||||||
|
: item.task_id;
|
||||||
return {
|
return {
|
||||||
id: item.id || item.task_id || `task_${idx + 1}`,
|
id: item.id || item.task_id || `task_${idx + 1}`,
|
||||||
|
promotion_factory_id: promotionFactoryId != null ? String(promotionFactoryId) : '',
|
||||||
task_id: String(item.task_id != null ? item.task_id : item.id || ''),
|
task_id: String(item.task_id != null ? item.task_id : item.id || ''),
|
||||||
task_name: item.task_name || item.name || '',
|
task_name: item.task_name || item.name || '',
|
||||||
scene: item.scene || '',
|
scene: item.scene || '',
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
v-model="selectedJournalId"
|
v-model="selectedJournalId"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
|
:disabled="isEditMode"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:placeholder="$t('autoPromotion.factoryJournalPlaceholder')"
|
:placeholder="$t('autoPromotion.factoryJournalPlaceholder')"
|
||||||
@change="onJournalChange"
|
@change="onJournalChange"
|
||||||
@@ -111,7 +112,7 @@
|
|||||||
<label class="param-label"
|
<label class="param-label"
|
||||||
>{{ $t('autoPromotion.factorySendCount') }}<span class="factory-required-star" aria-hidden="true">*</span></label
|
>{{ $t('autoPromotion.factorySendCount') }}<span class="factory-required-star" aria-hidden="true">*</span></label
|
||||||
>
|
>
|
||||||
<div class="param-inline-controls">
|
<div class="param-inline-controls param-inline-controls-send">
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-model="sendCount"
|
v-model="sendCount"
|
||||||
:min="1"
|
:min="1"
|
||||||
@@ -120,7 +121,7 @@
|
|||||||
controls-position="right"
|
controls-position="right"
|
||||||
:disabled="sendCountMaxLoading"
|
:disabled="sendCountMaxLoading"
|
||||||
/>
|
/>
|
||||||
<span v-if="sendCountMaxHint" class="max-tip">{{ sendCountMaxHint }}</span>
|
<span v-if="sendCountMaxHint" class="max-tip max-tip-under">{{ sendCountMaxHint }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -280,6 +281,9 @@
|
|||||||
const API_GET_ACCOUNTS = 'api/email_client/getAccounts';
|
const API_GET_ACCOUNTS = 'api/email_client/getAccounts';
|
||||||
const API_AVAILABLE_FIELDS = 'api/email_client/getAvailableFields';
|
const API_AVAILABLE_FIELDS = 'api/email_client/getAvailableFields';
|
||||||
const API_FACTORY_ADD = 'api/promotion_factory/add';
|
const API_FACTORY_ADD = 'api/promotion_factory/add';
|
||||||
|
const API_FACTORY_EDIT = 'api/promotion_factory/edit';
|
||||||
|
const API_FACTORY_DETAIL = 'api/promotion_factory/getDetail';
|
||||||
|
const API_TEMPLATE_LIST_ALL = 'api/mail_template/listTemplatesAll';
|
||||||
const API_GET_COUNT_FOR_EMAIL_IDS = 'api/promotion_factory/getCountForPromotionEmailIds';
|
const API_GET_COUNT_FOR_EMAIL_IDS = 'api/promotion_factory/getCountForPromotionEmailIds';
|
||||||
|
|
||||||
const PARTITION_TO_API = {
|
const PARTITION_TO_API = {
|
||||||
@@ -327,6 +331,8 @@
|
|||||||
factoryConfig: { defaultTemplateId: '', defaultStyleId: '' },
|
factoryConfig: { defaultTemplateId: '', defaultStyleId: '' },
|
||||||
factoryTemplateName: '',
|
factoryTemplateName: '',
|
||||||
factoryStyleName: '',
|
factoryStyleName: '',
|
||||||
|
editingTaskId: '',
|
||||||
|
templateNameMap: {},
|
||||||
showFactoryTemplateDialog: false,
|
showFactoryTemplateDialog: false,
|
||||||
_emailIdsSendLimitTimer: null
|
_emailIdsSendLimitTimer: null
|
||||||
};
|
};
|
||||||
@@ -393,6 +399,7 @@
|
|||||||
},
|
},
|
||||||
sendCountMaxHint() {
|
sendCountMaxHint() {
|
||||||
if (this.sendCountMaxLoading) return '';
|
if (this.sendCountMaxLoading) return '';
|
||||||
|
if (!this.selectedEmailIds || this.selectedEmailIds.length === 0) return '';
|
||||||
if (this.sendLimitFromApi) {
|
if (this.sendLimitFromApi) {
|
||||||
return this.$t('autoPromotion.factorySendMaxFromApi', { max: this.sendCountMax });
|
return this.$t('autoPromotion.factorySendMaxFromApi', { max: this.sendCountMax });
|
||||||
}
|
}
|
||||||
@@ -439,19 +446,96 @@
|
|||||||
await this.loadJournalList();
|
await this.loadJournalList();
|
||||||
if (this.journalList.length) {
|
if (this.journalList.length) {
|
||||||
const preferred = this.initialJournalId != null && this.initialJournalId !== '' ? String(this.initialJournalId) : '';
|
const preferred = this.initialJournalId != null && this.initialJournalId !== '' ? String(this.initialJournalId) : '';
|
||||||
|
const initialTaskJournalId = this.getInitialTaskJournalId(this.initialTask);
|
||||||
const matched = preferred
|
const matched = preferred
|
||||||
? this.journalList.find(function (j) {
|
? this.journalList.find(function (j) {
|
||||||
return String(j.journal_id) === preferred;
|
return String(j.journal_id) === preferred;
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
this.selectedJournalId = matched ? matched.journal_id : this.journalList[0].journal_id;
|
const matchedByTask = initialTaskJournalId
|
||||||
await this.onJournalChange(this.selectedJournalId);
|
? this.journalList.find(function (j) {
|
||||||
this.applyInitialTaskSeed();
|
return String(j.journal_id) === initialTaskJournalId;
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
this.selectedJournalId = matchedByTask
|
||||||
|
? matchedByTask.journal_id
|
||||||
|
: matched
|
||||||
|
? matched.journal_id
|
||||||
|
: this.journalList[0].journal_id;
|
||||||
|
if (this.isEditMode) {
|
||||||
|
await this.loadAccounts(this.selectedJournalId);
|
||||||
|
const initialSeed = await this.loadInitialTaskSeed();
|
||||||
|
await this.applyInitialTaskSeed(initialSeed);
|
||||||
|
await Promise.all([this.loadAvailableFields(this.selectedJournalId), this.refreshSendCountMax()]);
|
||||||
|
this.syncActiveStep();
|
||||||
|
} else {
|
||||||
|
await this.onJournalChange(this.selectedJournalId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
applyInitialTaskSeed() {
|
getInitialTaskId(task) {
|
||||||
|
if (!task || typeof task !== 'object') return '';
|
||||||
|
const id = task.promotion_factory_id != null ? task.promotion_factory_id : task.id != null ? task.id : '';
|
||||||
|
return String(id || '').trim();
|
||||||
|
},
|
||||||
|
getInitialTaskJournalId(task) {
|
||||||
|
if (!task || typeof task !== 'object') return '';
|
||||||
|
const id = task.journal_id != null ? task.journal_id : task.j_id != null ? task.j_id : '';
|
||||||
|
return String(id || '').trim();
|
||||||
|
},
|
||||||
|
async loadInitialTaskSeed() {
|
||||||
const task = this.initialTask && typeof this.initialTask === 'object' ? this.initialTask : null;
|
const task = this.initialTask && typeof this.initialTask === 'object' ? this.initialTask : null;
|
||||||
|
if (!task) return null;
|
||||||
|
const taskId = this.getInitialTaskId(task);
|
||||||
|
if (!taskId) return task;
|
||||||
|
try {
|
||||||
|
const res = await this.$api.post(API_FACTORY_DETAIL, { promotion_factory_id: taskId });
|
||||||
|
if (!res || (res.code != null && Number(res.code) !== 0)) {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
const payload = res.data != null ? res.data : res;
|
||||||
|
if (Array.isArray(payload)) return payload[0] || task;
|
||||||
|
if (payload && typeof payload === 'object') {
|
||||||
|
if (payload.detail && typeof payload.detail === 'object') return payload.detail;
|
||||||
|
if (payload.data && typeof payload.data === 'object' && !Array.isArray(payload.data)) return payload.data;
|
||||||
|
const fromArray = this.findArray(payload);
|
||||||
|
if (Array.isArray(fromArray) && fromArray.length) return fromArray[0];
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
},
|
||||||
|
async loadTemplateNameMapByJournal(journalId) {
|
||||||
|
const key = String(journalId || '');
|
||||||
|
if (!key) return {};
|
||||||
|
if (this.templateNameMap[key]) return this.templateNameMap[key];
|
||||||
|
let map = {};
|
||||||
|
try {
|
||||||
|
const res = await this.$api.post(API_TEMPLATE_LIST_ALL, { journal_id: key });
|
||||||
|
const payload = (res && res.data) || {};
|
||||||
|
const list = this.findArray(payload) || this.findArray(res) || [];
|
||||||
|
map = (Array.isArray(list) ? list : []).reduce(function (acc, item) {
|
||||||
|
const id = item && (item.template_id != null ? item.template_id : item.id);
|
||||||
|
const name = item && (item.title || item.name || '');
|
||||||
|
if (id != null && String(name).trim() !== '') {
|
||||||
|
acc[String(id)] = String(name);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
map = {};
|
||||||
|
}
|
||||||
|
this.$set(this.templateNameMap, key, map);
|
||||||
|
return map;
|
||||||
|
},
|
||||||
|
async applyInitialTaskSeed(seedTask) {
|
||||||
|
const task = seedTask && typeof seedTask === 'object' ? seedTask : this.initialTask && typeof this.initialTask === 'object' ? this.initialTask : null;
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
|
const taskId = this.getInitialTaskId(task);
|
||||||
|
this.editingTaskId = taskId || this.editingTaskId;
|
||||||
if (task.type != null && String(task.type) !== '') {
|
if (task.type != null && String(task.type) !== '') {
|
||||||
this.factoryType = String(task.type);
|
this.factoryType = String(task.type);
|
||||||
}
|
}
|
||||||
@@ -491,7 +575,10 @@
|
|||||||
this.factoryZoneCountryIds = zoneKeys;
|
this.factoryZoneCountryIds = zoneKeys;
|
||||||
if (task.template_id != null && String(task.template_id) !== '') {
|
if (task.template_id != null && String(task.template_id) !== '') {
|
||||||
this.factoryConfig.defaultTemplateId = String(task.template_id);
|
this.factoryConfig.defaultTemplateId = String(task.template_id);
|
||||||
this.factoryTemplateName = task.template_name || `Template #${task.template_id}`;
|
const tplId = String(task.template_id);
|
||||||
|
const fallbackTplName = task.template_name || '';
|
||||||
|
const templateMap = await this.loadTemplateNameMapByJournal(this.selectedJournalId);
|
||||||
|
this.factoryTemplateName = templateMap[tplId] || fallbackTplName || `Template #${task.template_id}`;
|
||||||
}
|
}
|
||||||
if (task.style_id != null && String(task.style_id) !== '') {
|
if (task.style_id != null && String(task.style_id) !== '') {
|
||||||
this.factoryConfig.defaultStyleId = String(task.style_id);
|
this.factoryConfig.defaultStyleId = String(task.style_id);
|
||||||
@@ -896,21 +983,31 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pc = this.buildPartitionsAndCountries();
|
const pc = this.buildPartitionsAndCountries();
|
||||||
|
const payload = {
|
||||||
|
journal_id: String(this.selectedJournalId),
|
||||||
|
type: String(this.factoryType),
|
||||||
|
expert_type: String(this.expertType || '').trim(),
|
||||||
|
email_ids: this.selectedEmailIds.join(','),
|
||||||
|
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,
|
||||||
|
start_promotion: '0'
|
||||||
|
};
|
||||||
|
const endpoint = this.isEditMode ? API_FACTORY_EDIT : API_FACTORY_ADD;
|
||||||
|
if (this.isEditMode) {
|
||||||
|
const taskId = this.editingTaskId || this.getInitialTaskId(this.initialTask || {});
|
||||||
|
if (!taskId) {
|
||||||
|
this.$message.error(this.$t('autoPromotion.factorySubmitFailed'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
payload.promotion_factory_id = String(taskId);
|
||||||
|
}
|
||||||
this.submitting = true;
|
this.submitting = true;
|
||||||
try {
|
try {
|
||||||
const res = await this.$api.post(API_FACTORY_ADD, {
|
const res = await this.$api.post(endpoint, payload);
|
||||||
journal_id: String(this.selectedJournalId),
|
|
||||||
type: String(this.factoryType),
|
|
||||||
expert_type: String(this.expertType || '').trim(),
|
|
||||||
email_ids: this.selectedEmailIds.join(','),
|
|
||||||
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,
|
|
||||||
start_promotion: '0'
|
|
||||||
});
|
|
||||||
if (res && Number(res.code) === 0) {
|
if (res && Number(res.code) === 0) {
|
||||||
this.$message.success(this.$t('autoPromotion.factorySubmitSuccess'));
|
this.$message.success(this.$t('autoPromotion.factorySubmitSuccess'));
|
||||||
this.innerVisible = false;
|
this.innerVisible = false;
|
||||||
@@ -1229,7 +1326,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 6px 14px;
|
gap: 6px 14px;
|
||||||
padding: 10px 16px 10px 18px;
|
padding: 10px 16px 10px 18px;
|
||||||
@@ -1244,7 +1341,7 @@
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
@@ -1267,6 +1364,13 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter-bar .param-inline-controls-send {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.parameter-bar .param-item-send {
|
.parameter-bar .param-item-send {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
@@ -1284,6 +1388,11 @@
|
|||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter-bar .el-input-number--small .el-input__inner {
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.max-tip {
|
.max-tip {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
color: #e6a23c;
|
color: #e6a23c;
|
||||||
@@ -1291,6 +1400,10 @@
|
|||||||
max-width: 260px;
|
max-width: 260px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-tip-under {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.factory-required-star {
|
.factory-required-star {
|
||||||
color: #f56c6c;
|
color: #f56c6c;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
@@ -1346,7 +1459,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.more-hint { font-size: 12px; color: #409eff; font-weight: bold; }
|
.more-hint { font-size: 12px; color: #409eff; font-weight: bold; }
|
||||||
/deep/.el-dialog__body{
|
::v-deep .el-dialog__body{
|
||||||
padding-top:15px !important;
|
padding-top:15px !important;
|
||||||
padding-bottom:15px !important;
|
padding-bottom:15px !important;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user