修改自动推广的相关任务

This commit is contained in:
wangjinlei
2026-04-22 18:15:09 +08:00
parent f1fad67f76
commit 5f724217c0
2 changed files with 122 additions and 99 deletions

View File

@@ -1362,84 +1362,48 @@ class EmailClient extends Base
// ==================== Promotion Tasks ==================== // ==================== Promotion Tasks ====================
/** /**
* Create a promotion sending task * 基于任务工厂创建单个推广任务(手动触发)
* Params: *
* - journal_id, template_id, style_id, scene, task_name * 参数:
* - expert_ids (comma separated) OR field + major_id (auto-query from DB) * - promotion_factory_id 必填工厂ID任务的模板/领域/国家/发送参数均从工厂读取
* - smtp_ids (comma separated, optional: restrict to specific SMTP accounts) * - send_date 可选默认明天Y-m-d
* - min_interval, max_interval (seconds between emails) * - task_name (可选,默认 "Manual-{journal_title}-F{factory_id}-{send_date}")
* - max_bounce_rate (%), no_repeat_days * - no_repeat_days (可选,默认 30覆盖默认不重复天数
* - send_start_hour, send_end_hour (UTC, default 8-22) * - min_interval/max_interval/max_bounce_rate/send_start_hour/send_end_hour 可选覆盖
* - send_date (Y-m-d计划发送日期有则「今日准备明日发」由定时任务处理无则创建后需手动 startTask)
*/ */
public function createTask() public function createTask()
{ {
$journalId = intval($this->request->param('journal_id', 0)); $factoryId = intval($this->request->param('promotion_factory_id', 0));
$templateId = intval($this->request->param('template_id', 0)); $sendDate = trim($this->request->param('send_date', date('Y-m-d', strtotime('+1 day'))));
$styleId = intval($this->request->param('style_id', 0)); $taskName = trim($this->request->param('task_name', ''));
$scene = trim($this->request->param('scene', '')); $noRepeatDays = intval($this->request->param('no_repeat_days', 30));
$taskName = trim($this->request->param('task_name', '')); $minInterval = intval($this->request->param('min_interval', 30));
$expertIds = trim($this->request->param('expert_ids', '')); $maxInterval = intval($this->request->param('max_interval', 60));
$field = trim($this->request->param('field', ''));
$fetchIds = trim($this->request->param('fetch_ids', ''));
$smtpIds = trim($this->request->param('smtp_ids', ''));
$minInterval = intval($this->request->param('min_interval', 30));
$maxInterval = intval($this->request->param('max_interval', 60));
$maxBounceRate = intval($this->request->param('max_bounce_rate', 5)); $maxBounceRate = intval($this->request->param('max_bounce_rate', 5));
$noRepeatDays = intval($this->request->param('no_repeat_days', 7)); $sendStartHour = intval($this->request->param('send_start_hour', 8));
$sendStartHour = intval($this->request->param('send_start_hour', 8)); $sendEndHour = intval($this->request->param('send_end_hour', 22));
$sendEndHour = intval($this->request->param('send_end_hour', 22));
$sendDate = trim($this->request->param('send_date', date("Y-m-d",strtotime('+1 day'))));
$targetPartitions = trim($this->request->param('target_partitions', ''));
$targetCountryIds = trim($this->request->param('target_country_ids', ''));
$type = intval($this->request->param('type', 0));
$expertType = intval($this->request->param('expert_type', 5));
if (!$journalId) { if (!$factoryId) {
return jsonError('journal_id is required'); return jsonError('promotion_factory_id is required');
} }
$journal_info = $this->journal_obj->where("journal_id",$journalId)->find();
$templateId = ($templateId == 0) ? intval($journal_info['default_template_id']) : $templateId; $factory = Db::name('promotion_factory')
$styleId = ($styleId == 0) ? intval(isset($journal_info['default_style_id']) ? $journal_info['default_style_id'] : 0) : $styleId; ->where('promotion_factory_id', $factoryId)
if($templateId==0){
return jsonError("template is not set!");
}
$tpl = Db::name('mail_template')
->where('template_id', $templateId)
->where('journal_id', $journalId)
->where('state', 0)
->find(); ->find();
if (!$tpl) { if (!$factory) {
return jsonError('Template not found for this journal'); return jsonError('Factory not found');
}
if (intval($factory['state']) !== 0) {
return jsonError('Factory is disabled');
}
if (intval($factory['expert_type']) !== 5) {
return jsonError('Only expert_type=5 is supported currently');
} }
if (empty($scene)) { $journalId = intval($factory['journal_id']);
$scene = $tpl['scene']; $journal = Db::name('journal')->where('journal_id', $journalId)->find();
} if (!$journal) {
return jsonError('Journal not found');
$experts = [];
if (!empty($expertIds)) {
$ids = array_map('intval', explode(',', $expertIds));
$experts = Db::name('expert')
->where('expert_id', 'in', $ids)
->where('state', 0)
->select();
} else {
// 领域来源优先级:前端传 field > 前端传 fetch_ids > journal_promotion_field
$fields = [];
if ($field !== '') {
$fields = [$field];
} elseif ($fetchIds !== '') {
$fields = $this->resolveFieldsByFetchIds($fetchIds);
} else {
$fields = $this->resolveFieldsByJournal($journalId);
}
$experts = $this->findEligibleExperts($fields, $noRepeatDays, 100, $targetPartitions, $targetCountryIds);
}
if (empty($experts)) {
return jsonError('No eligible experts found (all may have been promoted recently)');
} }
$sendDateVal = null; $sendDateVal = null;
@@ -1450,16 +1414,78 @@ class EmailClient extends Base
} }
} }
$now = time(); if ($sendDateVal) {
$existTask = Db::name('promotion_task')
->where('factory_id', $factoryId)
->where('send_date', $sendDateVal)
->where('state', 'in', [0, 1, 5])
->find();
if ($existTask) {
return jsonError('Factory already has an active task for send_date=' . $sendDateVal . ' (task_id=' . $existTask['task_id'] . ')');
}
}
$templateId = intval($factory['template_id']) > 0
? intval($factory['template_id'])
: intval($journal['default_template_id']);
$styleId = intval($factory['style_id']) > 0
? intval($factory['style_id'])
: intval(isset($journal['default_style_id']) ? $journal['default_style_id'] : 0);
if ($templateId <= 0) {
return jsonError('template_id is not set on factory or journal');
}
$tpl = Db::name('mail_template')
->where('template_id', $templateId)
->where('journal_id', $journalId)
->where('state', 0)
->find();
if (!$tpl) {
return jsonError('Template not found for this journal');
}
$scene = $tpl['scene'] ?? 'promotion';
$smtpIds = trim((string)$factory['email_ids']);
if ($smtpIds === '') {
$smtpCount = Db::name('journal_email')
->where('journal_id', $journalId)
->where('state', 0)
->count();
if ($smtpCount == 0) {
return jsonError('No active SMTP account for this journal');
}
}
$fields = $this->resolveFieldsByFetchIds($factory['fetch_ids']);
if (empty($fields)) {
return jsonError('No valid fields resolved from factory.fetch_ids');
}
$targetPartitions = trim((string)$factory['target_partitions']);
$targetCountryIds = trim((string)$factory['target_country_ids']);
$dailyLimit = max(1, intval($factory['send_count']));
$experts = $this->findEligibleExperts($fields, $noRepeatDays, $dailyLimit, $targetPartitions, $targetCountryIds);
if (empty($experts)) {
return jsonError('No eligible experts found (all may have been promoted recently)');
}
if ($taskName === '') {
$taskName = 'Manual-' . ($journal['title'] ?? $journalId) . '-F' . $factoryId . '-' . ($sendDateVal ?: date('Y-m-d H:i'));
}
$now = time();
$taskId = Db::name('promotion_task')->insertGetId([ $taskId = Db::name('promotion_task')->insertGetId([
'journal_id' => $journalId, 'journal_id' => $journalId,
'factory_id' => 0, 'factory_id' => $factoryId,
'template_id' => $templateId, 'template_id' => $templateId,
'style_id' => $styleId, 'style_id' => $styleId,
'scene' => $scene, 'scene' => $scene,
'type' => $type, 'type' => intval($factory['type']),
'expert_type' => $expertType, 'expert_type' => intval($factory['expert_type']),
'task_name' => $taskName ?: ('Task ' . date('Y-m-d H:i')), 'task_name' => $taskName,
'total_count' => count($experts), 'total_count' => count($experts),
'sent_count' => 0, 'sent_count' => 0,
'fail_count' => 0, 'fail_count' => 0,
@@ -1501,6 +1527,7 @@ class EmailClient extends Base
} }
return jsonSuccess([ return jsonSuccess([
'task_id' => $taskId, 'task_id' => $taskId,
'factory_id' => $factoryId,
'total_count' => count($experts), 'total_count' => count($experts),
'state' => 0, 'state' => 0,
'send_date' => $sendDateVal, 'send_date' => $sendDateVal,
@@ -1583,32 +1610,7 @@ class EmailClient extends Base
// ==================== Journal Promotion Field Mapping ==================== // ==================== Journal Promotion Field Mapping ====================
/**
* 获取某期刊已选的推广领域
* 参数: journal_id
*/
public function getJournalPromotionFields()
{
$journalId = intval($this->request->param('journal_id', 0));
if (!$journalId) {
return jsonError('journal_id is required');
}
$list = Db::name('journal_promotion_field')
->alias('jpf')
->join('t_expert_fetch ef', 'ef.expert_fetch_id = jpf.expert_fetch_id', 'left')
->where('jpf.journal_id', $journalId)
->where('jpf.state', 0)
->field('jpf.jpf_id, jpf.expert_fetch_id, ef.field, ef.source, ef.state as fetch_state, jpf.ctime')
->order('jpf.jpf_id asc')
->select();
foreach ($list as &$item) {
$item['ctime_text'] = $item['ctime'] ? date('Y-m-d H:i:s', $item['ctime']) : '';
}
return jsonSuccess($list);
}
/** /**
* 设置/更新期刊的推广领域(全量覆盖) * 设置/更新期刊的推广领域(全量覆盖)
@@ -1872,6 +1874,8 @@ class EmailClient extends Base
public function getTaskList() public function getTaskList()
{ {
$journalId = intval($this->request->param('journal_id', 0)); $journalId = intval($this->request->param('journal_id', 0));
$factoryId = $this->request->param('factory_id', '');
$type = $this->request->param('type', '');
$state = $this->request->param('state', '-1'); $state = $this->request->param('state', '-1');
$page = max(1, intval($this->request->param('page', 1))); $page = max(1, intval($this->request->param('page', 1)));
$perPage = max(1, min(intval($this->request->param('per_page', 20)), 100)); $perPage = max(1, min(intval($this->request->param('per_page', 20)), 100));
@@ -1880,6 +1884,12 @@ class EmailClient extends Base
if ($journalId) { if ($journalId) {
$where['journal_id'] = $journalId; $where['journal_id'] = $journalId;
} }
if ($factoryId !== '' && $factoryId !== '-1') {
$where['factory_id'] = intval($factoryId);
}
if ($type !== '' && $type !== '-1') {
$where['type'] = intval($type);
}
if ($state !== '-1' && $state !== '') { if ($state !== '-1' && $state !== '') {
$where['state'] = intval($state); $where['state'] = intval($state);
} }

View File

@@ -133,6 +133,19 @@ class PromotionFactory extends Base
return jsonSuccess(['promotion_factory_id' => $id]); return jsonSuccess(['promotion_factory_id' => $id]);
} }
public function changePromotionAct(){
$data = $this->request->post();
$rule = new Validate([
"promotion_factory_id"=>"require",
"start_promotion"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
Db::name("promotion_factory")->where("promotion_factory_id",$data['promotion_factory_id'])->update(['start_promotion'=>$data['start_promotion']]);
return jsonSuccess();
}
public function getCountForPromotionEmailIds(){ public function getCountForPromotionEmailIds(){
$data = $this->request->post(); $data = $this->request->post();
$rule = new Validate([ $rule = new Validate([