任务工厂

This commit is contained in:
2026-04-24 11:05:22 +08:00
parent 632913aaad
commit fe4bd7c9b0
8 changed files with 1068 additions and 99 deletions

View File

@@ -83,12 +83,12 @@
<span class="tpl-name tpl-name-single-line">{{ taskCard.templateName || 'No Template Configured' }}</span>
</div>
<div class="meta-row">
<!-- <div class="meta-row">
<i class="el-icon-collection-tag"
><span style="font-size: 11px; margin-left: 3px; margin-right: 3px">Promotion Fields&nbsp;:</span></i
>
<span class="tpl-name">{{ taskCard.fieldCountText }}</span>
</div>
</div> -->
<div class="meta-row">
<i class="el-icon-location-outline"
@@ -99,7 +99,7 @@
</div>
<div class="stats-container">
<!-- <div class="stats-container">
<div class="stat-box">
<span class="stat-label">SENT</span>
<span class="stat-value"><i class="el-icon-circle-check"></i> 1,240</span>
@@ -108,7 +108,7 @@
<span class="stat-label">PENDING</span>
<span class="stat-value warning"><i class="el-icon-time"></i> 150</span>
</div>
</div>
</div> -->
</div>
<div class="card-actions">
@@ -125,8 +125,20 @@
</span>
<span v-else>{{ getFactoryTaskActionText(taskCard) }}</span>
</button>
<div v-if="taskCard.createdAtText" class="task-create-time">
{{ $t('autoPromotion.createdAt') }}: {{ taskCard.createdAtText }}
<div class="task-card-footer-row">
<button
v-if="!taskCard.enabled && taskCard.taskId"
type="button"
class="promo-history-link"
@click.stop="openDetail(journal, taskCard)"
>
<span>{{ $t('autoPromotion.logs') }}</span>
<i class="el-icon-document"></i>
</button>
<span v-else class="promo-history-spacer"></span>
<div v-if="taskCard.createdAtText" class="task-create-time">
{{ $t('autoPromotion.createdAt') }}: {{ taskCard.createdAtText }}
</div>
</div>
</div>
</div>
@@ -364,6 +376,10 @@ export default {
this.allJournals = [];
return;
}
const journalIdsForTpl = raw
.map((item) => item.journal_id || item.id)
.filter((id) => id != null && String(id).trim() !== '');
await this.prefetchFactoryTemplateNameMapsOnce(journalIdsForTpl);
this.allJournals = await Promise.all(
raw.map(async (item) => {
const journalId = item.journal_id || item.id;
@@ -404,7 +420,6 @@ 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 || ''),
@@ -466,29 +481,47 @@ export default {
});
}
},
async loadFactoryTemplateNamesByJournal(journalId) {
const key = String(journalId || '');
if (!key) return {};
if (this.factoryTemplateNameMap[key]) {
return this.factoryTemplateNameMap[key];
}
let map = {};
/**
* 全页只请求一次 listTemplatesAll再按期刊写入 factoryTemplateNameMap。
* 若列表项带 journal_id 则按期刊拆分;否则用同一份 id->name 映射到当前页各期刊(与原先「每刊各请求一次」相比只发 1 次 HTTP
*/
async prefetchFactoryTemplateNameMapsOnce(journalIds) {
const ids = [...new Set((journalIds || []).map((id) => String(id).trim()).filter(Boolean))];
if (!ids.length) return;
try {
const res = await this.$api.post('api/mail_template/listTemplatesAll', { journal_id: key });
const res = await this.$api.post('api/mail_template/listTemplatesAll', { journal_id: ids[0] });
const payload = (res && res.data) || {};
const list = this.findArray(payload) || this.findArray(res) || [];
map = (Array.isArray(list) ? list : []).reduce((acc, item) => {
const flat = {};
const byJournal = {};
(Array.isArray(list) ? list : []).forEach((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;
}, {});
if (id == null) return;
const name = String(item.title || item.name || '').trim();
if (!name) return;
const tid = String(id);
flat[tid] = name;
const jid =
item.journal_id != null
? String(item.journal_id).trim()
: item.journalId != null
? String(item.journalId).trim()
: item.j_id != null
? String(item.j_id).trim()
: '';
if (jid) {
if (!byJournal[jid]) byJournal[jid] = {};
byJournal[jid][tid] = name;
}
});
const perItemJournal = Object.keys(byJournal).length > 0;
ids.forEach((jid) => {
const m = perItemJournal ? byJournal[jid] || {} : { ...flat };
this.$set(this.factoryTemplateNameMap, jid, m);
});
} catch (e) {
map = {};
console.error(e);
}
this.$set(this.factoryTemplateNameMap, key, map);
return map;
},
getFactoryTemplateName(task, journalId) {
const tplId = task && task.template_id != null ? String(task.template_id) : '';
@@ -1002,7 +1035,47 @@ export default {
gap: 8px;
}
.task-card-footer-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-height: 16px;
}
.promo-history-spacer {
flex: 0 0 auto;
min-width: 0;
}
.promo-history-link {
flex: 0 1 auto;
display: inline-flex;
align-items: center;
gap: 4px;
margin: 0;
padding: 0;
border: none;
background: transparent;
font-size: 11px;
font-weight: 600;
color: #409eff;
cursor: pointer;
line-height: 1.3;
text-align: left;
}
.promo-history-link i {
font-size: 12px;
}
.promo-history-link:hover {
color: #66b1ff;
text-decoration: underline;
}
.task-create-time {
flex-shrink: 0;
font-size: 11px;
color: #909399;
text-align: right;