提交
This commit is contained in:
@@ -62,13 +62,13 @@
|
||||
</div>
|
||||
<div class="status-tag">
|
||||
<span class="dot"></span>
|
||||
{{ taskCard.enabled ? $t('autoPromotion.running').toUpperCase() : 'STOPPED' }}
|
||||
{{ taskCard.enabled ? $t('autoPromotion.running') : $t('autoPromotion.stopped') }}
|
||||
</div>
|
||||
</div>
|
||||
<el-switch
|
||||
:value="taskCard.enabled"
|
||||
size="small"
|
||||
active-color="#409EFF"
|
||||
active-color="#3DBB6A"
|
||||
:disabled="!taskCard.taskId || !!taskCard.switchLoading"
|
||||
@change="onFactoryTaskSwitchChange(journal, taskCard, $event)"
|
||||
/>
|
||||
@@ -76,21 +76,21 @@
|
||||
|
||||
<div class="card-content">
|
||||
<div class="template-preview-box">
|
||||
<div>
|
||||
<div class="meta-row">
|
||||
<i class="el-icon-message"
|
||||
><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 class="meta-row">
|
||||
<i class="el-icon-collection-tag"
|
||||
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Promotion Fields :</span></i
|
||||
>
|
||||
<span class="tpl-name">{{ taskCard.fieldCountText }}</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="meta-row">
|
||||
<i class="el-icon-location-outline"
|
||||
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Country :</span></i
|
||||
>
|
||||
@@ -112,18 +112,29 @@
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</span>
|
||||
<span v-else>CONFIGURE</span>
|
||||
<span v-else>{{ getFactoryTaskActionText(taskCard) }}</span>
|
||||
</button>
|
||||
<div v-if="taskCard.createdAtText" class="task-create-time">
|
||||
{{ $t('autoPromotion.createdAt') }}: {{ taskCard.createdAtText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-task-tip">
|
||||
<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') }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -196,6 +207,7 @@ export default {
|
||||
saving: false,
|
||||
promotionUpdating: false,
|
||||
promotionUpdatingJournalId: '',
|
||||
promotionUpdatingTaskId: '',
|
||||
wizardJournal: null,
|
||||
wizardStartDate: '',
|
||||
wizardConfig: {
|
||||
@@ -215,6 +227,7 @@ export default {
|
||||
templateDialogInitialStyleId: '',
|
||||
templateDialogInitialTemplateId: '',
|
||||
templateNameMap: {},
|
||||
factoryTemplateNameMap: {},
|
||||
allJournals: [],
|
||||
showFactoryTaskDialog: false,
|
||||
factoryDialogInitialJournalId: '',
|
||||
@@ -225,6 +238,9 @@ export default {
|
||||
this.fetchPromotionJournals();
|
||||
},
|
||||
methods: {
|
||||
savePromotionCountriesNow(){
|
||||
|
||||
},
|
||||
// --- 逻辑部分完全保留你原有的实现 ---
|
||||
openTemplateSelector() {
|
||||
this.templateDialogInitialStyleId =
|
||||
@@ -279,6 +295,38 @@ export default {
|
||||
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) {
|
||||
const journalInfo = data.journal || data || {};
|
||||
const tpl = journalInfo.template || data.template || {};
|
||||
@@ -356,6 +404,7 @@ export default {
|
||||
async loadFactoryTaskSummaryByJournal(journal, userId) {
|
||||
if (!journal || !journal.journal_id) return;
|
||||
try {
|
||||
await this.loadFactoryTemplateNamesByJournal(journal.journal_id);
|
||||
const res = await this.$api.post('api/promotion_factory/getList', {
|
||||
journal_id: String(journal.journal_id),
|
||||
user_id: String(userId || ''),
|
||||
@@ -375,7 +424,12 @@ export default {
|
||||
const normalizedTasks = (Array.isArray(list) ? list : []).map((task, idx) => {
|
||||
const type = task && task.type != null ? String(task.type) : '';
|
||||
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 {
|
||||
cardKey: `${journal.journal_id}_${task.promotion_factory_id || idx}`,
|
||||
taskId: task.promotion_factory_id || '',
|
||||
@@ -384,10 +438,11 @@ export default {
|
||||
enabled: enabled,
|
||||
switchLoading: false,
|
||||
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,
|
||||
fieldCountText: String(fieldCount),
|
||||
countryScopeLabel: task.country_scope_label || '-',
|
||||
createdAtText: this.formatTaskCreateTime(task),
|
||||
totalCount: total,
|
||||
showCount: idx === 0 && total > 0,
|
||||
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) {
|
||||
if (!task) return 0;
|
||||
if (task.fetch_fields && typeof task.fetch_fields === 'object') {
|
||||
@@ -423,6 +509,23 @@ export default {
|
||||
.filter(Boolean);
|
||||
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) {
|
||||
const t = String(type || '');
|
||||
if (t === '1') return this.$t('autoPromotion.factoryScenarioSolicit');
|
||||
@@ -443,6 +546,7 @@ export default {
|
||||
},
|
||||
async refreshAll() {
|
||||
this.templateNameMap = {};
|
||||
this.factoryTemplateNameMap = {};
|
||||
this.allJournals = [];
|
||||
await this.fetchPromotionJournals();
|
||||
},
|
||||
@@ -512,34 +616,7 @@ export default {
|
||||
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) {
|
||||
this.wizardJournal = journal;
|
||||
const s = journal.solicit || {};
|
||||
@@ -575,8 +652,15 @@ export default {
|
||||
this.saving = false;
|
||||
}
|
||||
},
|
||||
openDetail(journal) {
|
||||
this.$router.push({ path: '/autoPromotionLogs', query: { journal_id: String(journal.journal_id) } });
|
||||
openDetail(journal,taskCard) {
|
||||
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) {
|
||||
if (!this.isSolicitConfigured(journal)) {
|
||||
@@ -713,6 +797,13 @@ export default {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.no-task-create-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 统计卡片基础样式 */
|
||||
.stat-card {
|
||||
background: #ffffff;
|
||||
@@ -732,7 +823,7 @@ export default {
|
||||
}
|
||||
|
||||
.stat-card.is-active {
|
||||
border-top: 3px solid #409eff;
|
||||
border-top: 3px solid #67c23a;
|
||||
}
|
||||
|
||||
.stat-card.is-stopped {
|
||||
@@ -839,6 +930,12 @@ export default {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.template-preview-box.is-empty {
|
||||
color: #909399;
|
||||
font-style: italic;
|
||||
@@ -852,6 +949,11 @@ export default {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tpl-name-single-line {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 统计项 */
|
||||
.stats-container {
|
||||
display: grid;
|
||||
@@ -896,24 +998,46 @@ export default {
|
||||
/* 底部按钮区 */
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-create-time {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.action-main-btn {
|
||||
flex: 1;
|
||||
height: 30px;
|
||||
background: #006699;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: 700;
|
||||
height: 24px;
|
||||
background: #eaf3ff;
|
||||
color: #409eff;
|
||||
border: 1px solid #d7e7ff;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
line-height: 22px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.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 {
|
||||
|
||||
Reference in New Issue
Block a user