Commit 7a200f4e authored by hzl's avatar hzl

feat: 任务页字段处理

parent 709dac45
...@@ -181,69 +181,108 @@ ...@@ -181,69 +181,108 @@
</el-switch> </el-switch>
</el-form-item> </el-form-item>
<el-form-item label="优化目标" prop="tiktok_json.optimizationGoal"> <el-form-item
<el-select v-model="form.tiktok_json.optimizationGoal" placeholder="请选择优化目标"> label="选择账户"
<el-option label="价值优化" value="VALUE"></el-option> prop="tiktok_json.advertiserId">
<el-option label="应用安装" value="INSTALL"></el-option> <el-select
v-model="form.tiktok_json.advertiserId"
placeholder="请选择账户"
:loading="advertiserLoading"
@change="handleAdvertiserChange">
<el-option
v-for="item in advertiserOptions"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="深度出价类型" prop="tiktok_json.deepBidType"> <el-form-item label="优化目标" prop="tiktok_json.optimizationGoal">
<el-select v-model="form.tiktok_json.deepBidType" placeholder="请选择深度出价类型"> <el-select v-model="form.tiktok_json.optimizationGoal" placeholder="请选择优化目标" @change="handleOptimizationGoalChange">
<el-option label="最小ROAS" value="VO_MIN_ROAS"></el-option> <el-option label="价值" value="VALUE"></el-option>
<el-option label="最高价值" value="VO_HIGHEST_VALUE"></el-option> <el-option label="安装" value="INSTALL"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="深度CPA出价" prop="tiktok_json.deepCpaBid"> <!-- 级联优化事件选择框 -->
<el-input-number v-model="form.tiktok_json.deepCpaBid" :min="0" :precision="2"></el-input-number> <el-form-item
label="优化事件"
prop="tiktok_json.optimizationEvent"
v-if="form.tiktok_json.optimizationGoal === 'VALUE'">
<el-select v-model="form.tiktok_json.optimizationEvent" placeholder="请选择优化事件">
<el-option label="应用内购价值" value="ACTIVE_PAY"></el-option>
<el-option label="广告收入价值" value="AD_REVENUE_VALUE"></el-option>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="投放位置" prop="tiktok_json.placements"> <el-form-item
<el-select v-model="form.tiktok_json.placements" multiple placeholder="请选择投放位置"> label="深度出价类型"
<el-option label="TikTok" value="PLACEMENT_TIKTOK"></el-option> prop="tiktok_json.deepBidType"
<el-option label="Pangle" value="PLACEMENT_PANGLE"></el-option> v-if="form.tiktok_json.optimizationGoal === 'VALUE'">
<el-option label="Global App Bundle" value="PLACEMENT_GLOBAL_APP_BUNDLE"></el-option> <el-select v-model="form.tiktok_json.deepBidType" placeholder="请选择深度出价类型" @change="handleDeepBidTypeChange">
<el-option label="最小ROAS" value="VO_MIN_ROAS"></el-option>
<el-option label="最高价值" value="VO_HIGHEST_VALUE"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="是否新建计划" prop="isNewCampaign"> <!-- ROAS目标值输入框 -->
<el-form-item
label="ROAS目标值"
prop="tiktok_json.roasBid"
v-if="form.tiktok_json.optimizationGoal === 'VALUE' && form.tiktok_json.deepBidType === 'VO_MIN_ROAS'">
<el-input-number
v-model="form.tiktok_json.roasBid"
:min="0.01"
:max="1000"
:precision="2"
placeholder="请输入ROAS目标值">
</el-input-number>
</el-form-item>
<!-- 价值优化窗口期选择框 -->
<!-- <el-form-item -->
<!-- label="价值优化窗口期" -->
<!-- prop="tiktok_json.vboWindow"-->
<!-- v-if="form.tiktok_json.optimizationGoal === 'VALUE'">-->
<!-- <el-select v-model="form.tiktok_json.vboWindow" placeholder="请选择价值优化窗口期">-->
<!-- <el-option label="前7天" value="SEVEN_DAYS"></el-option>-->
<!-- <el-option label="第0天(当天)" value="ZERO_DAY"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="深度CPA出价" prop="tiktok_json.deepCpaBid">-->
<!-- <el-input-number v-model="form.tiktok_json.deepCpaBid" :min="0" :precision="2"></el-input-number>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="投放位置" prop="tiktok_json.placements">-->
<!-- <el-select v-model="form.tiktok_json.placements" multiple placeholder="请选择投放位置">-->
<!-- <el-option label="TikTok" value="PLACEMENT_TIKTOK"></el-option>-->
<!-- <el-option label="Pangle" value="PLACEMENT_PANGLE"></el-option>-->
<!-- <el-option label="Global App Bundle" value="PLACEMENT_GLOBAL_APP_BUNDLE"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="是否新建计划" prop="tiktok_json.isNewCampaign">
<el-switch <el-switch
v-model="form.isNewCampaign" v-model="form.tiktok_json.isNewCampaign"
active-text="是" active-text="是"
inactive-text="否"> inactive-text="否">
</el-switch> </el-switch>
</el-form-item> </el-form-item>
<template v-if="!form.isNewCampaign"> <template v-if="!form.tiktok_json.isNewCampaign">
<el-form-item <el-form-item
label="选择账户" label="选择已有计划"
prop="advertiserId"> prop="tiktok_json.campaignIdList"
<el-select v-if="form.tiktok_json.advertiserId">
v-model="form.advertiserId" <el-select
placeholder="请选择账户" v-model="form.tiktok_json.campaignIdList"
:loading="advertiserLoading" multiple
@change="handleAdvertiserChange"> filterable
<el-option placeholder="请输入计划名称搜索"
v-for="item in advertiserOptions" :loading="campaignListLoading"
:key="item" style="width: 100%">
:label="item"
:value="item">
</el-option>
</el-select>
</el-form-item>
<el-form-item
label="选择已有计划"
prop="campaignIdList"
v-if="form.advertiserId">
<el-select
v-model="form.campaignIdList"
multiple
filterable
placeholder="请输入计划名称搜索"
:loading="campaignListLoading"
style="width: 100%">
<el-option <el-option
v-for="item in campaignOptions" v-for="item in campaignOptions"
:key="item.campaignId" :key="item.campaignId"
...@@ -687,17 +726,19 @@ export default { ...@@ -687,17 +726,19 @@ export default {
material_groups: [], material_groups: [],
title_groups: [], title_groups: [],
description_groups: [], description_groups: [],
// 新增TikTok特定字段
isNewCampaign: true,
advertiserId: '', // 新增:选中的广告主ID
campaignIdList: [],
// 修改字段名为tiktok_json // 修改字段名为tiktok_json
tiktok_json: { tiktok_json: {
optimizationGoal: 'VALUE', optimizationGoal: 'VALUE',
optimizationEvent: '', // 新增优化事件字段
deepBidType: 'VO_MIN_ROAS', deepBidType: 'VO_MIN_ROAS',
deepCpaBid: 0, deepCpaBid: 0,
roasBid: 0, // 新增ROAS目标值字段
vboWindow: '', // 新增价值优化窗口期字段
placements: [], placements: [],
isSmart: false // 添加isSmart字段,默认为false isSmart: false, // 添加isSmart字段,默认为false
isNewCampaign: true, // 是否新建计划
advertiserId: '', // 选中的广告主ID
campaignIdList: [] // 计划ID列表
} }
}, },
selectedTemplate: null, selectedTemplate: null,
...@@ -736,8 +777,33 @@ export default { ...@@ -736,8 +777,33 @@ export default {
'tiktok_json.optimizationGoal': [ 'tiktok_json.optimizationGoal': [
{ required: true, message: '请选择优化目标', trigger: 'change' } { required: true, message: '请选择优化目标', trigger: 'change' }
], ],
'tiktok_json.optimizationEvent': [
{
required: true,
message: '请选择优化事件',
trigger: 'change',
validator: (rule, value, callback) => {
if (this.form.tiktok_json.optimizationGoal === 'VALUE' && !value) {
callback(new Error('请选择优化事件'));
} else {
callback();
}
}
}
],
'tiktok_json.deepBidType': [ 'tiktok_json.deepBidType': [
{ required: true, message: '请选择深度出价类型', trigger: 'change' } {
required: true,
message: '请选择深度出价类型',
trigger: 'change',
validator: (rule, value, callback) => {
if (this.form.tiktok_json.optimizationGoal === 'VALUE' && !value) {
callback(new Error('请选择深度出价类型'));
} else {
callback();
}
}
}
], ],
'tiktok_json.deepCpaBid': [ 'tiktok_json.deepCpaBid': [
{ required: true, message: '请输入深度CPA出价', trigger: 'blur' }, { required: true, message: '请输入深度CPA出价', trigger: 'blur' },
...@@ -745,6 +811,52 @@ export default { ...@@ -745,6 +811,52 @@ export default {
], ],
'tiktok_json.placements': [ 'tiktok_json.placements': [
{ required: true, message: '请选择投放位置', trigger: 'change' } { required: true, message: '请选择投放位置', trigger: 'change' }
],
'tiktok_json.roasBid': [
{
required: true,
message: '请输入ROAS目标值',
trigger: 'blur',
validator: (rule, value, callback) => {
if (this.form.tiktok_json.optimizationGoal === 'VALUE' &&
this.form.tiktok_json.deepBidType === 'VO_MIN_ROAS' &&
!value) {
callback(new Error('请输入ROAS目标值'));
} else if (value && (value < 0.01 || value > 1000)) {
callback(new Error('ROAS目标值必须在0.01-1000之间'));
} else {
callback();
}
}
}
],
'tiktok_json.vboWindow': [
{
required: true,
message: '请选择价值优化窗口期',
trigger: 'change',
validator: (rule, value, callback) => {
if (this.form.tiktok_json.optimizationGoal === 'VALUE' && !value) {
callback(new Error('请选择价值优化窗口期'));
} else {
callback();
}
}
}
],
'tiktok_json.advertiserId': [
{
required: true,
message: '请选择账户',
trigger: 'change',
validator: (rule, value, callback) => {
if (!this.form.tiktok_json.isNewCampaign && !value) {
callback(new Error('请选择账户'));
} else {
callback();
}
}
}
] ]
}, },
templateMap: new Map(), templateMap: new Map(),
...@@ -908,17 +1020,19 @@ export default { ...@@ -908,17 +1020,19 @@ export default {
material_groups: [], material_groups: [],
title_groups: [], title_groups: [],
description_groups: [], description_groups: [],
// 新增TikTok特定字段
isNewCampaign: true,
advertiserId: '', // 新增:选中的广告主ID
campaignIdList: [],
// 修改字段名为tiktok_json // 修改字段名为tiktok_json
tiktok_json: { tiktok_json: {
optimizationGoal: 'VALUE', optimizationGoal: 'VALUE',
optimizationEvent: '', // 新增优化事件字段
deepBidType: 'VO_MIN_ROAS', deepBidType: 'VO_MIN_ROAS',
deepCpaBid: 0, deepCpaBid: 0,
roasBid: 0, // 新增ROAS目标值字段
vboWindow: '', // 新增价值优化窗口期字段
placements: [], placements: [],
isSmart: false // 添加isSmart字段,默认为false isSmart: false, // 添加isSmart字段,默认为false
isNewCampaign: true, // 是否新建计划
advertiserId: '', // 选中的广告主ID
campaignIdList: [] // 计划ID列表
} }
} }
...@@ -953,7 +1067,21 @@ export default { ...@@ -953,7 +1067,21 @@ export default {
location_groups: [], location_groups: [],
material_groups: [], material_groups: [],
title_groups: [], title_groups: [],
description_groups: [] description_groups: [],
// 修改字段名为tiktok_json
tiktok_json: {
optimizationGoal: 'VALUE',
optimizationEvent: '', // 新增优化事件字段
deepBidType: 'VO_MIN_ROAS',
deepCpaBid: 0,
roasBid: 0, // 新增ROAS目标值字段
vboWindow: '', // 新增价值优化窗口期字段
placements: [],
isSmart: false, // 添加isSmart字段,默认为false
isNewCampaign: true, // 是否新建计划
advertiserId: '', // 选中的广告主ID
campaignIdList: [] // 计划ID列表
}
} }
// 获取模板详情 // 获取模板详情
...@@ -1060,11 +1188,6 @@ export default { ...@@ -1060,11 +1188,6 @@ export default {
// 如果是TikTok平台,添加特定字段 // 如果是TikTok平台,添加特定字段
if (this.form.platform === 2) { if (this.form.platform === 2) {
taskData.isNewCampaign = this.form.isNewCampaign;
if (!this.form.isNewCampaign) {
taskData.advertiserId = this.form.advertiserId;
taskData.campaignIdList = this.form.campaignIdList;
}
// 修改字段名 // 修改字段名
taskData.tiktok_json = JSON.stringify(this.form.tiktok_json); taskData.tiktok_json = JSON.stringify(this.form.tiktok_json);
} }
...@@ -1207,60 +1330,76 @@ export default { ...@@ -1207,60 +1330,76 @@ export default {
const template = response.result.data; const template = response.result.data;
this.selectedTemplate = template; this.selectedTemplate = template;
// 将模板数据填充到表单中 // 将模板数据填充到表单中(优先使用模板中的值,如果没有则使用默认值)
this.form.tempName = template.name; this.form.tempName = template.name || '';
this.form.platform = template.platform || 1; this.form.platform = template.platform !== undefined ? template.platform : 1;
this.form.campaign_type = template.campaign_type || 1; this.form.campaign_type = template.campaign_type !== undefined ? template.campaign_type : 1;
this.form.appStore = template.appStore || 2; this.form.appStore = template.appStore !== undefined ? template.appStore : 2;
this.form.daily_budget = template.daily_budget || 100; this.form.daily_budget = template.daily_budget !== undefined ? template.daily_budget : 100;
this.form.bidding_type = template.bidding_type || 5; this.form.bidding_type = template.bidding_type !== undefined ? template.bidding_type : 5;
this.form.target_roas = template.target_roas || 100; this.form.target_roas = template.target_roas !== undefined ? template.target_roas : 100;
this.form.app_groups = [...(template.app_groups || [])]; this.form.app_groups = Array.isArray(template.app_groups) ? [...template.app_groups] : [];
this.form.location_groups = [...(template.location_groups || [])]; this.form.location_groups = Array.isArray(template.location_groups) ? [...template.location_groups] : [];
this.form.material_groups = [...(template.material_groups || [])]; this.form.material_groups = Array.isArray(template.material_groups) ? [...template.material_groups] : [];
this.form.title_groups = [...(template.title_groups || [])]; this.form.title_groups = Array.isArray(template.title_groups) ? [...template.title_groups] : [];
this.form.description_groups = [...(template.description_groups || [])]; this.form.description_groups = Array.isArray(template.description_groups) ? [...template.description_groups] : [];
// 处理TikTok特定字段 // 处理tiktok_json字段(所有平台都需要处理)
if (template.platform === 2) { try {
try { let tiktokData;
let tiktokData; if (template.tiktok_json) {
if (template.tiktok_json) { tiktokData = typeof template.tiktok_json === 'string' ?
tiktokData = typeof template.tiktok_json === 'string' ? JSON.parse(template.tiktok_json) : template.tiktok_json;
JSON.parse(template.tiktok_json) : template.tiktok_json; } else {
} else { // 如果没有tiktok_json,使用默认值
// 如果没有tiktok_json,使用默认值 tiktokData = {
tiktokData = {
optimizationGoal: 'VALUE',
deepBidType: 'VO_MIN_ROAS',
deepCpaBid: 0,
placements: [],
isSmart: false // 添加isSmart字段,默认为false
};
}
// 确保所有必要的字段都存在
this.form.tiktok_json = {
optimizationGoal: tiktokData.optimizationGoal || 'VALUE',
deepBidType: tiktokData.deepBidType || 'VO_MIN_ROAS',
deepCpaBid: tiktokData.deepCpaBid || 0,
placements: Array.isArray(tiktokData.placements) ? tiktokData.placements : [],
isSmart: tiktokData.isSmart || false // 添加isSmart字段处理
};
console.log('设置TikTok配置:', this.form.tiktok_json);
} catch (error) {
console.error('解析TikTok配置失败:', error);
this.$message.warning('TikTok配置解析失败,使用默认值');
// 设置默认值
this.form.tiktok_json = {
optimizationGoal: 'VALUE', optimizationGoal: 'VALUE',
optimizationEvent: '',
deepBidType: 'VO_MIN_ROAS', deepBidType: 'VO_MIN_ROAS',
deepCpaBid: 0, deepCpaBid: 0,
roasBid: 0,
vboWindow: '',
placements: [], placements: [],
isSmart: false // 添加默认值 isSmart: false,
isNewCampaign: true,
advertiserId: '',
campaignIdList: []
}; };
} }
// 确保所有必要的字段都存在
this.form.tiktok_json = {
optimizationGoal: tiktokData.optimizationGoal || 'VALUE',
optimizationEvent: tiktokData.optimizationEvent || '',
deepBidType: tiktokData.deepBidType || 'VO_MIN_ROAS',
deepCpaBid: tiktokData.deepCpaBid || 0,
roasBid: tiktokData.roasBid || 0,
vboWindow: tiktokData.vboWindow || '',
placements: Array.isArray(tiktokData.placements) ? tiktokData.placements : [],
isSmart: tiktokData.isSmart || false,
isNewCampaign: tiktokData.isNewCampaign !== undefined ? tiktokData.isNewCampaign : true,
advertiserId: tiktokData.advertiserId || '',
campaignIdList: Array.isArray(tiktokData.campaignIdList) ? tiktokData.campaignIdList : []
};
console.log('设置TikTok配置:', this.form.tiktok_json);
} catch (error) {
console.error('解析TikTok配置失败:', error);
this.$message.warning('TikTok配置解析失败,使用默认值');
// 设置默认值
this.form.tiktok_json = {
optimizationGoal: 'VALUE',
optimizationEvent: '',
deepBidType: 'VO_MIN_ROAS',
deepCpaBid: 0,
roasBid: 0,
vboWindow: '',
placements: [],
isSmart: false,
isNewCampaign: true,
advertiserId: '',
campaignIdList: []
};
} }
// 如果是TikTok平台,获取广告主列表 // 如果是TikTok平台,获取广告主列表
...@@ -1307,10 +1446,10 @@ export default { ...@@ -1307,10 +1446,10 @@ export default {
async handleAdvertiserChange(advertiserId) { async handleAdvertiserChange(advertiserId) {
if (!advertiserId) { if (!advertiserId) {
this.campaignOptions = []; this.campaignOptions = [];
this.form.campaignIdList = []; this.form.tiktok_json.campaignIdList = [];
return; return;
} }
await this.fetchCampaignList(advertiserId); await this.fetchCampaignList(advertiserId);
}, },
...@@ -1319,7 +1458,7 @@ export default { ...@@ -1319,7 +1458,7 @@ export default {
if (!query) { if (!query) {
this.filteredCampaignOptions = this.campaignOptions; this.filteredCampaignOptions = this.campaignOptions;
} else { } else {
this.filteredCampaignOptions = this.campaignOptions.filter(item => this.filteredCampaignOptions = this.campaignOptions.filter(item =>
item.toLowerCase().includes(query.toLowerCase()) item.toLowerCase().includes(query.toLowerCase())
); );
} }
...@@ -1328,7 +1467,7 @@ export default { ...@@ -1328,7 +1467,7 @@ export default {
// 修改获取计划列表的方法 // 修改获取计划列表的方法
async fetchCampaignList(advertiserId) { async fetchCampaignList(advertiserId) {
if (!advertiserId) return; if (!advertiserId) return;
this.campaignListLoading = true; this.campaignListLoading = true;
try { try {
const response = await axios.get(process.env.PUTIN_API + '/campaign-tasks/getCampaignIdByAdvertiserId', { const response = await axios.get(process.env.PUTIN_API + '/campaign-tasks/getCampaignIdByAdvertiserId', {
...@@ -1339,7 +1478,7 @@ export default { ...@@ -1339,7 +1478,7 @@ export default {
if (response.data && response.data.status === 200) { if (response.data && response.data.status === 200) {
// 直接使用返回的数据结构 // 直接使用返回的数据结构
this.campaignOptions = response.data.result.data || []; this.campaignOptions = response.data.result.data || [];
this.form.campaignIdList = []; this.form.tiktok_json.campaignIdList = [];
} else { } else {
this.$message.error(response.data.msg || '获取计划列表失败'); this.$message.error(response.data.msg || '获取计划列表失败');
} }
...@@ -1355,14 +1494,39 @@ export default { ...@@ -1355,14 +1494,39 @@ export default {
async handlePlatformChange(value) { async handlePlatformChange(value) {
if (value === 2) { if (value === 2) {
// 如果选择了TikTok平台,重置相关字段 // 如果选择了TikTok平台,重置相关字段
this.form.isNewCampaign = true; this.form.tiktok_json.isNewCampaign = true;
this.form.advertiserId = ''; this.form.tiktok_json.advertiserId = '';
this.form.campaignIdList = []; this.form.tiktok_json.campaignIdList = [];
// 获取广告主列表 // 获取广告主列表
await this.fetchAdvertiserList(); await this.fetchAdvertiserList();
} }
}, },
// 处理优化目标变化
handleOptimizationGoalChange(value) {
// 当优化目标改变时,清空相关字段
this.form.tiktok_json.optimizationEvent = '';
this.form.tiktok_json.deepBidType = '';
this.form.tiktok_json.roasBid = 0;
this.form.tiktok_json.vboWindow = '';
// 如果选择的是安装,则不需要优化事件和深度出价类型
if (value === 'INSTALL') {
this.form.tiktok_json.optimizationEvent = '';
this.form.tiktok_json.deepBidType = '';
this.form.tiktok_json.roasBid = 0;
this.form.tiktok_json.vboWindow = '';
}
},
// 处理深度出价类型变化
handleDeepBidTypeChange(value) {
// 当深度出价类型改变时,如果不是最小ROAS,则清空ROAS目标值
if (value !== 'VO_MIN_ROAS') {
this.form.tiktok_json.roasBid = 0;
}
},
// 应用组名称获取 // 应用组名称获取
getAppGroupName(id) { getAppGroupName(id) {
const group = this.appGroupOptions.find(item => item.id === id) const group = this.appGroupOptions.find(item => item.id === id)
...@@ -2064,7 +2228,7 @@ export default { ...@@ -2064,7 +2228,7 @@ export default {
.campaign-search-input { .campaign-search-input {
margin-bottom: 10px; margin-bottom: 10px;
} }
.campaign-select { .campaign-select {
width: 100%; width: 100%;
} }
......
...@@ -212,54 +212,144 @@ ...@@ -212,54 +212,144 @@
<el-input-number v-model="form.target_roas" :min="0"></el-input-number> <el-input-number v-model="form.target_roas" :min="0"></el-input-number>
</el-form-item> </el-form-item>
<!-- TikTok特定字段 --> <!-- TikTok特定字段 -->
<template v-if="form.platform === 2"> <template v-if="form.platform === 2">
<el-form-item label="智能创建" prop="tiktok_json.isSmart"> <el-form-item label="智能创建" prop="tiktok_json.isSmart">
<el-switch <el-switch
v-model="tiktokIsSmart" v-model="tiktokIsSmart"
:active-text="'开启'" :active-text="'开启'"
:inactive-text="'关闭'"> :inactive-text="'关闭'">
</el-switch> </el-switch>
</el-form-item> </el-form-item>
<el-form-item label="优化目标" prop="tiktok_json.optimizationGoal"> <el-form-item
<el-select label="选择账户"
v-model="tiktokOptimizationGoal" prop="tiktok_json.advertiserId">
placeholder="请选择优化目标"> <el-select
<el-option label="价值优化" value="VALUE"></el-option> v-model="tiktokAdvertiserId"
<el-option label="应用安装" value="INSTALL"></el-option> placeholder="请选择账户"
</el-select> :loading="advertiserLoading"
</el-form-item> @change="handleAdvertiserChange">
<el-option
<el-form-item label="深度出价类型" prop="tiktok_json.deepBidType"> v-for="item in advertiserOptions"
<el-select :key="item"
v-model="tiktokDeepBidType" :label="item"
placeholder="请选择深度出价类型"> :value="item">
<el-option label="最小ROAS" value="VO_MIN_ROAS"></el-option> </el-option>
<el-option label="最高价值" value="VO_HIGHEST_VALUE"></el-option> </el-select>
</el-select> </el-form-item>
</el-form-item>
<el-form-item label="优化目标" prop="tiktok_json.optimizationGoal">
<el-form-item label="深度CPA出价" prop="tiktok_json.deepCpaBid"> <el-select
<el-input-number v-model="tiktokOptimizationGoal"
v-model="tiktokDeepCpaBid" placeholder="请选择优化目标"
:min="0" @change="handleOptimizationGoalChange">
:precision="2" <el-option label="价值优化" value="VALUE"></el-option>
:step="0.01"> <el-option label="应用安装" value="INSTALL"></el-option>
</el-input-number> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="投放位置" prop="tiktok_json.placements"> <!-- 级联优化事件选择框 -->
<el-select <el-form-item
v-model="tiktokPlacements" label="优化事件"
multiple prop="tiktok_json.optimizationEvent"
placeholder="请选择投放位置"> v-if="tiktokOptimizationGoal === 'VALUE'">
<el-option label="TikTok" value="PLACEMENT_TIKTOK"></el-option> <el-select v-model="tiktokOptimizationEvent" placeholder="请选择优化事件">
<el-option label="Pangle" value="PLACEMENT_PANGLE"></el-option> <el-option label="应用内购价值" value="ACTIVE_PAY"></el-option>
<el-option label="Global App Bundle" value="PLACEMENT_GLOBAL_APP_BUNDLE"></el-option> <el-option label="广告收入价值" value="AD_REVENUE_VALUE"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template>
<el-form-item
label="深度出价类型"
prop="tiktok_json.deepBidType"
v-if="tiktokOptimizationGoal === 'VALUE'">
<el-select
v-model="tiktokDeepBidType"
placeholder="请选择深度出价类型"
@change="handleDeepBidTypeChange">
<el-option label="最小ROAS" value="VO_MIN_ROAS"></el-option>
<el-option label="最高价值" value="VO_HIGHEST_VALUE"></el-option>
</el-select>
</el-form-item>
<!-- ROAS目标值输入框 -->
<el-form-item
label="ROAS目标值"
prop="tiktok_json.roasBid"
v-if="tiktokOptimizationGoal === 'VALUE' && tiktokDeepBidType === 'VO_MIN_ROAS'">
<el-input-number
v-model="tiktokRoasBid"
:min="0.01"
:max="1000"
:precision="2"
placeholder="请输入ROAS目标值">
</el-input-number>
</el-form-item>
<!-- 价值优化窗口期选择框 -->
<!-- <el-form-item-->
<!-- label="价值优化窗口期"-->
<!-- prop="tiktok_json.vboWindow"-->
<!-- v-if="tiktokOptimizationGoal === 'VALUE'">-->
<!-- <el-select v-model="tiktokVboWindow" placeholder="请选择价值优化窗口期">-->
<!-- <el-option label="前7天" value="SEVEN_DAYS"></el-option>-->
<!-- <el-option label="第0天(当天)" value="ZERO_DAY"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- 深度CPA出价 -->
<!-- <el-form-item label="深度CPA出价" prop="tiktok_json.deepCpaBid">-->
<!-- <el-input-number -->
<!-- v-model="tiktokDeepCpaBid" -->
<!-- :min="0" -->
<!-- :precision="2"-->
<!-- :step="0.01">-->
<!-- </el-input-number>-->
<!-- </el-form-item>-->
<!-- 投放位置选择框 -->
<!-- <el-form-item label="投放位置" prop="tiktok_json.placements">-->
<!-- <el-select -->
<!-- v-model="tiktokPlacements" -->
<!-- multiple -->
<!-- placeholder="请选择投放位置">-->
<!-- <el-option label="TikTok" value="PLACEMENT_TIKTOK"></el-option>-->
<!-- <el-option label="Pangle" value="PLACEMENT_PANGLE"></el-option>-->
<!-- <el-option label="Global App Bundle" value="PLACEMENT_GLOBAL_APP_BUNDLE"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<el-form-item label="是否新建计划" prop="tiktok_json.isNewCampaign">
<el-switch
v-model="tiktokIsNewCampaign"
active-text="是"
inactive-text="否">
</el-switch>
</el-form-item>
<el-form-item
label="选择已有计划"
prop="tiktok_json.campaignIdList"
v-if="!tiktokIsNewCampaign && tiktokAdvertiserId">
<el-select
v-model="tiktokCampaignIdList"
multiple
filterable
placeholder="请输入计划名称搜索"
:loading="campaignListLoading"
style="width: 100%">
<el-option
v-for="item in campaignOptions"
:key="item.campaignId"
:label="item.campaignName"
:value="item.campaignId">
<span style="float: left">{{ item.campaignName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.campaignId }}</span>
</el-option>
</el-select>
</el-form-item>
</template>
<el-form-item label="应用组" prop="app_groups"> <el-form-item label="应用组" prop="app_groups">
<app-group-selector v-model="form.app_groups" /> <app-group-selector v-model="form.app_groups" />
...@@ -337,14 +427,20 @@ export default { ...@@ -337,14 +427,20 @@ export default {
material_groups: [], material_groups: [],
title_groups: [], title_groups: [],
description_groups: [], description_groups: [],
// 初始化tiktok_json为对象而不是null // 初始化tiktok_json为对象而不是null
tiktok_json: { tiktok_json: {
optimizationGoal: 'VALUE', optimizationGoal: 'VALUE',
deepBidType: 'VO_MIN_ROAS', optimizationEvent: '',
deepCpaBid: 0, deepBidType: 'VO_MIN_ROAS',
placements: [], // deepCpaBid: 0,
isSmart: false // 添加isSmart字段,默认为false roasBid: 0,
} // vboWindow: '',
// placements: [],
isSmart: false,
isNewCampaign: true,
advertiserId: '',
campaignIdList: []
}
}, },
rules: { rules: {
name: [ name: [
...@@ -382,21 +478,79 @@ export default { ...@@ -382,21 +478,79 @@ export default {
'tiktok_json.deepBidType': [ 'tiktok_json.deepBidType': [
{ required: true, message: '请选择深度出价类型', trigger: 'change' } { required: true, message: '请选择深度出价类型', trigger: 'change' }
], ],
'tiktok_json.deepCpaBid': [ // 'tiktok_json.deepCpaBid': [
{ required: true, message: '请输入深度CPA出价', trigger: 'blur' }, // { required: true, message: '请输入深度CPA出价', trigger: 'blur' },
{ type: 'number', min: 0, message: '深度CPA出价必须大于0', trigger: 'blur' } // { type: 'number', min: 0, message: '深度CPA出价必须大于0', trigger: 'blur' }
// ],
// 'tiktok_json.placements': [
// { required: true, message: '请选择投放位置', trigger: 'change' }
// ],
'tiktok_json.optimizationEvent': [
{
required: true,
message: '请选择优化事件',
trigger: 'change',
validator: (rule, value, callback) => {
if (this.tiktokOptimizationGoal === 'VALUE' && !value) {
callback(new Error('请选择优化事件'));
} else {
callback();
}
}
}
], ],
'tiktok_json.placements': [ 'tiktok_json.roasBid': [
{ required: true, message: '请选择投放位置', trigger: 'change' } {
] required: true,
message: '请输入ROAS目标值',
trigger: 'blur',
validator: (rule, value, callback) => {
if (this.tiktokOptimizationGoal === 'VALUE' &&
this.tiktokDeepBidType === 'VO_MIN_ROAS' &&
!value) {
callback(new Error('请输入ROAS目标值'));
} else if (value && (value < 0.01 || value > 1000)) {
callback(new Error('ROAS目标值必须在0.01-1000之间'));
} else {
callback();
}
}
}
],
// 'tiktok_json.vboWindow': [
// {
// required: true,
// message: '请选择价值优化窗口期',
// trigger: 'change',
// validator: (rule, value, callback) => {
// if (this.tiktokOptimizationGoal === 'VALUE' && !value) {
// callback(new Error('请选择价值优化窗口期'));
// } else {
// callback();
// }
// }
// }
// ],
'tiktok_json.advertiserId': [
{
required: true,
message: '请选择账户',
trigger: 'change'
}
]
}, },
groupNameMaps: { groupNameMaps: {
app: new Map(), app: new Map(),
location: new Map(), location: new Map(),
material: new Map(), material: new Map(),
title: new Map(), title: new Map(),
description: new Map() description: new Map()
} },
// 新增:账户相关数据
advertiserOptions: [],
advertiserLoading: false,
campaignOptions: [],
campaignListLoading: false
} }
}, },
computed: { computed: {
...@@ -423,37 +577,103 @@ export default { ...@@ -423,37 +577,103 @@ export default {
this.form.tiktok_json.deepBidType = value this.form.tiktok_json.deepBidType = value
} }
}, },
tiktokDeepCpaBid: { // tiktokDeepCpaBid: {
// get() {
// return this.form.tiktok_json ? Number(this.form.tiktok_json.deepCpaBid) : 0
// },
// set(value) {
// if (!this.form.tiktok_json) {
// this.form.tiktok_json = {}
// }
// this.form.tiktok_json.deepCpaBid = Number(value)
// }
// },
// tiktokPlacements: {
// get() {
// return this.form.tiktok_json ? this.form.tiktok_json.placements : []
// },
// set(value) {
// if (!this.form.tiktok_json) {
// this.form.tiktok_json = {}
// }
// this.form.tiktok_json.placements = value
// }
// },
tiktokIsSmart: {
get() { get() {
return this.form.tiktok_json ? Number(this.form.tiktok_json.deepCpaBid) : 0 return this.form.tiktok_json ? this.form.tiktok_json.isSmart : false
}, },
set(value) { set(value) {
if (!this.form.tiktok_json) { if (!this.form.tiktok_json) {
this.form.tiktok_json = {} this.form.tiktok_json = {}
} }
this.form.tiktok_json.deepCpaBid = Number(value) this.form.tiktok_json.isSmart = value
} }
}, },
tiktokPlacements: { tiktokOptimizationEvent: {
get() { get() {
return this.form.tiktok_json ? this.form.tiktok_json.placements : [] return this.form.tiktok_json ? this.form.tiktok_json.optimizationEvent : ''
}, },
set(value) { set(value) {
if (!this.form.tiktok_json) { if (!this.form.tiktok_json) {
this.form.tiktok_json = {} this.form.tiktok_json = {}
} }
this.form.tiktok_json.placements = value this.form.tiktok_json.optimizationEvent = value
} }
}, },
tiktokIsSmart: { tiktokRoasBid: {
get() { get() {
return this.form.tiktok_json ? this.form.tiktok_json.isSmart : false return this.form.tiktok_json ? Number(this.form.tiktok_json.roasBid) : 0
}, },
set(value) { set(value) {
if (!this.form.tiktok_json) { if (!this.form.tiktok_json) {
this.form.tiktok_json = {} this.form.tiktok_json = {}
} }
this.form.tiktok_json.isSmart = value this.form.tiktok_json.roasBid = Number(value)
}
},
// tiktokVboWindow: {
// get() {
// return this.form.tiktok_json ? this.form.tiktok_json.vboWindow : ''
// },
// set(value) {
// if (!this.form.tiktok_json) {
// this.form.tiktok_json = {}
// }
// this.form.tiktok_json.vboWindow = value
// }
// },
tiktokIsNewCampaign: {
get() {
return this.form.tiktok_json ? this.form.tiktok_json.isNewCampaign : true
},
set(value) {
if (!this.form.tiktok_json) {
this.form.tiktok_json = {}
}
this.form.tiktok_json.isNewCampaign = value
}
},
tiktokAdvertiserId: {
get() {
return this.form.tiktok_json ? this.form.tiktok_json.advertiserId : ''
},
set(value) {
if (!this.form.tiktok_json) {
this.form.tiktok_json = {}
}
this.form.tiktok_json.advertiserId = value
}
},
tiktokCampaignIdList: {
get() {
return this.form.tiktok_json ? this.form.tiktok_json.campaignIdList : []
},
set(value) {
if (!this.form.tiktok_json) {
this.form.tiktok_json = {}
}
this.form.tiktok_json.campaignIdList = value
} }
} }
}, },
...@@ -574,62 +794,94 @@ export default { ...@@ -574,62 +794,94 @@ export default {
material_groups: [], material_groups: [],
title_groups: [], title_groups: [],
description_groups: [], description_groups: [],
// 初始化为对象而不是null // 初始化为对象而不是null
tiktok_json: { tiktok_json: {
optimizationGoal: 'VALUE', optimizationGoal: 'VALUE',
deepBidType: 'VO_MIN_ROAS', optimizationEvent: '',
deepCpaBid: 0, deepBidType: 'VO_MIN_ROAS',
placements: [], // deepCpaBid: 0,
isSmart: false // 默认关闭智能创建 roasBid: 0,
} // vboWindow: '',
} // placements: [],
this.dialogVisible = true isSmart: false,
isNewCampaign: true,
advertiserId: '',
campaignIdList: []
}
}
this.dialogVisible = true
// 如果默认选择的是TikTok平台,获取广告主列表
if (this.form.platform === 2) {
this.fetchAdvertiserList();
}
}, },
// 平台变化时的处理 // 平台变化时的处理
handlePlatformChange(value) { async handlePlatformChange(value) {
// 当平台改变时,重新验证日预算字段 // 当平台改变时,重新验证日预算字段
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.form.validateField('daily_budget'); this.$refs.form.validateField('daily_budget');
// 如果切换到TikTok平台,初始化tiktok_json // 如果切换到TikTok平台,初始化tiktok_json
if (value === 2) { if (value === 2) {
// 使用Vue.set确保响应式 // 使用Vue.set确保响应式
this.$set(this.form, 'tiktok_json', { this.$set(this.form, 'tiktok_json', {
optimizationGoal: this.tiktokOptimizationGoal, optimizationGoal: this.tiktokOptimizationGoal,
deepBidType: this.tiktokDeepBidType, optimizationEvent: this.tiktokOptimizationEvent,
deepCpaBid: this.tiktokDeepCpaBid, deepBidType: this.tiktokDeepBidType,
placements: this.tiktokPlacements, // deepCpaBid: this.tiktokDeepCpaBid,
isSmart: this.tiktokIsSmart roasBid: this.tiktokRoasBid,
}); // vboWindow: this.tiktokVboWindow,
} else { // placements: this.tiktokPlacements,
// 如果切换到其他平台,保存当前值但设置为null isSmart: this.tiktokIsSmart,
const currentValues = { isNewCampaign: this.tiktokIsNewCampaign,
optimizationGoal: this.tiktokOptimizationGoal, advertiserId: this.tiktokAdvertiserId,
deepBidType: this.tiktokDeepBidType, campaignIdList: this.tiktokCampaignIdList
deepCpaBid: this.tiktokDeepCpaBid, });
placements: this.tiktokPlacements,
isSmart: this.tiktokIsSmart // 获取广告主列表
}; this.fetchAdvertiserList();
console.log('保存的TikTok配置:', currentValues); } else {
this.$set(this.form, 'tiktok_json', null); // 如果切换到其他平台,保存当前值但设置为null
} const currentValues = {
}); optimizationGoal: this.tiktokOptimizationGoal,
}, optimizationEvent: this.tiktokOptimizationEvent,
deepBidType: this.tiktokDeepBidType,
// deepCpaBid: this.tiktokDeepCpaBid,
roasBid: this.tiktokRoasBid,
// vboWindow: this.tiktokVboWindow,
// placements: this.tiktokPlacements,
isSmart: this.tiktokIsSmart,
isNewCampaign: this.tiktokIsNewCampaign,
advertiserId: this.tiktokAdvertiserId,
campaignIdList: this.tiktokCampaignIdList
};
console.log('保存的TikTok配置:', currentValues);
this.$set(this.form, 'tiktok_json', null);
}
});
},
// 修改编辑方法 // 修改编辑方法
handleEdit(row) { handleEdit(row) {
this.dialogTitle = '编辑模板' this.dialogTitle = '编辑模板'
console.log('编辑行数据:', row); console.log('编辑行数据:', row);
// 处理tiktok_json字段 // 处理tiktok_json字段
let tiktokJsonData = { let tiktokJsonData = {
optimizationGoal: 'VALUE', optimizationGoal: 'VALUE',
deepBidType: 'VO_MIN_ROAS', optimizationEvent: '',
deepCpaBid: 0, deepBidType: 'VO_MIN_ROAS',
placements: [], // deepCpaBid: 0,
isSmart: false roasBid: 0,
}; // vboWindow: '',
// placements: [],
isSmart: false,
isNewCampaign: true,
advertiserId: '',
campaignIdList: []
};
if (row.platform === 2) { if (row.platform === 2) {
try { try {
...@@ -640,15 +892,22 @@ export default { ...@@ -640,15 +892,22 @@ export default {
console.log('解析后的TikTok数据:', parsedData); console.log('解析后的TikTok数据:', parsedData);
// 使用解构赋值来合并默认值和已有数据,确保类型转换 // 使用解构赋值来合并默认值和已有数据,确保类型转换
tiktokJsonData = { tiktokJsonData = {
optimizationGoal: parsedData.optimizationGoal || 'VALUE', optimizationGoal: parsedData.optimizationGoal || 'VALUE',
deepBidType: parsedData.deepBidType || 'VO_MIN_ROAS', optimizationEvent: parsedData.optimizationEvent || '',
deepCpaBid: parsedData.deepCpaBid !== undefined && parsedData.deepCpaBid !== null ? deepBidType: parsedData.deepBidType || 'VO_MIN_ROAS',
Number(parsedData.deepCpaBid) : 0, // deepCpaBid: parsedData.deepCpaBid !== undefined && parsedData.deepCpaBid !== null ?
placements: Array.isArray(parsedData.placements) ? [...parsedData.placements] : [], // Number(parsedData.deepCpaBid) : 0,
isSmart: typeof parsedData.isSmart === 'boolean' ? parsedData.isSmart : false roasBid: parsedData.roasBid !== undefined && parsedData.roasBid !== null ?
}; Number(parsedData.roasBid) : 0,
// vboWindow: parsedData.vboWindow || '',
// placements: Array.isArray(parsedData.placements) ? [...parsedData.placements] : [],
isSmart: typeof parsedData.isSmart === 'boolean' ? parsedData.isSmart : false,
isNewCampaign: typeof parsedData.isNewCampaign === 'boolean' ? parsedData.isNewCampaign : true,
advertiserId: parsedData.advertiserId || '',
campaignIdList: Array.isArray(parsedData.campaignIdList) ? [...parsedData.campaignIdList] : []
};
} }
} catch (error) { } catch (error) {
console.error('解析TikTok配置失败:', error); console.error('解析TikTok配置失败:', error);
...@@ -666,15 +925,20 @@ export default { ...@@ -666,15 +925,20 @@ export default {
description_groups: Array.isArray(row.description_groups) ? [...row.description_groups] : [] description_groups: Array.isArray(row.description_groups) ? [...row.description_groups] : []
}; };
// 使用Vue.set确保响应式更新 // 使用Vue.set确保响应式更新
this.$set(this, 'form', formData); this.$set(this, 'form', formData);
this.$nextTick(() => { this.$nextTick(() => {
// 在下一个tick更新tiktok_json,确保响应式 // 在下一个tick更新tiktok_json,确保响应式
this.$set(this.form, 'tiktok_json', tiktokJsonData); this.$set(this.form, 'tiktok_json', tiktokJsonData);
console.log('设置后的表单数据:', this.form); console.log('设置后的表单数据:', this.form);
});
// 如果是TikTok平台,获取广告主列表
this.dialogVisible = true; if (row.platform === 2) {
this.fetchAdvertiserList();
}
});
this.dialogVisible = true;
}, },
async handleDelete(row) { async handleDelete(row) {
...@@ -713,13 +977,19 @@ export default { ...@@ -713,13 +977,19 @@ export default {
// 如果是TikTok平台,处理tiktok_json // 如果是TikTok平台,处理tiktok_json
if (formData.platform === 2) { if (formData.platform === 2) {
const tiktokData = { const tiktokData = {
optimizationGoal: this.tiktokOptimizationGoal, optimizationGoal: this.tiktokOptimizationGoal,
deepBidType: this.tiktokDeepBidType, optimizationEvent: this.tiktokOptimizationEvent,
deepCpaBid: this.tiktokDeepCpaBid, deepBidType: this.tiktokDeepBidType,
placements: Array.isArray(this.tiktokPlacements) ? [...this.tiktokPlacements] : [], // deepCpaBid: this.tiktokDeepCpaBid,
isSmart: this.tiktokIsSmart roasBid: this.tiktokRoasBid,
}; // vboWindow: this.tiktokVboWindow,
// placements: Array.isArray(this.tiktokPlacements) ? [...this.tiktokPlacements] : [],
isSmart: this.tiktokIsSmart,
isNewCampaign: this.tiktokIsNewCampaign,
advertiserId: this.tiktokAdvertiserId,
campaignIdList: Array.isArray(this.tiktokCampaignIdList) ? [...this.tiktokCampaignIdList] : []
};
console.log('提交前的TikTok数据:', tiktokData); console.log('提交前的TikTok数据:', tiktokData);
formData.tiktok_json = JSON.stringify(tiktokData); formData.tiktok_json = JSON.stringify(tiktokData);
...@@ -767,6 +1037,85 @@ export default { ...@@ -767,6 +1037,85 @@ export default {
handleDescriptionGroupChange() { handleDescriptionGroupChange() {
this.fetchData() this.fetchData()
}, },
// 处理优化目标变化
handleOptimizationGoalChange(value) {
// 当优化目标改变时,清空相关字段
this.tiktokOptimizationEvent = '';
this.tiktokDeepBidType = '';
this.tiktokRoasBid = 0;
// this.tiktokVboWindow = '';
// 如果选择的是安装,则不需要优化事件和深度出价类型
if (value === 'INSTALL') {
this.tiktokOptimizationEvent = '';
this.tiktokDeepBidType = '';
this.tiktokRoasBid = 0;
// this.tiktokVboWindow = '';
}
},
// 处理深度出价类型变化
handleDeepBidTypeChange(value) {
// 当深度出价类型改变时,如果不是最小ROAS,则清空ROAS目标值
if (value !== 'VO_MIN_ROAS') {
this.tiktokRoasBid = 0;
}
},
// 获取广告主列表
async fetchAdvertiserList() {
this.advertiserLoading = true;
try {
const response = await axios.get(process.env.PUTIN_API + '/campaign-tasks/getTiktokAdvertiserId');
if (response.data && response.data.status === 200) {
this.advertiserOptions = response.data.result.data || [];
} else {
this.$message.error(response.data.msg || '获取账户列表失败');
}
} catch (error) {
console.error('获取账户列表失败:', error);
this.$message.error('获取账户列表失败');
} finally {
this.advertiserLoading = false;
}
},
// 处理广告主变化
async handleAdvertiserChange(advertiserId) {
if (!advertiserId) {
this.campaignOptions = [];
this.tiktokCampaignIdList = [];
return;
}
await this.fetchCampaignList(advertiserId);
},
// 获取计划列表
async fetchCampaignList(advertiserId) {
if (!advertiserId) return;
this.campaignListLoading = true;
try {
const response = await axios.get(process.env.PUTIN_API + '/campaign-tasks/getCampaignIdByAdvertiserId', {
params: {
advertiserId: advertiserId
}
});
if (response.data && response.data.status === 200) {
this.campaignOptions = response.data.result.data || [];
this.tiktokCampaignIdList = [];
} else {
this.$message.error(response.data.msg || '获取计划列表失败');
}
} catch (error) {
console.error('获取计划列表失败:', error);
this.$message.error('获取计划列表失败');
} finally {
this.campaignListLoading = false;
}
},
} }
} }
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment